DATAJDBC-227 - Refactored JdbcEntityWriter and DbActions.
JdbcEntityWriter and JdbcDeleteEntityWriter now use an iterative approach based on PersistentPropertyPath instead of a recursive one. DbAction is now split into multiple interfaces representing different variants of actions. The implementations are simple value types without any implementation inheritance hierarchy. All elements of a DbAction implementation are not null making usage and construction of instances much easier. Original pull request: #79.
This commit is contained in:
committed by
Mark Paluch
parent
c412aad6b8
commit
bdefd3da9a
@@ -16,7 +16,7 @@
|
||||
package org.springframework.data.jdbc.core;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
import static org.mockito.ArgumentMatchers.*;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import java.util.AbstractMap.SimpleEntry;
|
||||
@@ -25,13 +25,11 @@ import java.util.Map;
|
||||
import org.junit.Test;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.relational.core.conversion.DbAction;
|
||||
import org.springframework.data.relational.core.conversion.RelationalPropertyPath;
|
||||
import org.springframework.data.relational.core.conversion.DbAction.Insert;
|
||||
import org.springframework.data.relational.core.conversion.DbAction.InsertRoot;
|
||||
import org.springframework.data.relational.core.mapping.NamingStrategy;
|
||||
import org.springframework.data.relational.core.mapping.RelationalMappingContext;
|
||||
import org.springframework.data.relational.core.mapping.RelationalPersistentProperty;
|
||||
import org.springframework.data.relational.core.mapping.NamingStrategy;
|
||||
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link DefaultJdbcInterpreter}
|
||||
@@ -61,8 +59,8 @@ public class DefaultJdbcInterpreterUnitTests {
|
||||
|
||||
Element element = new Element();
|
||||
|
||||
Insert<?> containerInsert = DbAction.insert(container, RelationalPropertyPath.from("", Container.class), null);
|
||||
Insert<?> insert = DbAction.insert(element, RelationalPropertyPath.from("element", Container.class), containerInsert);
|
||||
InsertRoot<Container> containerInsert = new InsertRoot<>(container);
|
||||
Insert<?> insert = new Insert<>(element, PropertyPathUtils.toPath("element", Container.class, context), containerInsert);
|
||||
|
||||
interpreter.interpret(insert);
|
||||
|
||||
|
||||
@@ -22,14 +22,14 @@ import static org.mockito.Mockito.*;
|
||||
import java.util.Collections;
|
||||
|
||||
import org.apache.ibatis.session.SqlSession;
|
||||
import org.apache.ibatis.session.SqlSessionFactory;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Mockito;
|
||||
import org.springframework.data.jdbc.mybatis.MyBatisContext;
|
||||
import org.springframework.data.jdbc.mybatis.MyBatisDataAccessStrategy;
|
||||
import org.springframework.data.mapping.PropertyPath;
|
||||
import org.springframework.data.mapping.PersistentPropertyPath;
|
||||
import org.springframework.data.relational.core.mapping.RelationalMappingContext;
|
||||
import org.springframework.data.relational.core.mapping.RelationalPersistentProperty;
|
||||
|
||||
/**
|
||||
@@ -39,11 +39,20 @@ import org.springframework.data.relational.core.mapping.RelationalPersistentProp
|
||||
*/
|
||||
public class MyBatisDataAccessStrategyUnitTests {
|
||||
|
||||
RelationalMappingContext context = new RelationalMappingContext();
|
||||
|
||||
SqlSession session = mock(SqlSession.class);
|
||||
ArgumentCaptor<MyBatisContext> captor = ArgumentCaptor.forClass(MyBatisContext.class);
|
||||
|
||||
MyBatisDataAccessStrategy accessStrategy = new MyBatisDataAccessStrategy(session);
|
||||
|
||||
PersistentPropertyPath<RelationalPersistentProperty> path(String path, Class source) {
|
||||
|
||||
RelationalMappingContext context = this.context;
|
||||
return PropertyPathUtils.toPath(path, source, context);
|
||||
|
||||
}
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
|
||||
@@ -119,9 +128,11 @@ public class MyBatisDataAccessStrategyUnitTests {
|
||||
@Test // DATAJDBC-123
|
||||
public void deleteAllByPath() {
|
||||
|
||||
accessStrategy.deleteAll(PropertyPath.from("class.name.bytes", String.class));
|
||||
accessStrategy.deleteAll(path("one.two", DummyEntity.class));
|
||||
|
||||
verify(session).delete(eq("java.lang.StringMapper.deleteAll-class-name-bytes"), captor.capture());
|
||||
verify(session).delete(
|
||||
eq("org.springframework.data.jdbc.core.MyBatisDataAccessStrategyUnitTests$DummyEntityMapper.deleteAll-one-two"),
|
||||
captor.capture());
|
||||
|
||||
assertThat(captor.getValue()) //
|
||||
.isNotNull() //
|
||||
@@ -133,7 +144,7 @@ public class MyBatisDataAccessStrategyUnitTests {
|
||||
).containsExactly( //
|
||||
null, //
|
||||
null, //
|
||||
byte[].class, //
|
||||
ChildTwo.class, //
|
||||
null //
|
||||
);
|
||||
}
|
||||
@@ -163,9 +174,11 @@ public class MyBatisDataAccessStrategyUnitTests {
|
||||
@Test // DATAJDBC-123
|
||||
public void deleteByPath() {
|
||||
|
||||
accessStrategy.delete("rootid", PropertyPath.from("class.name.bytes", String.class));
|
||||
accessStrategy.delete("rootid", path("one.two", DummyEntity.class));
|
||||
|
||||
verify(session).delete(eq("java.lang.StringMapper.delete-class-name-bytes"), captor.capture());
|
||||
verify(session).delete(
|
||||
eq("org.springframework.data.jdbc.core.MyBatisDataAccessStrategyUnitTests$DummyEntityMapper.delete-one-two"),
|
||||
captor.capture());
|
||||
|
||||
assertThat(captor.getValue()) //
|
||||
.isNotNull() //
|
||||
@@ -176,7 +189,7 @@ public class MyBatisDataAccessStrategyUnitTests {
|
||||
c -> c.get("key") //
|
||||
).containsExactly( //
|
||||
null, "rootid", //
|
||||
byte[].class, //
|
||||
ChildTwo.class, //
|
||||
null //
|
||||
);
|
||||
}
|
||||
@@ -304,7 +317,6 @@ public class MyBatisDataAccessStrategyUnitTests {
|
||||
|
||||
accessStrategy.count(String.class);
|
||||
|
||||
|
||||
verify(session).selectOne(eq("java.lang.StringMapper.count"), captor.capture());
|
||||
|
||||
assertThat(captor.getValue()) //
|
||||
@@ -315,11 +327,20 @@ public class MyBatisDataAccessStrategyUnitTests {
|
||||
MyBatisContext::getDomainType, //
|
||||
c -> c.get("key") //
|
||||
).containsExactly( //
|
||||
null, //
|
||||
null, //
|
||||
String.class, //
|
||||
null //
|
||||
null, //
|
||||
null, //
|
||||
String.class, //
|
||||
null //
|
||||
);
|
||||
}
|
||||
|
||||
private static class DummyEntity {
|
||||
ChildOne one;
|
||||
}
|
||||
|
||||
private static class ChildOne {
|
||||
ChildTwo two;
|
||||
}
|
||||
|
||||
private static class ChildTwo {}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
package org.springframework.data.jdbc.core;
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import lombok.experimental.UtilityClass;
|
||||
|
||||
import org.springframework.data.mapping.PersistentPropertyPath;
|
||||
import org.springframework.data.mapping.PersistentPropertyPaths;
|
||||
import org.springframework.data.relational.core.mapping.RelationalMappingContext;
|
||||
import org.springframework.data.relational.core.mapping.RelationalPersistentProperty;
|
||||
|
||||
/**
|
||||
* Utility class for easy creation of {@link PersistentPropertyPath} instances for tests.
|
||||
*
|
||||
* @author Jens Schauder
|
||||
*/
|
||||
@UtilityClass
|
||||
class PropertyPathUtils {
|
||||
|
||||
static PersistentPropertyPath<RelationalPersistentProperty> toPath(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);
|
||||
}
|
||||
}
|
||||
@@ -25,10 +25,12 @@ import java.util.function.Consumer;
|
||||
import org.assertj.core.api.SoftAssertions;
|
||||
import org.junit.Test;
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.mapping.PropertyPath;
|
||||
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;
|
||||
import org.springframework.data.relational.core.mapping.RelationalPersistentEntity;
|
||||
import org.springframework.data.relational.core.mapping.NamingStrategy;
|
||||
import org.springframework.data.relational.core.mapping.RelationalPersistentProperty;
|
||||
|
||||
/**
|
||||
* Unit tests to verify a contextual {@link NamingStrategy} implementation that customizes using a user-centric
|
||||
@@ -39,7 +41,8 @@ import org.springframework.data.relational.core.mapping.NamingStrategy;
|
||||
*/
|
||||
public class SqlGeneratorContextBasedNamingStrategyUnitTests {
|
||||
|
||||
private final ThreadLocal<String> userHandler = new ThreadLocal<>();
|
||||
RelationalMappingContext context = new RelationalMappingContext();
|
||||
ThreadLocal<String> userHandler = new ThreadLocal<>();
|
||||
|
||||
/**
|
||||
* Use a {@link NamingStrategy}, but override the schema with a {@link ThreadLocal}-based setting.
|
||||
@@ -80,9 +83,9 @@ public class SqlGeneratorContextBasedNamingStrategyUnitTests {
|
||||
|
||||
SqlGenerator sqlGenerator = configureSqlGenerator(contextualNamingStrategy);
|
||||
|
||||
String sql = sqlGenerator.createDeleteByPath(PropertyPath.from("ref", DummyEntity.class));
|
||||
String sql = sqlGenerator.createDeleteByPath(getPath("ref", DummyEntity.class));
|
||||
|
||||
assertThat(sql).isEqualTo("DELETE FROM " + user + ".referenced_entity WHERE " + user + ".dummy_entity = :rootId");
|
||||
assertThat(sql).isEqualTo("DELETE FROM " + user + ".referenced_entity WHERE " + "dummy_entity = :rootId");
|
||||
});
|
||||
}
|
||||
|
||||
@@ -93,13 +96,13 @@ public class SqlGeneratorContextBasedNamingStrategyUnitTests {
|
||||
|
||||
SqlGenerator sqlGenerator = configureSqlGenerator(contextualNamingStrategy);
|
||||
|
||||
String sql = sqlGenerator.createDeleteByPath(PropertyPath.from("ref.further", DummyEntity.class));
|
||||
String sql = sqlGenerator.createDeleteByPath(getPath("ref.further", DummyEntity.class));
|
||||
|
||||
assertThat(sql).isEqualTo( //
|
||||
"DELETE FROM " + user + ".second_level_referenced_entity " //
|
||||
+ "WHERE " + user + ".referenced_entity IN " //
|
||||
+ "WHERE " + "referenced_entity IN " //
|
||||
+ "(SELECT l1id FROM " + user + ".referenced_entity " //
|
||||
+ "WHERE " + user + ".dummy_entity = :rootId)");
|
||||
+ "WHERE " + "dummy_entity = :rootId)");
|
||||
});
|
||||
}
|
||||
|
||||
@@ -123,10 +126,10 @@ public class SqlGeneratorContextBasedNamingStrategyUnitTests {
|
||||
|
||||
SqlGenerator sqlGenerator = configureSqlGenerator(contextualNamingStrategy);
|
||||
|
||||
String sql = sqlGenerator.createDeleteAllSql(PropertyPath.from("ref", DummyEntity.class));
|
||||
String sql = sqlGenerator.createDeleteAllSql(getPath("ref", DummyEntity.class));
|
||||
|
||||
assertThat(sql).isEqualTo( //
|
||||
"DELETE FROM " + user + ".referenced_entity WHERE " + user + ".dummy_entity IS NOT NULL");
|
||||
"DELETE FROM " + user + ".referenced_entity WHERE " + "dummy_entity IS NOT NULL");
|
||||
});
|
||||
}
|
||||
|
||||
@@ -137,16 +140,20 @@ public class SqlGeneratorContextBasedNamingStrategyUnitTests {
|
||||
|
||||
SqlGenerator sqlGenerator = configureSqlGenerator(contextualNamingStrategy);
|
||||
|
||||
String sql = sqlGenerator.createDeleteAllSql(PropertyPath.from("ref.further", DummyEntity.class));
|
||||
String sql = sqlGenerator.createDeleteAllSql(getPath("ref.further", DummyEntity.class));
|
||||
|
||||
assertThat(sql).isEqualTo( //
|
||||
"DELETE FROM " + user + ".second_level_referenced_entity " //
|
||||
+ "WHERE " + user + ".referenced_entity IN " //
|
||||
+ "WHERE " + "referenced_entity IN " //
|
||||
+ "(SELECT l1id FROM " + user + ".referenced_entity " //
|
||||
+ "WHERE " + user + ".dummy_entity IS NOT NULL)");
|
||||
+ "WHERE " + "dummy_entity IS NOT NULL)");
|
||||
});
|
||||
}
|
||||
|
||||
private PersistentPropertyPath<RelationalPersistentProperty> getPath(String path, Class<DummyEntity> baseType) {
|
||||
return PersistentPropertyPathTestUtils.getPath(this.context, path, baseType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Take a set of user-based assertions and run them against multiple users, in different threads.
|
||||
*/
|
||||
|
||||
@@ -20,6 +20,8 @@ import static org.assertj.core.api.Assertions.*;
|
||||
import org.assertj.core.api.SoftAssertions;
|
||||
import org.junit.Test;
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.jdbc.core.mapping.PersistentPropertyPathTestUtils;
|
||||
import org.springframework.data.mapping.PersistentPropertyPath;
|
||||
import org.springframework.data.mapping.PropertyPath;
|
||||
import org.springframework.data.relational.core.mapping.RelationalMappingContext;
|
||||
import org.springframework.data.relational.core.mapping.RelationalPersistentEntity;
|
||||
@@ -65,6 +67,8 @@ public class SqlGeneratorFixedNamingStrategyUnitTests {
|
||||
}
|
||||
};
|
||||
|
||||
private RelationalMappingContext context = new RelationalMappingContext();
|
||||
|
||||
@Test // DATAJDBC-107
|
||||
public void findOneWithOverriddenFixedTableName() {
|
||||
|
||||
@@ -108,10 +112,10 @@ public class SqlGeneratorFixedNamingStrategyUnitTests {
|
||||
|
||||
SqlGenerator sqlGenerator = configureSqlGenerator(fixedCustomTablePrefixStrategy);
|
||||
|
||||
String sql = sqlGenerator.createDeleteByPath(PropertyPath.from("ref", DummyEntity.class));
|
||||
String sql = sqlGenerator.createDeleteByPath(getPath("ref", DummyEntity.class));
|
||||
|
||||
assertThat(sql).isEqualTo("DELETE FROM FixedCustomSchema.FixedCustomTablePrefix_ReferencedEntity "
|
||||
+ "WHERE FixedCustomSchema.FixedCustomTablePrefix_DummyEntity = :rootId");
|
||||
+ "WHERE dummy_entity = :rootId");
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-107
|
||||
@@ -119,12 +123,12 @@ public class SqlGeneratorFixedNamingStrategyUnitTests {
|
||||
|
||||
SqlGenerator sqlGenerator = configureSqlGenerator(fixedCustomTablePrefixStrategy);
|
||||
|
||||
String sql = sqlGenerator.createDeleteByPath(PropertyPath.from("ref.further", DummyEntity.class));
|
||||
String sql = sqlGenerator.createDeleteByPath(getPath("ref.further", DummyEntity.class));
|
||||
|
||||
assertThat(sql).isEqualTo("DELETE FROM FixedCustomSchema.FixedCustomTablePrefix_SecondLevelReferencedEntity "
|
||||
+ "WHERE FixedCustomSchema.FixedCustomTablePrefix_ReferencedEntity IN "
|
||||
+ "WHERE referenced_entity IN "
|
||||
+ "(SELECT FixedCustomPropertyPrefix_l1id " + "FROM FixedCustomSchema.FixedCustomTablePrefix_ReferencedEntity "
|
||||
+ "WHERE FixedCustomSchema.FixedCustomTablePrefix_DummyEntity = :rootId)");
|
||||
+ "WHERE dummy_entity = :rootId)");
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-107
|
||||
@@ -142,10 +146,10 @@ public class SqlGeneratorFixedNamingStrategyUnitTests {
|
||||
|
||||
SqlGenerator sqlGenerator = configureSqlGenerator(fixedCustomTablePrefixStrategy);
|
||||
|
||||
String sql = sqlGenerator.createDeleteAllSql(PropertyPath.from("ref", DummyEntity.class));
|
||||
String sql = sqlGenerator.createDeleteAllSql(getPath("ref", DummyEntity.class));
|
||||
|
||||
assertThat(sql).isEqualTo("DELETE FROM FixedCustomSchema.FixedCustomTablePrefix_ReferencedEntity "
|
||||
+ "WHERE FixedCustomSchema.FixedCustomTablePrefix_DummyEntity IS NOT NULL");
|
||||
+ "WHERE dummy_entity IS NOT NULL");
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-107
|
||||
@@ -153,12 +157,12 @@ public class SqlGeneratorFixedNamingStrategyUnitTests {
|
||||
|
||||
SqlGenerator sqlGenerator = configureSqlGenerator(fixedCustomTablePrefixStrategy);
|
||||
|
||||
String sql = sqlGenerator.createDeleteAllSql(PropertyPath.from("ref.further", DummyEntity.class));
|
||||
String sql = sqlGenerator.createDeleteAllSql(getPath("ref.further", DummyEntity.class));
|
||||
|
||||
assertThat(sql).isEqualTo("DELETE FROM FixedCustomSchema.FixedCustomTablePrefix_SecondLevelReferencedEntity "
|
||||
+ "WHERE FixedCustomSchema.FixedCustomTablePrefix_ReferencedEntity IN "
|
||||
+ "WHERE referenced_entity IN "
|
||||
+ "(SELECT FixedCustomPropertyPrefix_l1id " + "FROM FixedCustomSchema.FixedCustomTablePrefix_ReferencedEntity "
|
||||
+ "WHERE FixedCustomSchema.FixedCustomTablePrefix_DummyEntity IS NOT NULL)");
|
||||
+ "WHERE dummy_entity IS NOT NULL)");
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-113
|
||||
@@ -172,6 +176,10 @@ public class SqlGeneratorFixedNamingStrategyUnitTests {
|
||||
"DELETE FROM FixedCustomSchema.FixedCustomTablePrefix_DummyEntity WHERE FixedCustomPropertyPrefix_id IN (:ids)");
|
||||
}
|
||||
|
||||
private PersistentPropertyPath<RelationalPersistentProperty> getPath(String path, Class<?> baseType) {
|
||||
return PersistentPropertyPathTestUtils.getPath(context, path, baseType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Plug in a custom {@link NamingStrategy} for this test case.
|
||||
*
|
||||
|
||||
@@ -24,6 +24,8 @@ import org.assertj.core.api.SoftAssertions;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.jdbc.core.mapping.PersistentPropertyPathTestUtils;
|
||||
import org.springframework.data.mapping.PersistentPropertyPath;
|
||||
import org.springframework.data.mapping.PropertyPath;
|
||||
import org.springframework.data.relational.core.mapping.RelationalMappingContext;
|
||||
import org.springframework.data.relational.core.mapping.RelationalPersistentEntity;
|
||||
@@ -39,6 +41,7 @@ import org.springframework.data.relational.core.mapping.NamingStrategy;
|
||||
public class SqlGeneratorUnitTests {
|
||||
|
||||
private SqlGenerator sqlGenerator;
|
||||
private RelationalMappingContext context = new RelationalMappingContext();
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
@@ -69,7 +72,7 @@ public class SqlGeneratorUnitTests {
|
||||
@Test // DATAJDBC-112
|
||||
public void cascadingDeleteFirstLevel() {
|
||||
|
||||
String sql = sqlGenerator.createDeleteByPath(PropertyPath.from("ref", DummyEntity.class));
|
||||
String sql = sqlGenerator.createDeleteByPath(getPath("ref", DummyEntity.class));
|
||||
|
||||
assertThat(sql).isEqualTo("DELETE FROM referenced_entity WHERE dummy_entity = :rootId");
|
||||
}
|
||||
@@ -77,7 +80,7 @@ public class SqlGeneratorUnitTests {
|
||||
@Test // DATAJDBC-112
|
||||
public void cascadingDeleteAllSecondLevel() {
|
||||
|
||||
String sql = sqlGenerator.createDeleteByPath(PropertyPath.from("ref.further", DummyEntity.class));
|
||||
String sql = sqlGenerator.createDeleteByPath(getPath("ref.further", DummyEntity.class));
|
||||
|
||||
assertThat(sql).isEqualTo(
|
||||
"DELETE FROM second_level_referenced_entity WHERE referenced_entity IN (SELECT x_l1id FROM referenced_entity WHERE dummy_entity = :rootId)");
|
||||
@@ -94,7 +97,7 @@ public class SqlGeneratorUnitTests {
|
||||
@Test // DATAJDBC-112
|
||||
public void cascadingDeleteAllFirstLevel() {
|
||||
|
||||
String sql = sqlGenerator.createDeleteAllSql(PropertyPath.from("ref", DummyEntity.class));
|
||||
String sql = sqlGenerator.createDeleteAllSql(getPath("ref", DummyEntity.class));
|
||||
|
||||
assertThat(sql).isEqualTo("DELETE FROM referenced_entity WHERE dummy_entity IS NOT NULL");
|
||||
}
|
||||
@@ -102,12 +105,28 @@ public class SqlGeneratorUnitTests {
|
||||
@Test // DATAJDBC-112
|
||||
public void cascadingDeleteSecondLevel() {
|
||||
|
||||
String sql = sqlGenerator.createDeleteAllSql(PropertyPath.from("ref.further", DummyEntity.class));
|
||||
String sql = sqlGenerator.createDeleteAllSql(getPath("ref.further", DummyEntity.class));
|
||||
|
||||
assertThat(sql).isEqualTo(
|
||||
"DELETE FROM second_level_referenced_entity WHERE referenced_entity IN (SELECT x_l1id FROM referenced_entity WHERE dummy_entity IS NOT NULL)");
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-227
|
||||
public void deleteAllMap() {
|
||||
|
||||
String sql = sqlGenerator.createDeleteAllSql(getPath("mappedElements", DummyEntity.class));
|
||||
|
||||
assertThat(sql).isEqualTo("DELETE FROM element WHERE dummy_entity IS NOT NULL");
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-227
|
||||
public void deleteMapByPath() {
|
||||
|
||||
String sql = sqlGenerator.createDeleteByPath(getPath("mappedElements", DummyEntity.class));
|
||||
|
||||
assertThat(sql).isEqualTo("DELETE FROM element WHERE dummy_entity = :rootId");
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-131
|
||||
public void findAllByProperty() {
|
||||
|
||||
@@ -151,6 +170,10 @@ public class SqlGeneratorUnitTests {
|
||||
+ "WHERE back-ref = :back-ref " + "ORDER BY key-column");
|
||||
}
|
||||
|
||||
|
||||
private PersistentPropertyPath<RelationalPersistentProperty> getPath(String path, Class<?> base) {
|
||||
return PersistentPropertyPathTestUtils.getPath(context, path, base);
|
||||
}
|
||||
@SuppressWarnings("unused")
|
||||
static class DummyEntity {
|
||||
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* 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.core.mapping;
|
||||
|
||||
import lombok.experimental.UtilityClass;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
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
|
||||
*/
|
||||
@UtilityClass
|
||||
public class PersistentPropertyPathTestUtils {
|
||||
|
||||
@NotNull
|
||||
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)));
|
||||
}
|
||||
}
|
||||
@@ -1,102 +0,0 @@
|
||||
/*
|
||||
* 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.mapping.PropertyPath;
|
||||
import org.springframework.data.relational.core.mapping.RelationalMappingContext;
|
||||
|
||||
/**
|
||||
* @author Jens Schauder
|
||||
*/
|
||||
public class JdbcMappingContextUnitTests {
|
||||
|
||||
RelationalMappingContext context = new RelationalMappingContext();
|
||||
|
||||
// DATAJDBC-188
|
||||
@Test
|
||||
public void simpleEntityDoesntReferenceOtherEntities() {
|
||||
|
||||
List<PropertyPath> paths = context.referencedEntities(SimpleEntity.class, null);
|
||||
|
||||
assertThat(paths).isEmpty();
|
||||
}
|
||||
|
||||
// DATAJDBC-188
|
||||
@Test
|
||||
public void cascadingReferencesGetFound() {
|
||||
|
||||
List<PropertyPath> paths = context.referencedEntities(CascadingEntity.class, null);
|
||||
|
||||
assertThat(paths).extracting(PropertyPath::toDotPath) //
|
||||
.containsExactly( //
|
||||
"reference.reference", //
|
||||
"reference" //
|
||||
);
|
||||
}
|
||||
|
||||
// DATAJDBC-188
|
||||
@Test
|
||||
public void setReferencesGetFound() {
|
||||
|
||||
List<PropertyPath> paths = context.referencedEntities(EntityWithSet.class, null);
|
||||
|
||||
assertThat(paths).extracting(PropertyPath::toDotPath) //
|
||||
.containsExactly( //
|
||||
"set.reference", //
|
||||
"set" //
|
||||
);
|
||||
}
|
||||
|
||||
// DATAJDBC-188
|
||||
@Test
|
||||
public void mapReferencesGetFound() {
|
||||
|
||||
List<PropertyPath> 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<String, MiddleEntity> map;
|
||||
}
|
||||
|
||||
private static class EntityWithSet {
|
||||
Set<MiddleEntity> set;
|
||||
}
|
||||
}
|
||||
@@ -80,7 +80,7 @@ public class JdbcRepositoryManipulateDbActionsIntegrationTests {
|
||||
entity.id, //
|
||||
entity.name, //
|
||||
true) //
|
||||
);
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
@@ -103,14 +103,14 @@ public class JdbcRepositoryManipulateDbActionsIntegrationTests {
|
||||
one.id, //
|
||||
one.name, //
|
||||
true) //
|
||||
);
|
||||
);
|
||||
|
||||
assertThat(repository.findById(two.id)) //
|
||||
.contains(new DummyEntity( //
|
||||
two.id, //
|
||||
two.name, //
|
||||
true) //
|
||||
);
|
||||
);
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-120
|
||||
@@ -205,7 +205,7 @@ public class JdbcRepositoryManipulateDbActionsIntegrationTests {
|
||||
|
||||
List<DbAction<?>> actions = event.getChange().getActions();
|
||||
actions.clear();
|
||||
actions.add(DbAction.update(entity, null, null));
|
||||
actions.add(new DbAction.UpdateRoot<>(entity));
|
||||
};
|
||||
}
|
||||
|
||||
@@ -223,7 +223,7 @@ public class JdbcRepositoryManipulateDbActionsIntegrationTests {
|
||||
log.text = entity.name + " saved";
|
||||
|
||||
List<DbAction<?>> actions = event.getChange().getActions();
|
||||
actions.add(DbAction.insert(log, null, null));
|
||||
actions.add(new DbAction.InsertRoot<>(log));
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,16 +15,12 @@
|
||||
*/
|
||||
package org.springframework.data.relational.core.conversion;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.doThrow;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.data.relational.core.conversion.DbAction;
|
||||
import org.springframework.data.relational.core.conversion.DbActionExecutionException;
|
||||
import org.springframework.data.relational.core.conversion.Interpreter;
|
||||
import org.springframework.data.relational.core.conversion.RelationalPropertyPath;
|
||||
import org.springframework.data.relational.core.mapping.RelationalMappingContext;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link DbAction}s
|
||||
@@ -33,20 +29,21 @@ import org.springframework.data.relational.core.conversion.RelationalPropertyPat
|
||||
*/
|
||||
public class DbActionUnitTests {
|
||||
|
||||
RelationalMappingContext context = new RelationalMappingContext();
|
||||
|
||||
@Test // DATAJDBC-150
|
||||
public void exceptionFromActionContainsUsefulInformationWhenInterpreterFails() {
|
||||
|
||||
DummyEntity entity = new DummyEntity();
|
||||
DbAction.Insert<DummyEntity> insert = DbAction.insert(entity, RelationalPropertyPath.from("someName", DummyEntity.class),
|
||||
null);
|
||||
DbAction.InsertRoot<DummyEntity> insert = new DbAction.InsertRoot<>(entity);
|
||||
|
||||
Interpreter failingInterpreter = mock(Interpreter.class);
|
||||
doThrow(new RuntimeException()).when(failingInterpreter).interpret(any(DbAction.Insert.class));
|
||||
doThrow(new RuntimeException()).when(failingInterpreter).interpret(any(DbAction.InsertRoot.class));
|
||||
|
||||
assertThatExceptionOfType(DbActionExecutionException.class) //
|
||||
.isThrownBy(() -> insert.executeWith(failingInterpreter)) //
|
||||
.isThrownBy(() -> insert.executeWith(failingInterpreter)) //
|
||||
.withMessageContaining("Insert") //
|
||||
.withMessageContaining(entity.toString());
|
||||
.withMessageContaining(entity.toString());
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -23,17 +23,16 @@ import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.relational.core.conversion.AggregateChange;
|
||||
import org.springframework.data.relational.core.conversion.DbAction;
|
||||
import org.springframework.data.relational.core.conversion.RelationalEntityDeleteWriter;
|
||||
import org.springframework.data.relational.core.conversion.RelationalPropertyPath;
|
||||
import org.springframework.data.relational.core.conversion.AggregateChange.Kind;
|
||||
import org.springframework.data.mapping.PersistentPropertyPath;
|
||||
import org.springframework.data.relational.core.conversion.DbAction.Delete;
|
||||
import org.springframework.data.relational.core.conversion.DbAction.DeleteAll;
|
||||
import org.springframework.data.relational.core.conversion.DbAction.DeleteAllRoot;
|
||||
import org.springframework.data.relational.core.conversion.DbAction.DeleteRoot;
|
||||
import org.springframework.data.relational.core.conversion.AggregateChange.Kind;
|
||||
import org.springframework.data.relational.core.mapping.RelationalMappingContext;
|
||||
|
||||
/**
|
||||
* Unit tests for the {@link RelationalEntityDeleteWriter}
|
||||
* Unit tests for the {@link org.springframework.data.relational.core.conversion.RelationalEntityDeleteWriter}
|
||||
*
|
||||
* @author Jens Schauder
|
||||
*/
|
||||
@@ -43,9 +42,12 @@ public class RelationalEntityDeleteWriterUnitTests {
|
||||
RelationalEntityDeleteWriter converter = new RelationalEntityDeleteWriter(new RelationalMappingContext());
|
||||
|
||||
private static Object dotPath(DbAction dba) {
|
||||
|
||||
RelationalPropertyPath propertyPath = dba.getPropertyPath();
|
||||
return propertyPath == null ? null : propertyPath.toDotPath();
|
||||
if (dba instanceof DbAction.WithPropertyPath) {
|
||||
PersistentPropertyPath propertyPath = ((DbAction.WithPropertyPath<?>) dba).getPropertyPath();
|
||||
return propertyPath == null ? null : propertyPath.toDotPath();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-112
|
||||
@@ -62,16 +64,14 @@ public class RelationalEntityDeleteWriterUnitTests {
|
||||
.containsExactly( //
|
||||
Tuple.tuple(Delete.class, YetAnother.class, "other.yetAnother"), //
|
||||
Tuple.tuple(Delete.class, OtherEntity.class, "other"), //
|
||||
Tuple.tuple(Delete.class, SomeEntity.class, null) //
|
||||
Tuple.tuple(DeleteRoot.class, SomeEntity.class, null) //
|
||||
);
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-188
|
||||
public void deleteAllDeletesAllEntitiesAndReferencedEntities() {
|
||||
|
||||
SomeEntity entity = new SomeEntity(23L);
|
||||
|
||||
AggregateChange<SomeEntity> aggregateChange = new AggregateChange(Kind.DELETE, SomeEntity.class, null);
|
||||
AggregateChange<SomeEntity> aggregateChange = new AggregateChange<>(Kind.DELETE, SomeEntity.class, null);
|
||||
|
||||
converter.write(null, aggregateChange);
|
||||
|
||||
@@ -80,7 +80,7 @@ public class RelationalEntityDeleteWriterUnitTests {
|
||||
.containsExactly( //
|
||||
Tuple.tuple(DeleteAll.class, YetAnother.class, "other.yetAnother"), //
|
||||
Tuple.tuple(DeleteAll.class, OtherEntity.class, "other"), //
|
||||
Tuple.tuple(DeleteAll.class, SomeEntity.class, null) //
|
||||
Tuple.tuple(DeleteAllRoot.class, SomeEntity.class, null) //
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -30,14 +30,11 @@ import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.relational.core.conversion.AggregateChange;
|
||||
import org.springframework.data.relational.core.conversion.DbAction;
|
||||
import org.springframework.data.relational.core.conversion.RelationalEntityWriter;
|
||||
import org.springframework.data.relational.core.conversion.AggregateChange.Kind;
|
||||
import org.springframework.data.relational.core.conversion.DbAction.Delete;
|
||||
import org.springframework.data.relational.core.conversion.DbAction.DeleteAll;
|
||||
import org.springframework.data.relational.core.conversion.DbAction.Insert;
|
||||
import org.springframework.data.relational.core.conversion.DbAction.Update;
|
||||
import org.springframework.data.relational.core.conversion.DbAction.InsertRoot;
|
||||
import org.springframework.data.relational.core.conversion.DbAction.UpdateRoot;
|
||||
import org.springframework.data.relational.core.conversion.AggregateChange.Kind;
|
||||
import org.springframework.data.relational.core.mapping.RelationalMappingContext;
|
||||
|
||||
/**
|
||||
@@ -61,31 +58,54 @@ public class RelationalEntityWriterUnitTests {
|
||||
converter.write(entity, aggregateChange);
|
||||
|
||||
assertThat(aggregateChange.getActions()) //
|
||||
.extracting(DbAction::getClass, DbAction::getEntityType, this::extractPath) //
|
||||
.extracting(DbAction::getClass, DbAction::getEntityType, this::extractPath, this::actualEntityType,
|
||||
this::isWithDependsOn) //
|
||||
.containsExactly( //
|
||||
tuple(Insert.class, SingleReferenceEntity.class, "") //
|
||||
);
|
||||
tuple(InsertRoot.class, SingleReferenceEntity.class, "", SingleReferenceEntity.class, false) //
|
||||
);
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-112
|
||||
public void existingEntityGetsConvertedToUpdate() {
|
||||
public void newEntityWithReferenceGetsConvertedToTwoInserts() {
|
||||
|
||||
SingleReferenceEntity entity = new SingleReferenceEntity(null);
|
||||
entity.other = new Element(null);
|
||||
|
||||
SingleReferenceEntity entity = new SingleReferenceEntity(SOME_ENTITY_ID);
|
||||
AggregateChange<SingleReferenceEntity> aggregateChange = //
|
||||
new AggregateChange(Kind.SAVE, SingleReferenceEntity.class, entity);
|
||||
|
||||
converter.write(entity, aggregateChange);
|
||||
|
||||
assertThat(aggregateChange.getActions()) //
|
||||
.extracting(DbAction::getClass, DbAction::getEntityType, this::extractPath) //
|
||||
.extracting(DbAction::getClass, DbAction::getEntityType, this::extractPath, this::actualEntityType,
|
||||
this::isWithDependsOn) //
|
||||
.containsExactly( //
|
||||
tuple(Delete.class, Element.class, "other"), //
|
||||
tuple(Update.class, SingleReferenceEntity.class, "") //
|
||||
);
|
||||
tuple(InsertRoot.class, SingleReferenceEntity.class, "", SingleReferenceEntity.class, false), //
|
||||
tuple(Insert.class, Element.class, "other", Element.class, true) //
|
||||
);
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-112
|
||||
public void referenceTriggersDeletePlusInsert() {
|
||||
public void existingEntityGetsConvertedToDeletePlusUpdate() {
|
||||
|
||||
SingleReferenceEntity entity = new SingleReferenceEntity(SOME_ENTITY_ID);
|
||||
|
||||
AggregateChange<SingleReferenceEntity> aggregateChange = //
|
||||
new AggregateChange(Kind.SAVE, SingleReferenceEntity.class, entity);
|
||||
|
||||
converter.write(entity, aggregateChange);
|
||||
|
||||
assertThat(aggregateChange.getActions()) //
|
||||
.extracting(DbAction::getClass, DbAction::getEntityType, this::extractPath, this::actualEntityType,
|
||||
this::isWithDependsOn) //
|
||||
.containsExactly( //
|
||||
tuple(Delete.class, Element.class, "other", null, false), //
|
||||
tuple(UpdateRoot.class, SingleReferenceEntity.class, "", SingleReferenceEntity.class, false) //
|
||||
);
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-112
|
||||
public void newReferenceTriggersDeletePlusInsert() {
|
||||
|
||||
SingleReferenceEntity entity = new SingleReferenceEntity(SOME_ENTITY_ID);
|
||||
entity.other = new Element(null);
|
||||
@@ -96,26 +116,29 @@ public class RelationalEntityWriterUnitTests {
|
||||
converter.write(entity, aggregateChange);
|
||||
|
||||
assertThat(aggregateChange.getActions()) //
|
||||
.extracting(DbAction::getClass, DbAction::getEntityType, this::extractPath) //
|
||||
.extracting(DbAction::getClass, DbAction::getEntityType, this::extractPath, this::actualEntityType,
|
||||
this::isWithDependsOn) //
|
||||
.containsExactly( //
|
||||
tuple(Delete.class, Element.class, "other"), //
|
||||
tuple(Update.class, SingleReferenceEntity.class, ""), //
|
||||
tuple(Insert.class, Element.class, "other") //
|
||||
);
|
||||
tuple(Delete.class, Element.class, "other", null, false), //
|
||||
tuple(UpdateRoot.class, SingleReferenceEntity.class, "", SingleReferenceEntity.class, false), //
|
||||
tuple(Insert.class, Element.class, "other", Element.class, true) //
|
||||
);
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-113
|
||||
public void newEntityWithEmptySetResultsInSingleInsert() {
|
||||
|
||||
SetContainer entity = new SetContainer(null);
|
||||
AggregateChange<SingleReferenceEntity> aggregateChange = new AggregateChange(Kind.SAVE, SetContainer.class, entity);
|
||||
AggregateChange<RelationalEntityWriterUnitTests.SingleReferenceEntity> aggregateChange = new AggregateChange(
|
||||
Kind.SAVE, SetContainer.class, entity);
|
||||
|
||||
converter.write(entity, aggregateChange);
|
||||
|
||||
assertThat(aggregateChange.getActions()) //
|
||||
.extracting(DbAction::getClass, DbAction::getEntityType, this::extractPath) //
|
||||
.extracting(DbAction::getClass, DbAction::getEntityType, this::extractPath, this::actualEntityType,
|
||||
this::isWithDependsOn) //
|
||||
.containsExactly( //
|
||||
tuple(Insert.class, SetContainer.class, ""));
|
||||
tuple(InsertRoot.class, SetContainer.class, "", SetContainer.class, false));
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-113
|
||||
@@ -128,12 +151,14 @@ public class RelationalEntityWriterUnitTests {
|
||||
AggregateChange<SingleReferenceEntity> aggregateChange = new AggregateChange(Kind.SAVE, SetContainer.class, entity);
|
||||
converter.write(entity, aggregateChange);
|
||||
|
||||
assertThat(aggregateChange.getActions()).extracting(DbAction::getClass, DbAction::getEntityType, this::extractPath) //
|
||||
assertThat(aggregateChange.getActions())
|
||||
.extracting(DbAction::getClass, DbAction::getEntityType, this::extractPath, this::actualEntityType,
|
||||
this::isWithDependsOn) //
|
||||
.containsExactly( //
|
||||
tuple(Insert.class, SetContainer.class, ""), //
|
||||
tuple(Insert.class, Element.class, "elements"), //
|
||||
tuple(Insert.class, Element.class, "elements") //
|
||||
);
|
||||
tuple(InsertRoot.class, SetContainer.class, "", SetContainer.class, false), //
|
||||
tuple(Insert.class, Element.class, "elements", Element.class, true), //
|
||||
tuple(Insert.class, Element.class, "elements", Element.class, true) //
|
||||
);
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-113
|
||||
@@ -151,20 +176,25 @@ public class RelationalEntityWriterUnitTests {
|
||||
new Element(null)) //
|
||||
);
|
||||
|
||||
AggregateChange<SingleReferenceEntity> aggregateChange = new AggregateChange(Kind.SAVE, SetContainer.class, entity);
|
||||
AggregateChange<SingleReferenceEntity> aggregateChange = new AggregateChange(Kind.SAVE,
|
||||
CascadingReferenceEntity.class, entity);
|
||||
|
||||
converter.write(entity, aggregateChange);
|
||||
|
||||
assertThat(aggregateChange.getActions()).extracting(DbAction::getClass, DbAction::getEntityType, this::extractPath) //
|
||||
assertThat(aggregateChange.getActions())
|
||||
.extracting(DbAction::getClass, DbAction::getEntityType, this::extractPath, this::actualEntityType,
|
||||
this::isWithDependsOn) //
|
||||
.containsExactly( //
|
||||
tuple(Insert.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") //
|
||||
);
|
||||
tuple(InsertRoot.class, CascadingReferenceEntity.class, "", CascadingReferenceEntity.class, false), //
|
||||
tuple(Insert.class, CascadingReferenceMiddleElement.class, "other", CascadingReferenceMiddleElement.class,
|
||||
true), //
|
||||
tuple(Insert.class, CascadingReferenceMiddleElement.class, "other", CascadingReferenceMiddleElement.class,
|
||||
true), //
|
||||
tuple(Insert.class, Element.class, "other.element", Element.class, true), //
|
||||
tuple(Insert.class, Element.class, "other.element", Element.class, true), //
|
||||
tuple(Insert.class, Element.class, "other.element", Element.class, true), //
|
||||
tuple(Insert.class, Element.class, "other.element", Element.class, true) //
|
||||
);
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-188
|
||||
@@ -182,21 +212,26 @@ public class RelationalEntityWriterUnitTests {
|
||||
new Element(null)) //
|
||||
);
|
||||
|
||||
AggregateChange<SingleReferenceEntity> aggregateChange = new AggregateChange(Kind.SAVE, CascadingReferenceEntity.class, entity);
|
||||
AggregateChange<SingleReferenceEntity> aggregateChange = new AggregateChange(Kind.SAVE,
|
||||
CascadingReferenceEntity.class, entity);
|
||||
|
||||
converter.write(entity, aggregateChange);
|
||||
|
||||
assertThat(aggregateChange.getActions()).extracting(DbAction::getClass, DbAction::getEntityType, this::extractPath) //
|
||||
assertThat(aggregateChange.getActions())
|
||||
.extracting(DbAction::getClass, DbAction::getEntityType, this::extractPath, this::actualEntityType,
|
||||
this::isWithDependsOn) //
|
||||
.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") //
|
||||
tuple(Delete.class, Element.class, "other.element", null, false),
|
||||
tuple(Delete.class, CascadingReferenceMiddleElement.class, "other", null, false),
|
||||
tuple(UpdateRoot.class, CascadingReferenceEntity.class, "", CascadingReferenceEntity.class, false), //
|
||||
tuple(Insert.class, CascadingReferenceMiddleElement.class, "other", CascadingReferenceMiddleElement.class,
|
||||
true), //
|
||||
tuple(Insert.class, CascadingReferenceMiddleElement.class, "other", CascadingReferenceMiddleElement.class,
|
||||
true), //
|
||||
tuple(Insert.class, Element.class, "other.element", Element.class, true), //
|
||||
tuple(Insert.class, Element.class, "other.element", Element.class, true), //
|
||||
tuple(Insert.class, Element.class, "other.element", Element.class, true), //
|
||||
tuple(Insert.class, Element.class, "other.element", Element.class, true) //
|
||||
);
|
||||
}
|
||||
|
||||
@@ -210,7 +245,7 @@ public class RelationalEntityWriterUnitTests {
|
||||
|
||||
assertThat(aggregateChange.getActions()).extracting(DbAction::getClass, DbAction::getEntityType, this::extractPath) //
|
||||
.containsExactly( //
|
||||
tuple(Insert.class, MapContainer.class, ""));
|
||||
tuple(InsertRoot.class, MapContainer.class, ""));
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-131
|
||||
@@ -226,16 +261,16 @@ public class RelationalEntityWriterUnitTests {
|
||||
assertThat(aggregateChange.getActions())
|
||||
.extracting(DbAction::getClass, DbAction::getEntityType, this::getMapKey, this::extractPath) //
|
||||
.containsExactlyInAnyOrder( //
|
||||
tuple(Insert.class, MapContainer.class, null, ""), //
|
||||
tuple(InsertRoot.class, MapContainer.class, null, ""), //
|
||||
tuple(Insert.class, Element.class, "one", "elements"), //
|
||||
tuple(Insert.class, Element.class, "two", "elements") //
|
||||
).containsSubsequence( // container comes before the elements
|
||||
tuple(Insert.class, MapContainer.class, null, ""), //
|
||||
tuple(InsertRoot.class, MapContainer.class, null, ""), //
|
||||
tuple(Insert.class, Element.class, "two", "elements") //
|
||||
).containsSubsequence( // container comes before the elements
|
||||
tuple(Insert.class, MapContainer.class, null, ""), //
|
||||
tuple(InsertRoot.class, MapContainer.class, null, ""), //
|
||||
tuple(Insert.class, Element.class, "one", "elements") //
|
||||
);
|
||||
);
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-183
|
||||
@@ -261,7 +296,7 @@ public class RelationalEntityWriterUnitTests {
|
||||
assertThat(aggregateChange.getActions())
|
||||
.extracting(DbAction::getClass, DbAction::getEntityType, this::getMapKey, this::extractPath) //
|
||||
.containsExactlyInAnyOrder( //
|
||||
tuple(Insert.class, MapContainer.class, null, ""), //
|
||||
tuple(InsertRoot.class, MapContainer.class, null, ""), //
|
||||
tuple(Insert.class, Element.class, "1", "elements"), //
|
||||
tuple(Insert.class, Element.class, "2", "elements"), //
|
||||
tuple(Insert.class, Element.class, "3", "elements"), //
|
||||
@@ -287,7 +322,7 @@ public class RelationalEntityWriterUnitTests {
|
||||
|
||||
assertThat(aggregateChange.getActions()).extracting(DbAction::getClass, DbAction::getEntityType, this::extractPath) //
|
||||
.containsExactly( //
|
||||
tuple(Insert.class, ListContainer.class, ""));
|
||||
tuple(InsertRoot.class, ListContainer.class, ""));
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-130
|
||||
@@ -303,16 +338,16 @@ public class RelationalEntityWriterUnitTests {
|
||||
assertThat(aggregateChange.getActions())
|
||||
.extracting(DbAction::getClass, DbAction::getEntityType, this::getListKey, this::extractPath) //
|
||||
.containsExactlyInAnyOrder( //
|
||||
tuple(Insert.class, ListContainer.class, null, ""), //
|
||||
tuple(InsertRoot.class, ListContainer.class, null, ""), //
|
||||
tuple(Insert.class, Element.class, 0, "elements"), //
|
||||
tuple(Insert.class, Element.class, 1, "elements") //
|
||||
).containsSubsequence( // container comes before the elements
|
||||
tuple(Insert.class, ListContainer.class, null, ""), //
|
||||
tuple(InsertRoot.class, ListContainer.class, null, ""), //
|
||||
tuple(Insert.class, Element.class, 1, "elements") //
|
||||
).containsSubsequence( // container comes before the elements
|
||||
tuple(Insert.class, ListContainer.class, null, ""), //
|
||||
tuple(InsertRoot.class, ListContainer.class, null, ""), //
|
||||
tuple(Insert.class, Element.class, 0, "elements") //
|
||||
);
|
||||
);
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-131
|
||||
@@ -329,7 +364,7 @@ public class RelationalEntityWriterUnitTests {
|
||||
.extracting(DbAction::getClass, DbAction::getEntityType, this::getMapKey, this::extractPath) //
|
||||
.containsExactly( //
|
||||
tuple(Delete.class, Element.class, null, "elements"), //
|
||||
tuple(Update.class, MapContainer.class, null, ""), //
|
||||
tuple(UpdateRoot.class, MapContainer.class, null, ""), //
|
||||
tuple(Insert.class, Element.class, "one", "elements") //
|
||||
);
|
||||
}
|
||||
@@ -348,7 +383,7 @@ public class RelationalEntityWriterUnitTests {
|
||||
.extracting(DbAction::getClass, DbAction::getEntityType, this::getListKey, this::extractPath) //
|
||||
.containsExactly( //
|
||||
tuple(Delete.class, Element.class, null, "elements"), //
|
||||
tuple(Update.class, ListContainer.class, null, ""), //
|
||||
tuple(UpdateRoot.class, ListContainer.class, null, ""), //
|
||||
tuple(Insert.class, Element.class, 0, "elements") //
|
||||
);
|
||||
}
|
||||
@@ -362,15 +397,32 @@ public class RelationalEntityWriterUnitTests {
|
||||
}
|
||||
|
||||
private Object getMapKey(DbAction a) {
|
||||
return a.getAdditionalValues().get("map_container_key");
|
||||
return a instanceof DbAction.WithDependingOn ? ((DbAction.WithDependingOn) a).getAdditionalValues().get("map_container_key") : null;
|
||||
}
|
||||
|
||||
private Object getListKey(DbAction a) {
|
||||
return a.getAdditionalValues().get("list_container_key");
|
||||
return a instanceof DbAction.WithDependingOn ? ((DbAction.WithDependingOn) a).getAdditionalValues().get("list_container_key") : null;
|
||||
}
|
||||
|
||||
private String extractPath(DbAction action) {
|
||||
return action.getPropertyPath().toDotPath();
|
||||
|
||||
if (action instanceof DbAction.WithPropertyPath) {
|
||||
return ((DbAction.WithPropertyPath<?>) action).getPropertyPath().toDotPath();
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
private boolean isWithDependsOn(DbAction dbAction) {
|
||||
return dbAction instanceof DbAction.WithDependingOn;
|
||||
}
|
||||
|
||||
private Class<?> actualEntityType(DbAction a) {
|
||||
|
||||
if (a instanceof DbAction.WithEntity) {
|
||||
return ((DbAction.WithEntity) a).getEntity().getClass();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@@ -382,6 +434,15 @@ public class RelationalEntityWriterUnitTests {
|
||||
String name;
|
||||
}
|
||||
|
||||
@RequiredArgsConstructor
|
||||
static class ReferenceWoIdEntity {
|
||||
|
||||
@Id final Long id;
|
||||
NoIdElement other;
|
||||
// should not trigger own Dbaction
|
||||
String name;
|
||||
}
|
||||
|
||||
@RequiredArgsConstructor
|
||||
private static class CascadingReferenceMiddleElement {
|
||||
|
||||
@@ -422,4 +483,10 @@ public class RelationalEntityWriterUnitTests {
|
||||
@Id final Long id;
|
||||
}
|
||||
|
||||
@RequiredArgsConstructor
|
||||
private static class NoIdElement {
|
||||
// empty classes feel weird.
|
||||
String name;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,71 +0,0 @@
|
||||
/*
|
||||
* 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.relational.core.mapping;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.data.mapping.PropertyPath;
|
||||
import org.springframework.data.relational.core.mapping.RelationalMappingContext;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link RelationalMappingContext}.
|
||||
*
|
||||
* @author Jens Schauder
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class RelationalMappingContextUnitTests {
|
||||
|
||||
@Test // DATAJDBC-142
|
||||
public void referencedEntitiesGetFound() {
|
||||
|
||||
RelationalMappingContext mappingContext = new RelationalMappingContext();
|
||||
|
||||
List<PropertyPath> propertyPaths = mappingContext.referencedEntities(DummyEntity.class, null);
|
||||
|
||||
assertThat(propertyPaths) //
|
||||
.extracting(PropertyPath::toDotPath) //
|
||||
.containsExactly("one.two", "one");
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-142
|
||||
public void propertyPathDoesNotDependOnNamingStrategy() {
|
||||
|
||||
RelationalMappingContext mappingContext = new RelationalMappingContext();
|
||||
|
||||
List<PropertyPath> propertyPaths = mappingContext.referencedEntities(DummyEntity.class, null);
|
||||
|
||||
assertThat(propertyPaths) //
|
||||
.extracting(PropertyPath::toDotPath) //
|
||||
.containsExactly("one.two", "one");
|
||||
}
|
||||
|
||||
static class DummyEntity {
|
||||
|
||||
String simpleProperty;
|
||||
LevelOne one;
|
||||
}
|
||||
|
||||
static class LevelOne {
|
||||
LevelTwo two;
|
||||
}
|
||||
|
||||
static class LevelTwo {
|
||||
String someValue;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
CREATE TABLE dummy_entity ( id BIGINT AUTO_INCREMENT PRIMARY KEY, NAME VARCHAR(100));
|
||||
CREATE TABLE element (content VARCHAR(100), dummy_entity BIGINT);
|
||||
@@ -0,0 +1,2 @@
|
||||
CREATE TABLE dummy_entity ( id BIGINT AUTO_INCREMENT PRIMARY KEY, NAME VARCHAR(100));
|
||||
CREATE TABLE element (content VARCHAR(100), dummy_entity BIGINT);
|
||||
@@ -0,0 +1,4 @@
|
||||
DROP TABLE element;
|
||||
DROP TABLE dummy_entity;
|
||||
CREATE TABLE dummy_entity ( id SERIAL PRIMARY KEY, NAME VARCHAR(100));
|
||||
CREATE TABLE element (content VARCHAR(100), dummy_entity BIGINT);
|
||||
Reference in New Issue
Block a user