Browse Source

Remove dialect dependency from QueryMapper.

See #1601
Original pull request: #1617
pull/1622/head
Jens Schauder 2 years ago committed by Mark Paluch
parent
commit
6fb6110ca0
No known key found for this signature in database
GPG Key ID: 4406B84C1661DCD1
  1. 39
      spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/QueryMapper.java
  2. 2
      spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/SqlGenerator.java
  3. 53
      spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/query/EscapingParameterSource.java
  4. 2
      spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/query/JdbcQueryCreator.java
  5. 12
      spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/query/ParametrizedQuery.java
  6. 4
      spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/query/PartTreeJdbcQuery.java
  7. 2
      spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/convert/QueryMapperUnitTests.java
  8. 33
      spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/query/PartTreeJdbcQueryUnitTests.java

39
spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/QueryMapper.java

@ -23,6 +23,7 @@ import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.function.Function;
import org.springframework.data.domain.Sort; import org.springframework.data.domain.Sort;
import org.springframework.data.jdbc.core.mapping.JdbcValue; import org.springframework.data.jdbc.core.mapping.JdbcValue;
@ -60,7 +61,6 @@ import org.springframework.util.ClassUtils;
public class QueryMapper { public class QueryMapper {
private final JdbcConverter converter; private final JdbcConverter converter;
private final Dialect dialect;
private final MappingContext<? extends RelationalPersistentEntity<?>, RelationalPersistentProperty> mappingContext; private final MappingContext<? extends RelationalPersistentEntity<?>, RelationalPersistentProperty> mappingContext;
/** /**
@ -68,18 +68,31 @@ public class QueryMapper {
* *
* @param dialect must not be {@literal null}. * @param dialect must not be {@literal null}.
* @param converter must not be {@literal null}. * @param converter must not be {@literal null}.
* @deprecated use {@link QueryMapper(JdbcConverter)} instead.
*/ */
@SuppressWarnings({ "unchecked", "rawtypes" }) @Deprecated(since="3.2")
public QueryMapper(Dialect dialect, JdbcConverter converter) { public QueryMapper(Dialect dialect, JdbcConverter converter) {
Assert.notNull(dialect, "Dialect must not be null"); Assert.notNull(dialect, "Dialect must not be null");
Assert.notNull(converter, "JdbcConverter must not be null"); Assert.notNull(converter, "JdbcConverter must not be null");
this.converter = converter; this.converter = converter;
this.dialect = dialect;
this.mappingContext = (MappingContext) converter.getMappingContext(); this.mappingContext = (MappingContext) converter.getMappingContext();
} }
/**
* Creates a new {@link QueryMapper} with the given {@link JdbcConverter}.
*
* @param converter must not be {@literal null}.
*/
public QueryMapper( JdbcConverter converter) {
Assert.notNull(converter, "JdbcConverter must not be null");
this.converter = converter;
this.mappingContext = converter.getMappingContext();
}
/** /**
* Map the {@link Sort} object to apply field name mapping using {@link RelationalPersistentEntity the type to read}. * Map the {@link Sort} object to apply field name mapping using {@link RelationalPersistentEntity the type to read}.
* *
@ -295,16 +308,13 @@ public class QueryMapper {
mappedValue = convertValue(comparator, settableValue.getValue(), propertyField.getTypeHint()); mappedValue = convertValue(comparator, settableValue.getValue(), propertyField.getTypeHint());
sqlType = getTypeHint(mappedValue, actualType.getType(), settableValue); sqlType = getTypeHint(mappedValue, actualType.getType(), settableValue);
} else if (criteria.getValue() instanceof ValueFunction) { } else if (criteria.getValue() instanceof ValueFunction valueFunction) {
ValueFunction<Object> valueFunction = (ValueFunction<Object>) criteria.getValue(); mappedValue = valueFunction;
Object value = valueFunction.apply(getEscaper(comparator));
mappedValue = convertValue(comparator, value, propertyField.getTypeHint());
sqlType = propertyField.getSqlType(); sqlType = propertyField.getSqlType();
} else if (propertyField instanceof MetadataBackedField // } else if (propertyField instanceof MetadataBackedField metadataBackedField //
&& ((MetadataBackedField) propertyField).property != null // && metadataBackedField.property != null //
&& (criteria.getValue() == null || !criteria.getValue().getClass().isArray())) { && (criteria.getValue() == null || !criteria.getValue().getClass().isArray())) {
RelationalPersistentProperty property = ((MetadataBackedField) propertyField).property; RelationalPersistentProperty property = ((MetadataBackedField) propertyField).property;
@ -431,15 +441,6 @@ public class QueryMapper {
return Conditions.nest(condition); return Conditions.nest(condition);
} }
private Escaper getEscaper(Comparator comparator) {
if (comparator == Comparator.LIKE || comparator == Comparator.NOT_LIKE) {
return dialect.getLikeEscaper();
}
return Escaper.DEFAULT;
}
@Nullable @Nullable
private Object convertValue(Comparator comparator, @Nullable Object value, TypeInformation<?> typeHint) { private Object convertValue(Comparator comparator, @Nullable Object value, TypeInformation<?> typeHint) {

2
spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/SqlGenerator.java

@ -113,7 +113,7 @@ class SqlGenerator {
this.renderContext = new RenderContextFactory(dialect).createRenderContext(); this.renderContext = new RenderContextFactory(dialect).createRenderContext();
this.sqlRenderer = SqlRenderer.create(renderContext); this.sqlRenderer = SqlRenderer.create(renderContext);
this.columns = new Columns(entity, mappingContext, converter); this.columns = new Columns(entity, mappingContext, converter);
this.queryMapper = new QueryMapper(dialect, converter); this.queryMapper = new QueryMapper(converter);
this.dialect = dialect; this.dialect = dialect;
} }

53
spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/query/EscapingParameterSource.java

@ -0,0 +1,53 @@
/*
* Copyright 2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.jdbc.repository.query;
import org.springframework.data.relational.core.dialect.Escaper;
import org.springframework.data.relational.core.query.ValueFunction;
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
/**
* This {@link SqlParameterSource} will apply escaping to it's values.
*
* @author Jens Schauder
* @since 3.2
*/
public class EscapingParameterSource implements SqlParameterSource {
private final SqlParameterSource parameterSource;
private final Escaper escaper;
public EscapingParameterSource(SqlParameterSource parameterSource, Escaper escaper) {
this.parameterSource = parameterSource;
this.escaper = escaper;
}
@Override
public boolean hasValue(String paramName) {
return parameterSource.hasValue(paramName);
}
@Override
public Object getValue(String paramName) throws IllegalArgumentException {
Object value = parameterSource.getValue(paramName);
if (value instanceof ValueFunction<?>) {
return ((ValueFunction<?>) value).apply(escaper);
}
return value;
}
}

2
spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/query/JdbcQueryCreator.java

@ -102,7 +102,7 @@ class JdbcQueryCreator extends RelationalQueryCreator<ParametrizedQuery> {
this.accessor = accessor; this.accessor = accessor;
this.entityMetadata = entityMetadata; this.entityMetadata = entityMetadata;
this.queryMapper = new QueryMapper(dialect, converter); this.queryMapper = new QueryMapper(converter);
this.renderContextFactory = new RenderContextFactory(dialect); this.renderContextFactory = new RenderContextFactory(dialect);
this.isSliceQuery = isSliceQuery; this.isSliceQuery = isSliceQuery;
this.returnedType = returnedType; this.returnedType = returnedType;

12
spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/query/ParametrizedQuery.java

@ -15,12 +15,15 @@
*/ */
package org.springframework.data.jdbc.repository.query; package org.springframework.data.jdbc.repository.query;
import org.springframework.data.relational.core.dialect.Dialect;
import org.springframework.data.relational.core.dialect.Escaper;
import org.springframework.jdbc.core.namedparam.SqlParameterSource; import org.springframework.jdbc.core.namedparam.SqlParameterSource;
/** /**
* Value object encapsulating a query containing named parameters and a{@link SqlParameterSource} to bind the parameters. * Value object encapsulating a query containing named parameters and a{@link SqlParameterSource} to bind the parameters.
* *
* @author Mark Paluch * @author Mark Paluch
* @author Jens Schauder
* @since 2.0 * @since 2.0
*/ */
class ParametrizedQuery { class ParametrizedQuery {
@ -38,12 +41,13 @@ class ParametrizedQuery {
return query; return query;
} }
SqlParameterSource getParameterSource() {
return parameterSource;
}
@Override @Override
public String toString() { public String toString() {
return this.query; return this.query;
} }
public SqlParameterSource getParameterSource(Escaper escaper) {
return new EscapingParameterSource(parameterSource, escaper);
}
} }

4
spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/query/PartTreeJdbcQuery.java

@ -126,7 +126,7 @@ public class PartTreeJdbcQuery extends AbstractJdbcQuery {
ParametrizedQuery query = createQuery(accessor, processor.getReturnedType()); ParametrizedQuery query = createQuery(accessor, processor.getReturnedType());
JdbcQueryExecution<?> execution = getQueryExecution(processor, accessor); JdbcQueryExecution<?> execution = getQueryExecution(processor, accessor);
return execution.execute(query.getQuery(), query.getParameterSource()); return execution.execute(query.getQuery(), query.getParameterSource(dialect.getLikeEscaper()));
} }
private JdbcQueryExecution<?> getQueryExecution(ResultProcessor processor, private JdbcQueryExecution<?> getQueryExecution(ResultProcessor processor,
@ -164,7 +164,7 @@ public class PartTreeJdbcQuery extends AbstractJdbcQuery {
ParametrizedQuery countQuery = queryCreator.createQuery(Sort.unsorted()); ParametrizedQuery countQuery = queryCreator.createQuery(Sort.unsorted());
Object count = singleObjectQuery((rs, i) -> rs.getLong(1)).execute(countQuery.getQuery(), Object count = singleObjectQuery((rs, i) -> rs.getLong(1)).execute(countQuery.getQuery(),
countQuery.getParameterSource()); countQuery.getParameterSource(dialect.getLikeEscaper()));
return converter.getConversionService().convert(count, Long.class); return converter.getConversionService().convert(count, Long.class);
}); });

