DATACASS-638 - Skip properties that are not part of the result.
We now skip properties during mapping (assign a null value) if the backing result (Row, UDT) does not contain a particular column. Resultsets with limited columns are common for projections, in interface projections we use the actual entity to back calls to the projection.
This commit is contained in:
@@ -79,7 +79,6 @@ public class CassandraUDTValueProvider implements CassandraValueProvider {
|
||||
* @see org.springframework.data.mapping.model.PropertyValueProvider#getPropertyValue(org.springframework.data.mapping.PersistentProperty)
|
||||
*/
|
||||
@Nullable
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T getPropertyValue(CassandraPersistentProperty property) {
|
||||
|
||||
String spelExpression = property.getSpelExpression();
|
||||
|
||||
@@ -27,6 +27,7 @@ import java.util.function.Function;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanClassLoaderAware;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
@@ -952,7 +953,6 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
|
||||
* @return the return value, may be {@literal null}.
|
||||
*/
|
||||
@Nullable
|
||||
@SuppressWarnings("unchecked")
|
||||
private Object getReadValue(CassandraValueProvider valueProvider, CassandraPersistentProperty property) {
|
||||
|
||||
if (property.isCompositePrimaryKey()) {
|
||||
@@ -962,8 +962,11 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
|
||||
return instantiatePrimaryKey(keyEntity, property, valueProvider);
|
||||
}
|
||||
|
||||
Object value = valueProvider.getPropertyValue(property);
|
||||
if (!valueProvider.hasProperty(property)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Object value = valueProvider.getPropertyValue(property);
|
||||
return value == null ? null : convertReadValue(value, property.getTypeInformation());
|
||||
}
|
||||
|
||||
@@ -1010,7 +1013,7 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
|
||||
* @return the converted {@link Collection} or array, will never be {@literal null}.
|
||||
*/
|
||||
@Nullable
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
@SuppressWarnings({ "rawtypes" })
|
||||
private Object readCollectionOrArrayInternal(Collection<?> source, TypeInformation<?> targetType) {
|
||||
|
||||
Assert.notNull(targetType, "Target type must not be null");
|
||||
|
||||
@@ -19,6 +19,7 @@ import static org.assertj.core.api.Assertions.*;
|
||||
import static org.junit.Assume.*;
|
||||
import static org.springframework.data.cassandra.core.query.Criteria.*;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.Instant;
|
||||
@@ -36,10 +37,15 @@ import java.util.stream.Stream;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.cassandra.core.convert.MappingCassandraConverter;
|
||||
import org.springframework.data.cassandra.core.cql.CqlTemplate;
|
||||
import org.springframework.data.cassandra.core.cql.PrimaryKeyType;
|
||||
import org.springframework.data.cassandra.core.mapping.BasicMapId;
|
||||
import org.springframework.data.cassandra.core.mapping.PrimaryKey;
|
||||
import org.springframework.data.cassandra.core.mapping.PrimaryKeyClass;
|
||||
import org.springframework.data.cassandra.core.mapping.PrimaryKeyColumn;
|
||||
import org.springframework.data.cassandra.core.query.CassandraPageRequest;
|
||||
import org.springframework.data.cassandra.core.query.Columns;
|
||||
import org.springframework.data.cassandra.core.query.Query;
|
||||
@@ -83,9 +89,11 @@ public class CassandraTemplateIntegrationTests extends AbstractKeyspaceCreatingI
|
||||
SchemaTestUtils.potentiallyCreateTableFor(UserToken.class, template);
|
||||
SchemaTestUtils.potentiallyCreateTableFor(BookReference.class, template);
|
||||
SchemaTestUtils.potentiallyCreateTableFor(TimeClass.class, template);
|
||||
SchemaTestUtils.potentiallyCreateTableFor(TypeWithCompositeKey.class, template);
|
||||
SchemaTestUtils.truncate(User.class, template);
|
||||
SchemaTestUtils.truncate(UserToken.class, template);
|
||||
SchemaTestUtils.truncate(BookReference.class, template);
|
||||
SchemaTestUtils.truncate(TypeWithCompositeKey.class, template);
|
||||
}
|
||||
|
||||
@Test // DATACASS-343
|
||||
@@ -130,6 +138,45 @@ public class CassandraTemplateIntegrationTests extends AbstractKeyspaceCreatingI
|
||||
assertThat(loaded).containsSequence(token1, token2);
|
||||
}
|
||||
|
||||
@Test // DATACASS-638
|
||||
public void shouldSelectProjection() {
|
||||
|
||||
User user = new User("heisenberg", "Walter", "White");
|
||||
|
||||
template.insert(user);
|
||||
|
||||
Query query = Query.query(where("id").is(user.getId())).columns(Columns.empty().include("id").include("firstname"));
|
||||
List<User> loaded = template.select(query, User.class);
|
||||
|
||||
assertThat(loaded).hasSize(1);
|
||||
|
||||
User loadedUser = loaded.get(0);
|
||||
|
||||
assertThat(loadedUser.getFirstname()).isNotNull();
|
||||
assertThat(loadedUser.getLastname()).isNull();
|
||||
}
|
||||
|
||||
@Test // DATACASS-638
|
||||
public void shouldSelectProjectionWithCompositeKey() {
|
||||
|
||||
CompositeKey key = new CompositeKey("Walter", "White");
|
||||
TypeWithCompositeKey user = new TypeWithCompositeKey(key, "comment");
|
||||
|
||||
template.insert(user);
|
||||
|
||||
Query query = Query.empty().columns(Columns.empty().include("firstname").include("comment"));
|
||||
List<TypeWithCompositeKey> loaded = template.select(query, TypeWithCompositeKey.class);
|
||||
|
||||
assertThat(loaded).hasSize(1);
|
||||
|
||||
TypeWithCompositeKey loadedEntity = loaded.get(0);
|
||||
|
||||
assertThat(loadedEntity.getKey()).isNotNull();
|
||||
assertThat(loadedEntity.getKey().getFirstname()).isNotNull();
|
||||
assertThat(loadedEntity.getKey().getLastname()).isNull();
|
||||
assertThat(loadedEntity.getComment()).isNotNull();
|
||||
}
|
||||
|
||||
@Test // DATACASS-343
|
||||
public void shouldSelectOneByQuery() {
|
||||
|
||||
@@ -203,7 +250,7 @@ public class CassandraTemplateIntegrationTests extends AbstractKeyspaceCreatingI
|
||||
@Test // DATACASS-155
|
||||
public void shouldNotOverrideLaterMutation() {
|
||||
|
||||
Instant now = LocalDateTime.now().atZone( ZoneId.systemDefault() ).toInstant();
|
||||
Instant now = LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant();
|
||||
User user = new User("heisenberg", "Walter", "White");
|
||||
template.insert(user);
|
||||
|
||||
@@ -518,4 +565,21 @@ public class CassandraTemplateIntegrationTests extends AbstractKeyspaceCreatingI
|
||||
@Id LocalTime id;
|
||||
LocalTime bar;
|
||||
}
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
static class TypeWithCompositeKey {
|
||||
@PrimaryKey CompositeKey key;
|
||||
String comment;
|
||||
}
|
||||
|
||||
@Data
|
||||
@PrimaryKeyClass
|
||||
@AllArgsConstructor
|
||||
static class CompositeKey {
|
||||
|
||||
@PrimaryKeyColumn(type = PrimaryKeyType.PARTITIONED) String firstname;
|
||||
@PrimaryKeyColumn(type = PrimaryKeyType.PARTITIONED) String lastname;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.annotation.PersistenceConstructor;
|
||||
import org.springframework.data.cassandra.core.mapping.Table;
|
||||
|
||||
/**
|
||||
@@ -43,6 +44,7 @@ public class User {
|
||||
private String firstname;
|
||||
private String lastname;
|
||||
|
||||
@PersistenceConstructor
|
||||
public User(String id, String firstname, String lastname) {
|
||||
|
||||
this.id = id;
|
||||
|
||||
Reference in New Issue
Block a user