Introduce AggregatePath.
AggregatePath replaces PersistentPropertyPathExtension. It gets created and cached by the RelationalMappingContext, which should be more efficient and certainly looks nicer. Closes #1525 Original pull request #1486
This commit is contained in:
@@ -15,16 +15,7 @@
|
||||
*/
|
||||
package org.springframework.data.jdbc.core;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@@ -38,11 +29,12 @@ import org.springframework.data.jdbc.core.convert.JdbcIdentifierBuilder;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.data.mapping.PersistentPropertyPath;
|
||||
import org.springframework.data.mapping.PersistentPropertyPathAccessor;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.data.relational.core.conversion.DbAction;
|
||||
import org.springframework.data.relational.core.conversion.DbActionExecutionResult;
|
||||
import org.springframework.data.relational.core.conversion.IdValueSource;
|
||||
import org.springframework.data.relational.core.mapping.AggregatePath;
|
||||
import org.springframework.data.relational.core.mapping.PersistentPropertyPathExtension;
|
||||
import org.springframework.data.relational.core.mapping.RelationalMappingContext;
|
||||
import org.springframework.data.relational.core.mapping.RelationalPersistentEntity;
|
||||
import org.springframework.data.relational.core.mapping.RelationalPersistentProperty;
|
||||
import org.springframework.data.relational.core.sql.LockMode;
|
||||
@@ -65,7 +57,7 @@ class JdbcAggregateChangeExecutionContext {
|
||||
private static final String UPDATE_FAILED = "Failed to update entity [%s]; Id [%s] not found in database";
|
||||
private static final String UPDATE_FAILED_OPTIMISTIC_LOCKING = "Failed to update entity [%s]; The entity was updated since it was rea or it isn't in the database at all";
|
||||
|
||||
private final MappingContext<? extends RelationalPersistentEntity<?>, ? extends RelationalPersistentProperty> context;
|
||||
private final RelationalMappingContext context;
|
||||
private final JdbcConverter converter;
|
||||
private final DataAccessStrategy accessStrategy;
|
||||
|
||||
@@ -184,12 +176,11 @@ class JdbcAggregateChangeExecutionContext {
|
||||
Object id = getParentId(action);
|
||||
|
||||
JdbcIdentifierBuilder identifier = JdbcIdentifierBuilder //
|
||||
.forBackReferences(converter, new PersistentPropertyPathExtension(context, action.getPropertyPath()), id);
|
||||
.forBackReferences(converter, context.getAggregatePath(action.getPropertyPath()), id);
|
||||
|
||||
for (Map.Entry<PersistentPropertyPath<RelationalPersistentProperty>, Object> qualifier : action.getQualifiers()
|
||||
.entrySet()) {
|
||||
identifier = identifier.withQualifier(new PersistentPropertyPathExtension(context, qualifier.getKey()),
|
||||
qualifier.getValue());
|
||||
identifier = identifier.withQualifier(context.getAggregatePath(qualifier.getKey()), qualifier.getValue());
|
||||
}
|
||||
|
||||
return identifier.build();
|
||||
@@ -197,26 +188,22 @@ class JdbcAggregateChangeExecutionContext {
|
||||
|
||||
private Object getParentId(DbAction.WithDependingOn<?> action) {
|
||||
|
||||
PersistentPropertyPathExtension path = new PersistentPropertyPathExtension(context, action.getPropertyPath());
|
||||
PersistentPropertyPathExtension idPath = path.getIdDefiningParentPath();
|
||||
|
||||
DbAction.WithEntity<?> idOwningAction = getIdOwningAction(action, idPath);
|
||||
DbAction.WithEntity<?> idOwningAction = getIdOwningAction(action, context.getAggregatePath(action.getPropertyPath()).getIdDefiningParentPath());
|
||||
|
||||
return getPotentialGeneratedIdFrom(idOwningAction);
|
||||
}
|
||||
|
||||
private DbAction.WithEntity<?> getIdOwningAction(DbAction.WithEntity<?> action,
|
||||
PersistentPropertyPathExtension idPath) {
|
||||
private DbAction.WithEntity<?> getIdOwningAction(DbAction.WithEntity<?> action, AggregatePath idPath) {
|
||||
|
||||
if (!(action instanceof DbAction.WithDependingOn<?> withDependingOn)) {
|
||||
|
||||
Assert.state(idPath.getLength() == 0,
|
||||
Assert.state(idPath.isRoot(),
|
||||
"When the id path is not empty the id providing action should be of type WithDependingOn");
|
||||
|
||||
return action;
|
||||
}
|
||||
|
||||
if (idPath.matches(withDependingOn.getPropertyPath())) {
|
||||
if (idPath.equals(context.getAggregatePath(withDependingOn.getPropertyPath()))) {
|
||||
return action;
|
||||
}
|
||||
|
||||
|
||||
@@ -47,7 +47,8 @@ import org.springframework.data.mapping.model.SpELExpressionEvaluator;
|
||||
import org.springframework.data.mapping.model.SpELExpressionParameterValueProvider;
|
||||
import org.springframework.data.relational.core.conversion.BasicRelationalConverter;
|
||||
import org.springframework.data.relational.core.conversion.RelationalConverter;
|
||||
import org.springframework.data.relational.core.mapping.PersistentPropertyPathExtension;
|
||||
import org.springframework.data.relational.core.mapping.AggregatePath;
|
||||
import org.springframework.data.relational.core.mapping.RelationalMappingContext;
|
||||
import org.springframework.data.relational.core.mapping.RelationalPersistentEntity;
|
||||
import org.springframework.data.relational.core.mapping.RelationalPersistentProperty;
|
||||
import org.springframework.data.relational.core.sql.IdentifierProcessing;
|
||||
@@ -86,14 +87,14 @@ public class BasicJdbcConverter extends BasicRelationalConverter implements Jdbc
|
||||
* Creates a new {@link BasicRelationalConverter} given {@link MappingContext} and a
|
||||
* {@link JdbcTypeFactory#unsupported() no-op type factory} throwing {@link UnsupportedOperationException} on type
|
||||
* creation. Use
|
||||
* {@link #BasicJdbcConverter(MappingContext, RelationResolver, CustomConversions, JdbcTypeFactory, IdentifierProcessing)}
|
||||
* {@link #BasicJdbcConverter(RelationalMappingContext, RelationResolver, CustomConversions, JdbcTypeFactory, IdentifierProcessing)}
|
||||
* (MappingContext, RelationResolver, JdbcTypeFactory)} to convert arrays and large objects into JDBC-specific types.
|
||||
*
|
||||
* @param context must not be {@literal null}.
|
||||
* @param relationResolver used to fetch additional relations from the database. Must not be {@literal null}.
|
||||
*/
|
||||
public BasicJdbcConverter(
|
||||
MappingContext<? extends RelationalPersistentEntity<?>, ? extends RelationalPersistentProperty> context,
|
||||
RelationalMappingContext context,
|
||||
RelationResolver relationResolver) {
|
||||
|
||||
super(context, new JdbcCustomConversions());
|
||||
@@ -116,7 +117,7 @@ public class BasicJdbcConverter extends BasicRelationalConverter implements Jdbc
|
||||
* @since 2.0
|
||||
*/
|
||||
public BasicJdbcConverter(
|
||||
MappingContext<? extends RelationalPersistentEntity<?>, ? extends RelationalPersistentProperty> context,
|
||||
RelationalMappingContext context,
|
||||
RelationResolver relationResolver, CustomConversions conversions, JdbcTypeFactory typeFactory,
|
||||
IdentifierProcessing identifierProcessing) {
|
||||
|
||||
@@ -300,12 +301,13 @@ public class BasicJdbcConverter extends BasicRelationalConverter implements Jdbc
|
||||
|
||||
@Override
|
||||
public <T> T mapRow(RelationalPersistentEntity<T> entity, ResultSet resultSet, Object key) {
|
||||
return new ReadingContext<T>(new PersistentPropertyPathExtension(getMappingContext(), entity),
|
||||
return new ReadingContext<T>(getMappingContext().getAggregatePath( entity),
|
||||
new ResultSetAccessor(resultSet), Identifier.empty(), key).mapRow();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public <T> T mapRow(PersistentPropertyPathExtension path, ResultSet resultSet, Identifier identifier, Object key) {
|
||||
public <T> T mapRow(AggregatePath path, ResultSet resultSet, Identifier identifier, Object key) {
|
||||
return new ReadingContext<T>(path, new ResultSetAccessor(resultSet), identifier, key).mapRow();
|
||||
}
|
||||
|
||||
@@ -350,8 +352,8 @@ public class BasicJdbcConverter extends BasicRelationalConverter implements Jdbc
|
||||
|
||||
private final RelationalPersistentEntity<T> entity;
|
||||
|
||||
private final PersistentPropertyPathExtension rootPath;
|
||||
private final PersistentPropertyPathExtension path;
|
||||
private final AggregatePath rootPath;
|
||||
private final AggregatePath path;
|
||||
private final Identifier identifier;
|
||||
private final Object key;
|
||||
|
||||
@@ -360,7 +362,7 @@ public class BasicJdbcConverter extends BasicRelationalConverter implements Jdbc
|
||||
private final ResultSetAccessor accessor;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private ReadingContext(PersistentPropertyPathExtension rootPath, ResultSetAccessor accessor, Identifier identifier,
|
||||
private ReadingContext(AggregatePath rootPath, ResultSetAccessor accessor, Identifier identifier,
|
||||
Object key) {
|
||||
RelationalPersistentEntity<T> entity = (RelationalPersistentEntity<T>) rootPath.getLeafEntity();
|
||||
|
||||
@@ -368,7 +370,7 @@ public class BasicJdbcConverter extends BasicRelationalConverter implements Jdbc
|
||||
|
||||
this.entity = entity;
|
||||
this.rootPath = rootPath;
|
||||
this.path = new PersistentPropertyPathExtension(getMappingContext(), this.entity);
|
||||
this.path = getMappingContext().getAggregatePath( this.entity);
|
||||
this.identifier = identifier;
|
||||
this.key = key;
|
||||
this.propertyValueProvider = new JdbcPropertyValueProvider(path, accessor);
|
||||
@@ -376,10 +378,11 @@ public class BasicJdbcConverter extends BasicRelationalConverter implements Jdbc
|
||||
this.accessor = accessor;
|
||||
}
|
||||
|
||||
private ReadingContext(RelationalPersistentEntity<T> entity, PersistentPropertyPathExtension rootPath,
|
||||
PersistentPropertyPathExtension path, Identifier identifier, Object key,
|
||||
private ReadingContext(RelationalPersistentEntity<T> entity, AggregatePath rootPath,
|
||||
AggregatePath path, Identifier identifier, Object key,
|
||||
JdbcPropertyValueProvider propertyValueProvider,
|
||||
JdbcBackReferencePropertyValueProvider backReferencePropertyValueProvider, ResultSetAccessor accessor) {
|
||||
|
||||
this.entity = entity;
|
||||
this.rootPath = rootPath;
|
||||
this.path = path;
|
||||
@@ -393,7 +396,7 @@ public class BasicJdbcConverter extends BasicRelationalConverter implements Jdbc
|
||||
private <S> ReadingContext<S> extendBy(RelationalPersistentProperty property) {
|
||||
return new ReadingContext<>(
|
||||
(RelationalPersistentEntity<S>) getMappingContext().getRequiredPersistentEntity(property.getActualType()),
|
||||
rootPath.extendBy(property), path.extendBy(property), identifier, key,
|
||||
rootPath.append(property), path.append(property), identifier, key,
|
||||
propertyValueProvider.extendBy(property), backReferencePropertyValueProvider.extendBy(property), accessor);
|
||||
}
|
||||
|
||||
@@ -453,10 +456,10 @@ public class BasicJdbcConverter extends BasicRelationalConverter implements Jdbc
|
||||
private Iterable<Object> resolveRelation(@Nullable Object id, RelationalPersistentProperty property) {
|
||||
|
||||
Identifier identifier = id == null //
|
||||
? this.identifier.withPart(rootPath.getQualifierColumn(), key, Object.class) //
|
||||
: Identifier.of(rootPath.extendBy(property).getReverseColumnName(), id, Object.class);
|
||||
? this.identifier.withPart(rootPath.getTableInfo().qualifierColumnInfo().name(), key, Object.class) //
|
||||
: Identifier.of(rootPath.append(property).getTableInfo().reverseColumnInfo().name(), id, Object.class);
|
||||
|
||||
PersistentPropertyPath<? extends RelationalPersistentProperty> propertyPath = path.extendBy(property)
|
||||
PersistentPropertyPath<? extends RelationalPersistentProperty> propertyPath = path.append(property)
|
||||
.getRequiredPersistentPropertyPath();
|
||||
|
||||
return relationResolver.findAllByPath(identifier, propertyPath);
|
||||
|
||||
@@ -28,12 +28,12 @@ import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.mapping.PersistentPropertyPath;
|
||||
import org.springframework.data.relational.core.conversion.IdValueSource;
|
||||
import org.springframework.data.relational.core.mapping.AggregatePath;
|
||||
import org.springframework.data.relational.core.mapping.PersistentPropertyPathExtension;
|
||||
import org.springframework.data.relational.core.mapping.RelationalMappingContext;
|
||||
import org.springframework.data.relational.core.mapping.RelationalPersistentEntity;
|
||||
import org.springframework.data.relational.core.mapping.RelationalPersistentProperty;
|
||||
import org.springframework.data.relational.core.query.Query;
|
||||
import org.springframework.data.relational.core.sql.IdentifierProcessing;
|
||||
import org.springframework.data.relational.core.sql.LockMode;
|
||||
import org.springframework.data.relational.core.sql.SqlIdentifier;
|
||||
import org.springframework.jdbc.core.RowMapper;
|
||||
@@ -297,8 +297,8 @@ public class DefaultDataAccessStrategy implements DataAccessStrategy {
|
||||
Assert.notNull(identifier, "identifier must not be null");
|
||||
Assert.notNull(propertyPath, "propertyPath must not be null");
|
||||
|
||||
PersistentPropertyPathExtension path = new PersistentPropertyPathExtension(context, propertyPath);
|
||||
Class<?> actualType = path.getActualType();
|
||||
AggregatePath path = context.getAggregatePath(propertyPath);
|
||||
Class<?> actualType = path.getLeafEntity().getType();
|
||||
|
||||
String findAllByProperty = sql(actualType) //
|
||||
.getFindAllByProperty(identifier, propertyPath);
|
||||
@@ -339,8 +339,7 @@ public class DefaultDataAccessStrategy implements DataAccessStrategy {
|
||||
String sqlQuery = sql(domainType).selectByQuery(query, parameterSource);
|
||||
|
||||
try {
|
||||
return Optional.ofNullable(
|
||||
operations.queryForObject(sqlQuery, parameterSource, getEntityRowMapper(domainType)));
|
||||
return Optional.ofNullable(operations.queryForObject(sqlQuery, parameterSource, getEntityRowMapper(domainType)));
|
||||
} catch (EmptyResultDataAccessException e) {
|
||||
return Optional.empty();
|
||||
}
|
||||
@@ -394,14 +393,15 @@ public class DefaultDataAccessStrategy implements DataAccessStrategy {
|
||||
return new EntityRowMapper<>(getRequiredPersistentEntity(domainType), converter);
|
||||
}
|
||||
|
||||
private EntityRowMapper<?> getEntityRowMapper(PersistentPropertyPathExtension path, Identifier identifier) {
|
||||
private EntityRowMapper<?> getEntityRowMapper(AggregatePath path, Identifier identifier) {
|
||||
return new EntityRowMapper<>(path, converter, identifier);
|
||||
}
|
||||
|
||||
private RowMapper<?> getMapEntityRowMapper(PersistentPropertyPathExtension path, Identifier identifier) {
|
||||
private RowMapper<?> getMapEntityRowMapper(AggregatePath path, Identifier identifier) {
|
||||
|
||||
SqlIdentifier keyColumn = path.getQualifierColumn();
|
||||
Assert.notNull(keyColumn, () -> "KeyColumn must not be null for " + path);
|
||||
AggregatePath.ColumnInfo qualifierColumnInfo = path.getTableInfo().qualifierColumnInfo();
|
||||
Assert.notNull(qualifierColumnInfo, () -> "Qualifier column must not be null for " + path);
|
||||
SqlIdentifier keyColumn = qualifierColumnInfo.name();
|
||||
|
||||
return new MapEntityRowMapper<>(path, converter, identifier, keyColumn);
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ package org.springframework.data.jdbc.core.convert;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
|
||||
import org.springframework.data.relational.core.mapping.AggregatePath;
|
||||
import org.springframework.data.relational.core.mapping.PersistentPropertyPathExtension;
|
||||
import org.springframework.data.relational.core.mapping.RelationalPersistentEntity;
|
||||
import org.springframework.jdbc.core.RowMapper;
|
||||
@@ -35,13 +36,28 @@ import org.springframework.jdbc.core.RowMapper;
|
||||
public class EntityRowMapper<T> implements RowMapper<T> {
|
||||
|
||||
private final RelationalPersistentEntity<T> entity;
|
||||
private final PersistentPropertyPathExtension path;
|
||||
private final AggregatePath path;
|
||||
private final JdbcConverter converter;
|
||||
private final Identifier identifier;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @deprecated use {@link EntityRowMapper#EntityRowMapper(AggregatePath, JdbcConverter, Identifier)} instead
|
||||
*/
|
||||
@Deprecated(since = "3.2", forRemoval = true)
|
||||
@SuppressWarnings("unchecked")
|
||||
public EntityRowMapper(PersistentPropertyPathExtension path, JdbcConverter converter, Identifier identifier) {
|
||||
|
||||
this.entity = (RelationalPersistentEntity<T>) path.getLeafEntity();
|
||||
this.path = path.getAggregatePath();
|
||||
this.converter = converter;
|
||||
this.identifier = identifier;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public EntityRowMapper(AggregatePath path, JdbcConverter converter, Identifier identifier) {
|
||||
|
||||
this.entity = (RelationalPersistentEntity<T>) path.getLeafEntity();
|
||||
this.path = path;
|
||||
this.converter = converter;
|
||||
|
||||
@@ -16,9 +16,8 @@
|
||||
package org.springframework.data.jdbc.core.convert;
|
||||
|
||||
import org.springframework.data.mapping.model.PropertyValueProvider;
|
||||
import org.springframework.data.relational.core.mapping.PersistentPropertyPathExtension;
|
||||
import org.springframework.data.relational.core.mapping.AggregatePath;
|
||||
import org.springframework.data.relational.core.mapping.RelationalPersistentProperty;
|
||||
import org.springframework.data.relational.core.sql.IdentifierProcessing;
|
||||
|
||||
/**
|
||||
* {@link PropertyValueProvider} obtaining values from a {@link ResultSetAccessor}. For a given id property it provides
|
||||
@@ -31,14 +30,14 @@ import org.springframework.data.relational.core.sql.IdentifierProcessing;
|
||||
*/
|
||||
class JdbcBackReferencePropertyValueProvider implements PropertyValueProvider<RelationalPersistentProperty> {
|
||||
|
||||
private final PersistentPropertyPathExtension basePath;
|
||||
private final AggregatePath basePath;
|
||||
private final ResultSetAccessor resultSet;
|
||||
|
||||
/**
|
||||
* @param basePath path from the aggregate root relative to which all properties get resolved.
|
||||
* @param resultSet the {@link ResultSetAccessor} from which to obtain the actual values.
|
||||
*/
|
||||
JdbcBackReferencePropertyValueProvider(PersistentPropertyPathExtension basePath, ResultSetAccessor resultSet) {
|
||||
JdbcBackReferencePropertyValueProvider(AggregatePath basePath, ResultSetAccessor resultSet) {
|
||||
|
||||
this.resultSet = resultSet;
|
||||
this.basePath = basePath;
|
||||
@@ -46,10 +45,10 @@ class JdbcBackReferencePropertyValueProvider implements PropertyValueProvider<Re
|
||||
|
||||
@Override
|
||||
public <T> T getPropertyValue(RelationalPersistentProperty property) {
|
||||
return (T) resultSet.getObject(basePath.extendBy(property).getReverseColumnNameAlias().getReference());
|
||||
return (T) resultSet.getObject(basePath.append(property).getTableInfo().reverseColumnInfo().alias().getReference());
|
||||
}
|
||||
|
||||
public JdbcBackReferencePropertyValueProvider extendBy(RelationalPersistentProperty property) {
|
||||
return new JdbcBackReferencePropertyValueProvider(basePath.extendBy(property), resultSet);
|
||||
return new JdbcBackReferencePropertyValueProvider(basePath.append(property), resultSet);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,8 +19,11 @@ import java.sql.ResultSet;
|
||||
import java.sql.SQLType;
|
||||
|
||||
import org.springframework.data.jdbc.core.mapping.JdbcValue;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.data.relational.core.conversion.RelationalConverter;
|
||||
import org.springframework.data.relational.core.mapping.AggregatePath;
|
||||
import org.springframework.data.relational.core.mapping.PersistentPropertyPathExtension;
|
||||
import org.springframework.data.relational.core.mapping.RelationalMappingContext;
|
||||
import org.springframework.data.relational.core.mapping.RelationalPersistentEntity;
|
||||
import org.springframework.data.relational.core.mapping.RelationalPersistentProperty;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
@@ -67,8 +70,24 @@ public interface JdbcConverter extends RelationalConverter {
|
||||
* @param key primary key.
|
||||
* @param <T>
|
||||
* @return
|
||||
* @deprecated use {@link #mapRow(AggregatePath, ResultSet, Identifier, Object)} instead.
|
||||
*/
|
||||
<T> T mapRow(PersistentPropertyPathExtension path, ResultSet resultSet, Identifier identifier, Object key);
|
||||
@Deprecated(since = "3.2", forRemoval = true)
|
||||
default <T> T mapRow(PersistentPropertyPathExtension path, ResultSet resultSet, Identifier identifier, Object key){
|
||||
return mapRow(path.getAggregatePath(), resultSet, identifier, key);
|
||||
};
|
||||
|
||||
/**
|
||||
* Read the current row from {@link ResultSet} to an {@link AggregatePath#getLeafEntity()} entity}.
|
||||
*
|
||||
* @param path path to the owning property.
|
||||
* @param resultSet the {@link ResultSet} to read from.
|
||||
* @param identifier entity identifier.
|
||||
* @param key primary key.
|
||||
* @param <T>
|
||||
* @return
|
||||
*/
|
||||
<T> T mapRow(AggregatePath path, ResultSet resultSet, Identifier identifier, Object key);
|
||||
|
||||
/**
|
||||
* The type to be used to store this property in the database. Multidimensional arrays are unwrapped to reflect a
|
||||
@@ -88,4 +107,7 @@ public interface JdbcConverter extends RelationalConverter {
|
||||
* @since 2.0
|
||||
*/
|
||||
SQLType getTargetSqlType(RelationalPersistentProperty property);
|
||||
|
||||
@Override
|
||||
RelationalMappingContext getMappingContext();
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package org.springframework.data.jdbc.core.convert;
|
||||
|
||||
import org.springframework.data.relational.core.mapping.AggregatePath;
|
||||
import org.springframework.data.relational.core.mapping.PersistentPropertyPathExtension;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
@@ -39,12 +40,23 @@ public class JdbcIdentifierBuilder {
|
||||
|
||||
/**
|
||||
* Creates ParentKeys with backreference for the given path and value of the parents id.
|
||||
*
|
||||
* @deprecated Use {@link #forBackReferences(JdbcConverter, AggregatePath, Object)} instead.
|
||||
*/
|
||||
@Deprecated(since = "3.2", forRemoval = true)
|
||||
public static JdbcIdentifierBuilder forBackReferences(JdbcConverter converter, PersistentPropertyPathExtension path,
|
||||
@Nullable Object value) {
|
||||
return forBackReferences(converter, path.getAggregatePath(), value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates ParentKeys with backreference for the given path and value of the parents id.
|
||||
*/
|
||||
public static JdbcIdentifierBuilder forBackReferences(JdbcConverter converter, AggregatePath path,
|
||||
@Nullable Object value) {
|
||||
|
||||
Identifier identifier = Identifier.of( //
|
||||
path.getReverseColumnName(), //
|
||||
path.getTableInfo().reverseColumnInfo().name(), //
|
||||
value, //
|
||||
converter.getColumnType(path.getIdDefiningParentPath().getRequiredIdProperty()) //
|
||||
);
|
||||
@@ -59,12 +71,26 @@ public class JdbcIdentifierBuilder {
|
||||
* @param value map key or list index qualifying the map identified by {@code path}. Must not be {@literal null}.
|
||||
* @return this builder. Guaranteed to be not {@literal null}.
|
||||
*/
|
||||
@Deprecated
|
||||
public JdbcIdentifierBuilder withQualifier(PersistentPropertyPathExtension path, Object value) {
|
||||
|
||||
return withQualifier(path.getAggregatePath(), value);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adds a qualifier to the identifier to build. A qualifier is a map key or a list index.
|
||||
*
|
||||
* @param path path to the map that gets qualified by {@code value}. Must not be {@literal null}.
|
||||
* @param value map key or list index qualifying the map identified by {@code path}. Must not be {@literal null}.
|
||||
* @return this builder. Guaranteed to be not {@literal null}.
|
||||
*/
|
||||
public JdbcIdentifierBuilder withQualifier(AggregatePath path, Object value) {
|
||||
|
||||
Assert.notNull(path, "Path must not be null");
|
||||
Assert.notNull(value, "Value must not be null");
|
||||
|
||||
identifier = identifier.withPart(path.getQualifierColumn(), value, path.getQualifierColumnType());
|
||||
identifier = identifier.withPart(path.getTableInfo().qualifierColumnInfo().name(), value, path.getTableInfo().qualifierColumnType());
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -16,9 +16,8 @@
|
||||
package org.springframework.data.jdbc.core.convert;
|
||||
|
||||
import org.springframework.data.mapping.model.PropertyValueProvider;
|
||||
import org.springframework.data.relational.core.mapping.PersistentPropertyPathExtension;
|
||||
import org.springframework.data.relational.core.mapping.AggregatePath;
|
||||
import org.springframework.data.relational.core.mapping.RelationalPersistentProperty;
|
||||
import org.springframework.data.relational.core.sql.IdentifierProcessing;
|
||||
|
||||
/**
|
||||
* {@link PropertyValueProvider} obtaining values from a {@link ResultSetAccessor}.
|
||||
@@ -29,15 +28,14 @@ import org.springframework.data.relational.core.sql.IdentifierProcessing;
|
||||
*/
|
||||
class JdbcPropertyValueProvider implements PropertyValueProvider<RelationalPersistentProperty> {
|
||||
|
||||
private final PersistentPropertyPathExtension basePath;
|
||||
private final AggregatePath basePath;
|
||||
private final ResultSetAccessor resultSet;
|
||||
|
||||
/**
|
||||
* @param basePath path from the aggregate root relative to which all properties get resolved.
|
||||
* @param resultSet the {@link ResultSetAccessor} from which to obtain the actual values.
|
||||
*/
|
||||
JdbcPropertyValueProvider(PersistentPropertyPathExtension basePath,
|
||||
ResultSetAccessor resultSet) {
|
||||
JdbcPropertyValueProvider(AggregatePath basePath, ResultSetAccessor resultSet) {
|
||||
|
||||
this.resultSet = resultSet;
|
||||
this.basePath = basePath;
|
||||
@@ -59,10 +57,11 @@ class JdbcPropertyValueProvider implements PropertyValueProvider<RelationalPersi
|
||||
}
|
||||
|
||||
private String getColumnName(RelationalPersistentProperty property) {
|
||||
return basePath.extendBy(property).getColumnAlias().getReference();
|
||||
AggregatePath.ColumnInfo columnInfo = basePath.append(property).getColumnInfo();
|
||||
return columnInfo.alias().getReference();
|
||||
}
|
||||
|
||||
public JdbcPropertyValueProvider extendBy(RelationalPersistentProperty property) {
|
||||
return new JdbcPropertyValueProvider(basePath.extendBy(property), resultSet);
|
||||
return new JdbcPropertyValueProvider(basePath.append(property), resultSet);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import java.sql.SQLException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.data.relational.core.mapping.AggregatePath;
|
||||
import org.springframework.data.relational.core.mapping.PersistentPropertyPathExtension;
|
||||
import org.springframework.data.relational.core.sql.IdentifierProcessing;
|
||||
import org.springframework.data.relational.core.sql.SqlIdentifier;
|
||||
@@ -35,12 +36,13 @@ import org.springframework.jdbc.core.RowMapper;
|
||||
*/
|
||||
class MapEntityRowMapper<T> implements RowMapper<Map.Entry<Object, T>> {
|
||||
|
||||
private final PersistentPropertyPathExtension path;
|
||||
private final AggregatePath path;
|
||||
private final JdbcConverter converter;
|
||||
private final Identifier identifier;
|
||||
private final SqlIdentifier keyColumn;
|
||||
|
||||
MapEntityRowMapper(PersistentPropertyPathExtension path, JdbcConverter converter, Identifier identifier, SqlIdentifier keyColumn) {
|
||||
MapEntityRowMapper(AggregatePath path, JdbcConverter converter, Identifier identifier, SqlIdentifier keyColumn) {
|
||||
|
||||
this.path = path;
|
||||
this.converter = converter;
|
||||
this.identifier = identifier;
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
*/
|
||||
package org.springframework.data.jdbc.core.convert;
|
||||
|
||||
import org.springframework.data.relational.core.mapping.PersistentPropertyPathExtension;
|
||||
import org.springframework.data.relational.core.mapping.AggregatePath;
|
||||
import org.springframework.data.relational.core.mapping.RelationalPersistentEntity;
|
||||
import org.springframework.data.relational.core.sql.Column;
|
||||
import org.springframework.data.relational.core.sql.SqlIdentifier;
|
||||
@@ -52,18 +52,20 @@ class SqlContext {
|
||||
return table;
|
||||
}
|
||||
|
||||
Table getTable(PersistentPropertyPathExtension path) {
|
||||
Table getTable(AggregatePath path) {
|
||||
|
||||
SqlIdentifier tableAlias = path.getTableAlias();
|
||||
Table table = Table.create(path.getQualifiedTableName());
|
||||
SqlIdentifier tableAlias = path.getTableInfo().tableAlias();
|
||||
Table table = Table.create(path.getTableInfo().qualifiedTableName());
|
||||
return tableAlias == null ? table : table.as(tableAlias);
|
||||
}
|
||||
|
||||
Column getColumn(PersistentPropertyPathExtension path) {
|
||||
return getTable(path).column(path.getColumnName()).as(path.getColumnAlias());
|
||||
Column getColumn(AggregatePath path) {
|
||||
AggregatePath.ColumnInfo columnInfo = path.getColumnInfo();
|
||||
AggregatePath.ColumnInfo columnInfo1 = path.getColumnInfo();
|
||||
return getTable(path).column(columnInfo1.name()).as(columnInfo.alias());
|
||||
}
|
||||
|
||||
Column getReverseColumn(PersistentPropertyPathExtension path) {
|
||||
return getTable(path).column(path.getReverseColumnName()).as(path.getReverseColumnNameAlias());
|
||||
Column getReverseColumn(AggregatePath path) {
|
||||
return getTable(path).column(path.getTableInfo().reverseColumnInfo().name()).as(path.getTableInfo().reverseColumnInfo().alias());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ import org.springframework.data.mapping.PersistentPropertyPath;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.data.relational.core.dialect.Dialect;
|
||||
import org.springframework.data.relational.core.dialect.RenderContextFactory;
|
||||
import org.springframework.data.relational.core.mapping.PersistentPropertyPathExtension;
|
||||
import org.springframework.data.relational.core.mapping.AggregatePath;
|
||||
import org.springframework.data.relational.core.mapping.RelationalMappingContext;
|
||||
import org.springframework.data.relational.core.mapping.RelationalPersistentEntity;
|
||||
import org.springframework.data.relational.core.mapping.RelationalPersistentProperty;
|
||||
@@ -66,8 +66,13 @@ class SqlGenerator {
|
||||
static final SqlIdentifier IDS_SQL_PARAMETER = SqlIdentifier.unquoted("ids");
|
||||
static final SqlIdentifier ROOT_ID_PARAMETER = SqlIdentifier.unquoted("rootId");
|
||||
|
||||
/**
|
||||
* Length of an aggregate path that is one longer then the root path.
|
||||
*/
|
||||
private static final int FIRST_NON_ROOT_LENTH = 2;
|
||||
|
||||
private final RelationalPersistentEntity<?> entity;
|
||||
private final MappingContext<RelationalPersistentEntity<?>, RelationalPersistentProperty> mappingContext;
|
||||
private final RelationalMappingContext mappingContext;
|
||||
private final RenderContext renderContext;
|
||||
|
||||
private final SqlContext sqlContext;
|
||||
@@ -112,6 +117,40 @@ class SqlGenerator {
|
||||
this.dialect = dialect;
|
||||
}
|
||||
|
||||
/**
|
||||
* When deleting entities there is a fundamental difference between deleting
|
||||
* <ol>
|
||||
* <li>the aggregate root.</li>
|
||||
* <li>a first level entity which still references the root id directly</li>
|
||||
* <li>and all other entities which have to use a subselect to navigate from the id of the aggregate root to something
|
||||
* referenced by the table in question.</li>
|
||||
* </ol>
|
||||
* For paths of the second kind this method returns {@literal true}.
|
||||
*
|
||||
* @param path the path to analyze.
|
||||
* @return If the given path is considered deeply nested.
|
||||
*/
|
||||
private static boolean isFirstNonRoot(AggregatePath path) {
|
||||
return path.getLength() == FIRST_NON_ROOT_LENTH;
|
||||
}
|
||||
|
||||
/**
|
||||
* When deleting entities there is a fundamental difference between deleting
|
||||
* <ol>
|
||||
* <li>the aggregate root.</li>
|
||||
* <li>a first level entity which still references the root id directly</li>
|
||||
* <li>and all other entities which have to use a subselect to navigate from the id of the aggregate root to something
|
||||
* referenced by the table in question.</li>
|
||||
* </ol>
|
||||
* For paths of the third kind this method returns {@literal true}.
|
||||
*
|
||||
* @param path the path to analyze.
|
||||
* @return If the given path is considered deeply nested.
|
||||
*/
|
||||
private static boolean isDeeplyNested(AggregatePath path) {
|
||||
return path.getLength() > FIRST_NON_ROOT_LENTH;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct an IN-condition based on a {@link Select Sub-Select} which selects the ids (or stand-ins for ids) of the
|
||||
* given {@literal path} to those that reference the root entities specified by the {@literal rootCondition}.
|
||||
@@ -121,25 +160,25 @@ class SqlGenerator {
|
||||
* @param filterColumn the column to apply the IN-condition to.
|
||||
* @return the IN condition
|
||||
*/
|
||||
private Condition getSubselectCondition(PersistentPropertyPathExtension path,
|
||||
Function<Column, Condition> rootCondition, Column filterColumn) {
|
||||
private Condition getSubselectCondition(AggregatePath path, Function<Column, Condition> rootCondition,
|
||||
Column filterColumn) {
|
||||
|
||||
PersistentPropertyPathExtension parentPath = path.getParentPath();
|
||||
AggregatePath parentPath = path.getParentPath();
|
||||
|
||||
if (!parentPath.hasIdProperty()) {
|
||||
if (parentPath.getLength() > 1) {
|
||||
if (isDeeplyNested(parentPath)) {
|
||||
return getSubselectCondition(parentPath, rootCondition, filterColumn);
|
||||
}
|
||||
return rootCondition.apply(filterColumn);
|
||||
}
|
||||
|
||||
Table subSelectTable = Table.create(parentPath.getQualifiedTableName());
|
||||
Column idColumn = subSelectTable.column(parentPath.getIdColumnName());
|
||||
Column selectFilterColumn = subSelectTable.column(parentPath.getEffectiveIdColumnName());
|
||||
Table subSelectTable = Table.create(parentPath.getTableInfo().qualifiedTableName());
|
||||
Column idColumn = subSelectTable.column(parentPath.getTableInfo().idColumnName());
|
||||
Column selectFilterColumn = subSelectTable.column(parentPath.getTableInfo().effectiveIdColumnName());
|
||||
|
||||
Condition innerCondition;
|
||||
|
||||
if (parentPath.getLength() == 1) { // if the parent is the root of the path
|
||||
if (isFirstNonRoot(parentPath)) { // if the parent is the root of the path
|
||||
|
||||
// apply the rootCondition
|
||||
innerCondition = rootCondition.apply(selectFilterColumn);
|
||||
@@ -216,9 +255,9 @@ class SqlGenerator {
|
||||
Assert.notNull(parentIdentifier, "identifier must not be null");
|
||||
Assert.notNull(propertyPath, "propertyPath must not be null");
|
||||
|
||||
PersistentPropertyPathExtension path = new PersistentPropertyPathExtension(mappingContext, propertyPath);
|
||||
AggregatePath path = mappingContext.getAggregatePath(propertyPath);
|
||||
|
||||
return getFindAllByProperty(parentIdentifier, path.getQualifierColumn(), path.isOrdered());
|
||||
return getFindAllByProperty(parentIdentifier, path.getTableInfo().qualifierColumnInfo(), path.isOrdered());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -233,7 +272,8 @@ class SqlGenerator {
|
||||
* keyColumn must not be {@code null}.
|
||||
* @return a SQL String.
|
||||
*/
|
||||
String getFindAllByProperty(Identifier parentIdentifier, @Nullable SqlIdentifier keyColumn, boolean ordered) {
|
||||
String getFindAllByProperty(Identifier parentIdentifier, @Nullable AggregatePath.ColumnInfo keyColumn,
|
||||
boolean ordered) {
|
||||
|
||||
Assert.isTrue(keyColumn != null || !ordered,
|
||||
"If the SQL statement should be ordered a keyColumn to order by must be provided");
|
||||
@@ -243,14 +283,14 @@ class SqlGenerator {
|
||||
SelectBuilder.SelectWhere builder = selectBuilder( //
|
||||
keyColumn == null //
|
||||
? Collections.emptyList() //
|
||||
: Collections.singleton(keyColumn) //
|
||||
: Collections.singleton(keyColumn.name()) //
|
||||
);
|
||||
|
||||
Condition condition = buildConditionForBackReference(parentIdentifier, table);
|
||||
SelectBuilder.SelectWhereAndOr withWhereClause = builder.where(condition);
|
||||
|
||||
Select select = ordered //
|
||||
? withWhereClause.orderBy(table.column(keyColumn).as(keyColumn)).build() //
|
||||
? withWhereClause.orderBy(table.column(keyColumn.name()).as(keyColumn.alias())).build() //
|
||||
: withWhereClause.build();
|
||||
|
||||
return render(select);
|
||||
@@ -399,7 +439,7 @@ class SqlGenerator {
|
||||
return render(deleteAll.build());
|
||||
}
|
||||
|
||||
return createDeleteByPathAndCriteria(new PersistentPropertyPathExtension(mappingContext, path), Column::isNotNull);
|
||||
return createDeleteByPathAndCriteria(mappingContext.getAggregatePath(path), Column::isNotNull);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -410,7 +450,7 @@ class SqlGenerator {
|
||||
* @return the statement as a {@link String}. Guaranteed to be not {@literal null}.
|
||||
*/
|
||||
String createDeleteByPath(PersistentPropertyPath<RelationalPersistentProperty> path) {
|
||||
return createDeleteByPathAndCriteria(new PersistentPropertyPathExtension(mappingContext, path),
|
||||
return createDeleteByPathAndCriteria(mappingContext.getAggregatePath(path),
|
||||
filterColumn -> filterColumn.isEqualTo(getBindMarker(ROOT_ID_PARAMETER)));
|
||||
}
|
||||
|
||||
@@ -423,7 +463,7 @@ class SqlGenerator {
|
||||
*/
|
||||
String createDeleteInByPath(PersistentPropertyPath<RelationalPersistentProperty> path) {
|
||||
|
||||
return createDeleteByPathAndCriteria(new PersistentPropertyPathExtension(mappingContext, path),
|
||||
return createDeleteByPathAndCriteria(mappingContext.getAggregatePath(path),
|
||||
filterColumn -> filterColumn.in(getBindMarker(IDS_SQL_PARAMETER)));
|
||||
}
|
||||
|
||||
@@ -480,7 +520,7 @@ class SqlGenerator {
|
||||
for (PersistentPropertyPath<RelationalPersistentProperty> path : mappingContext
|
||||
.findPersistentPropertyPaths(entity.getType(), p -> true)) {
|
||||
|
||||
PersistentPropertyPathExtension extPath = new PersistentPropertyPathExtension(mappingContext, path);
|
||||
AggregatePath extPath = mappingContext.getAggregatePath(path);
|
||||
|
||||
// add a join if necessary
|
||||
Join join = getJoin(extPath);
|
||||
@@ -537,13 +577,13 @@ class SqlGenerator {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@link Column} for {@link PersistentPropertyPathExtension}.
|
||||
* Create a {@link Column} for {@link AggregatePath}.
|
||||
*
|
||||
* @param path the path to the column in question.
|
||||
* @return the statement as a {@link String}. Guaranteed to be not {@literal null}.
|
||||
*/
|
||||
@Nullable
|
||||
Column getColumn(PersistentPropertyPathExtension path) {
|
||||
Column getColumn(AggregatePath path) {
|
||||
|
||||
// an embedded itself doesn't give a column, its members will though.
|
||||
// if there is a collection or map on the path it won't get selected at all, but it will get loaded with a separate
|
||||
@@ -572,7 +612,7 @@ class SqlGenerator {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
Join getJoin(PersistentPropertyPathExtension path) {
|
||||
Join getJoin(AggregatePath path) {
|
||||
|
||||
if (!path.isEntity() || path.isEmbedded() || path.isMultiValued()) {
|
||||
return null;
|
||||
@@ -580,13 +620,13 @@ class SqlGenerator {
|
||||
|
||||
Table currentTable = sqlContext.getTable(path);
|
||||
|
||||
PersistentPropertyPathExtension idDefiningParentPath = path.getIdDefiningParentPath();
|
||||
AggregatePath idDefiningParentPath = path.getIdDefiningParentPath();
|
||||
Table parentTable = sqlContext.getTable(idDefiningParentPath);
|
||||
|
||||
return new Join( //
|
||||
currentTable, //
|
||||
currentTable.column(path.getReverseColumnName()), //
|
||||
parentTable.column(idDefiningParentPath.getIdColumnName()) //
|
||||
currentTable.column(path.getTableInfo().reverseColumnInfo().name()), //
|
||||
parentTable.column(idDefiningParentPath.getTableInfo().idColumnName()) //
|
||||
);
|
||||
}
|
||||
|
||||
@@ -707,18 +747,17 @@ class SqlGenerator {
|
||||
.where(getIdColumn().in(getBindMarker(IDS_SQL_PARAMETER)));
|
||||
}
|
||||
|
||||
private String createDeleteByPathAndCriteria(PersistentPropertyPathExtension path,
|
||||
Function<Column, Condition> rootCondition) {
|
||||
private String createDeleteByPathAndCriteria(AggregatePath path, Function<Column, Condition> rootCondition) {
|
||||
|
||||
Table table = Table.create(path.getQualifiedTableName());
|
||||
Table table = Table.create(path.getTableInfo().qualifiedTableName());
|
||||
|
||||
DeleteBuilder.DeleteWhere builder = Delete.builder() //
|
||||
.from(table);
|
||||
Delete delete;
|
||||
|
||||
Column filterColumn = table.column(path.getReverseColumnName());
|
||||
Column filterColumn = table.column(path.getTableInfo().reverseColumnInfo().name());
|
||||
|
||||
if (path.getLength() == 1) {
|
||||
if (isFirstNonRoot(path)) {
|
||||
|
||||
delete = builder //
|
||||
.where(rootCondition.apply(filterColumn)) //
|
||||
@@ -926,10 +965,10 @@ class SqlGenerator {
|
||||
for (PersistentPropertyPath<RelationalPersistentProperty> path : mappingContext
|
||||
.findPersistentPropertyPaths(entity.getType(), p -> true)) {
|
||||
|
||||
PersistentPropertyPathExtension extPath = new PersistentPropertyPathExtension(mappingContext, path);
|
||||
AggregatePath aggregatePath = mappingContext.getAggregatePath(path);
|
||||
|
||||
// add a join if necessary
|
||||
Join join = getJoin(extPath);
|
||||
Join join = getJoin(aggregatePath);
|
||||
if (join != null) {
|
||||
baseSelect = baseSelect.leftOuterJoin(join.joinTable).on(join.joinColumn).equals(join.parentId);
|
||||
}
|
||||
@@ -960,7 +999,7 @@ class SqlGenerator {
|
||||
for (PersistentPropertyPath<RelationalPersistentProperty> path : mappingContext
|
||||
.findPersistentPropertyPaths(entity.getType(), p -> true)) {
|
||||
|
||||
PersistentPropertyPathExtension extPath = new PersistentPropertyPathExtension(mappingContext, path);
|
||||
AggregatePath extPath = mappingContext.getAggregatePath(path);
|
||||
|
||||
// add a join if necessary
|
||||
Join join = getJoin(extPath);
|
||||
|
||||
@@ -25,10 +25,9 @@ import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.jdbc.core.convert.JdbcConverter;
|
||||
import org.springframework.data.jdbc.core.convert.QueryMapper;
|
||||
import org.springframework.data.mapping.PersistentPropertyPath;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.data.relational.core.dialect.Dialect;
|
||||
import org.springframework.data.relational.core.dialect.RenderContextFactory;
|
||||
import org.springframework.data.relational.core.mapping.PersistentPropertyPathExtension;
|
||||
import org.springframework.data.relational.core.mapping.AggregatePath;
|
||||
import org.springframework.data.relational.core.mapping.RelationalMappingContext;
|
||||
import org.springframework.data.relational.core.mapping.RelationalPersistentEntity;
|
||||
import org.springframework.data.relational.core.mapping.RelationalPersistentProperty;
|
||||
@@ -117,8 +116,7 @@ class JdbcQueryCreator extends RelationalQueryCreator<ParametrizedQuery> {
|
||||
* @param tree the tree structure defining the predicate of the query.
|
||||
* @param parameters parameters for the predicate.
|
||||
*/
|
||||
static void validate(PartTree tree, Parameters<?, ?> parameters,
|
||||
MappingContext<? extends RelationalPersistentEntity<?>, ? extends RelationalPersistentProperty> context) {
|
||||
static void validate(PartTree tree, Parameters<?, ?> parameters, RelationalMappingContext context) {
|
||||
|
||||
RelationalQueryCreator.validate(tree, parameters);
|
||||
|
||||
@@ -127,30 +125,30 @@ class JdbcQueryCreator extends RelationalQueryCreator<ParametrizedQuery> {
|
||||
|
||||
PersistentPropertyPath<? extends RelationalPersistentProperty> propertyPath = context
|
||||
.getPersistentPropertyPath(part.getProperty());
|
||||
PersistentPropertyPathExtension path = new PersistentPropertyPathExtension(context, propertyPath);
|
||||
AggregatePath path = context.getAggregatePath(propertyPath);
|
||||
|
||||
for (PersistentPropertyPathExtension pathToValidate = path; path.getLength() > 0; path = path.getParentPath()) {
|
||||
validateProperty(pathToValidate);
|
||||
}
|
||||
path.forEach(JdbcQueryCreator::validateProperty);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void validateProperty(PersistentPropertyPathExtension path) {
|
||||
private static void validateProperty(AggregatePath path) {
|
||||
|
||||
if (!path.getParentPath().isEmbedded() && path.getLength() > 1) {
|
||||
throw new IllegalArgumentException(
|
||||
String.format("Cannot query by nested property: %s", path.getRequiredPersistentPropertyPath().toDotPath()));
|
||||
if (path.isRoot()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!path.getParentPath().isEmbedded() && path.getLength() > 2) {
|
||||
throw new IllegalArgumentException(String.format("Cannot query by nested property: %s", path.toDotPath()));
|
||||
}
|
||||
|
||||
if (path.isMultiValued() || path.isMap()) {
|
||||
throw new IllegalArgumentException(String.format("Cannot query by multi-valued property: %s",
|
||||
path.getRequiredPersistentPropertyPath().getLeafProperty().getName()));
|
||||
throw new IllegalArgumentException(
|
||||
String.format("Cannot query by multi-valued property: %s", path.getRequiredLeafProperty().getName()));
|
||||
}
|
||||
|
||||
if (!path.isEmbedded() && path.isEntity()) {
|
||||
throw new IllegalArgumentException(
|
||||
String.format("Cannot query by nested entity: %s", path.getRequiredPersistentPropertyPath().toDotPath()));
|
||||
throw new IllegalArgumentException(String.format("Cannot query by nested entity: %s", path.toDotPath()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -245,22 +243,21 @@ class JdbcQueryCreator extends RelationalQueryCreator<ParametrizedQuery> {
|
||||
for (PersistentPropertyPath<RelationalPersistentProperty> path : context
|
||||
.findPersistentPropertyPaths(entity.getType(), p -> true)) {
|
||||
|
||||
PersistentPropertyPathExtension extPath = new PersistentPropertyPathExtension(context, path);
|
||||
AggregatePath aggregatePath = context.getAggregatePath(path);
|
||||
|
||||
if (returnedType.needsCustomConstruction()) {
|
||||
if (!returnedType.getInputProperties()
|
||||
.contains(extPath.getRequiredPersistentPropertyPath().getBaseProperty().getName())) {
|
||||
if (!returnedType.getInputProperties().contains(aggregatePath.getRequiredBaseProperty().getName())) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// add a join if necessary
|
||||
Join join = getJoin(sqlContext, extPath);
|
||||
Join join = getJoin(sqlContext, aggregatePath);
|
||||
if (join != null) {
|
||||
joinTables.add(join);
|
||||
}
|
||||
|
||||
Column column = getColumn(sqlContext, extPath);
|
||||
Column column = getColumn(sqlContext, aggregatePath);
|
||||
if (column != null) {
|
||||
columnExpressions.add(column);
|
||||
}
|
||||
@@ -277,14 +274,14 @@ class JdbcQueryCreator extends RelationalQueryCreator<ParametrizedQuery> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@link Column} for {@link PersistentPropertyPathExtension}.
|
||||
* Create a {@link Column} for {@link AggregatePath}.
|
||||
*
|
||||
* @param sqlContext
|
||||
* @param path the path to the column in question.
|
||||
* @return the statement as a {@link String}. Guaranteed to be not {@literal null}.
|
||||
*/
|
||||
@Nullable
|
||||
private Column getColumn(SqlContext sqlContext, PersistentPropertyPathExtension path) {
|
||||
private Column getColumn(SqlContext sqlContext, AggregatePath path) {
|
||||
|
||||
// an embedded itself doesn't give an column, its members will though.
|
||||
// if there is a collection or map on the path it won't get selected at all, but it will get loaded with a separate
|
||||
@@ -313,7 +310,7 @@ class JdbcQueryCreator extends RelationalQueryCreator<ParametrizedQuery> {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
Join getJoin(SqlContext sqlContext, PersistentPropertyPathExtension path) {
|
||||
Join getJoin(SqlContext sqlContext, AggregatePath path) {
|
||||
|
||||
if (!path.isEntity() || path.isEmbedded() || path.isMultiValued()) {
|
||||
return null;
|
||||
@@ -321,13 +318,13 @@ class JdbcQueryCreator extends RelationalQueryCreator<ParametrizedQuery> {
|
||||
|
||||
Table currentTable = sqlContext.getTable(path);
|
||||
|
||||
PersistentPropertyPathExtension idDefiningParentPath = path.getIdDefiningParentPath();
|
||||
AggregatePath idDefiningParentPath = path.getIdDefiningParentPath();
|
||||
Table parentTable = sqlContext.getTable(idDefiningParentPath);
|
||||
|
||||
return new Join( //
|
||||
currentTable, //
|
||||
currentTable.column(path.getReverseColumnName()), //
|
||||
parentTable.column(idDefiningParentPath.getIdColumnName()) //
|
||||
currentTable.column(path.getTableInfo().reverseColumnInfo().name()), //
|
||||
parentTable.column(idDefiningParentPath.getTableInfo().idColumnName()) //
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
*/
|
||||
package org.springframework.data.jdbc.repository.query;
|
||||
|
||||
import org.springframework.data.relational.core.mapping.PersistentPropertyPathExtension;
|
||||
import org.springframework.data.relational.core.mapping.AggregatePath;
|
||||
import org.springframework.data.relational.core.mapping.RelationalPersistentEntity;
|
||||
import org.springframework.data.relational.core.sql.Column;
|
||||
import org.springframework.data.relational.core.sql.SqlIdentifier;
|
||||
@@ -53,18 +53,21 @@ class SqlContext {
|
||||
return table;
|
||||
}
|
||||
|
||||
Table getTable(PersistentPropertyPathExtension path) {
|
||||
Table getTable(AggregatePath path) {
|
||||
|
||||
SqlIdentifier tableAlias = path.getTableAlias();
|
||||
Table table = Table.create(path.getQualifiedTableName());
|
||||
SqlIdentifier tableAlias = path.getTableInfo().tableAlias();
|
||||
Table table = Table.create(path.getTableInfo().qualifiedTableName());
|
||||
return tableAlias == null ? table : table.as(tableAlias);
|
||||
}
|
||||
|
||||
Column getColumn(PersistentPropertyPathExtension path) {
|
||||
return getTable(path).column(path.getColumnName()).as(path.getColumnAlias());
|
||||
Column getColumn(AggregatePath path) {
|
||||
AggregatePath.ColumnInfo columnInfo = path.getColumnInfo();
|
||||
AggregatePath.ColumnInfo columnInfo1 = path.getColumnInfo();
|
||||
return getTable(path).column(columnInfo1.name()).as(columnInfo.alias());
|
||||
}
|
||||
|
||||
Column getReverseColumn(PersistentPropertyPathExtension path) {
|
||||
return getTable(path).column(path.getReverseColumnName()).as(path.getReverseColumnNameAlias());
|
||||
Column getReverseColumn(AggregatePath path) {
|
||||
return getTable(path).column(path.getTableInfo().reverseColumnInfo().name())
|
||||
.as(path.getTableInfo().reverseColumnInfo().alias());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ import org.springframework.data.mapping.PersistentPropertyPath;
|
||||
import org.springframework.data.mapping.PersistentPropertyPaths;
|
||||
import org.springframework.data.relational.core.conversion.DbAction;
|
||||
import org.springframework.data.relational.core.conversion.IdValueSource;
|
||||
import org.springframework.data.relational.core.mapping.PersistentPropertyPathExtension;
|
||||
import org.springframework.data.relational.core.mapping.AggregatePath;
|
||||
import org.springframework.data.relational.core.mapping.RelationalMappingContext;
|
||||
import org.springframework.data.relational.core.mapping.RelationalPersistentProperty;
|
||||
import org.springframework.lang.Nullable;
|
||||
@@ -156,8 +156,8 @@ public class JdbcAggregateChangeExecutorContextImmutableUnitTests {
|
||||
key == null ? emptyMap() : singletonMap(toPath(propertyName), key), IdValueSource.GENERATED);
|
||||
}
|
||||
|
||||
PersistentPropertyPathExtension toPathExt(String path) {
|
||||
return new PersistentPropertyPathExtension(context, getPersistentPropertyPath(path));
|
||||
AggregatePath toAggregatePath(String path) {
|
||||
return context.getAggregatePath(getPersistentPropertyPath(path));
|
||||
}
|
||||
|
||||
PersistentPropertyPath<RelationalPersistentProperty> getPersistentPropertyPath(String propertyName) {
|
||||
@@ -165,7 +165,7 @@ public class JdbcAggregateChangeExecutorContextImmutableUnitTests {
|
||||
}
|
||||
|
||||
Identifier createBackRef(long value) {
|
||||
return JdbcIdentifierBuilder.forBackReferences(converter, toPathExt("content"), value).build();
|
||||
return JdbcIdentifierBuilder.forBackReferences(converter, toAggregatePath("content"), value).build();
|
||||
}
|
||||
|
||||
PersistentPropertyPath<RelationalPersistentProperty> toPath(String path) {
|
||||
|
||||
@@ -34,7 +34,7 @@ import org.springframework.data.mapping.PersistentPropertyPath;
|
||||
import org.springframework.data.mapping.PersistentPropertyPaths;
|
||||
import org.springframework.data.relational.core.conversion.DbAction;
|
||||
import org.springframework.data.relational.core.conversion.IdValueSource;
|
||||
import org.springframework.data.relational.core.mapping.PersistentPropertyPathExtension;
|
||||
import org.springframework.data.relational.core.mapping.AggregatePath;
|
||||
import org.springframework.data.relational.core.mapping.RelationalMappingContext;
|
||||
import org.springframework.data.relational.core.mapping.RelationalPersistentProperty;
|
||||
import org.springframework.data.relational.core.sql.SqlIdentifier;
|
||||
@@ -248,8 +248,8 @@ public class JdbcAggregateChangeExecutorContextUnitTests {
|
||||
key == null ? emptyMap() : singletonMap(toPath(propertyName), key), idValueSource);
|
||||
}
|
||||
|
||||
PersistentPropertyPathExtension toPathExt(String path) {
|
||||
return new PersistentPropertyPathExtension(context, getPersistentPropertyPath(path));
|
||||
AggregatePath toAggregatePath(String path) {
|
||||
return context.getAggregatePath(getPersistentPropertyPath(path));
|
||||
}
|
||||
|
||||
PersistentPropertyPath<RelationalPersistentProperty> getPersistentPropertyPath(String propertyName) {
|
||||
@@ -257,7 +257,7 @@ public class JdbcAggregateChangeExecutorContextUnitTests {
|
||||
}
|
||||
|
||||
Identifier createBackRef(long value) {
|
||||
return forBackReferences(converter, toPathExt("content"), value).build();
|
||||
return forBackReferences(converter, toAggregatePath("content"), value).build();
|
||||
}
|
||||
|
||||
PersistentPropertyPath<RelationalPersistentProperty> toPath(String path) {
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package org.springframework.data.jdbc.core;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
import static org.assertj.core.api.SoftAssertions.*;
|
||||
import static org.springframework.data.relational.core.sql.SqlIdentifier.*;
|
||||
|
||||
@@ -238,6 +239,14 @@ public class PersistentPropertyPathExtensionUnitTests {
|
||||
});
|
||||
}
|
||||
|
||||
@Test // GH-1525
|
||||
void getAggregatePath() {
|
||||
assertThat(extPath("withId").getAggregatePath()).isNotNull();
|
||||
}
|
||||
@Test // GH-1525
|
||||
void getAggregatePathFromRoot() {
|
||||
assertThat(extPath(entity).getAggregatePath()).isNotNull();
|
||||
}
|
||||
private PersistentPropertyPathExtension extPath(RelationalPersistentEntity<?> entity) {
|
||||
return new PersistentPropertyPathExtension(context, entity);
|
||||
}
|
||||
@@ -247,7 +256,7 @@ public class PersistentPropertyPathExtensionUnitTests {
|
||||
}
|
||||
|
||||
PersistentPropertyPath<RelationalPersistentProperty> createSimplePath(String path) {
|
||||
return PropertyPathTestingUtils.toPath(path, DummyEntity.class, context);
|
||||
return PersistentPropertyPathTestUtils.getPath(path, DummyEntity.class, context);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
|
||||
@@ -26,18 +26,22 @@ import org.springframework.data.relational.core.mapping.RelationalPersistentProp
|
||||
*
|
||||
* @author Jens Schauder
|
||||
*/
|
||||
public final class PropertyPathTestingUtils {
|
||||
public final class PersistentPropertyPathTestUtils {
|
||||
|
||||
private PropertyPathTestingUtils() {
|
||||
private PersistentPropertyPathTestUtils() {
|
||||
throw new UnsupportedOperationException("This is a utility class and cannot be instantiated");
|
||||
}
|
||||
|
||||
public static PersistentPropertyPath<RelationalPersistentProperty> toPath(String path, Class source,
|
||||
RelationalMappingContext context) {
|
||||
public static PersistentPropertyPath<RelationalPersistentProperty> getPath(String path, Class source,
|
||||
RelationalMappingContext context) {
|
||||
|
||||
PersistentPropertyPaths<?, RelationalPersistentProperty> persistentPropertyPaths = context
|
||||
.findPersistentPropertyPaths(source, p -> true);
|
||||
|
||||
return persistentPropertyPaths.filter(p -> p.toDotPath().equals(path)).stream().findFirst().orElse(null);
|
||||
return persistentPropertyPaths
|
||||
.filter(p -> p.toDotPath().equals(path))
|
||||
.stream()
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,6 @@
|
||||
package org.springframework.data.jdbc.core.convert;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
import static org.springframework.data.jdbc.core.PropertyPathTestingUtils.*;
|
||||
import static org.springframework.data.relational.core.sql.SqlIdentifier.*;
|
||||
|
||||
import java.util.List;
|
||||
@@ -25,8 +24,9 @@ import java.util.UUID;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.jdbc.core.PersistentPropertyPathTestUtils;
|
||||
import org.springframework.data.jdbc.core.mapping.JdbcMappingContext;
|
||||
import org.springframework.data.relational.core.mapping.PersistentPropertyPathExtension;
|
||||
import org.springframework.data.relational.core.mapping.AggregatePath;
|
||||
|
||||
/**
|
||||
* Unit tests for the {@link JdbcIdentifierBuilder}.
|
||||
@@ -55,7 +55,7 @@ public class JdbcIdentifierBuilderUnitTests {
|
||||
@Test // DATAJDBC-326
|
||||
public void qualifiersForMaps() {
|
||||
|
||||
PersistentPropertyPathExtension path = getPath("children");
|
||||
AggregatePath path = getPath("children");
|
||||
|
||||
Identifier identifier = JdbcIdentifierBuilder //
|
||||
.forBackReferences(converter, path, "parent-eins") //
|
||||
@@ -73,7 +73,7 @@ public class JdbcIdentifierBuilderUnitTests {
|
||||
@Test // DATAJDBC-326
|
||||
public void qualifiersForLists() {
|
||||
|
||||
PersistentPropertyPathExtension path = getPath("moreChildren");
|
||||
AggregatePath path = getPath("moreChildren");
|
||||
|
||||
Identifier identifier = JdbcIdentifierBuilder //
|
||||
.forBackReferences(converter, path, "parent-eins") //
|
||||
@@ -116,8 +116,8 @@ public class JdbcIdentifierBuilderUnitTests {
|
||||
);
|
||||
}
|
||||
|
||||
private PersistentPropertyPathExtension getPath(String dotPath) {
|
||||
return new PersistentPropertyPathExtension(context, toPath(dotPath, DummyEntity.class, context));
|
||||
private AggregatePath getPath(String dotPath) {
|
||||
return context.getAggregatePath(PersistentPropertyPathTestUtils.getPath(dotPath, DummyEntity.class, context));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
|
||||
@@ -26,8 +26,8 @@ import org.assertj.core.api.SoftAssertions;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.jdbc.core.PersistentPropertyPathTestUtils;
|
||||
import org.springframework.data.jdbc.core.mapping.JdbcMappingContext;
|
||||
import org.springframework.data.jdbc.core.mapping.PersistentPropertyPathTestUtils;
|
||||
import org.springframework.data.mapping.PersistentPropertyPath;
|
||||
import org.springframework.data.relational.core.mapping.NamingStrategy;
|
||||
import org.springframework.data.relational.core.mapping.RelationalMappingContext;
|
||||
@@ -157,7 +157,7 @@ public class SqlGeneratorContextBasedNamingStrategyUnitTests {
|
||||
}
|
||||
|
||||
private PersistentPropertyPath<RelationalPersistentProperty> getPath(String path) {
|
||||
return PersistentPropertyPathTestUtils.getPath(this.context, path, DummyEntity.class);
|
||||
return PersistentPropertyPathTestUtils.getPath(path, DummyEntity.class, this.context);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -23,12 +23,11 @@ import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.jdbc.core.PropertyPathTestingUtils;
|
||||
import org.springframework.data.jdbc.core.PersistentPropertyPathTestUtils;
|
||||
import org.springframework.data.jdbc.core.mapping.JdbcMappingContext;
|
||||
import org.springframework.data.relational.core.mapping.Column;
|
||||
import org.springframework.data.relational.core.mapping.Embedded;
|
||||
import org.springframework.data.relational.core.mapping.Embedded.OnEmpty;
|
||||
import org.springframework.data.relational.core.mapping.PersistentPropertyPathExtension;
|
||||
import org.springframework.data.relational.core.mapping.RelationalMappingContext;
|
||||
import org.springframework.data.relational.core.mapping.RelationalPersistentEntity;
|
||||
import org.springframework.data.relational.core.sql.Aliased;
|
||||
@@ -177,7 +176,7 @@ public class SqlGeneratorEmbeddedUnitTests {
|
||||
public void deleteByPath() {
|
||||
|
||||
final String sql = sqlGenerator
|
||||
.createDeleteByPath(PropertyPathTestingUtils.toPath("embedded.other", DummyEntity2.class, context));
|
||||
.createDeleteByPath(PersistentPropertyPathTestUtils.getPath("embedded.other", DummyEntity2.class, context));
|
||||
|
||||
assertThat(sql).containsSequence("DELETE FROM other_entity", //
|
||||
"WHERE", //
|
||||
@@ -295,7 +294,7 @@ public class SqlGeneratorEmbeddedUnitTests {
|
||||
|
||||
private SqlGenerator.Join generateJoin(String path, Class<?> type) {
|
||||
return createSqlGenerator(type)
|
||||
.getJoin(new PersistentPropertyPathExtension(context, PropertyPathTestingUtils.toPath(path, type, context)));
|
||||
.getJoin(context.getAggregatePath(PersistentPropertyPathTestUtils.getPath(path, type, context)));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -310,13 +309,14 @@ public class SqlGeneratorEmbeddedUnitTests {
|
||||
private org.springframework.data.relational.core.sql.Column generatedColumn(String path, Class<?> type) {
|
||||
|
||||
return createSqlGenerator(type)
|
||||
.getColumn(new PersistentPropertyPathExtension(context, PropertyPathTestingUtils.toPath(path, type, context)));
|
||||
.getColumn(context.getAggregatePath(PersistentPropertyPathTestUtils.getPath(path, type, context)));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
static class DummyEntity {
|
||||
|
||||
@Column("id1") @Id Long id;
|
||||
@Column("id1")
|
||||
@Id Long id;
|
||||
|
||||
@Embedded(onEmpty = OnEmpty.USE_NULL, prefix = "prefix_") CascadedEmbedded prefixedEmbeddable;
|
||||
|
||||
|
||||
@@ -21,8 +21,8 @@ import org.assertj.core.api.SoftAssertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.jdbc.core.PersistentPropertyPathTestUtils;
|
||||
import org.springframework.data.jdbc.core.mapping.JdbcMappingContext;
|
||||
import org.springframework.data.jdbc.core.mapping.PersistentPropertyPathTestUtils;
|
||||
import org.springframework.data.mapping.PersistentPropertyPath;
|
||||
import org.springframework.data.relational.core.dialect.AnsiDialect;
|
||||
import org.springframework.data.relational.core.mapping.NamingStrategy;
|
||||
@@ -70,7 +70,7 @@ class SqlGeneratorFixedNamingStrategyUnitTests {
|
||||
}
|
||||
};
|
||||
|
||||
private RelationalMappingContext context = new JdbcMappingContext();
|
||||
private RelationalMappingContext context;
|
||||
|
||||
@Test // DATAJDBC-107
|
||||
void findOneWithOverriddenFixedTableName() {
|
||||
@@ -122,7 +122,7 @@ class SqlGeneratorFixedNamingStrategyUnitTests {
|
||||
String sql = sqlGenerator.createDeleteByPath(getPath("ref"));
|
||||
|
||||
assertThat(sql).isEqualTo("DELETE FROM \"FIXEDCUSTOMSCHEMA\".\"FIXEDCUSTOMTABLEPREFIX_REFERENCEDENTITY\" "
|
||||
+ "WHERE \"FIXEDCUSTOMSCHEMA\".\"FIXEDCUSTOMTABLEPREFIX_REFERENCEDENTITY\".\"DUMMY_ENTITY\" = :rootId");
|
||||
+ "WHERE \"FIXEDCUSTOMSCHEMA\".\"FIXEDCUSTOMTABLEPREFIX_REFERENCEDENTITY\".\"FIXEDCUSTOMTABLEPREFIX_DUMMYENTITY\" = :rootId");
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-107
|
||||
@@ -137,7 +137,7 @@ class SqlGeneratorFixedNamingStrategyUnitTests {
|
||||
+ "WHERE \"FIXEDCUSTOMSCHEMA\".\"FIXEDCUSTOMTABLEPREFIX_SECONDLEVELREFERENCEDENTITY\".\"FIXEDCUSTOMTABLEPREFIX_REFERENCEDENTITY\" IN "
|
||||
+ "(SELECT \"FIXEDCUSTOMSCHEMA\".\"FIXEDCUSTOMTABLEPREFIX_REFERENCEDENTITY\".\"FIXEDCUSTOMPROPERTYPREFIX_L1ID\" "
|
||||
+ "FROM \"FIXEDCUSTOMSCHEMA\".\"FIXEDCUSTOMTABLEPREFIX_REFERENCEDENTITY\" "
|
||||
+ "WHERE \"FIXEDCUSTOMSCHEMA\".\"FIXEDCUSTOMTABLEPREFIX_REFERENCEDENTITY\".\"DUMMY_ENTITY\" = :rootId)");
|
||||
+ "WHERE \"FIXEDCUSTOMSCHEMA\".\"FIXEDCUSTOMTABLEPREFIX_REFERENCEDENTITY\".\"FIXEDCUSTOMTABLEPREFIX_DUMMYENTITY\" = :rootId)");
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-107
|
||||
@@ -158,7 +158,7 @@ class SqlGeneratorFixedNamingStrategyUnitTests {
|
||||
String sql = sqlGenerator.createDeleteAllSql(getPath("ref"));
|
||||
|
||||
assertThat(sql).isEqualTo("DELETE FROM \"FIXEDCUSTOMSCHEMA\".\"FIXEDCUSTOMTABLEPREFIX_REFERENCEDENTITY\" "
|
||||
+ "WHERE \"FIXEDCUSTOMSCHEMA\".\"FIXEDCUSTOMTABLEPREFIX_REFERENCEDENTITY\".\"DUMMY_ENTITY\" IS NOT NULL");
|
||||
+ "WHERE \"FIXEDCUSTOMSCHEMA\".\"FIXEDCUSTOMTABLEPREFIX_REFERENCEDENTITY\".\"FIXEDCUSTOMTABLEPREFIX_DUMMYENTITY\" IS NOT NULL");
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-107
|
||||
@@ -173,7 +173,7 @@ class SqlGeneratorFixedNamingStrategyUnitTests {
|
||||
+ "WHERE \"FIXEDCUSTOMSCHEMA\".\"FIXEDCUSTOMTABLEPREFIX_SECONDLEVELREFERENCEDENTITY\".\"FIXEDCUSTOMTABLEPREFIX_REFERENCEDENTITY\" IN "
|
||||
+ "(SELECT \"FIXEDCUSTOMSCHEMA\".\"FIXEDCUSTOMTABLEPREFIX_REFERENCEDENTITY\".\"FIXEDCUSTOMPROPERTYPREFIX_L1ID\" "
|
||||
+ "FROM \"FIXEDCUSTOMSCHEMA\".\"FIXEDCUSTOMTABLEPREFIX_REFERENCEDENTITY\" "
|
||||
+ "WHERE \"FIXEDCUSTOMSCHEMA\".\"FIXEDCUSTOMTABLEPREFIX_REFERENCEDENTITY\".\"DUMMY_ENTITY\" IS NOT NULL)");
|
||||
+ "WHERE \"FIXEDCUSTOMSCHEMA\".\"FIXEDCUSTOMTABLEPREFIX_REFERENCEDENTITY\".\"FIXEDCUSTOMTABLEPREFIX_DUMMYENTITY\" IS NOT NULL)");
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-113
|
||||
@@ -188,7 +188,7 @@ class SqlGeneratorFixedNamingStrategyUnitTests {
|
||||
}
|
||||
|
||||
private PersistentPropertyPath<RelationalPersistentProperty> getPath(String path) {
|
||||
return PersistentPropertyPathTestUtils.getPath(context, path, DummyEntity.class);
|
||||
return PersistentPropertyPathTestUtils.getPath(path, DummyEntity.class, context);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -196,7 +196,7 @@ class SqlGeneratorFixedNamingStrategyUnitTests {
|
||||
*/
|
||||
private SqlGenerator configureSqlGenerator(NamingStrategy namingStrategy) {
|
||||
|
||||
RelationalMappingContext context = new JdbcMappingContext(namingStrategy);
|
||||
context = new JdbcMappingContext(namingStrategy);
|
||||
JdbcConverter converter = new BasicJdbcConverter(context, (identifier, path) -> {
|
||||
throw new UnsupportedOperationException();
|
||||
});
|
||||
|
||||
@@ -32,18 +32,17 @@ import org.springframework.data.annotation.Version;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.jdbc.core.PropertyPathTestingUtils;
|
||||
import org.springframework.data.jdbc.core.PersistentPropertyPathTestUtils;
|
||||
import org.springframework.data.jdbc.core.mapping.AggregateReference;
|
||||
import org.springframework.data.jdbc.core.mapping.JdbcMappingContext;
|
||||
import org.springframework.data.jdbc.core.mapping.PersistentPropertyPathTestUtils;
|
||||
import org.springframework.data.mapping.PersistentPropertyPath;
|
||||
import org.springframework.data.relational.core.dialect.AnsiDialect;
|
||||
import org.springframework.data.relational.core.dialect.Dialect;
|
||||
import org.springframework.data.relational.core.dialect.PostgresDialect;
|
||||
import org.springframework.data.relational.core.dialect.SqlServerDialect;
|
||||
import org.springframework.data.relational.core.mapping.AggregatePath;
|
||||
import org.springframework.data.relational.core.mapping.Column;
|
||||
import org.springframework.data.relational.core.mapping.DefaultNamingStrategy;
|
||||
import org.springframework.data.relational.core.mapping.PersistentPropertyPathExtension;
|
||||
import org.springframework.data.relational.core.mapping.RelationalMappingContext;
|
||||
import org.springframework.data.relational.core.mapping.RelationalPersistentEntity;
|
||||
import org.springframework.data.relational.core.mapping.RelationalPersistentProperty;
|
||||
@@ -389,7 +388,7 @@ class SqlGeneratorUnitTests {
|
||||
void findAllByPropertyWithKey() {
|
||||
|
||||
// this would get called when ListParent is th element type of a Map
|
||||
String sql = sqlGenerator.getFindAllByProperty(BACKREF, unquoted("key-column"), false);
|
||||
String sql = sqlGenerator.getFindAllByProperty(BACKREF, new AggregatePath.ColumnInfo(unquoted("key-column"),unquoted("key-column")), false);
|
||||
|
||||
assertThat(sql).isEqualTo("SELECT dummy_entity.id1 AS id1, dummy_entity.x_name AS x_name, " //
|
||||
+ "dummy_entity.x_other AS x_other, " //
|
||||
@@ -412,7 +411,8 @@ class SqlGeneratorUnitTests {
|
||||
void findAllByPropertyWithKeyOrdered() {
|
||||
|
||||
// this would get called when ListParent is th element type of a Map
|
||||
String sql = sqlGenerator.getFindAllByProperty(BACKREF, unquoted("key-column"), true);
|
||||
String sql = sqlGenerator.getFindAllByProperty(BACKREF,
|
||||
new AggregatePath.ColumnInfo(unquoted("key-column"), unquoted("key-column")), true);
|
||||
|
||||
assertThat(sql).isEqualTo("SELECT dummy_entity.id1 AS id1, dummy_entity.x_name AS x_name, " //
|
||||
+ "dummy_entity.x_other AS x_other, " //
|
||||
@@ -432,8 +432,10 @@ class SqlGeneratorUnitTests {
|
||||
final SqlGenerator sqlGenerator = createSqlGenerator(ReferencedEntity.class);
|
||||
final String sql = sqlGenerator.getFindAllByProperty(
|
||||
Identifier.of(quoted("id"), "parent-id-value", DummyEntity.class), //
|
||||
quoted("X_L1ID"), // this key column collides with the name derived by the naming strategy for the id of
|
||||
// ReferencedEntity.
|
||||
new AggregatePath.ColumnInfo(quoted("X_L1ID"), quoted("X_L1ID")), // this key column collides with the name
|
||||
// derived by the naming strategy for the id
|
||||
// of
|
||||
// ReferencedEntity.
|
||||
false);
|
||||
|
||||
final String id = "referenced_entity.x_l1id AS x_l1id";
|
||||
@@ -447,10 +449,11 @@ class SqlGeneratorUnitTests {
|
||||
void findAllByPropertyWithEmptyBackrefColumn() {
|
||||
|
||||
Identifier emptyIdentifier = Identifier.of(EMPTY, 0, Object.class);
|
||||
assertThatThrownBy(() -> sqlGenerator.getFindAllByProperty(emptyIdentifier, unquoted("key-column"), false)) //
|
||||
.isInstanceOf(IllegalArgumentException.class) //
|
||||
.hasMessageContaining(
|
||||
"An empty SqlIdentifier can't be used in condition. Make sure that all composite primary keys are defined in the query");
|
||||
assertThatThrownBy(() -> sqlGenerator.getFindAllByProperty(emptyIdentifier,
|
||||
new AggregatePath.ColumnInfo(unquoted("key-column"), unquoted("key-column")), false)) //
|
||||
.isInstanceOf(IllegalArgumentException.class) //
|
||||
.hasMessageContaining(
|
||||
"An empty SqlIdentifier can't be used in condition. Make sure that all composite primary keys are defined in the query");
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-219
|
||||
@@ -574,15 +577,16 @@ class SqlGeneratorUnitTests {
|
||||
|
||||
final SqlGenerator sqlGenerator = createSqlGenerator(EntityWithReadOnlyProperty.class);
|
||||
|
||||
assertThat(sqlGenerator.getFindAllByProperty(BACKREF, unquoted("key-column"), true)).isEqualToIgnoringCase( //
|
||||
"SELECT " //
|
||||
+ "entity_with_read_only_property.x_id AS x_id, " //
|
||||
+ "entity_with_read_only_property.x_name AS x_name, " //
|
||||
+ "entity_with_read_only_property.x_read_only_value AS x_read_only_value, " //
|
||||
+ "entity_with_read_only_property.key-column AS key-column " //
|
||||
+ "FROM entity_with_read_only_property " //
|
||||
+ "WHERE entity_with_read_only_property.backref = :backref " //
|
||||
+ "ORDER BY key-column" //
|
||||
assertThat(sqlGenerator.getFindAllByProperty(BACKREF,
|
||||
new AggregatePath.ColumnInfo(unquoted("key-column"), unquoted("key-column")), true)).isEqualToIgnoringCase( //
|
||||
"SELECT " //
|
||||
+ "entity_with_read_only_property.x_id AS x_id, " //
|
||||
+ "entity_with_read_only_property.x_name AS x_name, " //
|
||||
+ "entity_with_read_only_property.x_read_only_value AS x_read_only_value, " //
|
||||
+ "entity_with_read_only_property.key-column AS key-column " //
|
||||
+ "FROM entity_with_read_only_property " //
|
||||
+ "WHERE entity_with_read_only_property.backref = :backref " //
|
||||
+ "ORDER BY key-column" //
|
||||
);
|
||||
}
|
||||
|
||||
@@ -736,7 +740,7 @@ class SqlGeneratorUnitTests {
|
||||
@Nullable
|
||||
private SqlGenerator.Join generateJoin(String path, Class<?> type) {
|
||||
return createSqlGenerator(type, AnsiDialect.INSTANCE)
|
||||
.getJoin(new PersistentPropertyPathExtension(context, PropertyPathTestingUtils.toPath(path, type, context)));
|
||||
.getJoin(context.getAggregatePath(PersistentPropertyPathTestUtils.getPath(path, type, context)));
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-340
|
||||
@@ -935,11 +939,11 @@ class SqlGeneratorUnitTests {
|
||||
private org.springframework.data.relational.core.sql.Column generatedColumn(String path, Class<?> type) {
|
||||
|
||||
return createSqlGenerator(type, AnsiDialect.INSTANCE)
|
||||
.getColumn(new PersistentPropertyPathExtension(context, PropertyPathTestingUtils.toPath(path, type, context)));
|
||||
.getColumn(context.getAggregatePath(PersistentPropertyPathTestUtils.getPath(path, type, context)));
|
||||
}
|
||||
|
||||
private PersistentPropertyPath<RelationalPersistentProperty> getPath(String path, Class<?> baseType) {
|
||||
return PersistentPropertyPathTestUtils.getPath(context, path, baseType);
|
||||
return PersistentPropertyPathTestUtils.getPath(path, baseType, context);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
|
||||
@@ -15,17 +15,11 @@
|
||||
*/
|
||||
package org.springframework.data.jdbc.core.mapping;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
import static org.assertj.core.api.SoftAssertions.*;
|
||||
import static org.springframework.data.relational.core.sql.SqlIdentifier.*;
|
||||
|
||||
import junit.framework.AssertionFailedError;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.mapping.PersistentPropertyPath;
|
||||
import org.springframework.data.relational.core.mapping.BasicRelationalPersistentProperty;
|
||||
import org.springframework.data.relational.core.mapping.Column;
|
||||
import org.springframework.data.relational.core.mapping.MappedCollection;
|
||||
import org.springframework.data.relational.core.mapping.PersistentPropertyPathExtension;
|
||||
import org.springframework.data.relational.core.mapping.RelationalMappingContext;
|
||||
import org.springframework.data.relational.core.mapping.RelationalPersistentEntity;
|
||||
import org.springframework.data.relational.core.mapping.RelationalPersistentProperty;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZonedDateTime;
|
||||
@@ -33,9 +27,16 @@ import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
import static org.assertj.core.api.SoftAssertions.*;
|
||||
import static org.springframework.data.relational.core.sql.SqlIdentifier.*;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.mapping.PersistentPropertyPath;
|
||||
import org.springframework.data.relational.core.mapping.AggregatePath;
|
||||
import org.springframework.data.relational.core.mapping.BasicRelationalPersistentProperty;
|
||||
import org.springframework.data.relational.core.mapping.Column;
|
||||
import org.springframework.data.relational.core.mapping.MappedCollection;
|
||||
import org.springframework.data.relational.core.mapping.RelationalMappingContext;
|
||||
import org.springframework.data.relational.core.mapping.RelationalPersistentEntity;
|
||||
import org.springframework.data.relational.core.mapping.RelationalPersistentProperty;
|
||||
|
||||
/**
|
||||
* Unit tests for the {@link BasicRelationalPersistentProperty}.
|
||||
@@ -63,9 +64,10 @@ public class BasicJdbcPersistentPropertyUnitTests {
|
||||
|
||||
String propertyName = "someList";
|
||||
RelationalPersistentProperty listProperty = entity.getRequiredPersistentProperty(propertyName);
|
||||
PersistentPropertyPathExtension path = getPersistentPropertyPath(DummyEntity.class, propertyName);
|
||||
AggregatePath path = getPersistentPropertyPath(DummyEntity.class, propertyName);
|
||||
|
||||
assertThat(listProperty.getReverseColumnName(path)).isEqualTo(quoted("dummy_column_name"));
|
||||
assertThat(listProperty.getReverseColumnName(path.getRequiredBaseProperty().getOwner()))
|
||||
.isEqualTo(quoted("dummy_column_name"));
|
||||
assertThat(listProperty.getKeyColumn()).isEqualTo(quoted("dummy_key_column_name"));
|
||||
}
|
||||
|
||||
@@ -76,10 +78,11 @@ public class BasicJdbcPersistentPropertyUnitTests {
|
||||
RelationalPersistentProperty listProperty = context //
|
||||
.getRequiredPersistentEntity(WithCollections.class) //
|
||||
.getRequiredPersistentProperty(propertyName);
|
||||
PersistentPropertyPathExtension path = getPersistentPropertyPath(DummyEntity.class, propertyName);
|
||||
AggregatePath path = getPersistentPropertyPath(DummyEntity.class, propertyName);
|
||||
|
||||
assertThat(listProperty.getKeyColumn()).isEqualTo(quoted("WITH_COLLECTIONS_KEY"));
|
||||
assertThat(listProperty.getReverseColumnName(path)).isEqualTo(quoted("some_value"));
|
||||
assertThat(listProperty.getReverseColumnName(path.getRequiredBaseProperty().getOwner()))
|
||||
.isEqualTo(quoted("some_value"));
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-331
|
||||
@@ -88,10 +91,11 @@ public class BasicJdbcPersistentPropertyUnitTests {
|
||||
RelationalPersistentProperty listProperty = context //
|
||||
.getRequiredPersistentEntity(WithCollections.class) //
|
||||
.getRequiredPersistentProperty("overrideList");
|
||||
PersistentPropertyPathExtension path = getPersistentPropertyPath(WithCollections.class, "overrideList");
|
||||
AggregatePath path = getPersistentPropertyPath(WithCollections.class, "overrideList");
|
||||
|
||||
assertThat(listProperty.getKeyColumn()).isEqualTo(quoted("override_key"));
|
||||
assertThat(listProperty.getReverseColumnName(path)).isEqualTo(quoted("override_id"));
|
||||
assertThat(listProperty.getReverseColumnName(path.getRequiredBaseProperty().getOwner()))
|
||||
.isEqualTo(quoted("override_id"));
|
||||
}
|
||||
|
||||
@Test // GH-938
|
||||
@@ -126,12 +130,13 @@ public class BasicJdbcPersistentPropertyUnitTests {
|
||||
});
|
||||
}
|
||||
|
||||
private PersistentPropertyPathExtension getPersistentPropertyPath(Class<?> type, String propertyName) {
|
||||
private AggregatePath getPersistentPropertyPath(Class<?> type, String propertyName) {
|
||||
|
||||
PersistentPropertyPath<RelationalPersistentProperty> path = context
|
||||
.findPersistentPropertyPaths(type, p -> p.getName().equals(propertyName)).getFirst()
|
||||
.orElseThrow(() -> new AssertionFailedError(String.format("Couldn't find path for '%s'", propertyName)));
|
||||
|
||||
return new PersistentPropertyPathExtension(context, path);
|
||||
return context.getAggregatePath(path);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@@ -142,8 +147,7 @@ public class BasicJdbcPersistentPropertyUnitTests {
|
||||
@SuppressWarnings("unused")
|
||||
private static class DummyEntity {
|
||||
|
||||
@Id
|
||||
private final Long id;
|
||||
@Id private final Long id;
|
||||
private final SomeEnum someEnum;
|
||||
private final LocalDateTime localDateTime;
|
||||
private final ZonedDateTime zonedDateTime;
|
||||
@@ -152,13 +156,13 @@ public class BasicJdbcPersistentPropertyUnitTests {
|
||||
private final UUID uuid;
|
||||
|
||||
@MappedCollection(idColumn = "dummy_column_name",
|
||||
keyColumn = "dummy_key_column_name")
|
||||
private List<Integer> someList;
|
||||
keyColumn = "dummy_key_column_name") private List<Integer> someList;
|
||||
|
||||
// DATACMNS-106
|
||||
private @Column("dummy_name") String name;
|
||||
|
||||
private DummyEntity(Long id, SomeEnum someEnum, LocalDateTime localDateTime, ZonedDateTime zonedDateTime, AggregateReference<DummyEntity, Long> reference, List<String> listField, UUID uuid) {
|
||||
private DummyEntity(Long id, SomeEnum someEnum, LocalDateTime localDateTime, ZonedDateTime zonedDateTime,
|
||||
AggregateReference<DummyEntity, Long> reference, List<String> listField, UUID uuid) {
|
||||
this.id = id;
|
||||
this.someEnum = someEnum;
|
||||
this.localDateTime = localDateTime;
|
||||
@@ -224,8 +228,7 @@ public class BasicJdbcPersistentPropertyUnitTests {
|
||||
|
||||
private static class WithCollections {
|
||||
|
||||
@Column(value = "some_value")
|
||||
List<Integer> someList;
|
||||
@Column(value = "some_value") List<Integer> someList;
|
||||
|
||||
@Column(value = "some_value") //
|
||||
@MappedCollection(idColumn = "override_id", keyColumn = "override_key") //
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
/*
|
||||
* Copyright 2018-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.core.mapping;
|
||||
|
||||
import org.springframework.data.mapping.PersistentPropertyPath;
|
||||
import org.springframework.data.relational.core.mapping.RelationalMappingContext;
|
||||
import org.springframework.data.relational.core.mapping.RelationalPersistentProperty;
|
||||
|
||||
/**
|
||||
* @author Jens Schauder
|
||||
*/
|
||||
public final class PersistentPropertyPathTestUtils {
|
||||
|
||||
private PersistentPropertyPathTestUtils() {
|
||||
throw new UnsupportedOperationException("This is a utility class and cannot be instantiated");
|
||||
}
|
||||
|
||||
public static PersistentPropertyPath<RelationalPersistentProperty> getPath(RelationalMappingContext context,
|
||||
String path, Class<?> baseType) {
|
||||
|
||||
return context.findPersistentPropertyPaths(baseType, p -> p.isEntity()) //
|
||||
.filter(p -> p.toDotPath().equals(path)) //
|
||||
.stream() //
|
||||
.findFirst() //
|
||||
.orElseThrow(() -> new IllegalArgumentException(String.format("No path for %s based on %s", path, baseType)));
|
||||
}
|
||||
}
|
||||
@@ -58,7 +58,7 @@ public class DefaultNamingStrategyUnitTests {
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-184
|
||||
public void getReverseColumnName() {
|
||||
public void getReverseColumnInfoName() {
|
||||
assertThat(target.getReverseColumnName(persistentEntity.getPersistentProperty("dummySubEntities")))
|
||||
.isEqualTo("dummy_entity");
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ import org.junit.jupiter.api.Test;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.jdbc.core.PropertyPathTestingUtils;
|
||||
import org.springframework.data.jdbc.core.PersistentPropertyPathTestUtils;
|
||||
import org.springframework.data.jdbc.core.convert.Identifier;
|
||||
import org.springframework.data.jdbc.core.mapping.JdbcMappingContext;
|
||||
import org.springframework.data.mapping.PersistentPropertyPath;
|
||||
@@ -54,7 +54,7 @@ public class MyBatisDataAccessStrategyUnitTests {
|
||||
|
||||
MyBatisDataAccessStrategy accessStrategy = new MyBatisDataAccessStrategy(session, IdentifierProcessing.ANSI);
|
||||
|
||||
PersistentPropertyPath<RelationalPersistentProperty> path = PropertyPathTestingUtils.toPath("one.two",
|
||||
PersistentPropertyPath<RelationalPersistentProperty> path = PersistentPropertyPathTestUtils.getPath("one.two",
|
||||
DummyEntity.class, context);
|
||||
|
||||
@BeforeEach
|
||||
|
||||
Reference in New Issue
Block a user