DATACASS-708 - Allow configuration of execution profile and serial consistency per statement.

We now allow configuration of the execution profile and serial consistency through QueryOptions and CassandraAccessor/ReactiveCqlTemplate. Settings are applied on a per-Statement basis. The newly ExecutionProfileResolver can resolve the profile either from a profile name or a DriverExecutionProfile object for more flexibility.

With this change, we removed the support for setting a RetryPolicy directly as the new driver 4 does not support a direct configuration of the RetryPolicy. Instead, the RetryPolicy is configured through an execution profile.
This commit is contained in:
Mark Paluch
2020-01-17 13:23:06 +01:00
parent a3e66c3f67
commit c341025138
25 changed files with 769 additions and 321 deletions

View File

@@ -21,6 +21,7 @@ import java.time.Duration;
import java.time.Instant;
import java.util.concurrent.TimeUnit;
import org.springframework.data.cassandra.core.cql.ExecutionProfileResolver;
import org.springframework.data.cassandra.core.cql.WriteOptions;
import org.springframework.data.cassandra.core.query.CriteriaDefinition;
import org.springframework.data.cassandra.core.query.Filter;
@@ -28,7 +29,6 @@ import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import com.datastax.oss.driver.api.core.ConsistencyLevel;
import com.datastax.oss.driver.api.core.retry.RetryPolicy;
/**
* Extension to {@link WriteOptions} for use with {@code DELETE} operations.
@@ -45,11 +45,12 @@ public class DeleteOptions extends WriteOptions {
private final @Nullable Filter ifCondition;
private DeleteOptions(@Nullable ConsistencyLevel consistencyLevel, @Nullable RetryPolicy retryPolicy,
@Nullable Boolean tracing, @Nullable Integer fetchSize, Duration readTimeout, Duration ttl,
@Nullable Long timestamp, boolean ifExists, @Nullable Filter ifCondition) {
private DeleteOptions(@Nullable ConsistencyLevel consistencyLevel, ExecutionProfileResolver executionProfileResolver,
@Nullable Integer pageSize, @Nullable ConsistencyLevel serialConsistencyLevel, Duration timeout, Duration ttl,
@Nullable Long timestamp, @Nullable Boolean tracing, boolean ifExists, @Nullable Filter ifCondition) {
super(consistencyLevel, retryPolicy, tracing, fetchSize, readTimeout, ttl, timestamp);
super(consistencyLevel, executionProfileResolver, pageSize, serialConsistencyLevel, timeout, ttl, timestamp,
tracing);
this.ifExists = ifExists;
this.ifCondition = ifCondition;
@@ -129,13 +130,20 @@ public class DeleteOptions extends WriteOptions {
}
/* (non-Javadoc)
* @see org.springframework.data.cassandra.core.cql.WriteOptions.WriteOptionsBuilder#retryPolicy(com.datastax.driver.core.policies.RetryPolicy)
* @see org.springframework.data.cassandra.core.cql.QueryOptions.QueryOptionsBuilder#executionProfile(String)
*/
@Override
@Deprecated
public DeleteOptionsBuilder retryPolicy(RetryPolicy driverRetryPolicy) {
public DeleteOptionsBuilder executionProfile(String profileName) {
super.executionProfile(profileName);
return this;
}
super.retryPolicy(driverRetryPolicy);
/* (non-Javadoc)
* @see org.springframework.data.cassandra.core.cql.QueryOptions.QueryOptionsBuilder#executionProfile(org.springframework.data.cassandra.core.cql.ExecutionProfileResolver)
*/
@Override
public DeleteOptionsBuilder executionProfile(ExecutionProfileResolver executionProfileResolver) {
super.executionProfile(executionProfileResolver);
return this;
}
@@ -182,6 +190,15 @@ public class DeleteOptions extends WriteOptions {
return this;
}
/* (non-Javadoc)
* @see org.springframework.data.cassandra.core.cql.QueryOptions.QueryOptionsBuilder#serialConsistencyLevel(com.datastax.oss.driver.api.core.ConsistencyLevel)
*/
@Override
public DeleteOptionsBuilder serialConsistencyLevel(ConsistencyLevel consistencyLevel) {
super.serialConsistencyLevel(consistencyLevel);
return this;
}
/* (non-Javadoc)
* @see org.springframework.data.cassandra.core.cql.WriteOptions.WriteOptionsBuilder#readTimeout(java.time.Duration)
*/
@@ -312,8 +329,9 @@ public class DeleteOptions extends WriteOptions {
*/
public DeleteOptions build() {
return new DeleteOptions(this.consistencyLevel, this.retryPolicy, this.tracing, this.pageSize, this.timeout,
this.ttl, this.timestamp, this.ifExists, this.ifCondition);
return new DeleteOptions(this.consistencyLevel, this.executionProfileResolver, this.pageSize,
this.serialConsistencyLevel, this.timeout, this.ttl, this.timestamp, this.tracing, this.ifExists,
this.ifCondition);
}
}
}

View File

@@ -21,11 +21,11 @@ import java.time.Duration;
import java.time.Instant;
import java.util.concurrent.TimeUnit;
import org.springframework.data.cassandra.core.cql.ExecutionProfileResolver;
import org.springframework.data.cassandra.core.cql.WriteOptions;
import org.springframework.lang.Nullable;
import com.datastax.oss.driver.api.core.ConsistencyLevel;
import com.datastax.oss.driver.api.core.retry.RetryPolicy;
/**
* Extension to {@link WriteOptions} for use with {@code INSERT} operations.
@@ -43,11 +43,12 @@ public class InsertOptions extends WriteOptions {
private boolean insertNulls;
private InsertOptions(@Nullable ConsistencyLevel consistencyLevel, @Nullable RetryPolicy retryPolicy,
@Nullable Boolean tracing, @Nullable Integer fetchSize, Duration readTimeout, Duration ttl,
@Nullable Long timestamp, boolean ifNotExists, boolean insertNulls) {
private InsertOptions(@Nullable ConsistencyLevel consistencyLevel, ExecutionProfileResolver executionProfileResolver,
@Nullable Integer pageSize, @Nullable ConsistencyLevel serialConsistencyLevel, Duration timeout, Duration ttl,
@Nullable Long timestamp, @Nullable Boolean tracing, boolean ifNotExists, boolean insertNulls) {
super(consistencyLevel, retryPolicy, tracing, fetchSize, readTimeout, ttl, timestamp);
super(consistencyLevel, executionProfileResolver, pageSize, serialConsistencyLevel, timeout, ttl, timestamp,
tracing);
this.ifNotExists = ifNotExists;
this.insertNulls = insertNulls;
@@ -131,13 +132,20 @@ public class InsertOptions extends WriteOptions {
}
/* (non-Javadoc)
* @see org.springframework.data.cassandra.core.cql.WriteOptions.WriteOptionsBuilder#retryPolicy(com.datastax.driver.core.policies.RetryPolicy)
* @see org.springframework.data.cassandra.core.cql.QueryOptions.QueryOptionsBuilder#executionProfile(String)
*/
@Override
@Deprecated
public InsertOptionsBuilder retryPolicy(RetryPolicy driverRetryPolicy) {
public InsertOptionsBuilder executionProfile(String profileName) {
super.executionProfile(profileName);
return this;
}
super.retryPolicy(driverRetryPolicy);
/* (non-Javadoc)
* @see org.springframework.data.cassandra.core.cql.QueryOptions.QueryOptionsBuilder#executionProfile(org.springframework.data.cassandra.core.cql.ExecutionProfileResolver)
*/
@Override
public InsertOptionsBuilder executionProfile(ExecutionProfileResolver executionProfileResolver) {
super.executionProfile(executionProfileResolver);
return this;
}
@@ -180,6 +188,15 @@ public class InsertOptions extends WriteOptions {
return this;
}
/* (non-Javadoc)
* @see org.springframework.data.cassandra.core.cql.QueryOptions.QueryOptionsBuilder#serialConsistencyLevel(com.datastax.oss.driver.api.core.ConsistencyLevel)
*/
@Override
public InsertOptionsBuilder serialConsistencyLevel(ConsistencyLevel consistencyLevel) {
super.serialConsistencyLevel(consistencyLevel);
return this;
}
/* (non-Javadoc)
* @see org.springframework.data.cassandra.core.cql.WriteOptions.WriteOptionsBuilder#readTimeout(java.time.Duration)
*/
@@ -274,8 +291,8 @@ public class InsertOptions extends WriteOptions {
/**
* Insert {@literal null} values from an entity. This allows the usage of {@code INSERT} statements as upsert by
* ensuring * that the whole entity state is persisted. Inserting {@literal null}s in Cassandra creates tombstones
* so this * option should be used with caution.
* ensuring that the whole entity state is persisted. Inserting {@literal null}s in Cassandra creates tombstones so
* this option should be used with caution.
*
* @return {@code this} {@link InsertOptionsBuilder}
* @since 2.1
@@ -306,8 +323,9 @@ public class InsertOptions extends WriteOptions {
* @return a new {@link InsertOptions} with the configured values
*/
public InsertOptions build() {
return new InsertOptions(this.consistencyLevel, this.retryPolicy, this.tracing, this.pageSize, this.timeout,
this.ttl, this.timestamp, this.ifNotExists, this.insertNulls);
return new InsertOptions(this.consistencyLevel, this.executionProfileResolver, this.pageSize,
this.serialConsistencyLevel, this.timeout, this.ttl, this.timestamp, this.tracing, this.ifNotExists,
this.insertNulls);
}
}
}

View File

