From 6a4dddd218fd8c37632f7fa438b6e26b3f686983 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Mon, 7 Jun 2021 14:38:15 +0200 Subject: [PATCH] Correctly write Where for entities using composite primary key classes with user-defined types. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We now correctly write properties from composite primary keys to the Where condition object. Previously, the object write used writeWhereFromObject(…) that isn't converter/UDT/tuple-type-aware. Closes #1137. --- .../convert/MappingCassandraConverter.java | 9 +- ...MappingCassandraConverterUDTUnitTests.java | 112 ++++++++++++++---- 2 files changed, 96 insertions(+), 25 deletions(-) diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/convert/MappingCassandraConverter.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/convert/MappingCassandraConverter.java index 369a59a32..0b5f8505e 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/convert/MappingCassandraConverter.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/convert/MappingCassandraConverter.java @@ -482,7 +482,7 @@ public class MappingCassandraConverter extends AbstractCassandraConverter if (sink instanceof Where) { writeWhereFromObject(source, (Where) sink, entity); } else if (sink instanceof Map) { - writeMapFromWrapper(newConvertingPropertyAccessor(source, entity), (Map) sink, entity); + writeInternal(newConvertingPropertyAccessor(source, entity), (Map) sink, entity); } else if (sink instanceof TupleValue) { writeTupleValue(newConvertingPropertyAccessor(source, entity), (TupleValue) sink, entity); } else if (sink instanceof UdtValue) { @@ -492,7 +492,7 @@ public class MappingCassandraConverter extends AbstractCassandraConverter } } - private void writeMapFromWrapper(ConvertingPropertyAccessor accessor, Map sink, + private void writeInternal(ConvertingPropertyAccessor accessor, Map sink, CassandraPersistentEntity entity) { for (CassandraPersistentProperty property : entity) { @@ -511,7 +511,7 @@ public class MappingCassandraConverter extends AbstractCassandraConverter CassandraPersistentEntity compositePrimaryKey = getMappingContext().getRequiredPersistentEntity(property); - writeMapFromWrapper(newConvertingPropertyAccessor(value, compositePrimaryKey), sink, compositePrimaryKey); + writeInternal(newConvertingPropertyAccessor(value, compositePrimaryKey), sink, compositePrimaryKey); continue; } @@ -583,8 +583,7 @@ public class MappingCassandraConverter extends AbstractCassandraConverter CassandraPersistentEntity compositePrimaryKey = getMappingContext() .getRequiredPersistentEntity(compositeIdProperty); - - writeWhere(newConvertingPropertyAccessor(id, compositePrimaryKey), sink, compositePrimaryKey); + writeInternal(newConvertingPropertyAccessor(id, compositePrimaryKey), sink, compositePrimaryKey); return; } diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/convert/MappingCassandraConverterUDTUnitTests.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/convert/MappingCassandraConverterUDTUnitTests.java index 5d045ef3d..a89e3f2b0 100755 --- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/convert/MappingCassandraConverterUDTUnitTests.java +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/convert/MappingCassandraConverterUDTUnitTests.java @@ -42,16 +42,10 @@ import org.springframework.core.convert.converter.Converter; import org.springframework.data.annotation.Id; import org.springframework.data.annotation.ReadOnlyProperty; import org.springframework.data.cassandra.core.StatementFactory; +import org.springframework.data.cassandra.core.cql.PrimaryKeyType; import org.springframework.data.cassandra.core.cql.WriteOptions; import org.springframework.data.cassandra.core.cql.util.StatementBuilder; -import org.springframework.data.cassandra.core.mapping.CassandraMappingContext; -import org.springframework.data.cassandra.core.mapping.CassandraPersistentEntity; -import org.springframework.data.cassandra.core.mapping.CassandraType; -import org.springframework.data.cassandra.core.mapping.Embedded; -import org.springframework.data.cassandra.core.mapping.Frozen; -import org.springframework.data.cassandra.core.mapping.Table; -import org.springframework.data.cassandra.core.mapping.UserDefinedType; -import org.springframework.data.cassandra.core.mapping.UserTypeResolver; +import org.springframework.data.cassandra.core.mapping.*; import org.springframework.data.cassandra.support.UserDefinedTypeBuilder; import org.springframework.data.cassandra.test.util.RowMockUtil; @@ -127,10 +121,7 @@ class MappingCassandraConverterUDTUnitTests { @Test // DATACASS-172 void shouldWriteMappedUdt() { - AddressUserType addressUserType = new AddressUserType(); - addressUserType.setZip("69469"); - addressUserType.setCity("Weinheim"); - addressUserType.setStreetLines(Arrays.asList("Heckenpfad", "14")); + AddressUserType addressUserType = prepareAddressUserType(); AddressBook addressBook = new AddressBook(); addressBook.setId("1"); @@ -146,10 +137,7 @@ class MappingCassandraConverterUDTUnitTests { @Test // DATACASS-172 void shouldWriteMappedUdtCollection() { - AddressUserType addressUserType = new AddressUserType(); - addressUserType.setZip("69469"); - addressUserType.setCity("Weinheim"); - addressUserType.setStreetLines(Arrays.asList("Heckenpfad", "14")); + AddressUserType addressUserType = prepareAddressUserType(); AddressBook addressBook = new AddressBook(); addressBook.setId("1"); @@ -188,10 +176,7 @@ class MappingCassandraConverterUDTUnitTests { @Test // DATACASS-172 void shouldWriteUdtPk() { - AddressUserType addressUserType = new AddressUserType(); - addressUserType.setZip("69469"); - addressUserType.setCity("Weinheim"); - addressUserType.setStreetLines(Arrays.asList("Heckenpfad", "14")); + AddressUserType addressUserType = prepareAddressUserType(); WithMappedUdtId withUdtId = new WithMappedUdtId(); withUdtId.setId(addressUserType); @@ -203,6 +188,72 @@ class MappingCassandraConverterUDTUnitTests { "INSERT INTO withmappedudtid (id) " + "VALUES ({zip:'69469',city:'Weinheim',streetlines:['Heckenpfad','14']})"); } + @Test // #1137 + void shouldWriteCompositeUdtPk() { + + AddressUserType addressUserType = prepareAddressUserType(); + + WithCompositePrimaryKey withUdt = new WithCompositePrimaryKey(); + withUdt.addressUserType = addressUserType; + withUdt.id = "foo"; + + SimpleStatement statement = new StatementFactory(converter).insert(withUdt, WriteOptions.empty()) + .build(StatementBuilder.ParameterHandling.INLINE); + + assertThat(statement.getQuery()).isEqualTo("INSERT INTO withcompositeprimarykey (id,addressusertype) " + + "VALUES ('foo',{zip:'69469',city:'Weinheim',streetlines:['Heckenpfad','14']})"); + } + + private static AddressUserType prepareAddressUserType() { + + AddressUserType addressUserType = new AddressUserType(); + addressUserType.setZip("69469"); + addressUserType.setCity("Weinheim"); + addressUserType.setStreetLines(Arrays.asList("Heckenpfad", "14")); + + return addressUserType; + } + + @Test // #1137 + void shouldWriteCompositeUdtPkClass() { + + WithCompositePrimaryKeyClassWithUdt object = prepareCompositePrimaryKeyClassWithUdt(); + + SimpleStatement statement = new StatementFactory(converter).insert(object, WriteOptions.empty()) + .build(StatementBuilder.ParameterHandling.INLINE); + + assertThat(statement.getQuery()) + .isEqualTo("INSERT INTO withcompositeprimarykeyclasswithudt (id,addressusertype,currency) " + + "VALUES ('foo',{zip:'69469',city:'Weinheim',streetlines:['Heckenpfad','14']},{currency:'EUR'})"); + } + + @Test // #1137 + void shouldWriteCompositeUdtPkClassToWhere() { + + WithCompositePrimaryKeyClassWithUdt object = prepareCompositePrimaryKeyClassWithUdt(); + + Where where = new Where(); + converter.write(object, where); + + assertThat((UdtValue) where.get(CqlIdentifier.fromCql("currency"))) // + .extracting(UdtValue::getFormattedContents) // + .isEqualTo("{currency:'EUR'}"); + } + + private static WithCompositePrimaryKeyClassWithUdt prepareCompositePrimaryKeyClassWithUdt() { + + AddressUserType addressUserType = prepareAddressUserType(); + + CompositePrimaryKeyClassWithUdt withUdt = new CompositePrimaryKeyClassWithUdt(); + withUdt.addressUserType = addressUserType; + withUdt.id = "foo"; + withUdt.currency = new Currency("EUR"); + + WithCompositePrimaryKeyClassWithUdt object = new WithCompositePrimaryKeyClassWithUdt(); + object.id = withUdt; + return object; + } + @Test // DATACASS-172 void shouldWriteMappedUdtPk() { @@ -585,6 +636,27 @@ class MappingCassandraConverterUDTUnitTests { @Id private Currency currency; } + @Data + @Table + public static class WithCompositePrimaryKey { + @PrimaryKeyColumn(ordinal = 0, type = PrimaryKeyType.PARTITIONED) String id; + @PrimaryKeyColumn(ordinal = 1) AddressUserType addressUserType; + } + + @Data + @Table + public static class WithCompositePrimaryKeyClassWithUdt { + @PrimaryKey CompositePrimaryKeyClassWithUdt id; + } + + @Data + @PrimaryKeyClass + public static class CompositePrimaryKeyClassWithUdt { + @PrimaryKeyColumn(ordinal = 0, type = PrimaryKeyType.PARTITIONED) String id; + @PrimaryKeyColumn(ordinal = 1) AddressUserType addressUserType; + @PrimaryKeyColumn(ordinal = 2) Currency currency; + } + @Table @AllArgsConstructor @Getter