Polishing.
Introduces the BatchedActions abstraction to encapsulate the different ways singular actions get combined into batched actions. Original pull request #1230 Original pull request #1229 Original pull request #1228 Original pull request #1211
This commit is contained in:
@@ -406,11 +406,9 @@ public class AggregateChangeIdGenerationImmutableUnitTests {
|
||||
|
||||
DbAction.Insert<?> createInsert(String propertyName, Object value, @Nullable Object key) {
|
||||
|
||||
DbAction.Insert<Object> insert = new DbAction.Insert<>(value,
|
||||
return new DbAction.Insert<>(value,
|
||||
context.getPersistentPropertyPath(propertyName, DummyEntity.class), rootInsert,
|
||||
singletonMap(toPath(propertyName), key), IdValueSource.GENERATED);
|
||||
|
||||
return insert;
|
||||
}
|
||||
|
||||
DbAction.Insert<?> createDeepInsert(String propertyName, Object value, Object key,
|
||||
@@ -418,10 +416,9 @@ public class AggregateChangeIdGenerationImmutableUnitTests {
|
||||
|
||||
PersistentPropertyPath<RelationalPersistentProperty> propertyPath = toPath(
|
||||
parentInsert.getPropertyPath().toDotPath() + "." + propertyName);
|
||||
DbAction.Insert<Object> insert = new DbAction.Insert<>(value, propertyPath, parentInsert,
|
||||
singletonMap(propertyPath, key), IdValueSource.GENERATED);
|
||||
|
||||
return insert;
|
||||
return new DbAction.Insert<>(value, propertyPath, parentInsert,
|
||||
singletonMap(propertyPath, key), IdValueSource.GENERATED);
|
||||
}
|
||||
|
||||
PersistentPropertyPath<RelationalPersistentProperty> toPath(String path) {
|
||||
|
||||
@@ -380,11 +380,11 @@ public class AggregateChangeIdGenerationUnitTests {
|
||||
@Id Integer id;
|
||||
}
|
||||
|
||||
private static class IncrementingIds implements Answer {
|
||||
private static class IncrementingIds implements Answer<Object> {
|
||||
long id = 1;
|
||||
|
||||
@Override
|
||||
public Object answer(InvocationOnMock invocation) throws Throwable {
|
||||
public Object answer(InvocationOnMock invocation) {
|
||||
|
||||
if (!invocation.getMethod().getReturnType().equals(Object.class)) {
|
||||
throw new UnsupportedOperationException("This mock does not support this invocation: " + invocation);
|
||||
@@ -392,16 +392,5 @@ public class AggregateChangeIdGenerationUnitTests {
|
||||
|
||||
return id++;
|
||||
}
|
||||
|
||||
private DbAction<?> findAction(Object[] arguments) {
|
||||
|
||||
for (Object argument : arguments) {
|
||||
|
||||
if (argument instanceof DbAction) {
|
||||
return (DbAction<?>) argument;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,8 +84,8 @@ public class JdbcAggregateChangeExecutorContextImmutableUnitTests {
|
||||
|
||||
when(accessStrategy.insert(any(DummyEntity.class), eq(DummyEntity.class), eq(Identifier.empty()),
|
||||
eq(IdValueSource.GENERATED))).thenReturn(23L);
|
||||
when(accessStrategy.insert(any(Content.class), eq(Content.class), eq(createBackRef(23L)), eq(IdValueSource.GENERATED)))
|
||||
.thenReturn(24L);
|
||||
when(accessStrategy.insert(any(Content.class), eq(Content.class), eq(createBackRef(23L)),
|
||||
eq(IdValueSource.GENERATED))).thenReturn(24L);
|
||||
|
||||
DbAction.InsertRoot<DummyEntity> rootInsert = new DbAction.InsertRoot<>(root, IdValueSource.GENERATED);
|
||||
executionContext.executeInsertRoot(rootInsert);
|
||||
@@ -134,7 +134,6 @@ public class JdbcAggregateChangeExecutorContextImmutableUnitTests {
|
||||
when(accessStrategy.insert(content1, Content.class, createBackRef(123L), IdValueSource.GENERATED)).thenReturn(11L);
|
||||
executionContext.executeInsert(createInsert(rootUpdate1, "content", content1, null));
|
||||
|
||||
|
||||
DummyEntity root2 = new DummyEntity();
|
||||
DbAction.InsertRoot<DummyEntity> rootInsert2 = new DbAction.InsertRoot<>(root2, IdValueSource.GENERATED);
|
||||
when(accessStrategy.insert(root2, DummyEntity.class, Identifier.empty(), IdValueSource.GENERATED)).thenReturn(456L);
|
||||
|
||||
@@ -167,9 +167,10 @@ public class JdbcAggregateChangeExecutorContextUnitTests {
|
||||
@Test // GH-537
|
||||
void batchInsertRootOperation_withGeneratedIds() {
|
||||
|
||||
when(accessStrategy.insert(singletonList(InsertSubject.describedBy(root, Identifier.empty())), DummyEntity.class, IdValueSource.GENERATED))
|
||||
.thenReturn(new Object[] { 123L });
|
||||
executionContext.executeBatchInsertRoot(new DbAction.BatchInsertRoot<>(singletonList(new DbAction.InsertRoot<>(root, IdValueSource.GENERATED))));
|
||||
when(accessStrategy.insert(singletonList(InsertSubject.describedBy(root, Identifier.empty())), DummyEntity.class,
|
||||
IdValueSource.GENERATED)).thenReturn(new Object[] { 123L });
|
||||
executionContext.executeBatchInsertRoot(
|
||||
new DbAction.BatchInsertRoot<>(singletonList(new DbAction.InsertRoot<>(root, IdValueSource.GENERATED))));
|
||||
|
||||
List<DummyEntity> newRoots = executionContext.populateIdsIfNecessary();
|
||||
|
||||
@@ -180,9 +181,10 @@ public class JdbcAggregateChangeExecutorContextUnitTests {
|
||||
@Test // GH-537
|
||||
void batchInsertRootOperation_withoutGeneratedIds() {
|
||||
|
||||
when(accessStrategy.insert(singletonList(InsertSubject.describedBy(root, Identifier.empty())), DummyEntity.class, IdValueSource.PROVIDED))
|
||||
.thenReturn(new Object[] { null });
|
||||
executionContext.executeBatchInsertRoot(new DbAction.BatchInsertRoot<>(singletonList(new DbAction.InsertRoot<>(root, IdValueSource.PROVIDED))));
|
||||
when(accessStrategy.insert(singletonList(InsertSubject.describedBy(root, Identifier.empty())), DummyEntity.class,
|
||||
IdValueSource.PROVIDED)).thenReturn(new Object[] { null });
|
||||
executionContext.executeBatchInsertRoot(
|
||||
new DbAction.BatchInsertRoot<>(singletonList(new DbAction.InsertRoot<>(root, IdValueSource.PROVIDED))));
|
||||
|
||||
List<DummyEntity> newRoots = executionContext.populateIdsIfNecessary();
|
||||
|
||||
@@ -242,7 +244,7 @@ public class JdbcAggregateChangeExecutorContextUnitTests {
|
||||
}
|
||||
|
||||
DbAction.Insert<?> createInsert(DbAction.WithEntity<?> parent, String propertyName, Object value,
|
||||
@Nullable Object key, IdValueSource idValueSource) {
|
||||
@Nullable Object key, IdValueSource idValueSource) {
|
||||
|
||||
return new DbAction.Insert<>(value, getPersistentPropertyPath(propertyName), parent,
|
||||
key == null ? emptyMap() : singletonMap(toPath(propertyName), key), idValueSource);
|
||||
@@ -269,6 +271,7 @@ public class JdbcAggregateChangeExecutorContextUnitTests {
|
||||
.orElseThrow(() -> new IllegalArgumentException("No matching path found"));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static class DummyEntity {
|
||||
|
||||
@Id Long id;
|
||||
|
||||
@@ -49,7 +49,7 @@ import org.springframework.context.annotation.Import;
|
||||
import org.springframework.dao.IncorrectUpdateSemanticsDataAccessException;
|
||||
import org.springframework.dao.OptimisticLockingFailureException;
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.annotation.PersistenceConstructor;
|
||||
import org.springframework.data.annotation.PersistenceCreator;
|
||||
import org.springframework.data.annotation.ReadOnlyProperty;
|
||||
import org.springframework.data.annotation.Version;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
@@ -205,14 +205,13 @@ class JdbcAggregateTemplateIntegrationTests {
|
||||
|
||||
assertThat(reloadedLegoSet.manual).isNotNull();
|
||||
|
||||
SoftAssertions softly = new SoftAssertions();
|
||||
assertSoftly(softly -> {
|
||||
softly.assertThat(reloadedLegoSet.manual.getId()) //
|
||||
.isEqualTo(legoSet.getManual().getId()) //
|
||||
.isNotNull();
|
||||
softly.assertThat(reloadedLegoSet.manual.getContent()).isEqualTo(legoSet.getManual().getContent());
|
||||
});
|
||||
|
||||
softly.assertThat(reloadedLegoSet.manual.getId()) //
|
||||
.isEqualTo(legoSet.getManual().getId()) //
|
||||
.isNotNull();
|
||||
softly.assertThat(reloadedLegoSet.manual.getContent()).isEqualTo(legoSet.getManual().getContent());
|
||||
|
||||
softly.assertAll();
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-112
|
||||
@@ -307,12 +306,11 @@ class JdbcAggregateTemplateIntegrationTests {
|
||||
|
||||
template.delete(legoSet, LegoSet.class);
|
||||
|
||||
SoftAssertions softly = new SoftAssertions();
|
||||
assertSoftly(softly -> {
|
||||
|
||||
softly.assertThat(template.findAll(LegoSet.class)).isEmpty();
|
||||
softly.assertThat(template.findAll(Manual.class)).isEmpty();
|
||||
|
||||
softly.assertAll();
|
||||
softly.assertThat(template.findAll(LegoSet.class)).isEmpty();
|
||||
softly.assertThat(template.findAll(Manual.class)).isEmpty();
|
||||
});
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-112
|
||||
@@ -323,44 +321,46 @@ class JdbcAggregateTemplateIntegrationTests {
|
||||
|
||||
template.deleteAll(LegoSet.class);
|
||||
|
||||
SoftAssertions softly = new SoftAssertions();
|
||||
assertSoftly(softly -> {
|
||||
|
||||
assertThat(template.findAll(LegoSet.class)).isEmpty();
|
||||
assertThat(template.findAll(Manual.class)).isEmpty();
|
||||
softly.assertThat(template.findAll(LegoSet.class)).isEmpty();
|
||||
softly.assertThat(template.findAll(Manual.class)).isEmpty();
|
||||
});
|
||||
|
||||
softly.assertAll();
|
||||
}
|
||||
|
||||
@Test // GH-537
|
||||
@EnabledOnFeature(SUPPORTS_QUOTED_IDS)
|
||||
void saveAndDeleteAllByAggregateRootsWithReferencedEntity() {
|
||||
|
||||
LegoSet legoSet1 = template.save(legoSet);
|
||||
LegoSet legoSet2 = template.save(createLegoSet("Some Name"));
|
||||
template.save(createLegoSet("Some other Name"));
|
||||
|
||||
template.deleteAll(List.of(legoSet1, legoSet2), LegoSet.class);
|
||||
|
||||
SoftAssertions softly = new SoftAssertions();
|
||||
assertSoftly(softly -> {
|
||||
|
||||
assertThat(template.findAll(LegoSet.class)).isEmpty();
|
||||
assertThat(template.findAll(Manual.class)).isEmpty();
|
||||
|
||||
softly.assertAll();
|
||||
softly.assertThat(template.findAll(LegoSet.class)).extracting(l -> l.name).containsExactly("Some other Name");
|
||||
softly.assertThat(template.findAll(Manual.class)).hasSize(1);
|
||||
});
|
||||
}
|
||||
|
||||
@Test // GH-537
|
||||
@EnabledOnFeature(SUPPORTS_QUOTED_IDS)
|
||||
void saveAndDeleteAllByIdsWithReferencedEntity() {
|
||||
|
||||
LegoSet legoSet1 = template.save(legoSet);
|
||||
LegoSet legoSet2 = template.save(createLegoSet("Some Name"));
|
||||
template.save(createLegoSet("Some other Name"));
|
||||
|
||||
template.deleteAllById(List.of(legoSet1.id, legoSet2.id), LegoSet.class);
|
||||
|
||||
SoftAssertions softly = new SoftAssertions();
|
||||
assertSoftly(softly -> {
|
||||
|
||||
assertThat(template.findAll(LegoSet.class)).isEmpty();
|
||||
assertThat(template.findAll(Manual.class)).isEmpty();
|
||||
|
||||
softly.assertAll();
|
||||
softly.assertThat(template.findAll(LegoSet.class)).extracting(l -> l.name).containsExactly("Some other Name");
|
||||
softly.assertThat(template.findAll(Manual.class)).hasSize(1);
|
||||
});
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-112
|
||||
@@ -427,12 +427,11 @@ class JdbcAggregateTemplateIntegrationTests {
|
||||
|
||||
LegoSet reloadedLegoSet = template.findById(legoSet.getId(), LegoSet.class);
|
||||
|
||||
SoftAssertions softly = new SoftAssertions();
|
||||
assertSoftly(softly -> {
|
||||
|
||||
softly.assertThat(reloadedLegoSet.manual.content).isEqualTo("other content");
|
||||
softly.assertThat(template.findAll(Manual.class)).describedAs("There should be only one manual").hasSize(1);
|
||||
|
||||
softly.assertAll();
|
||||
softly.assertThat(reloadedLegoSet.manual.content).isEqualTo("other content");
|
||||
softly.assertThat(template.findAll(Manual.class)).describedAs("There should be only one manual").hasSize(1);
|
||||
});
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-112
|
||||
@@ -524,14 +523,14 @@ class JdbcAggregateTemplateIntegrationTests {
|
||||
|
||||
LegoSet reloadedLegoSet = template.findById(legoSet.getId(), LegoSet.class);
|
||||
|
||||
SoftAssertions softly = new SoftAssertions();
|
||||
softly.assertThat(reloadedLegoSet.alternativeInstructions).isNotNull();
|
||||
softly.assertThat(reloadedLegoSet.alternativeInstructions.id).isNotNull();
|
||||
softly.assertThat(reloadedLegoSet.alternativeInstructions.id).isNotEqualTo(reloadedLegoSet.manual.id);
|
||||
softly.assertThat(reloadedLegoSet.alternativeInstructions.content)
|
||||
.isEqualTo(reloadedLegoSet.alternativeInstructions.content);
|
||||
assertSoftly(softly -> {
|
||||
|
||||
softly.assertAll();
|
||||
softly.assertThat(reloadedLegoSet.alternativeInstructions).isNotNull();
|
||||
softly.assertThat(reloadedLegoSet.alternativeInstructions.id).isNotNull();
|
||||
softly.assertThat(reloadedLegoSet.alternativeInstructions.id).isNotEqualTo(reloadedLegoSet.manual.id);
|
||||
softly.assertThat(reloadedLegoSet.alternativeInstructions.content)
|
||||
.isEqualTo(reloadedLegoSet.alternativeInstructions.content);
|
||||
});
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-276
|
||||
@@ -559,7 +558,7 @@ class JdbcAggregateTemplateIntegrationTests {
|
||||
|
||||
ElementNoId element = new ElementNoId();
|
||||
element.content = "content";
|
||||
ListParentAllArgs entity = new ListParentAllArgs("name", asList(element));
|
||||
ListParentAllArgs entity = new ListParentAllArgs("name", singletonList(element));
|
||||
|
||||
entity = template.save(entity);
|
||||
|
||||
@@ -1103,6 +1102,7 @@ class JdbcAggregateTemplateIntegrationTests {
|
||||
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
static class OneToOneParent {
|
||||
|
||||
@Column("id3") @Id private Long id;
|
||||
@@ -1116,6 +1116,7 @@ class JdbcAggregateTemplateIntegrationTests {
|
||||
}
|
||||
|
||||
@Table("LIST_PARENT")
|
||||
@SuppressWarnings("unused")
|
||||
static class ListParent {
|
||||
|
||||
@Column("id4") @Id private Long id;
|
||||
@@ -1130,7 +1131,7 @@ class JdbcAggregateTemplateIntegrationTests {
|
||||
private final String name;
|
||||
@MappedCollection(idColumn = "LIST_PARENT") private final List<ElementNoId> content = new ArrayList<>();
|
||||
|
||||
@PersistenceConstructor
|
||||
@PersistenceCreator
|
||||
ListParentAllArgs(Long id, String name, List<ElementNoId> content) {
|
||||
|
||||
this.id = id;
|
||||
@@ -1150,23 +1151,27 @@ class JdbcAggregateTemplateIntegrationTests {
|
||||
/**
|
||||
* One may think of ChainN as a chain with N further elements
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
static class Chain0 {
|
||||
@Id Long zero;
|
||||
String zeroValue;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
static class Chain1 {
|
||||
@Id Long one;
|
||||
String oneValue;
|
||||
Chain0 chain0;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
static class Chain2 {
|
||||
@Id Long two;
|
||||
String twoValue;
|
||||
Chain1 chain1;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
static class Chain3 {
|
||||
@Id Long three;
|
||||
String threeValue;
|
||||
@@ -1273,6 +1278,7 @@ class JdbcAggregateTemplateIntegrationTests {
|
||||
Map<String, NoIdMapChain3> chain3 = new HashMap<>();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
static class WithReadOnly {
|
||||
@Id Long id;
|
||||
String name;
|
||||
|
||||
@@ -50,6 +50,7 @@ import org.springframework.data.relational.core.sql.Aliased;
|
||||
import org.springframework.data.relational.core.sql.LockMode;
|
||||
import org.springframework.data.relational.core.sql.SqlIdentifier;
|
||||
import org.springframework.data.relational.core.sql.Table;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Unit tests for the {@link SqlGenerator}.
|
||||
@@ -65,16 +66,17 @@ import org.springframework.data.relational.core.sql.Table;
|
||||
* @author Mikhail Polivakha
|
||||
* @author Chirag Tailor
|
||||
*/
|
||||
@SuppressWarnings("Convert2MethodRef")
|
||||
class SqlGeneratorUnitTests {
|
||||
|
||||
private static final Identifier BACKREF = Identifier.of(unquoted("backref"), "some-value", String.class);
|
||||
|
||||
private SqlGenerator sqlGenerator;
|
||||
private NamingStrategy namingStrategy = new PrefixingNamingStrategy();
|
||||
private RelationalMappingContext context = new JdbcMappingContext(namingStrategy);
|
||||
private JdbcConverter converter = new BasicJdbcConverter(context, (identifier, path) -> {
|
||||
private final NamingStrategy namingStrategy = new PrefixingNamingStrategy();
|
||||
private final RelationalMappingContext context = new JdbcMappingContext(namingStrategy);
|
||||
private final JdbcConverter converter = new BasicJdbcConverter(context, (identifier, path) -> {
|
||||
throw new UnsupportedOperationException();
|
||||
});
|
||||
private SqlGenerator sqlGenerator;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
@@ -267,7 +269,8 @@ class SqlGeneratorUnitTests {
|
||||
|
||||
SqlGenerator sqlGenerator = createSqlGenerator(DummyEntity.class, PostgresDialect.INSTANCE);
|
||||
|
||||
String sql = sqlGenerator.getFindAll(Sort.by(new Sort.Order(Sort.Direction.ASC, "name", Sort.NullHandling.NULLS_LAST)));
|
||||
String sql = sqlGenerator
|
||||
.getFindAll(Sort.by(new Sort.Order(Sort.Direction.ASC, "name", Sort.NullHandling.NULLS_LAST)));
|
||||
|
||||
assertThat(sql).contains("ORDER BY \"dummy_entity\".\"x_name\" ASC NULLS LAST");
|
||||
}
|
||||
@@ -277,7 +280,8 @@ class SqlGeneratorUnitTests {
|
||||
|
||||
SqlGenerator sqlGenerator = createSqlGenerator(DummyEntity.class, SqlServerDialect.INSTANCE);
|
||||
|
||||
String sql = sqlGenerator.getFindAll(Sort.by(new Sort.Order(Sort.Direction.ASC, "name", Sort.NullHandling.NULLS_LAST)));
|
||||
String sql = sqlGenerator
|
||||
.getFindAll(Sort.by(new Sort.Order(Sort.Direction.ASC, "name", Sort.NullHandling.NULLS_LAST)));
|
||||
|
||||
assertThat(sql).endsWith("ORDER BY dummy_entity.x_name ASC");
|
||||
}
|
||||
@@ -695,6 +699,7 @@ class SqlGeneratorUnitTests {
|
||||
});
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private SqlGenerator.Join generateJoin(String path, Class<?> type) {
|
||||
return createSqlGenerator(type, AnsiDialect.INSTANCE)
|
||||
.getJoin(new PersistentPropertyPathExtension(context, PropertyPathTestingUtils.toPath(path, type, context)));
|
||||
@@ -733,6 +738,7 @@ class SqlGeneratorUnitTests {
|
||||
SqlIdentifier.quoted("child"), SqlIdentifier.quoted("CHILD_PARENT_OF_NO_ID_CHILD"));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private SqlIdentifier getAlias(Object maybeAliased) {
|
||||
|
||||
if (maybeAliased instanceof Aliased) {
|
||||
@@ -741,6 +747,7 @@ class SqlGeneratorUnitTests {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private org.springframework.data.relational.core.sql.Column generatedColumn(String path, Class<?> type) {
|
||||
|
||||
return createSqlGenerator(type, AnsiDialect.INSTANCE)
|
||||
@@ -762,6 +769,7 @@ class SqlGeneratorUnitTests {
|
||||
AggregateReference<OtherAggregate, Long> other;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
static class VersionedEntity extends DummyEntity {
|
||||
@Version Integer version;
|
||||
}
|
||||
@@ -781,6 +789,7 @@ class SqlGeneratorUnitTests {
|
||||
String something;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
static class Element {
|
||||
@Id Long id;
|
||||
String content;
|
||||
@@ -795,6 +804,7 @@ class SqlGeneratorUnitTests {
|
||||
|
||||
private static class NoIdChild {}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
static class OtherAggregate {
|
||||
@Id Long id;
|
||||
String name;
|
||||
@@ -823,6 +833,7 @@ class SqlGeneratorUnitTests {
|
||||
@ReadOnlyProperty String readOnlyValue;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
static class EntityWithQuotedColumnName {
|
||||
|
||||
// these column names behave like single double quote in the name since the get quoted and then doubling the double
|
||||
@@ -865,36 +876,43 @@ class SqlGeneratorUnitTests {
|
||||
Chain3 chain3;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
static class NoIdChain0 {
|
||||
String zeroValue;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
static class NoIdChain1 {
|
||||
String oneValue;
|
||||
NoIdChain0 chain0;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
static class NoIdChain2 {
|
||||
String twoValue;
|
||||
NoIdChain1 chain1;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
static class NoIdChain3 {
|
||||
String threeValue;
|
||||
NoIdChain2 chain2;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
static class NoIdChain4 {
|
||||
@Id Long four;
|
||||
String fourValue;
|
||||
NoIdChain3 chain3;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
static class IdNoIdChain {
|
||||
@Id Long id;
|
||||
NoIdChain4 chain4;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
static class IdIdNoIdChain {
|
||||
@Id Long id;
|
||||
IdNoIdChain idNoIdChain;
|
||||
|
||||
@@ -21,6 +21,10 @@ import static org.assertj.core.api.Assertions.*;
|
||||
import static org.assertj.core.api.SoftAssertions.*;
|
||||
import static org.springframework.test.context.TestExecutionListeners.MergeMode.*;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Value;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.sql.ResultSet;
|
||||
import java.time.Instant;
|
||||
@@ -48,8 +52,6 @@ import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Slice;
|
||||
import org.springframework.data.jdbc.core.mapping.AggregateReference;
|
||||
import org.springframework.data.relational.core.mapping.MappedCollection;
|
||||
import org.springframework.data.relational.repository.Lock;
|
||||
import org.springframework.data.jdbc.repository.query.Modifying;
|
||||
import org.springframework.data.jdbc.repository.query.Query;
|
||||
import org.springframework.data.jdbc.repository.support.JdbcRepositoryFactory;
|
||||
@@ -57,6 +59,7 @@ import org.springframework.data.jdbc.testing.AssumeFeatureTestExecutionListener;
|
||||
import org.springframework.data.jdbc.testing.EnabledOnFeature;
|
||||
import org.springframework.data.jdbc.testing.TestConfiguration;
|
||||
import org.springframework.data.jdbc.testing.TestDatabaseFeatures;
|
||||
import org.springframework.data.relational.core.mapping.MappedCollection;
|
||||
import org.springframework.data.relational.core.mapping.event.AbstractRelationalEvent;
|
||||
import org.springframework.data.relational.core.mapping.event.AfterConvertEvent;
|
||||
import org.springframework.data.relational.core.sql.LockMode;
|
||||
@@ -75,10 +78,6 @@ import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||
import org.springframework.test.jdbc.JdbcTestUtils;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Value;
|
||||
|
||||
/**
|
||||
* Very simple use cases for creation and usage of JdbcRepositories.
|
||||
*
|
||||
@@ -607,8 +606,7 @@ public class JdbcRepositoryIntegrationTests {
|
||||
repository.saveAll(asList(dummyA, dummyB, dummyC));
|
||||
|
||||
assertThat(repository.findByEnumTypeIn(Set.of(Direction.LEFT, Direction.RIGHT)))
|
||||
.extracting(DummyEntity::getDirection)
|
||||
.containsExactlyInAnyOrder(Direction.LEFT, Direction.RIGHT);
|
||||
.extracting(DummyEntity::getDirection).containsExactlyInAnyOrder(Direction.LEFT, Direction.RIGHT);
|
||||
}
|
||||
|
||||
@Test // GH-1212
|
||||
@@ -622,13 +620,13 @@ public class JdbcRepositoryIntegrationTests {
|
||||
dummyC.setDirection(Direction.RIGHT);
|
||||
repository.saveAll(asList(dummyA, dummyB, dummyC));
|
||||
|
||||
assertThat(repository.findByEnumType(Direction.CENTER))
|
||||
.extracting(DummyEntity::getDirection)
|
||||
assertThat(repository.findByEnumType(Direction.CENTER)).extracting(DummyEntity::getDirection)
|
||||
.containsExactlyInAnyOrder(Direction.CENTER);
|
||||
}
|
||||
|
||||
@Test // GH-537
|
||||
void manyInsertsWithNestedEntities() {
|
||||
|
||||
Root root1 = createRoot("root1");
|
||||
Root root2 = createRoot("root2");
|
||||
|
||||
@@ -644,6 +642,7 @@ public class JdbcRepositoryIntegrationTests {
|
||||
@Test // GH-537
|
||||
@EnabledOnFeature(TestDatabaseFeatures.Feature.SUPPORTS_GENERATED_IDS_IN_REFERENCED_ENTITIES)
|
||||
void manyUpdatesWithNestedEntities() {
|
||||
|
||||
Root root1 = createRoot("root1");
|
||||
Root root2 = createRoot("root2");
|
||||
List<Root> roots = rootRepository.saveAll(asList(root1, root2));
|
||||
@@ -669,6 +668,7 @@ public class JdbcRepositoryIntegrationTests {
|
||||
@Test // GH-537
|
||||
@EnabledOnFeature(TestDatabaseFeatures.Feature.SUPPORTS_GENERATED_IDS_IN_REFERENCED_ENTITIES)
|
||||
void manyInsertsAndUpdatesWithNestedEntities() {
|
||||
|
||||
Root root1 = createRoot("root1");
|
||||
Root savedRoot1 = rootRepository.save(root1);
|
||||
Root updatedRoot1 = new Root(savedRoot1.id, "updated" + savedRoot1.name,
|
||||
@@ -685,6 +685,7 @@ public class JdbcRepositoryIntegrationTests {
|
||||
}
|
||||
|
||||
private Root createRoot(String namePrefix) {
|
||||
|
||||
return new Root(null, namePrefix,
|
||||
new Intermediate(null, namePrefix + "Intermediate", new Leaf(null, namePrefix + "Leaf"), emptyList()),
|
||||
singletonList(new Intermediate(null, namePrefix + "QualifiedIntermediate", null,
|
||||
@@ -692,6 +693,7 @@ public class JdbcRepositoryIntegrationTests {
|
||||
}
|
||||
|
||||
private void assertIsEqualToWithNonNullIds(Root reloadedRoot1, Root root1) {
|
||||
|
||||
assertThat(reloadedRoot1.id).isNotNull();
|
||||
assertThat(reloadedRoot1.name).isEqualTo(root1.name);
|
||||
assertThat(reloadedRoot1.intermediate.id).isNotNull();
|
||||
@@ -840,6 +842,7 @@ public class JdbcRepositoryIntegrationTests {
|
||||
|
||||
@Value
|
||||
static class Root {
|
||||
|
||||
@Id Long id;
|
||||
String name;
|
||||
Intermediate intermediate;
|
||||
@@ -848,6 +851,7 @@ public class JdbcRepositoryIntegrationTests {
|
||||
|
||||
@Value
|
||||
static class Intermediate {
|
||||
|
||||
@Id Long id;
|
||||
String name;
|
||||
Leaf leaf;
|
||||
@@ -856,13 +860,14 @@ public class JdbcRepositoryIntegrationTests {
|
||||
|
||||
@Value
|
||||
static class Leaf {
|
||||
|
||||
@Id Long id;
|
||||
String name;
|
||||
}
|
||||
|
||||
static class MyEventListener implements ApplicationListener<AbstractRelationalEvent<?>> {
|
||||
|
||||
private List<AbstractRelationalEvent<?>> events = new ArrayList<>();
|
||||
private final List<AbstractRelationalEvent<?>> events = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
public void onApplicationEvent(AbstractRelationalEvent<?> event) {
|
||||
@@ -892,13 +897,11 @@ public class JdbcRepositoryIntegrationTests {
|
||||
}
|
||||
|
||||
interface DummyProjection {
|
||||
|
||||
String getName();
|
||||
}
|
||||
|
||||
@Value
|
||||
static class DtoProjection {
|
||||
|
||||
String name;
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ package org.springframework.data.jdbc.repository;
|
||||
|
||||
import static java.util.Arrays.*;
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
import static org.assertj.core.groups.Tuple.tuple;
|
||||
import static org.mockito.ArgumentMatchers.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
@@ -28,7 +29,6 @@ import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
import org.assertj.core.groups.Tuple;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.stubbing.Answer;
|
||||
@@ -45,8 +45,15 @@ import org.springframework.data.relational.core.dialect.Dialect;
|
||||
import org.springframework.data.relational.core.dialect.H2Dialect;
|
||||
import org.springframework.data.relational.core.dialect.HsqlDbDialect;
|
||||
import org.springframework.data.relational.core.mapping.RelationalMappingContext;
|
||||
import org.springframework.data.relational.core.mapping.event.*;
|
||||
import org.springframework.data.relational.core.mapping.event.AfterConvertEvent;
|
||||
import org.springframework.data.relational.core.mapping.event.AfterDeleteEvent;
|
||||
import org.springframework.data.relational.core.mapping.event.AfterSaveEvent;
|
||||
import org.springframework.data.relational.core.mapping.event.BeforeConvertEvent;
|
||||
import org.springframework.data.relational.core.mapping.event.BeforeDeleteEvent;
|
||||
import org.springframework.data.relational.core.mapping.event.BeforeSaveEvent;
|
||||
import org.springframework.data.relational.core.mapping.event.Identifier;
|
||||
import org.springframework.data.relational.core.mapping.event.RelationalEvent;
|
||||
import org.springframework.data.relational.core.mapping.event.WithId;
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
import org.springframework.data.repository.PagingAndSortingRepository;
|
||||
import org.springframework.jdbc.core.JdbcOperations;
|
||||
@@ -129,12 +136,12 @@ public class SimpleJdbcRepositoryEventsUnitTests {
|
||||
assertThat(publisher.events) //
|
||||
.extracting(RelationalEvent::getClass, e -> ((DummyEntity) e.getEntity()).getId()) //
|
||||
.containsExactly( //
|
||||
Tuple.tuple(BeforeConvertEvent.class, null), //
|
||||
Tuple.tuple(BeforeSaveEvent.class, null), //
|
||||
Tuple.tuple(BeforeConvertEvent.class, 23L), //
|
||||
Tuple.tuple(BeforeSaveEvent.class, 23L), //
|
||||
Tuple.tuple(AfterSaveEvent.class, generatedId), //
|
||||
Tuple.tuple(AfterSaveEvent.class, 23L) //
|
||||
tuple(BeforeConvertEvent.class, null), //
|
||||
tuple(BeforeSaveEvent.class, null), //
|
||||
tuple(BeforeConvertEvent.class, 23L), //
|
||||
tuple(BeforeSaveEvent.class, 23L), //
|
||||
tuple(AfterSaveEvent.class, generatedId), //
|
||||
tuple(AfterSaveEvent.class, 23L) //
|
||||
);
|
||||
}
|
||||
|
||||
@@ -150,8 +157,8 @@ public class SimpleJdbcRepositoryEventsUnitTests {
|
||||
this::getEntity, //
|
||||
this::getId //
|
||||
).containsExactly( //
|
||||
Tuple.tuple(BeforeDeleteEvent.class, entity, Identifier.of(23L)), //
|
||||
Tuple.tuple(AfterDeleteEvent.class, entity, Identifier.of(23L)) //
|
||||
tuple(BeforeDeleteEvent.class, entity, Identifier.of(23L)), //
|
||||
tuple(AfterDeleteEvent.class, entity, Identifier.of(23L)) //
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ CREATE TABLE ROOT
|
||||
ID BIGINT GENERATED BY DEFAULT AS IDENTITY ( START WITH 1 ) PRIMARY KEY,
|
||||
NAME VARCHAR(100)
|
||||
);
|
||||
|
||||
CREATE TABLE INTERMEDIATE
|
||||
(
|
||||
ID BIGINT GENERATED BY DEFAULT AS IDENTITY ( START WITH 1 ) PRIMARY KEY,
|
||||
@@ -27,6 +28,7 @@ CREATE TABLE INTERMEDIATE
|
||||
ROOT_ID BIGINT,
|
||||
ROOT_KEY INTEGER
|
||||
);
|
||||
|
||||
CREATE TABLE LEAF
|
||||
(
|
||||
ID BIGINT GENERATED BY DEFAULT AS IDENTITY ( START WITH 1 ) PRIMARY KEY,
|
||||
|
||||
@@ -14,6 +14,7 @@ CREATE TABLE ROOT
|
||||
ID BIGINT GENERATED BY DEFAULT AS IDENTITY ( START WITH 1 ) PRIMARY KEY,
|
||||
NAME VARCHAR(100)
|
||||
);
|
||||
|
||||
CREATE TABLE INTERMEDIATE
|
||||
(
|
||||
ID BIGINT GENERATED BY DEFAULT AS IDENTITY ( START WITH 1 ) PRIMARY KEY,
|
||||
@@ -22,6 +23,7 @@ CREATE TABLE INTERMEDIATE
|
||||
ROOT_ID BIGINT,
|
||||
ROOT_KEY INTEGER
|
||||
);
|
||||
|
||||
CREATE TABLE LEAF
|
||||
(
|
||||
ID BIGINT GENERATED BY DEFAULT AS IDENTITY ( START WITH 1 ) PRIMARY KEY,
|
||||
|
||||
@@ -14,6 +14,7 @@ CREATE TABLE ROOT
|
||||
ID BIGINT GENERATED BY DEFAULT AS IDENTITY ( START WITH 1 ) PRIMARY KEY,
|
||||
NAME VARCHAR(100)
|
||||
);
|
||||
|
||||
CREATE TABLE INTERMEDIATE
|
||||
(
|
||||
ID BIGINT GENERATED BY DEFAULT AS IDENTITY ( START WITH 1 ) PRIMARY KEY,
|
||||
@@ -22,6 +23,7 @@ CREATE TABLE INTERMEDIATE
|
||||
ROOT_ID BIGINT,
|
||||
ROOT_KEY INTEGER
|
||||
);
|
||||
|
||||
CREATE TABLE LEAF
|
||||
(
|
||||
ID BIGINT GENERATED BY DEFAULT AS IDENTITY ( START WITH 1 ) PRIMARY KEY,
|
||||
|
||||
@@ -14,6 +14,7 @@ CREATE TABLE ROOT
|
||||
ID BIGINT AUTO_INCREMENT PRIMARY KEY,
|
||||
NAME VARCHAR(100)
|
||||
);
|
||||
|
||||
CREATE TABLE INTERMEDIATE
|
||||
(
|
||||
ID BIGINT AUTO_INCREMENT PRIMARY KEY,
|
||||
@@ -22,6 +23,7 @@ CREATE TABLE INTERMEDIATE
|
||||
ROOT_ID BIGINT,
|
||||
ROOT_KEY INTEGER
|
||||
);
|
||||
|
||||
CREATE TABLE LEAF
|
||||
(
|
||||
ID BIGINT AUTO_INCREMENT PRIMARY KEY,
|
||||
|
||||
@@ -19,6 +19,7 @@ CREATE TABLE ROOT
|
||||
ID BIGINT IDENTITY PRIMARY KEY,
|
||||
NAME VARCHAR(100)
|
||||
);
|
||||
|
||||
CREATE TABLE INTERMEDIATE
|
||||
(
|
||||
ID BIGINT IDENTITY PRIMARY KEY,
|
||||
@@ -27,6 +28,7 @@ CREATE TABLE INTERMEDIATE
|
||||
ROOT_ID BIGINT,
|
||||
ROOT_KEY INTEGER
|
||||
);
|
||||
|
||||
CREATE TABLE LEAF
|
||||
(
|
||||
ID BIGINT IDENTITY PRIMARY KEY,
|
||||
|
||||
@@ -17,6 +17,7 @@ CREATE TABLE ROOT
|
||||
ID BIGINT AUTO_INCREMENT PRIMARY KEY,
|
||||
NAME VARCHAR(100)
|
||||
);
|
||||
|
||||
CREATE TABLE INTERMEDIATE
|
||||
(
|
||||
ID BIGINT AUTO_INCREMENT PRIMARY KEY,
|
||||
@@ -25,6 +26,7 @@ CREATE TABLE INTERMEDIATE
|
||||
ROOT_ID BIGINT,
|
||||
ROOT_KEY INTEGER
|
||||
);
|
||||
|
||||
CREATE TABLE LEAF
|
||||
(
|
||||
ID BIGINT AUTO_INCREMENT PRIMARY KEY,
|
||||
|
||||
@@ -19,6 +19,7 @@ CREATE TABLE ROOT
|
||||
ID NUMBER GENERATED BY DEFAULT ON NULL AS IDENTITY PRIMARY KEY,
|
||||
NAME VARCHAR2(100)
|
||||
);
|
||||
|
||||
CREATE TABLE INTERMEDIATE
|
||||
(
|
||||
ID NUMBER GENERATED BY DEFAULT ON NULL AS IDENTITY PRIMARY KEY,
|
||||
@@ -27,6 +28,7 @@ CREATE TABLE INTERMEDIATE
|
||||
ROOT_ID NUMBER,
|
||||
ROOT_KEY NUMBER
|
||||
);
|
||||
|
||||
CREATE TABLE LEAF
|
||||
(
|
||||
ID NUMBER GENERATED BY DEFAULT ON NULL AS IDENTITY PRIMARY KEY,
|
||||
|
||||
@@ -19,6 +19,7 @@ CREATE TABLE ROOT
|
||||
ID SERIAL PRIMARY KEY,
|
||||
NAME VARCHAR(100)
|
||||
);
|
||||
|
||||
CREATE TABLE INTERMEDIATE
|
||||
(
|
||||
ID SERIAL PRIMARY KEY,
|
||||
@@ -27,6 +28,7 @@ CREATE TABLE INTERMEDIATE
|
||||
"ROOT_ID" BIGINT,
|
||||
"ROOT_KEY" INTEGER
|
||||
);
|
||||
|
||||
CREATE TABLE LEAF
|
||||
(
|
||||
ID SERIAL PRIMARY KEY,
|
||||
|
||||
Reference in New Issue
Block a user