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:
Jens Schauder
2018-06-12 14:24:20 +02:00
committed by Mark Paluch
parent c412aad6b8
commit bdefd3da9a
30 changed files with 926 additions and 808 deletions

View File

@@ -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);

View File

@@ -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 {}
}

View File

@@ -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);
}
}

View File

@@ -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.
*/

View File

@@ -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.
*

View File

@@ -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 {

View File

@@ -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)));
}
}

View File

@@ -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;
}
}

View File

@@ -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));
};
}
}

View File

@@ -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());
}

View File

@@ -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) //
);
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);