diff --git a/pom.xml b/pom.xml index b293417702..16d92e7a35 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.springframework.data spring-data-jdbc - 1.0.0.BUILD-SNAPSHOT + 1.0.0.DATAJDBC-188-SNAPSHOT Spring Data JDBC Spring Data module for JDBC repositories. diff --git a/src/main/java/org/springframework/data/jdbc/core/mapping/JdbcMappingContext.java b/src/main/java/org/springframework/data/jdbc/core/mapping/JdbcMappingContext.java index fb8c972a30..7b6af0de45 100644 --- a/src/main/java/org/springframework/data/jdbc/core/mapping/JdbcMappingContext.java +++ b/src/main/java/org/springframework/data/jdbc/core/mapping/JdbcMappingContext.java @@ -94,6 +94,10 @@ public void setSimpleTypeHolder(SimpleTypeHolder simpleTypes) { this.simpleTypeHolder = simpleTypes; } + /** + * returns all {@link PropertyPath}s reachable from the root type in the order needed for deleting, i.e. the deepest + * reference first. + */ public List referencedEntities(Class rootType, PropertyPath path) { List paths = new ArrayList<>(); diff --git a/src/test/java/org/springframework/data/jdbc/core/conversion/JdbcEntityDeleteWriterUnitTests.java b/src/test/java/org/springframework/data/jdbc/core/conversion/JdbcEntityDeleteWriterUnitTests.java index beed915955..cc6adfdab4 100644 --- a/src/test/java/org/springframework/data/jdbc/core/conversion/JdbcEntityDeleteWriterUnitTests.java +++ b/src/test/java/org/springframework/data/jdbc/core/conversion/JdbcEntityDeleteWriterUnitTests.java @@ -25,6 +25,7 @@ import org.springframework.data.annotation.Id; import org.springframework.data.jdbc.core.conversion.AggregateChange.Kind; import org.springframework.data.jdbc.core.conversion.DbAction.Delete; +import org.springframework.data.jdbc.core.conversion.DbAction.DeleteAll; import org.springframework.data.jdbc.core.mapping.JdbcMappingContext; /** @@ -37,21 +38,46 @@ public class JdbcEntityDeleteWriterUnitTests { JdbcEntityDeleteWriter converter = new JdbcEntityDeleteWriter(new JdbcMappingContext()); - @Test + private static Object dotPath(DbAction dba) { + + JdbcPropertyPath propertyPath = dba.getPropertyPath(); + return propertyPath == null ? null : propertyPath.toDotPath(); + } + + @Test // DATAJDBC-112 public void deleteDeletesTheEntityAndReferencedEntities() { SomeEntity entity = new SomeEntity(23L); AggregateChange aggregateChange = new AggregateChange<>(Kind.DELETE, SomeEntity.class, entity); - converter.write(entity, aggregateChange); + converter.write(entity.id, aggregateChange); + + Assertions.assertThat(aggregateChange.getActions()) + .extracting(DbAction::getClass, DbAction::getEntityType, JdbcEntityDeleteWriterUnitTests::dotPath) // + .containsExactly( // + Tuple.tuple(Delete.class, YetAnother.class, "other.yetAnother"), // + Tuple.tuple(Delete.class, OtherEntity.class, "other"), // + Tuple.tuple(Delete.class, SomeEntity.class, null) // + ); + } + + @Test // DATAJDBC-188 + public void deleteAllDeletesAllEntitiesAndReferencedEntities() { + + SomeEntity entity = new SomeEntity(23L); + + AggregateChange aggregateChange = new AggregateChange(Kind.DELETE, SomeEntity.class, null); + + converter.write(null, aggregateChange); - Assertions.assertThat(aggregateChange.getActions()).extracting(DbAction::getClass, DbAction::getEntityType) + Assertions.assertThat(aggregateChange.getActions()) + .extracting(DbAction::getClass, DbAction::getEntityType, JdbcEntityDeleteWriterUnitTests::dotPath) // .containsExactly( // - Tuple.tuple(Delete.class, YetAnother.class), // - Tuple.tuple(Delete.class, OtherEntity.class), // - Tuple.tuple(Delete.class, SomeEntity.class) // - ); + Tuple.tuple(DeleteAll.class, YetAnother.class, "other.yetAnother"), // + Tuple.tuple(DeleteAll.class, OtherEntity.class, "other"), // + Tuple.tuple(DeleteAll.class, SomeEntity.class, null) // + ); } @Data diff --git a/src/test/java/org/springframework/data/jdbc/core/conversion/JdbcEntityWriterUnitTests.java b/src/test/java/org/springframework/data/jdbc/core/conversion/JdbcEntityWriterUnitTests.java index 8acb5c14b8..b86e2ae2a5 100644 --- a/src/test/java/org/springframework/data/jdbc/core/conversion/JdbcEntityWriterUnitTests.java +++ b/src/test/java/org/springframework/data/jdbc/core/conversion/JdbcEntityWriterUnitTests.java @@ -32,6 +32,7 @@ import org.springframework.data.annotation.Id; import org.springframework.data.jdbc.core.conversion.AggregateChange.Kind; import org.springframework.data.jdbc.core.conversion.DbAction.Delete; +import org.springframework.data.jdbc.core.conversion.DbAction.DeleteAll; import org.springframework.data.jdbc.core.conversion.DbAction.Insert; import org.springframework.data.jdbc.core.conversion.DbAction.Update; import org.springframework.data.jdbc.core.mapping.JdbcMappingContext; @@ -163,6 +164,39 @@ public void cascadingReferencesTriggerCascadingActions() { ); } + @Test // DATAJDBC-188 + public void cascadingReferencesTriggerCascadingActionsForUpdate() { + + CascadingReferenceEntity entity = new CascadingReferenceEntity(23L); + + entity.other.add(createMiddleElement( // + new Element(null), // + new Element(null)) // + ); + + entity.other.add(createMiddleElement( // + new Element(null), // + new Element(null)) // + ); + + AggregateChange aggregateChange = new AggregateChange(Kind.SAVE, CascadingReferenceEntity.class, entity); + + converter.write(entity, aggregateChange); + + assertThat(aggregateChange.getActions()).extracting(DbAction::getClass, DbAction::getEntityType, this::extractPath) // + .containsExactly( // + tuple(Delete.class, Element.class, "other.element"), + tuple(Delete.class, CascadingReferenceMiddleElement.class, "other"), + tuple(Update.class, CascadingReferenceEntity.class, ""), // + tuple(Insert.class, CascadingReferenceMiddleElement.class, "other"), // + tuple(Insert.class, Element.class, "other.element"), // + tuple(Insert.class, Element.class, "other.element"), // + tuple(Insert.class, CascadingReferenceMiddleElement.class, "other"), // + tuple(Insert.class, Element.class, "other.element"), // + tuple(Insert.class, Element.class, "other.element") // + ); + } + @Test // DATAJDBC-131 public void newEntityWithEmptyMapResultsInSingleInsert() { diff --git a/src/test/java/org/springframework/data/jdbc/mapping/model/JdbcMappingContextUnitTests.java b/src/test/java/org/springframework/data/jdbc/mapping/model/JdbcMappingContextUnitTests.java new file mode 100644 index 0000000000..0d25f840ba --- /dev/null +++ b/src/test/java/org/springframework/data/jdbc/mapping/model/JdbcMappingContextUnitTests.java @@ -0,0 +1,102 @@ +/* + * Copyright 2018 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 + * + * http://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.mapping.model; + +import static org.assertj.core.api.Assertions.*; + +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.junit.Test; +import org.springframework.data.jdbc.core.mapping.JdbcMappingContext; +import org.springframework.data.mapping.PropertyPath; + +/** + * @author Jens Schauder + */ +public class JdbcMappingContextUnitTests { + + JdbcMappingContext context = new JdbcMappingContext(); + + // DATAJDBC-188 + @Test + public void simpleEntityDoesntReferenceOtherEntities() { + + List paths = context.referencedEntities(SimpleEntity.class, null); + + assertThat(paths).isEmpty(); + } + + // DATAJDBC-188 + @Test + public void cascadingReferencesGetFound() { + + List paths = context.referencedEntities(CascadingEntity.class, null); + + assertThat(paths).extracting(PropertyPath::toDotPath) // + .containsExactly( // + "reference.reference", // + "reference" // + ); + } + + // DATAJDBC-188 + @Test + public void setReferencesGetFound() { + + List paths = context.referencedEntities(EntityWithSet.class, null); + + assertThat(paths).extracting(PropertyPath::toDotPath) // + .containsExactly( // + "set.reference", // + "set" // + ); + } + + // DATAJDBC-188 + @Test + public void mapReferencesGetFound() { + + List paths = context.referencedEntities(EntityWithMap.class, null); + + assertThat(paths).extracting(PropertyPath::toDotPath) // + .containsExactly( // + "map.reference", // + "map" // + ); + } + + private static class SimpleEntity { + String name; + } + + private static class CascadingEntity { + MiddleEntity reference; + } + + private static class MiddleEntity { + SimpleEntity reference; + } + + private static class EntityWithMap { + Map map; + } + + private static class EntityWithSet { + Set set; + } +}