diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/CassandraConnectionFailureException.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/CassandraConnectionFailureException.java index 37a49a1bb..97feee031 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/CassandraConnectionFailureException.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/CassandraConnectionFailureException.java @@ -17,9 +17,14 @@ import java.util.Collections; import java.util.HashMap; +import java.util.List; import java.util.Map; +import java.util.Map.Entry; +import java.util.function.Function; +import java.util.stream.Collectors; import org.springframework.dao.DataAccessResourceFailureException; +import org.springframework.util.CollectionUtils; import com.datastax.oss.driver.api.core.metadata.Node; @@ -32,14 +37,26 @@ public class CassandraConnectionFailureException extends DataAccessResourceFailu private static final long serialVersionUID = 6299912054261646552L; - private final Map messagesByHost = new HashMap<>(); + private final Map> messagesByHost = new HashMap<>(); public CassandraConnectionFailureException(Map map, String msg, Throwable cause) { + super(msg, cause); + map.forEach((node, throwable) -> messagesByHost.put(node, Collections.singletonList(throwable))); + } + + public CassandraConnectionFailureException(String msg, Map> map, Throwable cause) { super(msg, cause); this.messagesByHost.putAll(map); } + @Deprecated(forRemoval = true) public Map getMessagesByHost() { + HashMap singleMessageByHost = new HashMap<>(); + this.messagesByHost.forEach((node, throwables) -> singleMessageByHost.put(node, CollectionUtils.firstElement(throwables))); + return singleMessageByHost; + } + + public Map> getAllMessagesByHost() { return Collections.unmodifiableMap(messagesByHost); } } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/CassandraTemplate.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/CassandraTemplate.java index 6299d2189..4f14ebebe 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/CassandraTemplate.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/CassandraTemplate.java @@ -414,19 +414,22 @@ public List select(Query query, Class entityClass) throws DataAccessEx Assert.notNull(query, "Query must not be null"); Assert.notNull(entityClass, "Entity type must not be null"); - return doSelect(query, entityClass, getTableName(entityClass), entityClass); + return doSelect(query, entityClass, getTableName(entityClass), entityClass, getEntityOperations().getCustomKeyspaceName(entityClass)); } List doSelect(Query query, Class entityClass, CqlIdentifier tableName, Class returnType) { + return this.doSelect(query, entityClass, tableName, returnType, null); + } + List doSelect(Query query, Class entityClass, CqlIdentifier tableName, Class returnType, @Nullable CqlIdentifier keyspace) { CassandraPersistentEntity entity = getRequiredPersistentEntity(entityClass); EntityProjection projection = entityOperations.introspectProjection(returnType, entityClass); Columns columns = getStatementFactory().computeColumnsForProjection(projection, query.getColumns(), entity, - returnType); + returnType); Query queryToUse = query.columns(columns); - StatementBuilder select = getStatementFactory().select(queryToUse, entity, tableName, keyspace); Function mapper = getMapper(projection, tableName); return doQuery(select.build(), (row, rowNum) -> mapper.apply(row)); @@ -463,7 +466,7 @@ public Stream stream(Query query, Class entityClass) throws DataAccess Stream doStream(Query query, Class entityClass, CqlIdentifier tableName, Class returnType) { StatementBuilder countStatement = getStatementFactory().count(query, - getRequiredPersistentEntity(entityClass), tableName); + getRequiredPersistentEntity(entityClass), tableName, keyspace); return doQueryForObject(countStatement.build(), Long.class); } @@ -557,7 +569,7 @@ public boolean exists(Object id, Class entityClass) { Assert.notNull(entityClass, "Entity type must not be null"); CassandraPersistentEntity entity = getRequiredPersistentEntity(entityClass); - StatementBuilder select = getStatementFactory().selectOneById(id, entity, entity.getTableName(), entity.getCustomKeyspace()); return doQueryForResultSet(select.build()).one() != null; } @@ -574,7 +586,7 @@ public boolean exists(Query query, Class entityClass) throws DataAccessExcept boolean doExists(Query query, Class entityClass, CqlIdentifier tableName) { StatementBuilder select = getStatementFactory().selectOneById(id, entity, tableName); + StatementBuilder count(Query query, CassandraPersistentEntity * @since 2.1 */ public StatementBuilder count(Query query, CassandraPersistentEntity entity, CqlIdentifier tableName, @Nullable CqlIdentifier keyspace) { Filter filter = getQueryMapper().getMappedObject(query, entity); List selectors = Collections.singletonList(FunctionCall.from("COUNT", 1L)); - return createSelect(query, entity, filter, selectors, tableName); + return createSelect(query, entity, filter, selectors, tableName, keyspace); } /** @@ -213,13 +227,27 @@ public StatementBuilder selectOneById(Object id, CassandraPersistentEntity persistentEntity, CqlIdentifier tableName) { + return this.selectOneById(id, persistentEntity, tableName, null); + } + + /** + * Create an {@literal SELECT} statement by mapping {@code id} to {@literal SELECT … WHERE} considering + * {@link UpdateOptions}. + * + * @param id must not be {@literal null}. + * @param persistentEntity must not be {@literal null}. + * @param tableName must not be {@literal null}. + * @return the select builder. + */ + public StatementBuilder select(Query query, CassandraPersistentEntity Assert.notNull(query, "Query must not be null"); Assert.notNull(persistentEntity, "CassandraPersistentEntity must not be null"); - return select(query, persistentEntity, persistentEntity.getTableName()); + return select(query, persistentEntity, persistentEntity.getTableName(), persistentEntity.getCustomKeyspace()); } /** @@ -248,6 +276,20 @@ public StatementBuilder select(Query query, CassandraPersistentEntity persistentEntity, CqlIdentifier tableName) { + return this.select(query, persistentEntity, tableName, null); + } + + /** + * Create a {@literal SELECT} statement by mapping {@link Query} to {@link Select}. + * + * @param query must not be {@literal null}. + * @param persistentEntity must not be {@literal null}. + * @param tableName must not be {@literal null}. + * @param keyspace - keyspace in which table is located. Might be null, in which case the default keyspace is assumed + * @return the select builder. + * @since 2.1 + */ + public StatementBuilder select(Query query, CassandraPersistentEntity List selectors = getQueryMapper().getMappedSelectors(query.getColumns(), persistentEntity); - return createSelect(query, persistentEntity, filter, selectors, tableName); + return createSelect(query, persistentEntity, filter, selectors, tableName, keyspace); } /** @@ -289,6 +331,21 @@ public StatementBuilder insert(Object objectToInsert, WriteOption */ public StatementBuilder insert(Object objectToInsert, WriteOptions options, CassandraPersistentEntity persistentEntity, CqlIdentifier tableName) { + return this.insert(objectToInsert, options, persistentEntity, tableName, null); + } + + /** + * Creates a Query Object for an insert. + * + * @param tableName the table name, must not be empty and not {@literal null}. + * @param objectToInsert the object to save, must not be {@literal null}. + * @param options optional {@link WriteOptions} to apply to the {@link Insert} statement, may be {@literal null}. + * @param persistentEntity the {@link CassandraPersistentEntity} to write insert values. + * @param keyspace where the table is located. Might be null in which case the defualt keyspace assumed + * @return the select builder. + */ + public StatementBuilder insert(Object objectToInsert, WriteOptions options, + CassandraPersistentEntity persistentEntity, CqlIdentifier tableName, @Nullable CqlIdentifier keyspace) { Assert.notNull(tableName, "TableName must not be null"); Assert.notNull(objectToInsert, "Object to insert must not be null"); @@ -306,12 +363,12 @@ public StatementBuilder insert(Object objectToInsert, WriteOption cassandraConverter.write(objectToInsert, object, persistentEntity); StatementBuilder builder = StatementBuilder - .of(QueryBuilder.insertInto(tableName).valuesByIds(Collections.emptyMap())).bind((statement, factory) -> { + .of(QueryBuilder.insertInto(keyspace, tableName).valuesByIds(Collections.emptyMap())).bind((statement, factory) -> { - Map values = createTerms(insertNulls, object, factory); + Map values = createTerms(insertNulls, object, factory); - return statement.valuesByIds(values); - }).apply(statement -> (RegularInsert) addWriteOptions(statement, options)); + return statement.valuesByIds(values); + }).apply(statement -> (RegularInsert) addWriteOptions(statement, options)); builder.transform(statement -> QueryOptionsUtil.addQueryOptions(statement, options)); @@ -460,13 +517,27 @@ public StatementBuilder */ public StatementBuilder deleteById(Object id, CassandraPersistentEntity persistentEntity, CqlIdentifier tableName) { + return this.deleteById(id, persistentEntity, tableName, null); + } + + /** + * Create an {@literal DELETE} statement by mapping {@code id} to {@literal SELECT … WHERE} considering + * {@link UpdateOptions}. + * + * @param id must not be {@literal null}. + * @param persistentEntity must not be {@literal null}. + * @param tableName must not be {@literal null}. + * @return the delete builder. + */ + public StatementBuilder deleteById(Object id, CassandraPersistentEntity persistentEntity, + CqlIdentifier tableName, @Nullable CqlIdentifier keyspace) { Where where = new Where(); cassandraConverter.write(id, where, persistentEntity); - return StatementBuilder.of(QueryBuilder.deleteFrom(tableName).where()) - .bind((statement, factory) -> statement.where(toRelations(where, factory))); + return StatementBuilder.of(QueryBuilder.deleteFrom(keyspace, tableName).where()) + .bind((statement, factory) -> statement.where(toRelations(where, factory))); } /** @@ -495,6 +566,10 @@ public StatementBuilder delete(Query query, CassandraPersistentEntity */ public StatementBuilder delete(Query query, CassandraPersistentEntity persistentEntity, CqlIdentifier tableName) { + return this.delete(query, persistentEntity, tableName, null); + } + + public StatementBuilder delete(Query query, CassandraPersistentEntity persistentEntity, CqlIdentifier tableName, @Nullable CqlIdentifier keyspace) { Assert.notNull(query, "Query must not be null"); Assert.notNull(persistentEntity, "CassandraPersistentEntity must not be null"); @@ -506,18 +581,19 @@ public StatementBuilder delete(Query query, CassandraPersistentEntity StatementBuilder builder = delete(columnNames, tableName, filter); query.getQueryOptions().filter(DeleteOptions.class::isInstance).map(DeleteOptions.class::cast) - .map(DeleteOptions::getIfCondition) - .ifPresent(criteriaDefinitions -> applyDeleteIfCondition(builder, criteriaDefinitions)); + .map(DeleteOptions::getIfCondition) + .ifPresent(criteriaDefinitions -> applyDeleteIfCondition(builder, criteriaDefinitions)); query.getQueryOptions().filter(WriteOptions.class::isInstance).map(WriteOptions.class::cast) - .ifPresent(writeOptions -> builder.apply(statement -> addWriteOptions(statement, writeOptions))); + .ifPresent(writeOptions -> builder.apply(statement -> addWriteOptions(statement, writeOptions))); query.getQueryOptions() - .ifPresent(options -> builder.transform(statement -> QueryOptionsUtil.addQueryOptions(statement, options))); + .ifPresent(options -> builder.transform(statement -> QueryOptionsUtil.addQueryOptions(statement, options))); return builder; } + /** * Create an {@literal DELETE} statement by mapping {@code entity} to {@link Delete DELETE … WHERE} considering * {@link WriteOptions}. @@ -530,6 +606,11 @@ public StatementBuilder delete(Query query, CassandraPersistentEntity */ public StatementBuilder delete(Object entity, QueryOptions options, EntityWriter entityWriter, CqlIdentifier tableName) { + return this.delete(entity, options, entityWriter, tableName, null); + } + + public StatementBuilder delete(Object entity, QueryOptions options, EntityWriter entityWriter, + CqlIdentifier tableName, @Nullable CqlIdentifier keyspace) { Assert.notNull(tableName, "TableName must not be null"); Assert.notNull(entity, "Object to builder must not be null"); @@ -538,15 +619,15 @@ public StatementBuilder delete(Object entity, QueryOptions options, Enti Where where = new Where(); entityWriter.write(entity, where); - StatementBuilder builder = StatementBuilder.of(QueryBuilder.deleteFrom(tableName).where()) - .bind((statement, factory) -> statement.where(toRelations(where, factory))); + StatementBuilder builder = StatementBuilder.of(QueryBuilder.deleteFrom(keyspace, tableName).where()) + .bind((statement, factory) -> statement.where(toRelations(where, factory))); Optional.of(options).filter(WriteOptions.class::isInstance).map(WriteOptions.class::cast) - .ifPresent(it -> builder.apply(statement -> addWriteOptions(statement, it))); + .ifPresent(it -> builder.apply(statement -> addWriteOptions(statement, it))); Optional.of(options).filter(DeleteOptions.class::isInstance).map(DeleteOptions.class::cast) - .map(DeleteOptions::getIfCondition) - .ifPresent(criteriaDefinitions -> applyDeleteIfCondition(builder, criteriaDefinitions)); + .map(DeleteOptions::getIfCondition) + .ifPresent(criteriaDefinitions -> applyDeleteIfCondition(builder, criteriaDefinitions)); builder.transform(statement -> QueryOptionsUtil.addQueryOptions(statement, options)); @@ -608,12 +689,13 @@ Columns computeColumnsForProjection(EntityProjection projection, Columns c } private StatementBuilder select = createSelectAndOrder(selectors, tableName, filter, sort); + StatementBuilder createSelect(Query query, CassandraPersistentEn return select; } - private static StatementBuilder createSelectAndOrder(List selectors, CqlIdentifier from, Filter filter, Sort sort, @Nullable CqlIdentifier keyspace) { Select select; if (selectors.isEmpty()) { - select = QueryBuilder.selectFrom(from).all(); + select = QueryBuilder.selectFrom(keyspace, from).all(); } else { - - List mappedSelectors = new ArrayList<>( - selectors.size()); + List mappedSelectors = new ArrayList<>(selectors.size()); for (Selector selector : selectors) { com.datastax.oss.driver.api.querybuilder.select.Selector orElseGet = selector.getAlias() - .map(it -> getSelection(selector).as(it)).orElseGet(() -> getSelection(selector)); + .map(it -> getSelection(selector).as(it)) + .orElseGet(() -> getSelection(selector)); mappedSelectors.add(orElseGet); } - select = QueryBuilder.selectFrom(from).selectors(mappedSelectors); + select = QueryBuilder.selectFrom(keyspace, from).selectors(mappedSelectors); } StatementBuilder createSelectAndOrder(List sele Select statementToUse = statement; for (Sort.Order order : sort) { - statementToUse = statementToUse.orderBy(order.getProperty(), - order.isAscending() ? ClusteringOrder.ASC : ClusteringOrder.DESC); + statementToUse = statementToUse.orderBy(order.getProperty(), order.isAscending() ? ClusteringOrder.ASC : ClusteringOrder.DESC); } return statementToUse; @@ -801,14 +880,13 @@ private static Assignment getAssignment(IncrOp incrOp, TermFactory termFactory) private static Assignment getAssignment(SetOp updateOp, TermFactory termFactory) { - if (updateOp instanceof SetAtIndexOp) { + if (updateOp instanceof SetAtIndexOp setAtIndexOp) { return Assignment.setListValue(updateOp.toCqlIdentifier(), - termFactory.create(((SetAtIndexOp) updateOp).getIndex()), termFactory.create(updateOp.getValue())); + termFactory.create(setAtIndexOp.getIndex()), termFactory.create(updateOp.getValue())); } - if (updateOp instanceof SetAtKeyOp) { - SetAtKeyOp op = (SetAtKeyOp) updateOp; + if (updateOp instanceof SetAtKeyOp op) { return Assignment.setMapValue(op.toCqlIdentifier(), termFactory.create(op.getKey()), termFactory.create(op.getValue())); } @@ -1126,36 +1204,22 @@ public void appendTo(@NonNull StringBuilder builder) { } } - private static class RemoveCollectionElementsAssignment implements Assignment { - - private final CqlIdentifier columnId; - private final Term value; - - protected RemoveCollectionElementsAssignment(CqlIdentifier columnId, Term value) { - this.columnId = columnId; - this.value = value; - } - - @Override - public void appendTo(StringBuilder builder) { - builder.append(String.format("%1$s=%1$s-%2$s", columnId.asCql(true), buildRightOperand())); - } - - private String buildRightOperand() { - StringBuilder builder = new StringBuilder(); - value.appendTo(builder); - return builder.toString(); - } + private record RemoveCollectionElementsAssignment(CqlIdentifier columnId, Term value) implements Assignment { - @Override - public boolean isIdempotent() { - return value.isIdempotent(); - } + @Override + public void appendTo(StringBuilder builder) { + builder.append(String.format("%1$s=%1$s-%2$s", columnId.asCql(true), buildRightOperand())); + } - public Term getValue() { - return value; - } + private String buildRightOperand() { + StringBuilder builder = new StringBuilder(); + value.appendTo(builder); + return builder.toString(); + } + @Override + public boolean isIdempotent() { + return value.isIdempotent(); + } } - } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/CassandraExceptionTranslator.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/CassandraExceptionTranslator.java index b0fe6caab..6b30993cc 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/CassandraExceptionTranslator.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/CassandraExceptionTranslator.java @@ -71,7 +71,6 @@ * @author Matthew T. Adams * @author Mark Paluch */ -@SuppressWarnings("unchecked") public class CassandraExceptionTranslator implements CqlExceptionTranslator { private static final Set CONNECTION_FAILURE_TYPES = new HashSet<>( @@ -101,37 +100,33 @@ public DataAccessException translate(@Nullable String task, @Nullable String cql // superclass would match before the subclass! if (exception instanceof AuthenticationException) { - return new CassandraAuthenticationException(((AuthenticationException) exception).getEndPoint(), message, - exception); + return new CassandraAuthenticationException(((AuthenticationException) exception).getEndPoint(), message, exception); } if (exception instanceof ReadTimeoutException) { return new CassandraReadTimeoutException(((ReadTimeoutException) exception).wasDataPresent(), message, exception); } - if (exception instanceof WriteTimeoutException) { + if (exception instanceof WriteTimeoutException writeTimeoutException) { - WriteType writeType = ((WriteTimeoutException) exception).getWriteType(); - return new CassandraWriteTimeoutException(writeType == null ? null : writeType.name(), message, exception); + WriteType writeType = writeTimeoutException.getWriteType(); + return new CassandraWriteTimeoutException(writeType.name(), message, exception); } if (exception instanceof TruncateException) { return new CassandraTruncateException(message, exception); } - if (exception instanceof UnavailableException) { - - UnavailableException ux = (UnavailableException) exception; - return new CassandraInsufficientReplicasAvailableException(ux.getRequired(), ux.getAlive(), message, exception); + if (exception instanceof UnavailableException unavailableException) { + return new CassandraInsufficientReplicasAvailableException(unavailableException.getRequired(), unavailableException.getAlive(), message, exception); } if (exception instanceof OverloadedException || exception instanceof BootstrappingException) { return new TransientDataAccessResourceException(message, exception); } - if (exception instanceof AlreadyExistsException) { - AlreadyExistsException aex = (AlreadyExistsException) exception; - return new CassandraSchemaElementExistsException(aex.getMessage(), aex); + if (exception instanceof AlreadyExistsException alreadyExistsException) { + return new CassandraSchemaElementExistsException(alreadyExistsException.getMessage(), alreadyExistsException); } if (exception instanceof InvalidConfigurationInQueryException) { @@ -150,9 +145,8 @@ public DataAccessException translate(@Nullable String task, @Nullable String cql return new CassandraUnauthorizedException(message, exception); } - if (exception instanceof AllNodesFailedException) { - return new CassandraConnectionFailureException(((AllNodesFailedException) exception).getErrors(), message, - exception); + if (exception instanceof AllNodesFailedException allNodesFailedException) { + return new CassandraConnectionFailureException(message, allNodesFailedException.getAllErrors(), exception); } String exceptionType = ClassUtils.getShortName(ClassUtils.getUserClass(exception.getClass())); @@ -161,8 +155,7 @@ public DataAccessException translate(@Nullable String task, @Nullable String cql Map errorMap = Collections.emptyMap(); - if (exception instanceof CoordinatorException) { - CoordinatorException cx = (CoordinatorException) exception; + if (exception instanceof CoordinatorException cx) { errorMap = Collections.singletonMap(cx.getCoordinator(), exception); } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/legacy/AsyncCassandraTemplate.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/legacy/AsyncCassandraTemplate.java index 8ac7a29b3..dd88f2715 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/legacy/AsyncCassandraTemplate.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/legacy/AsyncCassandraTemplate.java @@ -881,14 +881,13 @@ private int getEffectivePageSize(Statement statement) { return statement.getPageSize(); } - if (getAsyncCqlOperations() instanceof CassandraAccessor) { + if (getAsyncCqlOperations() instanceof CassandraAccessor cassandraAccessor) { - CassandraAccessor accessor = (CassandraAccessor) getAsyncCqlOperations(); - - if (accessor.getFetchSize() != -1) { - return accessor.getFetchSize(); + if (cassandraAccessor.getPageSize() != -1) { + return cassandraAccessor.getPageSize(); } } + class GetConfiguredPageSize implements AsyncSessionCallback, CqlProvider { @Override public ListenableFuture doInSession(CqlSession session) { @@ -904,7 +903,6 @@ public String getCql() { return getAsyncCqlOperations().execute(new GetConfiguredPageSize()).completable().join(); } - @SuppressWarnings("unchecked") private Function getMapper(Class entityType, Class targetType, CqlIdentifier tableName) { EntityProjection projection = entityOperations.introspectProjection(targetType, entityType); diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/BasicCassandraPersistentEntity.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/BasicCassandraPersistentEntity.java index 9a91cc0c2..d39133f3a 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/BasicCassandraPersistentEntity.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/BasicCassandraPersistentEntity.java @@ -34,6 +34,7 @@ import org.springframework.expression.spel.support.StandardEvaluationContext; import org.springframework.lang.Nullable; import org.springframework.util.Assert; +import org.springframework.util.StringUtils; import com.datastax.oss.driver.api.core.CqlIdentifier; @@ -50,14 +51,16 @@ public class BasicCassandraPersistentEntity extends BasicPersistentEntity (String) AnnotationUtils.getValue(it, "keyspace")) + .orElse(null); + return (keyspaceName = (StringUtils.hasText(keyspace) ? CqlIdentifierGenerator.createIdentifier(keyspace, this.forceQuote) : null)); + } + @Override public void addAssociation(Association association) { throw new UnsupportedCassandraOperationException("Cassandra does not support associations"); @@ -181,7 +192,7 @@ public void setTableName(CqlIdentifier tableName) { * @since 3.0 */ public void setNamingStrategy(NamingStrategy namingStrategy) { - this.namingAccessor.setNamingStrategy(namingStrategy); + this.cqlIdentifierGenerator.setNamingStrategy(namingStrategy); } @Override @@ -189,6 +200,11 @@ public CqlIdentifier getTableName() { return Optional.ofNullable(this.tableName).orElseGet(this::determineTableName); } + @Override + public CqlIdentifier getCustomKeyspace() { + return Optional.ofNullable(this.keyspaceName).orElseGet(this::determineKeyspaceName); + } + /** * @param verifier The verifier to set. */ diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/CassandraMappingContext.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/CassandraMappingContext.java index 441e66d28..d6af5b296 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/CassandraMappingContext.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/CassandraMappingContext.java @@ -355,6 +355,8 @@ protected boolean shouldCreatePersistentEntityFor(TypeInformation typeInfo) { @Override protected BasicCassandraPersistentEntity createPersistentEntity(TypeInformation typeInformation) { + + BasicCassandraPersistentEntity entity = isUserDefinedType(typeInformation) ? new CassandraUserTypePersistentEntity<>(typeInformation, getVerifier()) : isTuple(typeInformation) ? new BasicCassandraPersistentTupleEntity<>(typeInformation) @@ -363,6 +365,7 @@ protected BasicCassandraPersistentEntity createPersistentEntity(TypeInfor if (this.namingStrategy != null) { entity.setNamingStrategy(this.namingStrategy); } + Optional.ofNullable(this.applicationContext).ifPresent(entity::setApplicationContext); return entity; diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/CassandraPersistentEntity.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/CassandraPersistentEntity.java index 7bd6b280d..613aecdb7 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/CassandraPersistentEntity.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/CassandraPersistentEntity.java @@ -16,6 +16,7 @@ package org.springframework.data.cassandra.core.mapping; import org.springframework.data.mapping.PersistentEntity; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import com.datastax.oss.driver.api.core.CqlIdentifier; @@ -50,6 +51,12 @@ public interface CassandraPersistentEntity extends PersistentEntity verifiers; + private final Collection verifiers; /** * Create a new {@link CompositeCassandraPersistentEntityMetadataVerifier} using default entity and primary key diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/EmbeddedEntityOperations.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/EmbeddedEntityOperations.java index d21c6a4b6..ac0d6fc5b 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/EmbeddedEntityOperations.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/EmbeddedEntityOperations.java @@ -114,9 +114,8 @@ public CqlIdentifier getTableName() { } @Override - @Deprecated - public void setTableName(org.springframework.data.cassandra.core.cql.CqlIdentifier tableName) { - delegate.setTableName(tableName); + public CqlIdentifier getCustomKeyspace() { + return this.delegate.getCustomKeyspace(); } @Override diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/Table.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/Table.java index d1283e821..9421ce629 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/Table.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/mapping/Table.java @@ -51,4 +51,9 @@ */ @Deprecated boolean forceQuote() default false; + + /** + * Keyspace where this table is located + */ + String keyspace() default ""; } diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/AsyncCqlTemplateUnitTests.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/AsyncCqlTemplateUnitTests.java index 98aad8043..f66102287 100644 --- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/AsyncCqlTemplateUnitTests.java +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/AsyncCqlTemplateUnitTests.java @@ -797,7 +797,7 @@ private void doTestStrings(@Nullable Integer fetchSize, @Nullable ConsistencyLev template.setSession(this.session); if (fetchSize != null) { - template.setFetchSize(fetchSize); + template.setPageSize(fetchSize); } if (consistencyLevel != null) { diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/CqlTemplateUnitTests.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/CqlTemplateUnitTests.java index cbdc35874..1c8fea831 100644 --- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/CqlTemplateUnitTests.java +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/CqlTemplateUnitTests.java @@ -770,7 +770,7 @@ private void doTestStrings(@Nullable Integer fetchSize, @Nullable ConsistencyLev template.setSession(this.session); if (fetchSize != null) { - template.setFetchSize(fetchSize); + template.setPageSize(fetchSize); } if (consistencyLevel != null) { diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/legacy/AsyncCqlTemplateUnitTests.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/legacy/AsyncCqlTemplateUnitTests.java index 2dc79f766..37594304f 100644 --- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/legacy/AsyncCqlTemplateUnitTests.java +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/legacy/AsyncCqlTemplateUnitTests.java @@ -794,7 +794,7 @@ private void doTestStrings(@Nullable Integer fetchSize, @Nullable ConsistencyLev template.setSession(this.session); if (fetchSize != null) { - template.setFetchSize(fetchSize); + template.setPageSize(fetchSize); } if (consistencyLevel != null) { diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/mapping/BasicCassandraPersistentEntityUnitTests.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/mapping/BasicCassandraPersistentEntityUnitTests.java index 12ac991c8..26114da27 100755 --- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/mapping/BasicCassandraPersistentEntityUnitTests.java +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/mapping/BasicCassandraPersistentEntityUnitTests.java @@ -89,14 +89,13 @@ void tableAllowsReferencingSpringBean() { @Test void setForceQuoteCallsSetTableName() { - BasicCassandraPersistentEntity entitySpy = spy( - new BasicCassandraPersistentEntity<>(TypeInformation.of(Message.class))); + BasicCassandraPersistentEntity entitySpy = spy(new BasicCassandraPersistentEntity<>(TypeInformation.of(Message.class))); DirectFieldAccessor directFieldAccessor = new DirectFieldAccessor(entitySpy); entitySpy.setTableName(CqlIdentifier.fromCql("Messages")); - assertThat(directFieldAccessor.getPropertyValue("forceQuote")).isNull(); + assertThat((Boolean) directFieldAccessor.getPropertyValue("forceQuote")).isFalse(); entitySpy.setForceQuote(true); diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/domain/EntityWithKeyspace.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/domain/EntityWithKeyspace.java new file mode 100644 index 000000000..b569ff7f3 --- /dev/null +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/domain/EntityWithKeyspace.java @@ -0,0 +1,11 @@ +package org.springframework.data.cassandra.domain; + +import org.springframework.data.annotation.Id; +import org.springframework.data.cassandra.core.mapping.Table; + +@Table(value = "entity_with_keyspace", keyspace = "custom") +public record EntityWithKeyspace( + @Id String id, + String name, + String type +){} \ No newline at end of file diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/repository/query/PartTreeCassandraQueryUnitTests.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/repository/query/PartTreeCassandraQueryUnitTests.java index ad4c03be4..773cde93b 100644 --- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/repository/query/PartTreeCassandraQueryUnitTests.java +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/repository/query/PartTreeCassandraQueryUnitTests.java @@ -23,6 +23,7 @@ import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.Optional; import java.util.stream.Collectors; import org.junit.jupiter.api.BeforeEach; @@ -39,9 +40,11 @@ import org.springframework.data.cassandra.core.mapping.CassandraMappingContext; import org.springframework.data.cassandra.core.mapping.UserTypeResolver; import org.springframework.data.cassandra.domain.AddressType; +import org.springframework.data.cassandra.domain.EntityWithKeyspace; import org.springframework.data.cassandra.domain.Group; import org.springframework.data.cassandra.domain.Person; import org.springframework.data.cassandra.repository.AllowFiltering; +import org.springframework.data.cassandra.repository.CassandraRepository; import org.springframework.data.cassandra.repository.Consistency; import org.springframework.data.cassandra.repository.MapIdCassandraRepository; import org.springframework.data.cassandra.repository.Query; @@ -225,6 +228,13 @@ void shouldApplyConsistencyLevel() { assertThat(statement.getConsistencyLevel()).isEqualTo(DefaultConsistencyLevel.LOCAL_ONE); } + @Test + void shouldCreateSelectQueryWithKeyspaceApplied() { + String query = deriveQueryFromMethod("findByName", EntityWithKeyspaceRepository.class, "Mark"); + + assertThat(query).isEqualTo("SELECT * FROM custom.entity_with_keyspace WHERE name='Mark'"); + } + @Test // DATACASS-512 void shouldCreateCountQuery() { @@ -251,6 +261,10 @@ void shouldCreateExistsQuery() { } private String deriveQueryFromMethod(String method, Object... args) { + return this.deriveQueryFromMethod(method, Repo.class, args); + } + + private String deriveQueryFromMethod(String method, Class> cassandraRepositoryClass, Object... args) { Class[] types = new Class[args.length]; @@ -258,21 +272,22 @@ private String deriveQueryFromMethod(String method, Object... args) { types[i] = ClassUtils.getUserClass(args[i].getClass()); } - SimpleStatement statement = deriveQueryFromMethod(Repo.class, method, types, args); + SimpleStatement statement = deriveQueryFromMethod(cassandraRepositoryClass, method, types, args); String query = statement.getQuery(); List positionalValues = statement.getPositionalValues(); for (Object positionalValue : positionalValues) { query = query.replaceFirst("\\?", - positionalValue != null - ? CodecRegistry.DEFAULT.codecFor((Class) positionalValue.getClass()).format(positionalValue) - : "null"); + positionalValue != null + ? CodecRegistry.DEFAULT.codecFor((Class) positionalValue.getClass()).format(positionalValue) + : "null"); } return query; } + private SimpleStatement deriveQueryFromMethod(Class repositoryInterface, String method, Class[] types, Object... args) { @@ -308,6 +323,11 @@ interface GroupRepository extends MapIdCassandraRepository { Group findByIdHashPrefix(String hashPrefix); } + interface EntityWithKeyspaceRepository extends CassandraRepository { + + Optional findByName(String name); + } + @SuppressWarnings("unused") interface Repo extends MapIdCassandraRepository { diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/repository/support/SimpleCassandraRepositoryIntegrationTests.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/repository/support/SimpleCassandraRepositoryIntegrationTests.java index 9126f29de..3a1f79c42 100644 --- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/repository/support/SimpleCassandraRepositoryIntegrationTests.java +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/repository/support/SimpleCassandraRepositoryIntegrationTests.java @@ -28,6 +28,7 @@ import java.util.stream.Collectors; import java.util.stream.IntStream; +import org.assertj.core.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.beans.BeansException; @@ -37,12 +38,14 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.data.cassandra.config.CqlSessionFactoryBean; import org.springframework.data.cassandra.core.CassandraOperations; import org.springframework.data.cassandra.core.mapping.event.AbstractCassandraEventListener; import org.springframework.data.cassandra.core.mapping.event.AfterSaveEvent; import org.springframework.data.cassandra.core.mapping.event.BeforeSaveEvent; import org.springframework.data.cassandra.core.mapping.event.CassandraMappingEvent; import org.springframework.data.cassandra.core.query.CassandraPageRequest; +import org.springframework.data.cassandra.domain.EntityWithKeyspace; import org.springframework.data.cassandra.domain.User; import org.springframework.data.cassandra.domain.UserToken; import org.springframework.data.cassandra.repository.CassandraRepository; @@ -56,7 +59,14 @@ import org.springframework.test.context.junit.jupiter.SpringJUnitConfig; import org.springframework.util.ClassUtils; +import com.datastax.driver.core.querybuilder.QueryBuilder; +import com.datastax.driver.core.querybuilder.Select; +import com.datastax.driver.core.schemabuilder.Create; import com.datastax.oss.driver.api.core.CqlSession; +import com.datastax.oss.driver.api.core.cql.SimpleStatement; +import com.datastax.oss.driver.api.core.cql.Statement; +import com.datastax.oss.driver.api.core.cql.StatementBuilder; +import com.datastax.oss.protocol.internal.request.Query; /** * Integration tests for {@link SimpleCassandraRepository}. @@ -92,8 +102,9 @@ CaptureEventListener eventListener() { private BeanFactory beanFactory; private CassandraRepositoryFactory factory; private ClassLoader classLoader; - private UserRepostitory repository; + private UserRepository userRepository; + private EntityWithKeyspaceRepostitory entityWithKeyspaceRepostitory; private User dave, oliver, carter, boyd; @Override @@ -115,26 +126,38 @@ void setUp() { factory.setBeanFactory(beanFactory); factory.setEvaluationContextProvider(ExtensionAwareQueryMethodEvaluationContextProvider.DEFAULT); - repository = factory.getRepository(UserRepostitory.class); + userRepository = factory.getRepository(UserRepository.class); + entityWithKeyspaceRepostitory = factory.getRepository(EntityWithKeyspaceRepostitory.class); cassandraVersion = CassandraVersion.get(session); - repository.deleteAll(); + userRepository.deleteAll(); dave = new User("42", "Dave", "Matthews"); oliver = new User("4", "Oliver August", "Matthews"); carter = new User("49", "Carter", "Beauford"); boyd = new User("45", "Boyd", "Tinsley"); - repository.saveAll(Arrays.asList(oliver, dave, carter, boyd)); + userRepository.saveAll(Arrays.asList(oliver, dave, carter, boyd)); eventListener.clear(); } + @Test + void whenInsertingEntityWithKeyspaceSpecified_thenAppliedQueryWithKeyspace() { + session.execute("CREATE KEYSPACE custom WITH REPLICATION = { 'class' : 'SimpleStrategy', 'replication_factor' : 1 }"); + session.execute("CREATE TABLE custom.entity_with_keyspace (id TEXT, name TEXT, type TEXT, PRIMARY KEY ((id)) )"); + EntityWithKeyspace entityWithKeyspace = new EntityWithKeyspace("12", "Artur", "COMMON"); + entityWithKeyspaceRepostitory.save(entityWithKeyspace); + Optional foundEntity = entityWithKeyspaceRepostitory.findById("12"); + Assertions.assertThat(foundEntity).isPresent(); + Assertions.assertThat(foundEntity.get().type()).isEqualTo("COMMON"); + } + @Test // DATACASS-396 void existsByIdShouldReturnTrueForExistingObject() { - Boolean exists = repository.existsById(dave.getId()); + Boolean exists = userRepository.existsById(dave.getId()); assertThat(exists).isTrue(); } @@ -142,7 +165,7 @@ void existsByIdShouldReturnTrueForExistingObject() { @Test // DATACASS-396 void existsByIdShouldReturnFalseForAbsentObject() { - boolean exists = repository.existsById("unknown"); + boolean exists = userRepository.existsById("unknown"); assertThat(exists).isFalse(); } @@ -150,7 +173,7 @@ void existsByIdShouldReturnFalseForAbsentObject() { @Test // DATACASS-396 void existsByMonoOfIdShouldReturnTrueForExistingObject() { - boolean exists = repository.existsById(dave.getId()); + boolean exists = userRepository.existsById(dave.getId()); assertThat(exists).isTrue(); } @@ -158,7 +181,7 @@ void existsByMonoOfIdShouldReturnTrueForExistingObject() { @Test // DATACASS-396 void findByIdShouldReturnObject() { - Optional User = repository.findById(dave.getId()); + Optional User = userRepository.findById(dave.getId()); assertThat(User).contains(dave); } @@ -166,7 +189,7 @@ void findByIdShouldReturnObject() { @Test // DATACASS-396 void findByIdShouldCompleteWithoutValueForAbsentObject() { - Optional User = repository.findById("unknown"); + Optional User = userRepository.findById("unknown"); assertThat(User).isEmpty(); } @@ -174,7 +197,7 @@ void findByIdShouldCompleteWithoutValueForAbsentObject() { @Test // DATACASS-396, DATACASS-416 void findAllShouldReturnAllResults() { - List Users = repository.findAll(); + List Users = userRepository.findAll(); assertThat(Users).hasSize(4); } @@ -182,7 +205,7 @@ void findAllShouldReturnAllResults() { @Test // DATACASS-396, DATACASS-416 void findAllByIterableOfIdShouldReturnResults() { - List Users = repository.findAllById(Arrays.asList(dave.getId(), boyd.getId())); + List Users = userRepository.findAllById(Arrays.asList(dave.getId(), boyd.getId())); assertThat(Users).hasSize(2); } @@ -190,11 +213,11 @@ void findAllByIterableOfIdShouldReturnResults() { @Test // DATACASS-56 void findAllWithPaging() { - Slice slice = repository.findAll(CassandraPageRequest.first(2)); + Slice slice = userRepository.findAll(CassandraPageRequest.first(2)); assertThat(slice).hasSize(2); - assertThat(repository.findAll(slice.nextPageable())).hasSize(2); + assertThat(userRepository.findAll(slice.nextPageable())).hasSize(2); } @Test // DATACASS-700 @@ -202,7 +225,7 @@ void findAllWithPagingAndSorting() { assumeTrue(cassandraVersion.isGreaterThan(CASSANDRA_3)); - UserTokenRepostitory repository = factory.getRepository(UserTokenRepostitory.class); + UserTokenRepository repository = factory.getRepository(UserTokenRepository.class); repository.deleteAll(); UUID id = UUID.randomUUID(); @@ -232,7 +255,7 @@ void findAllWithPagingAndSorting() { @Test // DATACASS-396 void countShouldReturnNumberOfRecords() { - long count = repository.count(); + long count = userRepository.count(); assertThat(count).isEqualTo(4); } @@ -240,23 +263,23 @@ void countShouldReturnNumberOfRecords() { @Test // DATACASS-415 void insertEntityShouldInsertEntity() { - repository.deleteAll(); + userRepository.deleteAll(); User User = new User("36", "Homer", "Simpson"); - repository.insert(User); + userRepository.insert(User); - assertThat(repository.count()).isEqualTo(1); + assertThat(userRepository.count()).isEqualTo(1); } @Test // DATACASS-415 void insertIterableOfEntitiesShouldInsertEntity() { - repository.deleteAll(); + userRepository.deleteAll(); - repository.insert(Arrays.asList(dave, oliver, boyd)); + userRepository.insert(Arrays.asList(dave, oliver, boyd)); - assertThat(repository.count()).isEqualTo(3); + assertThat(userRepository.count()).isEqualTo(3); } @Test // DATACASS-396, DATACASS-573 @@ -265,11 +288,11 @@ void saveEntityShouldUpdateExistingEntity() { dave.setFirstname("Hello, Dave"); dave.setLastname("Bowman"); - User saved = repository.save(dave); + User saved = userRepository.save(dave); assertThat(saved).isSameAs(saved); - Optional loaded = repository.findById(dave.getId()); + Optional loaded = userRepository.findById(dave.getId()); assertThat(loaded).isPresent(); @@ -285,7 +308,7 @@ void saveShouldEmitEvents() { dave.setFirstname("Hello, Dave"); dave.setLastname("Bowman"); - repository.save(dave); + userRepository.save(dave); assertThat(eventListener.getBeforeSave()).hasSize(1); assertThat(eventListener.getAfterSave()).hasSize(1); @@ -296,11 +319,11 @@ void saveEntityShouldInsertNewEntity() { User User = new User("36", "Homer", "Simpson"); - User saved = repository.save(User); + User saved = userRepository.save(User); assertThat(saved).isEqualTo(User); - Optional loaded = repository.findById(User.getId()); + Optional loaded = userRepository.findById(User.getId()); assertThat(loaded).contains(User); } @@ -308,13 +331,13 @@ void saveEntityShouldInsertNewEntity() { @Test // DATACASS-396, DATACASS-416, DATACASS-573 void saveIterableOfNewEntitiesShouldInsertEntity() { - repository.deleteAll(); + userRepository.deleteAll(); - List saved = repository.saveAll(Arrays.asList(dave, oliver, boyd)); + List saved = userRepository.saveAll(Arrays.asList(dave, oliver, boyd)); assertThat(saved).hasSize(3).contains(dave, oliver, boyd); - assertThat(repository.count()).isEqualTo(3); + assertThat(userRepository.count()).isEqualTo(3); } @Test // DATACASS-396, DATACASS-416 @@ -325,23 +348,23 @@ void saveIterableOfMixedEntitiesShouldInsertEntity() { dave.setFirstname("Hello, Dave"); dave.setLastname("Bowman"); - List saved = repository.saveAll(Arrays.asList(User, dave)); + List saved = userRepository.saveAll(Arrays.asList(User, dave)); assertThat(saved).hasSize(2); - Optional persistentDave = repository.findById(dave.getId()); + Optional persistentDave = userRepository.findById(dave.getId()); assertThat(persistentDave).contains(dave); - Optional persistentHomer = repository.findById(User.getId()); + Optional persistentHomer = userRepository.findById(User.getId()); assertThat(persistentHomer).contains(User); } @Test // DATACASS-396, DATACASS-416 void deleteAllShouldRemoveEntities() { - repository.deleteAll(); + userRepository.deleteAll(); - List result = repository.findAll(); + List result = userRepository.findAll(); assertThat(result).isEmpty(); } @@ -349,9 +372,9 @@ void deleteAllShouldRemoveEntities() { @Test // DATACASS-396 void deleteByIdShouldRemoveEntity() { - repository.deleteById(dave.getId()); + userRepository.deleteById(dave.getId()); - Optional loaded = repository.findById(dave.getId()); + Optional loaded = userRepository.findById(dave.getId()); assertThat(loaded).isEmpty(); } @@ -359,9 +382,9 @@ void deleteByIdShouldRemoveEntity() { @Test // DATACASS-825 void deleteAllByIdShouldRemoveEntity() { - repository.deleteAllById(Collections.singletonList(dave.getId())); + userRepository.deleteAllById(Collections.singletonList(dave.getId())); - Optional loaded = repository.findById(dave.getId()); + Optional loaded = userRepository.findById(dave.getId()); assertThat(loaded).isEmpty(); } @@ -369,9 +392,9 @@ void deleteAllByIdShouldRemoveEntity() { @Test // DATACASS-396 void deleteShouldRemoveEntity() { - repository.delete(dave); + userRepository.delete(dave); - Optional loaded = repository.findById(dave.getId()); + Optional loaded = userRepository.findById(dave.getId()); assertThat(loaded).isEmpty(); } @@ -379,16 +402,18 @@ void deleteShouldRemoveEntity() { @Test // DATACASS-396 void deleteIterableOfEntitiesShouldRemoveEntities() { - repository.deleteAll(Arrays.asList(dave, boyd)); + userRepository.deleteAll(Arrays.asList(dave, boyd)); - Optional loaded = repository.findById(boyd.getId()); + Optional loaded = userRepository.findById(boyd.getId()); assertThat(loaded).isEmpty(); } - interface UserRepostitory extends CassandraRepository {} + interface UserRepository extends CassandraRepository {} + + interface EntityWithKeyspaceRepostitory extends CassandraRepository {} - interface UserTokenRepostitory extends CassandraRepository { + interface UserTokenRepository extends CassandraRepository { Slice findAllByUserId(UUID id, Pageable pageRequest); }