Polishing.
Simplify ValueFunction mapping. Remove invariants of findBy SQL generation in favor of the Condition-based variant. Reduce visibility. Change return value of AggregateReader to List See #1601 Original pull request: #1617
This commit is contained in:
committed by
Mark Paluch
parent
0fdeaebbee
commit
f3bc0af8c4
@@ -18,16 +18,16 @@ package org.springframework.data.jdbc.core.convert;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
import org.springframework.dao.IncorrectResultSizeDataAccessException;
|
||||
import org.springframework.data.relational.core.dialect.Dialect;
|
||||
import org.springframework.data.relational.core.mapping.AggregatePath;
|
||||
import org.springframework.data.relational.core.mapping.RelationalPersistentEntity;
|
||||
import org.springframework.data.relational.core.query.Criteria;
|
||||
import org.springframework.data.relational.core.query.CriteriaDefinition;
|
||||
import org.springframework.data.relational.core.query.Query;
|
||||
import org.springframework.data.relational.core.sql.Condition;
|
||||
@@ -36,6 +36,7 @@ import org.springframework.data.relational.core.sqlgeneration.AliasFactory;
|
||||
import org.springframework.data.relational.core.sqlgeneration.SingleQuerySqlGenerator;
|
||||
import org.springframework.data.relational.core.sqlgeneration.SqlGenerator;
|
||||
import org.springframework.data.relational.domain.RowDocument;
|
||||
import org.springframework.data.util.Streamable;
|
||||
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
|
||||
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
|
||||
import org.springframework.lang.Nullable;
|
||||
@@ -43,7 +44,7 @@ import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Reads complete Aggregates from the database, by generating appropriate SQL using a {@link SingleQuerySqlGenerator}
|
||||
* through {@link org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate}. Results are converterd into an
|
||||
* through {@link org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate}. Results are converted into an
|
||||
* intermediate {@link RowDocumentResultSetExtractor RowDocument} and mapped via
|
||||
* {@link org.springframework.data.relational.core.conversion.RelationalConverter#read(Class, RowDocument)}.
|
||||
*
|
||||
@@ -55,7 +56,8 @@ import org.springframework.util.Assert;
|
||||
class AggregateReader<T> {
|
||||
|
||||
private final RelationalPersistentEntity<T> aggregate;
|
||||
private final org.springframework.data.relational.core.sqlgeneration.SqlGenerator sqlGenerator;
|
||||
private final Table table;
|
||||
private final SqlGenerator sqlGenerator;
|
||||
private final JdbcConverter converter;
|
||||
private final NamedParameterJdbcOperations jdbcTemplate;
|
||||
private final RowDocumentResultSetExtractor extractor;
|
||||
@@ -66,6 +68,7 @@ class AggregateReader<T> {
|
||||
this.converter = converter;
|
||||
this.aggregate = aggregate;
|
||||
this.jdbcTemplate = jdbcTemplate;
|
||||
this.table = Table.create(aggregate.getQualifiedTableName());
|
||||
|
||||
this.sqlGenerator = new CachingSqlGenerator(
|
||||
new SingleQuerySqlGenerator(converter.getMappingContext(), aliasFactory, dialect, aggregate));
|
||||
@@ -74,62 +77,58 @@ class AggregateReader<T> {
|
||||
createPathToColumnMapping(aliasFactory));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public T findById(Object id) {
|
||||
|
||||
Query query = Query.query(Criteria.where(aggregate.getRequiredIdProperty().getName()).is(id)).limit(1);
|
||||
|
||||
return findOne(query);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public T findOne(Query query) {
|
||||
|
||||
MapSqlParameterSource parameterSource = new MapSqlParameterSource();
|
||||
Condition condition = createCondition(query, parameterSource);
|
||||
|
||||
return jdbcTemplate.query(sqlGenerator.findAll(condition), parameterSource, this::extractZeroOrOne);
|
||||
}
|
||||
|
||||
public List<T> findAll() {
|
||||
return jdbcTemplate.query(sqlGenerator.findAll(), this::extractAll);
|
||||
}
|
||||
|
||||
public List<T> findAllById(Iterable<?> ids) {
|
||||
|
||||
Collection<?> identifiers = ids instanceof Collection<?> idl ? idl : Streamable.of(ids).toList();
|
||||
Query query = Query.query(Criteria.where(aggregate.getRequiredIdProperty().getName()).in(identifiers)).limit(1);
|
||||
|
||||
return findAll(query);
|
||||
}
|
||||
|
||||
public List<T> findAll(Query query) {
|
||||
|
||||
MapSqlParameterSource parameterSource = new MapSqlParameterSource();
|
||||
Condition condition = createCondition(query, parameterSource);
|
||||
return jdbcTemplate.query(sqlGenerator.findAll(condition), parameterSource, this::extractAll);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public T findById(Object id) {
|
||||
|
||||
id = converter.writeValue(id, aggregate.getRequiredIdProperty().getTypeInformation());
|
||||
|
||||
return jdbcTemplate.query(sqlGenerator.findById(), Map.of("id", id), this::extractZeroOrOne);
|
||||
}
|
||||
|
||||
public Iterable<T> findAllById(Iterable<?> ids) {
|
||||
|
||||
List<Object> convertedIds = new ArrayList<>();
|
||||
for (Object id : ids) {
|
||||
convertedIds.add(converter.writeValue(id, aggregate.getRequiredIdProperty().getTypeInformation()));
|
||||
}
|
||||
|
||||
return jdbcTemplate.query(sqlGenerator.findAllById(), Map.of("ids", convertedIds), this::extractAll);
|
||||
}
|
||||
|
||||
public Iterable<T> findAllBy(Query query) {
|
||||
|
||||
MapSqlParameterSource parameterSource = new MapSqlParameterSource();
|
||||
BiFunction<Table, RelationalPersistentEntity, Condition> condition = createConditionSource(query, parameterSource);
|
||||
return jdbcTemplate.query(sqlGenerator.findAllByCondition(condition), parameterSource, this::extractAll);
|
||||
}
|
||||
|
||||
public Optional<T> findOneByQuery(Query query) {
|
||||
|
||||
MapSqlParameterSource parameterSource = new MapSqlParameterSource();
|
||||
BiFunction<Table, RelationalPersistentEntity, Condition> condition = createConditionSource(query, parameterSource);
|
||||
|
||||
return Optional.ofNullable(
|
||||
jdbcTemplate.query(sqlGenerator.findAllByCondition(condition), parameterSource, this::extractZeroOrOne));
|
||||
}
|
||||
|
||||
private BiFunction<Table, RelationalPersistentEntity, Condition> createConditionSource(Query query, MapSqlParameterSource parameterSource) {
|
||||
private Condition createCondition(Query query, MapSqlParameterSource parameterSource) {
|
||||
|
||||
QueryMapper queryMapper = new QueryMapper(converter);
|
||||
|
||||
BiFunction<Table, RelationalPersistentEntity, Condition> condition = (table, aggregate) -> {
|
||||
Optional<CriteriaDefinition> criteria = query.getCriteria();
|
||||
return criteria
|
||||
.map(criteriaDefinition -> queryMapper.getMappedObject(parameterSource, criteriaDefinition, table, aggregate))
|
||||
.orElse(null);
|
||||
};
|
||||
return condition;
|
||||
Optional<CriteriaDefinition> criteria = query.getCriteria();
|
||||
return criteria
|
||||
.map(criteriaDefinition -> queryMapper.getMappedObject(parameterSource, criteriaDefinition, table, aggregate))
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts a list of aggregates from the given {@link ResultSet} by utilizing the
|
||||
* {@link RowDocumentResultSetExtractor} and the {@link JdbcConverter}. When used as a method reference this conforms
|
||||
* to the {@link org.springframework.jdbc.core.ResultSetExtractor} contract.
|
||||
*
|
||||
*
|
||||
* @param rs the {@link ResultSet} from which to extract the data. Must not be {(}@literal null}.
|
||||
* @return a {@code List} of aggregates, fully converted.
|
||||
* @throws SQLException
|
||||
@@ -195,21 +194,15 @@ class AggregateReader<T> {
|
||||
* @author Jens Schauder
|
||||
* @since 3.2
|
||||
*/
|
||||
static class CachingSqlGenerator implements org.springframework.data.relational.core.sqlgeneration.SqlGenerator {
|
||||
|
||||
private final org.springframework.data.relational.core.sqlgeneration.SqlGenerator delegate;
|
||||
static class CachingSqlGenerator implements SqlGenerator {
|
||||
|
||||
private final SqlGenerator delegate;
|
||||
private final String findAll;
|
||||
private final String findById;
|
||||
private final String findAllById;
|
||||
|
||||
public CachingSqlGenerator(SqlGenerator delegate) {
|
||||
|
||||
this.delegate = delegate;
|
||||
|
||||
findAll = delegate.findAll();
|
||||
findById = delegate.findById();
|
||||
findAllById = delegate.findAllById();
|
||||
this.findAll = delegate.findAll();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -218,18 +211,8 @@ class AggregateReader<T> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String findById() {
|
||||
return findById;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String findAllById() {
|
||||
return findAllById;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String findAllByCondition(BiFunction<Table, RelationalPersistentEntity, Condition> conditionSource) {
|
||||
return delegate.findAllByCondition(conditionSource);
|
||||
public String findAll(@Nullable Condition condition) {
|
||||
return delegate.findAll(condition);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -22,8 +22,6 @@ import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.jdbc.core.mapping.JdbcValue;
|
||||
@@ -35,7 +33,6 @@ import org.springframework.data.mapping.PropertyReferenceException;
|
||||
import org.springframework.data.mapping.context.InvalidPersistentPropertyPath;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.data.relational.core.dialect.Dialect;
|
||||
import org.springframework.data.relational.core.dialect.Escaper;
|
||||
import org.springframework.data.relational.core.mapping.RelationalPersistentEntity;
|
||||
import org.springframework.data.relational.core.mapping.RelationalPersistentProperty;
|
||||
import org.springframework.data.relational.core.query.CriteriaDefinition;
|
||||
@@ -77,7 +74,7 @@ public class QueryMapper {
|
||||
Assert.notNull(converter, "JdbcConverter must not be null");
|
||||
|
||||
this.converter = converter;
|
||||
this.mappingContext = (MappingContext) converter.getMappingContext();
|
||||
this.mappingContext = converter.getMappingContext();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -310,7 +307,7 @@ public class QueryMapper {
|
||||
sqlType = getTypeHint(mappedValue, actualType.getType(), settableValue);
|
||||
} else if (criteria.getValue() instanceof ValueFunction valueFunction) {
|
||||
|
||||
mappedValue = valueFunction.transform(v -> convertValue(comparator, v, propertyField.getTypeHint()));
|
||||
mappedValue = valueFunction.map(v -> convertValue(comparator, v, propertyField.getTypeHint()));
|
||||
sqlType = propertyField.getSqlType();
|
||||
|
||||
} else if (propertyField instanceof MetadataBackedField metadataBackedField //
|
||||
|
||||
@@ -77,13 +77,12 @@ class SingleQueryDataAccessStrategy implements ReadingDataAccessStrategy {
|
||||
|
||||
@Override
|
||||
public <T> Optional<T> findOne(Query query, Class<T> domainType) {
|
||||
return getReader(domainType).findOneByQuery(query);
|
||||
return Optional.ofNullable(getReader(domainType).findOne(query));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Iterable<T> findAll(Query query, Class<T> domainType) {
|
||||
|
||||
return getReader(domainType).findAllBy(query);
|
||||
return getReader(domainType).findAll(query);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -87,6 +87,7 @@ class SingleQueryFallbackDataAccessStrategy extends DelegatingDataAccessStrategy
|
||||
return super.findAllById(ids, domainType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Optional<T> findOne(Query query, Class<T> domainType) {
|
||||
|
||||
if (isSingleSelectQuerySupported(domainType) && isSingleSelectQuerySupported(query)) {
|
||||
@@ -137,11 +138,6 @@ class SingleQueryFallbackDataAccessStrategy extends DelegatingDataAccessStrategy
|
||||
|
||||
referenceFound = true;
|
||||
}
|
||||
|
||||
// AggregateReferences aren't supported yet
|
||||
// if (property.isAssociation()) {
|
||||
// return false;
|
||||
// }
|
||||
}
|
||||
return true;
|
||||
|
||||
|
||||
@@ -21,12 +21,13 @@ 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.
|
||||
*
|
||||
* This {@link SqlParameterSource} will apply escaping to its values.
|
||||
*
|
||||
* @author Jens Schauder
|
||||
* @since 3.2
|
||||
*/
|
||||
public class EscapingParameterSource implements SqlParameterSource {
|
||||
class EscapingParameterSource implements SqlParameterSource {
|
||||
|
||||
private final SqlParameterSource parameterSource;
|
||||
private final Escaper escaper;
|
||||
|
||||
|
||||
@@ -15,12 +15,12 @@
|
||||
*/
|
||||
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;
|
||||
|
||||
/**
|
||||
* 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 Jens Schauder
|
||||
@@ -41,13 +41,12 @@ class ParametrizedQuery {
|
||||
return query;
|
||||
}
|
||||
|
||||
SqlParameterSource getParameterSource(Escaper escaper) {
|
||||
return new EscapingParameterSource(parameterSource, escaper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.query;
|
||||
}
|
||||
|
||||
public SqlParameterSource getParameterSource(Escaper escaper) {
|
||||
|
||||
return new EscapingParameterSource(parameterSource, escaper);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user