DATAJDBC-318 - Adding a failing test.
Added failing tests for entities with references. Code deduplication. Documentation wording. Formatting. Original pull request: #209.
This commit is contained in:
@@ -27,8 +27,8 @@ import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* A query to be executed based on a repository method, it's annotated SQL query and the arguments provided to the
|
||||
* method.
|
||||
* Base class for queries based on a repository method. It holds the infrastructure for executing a query and knows how
|
||||
* to execute a query based on the return type of the method. How to construct the query is left to subclasses.
|
||||
*
|
||||
* @author Jens Schauder
|
||||
* @author Kazuki Shimizu
|
||||
|
||||
@@ -65,7 +65,7 @@ class JdbcQueryCreator extends RelationalQueryCreator<ParametrizedQuery> {
|
||||
* @param entityMetadata relational entity metadata, must not be {@literal null}.
|
||||
* @param accessor parameter metadata provider, must not be {@literal null}.
|
||||
*/
|
||||
public JdbcQueryCreator(PartTree tree, JdbcConverter converter, Dialect dialect,
|
||||
JdbcQueryCreator(PartTree tree, JdbcConverter converter, Dialect dialect,
|
||||
RelationalEntityMetadata<?> entityMetadata, RelationalParameterAccessor accessor) {
|
||||
super(tree, accessor);
|
||||
|
||||
|
||||
@@ -19,7 +19,8 @@ import org.springframework.jdbc.core.namedparam.SqlParameterSource;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Interface specifying a result execution strategy.
|
||||
* Interface specifying a query execution strategy. Implementations encapsulate information how to actually execute the
|
||||
* query and how to process the result in order to get the desired return type.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @since 2.0
|
||||
@@ -28,11 +29,11 @@ import org.springframework.lang.Nullable;
|
||||
interface JdbcQueryExecution<T> {
|
||||
|
||||
/**
|
||||
* Execute the given {@code query}.
|
||||
* Execute the given {@code query} and {@code parameter} and transforms the result into a {@code T}.
|
||||
*
|
||||
* @param query
|
||||
* @param parameter
|
||||
* @return
|
||||
* @param query the query to be executed. Must not be {@literal null}.
|
||||
* @param parameter the parameters to be bound to the query. Must not be {@literal null}.
|
||||
* @return the result of the query. Might be {@literal null}.
|
||||
*/
|
||||
@Nullable
|
||||
T execute(String query, SqlParameterSource parameter);
|
||||
|
||||
@@ -18,7 +18,7 @@ package org.springframework.data.jdbc.repository.query;
|
||||
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
|
||||
|
||||
/**
|
||||
* Value object encapsulating a parametrized query containing named parameters and {@link SqlParameterSource}.
|
||||
* Value object encapsulating a query containing named parameters and a{@link SqlParameterSource} to bind the parameters.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @since 2.0
|
||||
@@ -28,16 +28,17 @@ class ParametrizedQuery {
|
||||
private final String query;
|
||||
private final SqlParameterSource parameterSource;
|
||||
|
||||
public ParametrizedQuery(String query, SqlParameterSource parameterSource) {
|
||||
ParametrizedQuery(String query, SqlParameterSource parameterSource) {
|
||||
|
||||
this.query = query;
|
||||
this.parameterSource = parameterSource;
|
||||
}
|
||||
|
||||
public String getQuery() {
|
||||
String getQuery() {
|
||||
return query;
|
||||
}
|
||||
|
||||
public SqlParameterSource getParameterSource() {
|
||||
SqlParameterSource getParameterSource() {
|
||||
return parameterSource;
|
||||
}
|
||||
|
||||
|
||||
@@ -64,9 +64,11 @@ public class PartTreeJdbcQuery extends AbstractJdbcQuery {
|
||||
this.converter = converter;
|
||||
|
||||
try {
|
||||
|
||||
this.tree = new PartTree(queryMethod.getName(), queryMethod.getEntityInformation().getJavaType());
|
||||
JdbcQueryCreator.validate(this.tree, this.parameters);
|
||||
} catch (RuntimeException e) {
|
||||
|
||||
throw new IllegalArgumentException(
|
||||
String.format("Failed to create query for method %s! %s", queryMethod, e.getMessage()), e);
|
||||
}
|
||||
|
||||
@@ -69,7 +69,7 @@ class QueryMapper {
|
||||
* @param converter must not be {@literal null}.
|
||||
*/
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
public QueryMapper(Dialect dialect, JdbcConverter converter) {
|
||||
QueryMapper(Dialect dialect, JdbcConverter converter) {
|
||||
|
||||
Assert.notNull(dialect, "Dialect must not be null!");
|
||||
Assert.notNull(converter, "JdbcConverter must not be null!");
|
||||
@@ -80,13 +80,13 @@ class QueryMapper {
|
||||
}
|
||||
|
||||
/**
|
||||
* Map the {@link Sort} object to apply field name mapping using {@link Class the type to read}.
|
||||
* Map the {@link Sort} object to apply field name mapping using {@link RelationalPersistentEntity the type to read}.
|
||||
*
|
||||
* @param sort must not be {@literal null}.
|
||||
* @param entity related {@link RelationalPersistentEntity}, can be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public List<OrderByField> getMappedSort(Table table, Sort sort, @Nullable RelationalPersistentEntity<?> entity) {
|
||||
List<OrderByField> getMappedSort(Table table, Sort sort, @Nullable RelationalPersistentEntity<?> entity) {
|
||||
|
||||
List<OrderByField> mappedOrder = new ArrayList<>();
|
||||
|
||||
@@ -102,13 +102,14 @@ class QueryMapper {
|
||||
}
|
||||
|
||||
/**
|
||||
* Map the {@link Expression} object to apply field name mapping using {@link Class the type to read}.
|
||||
* Map the {@link Expression} object to apply field name mapping using {@link RelationalPersistentEntity the type to
|
||||
* read}.
|
||||
*
|
||||
* @param expression must not be {@literal null}.
|
||||
* @param entity related {@link RelationalPersistentEntity}, can be {@literal null}.
|
||||
* @return the mapped {@link Expression}.
|
||||
* @return the mapped {@link Expression}. Guaranteed to be not {@literal null}.
|
||||
*/
|
||||
public Expression getMappedObject(Expression expression, @Nullable RelationalPersistentEntity<?> entity) {
|
||||
Expression getMappedObject(Expression expression, @Nullable RelationalPersistentEntity<?> entity) {
|
||||
|
||||
if (entity == null || expression instanceof AsteriskFromTable) {
|
||||
return expression;
|
||||
@@ -120,6 +121,8 @@ class QueryMapper {
|
||||
Field field = createPropertyField(entity, column.getName());
|
||||
Table table = column.getTable();
|
||||
|
||||
Assert.state(table != null, String.format("The column %s must have a table set.", column));
|
||||
|
||||
Column columnFromTable = table.column(field.getMappedColumnName());
|
||||
return column instanceof Aliased ? columnFromTable.as(((Aliased) column).getAlias()) : columnFromTable;
|
||||
}
|
||||
@@ -144,7 +147,7 @@ class QueryMapper {
|
||||
}
|
||||
|
||||
/**
|
||||
* Map a {@link CriteriaDefinition} object into {@link Condition} and consider value/{@code NULL} {@link Bindings}.
|
||||
* Map a {@link CriteriaDefinition} object into {@link Condition} and consider value/{@code NULL} bindings.
|
||||
*
|
||||
* @param parameterSource bind parameterSource object, must not be {@literal null}.
|
||||
* @param criteria criteria definition to map, must not be {@literal null}.
|
||||
@@ -152,7 +155,7 @@ class QueryMapper {
|
||||
* @param entity related {@link RelationalPersistentEntity}, can be {@literal null}.
|
||||
* @return the mapped {@link Condition}.
|
||||
*/
|
||||
public Condition getMappedObject(MapSqlParameterSource parameterSource, CriteriaDefinition criteria, Table table,
|
||||
Condition getMappedObject(MapSqlParameterSource parameterSource, CriteriaDefinition criteria, Table table,
|
||||
@Nullable RelationalPersistentEntity<?> entity) {
|
||||
|
||||
Assert.notNull(parameterSource, "MapSqlParameterSource must not be null!");
|
||||
@@ -349,13 +352,13 @@ class QueryMapper {
|
||||
|
||||
Pair<Object, Object> pair = (Pair<Object, Object>) value;
|
||||
|
||||
Object first = convertValue(pair.getFirst(),
|
||||
typeInformation.getActualType() != null ? typeInformation.getRequiredActualType()
|
||||
: ClassTypeInformation.OBJECT);
|
||||
Object first = convertValue(pair.getFirst(), typeInformation.getActualType() != null //
|
||||
? typeInformation.getRequiredActualType()
|
||||
: ClassTypeInformation.OBJECT);
|
||||
|
||||
Object second = convertValue(pair.getSecond(),
|
||||
typeInformation.getActualType() != null ? typeInformation.getRequiredActualType()
|
||||
: ClassTypeInformation.OBJECT);
|
||||
Object second = convertValue(pair.getSecond(), typeInformation.getActualType() != null //
|
||||
? typeInformation.getRequiredActualType()
|
||||
: ClassTypeInformation.OBJECT);
|
||||
|
||||
return Pair.of(first, second);
|
||||
}
|
||||
@@ -365,6 +368,7 @@ class QueryMapper {
|
||||
List<Object> mapped = new ArrayList<>();
|
||||
|
||||
for (Object o : (Iterable<?>) value) {
|
||||
|
||||
mapped.add(convertValue(o, typeInformation.getActualType() != null ? typeInformation.getRequiredActualType()
|
||||
: ClassTypeInformation.OBJECT));
|
||||
}
|
||||
@@ -498,10 +502,6 @@ class QueryMapper {
|
||||
return entity == null ? new Field(key) : new MetadataBackedField(key, entity, mappingContext, converter);
|
||||
}
|
||||
|
||||
Class<?> getTypeHint(@Nullable Object mappedValue, Class<?> propertyType) {
|
||||
return propertyType;
|
||||
}
|
||||
|
||||
int getTypeHint(@Nullable Object mappedValue, Class<?> propertyType, JdbcValue settableValue) {
|
||||
|
||||
if (mappedValue == null || propertyType.equals(Object.class)) {
|
||||
@@ -560,7 +560,7 @@ class QueryMapper {
|
||||
*
|
||||
* @param name must not be {@literal null} or empty.
|
||||
*/
|
||||
public Field(SqlIdentifier name) {
|
||||
Field(SqlIdentifier name) {
|
||||
|
||||
Assert.notNull(name, "Name must not be null!");
|
||||
this.name = name;
|
||||
|
||||
@@ -94,11 +94,7 @@ class JdbcQueryLookupStrategy implements QueryLookupStrategy {
|
||||
JdbcQueryMethod queryMethod = new JdbcQueryMethod(method, repositoryMetadata, projectionFactory, namedQueries,
|
||||
context);
|
||||
|
||||
if (namedQueries.hasQuery(queryMethod.getNamedQueryName())) {
|
||||
|
||||
RowMapper<?> mapper = queryMethod.isModifyingQuery() ? null : createMapper(queryMethod);
|
||||
return new StringBasedJdbcQuery(queryMethod, operations, mapper, converter);
|
||||
} else if (queryMethod.hasAnnotatedQuery()) {
|
||||
if (namedQueries.hasQuery(queryMethod.getNamedQueryName()) || queryMethod.hasAnnotatedQuery()) {
|
||||
|
||||
RowMapper<?> mapper = queryMethod.isModifyingQuery() ? null : createMapper(queryMethod);
|
||||
return new StringBasedJdbcQuery(queryMethod, operations, mapper, converter);
|
||||
|
||||
@@ -19,7 +19,6 @@ import static org.assertj.core.api.Assertions.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Collection;
|
||||
@@ -31,7 +30,6 @@ import java.util.Properties;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.jdbc.core.convert.BasicJdbcConverter;
|
||||
import org.springframework.data.jdbc.core.convert.JdbcConverter;
|
||||
@@ -63,6 +61,26 @@ public class PartTreeJdbcQueryUnitTests {
|
||||
JdbcMappingContext mappingContext = new JdbcMappingContext();
|
||||
JdbcConverter converter = new BasicJdbcConverter(mappingContext, mock(RelationResolver.class));
|
||||
|
||||
@Test // DATAJDBC-318
|
||||
public void selectContainsColumnsForOneToOneReference() throws Exception {
|
||||
|
||||
JdbcQueryMethod queryMethod = getQueryMethod("findAllByFirstName", String.class);
|
||||
PartTreeJdbcQuery jdbcQuery = createQuery(queryMethod);
|
||||
ParametrizedQuery query = jdbcQuery.createQuery(getAccessor(queryMethod, new Object[] { "John" }));
|
||||
|
||||
assertThat(query.getQuery()).contains("hated.\"name\" AS \"hated_name\"");
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-318
|
||||
public void doesNotContainsColumnsForOneToManyReference() throws Exception{
|
||||
|
||||
JdbcQueryMethod queryMethod = getQueryMethod("findAllByFirstName", String.class);
|
||||
PartTreeJdbcQuery jdbcQuery = createQuery(queryMethod);
|
||||
ParametrizedQuery query = jdbcQuery.createQuery(getAccessor(queryMethod, new Object[] { "John" }));
|
||||
|
||||
assertThat(query.getQuery().toLowerCase()).doesNotContain("hobbies");
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-318
|
||||
public void createsQueryToFindAllEntitiesByStringAttribute() throws Exception {
|
||||
|
||||
@@ -622,7 +640,6 @@ public class PartTreeJdbcQueryUnitTests {
|
||||
}
|
||||
|
||||
@Table("users")
|
||||
@Data
|
||||
static class User {
|
||||
|
||||
@Id Long id;
|
||||
@@ -633,12 +650,18 @@ public class PartTreeJdbcQueryUnitTests {
|
||||
Boolean active;
|
||||
|
||||
@Embedded(prefix = "user_", onEmpty = Embedded.OnEmpty.USE_NULL) Address address;
|
||||
|
||||
List<Hobby> hobbies;
|
||||
Hobby hated;
|
||||
}
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
static class Address {
|
||||
String street;
|
||||
String city;
|
||||
}
|
||||
|
||||
static class Hobby {
|
||||
String name;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user