diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/AsyncCassandraTemplate.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/AsyncCassandraTemplate.java index ad4acc5b4..25c3ece26 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/AsyncCassandraTemplate.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/AsyncCassandraTemplate.java @@ -15,13 +15,13 @@ */ package org.springframework.data.cassandra.core; -import lombok.Value; - import java.util.List; import java.util.concurrent.ExecutionException; import java.util.function.Consumer; import java.util.function.Function; +import lombok.Value; + import org.springframework.context.ApplicationEvent; import org.springframework.context.ApplicationEventPublisher; import org.springframework.context.ApplicationEventPublisherAware; @@ -324,7 +324,7 @@ public class AsyncCassandraTemplate implements AsyncCassandraOperations, Applica Assert.notNull(query, "Query must not be null"); Assert.notNull(entityClass, "Entity type must not be null"); - return slice(this.statementFactory.select(query, getRequiredPersistentEntity(entityClass)), entityClass); + return slice(getStatementFactory().select(query, getRequiredPersistentEntity(entityClass)), entityClass); } /* (non-Javadoc) @@ -338,8 +338,8 @@ public class AsyncCassandraTemplate implements AsyncCassandraOperations, Applica Assert.notNull(entityConsumer, "Entity Consumer must not be empty"); Assert.notNull(entityClass, "Entity type must not be null"); - return select(getStatementFactory().select(query, getRequiredPersistentEntity(entityClass)), entityConsumer, - entityClass); + return select(getStatementFactory() + .select(query, getRequiredPersistentEntity(entityClass)), entityConsumer, entityClass); } /* (non-Javadoc) @@ -473,13 +473,14 @@ public class AsyncCassandraTemplate implements AsyncCassandraOperations, Applica CassandraPersistentEntity entity = getRequiredPersistentEntity(entityClass); Select select = QueryBuilder.select().all().from(entity.getTableName().toCql()); + getConverter().write(id, select.where(), entity); Function mapper = getMapper(entityClass, entityClass, entity.getTableName()); return new MappingListenableFutureAdapter<>( getAsyncCqlOperations().query(select, (row, rowNum) -> mapper.apply(row)), - it -> it.isEmpty() ? null : (T) it.get(0)); + it -> it.isEmpty() ? null : it.get(0)); } /* (non-Javadoc) @@ -718,8 +719,8 @@ public class AsyncCassandraTemplate implements AsyncCassandraOperations, Applica private void maybeEmitEvent(ApplicationEvent event) { - if (eventPublisher != null) { - eventPublisher.publishEvent(event); + if (this.eventPublisher != null) { + this.eventPublisher.publishEvent(event); } } @@ -747,7 +748,7 @@ public class AsyncCassandraTemplate implements AsyncCassandraOperations, Applica */ @Override protected T adapt(@Nullable S adapteeResult) throws ExecutionException { - return mapper.apply(adapteeResult); + return this.mapper.apply(adapteeResult); } } @@ -766,9 +767,9 @@ public class AsyncCassandraTemplate implements AsyncCassandraOperations, Applica @Override public ListenableFuture doInSession(Session session) throws DriverException, DataAccessException { return new GuavaListenableFutureAdapter<>(session.executeAsync(statement), - e -> (e instanceof DriverException + e -> e instanceof DriverException ? exceptionTranslator.translate("AsyncStatementCallback", getCql(), (DriverException) e) - : exceptionTranslator.translateExceptionIfPossible(e))); + : exceptionTranslator.translateExceptionIfPossible(e)); } /* (non-Javadoc) @@ -776,7 +777,7 @@ public class AsyncCassandraTemplate implements AsyncCassandraOperations, Applica */ @Override public String getCql() { - return statement.toString(); + return this.statement.toString(); } } } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/CassandraBatchTemplate.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/CassandraBatchTemplate.java index f6ac0f810..6f24db0a8 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/CassandraBatchTemplate.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/CassandraBatchTemplate.java @@ -27,8 +27,12 @@ import org.springframework.data.cassandra.core.mapping.CassandraPersistentEntity import org.springframework.util.Assert; import org.springframework.util.ClassUtils; +import com.datastax.driver.core.Statement; import com.datastax.driver.core.querybuilder.Batch; +import com.datastax.driver.core.querybuilder.Delete; +import com.datastax.driver.core.querybuilder.Insert; import com.datastax.driver.core.querybuilder.QueryBuilder; +import com.datastax.driver.core.querybuilder.Update; /** * Default implementation for {@link CassandraBatchOperations}. @@ -40,8 +44,6 @@ import com.datastax.driver.core.querybuilder.QueryBuilder; */ class CassandraBatchTemplate implements CassandraBatchOperations { - private final CassandraOperations operations; - private final AtomicBoolean executed = new AtomicBoolean(); private final Batch batch = QueryBuilder.batch(); @@ -50,6 +52,8 @@ class CassandraBatchTemplate implements CassandraBatchOperations { private final CassandraMappingContext mappingContext; + private final CassandraOperations operations; + private final StatementFactory statementFactory; /** @@ -63,18 +67,51 @@ class CassandraBatchTemplate implements CassandraBatchOperations { this.operations = operations; this.converter = operations.getConverter(); - this.mappingContext = converter.getMappingContext(); + this.mappingContext = this.converter.getMappingContext(); this.statementFactory = new StatementFactory(new UpdateMapper(converter)); } + /** + * Return a reference to the configured {@link CassandraConverter} used to map {@link Object Objects} + * to {@link com.datastax.driver.core.Row Rows}. + * + * @return a reference to the configured {@link CassandraConverter}. + * @see org.springframework.data.cassandra.core.convert.CassandraConverter + */ + protected CassandraConverter getConverter() { + return this.converter; + } + + /** + * Returns a reference to the configured {@link CassandraMappingContext} used to map entities to Cassandra tables + * and back. + * + * @return a reference to the configured {@link CassandraMappingContext}. + * @see org.springframework.data.cassandra.core.mapping.CassandraMappingContext + */ + protected CassandraMappingContext getMappingContext() { + return this.mappingContext; + } + + /** + * Return a reference to the configured {@link StatementFactory} used to create Cassandra {@link Statement} objects + * to perform data access operations on a Cassandra cluster. + * + * @return a reference to the configured {@link StatementFactory}. + * @see org.springframework.data.cassandra.core.StatementFactory + */ + protected StatementFactory getStatementFactory() { + return this.statementFactory; + } + /* (non-Javadoc) * @see org.springframework.data.cassandra.core.CassandraBatchOperations#execute() */ @Override public WriteResult execute() { - if (executed.compareAndSet(false, true)) { - return WriteResult.of(operations.getCqlOperations().queryForResultSet(batch)); + if (this.executed.compareAndSet(false, true)) { + return WriteResult.of(this.operations.getCqlOperations().queryForResultSet(batch)); } throw new IllegalStateException("This Cassandra Batch was already executed"); @@ -88,7 +125,7 @@ class CassandraBatchTemplate implements CassandraBatchOperations { assertNotExecuted(); - batch.using(QueryBuilder.timestamp(timestamp)); + this.batch.using(QueryBuilder.timestamp(timestamp)); return this; } @@ -119,19 +156,23 @@ class CassandraBatchTemplate implements CassandraBatchOperations { public CassandraBatchOperations insert(Iterable entities, WriteOptions options) { assertNotExecuted(); + Assert.notNull(entities, "Entities must not be null"); Assert.notNull(options, "WriteOptions must not be null"); - CassandraMappingContext mappingContext = operations.getConverter().getMappingContext(); + CassandraMappingContext mappingContext = getMappingContext(); for (Object entity : entities) { Assert.notNull(entity, "Entity must not be null"); - BasicCassandraPersistentEntity persistentEntity = mappingContext - .getRequiredPersistentEntity(entity.getClass()); - batch.add(EntityQueryUtils.createInsertQuery(persistentEntity.getTableName().toCql(), entity, options, - operations.getConverter(), persistentEntity)); + BasicCassandraPersistentEntity persistentEntity = + mappingContext.getRequiredPersistentEntity(entity.getClass()); + + Insert insertQuery = EntityQueryUtils.createInsertQuery(persistentEntity.getTableName().toCql(), + entity, options, getConverter(), persistentEntity); + + this.batch.add(insertQuery); } return this; @@ -163,6 +204,7 @@ class CassandraBatchTemplate implements CassandraBatchOperations { public CassandraBatchOperations update(Iterable entities, WriteOptions options) { assertNotExecuted(); + Assert.notNull(entities, "Entities must not be null"); Assert.notNull(options, "WriteOptions must not be null"); @@ -171,8 +213,11 @@ class CassandraBatchTemplate implements CassandraBatchOperations { Assert.notNull(entity, "Entity must not be null"); CassandraPersistentEntity persistentEntity = getRequiredPersistentEntity(entity.getClass()); - batch.add( - statementFactory.update(entity, options, this.converter, persistentEntity, persistentEntity.getTableName())); + + Update update = getStatementFactory() + .update(entity, options, getConverter(), persistentEntity, persistentEntity.getTableName()); + + this.batch.add(update); } return this; @@ -204,6 +249,7 @@ class CassandraBatchTemplate implements CassandraBatchOperations { public CassandraBatchOperations delete(Iterable entities, WriteOptions options) { assertNotExecuted(); + Assert.notNull(entities, "Entities must not be null"); Assert.notNull(options, "WriteOptions must not be null"); @@ -212,18 +258,21 @@ class CassandraBatchTemplate implements CassandraBatchOperations { Assert.notNull(entity, "Entity must not be null"); CassandraPersistentEntity persistentEntity = getRequiredPersistentEntity(entity.getClass()); - batch.add( - statementFactory.delete(entity, options, this.converter, persistentEntity, persistentEntity.getTableName())); + + Delete delete = getStatementFactory() + .delete(entity, options, this.converter, persistentEntity, persistentEntity.getTableName()); + + this.batch.add(delete); } return this; } private void assertNotExecuted() { - Assert.state(!executed.get(), "This Cassandra Batch was already executed"); + Assert.state(!this.executed.get(), "This Cassandra Batch was already executed"); } private CassandraPersistentEntity getRequiredPersistentEntity(Class entityType) { - return this.mappingContext.getRequiredPersistentEntity(ClassUtils.getUserClass(entityType)); + return getMappingContext().getRequiredPersistentEntity(ClassUtils.getUserClass(entityType)); } } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/DeleteOptions.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/DeleteOptions.java index 2fb7921f6..339dd619f 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/DeleteOptions.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/DeleteOptions.java @@ -15,12 +15,12 @@ */ package org.springframework.data.cassandra.core; -import lombok.EqualsAndHashCode; - import java.time.Duration; import java.time.Instant; import java.util.concurrent.TimeUnit; +import lombok.EqualsAndHashCode; + import org.springframework.data.cassandra.core.cql.WriteOptions; import org.springframework.data.cassandra.core.query.CriteriaDefinition; import org.springframework.data.cassandra.core.query.Filter; @@ -298,8 +298,9 @@ public class DeleteOptions extends WriteOptions { * @return a new {@link DeleteOptions} with the configured values */ public DeleteOptions build() { - return new DeleteOptions(this.consistencyLevel, this.retryPolicy, this.tracing, this.fetchSize, this.readTimeout, - this.ttl, this.timestamp, this.ifExists, this.ifCondition); + + return new DeleteOptions(this.consistencyLevel, this.retryPolicy, this.tracing, this.fetchSize, + this.readTimeout, this.ttl, this.timestamp, this.ifExists, this.ifCondition); } } } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/ReactiveCassandraBatchTemplate.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/ReactiveCassandraBatchTemplate.java index 45e07744f..c9f1e3b82 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/ReactiveCassandraBatchTemplate.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/ReactiveCassandraBatchTemplate.java @@ -15,9 +15,6 @@ */ package org.springframework.data.cassandra.core; -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; - import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -26,6 +23,9 @@ import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Function; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + import org.springframework.data.cassandra.core.convert.CassandraConverter; import org.springframework.data.cassandra.core.convert.UpdateMapper; import org.springframework.data.cassandra.core.cql.WriteOptions; @@ -35,6 +35,7 @@ import org.springframework.data.cassandra.core.mapping.CassandraPersistentEntity import org.springframework.util.Assert; import org.springframework.util.ClassUtils; +import com.datastax.driver.core.Statement; import com.datastax.driver.core.querybuilder.Batch; import com.datastax.driver.core.querybuilder.BuiltStatement; import com.datastax.driver.core.querybuilder.Delete; @@ -51,8 +52,6 @@ import com.datastax.driver.core.querybuilder.Update; */ class ReactiveCassandraBatchTemplate implements ReactiveCassandraBatchOperations { - private final ReactiveCassandraOperations operations; - private final AtomicBoolean executed = new AtomicBoolean(); private final Batch batch = QueryBuilder.batch(); @@ -61,10 +60,12 @@ class ReactiveCassandraBatchTemplate implements ReactiveCassandraBatchOperations private final CassandraMappingContext mappingContext; - private final StatementFactory statementFactory; - private final List>> batchMonos = new CopyOnWriteArrayList<>(); + private final ReactiveCassandraOperations operations; + + private final StatementFactory statementFactory; + /** * Create a new {@link CassandraBatchTemplate} given {@link CassandraOperations}. * @@ -76,8 +77,49 @@ class ReactiveCassandraBatchTemplate implements ReactiveCassandraBatchOperations this.operations = operations; this.converter = operations.getConverter(); - this.mappingContext = converter.getMappingContext(); - this.statementFactory = new StatementFactory(new UpdateMapper(converter)); + this.mappingContext = this.converter.getMappingContext(); + this.statementFactory = new StatementFactory(new UpdateMapper(this.converter)); + } + + private void assertNotExecuted() { + Assert.state(!this.executed.get(), "This Cassandra Batch was already executed"); + } + + /** + * Return a reference to the configured {@link CassandraConverter} used to map {@link Object Objects} + * to {@link com.datastax.driver.core.Row Rows}. + * + * @return a reference to the configured {@link CassandraConverter}. + * @see org.springframework.data.cassandra.core.convert.CassandraConverter + */ + protected CassandraConverter getConverter() { + return this.converter; + } + + /** + * Returns a reference to the configured {@link CassandraMappingContext} used to map entities to Cassandra tables + * and back. + * + * @return a reference to the configured {@link CassandraMappingContext}. + * @see org.springframework.data.cassandra.core.mapping.CassandraMappingContext + */ + protected CassandraMappingContext getMappingContext() { + return this.mappingContext; + } + + private CassandraPersistentEntity getRequiredPersistentEntity(Class entityType) { + return getMappingContext().getRequiredPersistentEntity(ClassUtils.getUserClass(entityType)); + } + + /** + * Return a reference to the configured {@link StatementFactory} used to create Cassandra {@link Statement} objects + * to perform data access operations on a Cassandra cluster. + * + * @return a reference to the configured {@link StatementFactory}. + * @see org.springframework.data.cassandra.core.StatementFactory + */ + protected StatementFactory getStatementFactory() { + return this.statementFactory; } /* (non-Javadoc) @@ -88,16 +130,17 @@ class ReactiveCassandraBatchTemplate implements ReactiveCassandraBatchOperations return Mono.defer(() -> { - if (executed.compareAndSet(false, true)) { + if (this.executed.compareAndSet(false, true)) { - return Flux.merge(batchMonos) // + return Flux.merge(this.batchMonos) // .flatMapIterable(Function.identity()) // .collectList() // .flatMap(statements -> { - statements.forEach(batch::add); + statements.forEach(this.batch::add); + + return this.operations.getReactiveCqlOperations().queryForResultSet(this.batch); - return operations.getReactiveCqlOperations().queryForResultSet(batch); }).flatMap(resultSet -> resultSet.rows().collectList() .map(rows -> new WriteResult(resultSet.getAllExecutionInfo(), resultSet.wasApplied(), rows))); } @@ -114,7 +157,7 @@ class ReactiveCassandraBatchTemplate implements ReactiveCassandraBatchOperations assertNotExecuted(); - batch.using(QueryBuilder.timestamp(timestamp)); + this.batch.using(QueryBuilder.timestamp(timestamp)); return this; } @@ -153,10 +196,11 @@ class ReactiveCassandraBatchTemplate implements ReactiveCassandraBatchOperations public ReactiveCassandraBatchOperations insert(Iterable entities, WriteOptions options) { assertNotExecuted(); + Assert.notNull(entities, "Entities must not be null"); Assert.notNull(options, "WriteOptions must not be null"); - batchMonos.add(Mono.just(doInsert(entities, options))); + this.batchMonos.add(Mono.just(doInsert(entities, options))); return this; } @@ -168,28 +212,32 @@ class ReactiveCassandraBatchTemplate implements ReactiveCassandraBatchOperations public ReactiveCassandraBatchOperations insert(Mono> entities, WriteOptions options) { assertNotExecuted(); + Assert.notNull(entities, "Entities must not be null"); Assert.notNull(options, "WriteOptions must not be null"); - batchMonos.add(entities.map(e -> doInsert(e, options))); + this.batchMonos.add(entities.map(entity -> doInsert(entity, options))); return this; } private Collection doInsert(Iterable entities, WriteOptions options) { + CassandraConverter converter = getConverter(); + CassandraMappingContext mappingContext = getMappingContext(); List insertQueries = new ArrayList<>(); - CassandraConverter converter = operations.getConverter(); - CassandraMappingContext mappingContext = converter.getMappingContext(); for (Object entity : entities) { Assert.notNull(entity, "Entity must not be null"); - BasicCassandraPersistentEntity persistentEntity = mappingContext - .getRequiredPersistentEntity(entity.getClass()); - insertQueries.add(EntityQueryUtils.createInsertQuery(persistentEntity.getTableName().toCql(), entity, options, - converter, persistentEntity)); + BasicCassandraPersistentEntity persistentEntity = + mappingContext.getRequiredPersistentEntity(entity.getClass()); + + Insert insertQuery = EntityQueryUtils.createInsertQuery(persistentEntity.getTableName().toCql(), + entity, options, converter, persistentEntity); + + insertQueries.add(insertQuery); } return insertQueries; @@ -229,10 +277,11 @@ class ReactiveCassandraBatchTemplate implements ReactiveCassandraBatchOperations public ReactiveCassandraBatchOperations update(Iterable entities, WriteOptions options) { assertNotExecuted(); + Assert.notNull(entities, "Entities must not be null"); Assert.notNull(options, "WriteOptions must not be null"); - batchMonos.add(Mono.just(doUpdate(entities, options))); + this.batchMonos.add(Mono.just(doUpdate(entities, options))); return this; } @@ -244,26 +293,30 @@ class ReactiveCassandraBatchTemplate implements ReactiveCassandraBatchOperations public ReactiveCassandraBatchOperations update(Mono> entities, WriteOptions options) { assertNotExecuted(); + Assert.notNull(entities, "Entities must not be null"); Assert.notNull(options, "WriteOptions must not be null"); - batchMonos.add(entities.map(e -> doUpdate(e, options))); + this.batchMonos.add(entities.map(entity -> doUpdate(entity, options))); return this; } private Collection doUpdate(Iterable entities, WriteOptions options) { + CassandraConverter converter = getConverter(); List updateQueries = new ArrayList<>(); - CassandraConverter converter = operations.getConverter(); for (Object entity : entities) { Assert.notNull(entity, "Entity must not be null"); CassandraPersistentEntity persistentEntity = getRequiredPersistentEntity(entity.getClass()); - updateQueries - .add(statementFactory.update(entity, options, converter, persistentEntity, persistentEntity.getTableName())); + + Update update = getStatementFactory() + .update(entity, options, converter, persistentEntity, persistentEntity.getTableName()); + + updateQueries.add(update); } return updateQueries; @@ -303,10 +356,11 @@ class ReactiveCassandraBatchTemplate implements ReactiveCassandraBatchOperations public ReactiveCassandraBatchOperations delete(Iterable entities, WriteOptions options) { assertNotExecuted(); + Assert.notNull(entities, "Entities must not be null"); Assert.notNull(options, "WriteOptions must not be null"); - batchMonos.add(Mono.just(doDelete(entities, options))); + this.batchMonos.add(Mono.just(doDelete(entities, options))); return this; } @@ -318,36 +372,32 @@ class ReactiveCassandraBatchTemplate implements ReactiveCassandraBatchOperations public ReactiveCassandraBatchOperations delete(Mono> entities, WriteOptions options) { assertNotExecuted(); + Assert.notNull(entities, "Entities must not be null"); Assert.notNull(options, "WriteOptions must not be null"); - batchMonos.add(entities.map(it -> doDelete(it, options))); + this.batchMonos.add(entities.map(it -> doDelete(it, options))); return this; } private Collection doDelete(Iterable entities, WriteOptions options) { + CassandraConverter converter = getConverter(); List deleteQueries = new ArrayList<>(); - CassandraConverter converter = operations.getConverter(); for (Object entity : entities) { Assert.notNull(entity, "Entity must not be null"); CassandraPersistentEntity persistentEntity = getRequiredPersistentEntity(entity.getClass()); - deleteQueries - .add(statementFactory.delete(entity, options, converter, persistentEntity, persistentEntity.getTableName())); + + Delete delete = getStatementFactory() + .delete(entity, options, converter, persistentEntity, persistentEntity.getTableName()); + + deleteQueries.add(delete); } return deleteQueries; } - - private void assertNotExecuted() { - Assert.state(!executed.get(), "This Cassandra Batch was already executed"); - } - - private CassandraPersistentEntity getRequiredPersistentEntity(Class entityType) { - return this.mappingContext.getRequiredPersistentEntity(ClassUtils.getUserClass(entityType)); - } } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/ReactiveCassandraTemplate.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/ReactiveCassandraTemplate.java index c6264ae8f..602d3ce9e 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/ReactiveCassandraTemplate.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/ReactiveCassandraTemplate.java @@ -15,13 +15,14 @@ */ package org.springframework.data.cassandra.core; -import lombok.Value; -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; - import java.util.Collections; import java.util.function.Function; +import lombok.Value; + +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + import org.reactivestreams.Publisher; import org.springframework.context.ApplicationEvent; import org.springframework.context.ApplicationEventPublisher; @@ -168,8 +169,8 @@ public class ReactiveCassandraTemplate implements ReactiveCassandraOperations, A this.converter = converter; this.cqlOperations = reactiveCqlOperations; this.mappingContext = this.converter.getMappingContext(); - this.statementFactory = new StatementFactory(new QueryMapper(converter), new UpdateMapper(converter)); this.projectionFactory = new SpelAwareProxyProjectionFactory(); + this.statementFactory = new StatementFactory(new QueryMapper(converter), new UpdateMapper(converter)); } /* (non-Javadoc) @@ -263,10 +264,9 @@ public class ReactiveCassandraTemplate implements ReactiveCassandraOperations, A ReactiveResultSet resultSet = tuple.getT1(); Integer effectiveFetchSize = tuple.getT2(); - return resultSet.availableRows().collectList().map(it -> { - return EntityQueryUtils.readSlice(it, resultSet.getExecutionInfo().getPagingState(), rowMapper, 1, - effectiveFetchSize); - }); + return resultSet.availableRows().collectList().map(it -> + EntityQueryUtils.readSlice(it, resultSet.getExecutionInfo().getPagingState(), rowMapper, 1, + effectiveFetchSize)); }).defaultIfEmpty(new SliceImpl<>(Collections.emptyList())); } @@ -299,8 +299,8 @@ public class ReactiveCassandraTemplate implements ReactiveCassandraOperations, A CassandraPersistentEntity persistentEntity = getRequiredPersistentEntity(entityClass); - Columns columns = getStatementFactory().computeColumnsForProjection(query.getColumns(), persistentEntity, - returnType); + Columns columns = getStatementFactory() + .computeColumnsForProjection(query.getColumns(), persistentEntity, returnType); Query queryToUse = query.columns(columns); @@ -354,8 +354,8 @@ public class ReactiveCassandraTemplate implements ReactiveCassandraOperations, A Mono doUpdate(Query query, org.springframework.data.cassandra.core.query.Update update, Class entityClass, CqlIdentifier tableName) { - RegularStatement statement = getStatementFactory().update(query, update, getRequiredPersistentEntity(entityClass), - tableName); + RegularStatement statement = getStatementFactory() + .update(query, update, getRequiredPersistentEntity(entityClass), tableName); return getReactiveCqlOperations().execute(new StatementCallback(statement)).next(); } @@ -374,7 +374,8 @@ public class ReactiveCassandraTemplate implements ReactiveCassandraOperations, A Mono doDelete(Query query, Class entityClass, CqlIdentifier tableName) { - RegularStatement delete = getStatementFactory().delete(query, getRequiredPersistentEntity(entityClass), tableName); + RegularStatement delete = getStatementFactory() + .delete(query, getRequiredPersistentEntity(entityClass), tableName); Mono writeResult = getReactiveCqlOperations().execute(new StatementCallback(delete)) .doOnSubscribe(it -> maybeEmitEvent(new BeforeDeleteEvent<>(delete, entityClass, tableName))).next(); @@ -430,6 +431,7 @@ public class ReactiveCassandraTemplate implements ReactiveCassandraOperations, A CassandraPersistentEntity entity = getRequiredPersistentEntity(entityClass); Select select = QueryBuilder.select().from(entity.getTableName().toCql()); + getConverter().write(id, select.where(), entity); return getReactiveCqlOperations().queryForRows(select).hasElements(); @@ -449,8 +451,8 @@ public class ReactiveCassandraTemplate implements ReactiveCassandraOperations, A Mono doExists(Query query, Class entityClass, CqlIdentifier tableName) { - RegularStatement select = getStatementFactory().select(query.limit(1), getRequiredPersistentEntity(entityClass), - tableName); + RegularStatement select = getStatementFactory() + .select(query.limit(1), getRequiredPersistentEntity(entityClass), tableName); return getReactiveCqlOperations().queryForRows(select).hasElements(); } @@ -467,6 +469,7 @@ public class ReactiveCassandraTemplate implements ReactiveCassandraOperations, A CassandraPersistentEntity entity = getRequiredPersistentEntity(entityClass); Select select = QueryBuilder.select().all().from(entity.getTableName().toCql()); + getConverter().write(id, select.where(), entity); return selectOne(select, entityClass); @@ -578,7 +581,6 @@ public class ReactiveCassandraTemplate implements ReactiveCassandraOperations, A Assert.notNull(entityClass, "Entity type must not be null"); CassandraPersistentEntity entity = getRequiredPersistentEntity(entityClass); - CqlIdentifier tableName = entity.getTableName(); Delete delete = QueryBuilder.delete().from(tableName.toCql()); @@ -719,8 +721,8 @@ public class ReactiveCassandraTemplate implements ReactiveCassandraOperations, A private void maybeEmitEvent(ApplicationEvent event) { - if (eventPublisher != null) { - eventPublisher.publishEvent(event); + if (this.eventPublisher != null) { + this.eventPublisher.publishEvent(event); } } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/ReactiveUpdateOperation.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/ReactiveUpdateOperation.java index 894878d91..069e773eb 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/ReactiveUpdateOperation.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/ReactiveUpdateOperation.java @@ -54,7 +54,6 @@ public interface ReactiveUpdateOperation { /** * Begin creating an {@code UPDATE} operation for the given {@link Class domainType}. * - * @param {@link Class type} of the application domain object. * @param domainType {@link Class type} of domain object to update; must not be {@literal null}. * @return new instance of {@link ReactiveUpdate}. * @throws IllegalArgumentException if {@link Class domainType} is {@literal null}. diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/StatementFactory.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/StatementFactory.java index 874222842..17e105b42 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/StatementFactory.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/StatementFactory.java @@ -328,9 +328,8 @@ public class StatementFactory { query.getQueryOptions().ifPresent(queryOptions -> { - potentiallyApplyIfCondition(queryOptions, UpdateOptions.class, UpdateOptions::getIfCondition, condition -> { - addIfCondition(condition, update, entity); - }); + potentiallyApplyIfCondition(queryOptions, UpdateOptions.class, UpdateOptions::getIfCondition, + condition -> addIfCondition(condition, update, entity)); if (queryOptions instanceof WriteOptions) { EntityQueryUtils.addWriteOptions(update, (WriteOptions) queryOptions); @@ -359,12 +358,11 @@ public class StatementFactory { EntityWriter entityWriter, CassandraPersistentEntity persistentEntity, CqlIdentifier tableName) { - com.datastax.driver.core.querybuilder.Update update = EntityQueryUtils.createUpdateQuery(tableName.toCql(), entity, - options, entityWriter); + com.datastax.driver.core.querybuilder.Update update = + EntityQueryUtils.createUpdateQuery(tableName.toCql(), entity, options, entityWriter); - potentiallyApplyIfCondition(options, UpdateOptions.class, UpdateOptions::getIfCondition, condition -> { - addIfCondition(condition, update, persistentEntity); - }); + potentiallyApplyIfCondition(options, UpdateOptions.class, UpdateOptions::getIfCondition, + condition -> addIfCondition(condition, update, persistentEntity)); return update; } @@ -407,9 +405,8 @@ public class StatementFactory { query.getQueryOptions().ifPresent(queryOptions -> { - potentiallyApplyIfCondition(queryOptions, DeleteOptions.class, DeleteOptions::getIfCondition, condition -> { - addIfCondition(condition, delete, entity); - }); + potentiallyApplyIfCondition(queryOptions, DeleteOptions.class, DeleteOptions::getIfCondition, + condition -> addIfCondition(condition, delete, entity)); if (queryOptions instanceof WriteOptions) { EntityQueryUtils.addWriteOptions(delete, (WriteOptions) queryOptions); @@ -439,9 +436,8 @@ public class StatementFactory { Delete delete = EntityQueryUtils.createDeleteQuery(tableName.toCql(), entity, options, entityWriter); - potentiallyApplyIfCondition(options, DeleteOptions.class, DeleteOptions::getIfCondition, condition -> { - addIfCondition(condition, delete, persistentEntity); - }); + potentiallyApplyIfCondition(options, DeleteOptions.class, DeleteOptions::getIfCondition, + condition -> addIfCondition(condition, delete, persistentEntity)); return delete; } @@ -624,40 +620,46 @@ public class StatementFactory { if (optionsClass.isInstance(object)) { T options = optionsClass.cast(object); + Filter filter = filterExtractor.apply(options); + if (filter != null) { consumeIfPresent.accept(filter); } } - } private static Clause toClause(CriteriaDefinition criteriaDefinition) { - Predicate predicate = criteriaDefinition.getPredicate(); String columnName = criteriaDefinition.getColumnName().toCql(); - switch (predicate.getOperator().toString()) { + Predicate predicate = criteriaDefinition.getPredicate(); - case "=": + CriteriaDefinition.Operators predicateOperator = + CriteriaDefinition.Operators.from(predicate.getOperator().toString()) + .orElseThrow(() -> new IllegalArgumentException(String.format("Unknown operator [%s]", predicate.getOperator()))); + + switch (predicateOperator) { + + case EQ: return QueryBuilder.eq(columnName, predicate.getValue()); - case "!=": + case NE: return QueryBuilder.ne(columnName, predicate.getValue()); - case ">": + case GT: return QueryBuilder.gt(columnName, predicate.getValue()); - case ">=": + case GTE: return QueryBuilder.gte(columnName, predicate.getValue()); - case "<": + case LT: return QueryBuilder.lt(columnName, predicate.getValue()); - case "<=": + case LTE: return QueryBuilder.lte(columnName, predicate.getValue()); - case "IN": + case IN: if (predicate.getValue() instanceof List) { return QueryBuilder.in(columnName, (List) predicate.getValue()); @@ -669,25 +671,28 @@ public class StatementFactory { return QueryBuilder.in(columnName, predicate.getValue()); - case "LIKE": + case LIKE: return QueryBuilder.like(columnName, predicate.getValue()); - case "IS NOT NULL": + case IS_NOT_NULL: return QueryBuilder.notNull(columnName); - case "CONTAINS": + case CONTAINS: + Assert.state(predicate.getValue() != null, () -> String.format("CONTAINS value for column %s is null", columnName)); + return QueryBuilder.contains(columnName, predicate.getValue()); - case "CONTAINS KEY": + case CONTAINS_KEY: + Assert.state(predicate.getValue() != null, () -> String.format("CONTAINS KEY value for column %s is null", columnName)); + return QueryBuilder.containsKey(columnName, predicate.getValue()); } - throw new IllegalArgumentException( - String.format("Criteria %s %s %s not supported", columnName, predicate.getOperator(), predicate.getValue())); + throw new IllegalArgumentException(String.format("Criteria %s %s %s not supported", + columnName, predicate.getOperator(), predicate.getValue())); } - } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/UpdateOptions.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/UpdateOptions.java index 6972ba55a..2780422fd 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/UpdateOptions.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/UpdateOptions.java @@ -15,12 +15,12 @@ */ package org.springframework.data.cassandra.core; -import lombok.EqualsAndHashCode; - import java.time.Duration; import java.time.Instant; import java.util.concurrent.TimeUnit; +import lombok.EqualsAndHashCode; + import org.springframework.data.cassandra.core.cql.WriteOptions; import org.springframework.data.cassandra.core.query.CriteriaDefinition; import org.springframework.data.cassandra.core.query.Filter; @@ -306,8 +306,9 @@ public class UpdateOptions extends WriteOptions { * @return a new {@link UpdateOptions} with the configured values */ public UpdateOptions build() { - return new UpdateOptions(this.consistencyLevel, this.retryPolicy, this.tracing, this.fetchSize, this.readTimeout, - this.ttl, this.timestamp, this.ifExists, this.ifCondition); + + return new UpdateOptions(this.consistencyLevel, this.retryPolicy, this.tracing, this.fetchSize, + this.readTimeout, this.ttl, this.timestamp, this.ifExists, this.ifCondition); } } } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/query/CriteriaDefinition.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/query/CriteriaDefinition.java index 22f8a8038..6094ec21b 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/query/CriteriaDefinition.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/query/CriteriaDefinition.java @@ -15,6 +15,8 @@ */ package org.springframework.data.cassandra.core.query; +import java.util.Optional; + import lombok.EqualsAndHashCode; import org.springframework.lang.Nullable; @@ -72,7 +74,7 @@ public interface CriteriaDefinition { * @return the operator, such as {@literal =}, {@literal >=}, {@literal LIKE}. */ public Operator getOperator() { - return operator; + return this.operator; } /** @@ -80,7 +82,7 @@ public interface CriteriaDefinition { */ @Nullable public Object getValue() { - return value; + return this.value; } } @@ -131,6 +133,7 @@ public interface CriteriaDefinition { return toString(); } }, + GT(">"), GTE(">="), LT("<"), @@ -138,6 +141,17 @@ public interface CriteriaDefinition { IN("IN"), LIKE("LIKE"); + public static Optional from(String operator) { + + for (Operators operatorsValue : Operators.values()) { + if (operatorsValue.toString().equals(operator)) { + return Optional.of(operatorsValue); + } + } + + return Optional.empty(); + } + private final String operator; Operators(String operator) { @@ -146,7 +160,7 @@ public interface CriteriaDefinition { @Override public String toString() { - return operator; + return this.operator; } } } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/query/Update.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/query/Update.java index e33d392fc..cd03eb3e8 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/query/Update.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/query/Update.java @@ -478,7 +478,7 @@ public class Update { * @return the {@link ColumnName}. */ public ColumnName getColumnName() { - return columnName; + return this.columnName; } } @@ -500,11 +500,11 @@ public class Update { } public Iterable getValue() { - return value; + return this.value; } public Mode getMode() { - return mode; + return this.mode; } /* (non-Javadoc) diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/AsyncCassandraTemplateUnitTests.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/AsyncCassandraTemplateUnitTests.java index 7cedca280..7c69407a7 100644 --- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/AsyncCassandraTemplateUnitTests.java +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/AsyncCassandraTemplateUnitTests.java @@ -15,10 +15,15 @@ */ package org.springframework.data.cassandra.core; -import static org.assertj.core.api.Assertions.*; -import static org.mockito.ArgumentMatchers.*; -import static org.mockito.Mockito.*; -import static org.springframework.data.cassandra.core.query.Criteria.*; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.fail; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.springframework.data.cassandra.core.query.Criteria.where; import java.util.ArrayList; import java.util.Collections; @@ -35,6 +40,7 @@ import org.mockito.ArgumentCaptor; import org.mockito.Captor; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; + import org.springframework.data.cassandra.CassandraConnectionFailureException; import org.springframework.data.cassandra.core.query.Filter; import org.springframework.data.cassandra.core.query.Query; @@ -328,7 +334,10 @@ public class AsyncCassandraTemplateUnitTests { @Test // DATACASS-575 public void updateShouldApplyUpdateQuery() { - template.update(Query.query(where("id").is("heisenberg")), Update.update("firstname", "Walter"), User.class); + Query query = Query.query(where("id").is("heisenberg")); + Update update = Update.update("firstname", "Walter"); + + template.update(query, update, User.class); verify(session).executeAsync(statementCaptor.capture()); assertThat(statementCaptor.getValue().toString()) @@ -339,14 +348,17 @@ public class AsyncCassandraTemplateUnitTests { public void updateShouldApplyUpdateQueryWitLwt() { Filter ifCondition = Filter.from(where("firstname").is("Walter"), where("lastname").is("White")); + Query query = Query.query(where("id").is("heisenberg")) .queryOptions(UpdateOptions.builder().ifCondition(ifCondition).build()); - template.update(query, Update.update("firstname", "Walter"), User.class); + Update update = Update.update("firstname", "Walter"); + + template.update(query, update, User.class); verify(session).executeAsync(statementCaptor.capture()); - assertThat(statementCaptor.getValue().toString()).isEqualTo( - "UPDATE users SET firstname='Walter' WHERE id='heisenberg' IF firstname='Walter' AND lastname='White';"); + assertThat(statementCaptor.getValue().toString()) + .isEqualTo("UPDATE users SET firstname='Walter' WHERE id='heisenberg' IF firstname='Walter' AND lastname='White';"); } @Test // DATACASS-292 diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/CassandraTemplateUnitTests.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/CassandraTemplateUnitTests.java index c7739d023..484d61899 100644 --- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/CassandraTemplateUnitTests.java +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/CassandraTemplateUnitTests.java @@ -15,10 +15,15 @@ */ package org.springframework.data.cassandra.core; -import static org.assertj.core.api.Assertions.*; -import static org.mockito.ArgumentMatchers.*; -import static org.mockito.Mockito.*; -import static org.springframework.data.cassandra.core.query.Criteria.*; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.fail; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.springframework.data.cassandra.core.query.Criteria.where; import java.util.Collections; import java.util.List; @@ -32,6 +37,7 @@ import org.mockito.Captor; import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.junit.MockitoJUnitRunner; + import org.springframework.data.cassandra.CassandraConnectionFailureException; import org.springframework.data.cassandra.core.query.Filter; import org.springframework.data.cassandra.core.query.Query; @@ -355,7 +361,10 @@ public class CassandraTemplateUnitTests { @Test // DATACASS-575 public void updateShouldApplyUpdateQuery() { - template.update(Query.query(where("id").is("heisenberg")), Update.update("firstname", "Walter"), User.class); + Query query = Query.query(where("id").is("heisenberg")); + Update update = Update.update("firstname", "Walter"); + + template.update(query, update, User.class); verify(session).execute(statementCaptor.capture()); assertThat(statementCaptor.getValue().toString()) @@ -366,14 +375,17 @@ public class CassandraTemplateUnitTests { public void updateShouldApplyUpdateQueryWitLwt() { Filter ifCondition = Filter.from(where("firstname").is("Walter"), where("lastname").is("White")); + Query query = Query.query(where("id").is("heisenberg")) .queryOptions(UpdateOptions.builder().ifCondition(ifCondition).build()); - template.update(query, Update.update("firstname", "Walter"), User.class); + Update update = Update.update("firstname", "Walter"); + + template.update(query, update, User.class); verify(session).execute(statementCaptor.capture()); - assertThat(statementCaptor.getValue().toString()).isEqualTo( - "UPDATE users SET firstname='Walter' WHERE id='heisenberg' IF firstname='Walter' AND lastname='White';"); + assertThat(statementCaptor.getValue().toString()) + .isEqualTo("UPDATE users SET firstname='Walter' WHERE id='heisenberg' IF firstname='Walter' AND lastname='White';"); } @Test // DATACASS-292 diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/DeleteOptionsUnitTests.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/DeleteOptionsUnitTests.java index c0b1ca5d4..e51f2f109 100644 --- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/DeleteOptionsUnitTests.java +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/DeleteOptionsUnitTests.java @@ -15,12 +15,13 @@ */ package org.springframework.data.cassandra.core; -import static org.assertj.core.api.Assertions.*; +import static org.assertj.core.api.Assertions.assertThat; import java.time.Duration; import java.time.Instant; import org.junit.Test; + import org.springframework.data.cassandra.core.query.Query; /** @@ -44,6 +45,7 @@ public class DeleteOptionsUnitTests { assertThat(deleteOptions.getTtl()).isEqualTo(Duration.ofSeconds(10)); assertThat(deleteOptions.getTimestamp()).isEqualTo(now.toEpochMilli() * 1000); assertThat(deleteOptions.isIfExists()).isTrue(); + assertThat(deleteOptions.getIfCondition()).isNull(); } @Test // DATACASS-575 @@ -62,6 +64,7 @@ public class DeleteOptionsUnitTests { assertThat(mutated.getTtl()).isEqualTo(Duration.ofSeconds(20)); assertThat(mutated.getTimestamp()).isEqualTo(1519000753); assertThat(mutated.isIfExists()).isTrue(); + assertThat(mutated.getIfCondition()).isNull(); } @Test // DATACASS-575 diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/ReactiveCassandraTemplateUnitTests.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/ReactiveCassandraTemplateUnitTests.java index d9d0629a1..7ca4b4611 100644 --- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/ReactiveCassandraTemplateUnitTests.java +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/ReactiveCassandraTemplateUnitTests.java @@ -15,17 +15,21 @@ */ package org.springframework.data.cassandra.core; -import static org.assertj.core.api.Assertions.*; -import static org.mockito.ArgumentMatchers.*; -import static org.mockito.Mockito.*; -import static org.springframework.data.cassandra.core.query.Criteria.*; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.springframework.data.cassandra.core.query.Criteria.where; + +import java.util.Collections; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import reactor.test.StepVerifier; -import java.util.Collections; - import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -33,6 +37,7 @@ import org.mockito.ArgumentCaptor; import org.mockito.Captor; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; + import org.springframework.data.cassandra.ReactiveResultSet; import org.springframework.data.cassandra.ReactiveSession; import org.springframework.data.cassandra.core.query.Filter; @@ -305,7 +310,10 @@ public class ReactiveCassandraTemplateUnitTests { when(reactiveResultSet.rows()).thenReturn(Flux.just(row)); - template.update(Query.query(where("id").is("heisenberg")), Update.update("firstname", "Walter"), User.class) // + Query query = Query.query(where("id").is("heisenberg")); + Update update = Update.update("firstname", "Walter"); + + template.update(query, update, User.class) // .as(StepVerifier::create) // .expectNextCount(1) // .verifyComplete(); @@ -321,17 +329,20 @@ public class ReactiveCassandraTemplateUnitTests { when(reactiveResultSet.rows()).thenReturn(Flux.just(row)); Filter ifCondition = Filter.from(where("firstname").is("Walter"), where("lastname").is("White")); + Query query = Query.query(where("id").is("heisenberg")) .queryOptions(UpdateOptions.builder().ifCondition(ifCondition).build()); - template.update(query, Update.update("firstname", "Walter"), User.class) // + Update update = Update.update("firstname", "Walter"); + + template.update(query, update, User.class) // .as(StepVerifier::create) // .expectNextCount(1) // .verifyComplete(); verify(session).execute(statementCaptor.capture()); - assertThat(statementCaptor.getValue().toString()).isEqualTo( - "UPDATE users SET firstname='Walter' WHERE id='heisenberg' IF firstname='Walter' AND lastname='White';"); + assertThat(statementCaptor.getValue().toString()) + .isEqualTo("UPDATE users SET firstname='Walter' WHERE id='heisenberg' IF firstname='Walter' AND lastname='White';"); } @Test // DATACASS-335 diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/UpdateOptionsUnitTests.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/UpdateOptionsUnitTests.java index e3635ff04..77750b683 100644 --- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/UpdateOptionsUnitTests.java +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/UpdateOptionsUnitTests.java @@ -15,12 +15,13 @@ */ package org.springframework.data.cassandra.core; -import static org.assertj.core.api.Assertions.*; +import static org.assertj.core.api.Assertions.assertThat; import java.time.Duration; import java.time.Instant; import org.junit.Test; + import org.springframework.data.cassandra.core.query.Query; /** @@ -45,6 +46,7 @@ public class UpdateOptionsUnitTests { assertThat(updateOptions.getTtl()).isEqualTo(Duration.ofSeconds(10)); assertThat(updateOptions.getTimestamp()).isEqualTo(now.toEpochMilli() * 1000); assertThat(updateOptions.isIfExists()).isTrue(); + assertThat(updateOptions.getIfCondition()).isNull(); } @Test // DATACASS-56, DATACASS-155 @@ -66,6 +68,7 @@ public class UpdateOptionsUnitTests { assertThat(mutated.getTtl()).isEqualTo(Duration.ofSeconds(20)); assertThat(mutated.getTimestamp()).isEqualTo(1519000753); assertThat(mutated.isIfExists()).isTrue(); + assertThat(mutated.getIfCondition()).isNull(); } @Test // DATACASS-575