createPreparedStatement(CqlSession session) throws DriverException {
- return new CassandraFutureAdapter<>(session.prepareAsync(getCql()),
- exceptionTranslator::translateExceptionIfPossible);
+ public String getCql() {
+ return this.statement.getQuery();
}
}
diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/CassandraAccessor.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/CassandraAccessor.java
index 2391fe46d..b32097909 100644
--- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/CassandraAccessor.java
+++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/CassandraAccessor.java
@@ -32,7 +32,6 @@ import com.datastax.oss.driver.api.core.ConsistencyLevel;
import com.datastax.oss.driver.api.core.CqlIdentifier;
import com.datastax.oss.driver.api.core.CqlSession;
import com.datastax.oss.driver.api.core.cql.BatchStatement;
-import com.datastax.oss.driver.api.core.cql.BoundStatement;
import com.datastax.oss.driver.api.core.cql.SimpleStatement;
import com.datastax.oss.driver.api.core.cql.Statement;
import com.datastax.oss.driver.api.core.retry.RetryPolicy;
@@ -64,6 +63,12 @@ public class CassandraAccessor implements InitializingBean {
*/
private ExecutionProfileResolver executionProfileResolver = ExecutionProfileResolver.none();
+ /**
+ * If this variable is set to a value, it will be used for setting the {@code keyspace} property on statements used
+ * for query processing.
+ */
+ private @Nullable CqlIdentifier keyspace;
+
/**
* 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.
@@ -84,12 +89,6 @@ public class CassandraAccessor implements InitializingBean {
private @Nullable SessionFactory sessionFactory;
- /**
- * If this variable is set to a value, it will be used for setting the {@code keyspace} property on statements used
- * for query processing.
- */
- private @Nullable CqlIdentifier keyspace;
-
/**
* Ensures the Cassandra {@link CqlSession} and exception translator has been propertly set.
*/
@@ -200,6 +199,31 @@ public class CassandraAccessor implements InitializingBean {
return getPageSize();
}
+ /**
+ * Set the {@link CqlIdentifier keyspace} to be applied on statement-level for this template. If not set, the default
+ * {@link CqlSession} keyspace will be used.
+ *
+ * @param keyspace the keyspace to apply, must not be {@literal null}.
+ * @see SimpleStatement#setKeyspace(CqlIdentifier)
+ * @see BatchStatement#setKeyspace(CqlIdentifier)
+ * @since 3.1
+ */
+ public void setKeyspace(CqlIdentifier keyspace) {
+
+ Assert.notNull(keyspace, "Keyspace must not be null");
+
+ this.keyspace = keyspace;
+ }
+
+ /**
+ * @return the {@link CqlIdentifier keyspace} to be applied on statement-level for this template.
+ * @since 3.1
+ */
+ @Nullable
+ public CqlIdentifier getKeyspace() {
+ return this.keyspace;
+ }
+
/**
* Set the page 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
@@ -297,24 +321,6 @@ public class CassandraAccessor implements InitializingBean {
return this.sessionFactory;
}
- /**
- * Set the keyspace for this template. If it is null, then the default {@link CqlSession} level keyspace will be used.
- *
- * @see SimpleStatement#setKeyspace(CqlIdentifier)
- * @see BatchStatement#setKeyspace(CqlIdentifier)
- */
- public void setKeyspace(@Nullable CqlIdentifier keyspace) {
- this.keyspace = keyspace;
- }
-
- /**
- * @return the {@link CqlIdentifier} keyspace for this template.
- */
- @Nullable
- public CqlIdentifier getKeyspace() {
- return this.keyspace;
- }
-
/**
* Create a {@link SimpleStatement} given {@code cql}.
*
@@ -357,9 +363,6 @@ public class CassandraAccessor implements InitializingBean {
}
if (keyspace != null) {
- if (statementToUse instanceof BoundStatement) {
- throw new IllegalArgumentException("Keyspace cannot be set for a BoundStatement");
- }
if (statementToUse instanceof BatchStatement) {
statementToUse = ((BatchStatement) statementToUse).setKeyspace(keyspace);
}
diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/CqlTemplate.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/CqlTemplate.java
index 227f29652..bd6834aa2 100644
--- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/CqlTemplate.java
+++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/CqlTemplate.java
@@ -32,6 +32,7 @@ import com.datastax.oss.driver.api.core.DriverException;
import com.datastax.oss.driver.api.core.cql.PreparedStatement;
import com.datastax.oss.driver.api.core.cql.ResultSet;
import com.datastax.oss.driver.api.core.cql.Row;
+import com.datastax.oss.driver.api.core.cql.SimpleStatement;
import com.datastax.oss.driver.api.core.cql.Statement;
import com.datastax.oss.driver.api.core.metadata.Node;
@@ -726,7 +727,8 @@ public class CqlTemplate extends CassandraAccessor implements CqlOperations {
* @return the new {@link PreparedStatementCreator} to use
*/
protected PreparedStatementCreator newPreparedStatementCreator(String cql) {
- return new SimplePreparedStatementCreator(cql);
+ return new SimplePreparedStatementCreator(
+ (SimpleStatement) applyStatementSettings(SimpleStatement.newInstance(cql)));
}
/**
diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/QueryOptions.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/QueryOptions.java
index b16a13adc..1d41a7aba 100644
--- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/QueryOptions.java
+++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/QueryOptions.java
@@ -43,6 +43,8 @@ public class QueryOptions {
private final ExecutionProfileResolver executionProfileResolver;
+ private final @Nullable CqlIdentifier keyspace;
+
private final @Nullable Integer pageSize;
private final @Nullable ConsistencyLevel serialConsistencyLevel;
@@ -51,25 +53,17 @@ public class QueryOptions {
private final @Nullable Boolean tracing;
- private final @Nullable CqlIdentifier keyspace;
-
protected QueryOptions(@Nullable ConsistencyLevel consistencyLevel, ExecutionProfileResolver executionProfileResolver,
- @Nullable Integer pageSize, @Nullable ConsistencyLevel serialConsistencyLevel, Duration timeout,
- @Nullable Boolean tracing) {
- this(consistencyLevel, executionProfileResolver, pageSize, serialConsistencyLevel, timeout, tracing, null);
- }
-
- protected QueryOptions(@Nullable ConsistencyLevel consistencyLevel, ExecutionProfileResolver executionProfileResolver,
- @Nullable Integer pageSize, @Nullable ConsistencyLevel serialConsistencyLevel, Duration timeout,
- @Nullable Boolean tracing, @Nullable CqlIdentifier keyspace) {
+ @Nullable CqlIdentifier keyspace, @Nullable Integer pageSize, @Nullable ConsistencyLevel serialConsistencyLevel,
+ Duration timeout, @Nullable Boolean tracing) {
this.consistencyLevel = consistencyLevel;
this.executionProfileResolver = executionProfileResolver;
+ this.keyspace = keyspace;
this.pageSize = pageSize;
this.serialConsistencyLevel = serialConsistencyLevel;
this.timeout = timeout;
this.tracing = tracing;
- this.keyspace = keyspace;
}
/**
@@ -167,8 +161,9 @@ public class QueryOptions {
}
/**
- * @return the keyspace associated with the query. If it is null, it means that the default keyspace from
- * {@link CqlSession} will be used.
+ * @return the keyspace associated with the query. If it is {@literal null}, it means that either keyspace configured
+ * on the statement or from the {@link CqlSession} will be used.
+ * @since 3.1
*/
@Nullable
public CqlIdentifier getKeyspace() {
@@ -247,6 +242,8 @@ public class QueryOptions {
protected ExecutionProfileResolver executionProfileResolver = ExecutionProfileResolver.none();
+ protected @Nullable CqlIdentifier keyspace;
+
protected @Nullable Integer pageSize;
protected @Nullable ConsistencyLevel serialConsistencyLevel;
@@ -255,19 +252,17 @@ public class QueryOptions {
protected @Nullable Boolean tracing;
- protected @Nullable CqlIdentifier keyspace;
-
QueryOptionsBuilder() {}
QueryOptionsBuilder(QueryOptions queryOptions) {
this.consistencyLevel = queryOptions.consistencyLevel;
this.executionProfileResolver = queryOptions.executionProfileResolver;
+ this.keyspace = queryOptions.keyspace;
this.pageSize = queryOptions.pageSize;
this.serialConsistencyLevel = queryOptions.serialConsistencyLevel;
this.timeout = queryOptions.timeout;
this.tracing = queryOptions.tracing;
- this.keyspace = queryOptions.keyspace;
}
/**
@@ -330,6 +325,23 @@ public class QueryOptions {
return pageSize(fetchSize);
}
+ /**
+ * Sets the {@link CqlIdentifier keyspace} to use. If left unconfigured, then the keyspace set on the statement or
+ * {@link CqlSession} will be used.
+ *
+ * @param keyspace the specific keyspace to use to run a statement, must not be {@literal null}.
+ * @return {@code this} {@link QueryOptionsBuilder}.
+ * @since 3.1
+ */
+ public QueryOptionsBuilder keyspace(CqlIdentifier keyspace) {
+
+ Assert.notNull(keyspace, "Keyspace must not be null");
+
+ this.keyspace = keyspace;
+
+ return this;
+ }
+
/**
* Sets the query fetch size for {@link com.datastax.oss.driver.api.core.cql.ResultSet} chunks.
*
@@ -459,27 +471,14 @@ public class QueryOptions {
return tracing(true);
}
- /**
- * Sets the keyspace to use.
- *
- * @param keyspace if it is null, then the default {@link CqlSession} level keyspace will be used.
- * @return {@code this} {@link QueryOptionsBuilder}
- */
- public QueryOptionsBuilder keyspace(CqlIdentifier keyspace) {
-
- this.keyspace = keyspace;
-
- return this;
- }
-
/**
* Builds a new {@link QueryOptions} with the configured values.
*
* @return a new {@link QueryOptions} with the configured values
*/
public QueryOptions build() {
- return new QueryOptions(this.consistencyLevel, this.executionProfileResolver, this.pageSize,
- this.serialConsistencyLevel, this.timeout, this.tracing, this.keyspace);
+ return new QueryOptions(this.consistencyLevel, this.executionProfileResolver, this.keyspace, this.pageSize,
+ this.serialConsistencyLevel, this.timeout, this.tracing);
}
}
}
diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/ReactiveCqlTemplate.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/ReactiveCqlTemplate.java
index 2e185833b..14167ae3f 100644
--- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/ReactiveCqlTemplate.java
+++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/ReactiveCqlTemplate.java
@@ -23,6 +23,7 @@ import java.util.Optional;
import java.util.function.Function;
import org.reactivestreams.Publisher;
+
import org.springframework.dao.DataAccessException;
import org.springframework.dao.support.DataAccessUtils;
import org.springframework.data.cassandra.ReactiveResultSet;
@@ -84,12 +85,6 @@ import com.datastax.oss.driver.api.core.retry.RetryPolicy;
*/
public class ReactiveCqlTemplate extends ReactiveCassandraAccessor implements ReactiveCqlOperations {
- /**
- * 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.
- */
- private int pageSize = -1;
-
/**
* If this variable is set to a value, it will be used for setting the {@code consistencyLevel} property on statements
* used for query processing.
@@ -102,18 +97,24 @@ public class ReactiveCqlTemplate extends ReactiveCassandraAccessor implements Re
*/
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;
-
/**
* If this variable is set to a value, it will be used for setting the {@code keyspace} property on statements used
* for query processing.
*/
private @Nullable CqlIdentifier keyspace;
+ /**
+ * 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.
+ */
+ private int pageSize = -1;
+
+ /**
+ * 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.
@@ -226,6 +227,31 @@ public class ReactiveCqlTemplate extends ReactiveCassandraAccessor implements Re
return getPageSize();
}
+ /**
+ * Set the {@link CqlIdentifier keyspace} to be applied on statement-level for this template. If not set, the default
+ * {@link CqlSession} keyspace will be used.
+ *
+ * @param keyspace the keyspace to apply, must not be {@literal null}.
+ * @see SimpleStatement#setKeyspace(CqlIdentifier)
+ * @see BatchStatement#setKeyspace(CqlIdentifier)
+ * @since 3.1
+ */
+ public void setKeyspace(CqlIdentifier keyspace) {
+
+ Assert.notNull(keyspace, "Keyspace must not be null");
+
+ this.keyspace = keyspace;
+ }
+
+ /**
+ * @return the {@link CqlIdentifier keyspace} to be applied on statement-level for this template.
+ * @since 3.1
+ */
+ @Nullable
+ public CqlIdentifier getKeyspace() {
+ return this.keyspace;
+ }
+
/**
* Set the page 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
@@ -265,24 +291,6 @@ public class ReactiveCqlTemplate extends ReactiveCassandraAccessor implements Re
return this.serialConsistencyLevel;
}
- /**
- * Set the keyspace for this template. If it is null, then the default {@link CqlSession} level keyspace will be used.
- *
- * @see SimpleStatement#setKeyspace(CqlIdentifier)
- * @see BatchStatement#setKeyspace(CqlIdentifier)
- */
- public void setKeyspace(@Nullable CqlIdentifier keyspace) {
- this.keyspace = keyspace;
- }
-
- /**
- * @return the {@link CqlIdentifier} keyspace for this template.
- */
- @Nullable
- public CqlIdentifier getKeyspace() {
- return this.keyspace;
- }
-
// -------------------------------------------------------------------------
// Methods dealing with a plain org.springframework.data.cassandra.core.cql.ReactiveSession
// -------------------------------------------------------------------------
@@ -754,7 +762,8 @@ public class ReactiveCqlTemplate extends ReactiveCassandraAccessor implements Re
* @since 2.0.8
*/
protected ReactivePreparedStatementCreator newReactivePreparedStatementCreator(String cql) {
- return new SimpleReactivePreparedStatementCreator(cql);
+ return new SimpleReactivePreparedStatementCreator(
+ (SimpleStatement) applyStatementSettings(SimpleStatement.newInstance(cql)));
}
/**
@@ -865,9 +874,6 @@ public class ReactiveCqlTemplate extends ReactiveCassandraAccessor implements Re
}
if (keyspace != null) {
- if (statementToUse instanceof BoundStatement) {
- throw new IllegalArgumentException("Keyspace cannot be set for a BoundStatement");
- }
if (statementToUse instanceof BatchStatement) {
statementToUse = ((BatchStatement) statementToUse).setKeyspace(keyspace);
}
@@ -922,23 +928,20 @@ public class ReactiveCqlTemplate extends ReactiveCassandraAccessor implements Re
static class SimpleReactivePreparedStatementCreator implements ReactivePreparedStatementCreator, CqlProvider {
- private final String cql;
+ private final SimpleStatement statement;
- SimpleReactivePreparedStatementCreator(String cql) {
-
- Assert.notNull(cql, "CQL must not be null");
-
- this.cql = cql;
+ SimpleReactivePreparedStatementCreator(SimpleStatement statement) {
+ this.statement = statement;
}
@Override
public Mono createPreparedStatement(ReactiveSession session) throws DriverException {
- return session.prepare(cql);
+ return session.prepare(this.statement);
}
@Override
public String getCql() {
- return cql;
+ return this.statement.getQuery();
}
}
}
diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/SimplePreparedStatementCreator.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/SimplePreparedStatementCreator.java
index e6d9da7de..d1d938ae1 100644
--- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/SimplePreparedStatementCreator.java
+++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/SimplePreparedStatementCreator.java
@@ -15,11 +15,12 @@
*/
package org.springframework.data.cassandra.core.cql;
+import org.springframework.util.Assert;
+
import com.datastax.oss.driver.api.core.CqlSession;
import com.datastax.oss.driver.api.core.DriverException;
import com.datastax.oss.driver.api.core.cql.PreparedStatement;
-
-import org.springframework.util.Assert;
+import com.datastax.oss.driver.api.core.cql.SimpleStatement;
/**
* Trivial implementation of {@link PreparedStatementCreator}. This prepared statement creator simply prepares a
@@ -34,7 +35,7 @@ import org.springframework.util.Assert;
*/
public class SimplePreparedStatementCreator implements PreparedStatementCreator, CqlProvider {
- private final String cql;
+ private final SimpleStatement statement;
/**
* Create a {@link SimplePreparedStatementCreator} given {@code cql}.
@@ -45,14 +46,20 @@ public class SimplePreparedStatementCreator implements PreparedStatementCreator,
Assert.notNull(cql, "CQL is required to create a PreparedStatement");
- this.cql = cql;
+ this.statement = SimpleStatement.newInstance(cql);
}
- /* (non-Javadoc)
- * @see org.springframework.data.cassandra.core.cqlProvider#getCql()
+ /**
+ * Create a {@link SimplePreparedStatementCreator} given {@code cql}.
+ *
+ * @param statement must not be {@literal null}.
+ * @since 3.1
*/
- public String getCql() {
- return this.cql;
+ public SimplePreparedStatementCreator(SimpleStatement statement) {
+
+ Assert.notNull(statement, "CQL is required to create a PreparedStatement");
+
+ this.statement = statement;
}
/* (non-Javadoc)
@@ -60,6 +67,13 @@ public class SimplePreparedStatementCreator implements PreparedStatementCreator,
*/
@Override
public PreparedStatement createPreparedStatement(CqlSession session) throws DriverException {
- return session.prepare(this.cql);
+ return session.prepare(this.statement);
+ }
+
+ /* (non-Javadoc)
+ * @see org.springframework.data.cassandra.core.cqlProvider#getCql()
+ */
+ public String getCql() {
+ return this.statement.getQuery();
}
}
diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/WriteOptions.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/WriteOptions.java
index a6ee1baeb..e05b34166 100644
--- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/WriteOptions.java
+++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/WriteOptions.java
@@ -41,13 +41,15 @@ public class WriteOptions extends QueryOptions {
private static final WriteOptions EMPTY = new WriteOptionsBuilder().build();
private final Duration ttl;
+
private final @Nullable Long timestamp;
protected WriteOptions(@Nullable ConsistencyLevel consistencyLevel, ExecutionProfileResolver executionProfileResolver,
- @Nullable Integer pageSize, @Nullable ConsistencyLevel serialConsistencyLevel, Duration timeout, Duration ttl,
+ @Nullable CqlIdentifier keyspace, @Nullable Integer pageSize, @Nullable ConsistencyLevel serialConsistencyLevel,
+ Duration timeout, Duration ttl,
@Nullable Long timestamp, @Nullable Boolean tracing) {
- super(consistencyLevel, executionProfileResolver, pageSize, serialConsistencyLevel, timeout, tracing);
+ super(consistencyLevel, executionProfileResolver, keyspace, pageSize, serialConsistencyLevel, timeout, tracing);
this.ttl = ttl;
this.timestamp = timestamp;
@@ -150,6 +152,7 @@ public class WriteOptions extends QueryOptions {
public static class WriteOptionsBuilder extends QueryOptionsBuilder {
protected Duration ttl = Duration.ofMillis(-1);
+
protected Long timestamp = null;
protected WriteOptionsBuilder() {}
@@ -201,6 +204,16 @@ public class WriteOptions extends QueryOptions {
return this;
}
+ /* (non-Javadoc)
+ * @see org.springframework.data.cassandra.core.cql.QueryOptions.QueryOptionsBuilder#keyspace()
+ */
+ @Override
+ public WriteOptionsBuilder keyspace(CqlIdentifier keyspace) {
+
+ super.keyspace(keyspace);
+ return this;
+ }
+
/* (non-Javadoc)
* @see org.springframework.data.cassandra.core.cql.QueryOptions.QueryOptionsBuilder#pageSize(int)
*/
@@ -272,16 +285,6 @@ public class WriteOptions extends QueryOptions {
return this;
}
- /* (non-Javadoc)
- * @see org.springframework.data.cassandra.core.cql.QueryOptions.QueryOptionsBuilder#keyspace()
- */
- @Override
- public WriteOptionsBuilder keyspace(CqlIdentifier keyspace) {
-
- super.keyspace(keyspace);
- return this;
- }
-
/**
* Sets the time to live in seconds for write operations.
*
@@ -353,7 +356,7 @@ public class WriteOptions extends QueryOptions {
* @return a new {@link WriteOptions} with the configured values
*/
public WriteOptions build() {
- return new WriteOptions(this.consistencyLevel, this.executionProfileResolver, this.pageSize,
+ return new WriteOptions(this.consistencyLevel, this.executionProfileResolver, this.keyspace, this.pageSize,
this.serialConsistencyLevel, this.timeout, this.ttl, this.timestamp, this.tracing);
}
}
diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/CassandraTemplateIntegrationTests.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/CassandraTemplateIntegrationTests.java
index 8dde813de..c4e5429ef 100644
--- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/CassandraTemplateIntegrationTests.java
+++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/CassandraTemplateIntegrationTests.java
@@ -16,6 +16,7 @@
package org.springframework.data.cassandra.core;
import static org.assertj.core.api.Assertions.*;
+import static org.assertj.core.api.Assumptions.assumeThat;
import static org.junit.Assume.*;
import static org.springframework.data.cassandra.core.query.Criteria.*;
@@ -438,7 +439,8 @@ class CassandraTemplateIntegrationTests extends AbstractKeyspaceCreatingIntegrat
@Test // DATACASS-767
void selectByQueryWithKeyspaceShouldRetrieveData() {
- assumeTrue(cassandraVersion.isGreaterThanOrEqualTo(CASSANDRA_4));
+
+ assumeThat(cassandraVersion.isGreaterThanOrEqualTo(CASSANDRA_4)).isTrue();
QueryOptions queryOptions = QueryOptions.builder().keyspace(CqlIdentifier.fromCql(keyspace)).build();
@@ -451,7 +453,8 @@ class CassandraTemplateIntegrationTests extends AbstractKeyspaceCreatingIntegrat
@Test // DATACASS-767
void selectByQueryWithNonExistingKeyspaceShouldThrowThatKeyspaceDoesNotExists() {
- assumeTrue(cassandraVersion.isGreaterThanOrEqualTo(CASSANDRA_4));
+
+ assumeThat(cassandraVersion.isGreaterThanOrEqualTo(CASSANDRA_4)).isTrue();
QueryOptions queryOptions = QueryOptions.builder().keyspace(CqlIdentifier.fromCql("non_existing")).build();
diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/DeleteOptionsUnitTests.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/DeleteOptionsUnitTests.java
index 79b81b7e1..a56c66b11 100644
--- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/DeleteOptionsUnitTests.java
+++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/DeleteOptionsUnitTests.java
@@ -20,6 +20,7 @@ import static org.assertj.core.api.Assertions.*;
import java.time.Duration;
import java.time.Instant;
+import com.datastax.oss.driver.api.core.CqlIdentifier;
import org.junit.jupiter.api.Test;
import org.springframework.data.cassandra.core.query.Query;
@@ -33,7 +34,7 @@ import com.datastax.oss.driver.api.core.DefaultConsistencyLevel;
*/
class DeleteOptionsUnitTests {
- @Test // DATACASS-575, DATACASS-708
+ @Test // DATACASS-575, DATACASS-708, DATACASS-767
void shouldConfigureDeleteOptions() {
Instant now = Instant.ofEpochSecond(1234);
@@ -44,13 +45,14 @@ class DeleteOptionsUnitTests {
.withIfExists() //
.executionProfile("foo") //
.serialConsistencyLevel(DefaultConsistencyLevel.LOCAL_ONE) //
+ .keyspace(CqlIdentifier.fromCql("my_keyspace"))
.build();
-
assertThat(deleteOptions.getTtl()).isEqualTo(Duration.ofSeconds(10));
assertThat(deleteOptions.getTimestamp()).isEqualTo(now.toEpochMilli() * 1000);
assertThat(deleteOptions.isIfExists()).isTrue();
assertThat(deleteOptions.getIfCondition()).isNull();
+ assertThat(deleteOptions.getKeyspace()).isEqualTo(CqlIdentifier.fromCql("my_keyspace"));
}
@Test // DATACASS-575
diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/InsertOptionsUnitTests.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/InsertOptionsUnitTests.java
index f2e053204..63f2a088c 100644
--- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/InsertOptionsUnitTests.java
+++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/InsertOptionsUnitTests.java
@@ -24,6 +24,7 @@ import java.time.ZoneOffset;
import org.junit.jupiter.api.Test;
+import com.datastax.oss.driver.api.core.CqlIdentifier;
import com.datastax.oss.driver.api.core.DefaultConsistencyLevel;
/**
@@ -34,7 +35,7 @@ import com.datastax.oss.driver.api.core.DefaultConsistencyLevel;
*/
class InsertOptionsUnitTests {
- @Test // DATACASS-250, DATACASS-155, DATACASS-708
+ @Test // DATACASS-250, DATACASS-155, DATACASS-708, DATACASS-767
void shouldConfigureInsertOptions() {
Instant now = LocalDateTime.now().toInstant(ZoneOffset.UTC);
@@ -45,11 +46,13 @@ class InsertOptionsUnitTests {
.withIfNotExists() //
.executionProfile("foo") //
.serialConsistencyLevel(DefaultConsistencyLevel.LOCAL_ONE) //
+ .keyspace(CqlIdentifier.fromCql("my_keyspace"))
.build();
assertThat(insertOptions.getTtl()).isEqualTo(Duration.ofSeconds(10));
assertThat(insertOptions.getTimestamp()).isEqualTo(now.toEpochMilli() * 1000);
assertThat(insertOptions.isIfNotExists()).isTrue();
+ assertThat(insertOptions.getKeyspace()).isEqualTo(CqlIdentifier.fromCql("my_keyspace"));
}
@Test // DATACASS-56
diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/UpdateOptionsUnitTests.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/UpdateOptionsUnitTests.java
index 179721afd..3e11697a6 100644
--- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/UpdateOptionsUnitTests.java
+++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/UpdateOptionsUnitTests.java
@@ -24,6 +24,7 @@ import org.junit.jupiter.api.Test;
import org.springframework.data.cassandra.core.query.Query;
+import com.datastax.oss.driver.api.core.CqlIdentifier;
import com.datastax.oss.driver.api.core.DefaultConsistencyLevel;
/**
@@ -34,7 +35,7 @@ import com.datastax.oss.driver.api.core.DefaultConsistencyLevel;
*/
class UpdateOptionsUnitTests {
- @Test // DATACASS-250, DATACASS-155, DATACASS-708
+ @Test // DATACASS-250, DATACASS-155, DATACASS-708, DATACASS-767
void shouldConfigureUpdateOptions() {
Instant now = Instant.ofEpochSecond(1234);
@@ -45,12 +46,14 @@ class UpdateOptionsUnitTests {
.executionProfile("foo") //
.serialConsistencyLevel(DefaultConsistencyLevel.LOCAL_ONE) //
.withIfExists() //
+ .keyspace(CqlIdentifier.fromCql("my_keyspace")) //
.build();
assertThat(updateOptions.getTtl()).isEqualTo(Duration.ofSeconds(10));
assertThat(updateOptions.getTimestamp()).isEqualTo(now.toEpochMilli() * 1000);
assertThat(updateOptions.isIfExists()).isTrue();
assertThat(updateOptions.getIfCondition()).isNull();
+ assertThat(updateOptions.getKeyspace()).isEqualTo(CqlIdentifier.fromCql("my_keyspace"));
}
@Test // DATACASS-56, DATACASS-155
diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/AsyncCqlTemplateUnitTests.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/AsyncCqlTemplateUnitTests.java
index 546e071ba..85a9a31f5 100644
--- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/AsyncCqlTemplateUnitTests.java
+++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/AsyncCqlTemplateUnitTests.java
@@ -46,6 +46,7 @@ import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.util.concurrent.ListenableFuture;
import com.datastax.oss.driver.api.core.ConsistencyLevel;
+import com.datastax.oss.driver.api.core.CqlIdentifier;
import com.datastax.oss.driver.api.core.CqlSession;
import com.datastax.oss.driver.api.core.NoNodeAvailableException;
import com.datastax.oss.driver.api.core.cql.AsyncResultSet;
@@ -64,7 +65,7 @@ import com.datastax.oss.driver.api.core.servererrors.InvalidQueryException;
*/
@ExtendWith(MockitoExtension.class)
@MockitoSettings(strictness = Strictness.LENIENT)
-public class AsyncCqlTemplateUnitTests {
+class AsyncCqlTemplateUnitTests {
@Mock CqlSession session;
@Mock AsyncResultSet resultSet;
@@ -133,10 +134,24 @@ public class AsyncCqlTemplateUnitTests {
});
}
+ @Test // DATACASS-767
+ void executePreparedStatementShouldApplyKeyspace() {
+
+ doTestStrings(null, null, CqlIdentifier.fromCql("ks1"), cqlTemplate -> {
+ cqlTemplate.execute("SELECT * from USERS", (session, ps) -> session.executeAsync(ps.bind("A")));
+ });
+
+ ArgumentCaptor captor = ArgumentCaptor.forClass(SimpleStatement.class);
+ verify(session).prepareAsync(captor.capture());
+
+ SimpleStatement statement = captor.getValue();
+ assertThat(statement.getKeyspace()).isEqualTo(CqlIdentifier.fromCql("ks1"));
+ }
+
@Test // DATACASS-292
void executeCqlWithArgumentsShouldCallExecution() {
- doTestStrings(5, ConsistencyLevel.ONE, asyncCqlTemplate -> {
+ doTestStrings(5, ConsistencyLevel.ONE, null, asyncCqlTemplate -> {
asyncCqlTemplate.execute("SELECT * from USERS");
@@ -172,7 +187,7 @@ public class AsyncCqlTemplateUnitTests {
@Test // DATACASS-292
void queryWithResultSetExtractorWithArgumentsShouldCallExecution() {
- doTestStrings(5, ConsistencyLevel.ONE, asyncCqlTemplate -> {
+ doTestStrings(5, ConsistencyLevel.ONE, null, asyncCqlTemplate -> {
List rows = getUninterruptibly(
asyncCqlTemplate.query("SELECT * from USERS", (row, index) -> row.getString(0)));
@@ -313,7 +328,7 @@ public class AsyncCqlTemplateUnitTests {
@Test // DATACASS-292
void executeStatementWithArgumentsShouldCallExecution() {
- doTestStrings(5, ConsistencyLevel.ONE, asyncCqlTemplate -> {
+ doTestStrings(5, ConsistencyLevel.ONE, null, asyncCqlTemplate -> {
asyncCqlTemplate.execute(SimpleStatement.newInstance("SELECT * from USERS"));
@@ -350,7 +365,7 @@ public class AsyncCqlTemplateUnitTests {
@Test // DATACASS-292
void queryWithResultSetStatementExtractorWithArgumentsShouldCallExecution() {
- doTestStrings(5, ConsistencyLevel.ONE, asyncCqlTemplate -> {
+ doTestStrings(5, ConsistencyLevel.ONE, null, asyncCqlTemplate -> {
ListenableFuture> future = asyncCqlTemplate.query(SimpleStatement.newInstance("SELECT * from USERS"),
(row, index) -> row.getString(0));
@@ -657,7 +672,7 @@ public class AsyncCqlTemplateUnitTests {
@Test // DATACASS-292
void queryForObjectPreparedStatementShouldBeEmpty() throws Exception {
- when(session.prepareAsync("SELECT * FROM user WHERE username = ?"))
+ when(session.prepareAsync(any(SimpleStatement.class)))
.thenReturn(new TestPreparedStatementFuture(preparedStatement));
when(preparedStatement.bind("Walter")).thenReturn(boundStatement);
when(session.executeAsync(boundStatement)).thenReturn(new TestResultSetFuture(resultSet));
@@ -679,7 +694,7 @@ public class AsyncCqlTemplateUnitTests {
@Test // DATACASS-292
void queryForObjectPreparedStatementShouldReturnRecord() {
- when(session.prepareAsync("SELECT * FROM user WHERE username = ?"))
+ when(session.prepareAsync(any(SimpleStatement.class)))
.thenReturn(new TestPreparedStatementFuture(preparedStatement));
when(preparedStatement.bind("Walter")).thenReturn(boundStatement);
when(session.executeAsync(boundStatement)).thenReturn(new TestResultSetFuture(resultSet));
@@ -693,7 +708,7 @@ public class AsyncCqlTemplateUnitTests {
@Test // DATACASS-292
void queryForObjectPreparedStatementShouldFailReturningManyRecords() throws Exception {
- when(session.prepareAsync("SELECT * FROM user WHERE username = ?"))
+ when(session.prepareAsync(any(SimpleStatement.class)))
.thenReturn(new TestPreparedStatementFuture(preparedStatement));
when(preparedStatement.bind("Walter")).thenReturn(boundStatement);
when(session.executeAsync(boundStatement)).thenReturn(new TestResultSetFuture(resultSet));
@@ -714,7 +729,7 @@ public class AsyncCqlTemplateUnitTests {
@Test // DATACASS-292
void queryForObjectPreparedStatementWithTypeShouldReturnRecord() {
- when(session.prepareAsync("SELECT * FROM user WHERE username = ?"))
+ when(session.prepareAsync(any(SimpleStatement.class)))
.thenReturn(new TestPreparedStatementFuture(preparedStatement));
when(preparedStatement.bind("Walter")).thenReturn(boundStatement);
when(session.executeAsync(boundStatement)).thenReturn(new TestResultSetFuture(resultSet));
@@ -731,7 +746,7 @@ public class AsyncCqlTemplateUnitTests {
@Test // DATACASS-292
void queryForListPreparedStatementWithTypeShouldReturnRecord() {
- when(session.prepareAsync("SELECT * FROM user WHERE username = ?"))
+ when(session.prepareAsync(any(SimpleStatement.class)))
.thenReturn(new TestPreparedStatementFuture(preparedStatement));
when(preparedStatement.bind("Walter")).thenReturn(boundStatement);
when(session.executeAsync(boundStatement)).thenReturn(new TestResultSetFuture(resultSet));
@@ -749,7 +764,7 @@ public class AsyncCqlTemplateUnitTests {
@Test // DATACASS-292
void updatePreparedStatementShouldReturnApplied() {
- when(session.prepareAsync("UPDATE user SET username = ?"))
+ when(session.prepareAsync(any(SimpleStatement.class)))
.thenReturn(new TestPreparedStatementFuture(preparedStatement));
when(preparedStatement.bind("Walter")).thenReturn(boundStatement);
when(session.executeAsync(boundStatement)).thenReturn(new TestResultSetFuture(resultSet));
@@ -761,10 +776,11 @@ public class AsyncCqlTemplateUnitTests {
}
private void doTestStrings(Consumer cqlTemplateConsumer) {
- doTestStrings(null, null, cqlTemplateConsumer);
+ doTestStrings(null, null, null, cqlTemplateConsumer);
}
private void doTestStrings(@Nullable Integer fetchSize, @Nullable ConsistencyLevel consistencyLevel,
+ @Nullable CqlIdentifier keyspace,
Consumer cqlTemplateConsumer) {
String[] results = { "Walter", "Hank", " Jesse" };
@@ -773,6 +789,8 @@ public class AsyncCqlTemplateUnitTests {
when(this.resultSet.currentPage()).thenReturn(Arrays.asList(row, row, row));
when(this.row.getString(0)).thenReturn(results[0], results[1], results[2]);
when(this.session.prepareAsync(anyString())).thenReturn(new TestPreparedStatementFuture(this.preparedStatement));
+ when(this.session.prepareAsync(any(SimpleStatement.class)))
+ .thenReturn(new TestPreparedStatementFuture(this.preparedStatement));
AsyncCqlTemplate template = new AsyncCqlTemplate();
template.setSession(this.session);
@@ -780,10 +798,15 @@ public class AsyncCqlTemplateUnitTests {
if (fetchSize != null) {
template.setFetchSize(fetchSize);
}
+
if (consistencyLevel != null) {
template.setConsistencyLevel(consistencyLevel);
}
+ if (keyspace != null) {
+ template.setKeyspace(keyspace);
+ }
+
cqlTemplateConsumer.accept(template);
ArgumentCaptor statementArgumentCaptor = ArgumentCaptor.forClass(Statement.class);
diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/CassandraAccessorUnitTests.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/CassandraAccessorUnitTests.java
index ff44e5b26..da419c85f 100755
--- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/CassandraAccessorUnitTests.java
+++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/CassandraAccessorUnitTests.java
@@ -20,7 +20,6 @@ import static org.assertj.core.api.Assertions.*;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
-
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
@@ -33,6 +32,7 @@ import com.datastax.oss.driver.api.core.CqlSession;
*
* @author John Blum
* @author Mark Paluch
+ * @author Tomasz Lelek
*/
@ExtendWith(MockitoExtension.class)
class CassandraAccessorUnitTests {
@@ -107,8 +107,10 @@ class CassandraAccessorUnitTests {
@Test // DATACASS-767
void setAndGetKeyspace() {
+
CqlIdentifier keyspace = CqlIdentifier.fromCql("ks1");
cassandraAccessor.setKeyspace(keyspace);
+
assertThat(cassandraAccessor.getKeyspace()).isEqualTo(keyspace);
}
diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/CqlTemplateUnitTests.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/CqlTemplateUnitTests.java
index 9d07a882b..84b71f472 100644
--- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/CqlTemplateUnitTests.java
+++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/CqlTemplateUnitTests.java
@@ -28,12 +28,12 @@ import java.util.function.Consumer;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
-
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.junit.jupiter.MockitoSettings;
import org.mockito.quality.Strictness;
+
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.dao.IncorrectResultSizeDataAccessException;
import org.springframework.data.cassandra.CassandraConnectionFailureException;
@@ -459,6 +459,23 @@ class CqlTemplateUnitTests {
});
}
+ @Test // DATACASS-767
+ void executePreparedStatementShouldApplyKeyspace() {
+
+ when(preparedStatement.bind("A")).thenReturn(boundStatement);
+ when(boundStatement.getKeyspace()).thenReturn(CqlIdentifier.fromCql("ks1"));
+
+ doTestStrings(null, null, null, null, CqlIdentifier.fromCql("ks1"), cqlTemplate -> {
+ cqlTemplate.execute("SELECT * from USERS", (session, ps) -> session.execute(ps.bind("A")));
+ });
+
+ ArgumentCaptor captor = ArgumentCaptor.forClass(SimpleStatement.class);
+ verify(session).prepare(captor.capture());
+
+ SimpleStatement statement = captor.getValue();
+ assertThat(statement.getKeyspace()).isEqualTo(CqlIdentifier.fromCql("ks1"));
+ }
+
@Test // DATACASS-292
void executePreparedStatementWithCallbackShouldCallExecution() {
@@ -596,7 +613,7 @@ class CqlTemplateUnitTests {
@Test // DATACASS-292
void queryForObjectPreparedStatementShouldBeEmpty() {
- when(session.prepare("SELECT * FROM user WHERE username = ?")).thenReturn(preparedStatement);
+ when(session.prepare(any(SimpleStatement.class))).thenReturn(preparedStatement);
when(preparedStatement.bind("Walter")).thenReturn(boundStatement);
when(session.execute(boundStatement)).thenReturn(resultSet);
when(resultSet.iterator()).thenReturn(Collections.emptyIterator());
@@ -613,7 +630,7 @@ class CqlTemplateUnitTests {
@Test // DATACASS-292
void queryForObjectPreparedStatementShouldReturnRecord() {
- when(session.prepare("SELECT * FROM user WHERE username = ?")).thenReturn(preparedStatement);
+ when(session.prepare(any(SimpleStatement.class))).thenReturn(preparedStatement);
when(preparedStatement.bind("Walter")).thenReturn(boundStatement);
when(session.execute(boundStatement)).thenReturn(resultSet);
when(resultSet.iterator()).thenReturn(Collections.singleton(row).iterator());
@@ -625,7 +642,7 @@ class CqlTemplateUnitTests {
@Test // DATACASS-292
void queryForObjectPreparedStatementShouldFailReturningManyRecords() {
- when(session.prepare("SELECT * FROM user WHERE username = ?")).thenReturn(preparedStatement);
+ when(session.prepare(any(SimpleStatement.class))).thenReturn(preparedStatement);
when(preparedStatement.bind("Walter")).thenReturn(boundStatement);
when(session.execute(boundStatement)).thenReturn(resultSet);
when(resultSet.iterator()).thenReturn(Arrays.asList(row, row).iterator());
@@ -642,7 +659,7 @@ class CqlTemplateUnitTests {
@Test // DATACASS-292
void queryForObjectPreparedStatementWithTypeShouldReturnRecord() {
- when(session.prepare("SELECT * FROM user WHERE username = ?")).thenReturn(preparedStatement);
+ when(session.prepare(any(SimpleStatement.class))).thenReturn(preparedStatement);
when(preparedStatement.bind("Walter")).thenReturn(boundStatement);
when(session.execute(boundStatement)).thenReturn(resultSet);
when(resultSet.iterator()).thenReturn(Collections.singleton(row).iterator());
@@ -658,7 +675,7 @@ class CqlTemplateUnitTests {
@Test // DATACASS-292
void queryForListPreparedStatementWithTypeShouldReturnRecord() {
- when(session.prepare("SELECT * FROM user WHERE username = ?")).thenReturn(preparedStatement);
+ when(session.prepare(any(SimpleStatement.class))).thenReturn(preparedStatement);
when(preparedStatement.bind("Walter")).thenReturn(boundStatement);
when(session.execute(boundStatement)).thenReturn(resultSet);
when(resultSet.iterator()).thenReturn(Arrays.asList(row, row).iterator());
@@ -674,7 +691,7 @@ class CqlTemplateUnitTests {
@Test // DATACASS-292
void updatePreparedStatementShouldReturnApplied() {
- when(session.prepare("UPDATE user SET username = ?")).thenReturn(preparedStatement);
+ when(session.prepare(any(SimpleStatement.class))).thenReturn(preparedStatement);
when(preparedStatement.bind("Walter")).thenReturn(boundStatement);
when(session.execute(boundStatement)).thenReturn(resultSet);
when(resultSet.wasApplied()).thenReturn(true);
@@ -687,27 +704,27 @@ class CqlTemplateUnitTests {
@Test // DATACASS-767
void executeCqlWithKeyspaceShouldCallExecution() {
- doTestStrings(5, DefaultConsistencyLevel.ONE, null, "foo", cqlTemplate -> {
+ doTestStrings(5, DefaultConsistencyLevel.ONE, null, "foo", CqlIdentifier.fromCql("some_keyspace"), cqlTemplate -> {
cqlTemplate.execute("SELECT * from USERS");
verify(session).execute(any(Statement.class));
- }, CqlIdentifier.fromCql("some_keyspace"));
+ });
}
private void doTestStrings(Consumer cqlTemplateConsumer) {
- doTestStrings(null, null, null, null, cqlTemplateConsumer, null);
+ doTestStrings(null, null, null, null, null, cqlTemplateConsumer);
}
private void doTestStrings(@Nullable Integer fetchSize, @Nullable ConsistencyLevel consistencyLevel,
@Nullable ConsistencyLevel serialConsistencyLevel, @Nullable String executionProfile,
Consumer cqlTemplateConsumer) {
- doTestStrings(fetchSize, consistencyLevel, serialConsistencyLevel, executionProfile, cqlTemplateConsumer, null);
+ doTestStrings(fetchSize, consistencyLevel, serialConsistencyLevel, executionProfile, null, cqlTemplateConsumer);
}
private void doTestStrings(@Nullable Integer fetchSize, @Nullable ConsistencyLevel consistencyLevel,
@Nullable ConsistencyLevel serialConsistencyLevel, @Nullable String executionProfile,
- Consumer cqlTemplateConsumer, @Nullable CqlIdentifier keyspace) {
+ @Nullable CqlIdentifier keyspace, Consumer cqlTemplateConsumer) {
String[] results = { "Walter", "Hank", " Jesse" };
@@ -717,6 +734,7 @@ class CqlTemplateUnitTests {
when(this.row.getString(0)).thenReturn(results[0], results[1], results[2]);
when(this.session.prepare(anyString())).thenReturn(preparedStatement);
+ when(this.session.prepare(any(SimpleStatement.class))).thenReturn(preparedStatement);
CqlTemplate template = new CqlTemplate();
template.setSession(this.session);
diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/QueryOptionsUnitTests.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/QueryOptionsUnitTests.java
index e72c0e4e2..4066c03d3 100644
--- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/QueryOptionsUnitTests.java
+++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/QueryOptionsUnitTests.java
@@ -35,8 +35,13 @@ class QueryOptionsUnitTests {
@Test // DATACASS-202
void buildQueryOptions() {
- QueryOptions queryOptions = QueryOptions.builder().consistencyLevel(DefaultConsistencyLevel.ANY)
- .timeout(Duration.ofSeconds(1)).pageSize(10).tracing(true).keyspace(CqlIdentifier.fromCql("ks1")).build();
+ QueryOptions queryOptions = QueryOptions.builder() //
+ .consistencyLevel(DefaultConsistencyLevel.ANY) //
+ .timeout(Duration.ofSeconds(1)) //
+ .pageSize(10) //
+ .tracing(true) //
+ .keyspace(CqlIdentifier.fromCql("ks1")) //
+ .build();
assertThat(queryOptions.getClass()).isEqualTo(QueryOptions.class);
assertThat(queryOptions.getConsistencyLevel()).isEqualTo(DefaultConsistencyLevel.ANY);
@@ -49,13 +54,17 @@ class QueryOptionsUnitTests {
@Test // DATACASS-56
void buildQueryOptionsMutate() {
- QueryOptions queryOptions = QueryOptions.builder().consistencyLevel(DefaultConsistencyLevel.ANY)
- .timeout(Duration.ofSeconds(1)).pageSize(10).tracing(true).keyspace(CqlIdentifier.fromCql("ks1")).build();
+ QueryOptions queryOptions = QueryOptions.builder() //
+ .consistencyLevel(DefaultConsistencyLevel.ANY) //
+ .timeout(Duration.ofSeconds(1)) //
+ .pageSize(10) //
+ .tracing(true) //
+ .keyspace(CqlIdentifier.fromCql("ks1")) //
+ .build();
QueryOptions mutated = queryOptions.mutate().timeout(Duration.ofSeconds(5)).build();
- assertThat(mutated).isNotNull();
- assertThat(mutated).isNotSameAs(queryOptions);
+ assertThat(mutated).isNotNull().isNotSameAs(queryOptions);
assertThat(mutated.getClass()).isEqualTo(QueryOptions.class);
assertThat(mutated.getConsistencyLevel()).isEqualTo(DefaultConsistencyLevel.ANY);
assertThat(mutated.getTimeout()).isEqualTo(Duration.ofSeconds(5));
diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/QueryOptionsUtilUnitTests.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/QueryOptionsUtilUnitTests.java
index a822c186e..79dd7e386 100755
--- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/QueryOptionsUtilUnitTests.java
+++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/QueryOptionsUtilUnitTests.java
@@ -23,7 +23,6 @@ import java.util.concurrent.TimeUnit;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
-
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
@@ -99,6 +98,7 @@ class QueryOptionsUtilUnitTests {
@Test // DATACASS-767
void addKeyspaceOptionsOnSimpleStatementShouldAddDriverQueryOptions() {
+
when(simpleStatement.setKeyspace(any(CqlIdentifier.class))).thenReturn(simpleStatement);
QueryOptions queryOptions = QueryOptions.builder() //
@@ -111,6 +111,7 @@ class QueryOptionsUtilUnitTests {
@Test // DATACASS-767
void addKeyspaceOptionsOnBatchStatementShouldAddDriverQueryOptions() {
+
when(batchStatement.setKeyspace(any(CqlIdentifier.class))).thenReturn(batchStatement);
QueryOptions queryOptions = QueryOptions.builder() //
@@ -123,12 +124,12 @@ class QueryOptionsUtilUnitTests {
@Test // DATACASS-767
void addKeyspaceOptionsOnBoundStatementShouldThrowException() {
+
QueryOptions queryOptions = QueryOptions.builder() //
.keyspace(CqlIdentifier.fromCql("ks1")).build();
assertThatThrownBy(() -> QueryOptionsUtil.addQueryOptions(boundStatement, queryOptions))
.isInstanceOf(IllegalArgumentException.class)
.hasMessageContaining("Keyspace cannot be set for a BoundStatement");
-
}
}
diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/ReactiveCqlTemplateUnitTests.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/ReactiveCqlTemplateUnitTests.java
index d8da69ea5..df80ab48f 100644
--- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/ReactiveCqlTemplateUnitTests.java
+++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/ReactiveCqlTemplateUnitTests.java
@@ -28,12 +28,12 @@ import java.util.function.Consumer;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
-
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.junit.jupiter.MockitoSettings;
import org.mockito.quality.Strictness;
+
import org.springframework.dao.IncorrectResultSizeDataAccessException;
import org.springframework.data.cassandra.CassandraConnectionFailureException;
import org.springframework.data.cassandra.CassandraInvalidQueryException;
@@ -550,6 +550,24 @@ class ReactiveCqlTemplateUnitTests {
});
}
+ @Test // DATACASS-767
+ void executePreparedStatementShouldApplyKeyspace() {
+
+ when(preparedStatement.bind("A")).thenReturn(boundStatement);
+ when(boundStatement.getKeyspace()).thenReturn(CqlIdentifier.fromCql("ks1"));
+
+ doTestStrings(null, null, null, null, CqlIdentifier.fromCql("ks1"), cqlTemplate -> {
+ cqlTemplate.execute("SELECT * from USERS", (session, ps) -> session.execute(ps.bind("A")))
+ .as(StepVerifier::create).expectNextCount(1).verifyComplete();
+ });
+
+ ArgumentCaptor captor = ArgumentCaptor.forClass(SimpleStatement.class);
+ verify(session).prepare(captor.capture());
+
+ SimpleStatement statement = captor.getValue();
+ assertThat(statement.getKeyspace()).isEqualTo(CqlIdentifier.fromCql("ks1"));
+ }
+
@Test // DATACASS-335
void executePreparedStatementWithCallbackShouldCallExecution() {
@@ -566,7 +584,7 @@ class ReactiveCqlTemplateUnitTests {
@Test // DATACASS-335
void executePreparedStatementCallbackShouldExecuteDeferred() {
- when(session.prepare(anyString())).thenReturn(Mono.just(preparedStatement));
+ when(session.prepare(any(SimpleStatement.class))).thenReturn(Mono.just(preparedStatement));
when(preparedStatement.bind()).thenReturn(boundStatement);
when(session.execute(boundStatement)).thenReturn(Mono.just(reactiveResultSet));
@@ -577,7 +595,7 @@ class ReactiveCqlTemplateUnitTests {
flux.as(StepVerifier::create).expectNext(reactiveResultSet).verifyComplete();
- verify(session).prepare(anyString());
+ verify(session).prepare(any(SimpleStatement.class));
verify(session).execute(boundStatement);
}
@@ -670,7 +688,7 @@ class ReactiveCqlTemplateUnitTests {
@Test // DATACASS-335
void queryForObjectPreparedStatementShouldBeEmpty() {
- when(session.prepare("SELECT * FROM user WHERE username = ?")).thenReturn(Mono.just(preparedStatement));
+ when(session.prepare(any(SimpleStatement.class))).thenReturn(Mono.just(preparedStatement));
when(preparedStatement.bind("Walter")).thenReturn(boundStatement);
when(session.execute(boundStatement)).thenReturn(Mono.just(reactiveResultSet));
when(reactiveResultSet.rows()).thenReturn(Flux.empty());
@@ -684,7 +702,7 @@ class ReactiveCqlTemplateUnitTests {
@Test // DATACASS-335
void queryForObjectPreparedStatementShouldReturnRecord() {
- when(session.prepare("SELECT * FROM user WHERE username = ?")).thenReturn(Mono.just(preparedStatement));
+ when(session.prepare(any(SimpleStatement.class))).thenReturn(Mono.just(preparedStatement));
when(preparedStatement.bind("Walter")).thenReturn(boundStatement);
when(session.execute(boundStatement)).thenReturn(Mono.just(reactiveResultSet));
when(reactiveResultSet.rows()).thenReturn(Flux.just(row));
@@ -698,7 +716,7 @@ class ReactiveCqlTemplateUnitTests {
@Test // DATACASS-335
void queryForObjectPreparedStatementShouldFailReturningManyRecords() {
- when(session.prepare("SELECT * FROM user WHERE username = ?")).thenReturn(Mono.just(preparedStatement));
+ when(session.prepare(any(SimpleStatement.class))).thenReturn(Mono.just(preparedStatement));
when(preparedStatement.bind("Walter")).thenReturn(boundStatement);
when(session.execute(boundStatement)).thenReturn(Mono.just(reactiveResultSet));
when(reactiveResultSet.rows()).thenReturn(Flux.just(row, row));
@@ -712,7 +730,7 @@ class ReactiveCqlTemplateUnitTests {
@Test // DATACASS-335
void queryForObjectPreparedStatementWithTypeShouldReturnRecord() {
- when(session.prepare("SELECT * FROM user WHERE username = ?")).thenReturn(Mono.just(preparedStatement));
+ when(session.prepare(any(SimpleStatement.class))).thenReturn(Mono.just(preparedStatement));
when(preparedStatement.bind("Walter")).thenReturn(boundStatement);
when(session.execute(boundStatement)).thenReturn(Mono.just(reactiveResultSet));
when(reactiveResultSet.rows()).thenReturn(Flux.just(row));
@@ -728,7 +746,7 @@ class ReactiveCqlTemplateUnitTests {
@Test // DATACASS-335
void queryForFluxPreparedStatementWithTypeShouldReturnRecord() {
- when(session.prepare("SELECT * FROM user WHERE username = ?")).thenReturn(Mono.just(preparedStatement));
+ when(session.prepare(any(SimpleStatement.class))).thenReturn(Mono.just(preparedStatement));
when(preparedStatement.bind("Walter")).thenReturn(boundStatement);
when(session.execute(boundStatement)).thenReturn(Mono.just(reactiveResultSet));
when(reactiveResultSet.rows()).thenReturn(Flux.just(row, row));
@@ -744,7 +762,7 @@ class ReactiveCqlTemplateUnitTests {
@Test // DATACASS-335
void queryForRowsPreparedStatementReturnRows() {
- when(session.prepare("SELECT * FROM user WHERE username = ?")).thenReturn(Mono.just(preparedStatement));
+ when(session.prepare(any(SimpleStatement.class))).thenReturn(Mono.just(preparedStatement));
when(preparedStatement.bind("Walter")).thenReturn(boundStatement);
when(session.execute(boundStatement)).thenReturn(Mono.just(reactiveResultSet));
when(reactiveResultSet.rows()).thenReturn(Flux.just(row, row));
@@ -757,7 +775,7 @@ class ReactiveCqlTemplateUnitTests {
@Test // DATACASS-335
void updatePreparedStatementShouldReturnApplied() {
- when(session.prepare("UPDATE user SET username = ?")).thenReturn(Mono.just(preparedStatement));
+ when(session.prepare(any(SimpleStatement.class))).thenReturn(Mono.just(preparedStatement));
when(preparedStatement.bind("Walter")).thenReturn(boundStatement);
when(session.execute(boundStatement)).thenReturn(Mono.just(reactiveResultSet));
when(reactiveResultSet.wasApplied()).thenReturn(true);
@@ -770,7 +788,7 @@ class ReactiveCqlTemplateUnitTests {
@Test // DATACASS-335
void updatePreparedStatementArgsPublisherShouldReturnApplied() {
- when(session.prepare("UPDATE user SET username = ?")).thenReturn(Mono.just(preparedStatement));
+ when(session.prepare(any(SimpleStatement.class))).thenReturn(Mono.just(preparedStatement));
when(preparedStatement.bind("Walter")).thenReturn(boundStatement);
when(preparedStatement.bind("Hank")).thenReturn(boundStatement);
when(session.execute(boundStatement)).thenReturn(Mono.just(reactiveResultSet));
@@ -786,18 +804,18 @@ class ReactiveCqlTemplateUnitTests {
}
private void doTestStrings(Consumer cqlTemplateConsumer) {
- doTestStrings(null, null, null, null, cqlTemplateConsumer, null);
+ doTestStrings(null, null, null, null, null, cqlTemplateConsumer);
}
private void doTestStrings(@Nullable Integer fetchSize, @Nullable ConsistencyLevel consistencyLevel,
@Nullable ConsistencyLevel serialConsistencyLevel, @Nullable String executionProfile,
Consumer cqlTemplateConsumer) {
- doTestStrings(fetchSize, consistencyLevel, serialConsistencyLevel, executionProfile, cqlTemplateConsumer, null);
+ doTestStrings(fetchSize, consistencyLevel, serialConsistencyLevel, executionProfile, null, cqlTemplateConsumer);
}
private void doTestStrings(@Nullable Integer fetchSize, @Nullable ConsistencyLevel consistencyLevel,
@Nullable ConsistencyLevel serialConsistencyLevel, @Nullable String executionProfile,
- Consumer cqlTemplateConsumer, @Nullable CqlIdentifier keyspace) {
+ @Nullable CqlIdentifier keyspace, Consumer cqlTemplateConsumer) {
String[] results = { "Walter", "Hank", " Jesse" };
@@ -806,6 +824,7 @@ class ReactiveCqlTemplateUnitTests {
when(this.row.getString(0)).thenReturn(results[0], results[1], results[2]);
when(this.session.prepare(anyString())).thenReturn(Mono.just(this.preparedStatement));
+ when(this.session.prepare(any(SimpleStatement.class))).thenReturn(Mono.just(this.preparedStatement));
ReactiveCqlTemplate template = new ReactiveCqlTemplate();
template.setSessionFactory(this.sessionFactory);
@@ -852,6 +871,7 @@ class ReactiveCqlTemplateUnitTests {
if (executionProfile != null) {
assertThat(statement.getExecutionProfileName()).isEqualTo(executionProfile);
}
+
if (keyspace != null) {
assertThat(statement.getKeyspace()).isEqualTo(keyspace);
}
diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/WriteOptionsUnitTests.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/WriteOptionsUnitTests.java
index 01d0588b9..5a3898fd6 100644
--- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/WriteOptionsUnitTests.java
+++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/cql/WriteOptionsUnitTests.java
@@ -24,6 +24,7 @@ import java.time.ZoneOffset;
import org.junit.jupiter.api.Test;
+import com.datastax.oss.driver.api.core.CqlIdentifier;
import com.datastax.oss.driver.api.core.DefaultConsistencyLevel;
/**
@@ -33,17 +34,17 @@ import com.datastax.oss.driver.api.core.DefaultConsistencyLevel;
*/
class WriteOptionsUnitTests {
- @Test // DATACASS-202
+ @Test // DATACASS-202, DATACASS-767
void buildWriteOptions() {
- WriteOptions writeOptions = WriteOptions.builder()
- .consistencyLevel(DefaultConsistencyLevel.ANY)
- .ttl(123)
- .timestamp(1519000753)
- .readTimeout(1)
- .pageSize(10)
- .withTracing()
- .build();
+ WriteOptions writeOptions = WriteOptions.builder() //
+ .consistencyLevel(DefaultConsistencyLevel.ANY) //
+ .ttl(123) //
+ .timestamp(1519000753) //
+ .readTimeout(1) //
+ .pageSize(10) //
+ .withTracing() //
+ .keyspace(CqlIdentifier.fromCql("my_keyspace")).build();
assertThat(writeOptions.getTtl()).isEqualTo(Duration.ofSeconds(123));
assertThat(writeOptions.getTimestamp()).isEqualTo(1519000753);
@@ -51,6 +52,7 @@ class WriteOptionsUnitTests {
assertThat(writeOptions.getTimeout()).isEqualTo(Duration.ofMillis(1));
assertThat(writeOptions.getPageSize()).isEqualTo(10);
assertThat(writeOptions.getTracing()).isTrue();
+ assertThat(writeOptions.getKeyspace()).isEqualTo(CqlIdentifier.fromCql("my_keyspace"));
}
@Test // DATACASS-202
@@ -63,18 +65,17 @@ class WriteOptionsUnitTests {
assertThat(writeOptions.getTracing()).isNull();
}
-
@Test // DATACASS-56
void buildWriteOptionsMutate() {
Instant now = LocalDateTime.now().toInstant(ZoneOffset.UTC);
- WriteOptions writeOptions = WriteOptions.builder()
- .consistencyLevel(DefaultConsistencyLevel.ANY)
- .ttl(123)
- .timestamp(now)
- .readTimeout(1)
- .pageSize(10)
- .withTracing()
+ WriteOptions writeOptions = WriteOptions.builder() //
+ .consistencyLevel(DefaultConsistencyLevel.ANY) //
+ .ttl(123) //
+ .timestamp(now) //
+ .readTimeout(1) //
+ .pageSize(10) //
+ .withTracing() //
.build();
WriteOptions mutated = writeOptions.mutate().timeout(Duration.ofMillis(100)).build();
diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/util/CassandraDelegate.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/util/CassandraDelegate.java
index 69e28120f..a013094ad 100644
--- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/util/CassandraDelegate.java
+++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/util/CassandraDelegate.java
@@ -28,11 +28,13 @@ import org.springframework.data.cassandra.support.CqlDataSet;
import org.springframework.util.Assert;
import org.springframework.util.SocketUtils;
import org.springframework.util.StringUtils;
+
import org.testcontainers.containers.CassandraContainer;
import com.datastax.oss.driver.api.core.CqlIdentifier;
import com.datastax.oss.driver.api.core.CqlSession;
import com.datastax.oss.driver.api.core.CqlSessionBuilder;
+import com.datastax.oss.driver.api.core.Version;
import com.datastax.oss.driver.api.core.config.DefaultDriverOption;
import com.datastax.oss.driver.api.core.config.DriverConfigLoader;
import com.datastax.oss.driver.api.core.metadata.Node;
@@ -302,8 +304,9 @@ class CassandraDelegate {
CqlSessionBuilder builder = CqlSession.builder().addContactPoint(InetSocketAddress.createUnresolved(host, port))
.withLocalDatacenter("datacenter1");
- CqlSession cqlSession = builder.build();
- if (cassandraVersionGreaterThanOrEqualTo4(cqlSession)) {
+ Version cassandraVersion = getCassandraVersion(builder);
+
+ if (cassandraVersion.getMajor() >= 4) {
return builder.withConfigLoader(
DriverConfigLoader.programmaticBuilder().withString(DefaultDriverOption.PROTOCOL_VERSION, "V5").build());
} else {
@@ -311,9 +314,17 @@ class CassandraDelegate {
}
}
- private boolean cassandraVersionGreaterThanOrEqualTo4(CqlSession cqlSession) {
- return cqlSession.getMetadata().getNodes().values().stream().map(Node::getCassandraVersion)
- .allMatch(v -> v != null && v.getMajor() >= 4);
+ private Version getCassandraVersion(CqlSessionBuilder builder) {
+
+ try (CqlSession cqlSession = builder.build()) {
+
+ return cqlSession.getMetadata().getNodes() //
+ .values() //
+ .stream() //
+ .map(Node::getCassandraVersion) //
+ .findFirst() //
+ .orElseThrow(() -> new IllegalStateException("Cannot determine Cassandra version"));
+ }
}
private String resolveHost() {
diff --git a/src/main/asciidoc/new-features.adoc b/src/main/asciidoc/new-features.adoc
index bee5bbab8..52b0dcfd3 100644
--- a/src/main/asciidoc/new-features.adoc
+++ b/src/main/asciidoc/new-features.adoc
@@ -8,6 +8,7 @@ This chapter summarizes changes and new features for each release.
* <> enabled through `@EnableReactiveCassandraAuditing`. `@EnableCassandraAuditing` no longer registers `ReactiveAuditingEntityCallback`.
* Reactive SpEL support in `@Query` query methods.
+* Configuration of the keyspace per `Statement` through `CqlTemplate` and `QueryOptions`.
[[new-features.3-0-0]]
== What's new in Spring Data for Apache Cassandra 3.0