2
spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/convert/QueryMapperUnitTests.java

@ -50,7 +50,7 @@ public class QueryMapperUnitTests {
JdbcMappingContext context = new JdbcMappingContext(); JdbcMappingContext context = new JdbcMappingContext();
JdbcConverter converter = new BasicJdbcConverter(context, mock(RelationResolver.class)); JdbcConverter converter = new BasicJdbcConverter(context, mock(RelationResolver.class));
QueryMapper mapper = new QueryMapper(PostgresDialect.INSTANCE, converter); QueryMapper mapper = new QueryMapper(converter);
MapSqlParameterSource parameterSource = new MapSqlParameterSource(); MapSqlParameterSource parameterSource = new MapSqlParameterSource();
@Test // DATAJDBC-318 @Test // DATAJDBC-318

33
spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/query/PartTreeJdbcQueryUnitTests.java

@ -36,6 +36,7 @@ import org.springframework.data.jdbc.core.convert.RelationResolver;
import org.springframework.data.jdbc.core.mapping.AggregateReference; import org.springframework.data.jdbc.core.mapping.AggregateReference;
import org.springframework.data.jdbc.core.mapping.JdbcMappingContext; import org.springframework.data.jdbc.core.mapping.JdbcMappingContext;
import org.springframework.data.projection.SpelAwareProxyProjectionFactory; import org.springframework.data.projection.SpelAwareProxyProjectionFactory;
import org.springframework.data.relational.core.dialect.Escaper;
import org.springframework.data.relational.core.dialect.H2Dialect; import org.springframework.data.relational.core.dialect.H2Dialect;
import org.springframework.data.relational.core.mapping.Embedded; import org.springframework.data.relational.core.mapping.Embedded;
import org.springframework.data.relational.core.mapping.MappedCollection; import org.springframework.data.relational.core.mapping.MappedCollection;
@ -93,7 +94,7 @@ public class PartTreeJdbcQueryUnitTests {
softly.assertThat(query.getQuery()) softly.assertThat(query.getQuery())
.isEqualTo(BASE_SELECT + " WHERE " + TABLE + ".\"HOBBY_REFERENCE\" = :hobby_reference"); .isEqualTo(BASE_SELECT + " WHERE " + TABLE + ".\"HOBBY_REFERENCE\" = :hobby_reference");
softly.assertThat(query.getParameterSource().getValue("hobby_reference")).isEqualTo("twentythree"); softly.assertThat(query.getParameterSource(Escaper.DEFAULT).getValue("hobby_reference")).isEqualTo("twentythree");
}); });
} }
@ -112,8 +113,8 @@ public class PartTreeJdbcQueryUnitTests {
softly.assertThat(query.getQuery().toUpperCase()).endsWith("FOR UPDATE"); softly.assertThat(query.getQuery().toUpperCase()).endsWith("FOR UPDATE");
softly.assertThat(query.getParameterSource().getValue("first_name")).isEqualTo(firstname); softly.assertThat(query.getParameterSource(Escaper.DEFAULT).getValue("first_name")).isEqualTo(firstname);
softly.assertThat(query.getParameterSource().getValue("last_name")).isEqualTo(lastname); softly.assertThat(query.getParameterSource(Escaper.DEFAULT).getValue("last_name")).isEqualTo(lastname);
}); });
} }
@ -133,8 +134,8 @@ public class PartTreeJdbcQueryUnitTests {
// this is also for update since h2 dialect does not distinguish between lockmodes // this is also for update since h2 dialect does not distinguish between lockmodes
softly.assertThat(query.getQuery().toUpperCase()).endsWith("FOR UPDATE"); softly.assertThat(query.getQuery().toUpperCase()).endsWith("FOR UPDATE");
softly.assertThat(query.getParameterSource().getValue("first_name")).isEqualTo(firstname); softly.assertThat(query.getParameterSource(Escaper.DEFAULT).getValue("first_name")).isEqualTo(firstname);
softly.assertThat(query.getParameterSource().getValue("age")).isEqualTo(age); softly.assertThat(query.getParameterSource(Escaper.DEFAULT).getValue("age")).isEqualTo(age);
}); });
} }
@ -165,7 +166,7 @@ public class PartTreeJdbcQueryUnitTests {
softly.assertThat(query.getQuery()) softly.assertThat(query.getQuery())
.isEqualTo(BASE_SELECT + " WHERE " + TABLE + ".\"HOBBY_REFERENCE\" = :hobby_reference"); .isEqualTo(BASE_SELECT + " WHERE " + TABLE + ".\"HOBBY_REFERENCE\" = :hobby_reference");
softly.assertThat(query.getParameterSource().getValue("hobby_reference")).isEqualTo("twentythree"); softly.assertThat(query.getParameterSource(Escaper.DEFAULT).getValue("hobby_reference")).isEqualTo("twentythree");
}); });
} }
@ -182,7 +183,7 @@ public class PartTreeJdbcQueryUnitTests {
softly.assertThat(query.getQuery()) softly.assertThat(query.getQuery())
.isEqualTo(BASE_SELECT + " WHERE " + TABLE + ".\"HOBBY_REFERENCE\" = :hobby_reference"); .isEqualTo(BASE_SELECT + " WHERE " + TABLE + ".\"HOBBY_REFERENCE\" = :hobby_reference");
softly.assertThat(query.getParameterSource().getValue("hobby_reference")).isEqualTo("twentythree"); softly.assertThat(query.getParameterSource(Escaper.DEFAULT).getValue("hobby_reference")).isEqualTo("twentythree");
}); });
} }
@ -270,8 +271,8 @@ public class PartTreeJdbcQueryUnitTests {
softly.assertThat(query.getQuery()) softly.assertThat(query.getQuery())
.isEqualTo(BASE_SELECT + " WHERE " + TABLE + ".\"DATE_OF_BIRTH\" BETWEEN :date_of_birth AND :date_of_birth1"); .isEqualTo(BASE_SELECT + " WHERE " + TABLE + ".\"DATE_OF_BIRTH\" BETWEEN :date_of_birth AND :date_of_birth1");
softly.assertThat(query.getParameterSource().getValue("date_of_birth")).isEqualTo(from); softly.assertThat(query.getParameterSource(Escaper.DEFAULT).getValue("date_of_birth")).isEqualTo(from);
softly.assertThat(query.getParameterSource().getValue("date_of_birth1")).isEqualTo(to); softly.assertThat(query.getParameterSource(Escaper.DEFAULT).getValue("date_of_birth1")).isEqualTo(to);
}); });
} }
@ -405,7 +406,7 @@ public class PartTreeJdbcQueryUnitTests {
ParametrizedQuery query = jdbcQuery.createQuery(accessor, returnedType); ParametrizedQuery query = jdbcQuery.createQuery(accessor, returnedType);
assertThat(query.getQuery()).isEqualTo(BASE_SELECT + " WHERE " + TABLE + ".\"FIRST_NAME\" LIKE :first_name"); assertThat(query.getQuery()).isEqualTo(BASE_SELECT + " WHERE " + TABLE + ".\"FIRST_NAME\" LIKE :first_name");
assertThat(query.getParameterSource().getValue("first_name")).isEqualTo("Jo%"); assertThat(query.getParameterSource(Escaper.DEFAULT).getValue("first_name")).isEqualTo("Jo%");
} }
@Test // DATAJDBC-318 @Test // DATAJDBC-318
@ -428,7 +429,7 @@ public class PartTreeJdbcQueryUnitTests {
ParametrizedQuery query = jdbcQuery.createQuery(accessor, returnedType); ParametrizedQuery query = jdbcQuery.createQuery(accessor, returnedType);
assertThat(query.getQuery()).isEqualTo(BASE_SELECT + " WHERE " + TABLE + ".\"FIRST_NAME\" LIKE :first_name"); assertThat(query.getQuery()).isEqualTo(BASE_SELECT + " WHERE " + TABLE + ".\"FIRST_NAME\" LIKE :first_name");
assertThat(query.getParameterSource().getValue("first_name")).isEqualTo("%hn"); assertThat(query.getParameterSource(Escaper.DEFAULT).getValue("first_name")).isEqualTo("%hn");
} }
@Test // DATAJDBC-318 @Test // DATAJDBC-318
@ -451,7 +452,7 @@ public class PartTreeJdbcQueryUnitTests {
ParametrizedQuery query = jdbcQuery.createQuery(accessor, returnedType); ParametrizedQuery query = jdbcQuery.createQuery(accessor, returnedType);
assertThat(query.getQuery()).isEqualTo(BASE_SELECT + " WHERE " + TABLE + ".\"FIRST_NAME\" LIKE :first_name"); assertThat(query.getQuery()).isEqualTo(BASE_SELECT + " WHERE " + TABLE + ".\"FIRST_NAME\" LIKE :first_name");
assertThat(query.getParameterSource().getValue("first_name")).isEqualTo("%oh%"); assertThat(query.getParameterSource(Escaper.DEFAULT).getValue("first_name")).isEqualTo("%oh%");
} }
@Test // DATAJDBC-318 @Test // DATAJDBC-318
@ -474,7 +475,7 @@ public class PartTreeJdbcQueryUnitTests {
ParametrizedQuery query = jdbcQuery.createQuery(accessor, returnedType); ParametrizedQuery query = jdbcQuery.createQuery(accessor, returnedType);
assertThat(query.getQuery()).isEqualTo(BASE_SELECT + " WHERE " + TABLE + ".\"FIRST_NAME\" NOT LIKE :first_name"); assertThat(query.getQuery()).isEqualTo(BASE_SELECT + " WHERE " + TABLE + ".\"FIRST_NAME\" NOT LIKE :first_name");
assertThat(query.getParameterSource().getValue("first_name")).isEqualTo("%oh%"); assertThat(query.getParameterSource(Escaper.DEFAULT).getValue("first_name")).isEqualTo("%oh%");
} }
@Test // DATAJDBC-318 @Test // DATAJDBC-318
@ -638,8 +639,8 @@ public class PartTreeJdbcQueryUnitTests {
.contains(TABLE + ".\"USER_STREET\" = :user_street", // .contains(TABLE + ".\"USER_STREET\" = :user_street", //
" AND ", // " AND ", //
TABLE + ".\"USER_CITY\" = :user_city"); TABLE + ".\"USER_CITY\" = :user_city");
assertThat(query.getParameterSource().getValue("user_street")).isEqualTo("Hello"); assertThat(query.getParameterSource(Escaper.DEFAULT).getValue("user_street")).isEqualTo("Hello");
assertThat(query.getParameterSource().getValue("user_city")).isEqualTo("World"); assertThat(query.getParameterSource(Escaper.DEFAULT).getValue("user_city")).isEqualTo("World");
} }
@Test // DATAJDBC-318 @Test // DATAJDBC-318
@ -653,7 +654,7 @@ public class PartTreeJdbcQueryUnitTests {
String expectedSql = BASE_SELECT + " WHERE " + TABLE + ".\"USER_STREET\" = :user_street"; String expectedSql = BASE_SELECT + " WHERE " + TABLE + ".\"USER_STREET\" = :user_street";
assertThat(query.getQuery()).isEqualTo(expectedSql); assertThat(query.getQuery()).isEqualTo(expectedSql);
assertThat(query.getParameterSource().getValue("user_street")).isEqualTo("Hello"); assertThat(query.getParameterSource(Escaper.DEFAULT).getValue("user_street")).isEqualTo("Hello");
} }
@Test // DATAJDBC-534 @Test // DATAJDBC-534

Loading…
Cancel
Save