DATAJDBC-291 - Polishing.
Introduce factory methods for AggregateChange save/delete object creation. Replace computeIfAbsent pattern with appropriate methods. Add indirection for staged values traversal. Rename CascadingValuesLookup to StagedValues. Javadoc, formatting. Original pull request: #173.
This commit is contained in:
committed by
Jens Schauder
parent
9727136827
commit
fe2e4bb419
@@ -26,7 +26,6 @@ import org.springframework.data.jdbc.core.convert.DataAccessStrategy;
|
||||
import org.springframework.data.mapping.IdentifierAccessor;
|
||||
import org.springframework.data.mapping.callback.EntityCallbacks;
|
||||
import org.springframework.data.relational.core.conversion.AggregateChange;
|
||||
import org.springframework.data.relational.core.conversion.AggregateChange.Kind;
|
||||
import org.springframework.data.relational.core.conversion.Interpreter;
|
||||
import org.springframework.data.relational.core.conversion.RelationalConverter;
|
||||
import org.springframework.data.relational.core.conversion.RelationalEntityDeleteWriter;
|
||||
@@ -331,33 +330,30 @@ public class JdbcAggregateTemplate implements JdbcAggregateOperations {
|
||||
triggerAfterDelete(entity, id, change);
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
private <T> AggregateChange<T> createInsertChange(T instance) {
|
||||
|
||||
AggregateChange<T> aggregateChange = new AggregateChange(Kind.SAVE, instance.getClass(), instance);
|
||||
AggregateChange<T> aggregateChange = AggregateChange.forSave(instance);
|
||||
jdbcEntityInsertWriter.write(instance, aggregateChange);
|
||||
return aggregateChange;
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
private <T> AggregateChange<T> createUpdateChange(T instance) {
|
||||
|
||||
AggregateChange<T> aggregateChange = new AggregateChange(Kind.SAVE, instance.getClass(), instance);
|
||||
AggregateChange<T> aggregateChange = AggregateChange.forSave(instance);
|
||||
jdbcEntityUpdateWriter.write(instance, aggregateChange);
|
||||
return aggregateChange;
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
private <T> AggregateChange<T> createDeletingChange(Object id, @Nullable T entity, Class<T> domainType) {
|
||||
|
||||
AggregateChange<T> aggregateChange = new AggregateChange(Kind.DELETE, domainType, entity);
|
||||
AggregateChange<T> aggregateChange = AggregateChange.forDelete(domainType, entity);
|
||||
jdbcEntityDeleteWriter.write(id, aggregateChange);
|
||||
return aggregateChange;
|
||||
}
|
||||
|
||||
private AggregateChange<?> createDeletingChange(Class<?> domainType) {
|
||||
|
||||
AggregateChange<?> aggregateChange = new AggregateChange<>(Kind.DELETE, domainType, null);
|
||||
AggregateChange<?> aggregateChange = AggregateChange.forDelete(domainType, null);
|
||||
jdbcEntityDeleteWriter.write(null, aggregateChange);
|
||||
return aggregateChange;
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.data.mapping.PersistentPropertyAccessor;
|
||||
@@ -34,6 +35,7 @@ import org.springframework.data.relational.core.mapping.RelationalPersistentEnti
|
||||
import org.springframework.data.util.Pair;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* Represents the change happening to the aggregate (as used in the context of Domain Driven Design) as a whole.
|
||||
@@ -59,7 +61,53 @@ public class AggregateChange<T> {
|
||||
this.entity = entity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory method to create an {@link AggregateChange} for saving entities.
|
||||
*
|
||||
* @param entity aggregate root to save.
|
||||
* @param <T> entity type.
|
||||
* @return the {@link AggregateChange} for saving the root {@code entity}.
|
||||
* @since 1.2
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> AggregateChange<T> forSave(T entity) {
|
||||
|
||||
Assert.notNull(entity, "Entity must not be null");
|
||||
return new AggregateChange<>(Kind.SAVE, (Class<T>) ClassUtils.getUserClass(entity), entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory method to create an {@link AggregateChange} for deleting entities.
|
||||
*
|
||||
* @param entity aggregate root to delete.
|
||||
* @param <T> entity type.
|
||||
* @return the {@link AggregateChange} for deleting the root {@code entity}.
|
||||
* @since 1.2
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> AggregateChange<T> forDelete(T entity) {
|
||||
|
||||
Assert.notNull(entity, "Entity must not be null");
|
||||
return forDelete((Class<T>) ClassUtils.getUserClass(entity), entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory method to create an {@link AggregateChange} for deleting entities.
|
||||
*
|
||||
* @param entityClass aggregate root type.
|
||||
* @param entity aggregate root to delete.
|
||||
* @param <T> entity type.
|
||||
* @return the {@link AggregateChange} for deleting the root {@code entity}.
|
||||
* @since 1.2
|
||||
*/
|
||||
public static <T> AggregateChange<T> forDelete(Class<T> entityClass, @Nullable T entity) {
|
||||
|
||||
Assert.notNull(entityClass, "Entity class must not be null");
|
||||
return new AggregateChange<>(Kind.DELETE, entityClass, entity);
|
||||
}
|
||||
|
||||
public void setEntity(@Nullable T aggregateRoot) {
|
||||
// TODO: Check instanceOf compatibility to ensure type contract.
|
||||
entity = aggregateRoot;
|
||||
}
|
||||
|
||||
@@ -67,16 +115,15 @@ public class AggregateChange<T> {
|
||||
|
||||
actions.forEach(action -> action.executeWith(interpreter));
|
||||
|
||||
T newRoot = setGeneratedIds(context, converter);
|
||||
T newRoot = populateIdsIfNecessary(context, converter);
|
||||
|
||||
if (newRoot != null) {
|
||||
entity = newRoot;
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Nullable
|
||||
private T setGeneratedIds(RelationalMappingContext context, RelationalConverter converter) {
|
||||
private T populateIdsIfNecessary(RelationalMappingContext context, RelationalConverter converter) {
|
||||
|
||||
T newRoot = null;
|
||||
|
||||
@@ -84,32 +131,31 @@ public class AggregateChange<T> {
|
||||
ArrayList<DbAction<?>> reverseActions = new ArrayList<>(actions);
|
||||
Collections.reverse(reverseActions);
|
||||
|
||||
CascadingValuesLookup cascadingValues = new CascadingValuesLookup();
|
||||
StagedValues cascadingValues = new StagedValues();
|
||||
|
||||
for (DbAction<?> action : reverseActions) {
|
||||
|
||||
if (action instanceof DbAction.WithGeneratedId) {
|
||||
if (!(action instanceof DbAction.WithGeneratedId)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
DbAction.WithGeneratedId<?> withGeneratedId = (DbAction.WithGeneratedId<?>) action;
|
||||
Object generatedId = withGeneratedId.getGeneratedId();
|
||||
DbAction.WithGeneratedId<?> withGeneratedId = (DbAction.WithGeneratedId<?>) action;
|
||||
Object generatedId = withGeneratedId.getGeneratedId();
|
||||
Object newEntity = setIdAndCascadingProperties(context, converter, withGeneratedId, generatedId, cascadingValues);
|
||||
|
||||
Object newEntity = setIdAndCascadingProperties(context, converter, withGeneratedId, generatedId,
|
||||
cascadingValues);
|
||||
// the id property was immutable so we have to propagate changes up the tree
|
||||
if (newEntity != ((DbAction.WithGeneratedId<?>) action).getEntity()) {
|
||||
|
||||
// the id property was immutable so we have to propagate changes up the tree
|
||||
if (newEntity != ((DbAction.WithGeneratedId<?>) action).getEntity()) {
|
||||
if (action instanceof DbAction.Insert) {
|
||||
DbAction.Insert insert = (DbAction.Insert) action;
|
||||
|
||||
if (action instanceof DbAction.Insert) {
|
||||
DbAction.Insert insert = (DbAction.Insert) action;
|
||||
Pair qualifier = insert.getQualifier();
|
||||
|
||||
Pair qualifier = insert.getQualifier();
|
||||
cascadingValues.stage(insert.dependingOn, insert.propertyPath,
|
||||
qualifier == null ? null : qualifier.getSecond(), newEntity);
|
||||
|
||||
cascadingValues.add(insert.dependingOn, insert.propertyPath, newEntity,
|
||||
qualifier == null ? null : qualifier.getSecond());
|
||||
|
||||
} else if (action instanceof DbAction.InsertRoot) {
|
||||
newRoot = (T) newEntity;
|
||||
}
|
||||
} else if (action instanceof DbAction.InsertRoot) {
|
||||
newRoot = entityType.cast(newEntity);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -119,7 +165,7 @@ public class AggregateChange<T> {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <S> Object setIdAndCascadingProperties(RelationalMappingContext context, RelationalConverter converter,
|
||||
DbAction.WithGeneratedId<S> action, @Nullable Object generatedId, CascadingValuesLookup cascadingValues) {
|
||||
DbAction.WithGeneratedId<S> action, @Nullable Object generatedId, StagedValues cascadingValues) {
|
||||
|
||||
S originalEntity = action.getEntity();
|
||||
|
||||
@@ -132,19 +178,14 @@ public class AggregateChange<T> {
|
||||
}
|
||||
|
||||
// set values of changed immutables referenced by this entity
|
||||
Map<PersistentPropertyPath, Object> cascadingValue = cascadingValues.get(action);
|
||||
for (Map.Entry<PersistentPropertyPath, Object> pathValuePair : cascadingValue.entrySet()) {
|
||||
propertyAccessor.setProperty(getRelativePath(action, pathValuePair), pathValuePair.getValue());
|
||||
}
|
||||
cascadingValues.forEachPath(action, (persistentPropertyPath, o) -> propertyAccessor
|
||||
.setProperty(getRelativePath(action, persistentPropertyPath), o));
|
||||
|
||||
return propertyAccessor.getBean();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private PersistentPropertyPath getRelativePath(DbAction action,
|
||||
Map.Entry<PersistentPropertyPath, Object> pathValuePair) {
|
||||
|
||||
PersistentPropertyPath pathToValue = pathValuePair.getKey();
|
||||
private PersistentPropertyPath getRelativePath(DbAction action, PersistentPropertyPath pathToValue) {
|
||||
|
||||
if (action instanceof DbAction.Insert) {
|
||||
return pathToValue.getExtensionForBaseOf(((DbAction.Insert) action).propertyPath);
|
||||
@@ -178,12 +219,13 @@ public class AggregateChange<T> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gathers and holds information about immutable properties in an aggregate that need updating.
|
||||
* Accumulates information about staged immutable objects in an aggregate that require updating because their state
|
||||
* changed because of {@link DbAction} execution.
|
||||
*/
|
||||
private static class CascadingValuesLookup {
|
||||
private static class StagedValues {
|
||||
|
||||
static final List<MultiValueAggregator> aggregators = Arrays.asList(new SetAggregator(), new MapAggregator(),
|
||||
new ListAggregator(), new SingleElementAggregator());
|
||||
static final List<MultiValueAggregator> aggregators = Arrays.asList(SetAggregator.INSTANCE, MapAggregator.INSTANCE,
|
||||
ListAggregator.INSTANCE, SingleElementAggregator.INSTANCE);
|
||||
|
||||
Map<DbAction, Map<PersistentPropertyPath, Object>> values = new HashMap<>();
|
||||
|
||||
@@ -194,27 +236,22 @@ public class AggregateChange<T> {
|
||||
* @param action The action responsible for persisting the entity that needs the added value set. Must not be
|
||||
* {@literal null}.
|
||||
* @param path The path to the property in which to set the value. Must not be {@literal null}.
|
||||
* @param value The value to be set. Must not be {@literal null}.
|
||||
* @param qualifier If {@code path} is a qualified multivalued properties this parameter contains the qualifier. May
|
||||
* be {@literal null}.
|
||||
* @param value The value to be set. Must not be {@literal null}.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> void add(DbAction<?> action, PersistentPropertyPath path, Object value, @Nullable Object qualifier) {
|
||||
<T> void stage(DbAction<?> action, PersistentPropertyPath path, @Nullable Object qualifier, Object value) {
|
||||
|
||||
MultiValueAggregator<T> aggregator = getAggregatorFor(path);
|
||||
|
||||
Map<PersistentPropertyPath, Object> valuesForPath = this.values.get(action);
|
||||
if (valuesForPath == null) {
|
||||
valuesForPath = new HashMap<>();
|
||||
values.put(action, valuesForPath);
|
||||
}
|
||||
Map<PersistentPropertyPath, Object> valuesForPath = this.values.computeIfAbsent(action,
|
||||
dbAction -> new HashMap<>());
|
||||
|
||||
T currentValue = (T) valuesForPath.get(path);
|
||||
if (currentValue == null) {
|
||||
currentValue = aggregator.createEmptyInstance();
|
||||
}
|
||||
T currentValue = (T) valuesForPath.computeIfAbsent(path,
|
||||
persistentPropertyPath -> aggregator.createEmptyInstance());
|
||||
|
||||
Object newValue = aggregator.add(currentValue, value, qualifier);
|
||||
Object newValue = aggregator.add(currentValue, qualifier, value);
|
||||
|
||||
valuesForPath.put(path, newValue);
|
||||
}
|
||||
@@ -231,8 +268,17 @@ public class AggregateChange<T> {
|
||||
throw new IllegalStateException(String.format("Can't handle path %s", path));
|
||||
}
|
||||
|
||||
public Map<PersistentPropertyPath, Object> get(DbAction<?> action) {
|
||||
return values.getOrDefault(action, Collections.emptyMap());
|
||||
/**
|
||||
* Performs the given action for each entry in this the staging area that are provided by {@link DbAction} until all
|
||||
* {@link PersistentPropertyPath} have been processed or the action throws an exception. The {@link BiConsumer
|
||||
* action} is called with each applicable {@link PersistentPropertyPath} and {@code value} that is assignable to the
|
||||
* property.
|
||||
*
|
||||
* @param dbAction
|
||||
* @param action
|
||||
*/
|
||||
void forEachPath(DbAction<?> dbAction, BiConsumer<PersistentPropertyPath, Object> action) {
|
||||
values.getOrDefault(dbAction, Collections.emptyMap()).forEach(action);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -249,11 +295,13 @@ public class AggregateChange<T> {
|
||||
@Nullable
|
||||
T createEmptyInstance();
|
||||
|
||||
T add(@Nullable T aggregate, Object value, @Nullable Object qualifier);
|
||||
T add(@Nullable T aggregate, @Nullable Object qualifier, Object value);
|
||||
|
||||
}
|
||||
|
||||
static private class SetAggregator implements MultiValueAggregator<Set> {
|
||||
private enum SetAggregator implements MultiValueAggregator<Set> {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
@Override
|
||||
public Class<Set> handledType() {
|
||||
@@ -267,7 +315,7 @@ public class AggregateChange<T> {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public Set add(@Nullable Set set, Object value, @Nullable Object qualifier) {
|
||||
public Set add(@Nullable Set set, @Nullable Object qualifier, Object value) {
|
||||
|
||||
Assert.notNull(set, "Set must not be null");
|
||||
|
||||
@@ -276,7 +324,9 @@ public class AggregateChange<T> {
|
||||
}
|
||||
}
|
||||
|
||||
static private class ListAggregator implements MultiValueAggregator<List> {
|
||||
private enum ListAggregator implements MultiValueAggregator<List> {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
@Override
|
||||
public boolean handles(PersistentProperty property) {
|
||||
@@ -290,7 +340,7 @@ public class AggregateChange<T> {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public List add(@Nullable List list, Object value, @Nullable Object qualifier) {
|
||||
public List add(@Nullable List list, @Nullable Object qualifier, Object value) {
|
||||
|
||||
Assert.notNull(list, "List must not be null.");
|
||||
|
||||
@@ -305,7 +355,9 @@ public class AggregateChange<T> {
|
||||
}
|
||||
}
|
||||
|
||||
static private class MapAggregator implements MultiValueAggregator<Map> {
|
||||
private enum MapAggregator implements MultiValueAggregator<Map> {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
@Override
|
||||
public Class<Map> handledType() {
|
||||
@@ -319,7 +371,7 @@ public class AggregateChange<T> {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public Map add(@Nullable Map map, Object value, @Nullable Object qualifier) {
|
||||
public Map add(@Nullable Map map, @Nullable Object qualifier, Object value) {
|
||||
|
||||
Assert.notNull(map, "Map must not be null.");
|
||||
|
||||
@@ -328,7 +380,9 @@ public class AggregateChange<T> {
|
||||
}
|
||||
}
|
||||
|
||||
static private class SingleElementAggregator implements MultiValueAggregator<Object> {
|
||||
private enum SingleElementAggregator implements MultiValueAggregator<Object> {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
@@ -337,7 +391,7 @@ public class AggregateChange<T> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object add(@Nullable Object __null, Object value, @Nullable Object qualifier) {
|
||||
public Object add(@Nullable Object __null, @Nullable Object qualifier, Object value) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -262,6 +262,9 @@ public interface DbAction<T> {
|
||||
*/
|
||||
Map<PersistentPropertyPath<RelationalPersistentProperty>, Object> getQualifiers();
|
||||
|
||||
// TODO: Encapsulate propertyPath and qualifier in object: PropertyPathWithListIndex,
|
||||
// PropertyPathWithMapIndex, PropertyPathInSet, PropertyPathWithoutQualifier
|
||||
// Probably we need better names.
|
||||
@Nullable
|
||||
default Pair<PersistentPropertyPath<RelationalPersistentProperty>, Object> getQualifier() {
|
||||
Map<PersistentPropertyPath<RelationalPersistentProperty>, Object> qualifiers = getQualifiers();
|
||||
@@ -272,14 +275,14 @@ public interface DbAction<T> {
|
||||
throw new IllegalStateException("Can't handle more then on qualifier");
|
||||
}
|
||||
|
||||
Map.Entry<PersistentPropertyPath<RelationalPersistentProperty>, Object> entry = qualifiers.entrySet().iterator().next();
|
||||
Map.Entry<PersistentPropertyPath<RelationalPersistentProperty>, Object> entry = qualifiers.entrySet().iterator()
|
||||
.next();
|
||||
if (entry.getValue() == null) {
|
||||
return null;
|
||||
}
|
||||
return Pair.of(entry.getKey(), entry.getValue());
|
||||
};
|
||||
|
||||
|
||||
@Override
|
||||
default Class<T> getEntityType() {
|
||||
return WithEntity.super.getEntityType();
|
||||
|
||||
@@ -18,6 +18,7 @@ package org.springframework.data.relational.core.conversion;
|
||||
import static java.util.Arrays.*;
|
||||
import static java.util.Collections.*;
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
import static org.assertj.core.api.SoftAssertions.*;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Value;
|
||||
@@ -30,8 +31,8 @@ import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.assertj.core.api.SoftAssertions;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.mapping.PersistentPropertyPath;
|
||||
import org.springframework.data.mapping.PersistentPropertyPaths;
|
||||
@@ -41,7 +42,8 @@ import org.springframework.data.relational.core.mapping.RelationalPersistentProp
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Unit tests for the {@link AggregateChange} testing the setting of generated ids in aggregates consisting of immutable entities.
|
||||
* Unit tests for the {@link AggregateChange} testing the setting of generated ids in aggregates consisting of immutable
|
||||
* entities.
|
||||
*
|
||||
* @author Jens Schauder
|
||||
* @author Myeonghyeon-Lee
|
||||
@@ -59,14 +61,12 @@ public class AggregateChangeIdGenerationImmutableUnitTests {
|
||||
|
||||
RelationalMappingContext context = new RelationalMappingContext();
|
||||
RelationalConverter converter = new BasicRelationalConverter(context);
|
||||
|
||||
DbAction.WithEntity<?> rootInsert = new DbAction.InsertRoot<>(entity);
|
||||
|
||||
@Test // DATAJDBC-291
|
||||
public void singleRoot() {
|
||||
|
||||
AggregateChange<DummyEntity> aggregateChange = new AggregateChange<>(AggregateChange.Kind.SAVE, DummyEntity.class,
|
||||
entity);
|
||||
AggregateChange<DummyEntity> aggregateChange = AggregateChange.forSave(entity);
|
||||
aggregateChange.addAction(rootInsert);
|
||||
|
||||
aggregateChange.executeWith(new IdSettingInterpreter(), context, converter);
|
||||
@@ -81,8 +81,7 @@ public class AggregateChangeIdGenerationImmutableUnitTests {
|
||||
|
||||
entity = entity.withSingle(content);
|
||||
|
||||
AggregateChange<DummyEntity> aggregateChange = new AggregateChange<>(AggregateChange.Kind.SAVE, DummyEntity.class,
|
||||
entity);
|
||||
AggregateChange<DummyEntity> aggregateChange = AggregateChange.forSave(entity);
|
||||
aggregateChange.addAction(rootInsert);
|
||||
aggregateChange.addAction(createInsert("single", content, null));
|
||||
|
||||
@@ -90,7 +89,7 @@ public class AggregateChangeIdGenerationImmutableUnitTests {
|
||||
|
||||
entity = aggregateChange.getEntity();
|
||||
|
||||
SoftAssertions.assertSoftly(softly -> {
|
||||
assertSoftly(softly -> {
|
||||
|
||||
softly.assertThat(entity.rootId).isEqualTo(1);
|
||||
softly.assertThat(entity.single.id).isEqualTo(2);
|
||||
@@ -102,8 +101,7 @@ public class AggregateChangeIdGenerationImmutableUnitTests {
|
||||
|
||||
entity = entity.withContentList(asList(content, content2));
|
||||
|
||||
AggregateChange<DummyEntity> aggregateChange = new AggregateChange<>(AggregateChange.Kind.SAVE, DummyEntity.class,
|
||||
entity);
|
||||
AggregateChange<DummyEntity> aggregateChange = AggregateChange.forSave(entity);
|
||||
aggregateChange.addAction(rootInsert);
|
||||
aggregateChange.addAction(createInsert("contentList", content, 0));
|
||||
aggregateChange.addAction(createInsert("contentList", content2, 1));
|
||||
@@ -112,7 +110,7 @@ public class AggregateChangeIdGenerationImmutableUnitTests {
|
||||
|
||||
entity = aggregateChange.getEntity();
|
||||
|
||||
SoftAssertions.assertSoftly(softly -> {
|
||||
assertSoftly(softly -> {
|
||||
|
||||
softly.assertThat(entity.rootId).isEqualTo(1);
|
||||
softly.assertThat(entity.contentList).extracting(c -> c.id).containsExactly(2, 3);
|
||||
@@ -124,8 +122,7 @@ public class AggregateChangeIdGenerationImmutableUnitTests {
|
||||
|
||||
entity = entity.withContentMap(createContentMap("a", content, "b", content2));
|
||||
|
||||
AggregateChange<DummyEntity> aggregateChange = new AggregateChange<>(AggregateChange.Kind.SAVE, DummyEntity.class,
|
||||
entity);
|
||||
AggregateChange<DummyEntity> aggregateChange = AggregateChange.forSave(entity);
|
||||
aggregateChange.addAction(rootInsert);
|
||||
aggregateChange.addAction(createInsert("contentMap", content, "a"));
|
||||
aggregateChange.addAction(createInsert("contentMap", content2, "b"));
|
||||
@@ -147,8 +144,7 @@ public class AggregateChangeIdGenerationImmutableUnitTests {
|
||||
DbAction.Insert<?> parentInsert = createInsert("single", content, null);
|
||||
DbAction.Insert<?> insert = createDeepInsert("single", tag1, null, parentInsert);
|
||||
|
||||
AggregateChange<DummyEntity> aggregateChange = new AggregateChange<>(AggregateChange.Kind.SAVE, DummyEntity.class,
|
||||
entity);
|
||||
AggregateChange<DummyEntity> aggregateChange = AggregateChange.forSave(entity);
|
||||
aggregateChange.addAction(rootInsert);
|
||||
aggregateChange.addAction(parentInsert);
|
||||
aggregateChange.addAction(insert);
|
||||
@@ -172,8 +168,7 @@ public class AggregateChangeIdGenerationImmutableUnitTests {
|
||||
DbAction.Insert<?> insert1 = createDeepInsert("tagList", tag1, 0, parentInsert);
|
||||
DbAction.Insert<?> insert2 = createDeepInsert("tagList", tag2, 1, parentInsert);
|
||||
|
||||
AggregateChange<DummyEntity> aggregateChange = new AggregateChange<>(AggregateChange.Kind.SAVE, DummyEntity.class,
|
||||
entity);
|
||||
AggregateChange<DummyEntity> aggregateChange = AggregateChange.forSave(entity);
|
||||
aggregateChange.addAction(rootInsert);
|
||||
aggregateChange.addAction(parentInsert);
|
||||
aggregateChange.addAction(insert1);
|
||||
@@ -183,7 +178,7 @@ public class AggregateChangeIdGenerationImmutableUnitTests {
|
||||
|
||||
entity = aggregateChange.getEntity();
|
||||
|
||||
SoftAssertions.assertSoftly(softly -> {
|
||||
assertSoftly(softly -> {
|
||||
|
||||
softly.assertThat(entity.rootId).isEqualTo(1);
|
||||
softly.assertThat(entity.single.id).isEqualTo(2);
|
||||
@@ -201,8 +196,7 @@ public class AggregateChangeIdGenerationImmutableUnitTests {
|
||||
DbAction.Insert<?> insert1 = createDeepInsert("tagSet", tag1, null, parentInsert);
|
||||
DbAction.Insert<?> insert2 = createDeepInsert("tagSet", tag2, null, parentInsert);
|
||||
|
||||
AggregateChange<DummyEntity> aggregateChange = new AggregateChange<>(AggregateChange.Kind.SAVE, DummyEntity.class,
|
||||
entity);
|
||||
AggregateChange<DummyEntity> aggregateChange = AggregateChange.forSave(entity);
|
||||
aggregateChange.addAction(rootInsert);
|
||||
aggregateChange.addAction(parentInsert);
|
||||
aggregateChange.addAction(insert1);
|
||||
@@ -212,7 +206,7 @@ public class AggregateChangeIdGenerationImmutableUnitTests {
|
||||
|
||||
entity = aggregateChange.getEntity();
|
||||
|
||||
SoftAssertions.assertSoftly(softly -> {
|
||||
assertSoftly(softly -> {
|
||||
|
||||
softly.assertThat(entity.rootId).isEqualTo(1);
|
||||
softly.assertThat(entity.contentSet) //
|
||||
@@ -237,8 +231,7 @@ public class AggregateChangeIdGenerationImmutableUnitTests {
|
||||
DbAction.Insert<?> insert1 = createDeepInsert("single", tag1, null, parentInsert1);
|
||||
DbAction.Insert<?> insert2 = createDeepInsert("single", tag2, null, parentInsert2);
|
||||
|
||||
AggregateChange<DummyEntity> aggregateChange = new AggregateChange<>(AggregateChange.Kind.SAVE, DummyEntity.class,
|
||||
entity);
|
||||
AggregateChange<DummyEntity> aggregateChange = AggregateChange.forSave(entity);
|
||||
aggregateChange.addAction(rootInsert);
|
||||
aggregateChange.addAction(parentInsert1);
|
||||
aggregateChange.addAction(parentInsert2);
|
||||
@@ -249,7 +242,7 @@ public class AggregateChangeIdGenerationImmutableUnitTests {
|
||||
|
||||
entity = aggregateChange.getEntity();
|
||||
|
||||
SoftAssertions.assertSoftly(softly -> {
|
||||
assertSoftly(softly -> {
|
||||
|
||||
softly.assertThat(entity.rootId).isEqualTo(1);
|
||||
softly.assertThat(entity.contentList) //
|
||||
@@ -271,8 +264,7 @@ public class AggregateChangeIdGenerationImmutableUnitTests {
|
||||
DbAction.Insert<?> insert2 = createDeepInsert("tagList", tag2, 0, parentInsert2);
|
||||
DbAction.Insert<?> insert3 = createDeepInsert("tagList", tag3, 1, parentInsert2);
|
||||
|
||||
AggregateChange<DummyEntity> aggregateChange = new AggregateChange<>(AggregateChange.Kind.SAVE, DummyEntity.class,
|
||||
entity);
|
||||
AggregateChange<DummyEntity> aggregateChange = AggregateChange.forSave(entity);
|
||||
aggregateChange.addAction(rootInsert);
|
||||
aggregateChange.addAction(parentInsert1);
|
||||
aggregateChange.addAction(parentInsert2);
|
||||
@@ -284,7 +276,7 @@ public class AggregateChangeIdGenerationImmutableUnitTests {
|
||||
|
||||
entity = aggregateChange.getEntity();
|
||||
|
||||
SoftAssertions.assertSoftly(softly -> {
|
||||
assertSoftly(softly -> {
|
||||
|
||||
softly.assertThat(entity.rootId).isEqualTo(1);
|
||||
softly.assertThat(entity.contentList) //
|
||||
@@ -309,8 +301,7 @@ public class AggregateChangeIdGenerationImmutableUnitTests {
|
||||
DbAction.Insert<?> insert2 = createDeepInsert("tagMap", tag2, "222", parentInsert2);
|
||||
DbAction.Insert<?> insert3 = createDeepInsert("tagMap", tag3, "333", parentInsert2);
|
||||
|
||||
AggregateChange<DummyEntity> aggregateChange = new AggregateChange<>(AggregateChange.Kind.SAVE, DummyEntity.class,
|
||||
entity);
|
||||
AggregateChange<DummyEntity> aggregateChange = AggregateChange.forSave(entity);
|
||||
aggregateChange.addAction(rootInsert);
|
||||
aggregateChange.addAction(parentInsert1);
|
||||
aggregateChange.addAction(parentInsert2);
|
||||
@@ -322,7 +313,7 @@ public class AggregateChangeIdGenerationImmutableUnitTests {
|
||||
|
||||
entity = aggregateChange.getEntity();
|
||||
|
||||
SoftAssertions.assertSoftly(softly -> {
|
||||
assertSoftly(softly -> {
|
||||
|
||||
softly.assertThat(entity.rootId).isEqualTo(1);
|
||||
softly.assertThat(entity.contentMap.entrySet()) //
|
||||
@@ -351,8 +342,7 @@ public class AggregateChangeIdGenerationImmutableUnitTests {
|
||||
DbAction.Insert<?> insert1 = createDeepInsert("single", tag1, null, parentInsert1);
|
||||
DbAction.Insert<?> insert2 = createDeepInsert("single", tag2, null, parentInsert2);
|
||||
|
||||
AggregateChange<DummyEntity> aggregateChange = new AggregateChange<>(AggregateChange.Kind.SAVE, DummyEntity.class,
|
||||
entity);
|
||||
AggregateChange<DummyEntity> aggregateChange = AggregateChange.forSave(entity);
|
||||
aggregateChange.addAction(rootInsert);
|
||||
aggregateChange.addAction(parentInsert1);
|
||||
aggregateChange.addAction(parentInsert2);
|
||||
@@ -363,7 +353,7 @@ public class AggregateChangeIdGenerationImmutableUnitTests {
|
||||
|
||||
entity = aggregateChange.getEntity();
|
||||
|
||||
SoftAssertions.assertSoftly(softly -> {
|
||||
assertSoftly(softly -> {
|
||||
|
||||
softly.assertThat(entity.rootId).isEqualTo(1);
|
||||
softly.assertThat(entity.contentNoIdList) //
|
||||
@@ -380,8 +370,7 @@ public class AggregateChangeIdGenerationImmutableUnitTests {
|
||||
|
||||
DbAction.Insert<?> parentInsert = createInsert("embedded.single", tag1, null);
|
||||
|
||||
AggregateChange<DummyEntity> aggregateChange = new AggregateChange<>(AggregateChange.Kind.SAVE, DummyEntity.class,
|
||||
entity);
|
||||
AggregateChange<DummyEntity> aggregateChange = AggregateChange.forSave(entity);
|
||||
aggregateChange.addAction(rootInsert);
|
||||
aggregateChange.addAction(parentInsert);
|
||||
|
||||
@@ -441,11 +430,10 @@ public class AggregateChangeIdGenerationImmutableUnitTests {
|
||||
|
||||
PersistentPropertyPath<RelationalPersistentProperty> toPath(DummyEntity root, Object pathValue) {
|
||||
// DefaultPersistentPropertyPath is package-public
|
||||
return new WritingContext(context, entity,
|
||||
new AggregateChange<>(AggregateChange.Kind.SAVE, DummyEntity.class, root)).insert().stream()
|
||||
.filter(a -> a instanceof DbAction.Insert).map(DbAction.Insert.class::cast)
|
||||
.filter(a -> a.getEntity() == pathValue).map(DbAction.Insert::getPropertyPath).findFirst()
|
||||
.orElseThrow(() -> new IllegalArgumentException("No matching path found for " + pathValue));
|
||||
return new WritingContext(context, entity, AggregateChange.forSave(root)).insert().stream()
|
||||
.filter(a -> a instanceof DbAction.Insert).map(DbAction.Insert.class::cast)
|
||||
.filter(a -> a.getEntity() == pathValue).map(DbAction.Insert::getPropertyPath).findFirst()
|
||||
.orElseThrow(() -> new IllegalArgumentException("No matching path found for " + pathValue));
|
||||
}
|
||||
|
||||
@Value
|
||||
|
||||
@@ -37,7 +37,7 @@ import org.springframework.lang.Nullable;
|
||||
* Unit tests for the {@link AggregateChange}.
|
||||
*
|
||||
* @author Jens Schauder
|
||||
* Myeonghyeon-Lee
|
||||
* @author Myeonghyeon-Lee
|
||||
*/
|
||||
public class AggregateChangeIdGenerationUnitTests {
|
||||
|
||||
@@ -50,14 +50,12 @@ public class AggregateChangeIdGenerationUnitTests {
|
||||
|
||||
RelationalMappingContext context = new RelationalMappingContext();
|
||||
RelationalConverter converter = new BasicRelationalConverter(context);
|
||||
|
||||
DbAction.WithEntity<?> rootInsert = new DbAction.InsertRoot<>(entity);
|
||||
|
||||
@Test // DATAJDBC-291
|
||||
public void singleRoot() {
|
||||
|
||||
AggregateChange<DummyEntity> aggregateChange = new AggregateChange<>(AggregateChange.Kind.SAVE, DummyEntity.class,
|
||||
entity);
|
||||
AggregateChange<DummyEntity> aggregateChange = AggregateChange.forSave(entity);
|
||||
aggregateChange.addAction(rootInsert);
|
||||
|
||||
aggregateChange.executeWith(new IdSettingInterpreter(), context, converter);
|
||||
@@ -70,8 +68,7 @@ public class AggregateChangeIdGenerationUnitTests {
|
||||
|
||||
entity.single = content;
|
||||
|
||||
AggregateChange<DummyEntity> aggregateChange = new AggregateChange<>(AggregateChange.Kind.SAVE, DummyEntity.class,
|
||||
entity);
|
||||
AggregateChange<DummyEntity> aggregateChange = AggregateChange.forSave(entity);
|
||||
aggregateChange.addAction(rootInsert);
|
||||
aggregateChange.addAction(createInsert("single", content, null));
|
||||
|
||||
@@ -90,8 +87,7 @@ public class AggregateChangeIdGenerationUnitTests {
|
||||
entity.contentList.add(content);
|
||||
entity.contentList.add(content2);
|
||||
|
||||
AggregateChange<DummyEntity> aggregateChange = new AggregateChange<>(AggregateChange.Kind.SAVE, DummyEntity.class,
|
||||
entity);
|
||||
AggregateChange<DummyEntity> aggregateChange = AggregateChange.forSave(entity);
|
||||
aggregateChange.addAction(rootInsert);
|
||||
aggregateChange.addAction(createInsert("contentList", content, 0));
|
||||
aggregateChange.addAction(createInsert("contentList", content2, 1));
|
||||
@@ -111,8 +107,7 @@ public class AggregateChangeIdGenerationUnitTests {
|
||||
entity.contentMap.put("a", content);
|
||||
entity.contentMap.put("b", content2);
|
||||
|
||||
AggregateChange<DummyEntity> aggregateChange = new AggregateChange<>(AggregateChange.Kind.SAVE, DummyEntity.class,
|
||||
entity);
|
||||
AggregateChange<DummyEntity> aggregateChange = AggregateChange.forSave(entity);
|
||||
aggregateChange.addAction(rootInsert);
|
||||
aggregateChange.addAction(createInsert("contentMap", content, "a"));
|
||||
aggregateChange.addAction(createInsert("contentMap", content2, "b"));
|
||||
@@ -132,8 +127,7 @@ public class AggregateChangeIdGenerationUnitTests {
|
||||
DbAction.Insert<?> parentInsert = createInsert("single", content, null);
|
||||
DbAction.Insert<?> insert = createDeepInsert("single", tag1, null, parentInsert);
|
||||
|
||||
AggregateChange<DummyEntity> aggregateChange = new AggregateChange<>(AggregateChange.Kind.SAVE, DummyEntity.class,
|
||||
entity);
|
||||
AggregateChange<DummyEntity> aggregateChange = AggregateChange.forSave(entity);
|
||||
aggregateChange.addAction(rootInsert);
|
||||
aggregateChange.addAction(parentInsert);
|
||||
aggregateChange.addAction(insert);
|
||||
@@ -156,8 +150,7 @@ public class AggregateChangeIdGenerationUnitTests {
|
||||
DbAction.Insert<?> insert1 = createDeepInsert("tagList", tag1, 0, parentInsert);
|
||||
DbAction.Insert<?> insert2 = createDeepInsert("tagList", tag2, 1, parentInsert);
|
||||
|
||||
AggregateChange<DummyEntity> aggregateChange = new AggregateChange<>(AggregateChange.Kind.SAVE, DummyEntity.class,
|
||||
entity);
|
||||
AggregateChange<DummyEntity> aggregateChange = AggregateChange.forSave(entity);
|
||||
aggregateChange.addAction(rootInsert);
|
||||
aggregateChange.addAction(parentInsert);
|
||||
aggregateChange.addAction(insert1);
|
||||
@@ -184,8 +177,7 @@ public class AggregateChangeIdGenerationUnitTests {
|
||||
DbAction.Insert<?> insert1 = createDeepInsert("tagSet", tag1, null, parentInsert);
|
||||
DbAction.Insert<?> insert2 = createDeepInsert("tagSet", tag2, null, parentInsert);
|
||||
|
||||
AggregateChange<DummyEntity> aggregateChange = new AggregateChange<>(AggregateChange.Kind.SAVE, DummyEntity.class,
|
||||
entity);
|
||||
AggregateChange<DummyEntity> aggregateChange = AggregateChange.forSave(entity);
|
||||
aggregateChange.addAction(rootInsert);
|
||||
aggregateChange.addAction(parentInsert);
|
||||
aggregateChange.addAction(insert1);
|
||||
@@ -219,8 +211,7 @@ public class AggregateChangeIdGenerationUnitTests {
|
||||
DbAction.Insert<?> insert1 = createDeepInsert("single", tag1, null, parentInsert1);
|
||||
DbAction.Insert<?> insert2 = createDeepInsert("single", tag2, null, parentInsert2);
|
||||
|
||||
AggregateChange<DummyEntity> aggregateChange = new AggregateChange<>(AggregateChange.Kind.SAVE, DummyEntity.class,
|
||||
entity);
|
||||
AggregateChange<DummyEntity> aggregateChange = AggregateChange.forSave(entity);
|
||||
aggregateChange.addAction(rootInsert);
|
||||
aggregateChange.addAction(parentInsert1);
|
||||
aggregateChange.addAction(parentInsert2);
|
||||
@@ -253,8 +244,7 @@ public class AggregateChangeIdGenerationUnitTests {
|
||||
DbAction.Insert<?> insert2 = createDeepInsert("tagList", tag2, 0, parentInsert2);
|
||||
DbAction.Insert<?> insert3 = createDeepInsert("tagList", tag3, 1, parentInsert2);
|
||||
|
||||
AggregateChange<DummyEntity> aggregateChange = new AggregateChange<>(AggregateChange.Kind.SAVE, DummyEntity.class,
|
||||
entity);
|
||||
AggregateChange<DummyEntity> aggregateChange = AggregateChange.forSave(entity);
|
||||
aggregateChange.addAction(rootInsert);
|
||||
aggregateChange.addAction(parentInsert1);
|
||||
aggregateChange.addAction(parentInsert2);
|
||||
@@ -292,8 +282,7 @@ public class AggregateChangeIdGenerationUnitTests {
|
||||
DbAction.Insert<?> insert2 = createDeepInsert("tagMap", tag2, "222", parentInsert2);
|
||||
DbAction.Insert<?> insert3 = createDeepInsert("tagMap", tag3, "333", parentInsert2);
|
||||
|
||||
AggregateChange<DummyEntity> aggregateChange = new AggregateChange<>(AggregateChange.Kind.SAVE, DummyEntity.class,
|
||||
entity);
|
||||
AggregateChange<DummyEntity> aggregateChange = AggregateChange.forSave(entity);
|
||||
aggregateChange.addAction(rootInsert);
|
||||
aggregateChange.addAction(parentInsert1);
|
||||
aggregateChange.addAction(parentInsert2);
|
||||
@@ -348,11 +337,10 @@ public class AggregateChangeIdGenerationUnitTests {
|
||||
|
||||
PersistentPropertyPath<RelationalPersistentProperty> toPath(DummyEntity root, Object pathValue) {
|
||||
// DefaultPersistentPropertyPath is package-public
|
||||
return new WritingContext(context, entity,
|
||||
new AggregateChange<>(AggregateChange.Kind.SAVE, DummyEntity.class, root)).insert().stream()
|
||||
.filter(a -> a instanceof DbAction.Insert).map(DbAction.Insert.class::cast)
|
||||
.filter(a -> a.getEntity() == pathValue).map(DbAction.Insert::getPropertyPath).findFirst()
|
||||
.orElseThrow(() -> new IllegalArgumentException("No matching path found"));
|
||||
return new WritingContext(context, entity, AggregateChange.forSave(root)).insert().stream()
|
||||
.filter(a -> a instanceof DbAction.Insert).map(DbAction.Insert.class::cast)
|
||||
.filter(a -> a.getEntity() == pathValue).map(DbAction.Insert::getPropertyPath).findFirst()
|
||||
.orElseThrow(() -> new IllegalArgumentException("No matching path found"));
|
||||
}
|
||||
|
||||
private static class DummyEntity {
|
||||
|
||||
Reference in New Issue
Block a user