DATACASS-362 - Add tests to assert composite key usage in …ById template methods.

Extend Javadoc to mention the accepted Id types. Add tests to verify query creation via MappingCassandraConverter.
This commit is contained in:
Mark Paluch
2017-07-19 10:50:44 +02:00
parent ca501ba936
commit ac0d34fe2c
5 changed files with 111 additions and 31 deletions

View File

@@ -206,7 +206,9 @@ public interface AsyncCassandraOperations {
/**
* Determine whether the row {@code entityClass} with the given {@code id} exists.
*
* @param id must not be {@literal null}.
* @param id the Id value. For single primary keys it's the plain value. For composite primary keys either the
* {@link org.springframework.data.cassandra.core.mapping.PrimaryKeyClass} or
* {@link org.springframework.data.cassandra.core.mapping.MapId}. Must not be {@literal null}.
* @param entityClass must not be {@literal null}.
* @return {@literal true}, if the object exists.
* @throws DataAccessException if there is any problem executing the query.
@@ -216,7 +218,9 @@ public interface AsyncCassandraOperations {
/**
* Execute the Select by {@code id} for the given {@code entityClass}.
*
* @param id must not be {@literal null}.
* @param id the Id value. For single primary keys it's the plain value. For composite primary keys either the
* {@link org.springframework.data.cassandra.core.mapping.PrimaryKeyClass} or
* {@link org.springframework.data.cassandra.core.mapping.MapId}. Must not be {@literal null}.
* @param entityClass The entity type must not be {@literal null}.
* @return the converted object or {@literal null}.
* @throws DataAccessException if there is any problem executing the query.
@@ -283,7 +287,9 @@ public interface AsyncCassandraOperations {
/**
* Remove the given object from the table by id.
*
* @param id must not be {@literal null}.
* @param id the Id value. For single primary keys it's the plain value. For composite primary keys either the
* {@link org.springframework.data.cassandra.core.mapping.PrimaryKeyClass} or
* {@link org.springframework.data.cassandra.core.mapping.MapId}. Must not be {@literal null}.
* @param entityClass The entity type must not be {@literal null}.
* @return {@literal true} if the deletion was applied.
* @throws DataAccessException if there is any problem executing the query.

View File

@@ -227,7 +227,9 @@ public interface CassandraOperations {
/**
* Determine whether the row {@code entityClass} with the given {@code id} exists.
*
* @param id must not be {@literal null}.
* @param id the Id value. For single primary keys it's the plain value. For composite primary keys either the
* {@link org.springframework.data.cassandra.core.mapping.PrimaryKeyClass} or
* {@link org.springframework.data.cassandra.core.mapping.MapId}. Must not be {@literal null}.
* @param entityClass The entity type must not be {@literal null}.
* @return true, if the object exists.
* @throws DataAccessException if there is any problem executing the query.
@@ -237,7 +239,9 @@ public interface CassandraOperations {
/**
* Execute the Select by {@code id} for the given {@code entityClass}.
*
* @param id must not be {@literal null}.
* @param id the Id value. For single primary keys it's the plain value. For composite primary keys either the
* {@link org.springframework.data.cassandra.core.mapping.PrimaryKeyClass} or
* {@link org.springframework.data.cassandra.core.mapping.MapId}. Must not be {@literal null}.
* @param entityClass The entity type must not be {@literal null}.
* @return the converted object or {@literal null}.
* @throws DataAccessException if there is any problem executing the query.
@@ -301,7 +305,9 @@ public interface CassandraOperations {
/**
* Remove the given object from the table by id.
*
* @param id must not be {@literal null}.
* @param id the Id value. For single primary keys it's the plain value. For composite primary keys either the
* {@link org.springframework.data.cassandra.core.mapping.PrimaryKeyClass} or
* {@link org.springframework.data.cassandra.core.mapping.MapId}. Must not be {@literal null}.
* @param entityClass The entity type must not be {@literal null}.
* @throws DataAccessException if there is any problem executing the query.
*/

View File

@@ -152,7 +152,9 @@ public interface ReactiveCassandraOperations {
/**
* Determine whether the row {@code entityClass} with the given {@code id} exists.
*
* @param id must not be {@literal null}.
* @param id the Id value. For single primary keys it's the plain value. For composite primary keys either the
* {@link org.springframework.data.cassandra.core.mapping.PrimaryKeyClass} or
* {@link org.springframework.data.cassandra.core.mapping.MapId}. Must not be {@literal null}.
* @param entityClass must not be {@literal null}.
* @return {@literal true} if the object exists.
* @throws DataAccessException if there is any problem issuing the execution.
@@ -162,7 +164,9 @@ public interface ReactiveCassandraOperations {
/**
* Execute the Select by {@code id} for the given {@code entityClass}.
*
* @param id must not be {@literal null}.
* @param id the Id value. For single primary keys it's the plain value. For composite primary keys either the
* {@link org.springframework.data.cassandra.core.mapping.PrimaryKeyClass} or
* {@link org.springframework.data.cassandra.core.mapping.MapId}. Must not be {@literal null}.
* @param entityClass The entity type must not be {@literal null}.
* @return the result object returned by the action or {@link Mono#empty()}
* @throws DataAccessException if there is any problem issuing the execution.
@@ -229,7 +233,9 @@ public interface ReactiveCassandraOperations {
/**
* Remove the given object from the table by id.
*
* @param id must not be {@literal null}.
* @param id the Id value. For single primary keys it's the plain value. For composite primary keys either the
* {@link org.springframework.data.cassandra.core.mapping.PrimaryKeyClass} or
* {@link org.springframework.data.cassandra.core.mapping.MapId}. Must not be {@literal null}.
* @param entityClass The entity type must not be {@literal null}.
* @return {@literal true} if the deletion was applied.
* @throws DataAccessException if there is any problem issuing the execution.

View File

@@ -144,6 +144,13 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
return mappingContext;
}
/**
* Read a {@link Row} into the requested target {@code type}.
*
* @param type must not be {@literal null}.
* @param row must not be {@literal null}.
* @return the converted valued.
*/
@SuppressWarnings("unchecked")
public <R> R readRow(Class<R> type, Row row) {
@@ -498,12 +505,11 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
if (id instanceof MapId) {
// FIXME: Generics
CassandraPersistentEntity<?> whereEntity = compositeIdProperty != null
? mappingContext.getRequiredPersistentEntity(compositeIdProperty)
: entity;
return getWhereClauses((MapId) id, whereEntity);
return getWhereClauses(MapId.class.cast(id), whereEntity);
}
if (idProperty == null) {
@@ -518,20 +524,16 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
String.format("Cannot use [%s] as composite Id for [%s]", id, entity.getName()));
}
CassandraPersistentEntity<?> compositePrimaryKey =
mappingContext.getRequiredPersistentEntity(compositeIdProperty);
CassandraPersistentEntity<?> compositePrimaryKey = mappingContext
.getRequiredPersistentEntity(compositeIdProperty);
return getWhereClauses(getConvertingAccessor(id, compositePrimaryKey), compositePrimaryKey);
}
Class<?> targetType = getTargetType(idProperty);
if (getConversionService().canConvert(id.getClass(), targetType)) {
return Collections.singleton(
QueryBuilder.eq(idProperty.getColumnName().toCql(), getPotentiallyConvertedSimpleValue(id, targetType)));
}
return Collections.singleton(QueryBuilder.eq(idProperty.getColumnName().toCql(), id));
return Collections.singleton(
QueryBuilder.eq(idProperty.getColumnName().toCql(), getPotentiallyConvertedSimpleValue(id, targetType)));
}
private Object extractId(Object source, CassandraPersistentEntity<?> entity) {
@@ -608,8 +610,9 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
if (idProperty != null) {
// TODO: NullId
return propertyAccessor.getProperty(idProperty, idProperty.isCompositePrimaryKey()
? (Class<Object>) idProperty.getType() : (Class<Object>) getTargetType(idProperty));
return propertyAccessor.getProperty(idProperty,
idProperty.isCompositePrimaryKey() ? (Class<Object>) idProperty.getType()
: (Class<Object>) getTargetType(idProperty));
}
// if the class doesn't have an id property, then it's using MapId

View File

@@ -50,8 +50,10 @@ import org.junit.rules.ExpectedException;
import org.springframework.core.SpringVersion;
import org.springframework.core.convert.ConverterNotFoundException;
import org.springframework.data.cassandra.core.cql.PrimaryKeyType;
import org.springframework.data.cassandra.core.mapping.BasicMapId;
import org.springframework.data.cassandra.core.mapping.CassandraMappingContext;
import org.springframework.data.cassandra.core.mapping.CassandraType;
import org.springframework.data.cassandra.core.mapping.MapId;
import org.springframework.data.cassandra.core.mapping.PrimaryKey;
import org.springframework.data.cassandra.core.mapping.PrimaryKeyClass;
import org.springframework.data.cassandra.core.mapping.PrimaryKeyColumn;
@@ -77,6 +79,7 @@ import com.datastax.driver.core.querybuilder.Delete;
import com.datastax.driver.core.querybuilder.Delete.Where;
import com.datastax.driver.core.querybuilder.Insert;
import com.datastax.driver.core.querybuilder.QueryBuilder;
import com.datastax.driver.core.querybuilder.Select;
import com.datastax.driver.core.querybuilder.Update;
import com.datastax.driver.core.querybuilder.Update.Assignments;
@@ -851,32 +854,88 @@ public class MappingCassandraConverterUnitTests {
mappingContext.getRequiredPersistentEntity(TypeWithMapId.class));
}
@Test // DATACASS-362
public void shouldSelectCompositeIdUsingMapId() {
Select select = QueryBuilder.select().from("foo");
MapId mapId = BasicMapId.id("firstname", "first").with("lastname", "last");
mappingCassandraConverter.write(mapId, select.where(),
mappingContext.getRequiredPersistentEntity(TypeWithMapId.class));
assertThat(select.toString()).isEqualTo("SELECT * FROM foo WHERE firstname='first' AND lastname='last';");
}
@Test // DATACASS-362
public void shouldSelectCompositeIdUsingCompositeKeyClass() {
Select select = QueryBuilder.select().from("foo");
CompositeKey key = new CompositeKey();
key.setFirstname("first");
key.setLastname("last");
mappingCassandraConverter.write(key, select.where(),
mappingContext.getRequiredPersistentEntity(TypeWithKeyClass.class));
assertThat(select.toString()).isEqualTo("SELECT * FROM foo WHERE first_name='first' AND lastname='last';");
}
@Test // DATACASS-362
public void shouldSelectCompositeIdUsingCompositeKeyClassViaMapId() {
Select select = QueryBuilder.select().from("foo");
MapId mapId = BasicMapId.id("firstname", "first").with("lastname", "last");
mappingCassandraConverter.write(mapId, select.where(),
mappingContext.getRequiredPersistentEntity(TypeWithKeyClass.class));
assertThat(select.toString()).isEqualTo("SELECT * FROM foo WHERE first_name='first' AND lastname='last';");
}
@Test // DATACASS-362
public void shouldDeleteCompositeIdUsingCompositeKeyClass() {
Delete delete = QueryBuilder.delete().from("foo");
CompositeKey key = new CompositeKey();
key.setFirstname("first");
key.setLastname("last");
mappingCassandraConverter.write(key, delete.where(),
mappingContext.getRequiredPersistentEntity(TypeWithKeyClass.class));
assertThat(delete.toString()).isEqualTo("DELETE FROM foo WHERE first_name='first' AND lastname='last';");
}
@SuppressWarnings("unchecked")
private <T> List<T> getListValue(Insert statement) {
private static <T> List<T> getListValue(Insert statement) {
List<Object> values = getValues(statement);
return (List<T>) values.stream().filter(value -> value instanceof List).findFirst().orElse(null);
}
@SuppressWarnings("unchecked")
private <T> Set<T> getSetValue(Insert statement) {
private static <T> Set<T> getSetValue(Insert statement) {
List<Object> values = getValues(statement);
return (Set<T>) values.stream().filter(value -> value instanceof Set).findFirst().orElse(null);
}
@SuppressWarnings("unchecked")
private List<Object> getValues(Insert statement) {
private static List<Object> getValues(Insert statement) {
return (List<Object>) ReflectionTestUtils.getField(statement, "values");
}
@SuppressWarnings("unchecked")
private Collection<Object> getAssignmentValues(Update statement) {
private static Collection<Object> getAssignmentValues(Update statement) {
return getAssignments(statement).values();
}
@SuppressWarnings("unchecked")
private Map<String, Object> getAssignments(Update statement) {
private static Map<String, Object> getAssignments(Update statement) {
Map<String, Object> result = new LinkedHashMap<>();
@@ -891,24 +950,24 @@ public class MappingCassandraConverterUnitTests {
return result;
}
private Collection<Object> getWhereValues(Update update) {
private static Collection<Object> getWhereValues(Update update) {
return getWherePredicates(update.where()).values();
}
private Collection<Object> getWhereValues(BuiltStatement where) {
private static Collection<Object> getWhereValues(BuiltStatement where) {
return getWherePredicates(where).values();
}
private Map<String, Object> getWherePredicates(Update statement) {
private static Map<String, Object> getWherePredicates(Update statement) {
return getWherePredicates(statement.where());
}
private Map<String, Object> getWherePredicates(Delete statement) {
private static Map<String, Object> getWherePredicates(Delete statement) {
return getWherePredicates(statement.where());
}
@SuppressWarnings("unchecked")
private Map<String, Object> getWherePredicates(BuiltStatement where) {
private static Map<String, Object> getWherePredicates(BuiltStatement where) {
Map<String, Object> result = new LinkedHashMap<>();