@@ -845,8 +845,8 @@ public class ReactiveCassandraTemplate
if (getReactiveCqlOperations() instanceof CassandraAccessor) {
CassandraAccessor accessor = (CassandraAccessor) getReactiveCqlOperations();
if (accessor.getFetchSize() != -1) {
return Mono.just(accessor.getFetchSize());
if (accessor.getPageSize() != -1) {
return Mono.just(accessor.getPageSize());
}
}

View File

@@ -315,9 +315,7 @@ public class StatementFactory {
return statement.valuesByIds(values);
}).apply(statement -> (RegularInsert) addWriteOptions(statement, options));
builder.onBuild(statementBuilder -> {
QueryOptionsUtil.addQueryOptions(statementBuilder, options);
});
builder.transform(statement -> QueryOptionsUtil.addQueryOptions(statement, options));
return builder;
}
@@ -395,9 +393,7 @@ public class StatementFactory {
});
query.getQueryOptions().ifPresent(options -> {
builder.onBuild(statementBuilder -> {
query.getQueryOptions().ifPresent(it -> QueryOptionsUtil.addQueryOptions(statementBuilder, it));
});
builder.transform(statementBuilder -> QueryOptionsUtil.addQueryOptions(statementBuilder, options));
});
return builder;
@@ -462,9 +458,7 @@ public class StatementFactory {
applyUpdateIfCondition(builder, criteriaDefinitions);
});
builder.onBuild(statementBuilder -> {
QueryOptionsUtil.addQueryOptions(statementBuilder, options);
});
builder.transform(statement -> QueryOptionsUtil.addQueryOptions(statement, options));
return builder;
}
@@ -542,9 +536,7 @@ public class StatementFactory {
});
query.getQueryOptions().ifPresent(options -> {
builder.onBuild(statementBuilder -> {
query.getQueryOptions().ifPresent(it -> QueryOptionsUtil.addQueryOptions(statementBuilder, it));
});
builder.transform(statement -> QueryOptionsUtil.addQueryOptions(statement, options));
});
return builder;
@@ -588,9 +580,7 @@ public class StatementFactory {
applyDeleteIfCondition(builder, criteriaDefinitions);
});
builder.onBuild(statementBuilder -> {
QueryOptionsUtil.addQueryOptions(statementBuilder, options);
});
builder.transform(statement -> QueryOptionsUtil.addQueryOptions(statement, options));
return builder;
}
@@ -651,7 +641,10 @@ public class StatementFactory {
select.onBuild(statementBuilder -> {
query.getPagingState().ifPresent(statementBuilder::setPagingState);
query.getQueryOptions().ifPresent(it -> QueryOptionsUtil.addQueryOptions(statementBuilder, it));
});
query.getQueryOptions().ifPresent(it -> {
select.transform(statement -> QueryOptionsUtil.addQueryOptions(statement, it));
});
return select;
@@ -839,8 +832,7 @@ public class StatementFactory {
Collection<Object> collection = (Collection<Object>) updateOp.getValue();
Assert.isTrue(collection.size() == 1, "RemoveOp must contain a single set element");
return Assignment.removeSetElement(updateOp.toCqlIdentifier(),
termFactory.create(collection.iterator().next()));
return Assignment.removeSetElement(updateOp.toCqlIdentifier(), termFactory.create(collection.iterator().next()));
}
if (updateOp.getValue() instanceof List) {
@@ -848,8 +840,7 @@ public class StatementFactory {
Collection<Object> collection = (Collection<Object>) updateOp.getValue();
Assert.isTrue(collection.size() == 1, "RemoveOp must contain a single list element");
return Assignment.removeListElement(updateOp.toCqlIdentifier(),
termFactory.create(collection.iterator().next()));
return Assignment.removeListElement(updateOp.toCqlIdentifier(), termFactory.create(collection.iterator().next()));
}
return Assignment.remove(updateOp.toCqlIdentifier(), termFactory.create(updateOp.getValue()));

View File

@@ -21,6 +21,7 @@ import java.time.Duration;
import java.time.Instant;
import java.util.concurrent.TimeUnit;
import org.springframework.data.cassandra.core.cql.ExecutionProfileResolver;
import org.springframework.data.cassandra.core.cql.WriteOptions;
import org.springframework.data.cassandra.core.query.CriteriaDefinition;
import org.springframework.data.cassandra.core.query.Filter;
@@ -28,7 +29,6 @@ import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import com.datastax.oss.driver.api.core.ConsistencyLevel;
import com.datastax.oss.driver.api.core.retry.RetryPolicy;
/**
* Extension to {@link WriteOptions} for use with {@code UPDATE} operations.
@@ -46,11 +46,12 @@ public class UpdateOptions extends WriteOptions {
private final @Nullable Filter ifCondition;
private UpdateOptions(@Nullable ConsistencyLevel consistencyLevel, @Nullable RetryPolicy retryPolicy,
@Nullable Boolean tracing, @Nullable Integer fetchSize, Duration readTimeout, Duration ttl,
@Nullable Long timestamp, boolean ifExists, @Nullable Filter ifCondition) {
private UpdateOptions(@Nullable ConsistencyLevel consistencyLevel, ExecutionProfileResolver executionProfileResolver,
@Nullable Integer pageSize, @Nullable ConsistencyLevel serialConsistencyLevel, Duration timeout, Duration ttl,
@Nullable Long timestamp, @Nullable Boolean tracing, boolean ifExists, @Nullable Filter ifCondition) {
super(consistencyLevel, retryPolicy, tracing, fetchSize, readTimeout, ttl, timestamp);
super(consistencyLevel, executionProfileResolver, pageSize, serialConsistencyLevel, timeout, ttl, timestamp,
tracing);
this.ifExists = ifExists;
this.ifCondition = ifCondition;
@@ -135,13 +136,20 @@ public class UpdateOptions extends WriteOptions {
}
/* (non-Javadoc)
* @see org.springframework.data.cassandra.core.cql.WriteOptions.WriteOptionsBuilder#retryPolicy(com.datastax.driver.core.policies.RetryPolicy)
* @see org.springframework.data.cassandra.core.cql.QueryOptions.QueryOptionsBuilder#executionProfile(String)
*/
@Override
@Deprecated
public UpdateOptionsBuilder retryPolicy(RetryPolicy driverRetryPolicy) {
public UpdateOptionsBuilder executionProfile(String profileName) {
super.executionProfile(profileName);
return this;
}
super.retryPolicy(driverRetryPolicy);
/* (non-Javadoc)
* @see org.springframework.data.cassandra.core.cql.QueryOptions.QueryOptionsBuilder#executionProfile(org.springframework.data.cassandra.core.cql.ExecutionProfileResolver)
*/
@Override
public UpdateOptionsBuilder executionProfile(ExecutionProfileResolver executionProfileResolver) {
super.executionProfile(executionProfileResolver);
return this;
}
@@ -188,6 +196,15 @@ public class UpdateOptions extends WriteOptions {
return this;
}
/* (non-Javadoc)
* @see org.springframework.data.cassandra.core.cql.QueryOptions.QueryOptionsBuilder#serialConsistencyLevel(com.datastax.oss.driver.api.core.ConsistencyLevel)
*/
@Override
public UpdateOptionsBuilder serialConsistencyLevel(ConsistencyLevel consistencyLevel) {
super.serialConsistencyLevel(consistencyLevel);
return this;
}
/* (non-Javadoc)
* @see org.springframework.data.cassandra.core.cql.WriteOptions.WriteOptionsBuilder#readTimeout(java.time.Duration)
*/
@@ -320,8 +337,9 @@ public class UpdateOptions extends WriteOptions {
*/
public UpdateOptions build() {
return new UpdateOptions(this.consistencyLevel, this.retryPolicy, this.tracing, this.pageSize, this.timeout,
this.ttl, this.timestamp, this.ifExists, this.ifCondition);
return new UpdateOptions(this.consistencyLevel, this.executionProfileResolver, this.pageSize,
this.serialConsistencyLevel, this.timeout, this.ttl, this.timestamp, this.tracing, this.ifExists,
this.ifCondition);
}
}
}

View File

@@ -54,6 +54,12 @@ public class CassandraAccessor implements InitializingBean {
private CqlExceptionTranslator exceptionTranslator = new CassandraExceptionTranslator();
/**
* If this variable is set to a value, it will be used for setting the {@code executionProfile} property on statements
* used for query processing.
*/
private ExecutionProfileResolver executionProfileResolver = ExecutionProfileResolver.none();
/**
* If this variable is set to a non-negative value, it will be used for setting the {@code pageSize} property on
* statements used for query processing.
@@ -67,10 +73,10 @@ public class CassandraAccessor implements InitializingBean {
private @Nullable ConsistencyLevel consistencyLevel;
/**
* If this variable is set to a value, it will be used for setting the {@code retryPolicy} property on statements used
* for query processing.
* If this variable is set to a value, it will be used for setting the {@code serial consistencyLevel} property on
* statements used for query processing.
*/
private @Deprecated @Nullable RetryPolicy retryPolicy;
private @Nullable ConsistencyLevel serialConsistencyLevel;
private @Nullable SessionFactory sessionFactory;
@@ -127,6 +133,40 @@ public class CassandraAccessor implements InitializingBean {
return this.exceptionTranslator;
}
/**
* Set the driver execution profile for this template.
*
* @see Statement#setExecutionProfileName(String)
* @see ExecutionProfileResolver
* @since 3.0
*/
public void setExecutionProfile(String profileName) {
setExecutionProfileResolver(ExecutionProfileResolver.from(profileName));
}
/**
* Set the {@link ExecutionProfileResolver} for this template.
*
* @see com.datastax.oss.driver.api.core.config.DriverExecutionProfile
* @see ExecutionProfileResolver
* @since 3.0
*/
public void setExecutionProfileResolver(ExecutionProfileResolver executionProfileResolver) {
Assert.notNull(executionProfileResolver, "ExecutionProfileResolver must not be null");
this.executionProfileResolver = executionProfileResolver;
}
/**
* @return the {@link ExecutionProfileResolver} specified for this template.
* @since 3.0
*/
public ExecutionProfileResolver getExecutionProfileResolver() {
return executionProfileResolver;
}
/**
* Set the fetch size for this template. This is important for processing large result sets: Setting this higher than
* the default value will increase processing speed at the cost of memory consumption; setting this lower can avoid
@@ -170,24 +210,23 @@ public class CassandraAccessor implements InitializingBean {
}
/**
* Set the retry policy for this template. This is important for defining behavior when a request fails.
* Set the serial consistency level for this template.
*
* @see RetryPolicy
* @deprecated since 3.0. Use driver execution profiles instead.
* @since 3.0
* @see Statement#setSerialConsistencyLevel(ConsistencyLevel)
* @see ConsistencyLevel
*/
@Deprecated
public void setRetryPolicy(@Nullable RetryPolicy retryPolicy) {
this.retryPolicy = retryPolicy;
public void setSerialConsistencyLevel(@Nullable ConsistencyLevel consistencyLevel) {
this.serialConsistencyLevel = consistencyLevel;
}
/**
* @return the {@link RetryPolicy} specified for this template.
* @deprecated since 3.0. Use driver execution profiles instead.
* @return the serial {@link ConsistencyLevel} specified for this template.
* @since 3.0
*/
@Nullable
@Deprecated
public RetryPolicy getRetryPolicy() {
return this.retryPolicy;
public ConsistencyLevel getSerialConsistencyLevel() {
return this.serialConsistencyLevel;
}
/**
@@ -263,22 +302,33 @@ public class CassandraAccessor implements InitializingBean {
* Prepare the given CQL Statement applying statement settings such as page size and consistency level.
*
* @param statement the CQL Statement to prepare
* @see #setPageSize(int)
* @see #setConsistencyLevel(ConsistencyLevel)
* @see #setSerialConsistencyLevel(ConsistencyLevel)
* @see #setPageSize(int)
* @see #setExecutionProfile(String)
* @see #setExecutionProfileResolver(ExecutionProfileResolver)
*/
protected Statement<?> applyStatementSettings(Statement<?> statement) {
Statement<?> statementToUse = statement;
ConsistencyLevel consistencyLevel = getConsistencyLevel();
ConsistencyLevel serialConsistencyLevel = getSerialConsistencyLevel();
int pageSize = getPageSize();
if (getFetchSize() > -1 && statement.getPageSize() < 0) {
statementToUse = statementToUse.setPageSize(getFetchSize());
if (consistencyLevel != null) {
statementToUse = statementToUse.setConsistencyLevel(consistencyLevel);
}
if (consistencyLevel != null && statementToUse.getConsistencyLevel() == null) {
statementToUse = statementToUse.setConsistencyLevel(getConsistencyLevel());
if (serialConsistencyLevel != null) {
statementToUse = statementToUse.setSerialConsistencyLevel(serialConsistencyLevel);
}
if (pageSize > -1) {
statementToUse = statementToUse.setPageSize(pageSize);
}
statementToUse = getExecutionProfileResolver().apply(statementToUse);
return statementToUse;
}

View File

@@ -0,0 +1,78 @@
/*
* Copyright 2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.cassandra.core.cql;
import org.springframework.util.Assert;
import com.datastax.oss.driver.api.core.config.DriverExecutionProfile;
import com.datastax.oss.driver.api.core.cql.Statement;
/**
* Resolver for a {@link com.datastax.oss.driver.api.core.config.DriverExecutionProfile} used with
* {@link com.datastax.oss.driver.api.core.cql.Statement#setExecutionProfileName(String)} or
* {@link com.datastax.oss.driver.api.core.cql.Statement#setExecutionProfile(DriverExecutionProfile)}.
*
* @author Mark Paluch
* @since 3.0
*/
@FunctionalInterface
public interface ExecutionProfileResolver {
/**
* Apply an execution profile based on the {@link Statement}.
*
* @param statement the statement to inspect and to apply the {@code driver execution profile} to.
* @return the statement with the profile applied.
*/
Statement<?> apply(Statement<?> statement);
/**
* Create a no-op {@link ExecutionProfileResolver} that preserves the {@link Statement} settings.
*
* @return no-op {@link ExecutionProfileResolver} that preserves the {@link Statement} settings.
*/
static ExecutionProfileResolver none() {
return statement -> statement;
}
/**
* Create a {@link ExecutionProfileResolver} from a {@link DriverExecutionProfile} to apply the profile object.
*
* @param driverExecutionProfile must not be {@literal null}.
* @return a {@link ExecutionProfileResolver} that applies the given {@link DriverExecutionProfile}.
* @see Statement#setExecutionProfile(DriverExecutionProfile)
*/
static ExecutionProfileResolver from(DriverExecutionProfile driverExecutionProfile) {
Assert.notNull(driverExecutionProfile, "DriverExecutionProfile must not be null");
return statement -> statement.setExecutionProfile(driverExecutionProfile);
}
/**
* Create a {@link ExecutionProfileResolver} from a {@code profileName}.
*
* @param profileName must not be {@literal null} or empty.
* @return a {@link ExecutionProfileResolver} that applies the given {@code profileName}.
* @see Statement#setExecutionProfileName(String)
*/
static ExecutionProfileResolver from(String profileName) {
Assert.hasText(profileName, "DriverExecutionProfile name must not be empty");
return statement -> statement.setExecutionProfileName(profileName);
}
}

View File

@@ -24,7 +24,7 @@ import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import com.datastax.oss.driver.api.core.ConsistencyLevel;
import com.datastax.oss.driver.api.core.retry.RetryPolicy;
import com.datastax.oss.driver.api.core.config.DriverExecutionProfile;
/**
* Cassandra Query Options for queries. {@link QueryOptions} allow tuning of various query options on a per-request
@@ -38,41 +38,28 @@ public class QueryOptions {
private static final QueryOptions EMPTY = QueryOptions.builder().build();
private final @Nullable Boolean tracing;
private final @Nullable ConsistencyLevel consistencyLevel;
private final Duration readTimeout;
private final ExecutionProfileResolver executionProfileResolver;
private final @Nullable Integer pageSize;
private final @Nullable RetryPolicy retryPolicy;
private final @Nullable ConsistencyLevel serialConsistencyLevel;
protected QueryOptions(@Nullable ConsistencyLevel consistencyLevel, @Nullable RetryPolicy retryPolicy,
@Nullable Boolean tracing, @Nullable Integer fetchSize, Duration readTimeout) {
private final Duration timeout;
private final @Nullable Boolean tracing;
protected QueryOptions(@Nullable ConsistencyLevel consistencyLevel, ExecutionProfileResolver executionProfileResolver,
@Nullable Integer pageSize, @Nullable ConsistencyLevel serialConsistencyLevel, Duration timeout,
@Nullable Boolean tracing) {
this.consistencyLevel = consistencyLevel;
this.retryPolicy = retryPolicy;
this.executionProfileResolver = executionProfileResolver;
this.pageSize = pageSize;
this.serialConsistencyLevel = serialConsistencyLevel;
this.timeout = timeout;
this.tracing = tracing;
this.pageSize = fetchSize;
this.readTimeout = readTimeout;
}
/**
* Creates new {@link QueryOptions} for the given {@link ConsistencyLevel} and {@link RetryPolicy}.
*
* @param consistencyLevel the consistency level, may be {@literal null}.
* @param retryPolicy the retry policy, may be {@literal null}.
* @deprecated since 2.0, use {@link #builder()}.
*/
@Deprecated
public QueryOptions(@Nullable ConsistencyLevel consistencyLevel, @Nullable RetryPolicy retryPolicy) {
this.consistencyLevel = consistencyLevel;
this.retryPolicy = retryPolicy;
this.tracing = false;
this.pageSize = null;
this.readTimeout = Duration.ofMillis(-1);
}
/**
@@ -106,7 +93,7 @@ public class QueryOptions {
}
/**
* @return the the driver {@link ConsistencyLevel}
* @return the the driver {@link ConsistencyLevel}.
* @since 1.5
*/
@Nullable
@@ -114,6 +101,14 @@ public class QueryOptions {
return this.consistencyLevel;
}
/**
* @return the the {@link ExecutionProfileResolver}.
* @since 3.0
*/
protected ExecutionProfileResolver getExecutionProfileResolver() {
return this.executionProfileResolver;
}
/**
* @return the number of rows to fetch per chunking request. May be {@literal null} if not set.
* @since 1.5
@@ -124,20 +119,33 @@ public class QueryOptions {
}
/**
* @return the read timeout in milliseconds. May be {@literal null} if not set.
* @return the command timeout. May be {@link Duration#isNegative() negative} if not set.
* @since 1.5
* @see com.datastax.oss.driver.api.core.cql.Statement#setTimeout(Duration)
* @deprecated since 3.0, use {@link #getTimeout()} instead.
*/
@Deprecated
protected Duration getReadTimeout() {
return this.readTimeout;
return getTimeout();
}
/**
* @return the driver {@link RetryPolicy}
* @since 1.5
* @return the command timeout. May be {@link Duration#isNegative() negative} if not set.
* @since 3.0
* @see com.datastax.oss.driver.api.core.cql.Statement#setTimeout(Duration)
*/
protected Duration getTimeout() {
return this.timeout;
}
/**
* @return the the serial {@link ConsistencyLevel}.
* @since 3.0
* @see com.datastax.oss.driver.api.core.cql.Statement#setSerialConsistencyLevel(ConsistencyLevel)
*/
@Nullable
protected RetryPolicy getRetryPolicy() {
return this.retryPolicy;
protected ConsistencyLevel getSerialConsistencyLevel() {
return this.serialConsistencyLevel;
}
/**
@@ -156,24 +164,27 @@ public class QueryOptions {
*/
public static class QueryOptionsBuilder {
protected @Nullable Boolean tracing;
protected @Nullable ConsistencyLevel consistencyLevel;
protected Duration timeout = Duration.ofMillis(-1);
protected ExecutionProfileResolver executionProfileResolver = ExecutionProfileResolver.none();
protected @Nullable Integer pageSize;
protected @Nullable RetryPolicy retryPolicy;
protected @Nullable ConsistencyLevel serialConsistencyLevel;
protected Duration timeout = Duration.ofMillis(-1);
protected @Nullable Boolean tracing;
QueryOptionsBuilder() {}
QueryOptionsBuilder(QueryOptions queryOptions) {
this.consistencyLevel = queryOptions.consistencyLevel;
this.executionProfileResolver = queryOptions.executionProfileResolver;
this.pageSize = queryOptions.pageSize;
this.timeout = queryOptions.readTimeout;
this.retryPolicy = queryOptions.retryPolicy;
this.serialConsistencyLevel = queryOptions.serialConsistencyLevel;
this.timeout = queryOptions.timeout;
this.tracing = queryOptions.tracing;
}
@@ -193,19 +204,29 @@ public class QueryOptions {
}
/**
* Sets the {@link RetryPolicy driver RetryPolicy} to use. Setting both ( {@link RetryPolicy} and {@link RetryPolicy
* driver RetryPolicy}) retry policies is not supported.
* Sets the {@code execution profile} to use.
*
* @param retryPolicy must not be {@literal null}.
* @param profileName must not be {@literal null} or empty.
* @return {@code this} {@link QueryOptionsBuilder}
* @deprecated since 3.0, use execution profiles instead.
* @since 3.0
* @see com.datastax.oss.driver.api.core.cql.Statement#setExecutionProfileName(String)
*/
@Deprecated
public QueryOptionsBuilder retryPolicy(RetryPolicy retryPolicy) {
public QueryOptionsBuilder executionProfile(String profileName) {
return executionProfile(ExecutionProfileResolver.from(profileName));
}
Assert.notNull(retryPolicy, "RetryPolicy must not be null");
/**
* Sets the {@link ExecutionProfileResolver} to use.
*
* @param executionProfileResolver must not be {@literal null}.
* @return {@code this} {@link QueryOptionsBuilder}
* @see com.datastax.oss.driver.api.core.cql.Statement#setExecutionProfile(DriverExecutionProfile)
*/
public QueryOptionsBuilder executionProfile(ExecutionProfileResolver executionProfileResolver) {
this.retryPolicy = retryPolicy;
Assert.notNull(executionProfileResolver, "ExecutionProfileResolver must not be null");
this.executionProfileResolver = executionProfileResolver;
return this;
}
@@ -301,6 +322,21 @@ public class QueryOptions {
return this;
}
/**
* Sets the serial {@link ConsistencyLevel} to use.
*
* @param consistencyLevel must not be {@literal null}.
* @return {@code this} {@link QueryOptionsBuilder}
*/
public QueryOptionsBuilder serialConsistencyLevel(ConsistencyLevel consistencyLevel) {
Assert.notNull(consistencyLevel, "Serial ConsistencyLevel must not be null");
this.serialConsistencyLevel = consistencyLevel;
return this;
}
/**
* Sets the request timeout. Overrides the default timeout.
*
@@ -347,7 +383,8 @@ public class QueryOptions {
* @return a new {@link QueryOptions} with the configured values
*/
public QueryOptions build() {
return new QueryOptions(this.consistencyLevel, this.retryPolicy, this.tracing, this.pageSize, this.timeout);
return new QueryOptions(this.consistencyLevel, this.executionProfileResolver, this.pageSize,
this.serialConsistencyLevel, this.timeout, this.tracing);
}
}
}

View File

@@ -19,7 +19,6 @@ import java.time.Duration;
import org.springframework.util.Assert;
import com.datastax.oss.driver.api.core.cql.SimpleStatementBuilder;
import com.datastax.oss.driver.api.core.cql.Statement;
import com.datastax.oss.driver.api.querybuilder.delete.Delete;
import com.datastax.oss.driver.api.querybuilder.delete.DeleteSelection;
@@ -52,12 +51,18 @@ public abstract class QueryOptionsUtil {
statementToUse = statementToUse.setConsistencyLevel(queryOptions.getConsistencyLevel());
}
statementToUse = queryOptions.getExecutionProfileResolver().apply(statementToUse);
if (queryOptions.getPageSize() != null) {
statementToUse = statementToUse.setPageSize(queryOptions.getPageSize());
}
if (!queryOptions.getReadTimeout().isNegative()) {
statementToUse = statementToUse.setTimeout(queryOptions.getReadTimeout());
if (queryOptions.getSerialConsistencyLevel() != null) {
statementToUse = statementToUse.setSerialConsistencyLevel(queryOptions.getSerialConsistencyLevel());
}
if (!queryOptions.getTimeout().isNegative()) {
statementToUse = statementToUse.setTimeout(queryOptions.getTimeout());
}
if (queryOptions.getTracing() != null) {
@@ -71,37 +76,6 @@ public abstract class QueryOptionsUtil {
return (T) statementToUse;
}
/**
* Add common {@link QueryOptions} to all types of queries.
*
* @param statement a {@link SimpleStatementBuilder}, must not be {@literal null}.
* @param queryOptions query options (e.g. consistency level) to add to the CQL statement.
*/
public static void addQueryOptions(SimpleStatementBuilder statementBuilder, QueryOptions queryOptions) {
Assert.notNull(statementBuilder, "SimpleStatementBuilder must not be null");
if (queryOptions.getConsistencyLevel() != null) {
statementBuilder.setConsistencyLevel(queryOptions.getConsistencyLevel());
}
if (queryOptions.getPageSize() != null) {
statementBuilder.setPageSize(queryOptions.getPageSize());
}
if (!queryOptions.getReadTimeout().isNegative()) {
statementBuilder.setTimeout(queryOptions.getReadTimeout());
}
if (queryOptions.getTracing() != null) {
if (queryOptions.getTracing()) {
statementBuilder.setTracing(true);
} else {
statementBuilder.setTracing(false);
}
}
}
/**
* Add common {@link WriteOptions} options to {@link Insert} CQL statements.
*

View File

@@ -87,18 +87,24 @@ public class ReactiveCqlTemplate extends ReactiveCassandraAccessor implements Re
*/
private int pageSize = -1;
/**
* If this variable is set to a value, it will be used for setting the {@code retryPolicy} property on statements used
* for query processing.
*/
private @Deprecated @Nullable RetryPolicy retryPolicy;
/**
* If this variable is set to a value, it will be used for setting the {@code consistencyLevel} property on statements
* used for query processing.
*/
private @Nullable ConsistencyLevel consistencyLevel;
/**
* If this variable is set to a value, it will be used for setting the {@code executionProfile} property on statements
* used for query processing.
*/
private ExecutionProfileResolver executionProfileResolver = ExecutionProfileResolver.none();
/**
* If this variable is set to a value, it will be used for setting the serial {@code consistencyLevel} property on
* statements used for query processing.
*/
private @Nullable ConsistencyLevel serialConsistencyLevel;
/**
* Construct a new {@link ReactiveCqlTemplate Note: The {@link ReactiveSessionFactory} has to be set before using the
* instance.
@@ -154,6 +160,40 @@ public class ReactiveCqlTemplate extends ReactiveCassandraAccessor implements Re
return consistencyLevel;
}
/**
* Set the driver execution profile for this template.
*
* @see Statement#setExecutionProfileName(String)
* @see ExecutionProfileResolver
* @since 3.0
*/
public void setExecutionProfile(String profileName) {
setExecutionProfileResolver(ExecutionProfileResolver.from(profileName));
}
/**
* Set the {@link ExecutionProfileResolver} for this template.
*
* @see com.datastax.oss.driver.api.core.config.DriverExecutionProfile
* @see ExecutionProfileResolver
* @since 3.0
*/
public void setExecutionProfileResolver(ExecutionProfileResolver executionProfileResolver) {
Assert.notNull(executionProfileResolver, "ExecutionProfileResolver must not be null");
this.executionProfileResolver = executionProfileResolver;
}
/**
* @return the {@link ExecutionProfileResolver} specified for this {@link ReactiveCqlTemplate}.
* @since 3.0
*/
public ExecutionProfileResolver getExecutionProfileResolver() {
return executionProfileResolver;
}
/**
* Set the fetch size for this template. This is important for processing large result sets: Setting this higher than
* the default value will increase processing speed at the cost of memory consumption; setting this lower can avoid
@@ -197,24 +237,23 @@ public class ReactiveCqlTemplate extends ReactiveCassandraAccessor implements Re
}
/**
* Set the retry policy for this template. This is important for defining behavior when a request fails.
* Set the serial consistency level for this template.
*
* @see RetryPolicy
* @deprecated since 3.0. Use driver execution profiles instead.
* @since 3.0
* @see Statement#setSerialConsistencyLevel(ConsistencyLevel)
* @see ConsistencyLevel
*/
@Deprecated
public void setRetryPolicy(@Nullable RetryPolicy retryPolicy) {
this.retryPolicy = retryPolicy;
public void setSerialConsistencyLevel(@Nullable ConsistencyLevel consistencyLevel) {
this.serialConsistencyLevel = consistencyLevel;
}
/**
* @return the {@link RetryPolicy} specified for this template.
* @deprecated since 3.0. Use driver execution profiles instead.
* @return the serial {@link ConsistencyLevel} specified for this template.
* @since 3.0
*/
@Nullable
@Deprecated
public RetryPolicy getRetryPolicy() {
return this.retryPolicy;
public ConsistencyLevel getSerialConsistencyLevel() {
return this.serialConsistencyLevel;
}
// -------------------------------------------------------------------------
@@ -778,22 +817,33 @@ public class ReactiveCqlTemplate extends ReactiveCassandraAccessor implements Re
* Prepare the given CQL Statement applying statement settings such as page size and consistency level.
*
* @param stmt the CQL Statement to prepare
* @see #setPageSize(int)
* @see #setConsistencyLevel(ConsistencyLevel)
* @see #setSerialConsistencyLevel(ConsistencyLevel)
* @see #setPageSize(int)
* @see #setExecutionProfile(String)
* @see #setExecutionProfileResolver(ExecutionProfileResolver)
*/
protected Statement<?> applyStatementSettings(Statement<?> statement) {
Statement<?> statementToUse = statement;
ConsistencyLevel consistencyLevel = getConsistencyLevel();
ConsistencyLevel serialConsistencyLevel = getSerialConsistencyLevel();
int pageSize = getPageSize();
if (getFetchSize() > -1 && statement.getPageSize() < 0) {
statementToUse = statementToUse.setPageSize(getFetchSize());
if (consistencyLevel != null) {
statementToUse = statementToUse.setConsistencyLevel(consistencyLevel);
}
if (consistencyLevel != null && statementToUse.getConsistencyLevel() == null) {
statementToUse = statementToUse.setConsistencyLevel(getConsistencyLevel());
if (serialConsistencyLevel != null) {
statementToUse = statementToUse.setSerialConsistencyLevel(serialConsistencyLevel);
}
if (pageSize > -1) {
statementToUse = statementToUse.setPageSize(pageSize);
}
statementToUse = getExecutionProfileResolver().apply(statementToUse);
return statementToUse;
}

View File

@@ -25,10 +25,9 @@ import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import com.datastax.oss.driver.api.core.ConsistencyLevel;
import com.datastax.oss.driver.api.core.retry.RetryPolicy;
/**
* Cassandra Write Options are an extension to {@link QueryOptions} for write operations. {@link WriteOptions}allow
* Cassandra Write Options are an extension to {@link QueryOptions} for write operations. {@link WriteOptions} allow
* tuning of various query options on a per-request level. Only options that are set are applied to queries.
*
* @author David Webb
@@ -44,41 +43,11 @@ public class WriteOptions extends QueryOptions {
private final Duration ttl;
private final @Nullable Long timestamp;
/**
* Creates new {@link WriteOptions} for the given {@link ConsistencyLevel} and {@link RetryPolicy}.
*
* @param consistencyLevel the consistency level, may be {@literal null}.
* @param retryPolicy the retry policy, may be {@literal null}.
* @deprecated since 2.0, use {@link #builder()} or {@link #empty()}.
*/
@Deprecated
public WriteOptions(@Nullable ConsistencyLevel consistencyLevel, @Nullable RetryPolicy retryPolicy) {
this(consistencyLevel, retryPolicy, null);
}
protected WriteOptions(@Nullable ConsistencyLevel consistencyLevel, ExecutionProfileResolver executionProfileResolver,
@Nullable Integer pageSize, @Nullable ConsistencyLevel serialConsistencyLevel, Duration timeout, Duration ttl,
@Nullable Long timestamp, @Nullable Boolean tracing) {
/**
* Creates new {@link WriteOptions} for the given {@link ConsistencyLevel}, {@link RetryPolicy} and {@code ttl}.
*
* @param consistencyLevel the consistency level, may be {@literal null}.
* @param retryPolicy the retry policy, may be {@literal null}.
* @param ttl the ttl, may be {@literal null}.
* @deprecated since 2.0, use {@link #builder()}.
*/
@Deprecated
public WriteOptions(@Nullable ConsistencyLevel consistencyLevel, @Nullable RetryPolicy retryPolicy,
@Nullable Integer ttl) {
super(consistencyLevel, retryPolicy);
this.ttl = ttl == null ? Duration.ofMillis(-1) : Duration.ofSeconds(ttl);
this.timestamp = null;
}
protected WriteOptions(@Nullable ConsistencyLevel consistencyLevel, @Nullable RetryPolicy retryPolicy,
@Nullable Boolean tracing, @Nullable Integer fetchSize, Duration readTimeout, Duration ttl,
@Nullable Long timestamp) {
super(consistencyLevel, retryPolicy, tracing, fetchSize, readTimeout);
super(consistencyLevel, executionProfileResolver, pageSize, serialConsistencyLevel, timeout, tracing);
this.ttl = ttl;
this.timestamp = timestamp;
@@ -154,7 +123,7 @@ public class WriteOptions extends QueryOptions {
}
/* (non-Javadoc)
* @see org.springframework.data.cassandra.core.cql.QueryOptions.QueryOptionsBuilder#consistencyLevel(com.datastax.driver.core.ConsistencyLevel)
* @see org.springframework.data.cassandra.core.cql.QueryOptions.QueryOptionsBuilder#consistencyLevel(com.datastax.oss.driver.api.core.ConsistencyLevel)
*/
@Override
public WriteOptionsBuilder consistencyLevel(ConsistencyLevel consistencyLevel) {
@@ -164,13 +133,20 @@ public class WriteOptions extends QueryOptions {
}
/* (non-Javadoc)
* @see org.springframework.data.cassandra.core.cql.QueryOptions.QueryOptionsBuilder#retryPolicy(com.datastax.oss.driver.api.core.retry.RetryPolicy)
* @see org.springframework.data.cassandra.core.cql.QueryOptions.QueryOptionsBuilder#executionProfile(String)
*/
@Override
@Deprecated
public WriteOptionsBuilder retryPolicy(RetryPolicy driverRetryPolicy) {
public WriteOptionsBuilder executionProfile(String profileName) {
super.executionProfile(profileName);
return this;
}
super.retryPolicy(driverRetryPolicy);
/* (non-Javadoc)
* @see org.springframework.data.cassandra.core.cql.QueryOptions.QueryOptionsBuilder#executionProfile(org.springframework.data.cassandra.core.cql.ExecutionProfileResolver)
*/
@Override
public WriteOptionsBuilder executionProfile(ExecutionProfileResolver executionProfileResolver) {
super.executionProfile(executionProfileResolver);
return this;
}
@@ -217,6 +193,15 @@ public class WriteOptions extends QueryOptions {
return this;
}
/* (non-Javadoc)
* @see org.springframework.data.cassandra.core.cql.QueryOptions.QueryOptionsBuilder#serialConsistencyLevel(com.datastax.oss.driver.api.core.ConsistencyLevel)
*/
@Override
public WriteOptionsBuilder serialConsistencyLevel(ConsistencyLevel consistencyLevel) {
super.serialConsistencyLevel(consistencyLevel);
return this;
}
/* (non-Javadoc)
* @see org.springframework.data.cassandra.core.cql.QueryOptions.QueryOptionsBuilder#readTimeout(java.time.Duration)
*/
@@ -318,8 +303,8 @@ public class WriteOptions extends QueryOptions {
* @return a new {@link WriteOptions} with the configured values
*/
public WriteOptions build() {
return new WriteOptions(this.consistencyLevel, this.retryPolicy, this.tracing, this.pageSize, this.timeout,
this.ttl, this.timestamp);
return new WriteOptions(this.consistencyLevel, this.executionProfileResolver, this.pageSize,
this.serialConsistencyLevel, this.timeout, this.ttl, this.timestamp, this.tracing);
}
}
}

View File

@@ -74,6 +74,7 @@ public class StatementBuilder<S extends BuildableQuery> {
private List<BuilderRunnable<S>> queryActions = new ArrayList<>();
private List<Consumer<SimpleStatementBuilder>> onBuild = new ArrayList<>();
private List<UnaryOperator<SimpleStatement>> onBuilt = new ArrayList<>();
private StatementBuilder(S statement) {
this.statement = statement;
@@ -138,6 +139,22 @@ public class StatementBuilder<S extends BuildableQuery> {
return this;
}
/**
* Add behavior after the {@link SimpleStatement} has been built. The {@link UnaryOperator} gets invoked with a
* {@link SimpleStatement} allowing association of the final statement with additional settings. The
* {@link UnaryOperator} is applied on {@link #build()}.
*
* @param mappingFunction the {@link UnaryOperator} function that gets notified on {@link #build()}.
* @return {@code this} {@link StatementBuilder}.
*/
public StatementBuilder<S> transform(UnaryOperator<SimpleStatement> mappingFunction) {
Assert.notNull(mappingFunction, "Mapping function must not be null");
onBuilt.add(mappingFunction);
return this;
}
/**
* Build a {@link SimpleStatement statement} by applying builder and bind functions using the default
* {@link CodecRegistry} and {@link ParameterHandling#INLINE} parameter rendering.
@@ -182,7 +199,7 @@ public class StatementBuilder<S extends BuildableQuery> {
statement = runnable.run(statement, termFactory);
}
return onBuild(statement.builder()).build();
return StatementBuilder.this.build(statement.builder());
}
if (parameterHandling == ParameterHandling.BY_INDEX) {
@@ -197,7 +214,7 @@ public class StatementBuilder<S extends BuildableQuery> {
statement = runnable.run(statement, termFactory);
}
return onBuild(statement.builder().addPositionalValues(values)).build();
return build(statement.builder().addPositionalValues(values));
}
if (parameterHandling == ParameterHandling.BY_NAME) {
@@ -216,12 +233,23 @@ public class StatementBuilder<S extends BuildableQuery> {
SimpleStatementBuilder builder = statement.builder();
values.forEach(builder::addNamedValue);
return onBuild(builder).build();
return build(builder);
}
throw new UnsupportedOperationException(String.format("ParameterHandling %s not supported", parameterHandling));
}
private SimpleStatement build(SimpleStatementBuilder builder) {
SimpleStatement statmentToUse = onBuild(builder).build();
for (UnaryOperator<SimpleStatement> operator : onBuilt) {
statmentToUse = operator.apply(statmentToUse);
}
return statmentToUse;
}
private static Term toLiteralTerms(@Nullable Object value, CodecRegistry codecRegistry) {
if (value instanceof List) {

View File

@@ -15,7 +15,7 @@
*/
package org.springframework.data.cassandra.core;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.*;
import java.time.Duration;
import java.time.Instant;
@@ -24,6 +24,8 @@ import org.junit.Test;
import org.springframework.data.cassandra.core.query.Query;
import com.datastax.oss.driver.api.core.DefaultConsistencyLevel;
/**
* Unit tests for {@link DeleteOptions}.
*
@@ -31,7 +33,7 @@ import org.springframework.data.cassandra.core.query.Query;
*/
public class DeleteOptionsUnitTests {
@Test // DATACASS-575
@Test // DATACASS-575, DATACASS-708
public void shouldConfigureDeleteOptions() {
Instant now = Instant.ofEpochSecond(1234);
@@ -40,8 +42,11 @@ public class DeleteOptionsUnitTests {
.ttl(10) //
.timestamp(now) //
.withIfExists() //
.executionProfile("foo") //
.serialConsistencyLevel(DefaultConsistencyLevel.LOCAL_ONE) //
.build();
assertThat(deleteOptions.getTtl()).isEqualTo(Duration.ofSeconds(10));
assertThat(deleteOptions.getTimestamp()).isEqualTo(now.toEpochMilli() * 1000);
assertThat(deleteOptions.isIfExists()).isTrue();

View File

@@ -24,6 +24,8 @@ import java.time.ZoneOffset;
import org.junit.Test;
import com.datastax.oss.driver.api.core.DefaultConsistencyLevel;
/**
* Unit tests for {@link InsertOptions}.
*
@@ -32,12 +34,18 @@ import org.junit.Test;
*/
public class InsertOptionsUnitTests {
@Test // DATACASS-250, DATACASS-155
@Test // DATACASS-250, DATACASS-155, DATACASS-708
public void shouldConfigureInsertOptions() {
Instant now = LocalDateTime.now().toInstant(ZoneOffset.UTC);
InsertOptions insertOptions = InsertOptions.builder().ttl(10).timestamp(now).withIfNotExists().build();
InsertOptions insertOptions = InsertOptions.builder() //
.ttl(10) //
.timestamp(now) //
.withIfNotExists() //
.executionProfile("foo") //
.serialConsistencyLevel(DefaultConsistencyLevel.LOCAL_ONE) //
.build();
assertThat(insertOptions.getTtl()).isEqualTo(Duration.ofSeconds(10));
assertThat(insertOptions.getTimestamp()).isEqualTo(now.toEpochMilli() * 1000);

View File

@@ -30,6 +30,7 @@ import org.springframework.data.annotation.Id;
import org.springframework.data.cassandra.core.convert.CassandraConverter;
import org.springframework.data.cassandra.core.convert.MappingCassandraConverter;
import org.springframework.data.cassandra.core.convert.UpdateMapper;
import org.springframework.data.cassandra.core.cql.QueryOptions;
import org.springframework.data.cassandra.core.cql.WriteOptions;
import org.springframework.data.cassandra.core.cql.util.StatementBuilder;
import org.springframework.data.cassandra.core.cql.util.StatementBuilder.ParameterHandling;
@@ -42,6 +43,8 @@ import org.springframework.data.cassandra.core.query.Update;
import org.springframework.data.cassandra.domain.Group;
import org.springframework.data.domain.Sort;
import com.datastax.oss.driver.api.core.DefaultConsistencyLevel;
import com.datastax.oss.driver.api.core.cql.SimpleStatement;
import com.datastax.oss.driver.api.querybuilder.delete.Delete;
import com.datastax.oss.driver.api.querybuilder.insert.RegularInsert;
import com.datastax.oss.driver.api.querybuilder.select.Select;
@@ -71,6 +74,22 @@ public class StatementFactoryUnitTests {
assertThat(select.build(ParameterHandling.INLINE).getQuery()).isEqualTo("SELECT * FROM group");
}
@Test // DATACASS-708
public void selectShouldApplyQueryOptions() {
QueryOptions queryOptions = QueryOptions.builder() //
.executionProfile("foo") //
.serialConsistencyLevel(DefaultConsistencyLevel.QUORUM) //
.build();
StatementBuilder<Select> select = statementFactory.select(Query.empty().queryOptions(queryOptions),
converter.getMappingContext().getRequiredPersistentEntity(Group.class));
SimpleStatement statement = select.build();
assertThat(statement.getExecutionProfileName()).isEqualTo("foo");
assertThat(statement.getSerialConsistencyLevel()).isEqualTo(DefaultConsistencyLevel.QUORUM);
}
@Test // DATACASS-343
public void shouldMapSelectQueryWithColumnsAndCriteria() {
@@ -149,6 +168,25 @@ public class StatementFactoryUnitTests {
.isEqualTo("DELETE FROM group USING TIMESTAMP 1234 WHERE foo='bar'");
}
@Test // DATACASS-708
public void deleteShouldApplyQueryOptions() {
Person person = new Person();
person.id = "foo";
QueryOptions queryOptions = QueryOptions.builder() //
.executionProfile("foo") //
.serialConsistencyLevel(DefaultConsistencyLevel.QUORUM) //
.build();
StatementBuilder<Delete> delete = statementFactory.delete(Query.empty().queryOptions(queryOptions),
converter.getMappingContext().getRequiredPersistentEntity(Group.class));
SimpleStatement statement = delete.build();
assertThat(statement.getExecutionProfileName()).isEqualTo("foo");
assertThat(statement.getSerialConsistencyLevel()).isEqualTo(DefaultConsistencyLevel.QUORUM);
}
@Test // DATACASS-656
public void shouldCreateInsert() {
@@ -160,6 +198,24 @@ public class StatementFactoryUnitTests {
assertThat(insert.build(ParameterHandling.INLINE).getQuery()).isEqualTo("INSERT INTO person (id) VALUES ('foo')");
}
@Test // DATACASS-708
public void insertShouldApplyQueryOptions() {
Person person = new Person();
person.id = "foo";
WriteOptions queryOptions = WriteOptions.builder() //
.executionProfile("foo") //
.serialConsistencyLevel(DefaultConsistencyLevel.QUORUM) //
.build();
StatementBuilder<RegularInsert> insert = statementFactory.insert(person, queryOptions);
SimpleStatement statement = insert.build();
assertThat(statement.getExecutionProfileName()).isEqualTo("foo");
assertThat(statement.getSerialConsistencyLevel()).isEqualTo(DefaultConsistencyLevel.QUORUM);
}
@Test // DATACASS-656
public void shouldCreateInsertIfNotExists() {
@@ -387,6 +443,24 @@ public class StatementFactoryUnitTests {
.isEqualTo("UPDATE person SET first_name='baz' WHERE foo='bar' IF foo='baz'");
}
@Test // DATACASS-708
public void updateShouldApplyQueryOptions() {
UpdateOptions queryOptions = UpdateOptions.builder() //
.executionProfile("foo") //
.serialConsistencyLevel(DefaultConsistencyLevel.QUORUM) //
.build();
Query query = Query.query(Criteria.where("foo").is("bar")).queryOptions(queryOptions);
StatementBuilder<com.datastax.oss.driver.api.querybuilder.update.Update> update = statementFactory.update(query,
Update.empty().set("firstName", "baz"), personEntity);
SimpleStatement statement = update.build();
assertThat(statement.getExecutionProfileName()).isEqualTo("foo");
assertThat(statement.getSerialConsistencyLevel()).isEqualTo(DefaultConsistencyLevel.QUORUM);
}
@Test // DATACASS-656
public void shouldCreateSetUpdateFromObject() {
@@ -470,6 +544,27 @@ public class StatementFactoryUnitTests {
.isEqualTo("UPDATE person SET first_name=NULL, list=[], map=NULL, number=NULL, set_col={} WHERE id='foo'");
}
@Test // DATACASS-708
public void updateObjectShouldApplyQueryOptions() {
WriteOptions queryOptions = WriteOptions.builder() //
.executionProfile("foo") //
.serialConsistencyLevel(DefaultConsistencyLevel.QUORUM) //
.build();
Person person = new Person();
person.id = "foo";
person.set = Collections.emptySet();
person.list = Collections.emptyList();
StatementBuilder<com.datastax.oss.driver.api.querybuilder.update.Update> update = statementFactory.update(person,
queryOptions);
SimpleStatement statement = update.build();
assertThat(statement.getExecutionProfileName()).isEqualTo("foo");
assertThat(statement.getSerialConsistencyLevel()).isEqualTo(DefaultConsistencyLevel.QUORUM);
}
@Test // DATACASS-512
public void shouldCreateCountQuery() {

View File

@@ -15,7 +15,7 @@
*/
package org.springframework.data.cassandra.core;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.*;
import java.time.Duration;
import java.time.Instant;
@@ -24,6 +24,8 @@ import org.junit.Test;
import org.springframework.data.cassandra.core.query.Query;
import com.datastax.oss.driver.api.core.DefaultConsistencyLevel;
/**
* Unit tests for {@link UpdateOptions}.
*
@@ -32,7 +34,7 @@ import org.springframework.data.cassandra.core.query.Query;
*/
public class UpdateOptionsUnitTests {
@Test // DATACASS-250, DATACASS-155
@Test // DATACASS-250, DATACASS-155, DATACASS-708
public void shouldConfigureUpdateOptions() {
Instant now = Instant.ofEpochSecond(1234);
@@ -40,6 +42,8 @@ public class UpdateOptionsUnitTests {
UpdateOptions updateOptions = UpdateOptions.builder() //
.ttl(10) //
.timestamp(now) //
.executionProfile("foo") //
.serialConsistencyLevel(DefaultConsistencyLevel.LOCAL_ONE) //
.withIfExists() //
.build();

View File

@@ -39,6 +39,7 @@ import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.dao.IncorrectResultSizeDataAccessException;
import org.springframework.data.cassandra.CassandraConnectionFailureException;
import org.springframework.data.cassandra.CassandraInvalidQueryException;
import org.springframework.lang.Nullable;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.util.concurrent.ListenableFuture;
@@ -121,7 +122,7 @@ public class AsyncCqlTemplateUnitTests {
@Test // DATACASS-292
public void executeCqlShouldCallExecution() {
doTestStrings(null, null, asyncCqlTemplate -> {
doTestStrings(asyncCqlTemplate -> {
asyncCqlTemplate.execute("SELECT * from USERS");
@@ -143,7 +144,7 @@ public class AsyncCqlTemplateUnitTests {
@Test // DATACASS-292
public void queryForResultSetShouldCallExecution() {
doTestStrings(null, null, asyncCqlTemplate -> {
doTestStrings(asyncCqlTemplate -> {
AsyncResultSet resultSet = getUninterruptibly(asyncCqlTemplate.queryForResultSet("SELECT * from USERS"));
@@ -155,7 +156,7 @@ public class AsyncCqlTemplateUnitTests {
@Test // DATACASS-292
public void queryWithResultSetExtractorShouldCallExecution() {
doTestStrings(null, null, asyncCqlTemplate -> {
doTestStrings(asyncCqlTemplate -> {
List<String> rows = getUninterruptibly(
asyncCqlTemplate.query("SELECT * from USERS", (row, index) -> row.getString(0)));
@@ -298,7 +299,7 @@ public class AsyncCqlTemplateUnitTests {
@Test // DATACASS-292
public void executeStatementShouldCallExecution() {
doTestStrings(null, null, asyncCqlTemplate -> {
doTestStrings(asyncCqlTemplate -> {
asyncCqlTemplate.execute(SimpleStatement.newInstance("SELECT * from USERS"));
@@ -320,7 +321,7 @@ public class AsyncCqlTemplateUnitTests {
@Test // DATACASS-292
public void queryForResultStatementSetShouldCallExecution() {
doTestStrings(null, null, asyncCqlTemplate -> {
doTestStrings(asyncCqlTemplate -> {
ListenableFuture<AsyncResultSet> future = asyncCqlTemplate
.queryForResultSet(SimpleStatement.newInstance("SELECT * from USERS"));
@@ -333,7 +334,7 @@ public class AsyncCqlTemplateUnitTests {
@Test // DATACASS-292
public void queryWithResultSetStatementExtractorShouldCallExecution() {
doTestStrings(null, null, asyncCqlTemplate -> {
doTestStrings(asyncCqlTemplate -> {
ListenableFuture<List<String>> future = asyncCqlTemplate.query(SimpleStatement.newInstance("SELECT * from USERS"),
(row, index) -> row.getString(0));
@@ -482,7 +483,7 @@ public class AsyncCqlTemplateUnitTests {
@Test // DATACASS-292
public void queryPreparedStatementWithCallbackShouldCallExecution() {
doTestStrings(null, null, asyncCqlTemplate -> {
doTestStrings(asyncCqlTemplate -> {
ListenableFuture<CompletionStage<AsyncResultSet>> futureOfFuture = asyncCqlTemplate.execute("SELECT * from USERS",
(session, ps) -> session.executeAsync(ps.bind("A")));
@@ -498,7 +499,7 @@ public class AsyncCqlTemplateUnitTests {
@Test // DATACASS-292
public void executePreparedStatementWithCallbackShouldCallExecution() {
doTestStrings(null, null, asyncCqlTemplate -> {
doTestStrings(asyncCqlTemplate -> {
when(this.preparedStatement.bind("White")).thenReturn(this.boundStatement);
when(this.resultSet.wasApplied()).thenReturn(true);
@@ -756,7 +757,11 @@ public class AsyncCqlTemplateUnitTests {
assertThat(getUninterruptibly(future)).isTrue();
}
private <T> void doTestStrings(Integer fetchSize, ConsistencyLevel consistencyLevel,
private void doTestStrings(Consumer<AsyncCqlTemplate> cqlTemplateConsumer) {
doTestStrings(null, null, cqlTemplateConsumer);
}
private void doTestStrings(@Nullable Integer fetchSize, @Nullable ConsistencyLevel consistencyLevel,
Consumer<AsyncCqlTemplate> cqlTemplateConsumer) {
String[] results = { "Walter", "Hank", " Jesse" };
@@ -783,24 +788,12 @@ public class AsyncCqlTemplateUnitTests {
Statement statement = statementArgumentCaptor.getValue();
if (statement instanceof PreparedStatement || statement instanceof BoundStatement) {
if (fetchSize != null) {
assertThat(statement.getPageSize()).isEqualTo(fetchSize.intValue());
}
if (fetchSize != null) {
verify(statement).setPageSize(fetchSize.intValue());
}
if (consistencyLevel != null) {
verify(statement).setConsistencyLevel(consistencyLevel);
}
} else {
if (fetchSize != null) {
assertThat(statement.getPageSize()).isEqualTo(fetchSize.intValue());
}
if (consistencyLevel != null) {
assertThat(statement.getConsistencyLevel()).isEqualTo(consistencyLevel);
}
if (consistencyLevel != null) {
assertThat(statement.getConsistencyLevel()).isEqualTo(consistencyLevel);
}
}

View File

@@ -36,6 +36,7 @@ import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.dao.IncorrectResultSizeDataAccessException;
import org.springframework.data.cassandra.CassandraConnectionFailureException;
import org.springframework.data.cassandra.CassandraInvalidQueryException;
import org.springframework.lang.Nullable;
import com.datastax.oss.driver.api.core.ConsistencyLevel;
import com.datastax.oss.driver.api.core.CqlSession;
@@ -112,7 +113,7 @@ public class CqlTemplateUnitTests {
@Test // DATACASS-292
public void executeCqlShouldCallExecution() {
doTestStrings(null, null, cqlTemplate -> {
doTestStrings(cqlTemplate -> {
cqlTemplate.execute("SELECT * from USERS");
@@ -123,7 +124,7 @@ public class CqlTemplateUnitTests {
@Test // DATACASS-292
public void executeCqlWithArgumentsShouldCallExecution() {
doTestStrings(5, DefaultConsistencyLevel.ONE, cqlTemplate -> {
doTestStrings(5, DefaultConsistencyLevel.ONE, null, "foo", cqlTemplate -> {
cqlTemplate.execute("SELECT * from USERS");
@@ -134,7 +135,7 @@ public class CqlTemplateUnitTests {
@Test // DATACASS-292
public void queryForResultSetShouldCallExecution() {
doTestStrings(null, null, cqlTemplate -> {
doTestStrings(cqlTemplate -> {
ResultSet resultSet = cqlTemplate.queryForResultSet("SELECT * from USERS");
@@ -146,7 +147,7 @@ public class CqlTemplateUnitTests {
@Test // DATACASS-292
public void queryWithResultSetExtractorShouldCallExecution() {
doTestStrings(null, null, cqlTemplate -> {
doTestStrings(cqlTemplate -> {
List<String> rows = cqlTemplate.query("SELECT * from USERS", (row, index) -> row.getString(0));
@@ -158,7 +159,7 @@ public class CqlTemplateUnitTests {
@Test // DATACASS-292
public void queryWithResultSetExtractorWithArgumentsShouldCallExecution() {
doTestStrings(5, ConsistencyLevel.ONE, cqlTemplate -> {
doTestStrings(5, ConsistencyLevel.ONE, ConsistencyLevel.EACH_QUORUM, "foo", cqlTemplate -> {
List<String> rows = cqlTemplate.query("SELECT * from USERS", (row, index) -> row.getString(0));
@@ -274,7 +275,7 @@ public class CqlTemplateUnitTests {
@Test // DATACASS-292
public void executeStatementShouldCallExecution() {
doTestStrings(null, null, cqlTemplate -> {
doTestStrings(cqlTemplate -> {
cqlTemplate.execute(SimpleStatement.newInstance("SELECT * from USERS"));
@@ -285,7 +286,7 @@ public class CqlTemplateUnitTests {
@Test // DATACASS-292
public void executeStatementWithArgumentsShouldCallExecution() {
doTestStrings(5, ConsistencyLevel.ONE, cqlTemplate -> {
doTestStrings(5, ConsistencyLevel.ONE, null, "foo", cqlTemplate -> {
cqlTemplate.execute(SimpleStatement.newInstance("SELECT * from USERS"));
@@ -296,7 +297,7 @@ public class CqlTemplateUnitTests {
@Test // DATACASS-292
public void queryForResultStatementSetShouldCallExecution() {
doTestStrings(null, null, cqlTemplate -> {
doTestStrings(cqlTemplate -> {
ResultSet resultSet = cqlTemplate.queryForResultSet(SimpleStatement.newInstance("SELECT * from USERS"));
@@ -308,7 +309,7 @@ public class CqlTemplateUnitTests {
@Test // DATACASS-292
public void queryWithResultSetStatementExtractorShouldCallExecution() {
doTestStrings(null, null, cqlTemplate -> {
doTestStrings(cqlTemplate -> {
List<String> result = cqlTemplate.query(SimpleStatement.newInstance("SELECT * from USERS"),
(row, index) -> row.getString(0));
@@ -321,7 +322,7 @@ public class CqlTemplateUnitTests {
@Test // DATACASS-292
public void queryWithResultSetStatementExtractorWithArgumentsShouldCallExecution() {
doTestStrings(5, ConsistencyLevel.ONE, cqlTemplate -> {
doTestStrings(5, ConsistencyLevel.ONE, null, "foo", cqlTemplate -> {
List<String> result = cqlTemplate.query(SimpleStatement.newInstance("SELECT * from USERS"),
(row, index) -> row.getString(0));
@@ -441,7 +442,7 @@ public class CqlTemplateUnitTests {
@Test // DATACASS-292
public void queryPreparedStatementWithCallbackShouldCallExecution() {
doTestStrings(null, null, cqlTemplate -> {
doTestStrings(cqlTemplate -> {
ResultSet resultSet = cqlTemplate.execute("SELECT * from USERS", (session, ps) -> session.execute(ps.bind("A")));
@@ -456,7 +457,7 @@ public class CqlTemplateUnitTests {
@Test // DATACASS-292
public void executePreparedStatementWithCallbackShouldCallExecution() {
doTestStrings(null, null, cqlTemplate -> {
doTestStrings(cqlTemplate -> {
when(this.preparedStatement.bind("White")).thenReturn(this.boundStatement);
when(this.resultSet.wasApplied()).thenReturn(true);
@@ -678,7 +679,12 @@ public class CqlTemplateUnitTests {
assertThat(applied).isTrue();
}
private <T> void doTestStrings(Integer fetchSize, ConsistencyLevel consistencyLevel,
private void doTestStrings(Consumer<CqlTemplate> cqlTemplateConsumer) {
doTestStrings(null, null, null, null, cqlTemplateConsumer);
}
private void doTestStrings(@Nullable Integer fetchSize, @Nullable ConsistencyLevel consistencyLevel,
@Nullable ConsistencyLevel serialConsistencyLevel, @Nullable String executionProfile,
Consumer<CqlTemplate> cqlTemplateConsumer) {
String[] results = { "Walter", "Hank", " Jesse" };
@@ -701,6 +707,14 @@ public class CqlTemplateUnitTests {
template.setConsistencyLevel(consistencyLevel);
}
if (serialConsistencyLevel != null) {
template.setSerialConsistencyLevel(serialConsistencyLevel);
}
if (executionProfile != null) {
template.setExecutionProfile(executionProfile);
}
cqlTemplateConsumer.accept(template);
ArgumentCaptor<Statement> statementArgumentCaptor = ArgumentCaptor.forClass(Statement.class);
@@ -708,24 +722,20 @@ public class CqlTemplateUnitTests {
Statement statement = statementArgumentCaptor.getValue();
if (statement instanceof PreparedStatement || statement instanceof BoundStatement) {
if (fetchSize != null) {
assertThat(statement.getPageSize()).isEqualTo(fetchSize.intValue());
}
if (fetchSize != null) {
verify(statement).setPageSize(fetchSize.intValue());
}
if (consistencyLevel != null) {
assertThat(statement.getConsistencyLevel()).isEqualTo(consistencyLevel);
}
if (consistencyLevel != null) {
verify(statement).setConsistencyLevel(consistencyLevel);
}
} else {
if (serialConsistencyLevel != null) {
assertThat(statement.getSerialConsistencyLevel()).isEqualTo(serialConsistencyLevel);
}
if (fetchSize != null) {
assertThat(statement.getPageSize()).isEqualTo(fetchSize.intValue());
}
if (consistencyLevel != null) {
assertThat(statement.getConsistencyLevel()).isEqualTo(consistencyLevel);
}
if (executionProfile != null) {
assertThat(statement.getExecutionProfileName()).isEqualTo(executionProfile);
}
}
}

View File

@@ -0,0 +1,52 @@
/*
* Copyright 2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.cassandra.core.cql;
import static org.mockito.Mockito.*;
import org.junit.Test;
import com.datastax.oss.driver.api.core.config.DriverExecutionProfile;
import com.datastax.oss.driver.api.core.cql.Statement;
/**
* Unit tests for {@link ExecutionProfileResolver}.
*
* @author Mark Paluch
*/
public class ExecutionProfileResolverUnitTests {
@Test // DATACASS-708
public void shouldSetProfileName() {
Statement statement = mock(Statement.class);
ExecutionProfileResolver.from("foo").apply(statement);
verify(statement).setExecutionProfileName("foo");
}
@Test // DATACASS-708
public void shouldSetProfileObject() {
Statement statement = mock(Statement.class);
DriverExecutionProfile profile = mock(DriverExecutionProfile.class);
ExecutionProfileResolver.from(profile).apply(statement);
verify(statement).setExecutionProfile(profile);
}
}

View File

@@ -38,7 +38,7 @@ public class QueryOptionsUnitTests {
assertThat(queryOptions.getClass()).isEqualTo(QueryOptions.class);
assertThat(queryOptions.getConsistencyLevel()).isEqualTo(DefaultConsistencyLevel.ANY);
assertThat(queryOptions.getReadTimeout()).isEqualTo(Duration.ofSeconds(1));
assertThat(queryOptions.getTimeout()).isEqualTo(Duration.ofSeconds(1));
assertThat(queryOptions.getPageSize()).isEqualTo(10);
assertThat(queryOptions.getTracing()).isTrue();
}
@@ -55,7 +55,7 @@ public class QueryOptionsUnitTests {
assertThat(mutated).isNotSameAs(queryOptions);
assertThat(mutated.getClass()).isEqualTo(QueryOptions.class);
assertThat(mutated.getConsistencyLevel()).isEqualTo(DefaultConsistencyLevel.ANY);
assertThat(mutated.getReadTimeout()).isEqualTo(Duration.ofSeconds(5));
assertThat(mutated.getTimeout()).isEqualTo(Duration.ofSeconds(5));
assertThat(mutated.getPageSize()).isEqualTo(10);
assertThat(mutated.getTracing()).isTrue();
}

View File

@@ -39,16 +39,24 @@ public class QueryOptionsUtilUnitTests {
@Mock SimpleStatement simpleStatement;
@Test // DATACASS-202
@Test // DATACASS-202, DATACASS-708
public void addPreparedStatementOptionsShouldAddDriverQueryOptions() {
when(simpleStatement.setConsistencyLevel(any())).thenReturn(simpleStatement);
when(simpleStatement.setSerialConsistencyLevel(any())).thenReturn(simpleStatement);
when(simpleStatement.setExecutionProfileName(anyString())).thenReturn(simpleStatement);
QueryOptions queryOptions = QueryOptions.builder() //
.consistencyLevel(DefaultConsistencyLevel.EACH_QUORUM) //
.serialConsistencyLevel(DefaultConsistencyLevel.LOCAL_ONE) //
.executionProfile("foo") //
.build();
QueryOptionsUtil.addQueryOptions(simpleStatement, queryOptions);
verify(simpleStatement).setConsistencyLevel(DefaultConsistencyLevel.EACH_QUORUM);
verify(simpleStatement).setSerialConsistencyLevel(DefaultConsistencyLevel.LOCAL_ONE);
verify(simpleStatement).setExecutionProfileName("foo");
}
@Test // DATACASS-202

View File

@@ -39,6 +39,7 @@ import org.springframework.data.cassandra.ReactiveResultSet;
import org.springframework.data.cassandra.ReactiveSession;
import org.springframework.data.cassandra.ReactiveSessionFactory;
import org.springframework.data.cassandra.core.cql.session.DefaultReactiveSessionFactory;
import org.springframework.lang.Nullable;
import com.datastax.oss.driver.api.core.ConsistencyLevel;
import com.datastax.oss.driver.api.core.DefaultConsistencyLevel;
@@ -135,7 +136,7 @@ public class ReactiveCqlTemplateUnitTests {
@Test // DATACASS-335
public void executeCqlShouldCallExecution() {
doTestStrings(null, null, reactiveCqlTemplate -> {
doTestStrings(reactiveCqlTemplate -> {
reactiveCqlTemplate.execute("SELECT * from USERS").as(StepVerifier::create).expectNextCount(1).verifyComplete();
@@ -146,7 +147,7 @@ public class ReactiveCqlTemplateUnitTests {
@Test // DATACASS-335
public void executeCqlWithArgumentsShouldCallExecution() {
doTestStrings(5, DefaultConsistencyLevel.ONE, reactiveCqlTemplate -> {
doTestStrings(5, DefaultConsistencyLevel.ONE, null, "foo", reactiveCqlTemplate -> {
reactiveCqlTemplate.execute("SELECT * from USERS").as(StepVerifier::create) //
.expectNextCount(1) //
@@ -159,7 +160,7 @@ public class ReactiveCqlTemplateUnitTests {
@Test // DATACASS-335
public void queryForResultSetShouldCallExecution() {
doTestStrings(null, null, reactiveCqlTemplate -> {
doTestStrings(reactiveCqlTemplate -> {
Mono<ReactiveResultSet> mono = reactiveCqlTemplate.queryForResultSet("SELECT * from USERS");
@@ -172,7 +173,7 @@ public class ReactiveCqlTemplateUnitTests {
@Test // DATACASS-335
public void queryWithResultSetExtractorShouldCallExecution() {
doTestStrings(null, null, reactiveCqlTemplate -> {
doTestStrings(reactiveCqlTemplate -> {
Flux<String> flux = reactiveCqlTemplate.query("SELECT * from USERS", (row, index) -> row.getString(0));
@@ -185,7 +186,7 @@ public class ReactiveCqlTemplateUnitTests {
@Test // DATACASS-335
public void queryWithResultSetExtractorWithArgumentsShouldCallExecution() {
doTestStrings(5, ConsistencyLevel.ONE, reactiveCqlTemplate -> {
doTestStrings(5, ConsistencyLevel.ONE, null, "foo", reactiveCqlTemplate -> {
Flux<String> flux = reactiveCqlTemplate.query("SELECT * from USERS", (row, index) -> row.getString(0));
@@ -336,7 +337,7 @@ public class ReactiveCqlTemplateUnitTests {
@Test // DATACASS-335
public void executeStatementShouldCallExecution() {
doTestStrings(null, null, reactiveCqlTemplate -> {
doTestStrings(reactiveCqlTemplate -> {
reactiveCqlTemplate.execute(SimpleStatement.newInstance("SELECT * from USERS")).as(StepVerifier::create) //
.expectNextCount(1) //
@@ -349,7 +350,7 @@ public class ReactiveCqlTemplateUnitTests {
@Test // DATACASS-335
public void executeStatementWithArgumentsShouldCallExecution() {
doTestStrings(5, ConsistencyLevel.ONE, reactiveCqlTemplate -> {
doTestStrings(5, ConsistencyLevel.ONE, DefaultConsistencyLevel.EACH_QUORUM, "foo", reactiveCqlTemplate -> {
reactiveCqlTemplate.execute(SimpleStatement.newInstance("SELECT * from USERS")).as(StepVerifier::create) //
.expectNextCount(1) //
@@ -362,7 +363,7 @@ public class ReactiveCqlTemplateUnitTests {
@Test // DATACASS-335
public void queryForResultStatementSetShouldCallExecution() {
doTestStrings(null, null, reactiveCqlTemplate -> {
doTestStrings(reactiveCqlTemplate -> {
reactiveCqlTemplate.queryForResultSet(SimpleStatement.newInstance("SELECT * from USERS"))
.flatMapMany(ReactiveResultSet::rows).as(StepVerifier::create) //
@@ -376,7 +377,7 @@ public class ReactiveCqlTemplateUnitTests {
@Test // DATACASS-335
public void queryWithResultSetStatementExtractorShouldCallExecution() {
doTestStrings(null, null, reactiveCqlTemplate -> {
doTestStrings(reactiveCqlTemplate -> {
Flux<String> flux = reactiveCqlTemplate.query(SimpleStatement.newInstance("SELECT * from USERS"),
(row, index) -> row.getString(0));
@@ -390,7 +391,7 @@ public class ReactiveCqlTemplateUnitTests {
@Test // DATACASS-335
public void queryWithResultSetStatementExtractorWithArgumentsShouldCallExecution() {
doTestStrings(5, ConsistencyLevel.ONE, reactiveCqlTemplate -> {
doTestStrings(5, ConsistencyLevel.ONE, null, "foo", reactiveCqlTemplate -> {
Flux<String> flux = reactiveCqlTemplate.query(SimpleStatement.newInstance("SELECT * from USERS"),
(row, index) -> row.getString(0));
@@ -533,7 +534,7 @@ public class ReactiveCqlTemplateUnitTests {
@Test // DATACASS-335
public void queryPreparedStatementWithCallbackShouldCallExecution() {
doTestStrings(null, null, reactiveCqlTemplate -> {
doTestStrings(reactiveCqlTemplate -> {
Flux<Row> flux = reactiveCqlTemplate.execute("SELECT * from USERS", (session, ps) -> {
@@ -547,7 +548,7 @@ public class ReactiveCqlTemplateUnitTests {
@Test // DATACASS-335
public void executePreparedStatementWithCallbackShouldCallExecution() {
doTestStrings(null, null, reactiveCqlTemplate -> {
doTestStrings(reactiveCqlTemplate -> {
Mono<Boolean> applied = reactiveCqlTemplate.execute("UPDATE users SET name = ?", "White");
when(this.preparedStatement.bind("White")).thenReturn(this.boundStatement);
@@ -779,7 +780,12 @@ public class ReactiveCqlTemplateUnitTests {
verify(session, times(2)).execute(boundStatement);
}
private <T> void doTestStrings(Integer fetchSize, ConsistencyLevel consistencyLevel,
private void doTestStrings(Consumer<ReactiveCqlTemplate> cqlTemplateConsumer) {
doTestStrings(null, null, null, null, cqlTemplateConsumer);
}
private void doTestStrings(@Nullable Integer fetchSize, @Nullable ConsistencyLevel consistencyLevel,
@Nullable ConsistencyLevel serialConsistencyLevel, @Nullable String executionProfile,
Consumer<ReactiveCqlTemplate> cqlTemplateConsumer) {
String[] results = { "Walter", "Hank", " Jesse" };
@@ -801,6 +807,14 @@ public class ReactiveCqlTemplateUnitTests {
template.setConsistencyLevel(consistencyLevel);
}
if (serialConsistencyLevel != null) {
template.setSerialConsistencyLevel(serialConsistencyLevel);
}
if (executionProfile != null) {
template.setExecutionProfile(executionProfile);
}
cqlTemplateConsumer.accept(template);
ArgumentCaptor<Statement> statementArgumentCaptor = ArgumentCaptor.forClass(Statement.class);
@@ -808,24 +822,20 @@ public class ReactiveCqlTemplateUnitTests {
Statement statement = statementArgumentCaptor.getValue();
if (statement instanceof PreparedStatement || statement instanceof BoundStatement) {
if (fetchSize != null) {
assertThat(statement.getPageSize()).isEqualTo(fetchSize.intValue());
}
if (fetchSize != null) {
verify(statement).setPageSize(fetchSize.intValue());
}
if (consistencyLevel != null) {
assertThat(statement.getConsistencyLevel()).isEqualTo(consistencyLevel);
}
if (consistencyLevel != null) {
verify(statement).setConsistencyLevel(consistencyLevel);
}
} else {
if (serialConsistencyLevel != null) {
assertThat(statement.getSerialConsistencyLevel()).isEqualTo(serialConsistencyLevel);
}
if (fetchSize != null) {
assertThat(statement.getPageSize()).isEqualTo(fetchSize.intValue());
}
if (consistencyLevel != null) {
assertThat(statement.getConsistencyLevel()).isEqualTo(consistencyLevel);
}
if (executionProfile != null) {
assertThat(statement.getExecutionProfileName()).isEqualTo(executionProfile);
}
}
}

View File

@@ -48,7 +48,7 @@ public class WriteOptionsUnitTests {
assertThat(writeOptions.getTtl()).isEqualTo(Duration.ofSeconds(123));
assertThat(writeOptions.getTimestamp()).isEqualTo(1519000753);
assertThat(writeOptions.getConsistencyLevel()).isEqualTo(DefaultConsistencyLevel.ANY);
assertThat(writeOptions.getReadTimeout()).isEqualTo(Duration.ofMillis(1));
assertThat(writeOptions.getTimeout()).isEqualTo(Duration.ofMillis(1));
assertThat(writeOptions.getPageSize()).isEqualTo(10);
assertThat(writeOptions.getTracing()).isTrue();
}
@@ -58,7 +58,7 @@ public class WriteOptionsUnitTests {
WriteOptions writeOptions = WriteOptions.builder().timeout(Duration.ofMinutes(1)).build();
assertThat(writeOptions.getReadTimeout()).isEqualTo(Duration.ofSeconds(60));
assertThat(writeOptions.getTimeout()).isEqualTo(Duration.ofSeconds(60));
assertThat(writeOptions.getPageSize()).isNull();
assertThat(writeOptions.getTracing()).isNull();
}
@@ -84,7 +84,7 @@ public class WriteOptionsUnitTests {
assertThat(mutated.getTtl()).isEqualTo(Duration.ofSeconds(123));
assertThat(mutated.getTimestamp()).isEqualTo(now.toEpochMilli() * 1000);
assertThat(mutated.getConsistencyLevel()).isEqualTo(DefaultConsistencyLevel.ANY);
assertThat(mutated.getReadTimeout()).isEqualTo(Duration.ofMillis(100));
assertThat(mutated.getTimeout()).isEqualTo(Duration.ofMillis(100));
assertThat(mutated.getPageSize()).isEqualTo(10);
assertThat(mutated.getTracing()).isTrue();
}

View File

@@ -137,5 +137,17 @@ public class StatementBuilderUnitTests {
assertThat(statement.getQuery()).isEqualTo("SELECT * FROM person");
assertThat(statement.getPositionalValues()).hasSize(1);
}
@Test // DATACASS-708
public void shouldTransformBuiltStatement() {
SimpleStatement statement = StatementBuilder.of(QueryBuilder.selectFrom("person").all())
.transform(statement1 -> statement1.setExecutionProfileName("foo"))
.build(StatementBuilder.ParameterHandling.BY_NAME);
assertThat(statement.getQuery()).isEqualTo("SELECT * FROM person");
assertThat(statement.getExecutionProfileName()).isEqualTo("foo");
}
}

View File

@@ -171,6 +171,10 @@ Keyspace creation via `CqlSessionFactoryBean` (`cassandra:session`) is not affec
=== Utilities
* `GuavaListenableFutureAdapter`
* `QueryOptions` and `WriteOptions` constructor taking `ConsistencyLevel` and `RetryPolicy` arguments.
Use the builder in conjunction of execution profiles as replacement.
* `CassandraAccessor.setRetryPolicy(…)` and `ReactiveCqlTemplate.setRetryPolicy(…)` methods.
Use execution profiles as replacement.
=== Namespace support