DATACASS-575 - Polish.

Resolves gh-135.
This commit is contained in:
John Blum
2019-02-26 17:40:42 -08:00
parent 0e624c9cc4
commit 101ee2aee7
15 changed files with 325 additions and 162 deletions

View File

@@ -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<Row, T> 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<ResultSet> 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();
}
}
}

View File

@@ -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));
}
}

View File

@@ -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);
}
}
}

View File

@@ -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<Mono<Collection<? extends BuiltStatement>>> 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<? extends Iterable<?>> 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<? extends BuiltStatement> doInsert(Iterable<?> entities, WriteOptions options) {
CassandraConverter converter = getConverter();
CassandraMappingContext mappingContext = getMappingContext();
List<Insert> 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<? extends Iterable<?>> 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<? extends BuiltStatement> doUpdate(Iterable<?> entities, WriteOptions options) {
CassandraConverter converter = getConverter();
List<Update> 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<? extends Iterable<?>> 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<? extends BuiltStatement> doDelete(Iterable<?> entities, WriteOptions options) {
CassandraConverter converter = getConverter();
List<Delete> 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));
}
}

View File

@@ -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<WriteResult> 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<WriteResult> 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> 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<Boolean> 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);
}
}

View File

@@ -54,7 +54,6 @@ public interface ReactiveUpdateOperation {
/**
* Begin creating an {@code UPDATE} operation for the given {@link Class domainType}.
*
* @param <T> {@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}.

View File

@@ -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<Object, Object> 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()));
}
}

View File

@@ -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);
}
}
}

View File

@@ -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<Operators> 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;
}
}
}

View File

@@ -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<Object> getValue() {
return value;
return this.value;
}
public Mode getMode() {
return mode;
return this.mode;
}
/* (non-Javadoc)

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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