diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/DeleteOptions.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/DeleteOptions.java index bb8bdd62f..b61297d81 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/DeleteOptions.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/DeleteOptions.java @@ -1,5 +1,5 @@ /* - * Copyright 2019-2021 the original author or authors. + * Copyright 2019-2022 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. @@ -15,6 +15,7 @@ */ package org.springframework.data.cassandra.core; +import java.nio.ByteBuffer; import java.time.Duration; import java.time.Instant; import java.util.concurrent.TimeUnit; @@ -35,6 +36,7 @@ import com.datastax.oss.driver.api.core.CqlIdentifier; * * @author Mark Paluch * @author Tomasz Lelek + * @author Sam Lightfoot * @since 2.2 */ public class DeleteOptions extends WriteOptions { @@ -48,10 +50,11 @@ public class DeleteOptions extends WriteOptions { private DeleteOptions(@Nullable ConsistencyLevel consistencyLevel, ExecutionProfileResolver executionProfileResolver, @Nullable CqlIdentifier keyspace, @Nullable Integer pageSize, @Nullable ConsistencyLevel serialConsistencyLevel, Duration timeout, Duration ttl, @Nullable Long timestamp, @Nullable Boolean tracing, boolean ifExists, - @Nullable Filter ifCondition) { + @Nullable Filter ifCondition, @Nullable Boolean idempotent, @Nullable CqlIdentifier routingKeyspace, + @Nullable ByteBuffer routingKey) { super(consistencyLevel, executionProfileResolver, keyspace, pageSize, serialConsistencyLevel, timeout, ttl, - timestamp, tracing); + timestamp, tracing, idempotent, routingKeyspace, routingKey); this.ifExists = ifExists; this.ifCondition = ifCondition; @@ -242,6 +245,13 @@ public class DeleteOptions extends WriteOptions { return this; } + @Override + public DeleteOptionsBuilder idempotent(boolean idempotent) { + + super.idempotent(idempotent); + return this; + } + public DeleteOptionsBuilder ttl(int ttl) { super.ttl(ttl); @@ -262,6 +272,19 @@ public class DeleteOptions extends WriteOptions { return this; } + @Override + public DeleteOptionsBuilder routingKeyspace(CqlIdentifier routingKeyspace) { + + super.routingKeyspace(routingKeyspace); + return this; + } + + @Override + public DeleteOptionsBuilder routingKey(ByteBuffer routingKey) { + + super.routingKey(routingKey); + return this; + } /** * Use light-weight transactions by applying {@code IF EXISTS}. Replaces a previous {@link #ifCondition(Filter)}. @@ -326,7 +349,7 @@ public class DeleteOptions extends WriteOptions { return new DeleteOptions(this.consistencyLevel, this.executionProfileResolver, this.keyspace, this.pageSize, this.serialConsistencyLevel, this.timeout, this.ttl, this.timestamp, this.tracing, this.ifExists, - this.ifCondition); + this.ifCondition, this.idempotent, this.routingKeyspace, this.routingKey); } } } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/InsertOptions.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/InsertOptions.java index 32107f8b6..daa535793 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/InsertOptions.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/InsertOptions.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2021 the original author or authors. + * Copyright 2017-2022 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. @@ -15,6 +15,7 @@ */ package org.springframework.data.cassandra.core; +import java.nio.ByteBuffer; import java.time.Duration; import java.time.Instant; import java.util.concurrent.TimeUnit; @@ -32,6 +33,7 @@ import com.datastax.oss.driver.api.core.CqlIdentifier; * @author Mark Paluch * @author Lukasz Antoniak * @author Tomasz Lelek + * @author Sam Lightfoot * @since 2.0 */ public class InsertOptions extends WriteOptions { @@ -45,10 +47,11 @@ public class InsertOptions extends WriteOptions { private InsertOptions(@Nullable ConsistencyLevel consistencyLevel, ExecutionProfileResolver executionProfileResolver, @Nullable CqlIdentifier keyspace, @Nullable Integer pageSize, @Nullable ConsistencyLevel serialConsistencyLevel, Duration timeout, Duration ttl, @Nullable Long timestamp, @Nullable Boolean tracing, boolean ifNotExists, - boolean insertNulls) { + boolean insertNulls, @Nullable Boolean idempotent, @Nullable CqlIdentifier routingKeyspace, + @Nullable ByteBuffer routingKey) { super(consistencyLevel, executionProfileResolver, keyspace, pageSize, serialConsistencyLevel, timeout, ttl, - timestamp, tracing); + timestamp, tracing, idempotent, routingKeyspace, routingKey); this.ifNotExists = ifNotExists; this.insertNulls = insertNulls; @@ -261,6 +264,27 @@ public class InsertOptions extends WriteOptions { return this; } + @Override + public InsertOptionsBuilder idempotent(boolean idempotent) { + + super.idempotent(idempotent); + return this; + } + + @Override + public InsertOptionsBuilder routingKeyspace(CqlIdentifier routingKeyspace) { + + super.routingKeyspace(routingKeyspace); + return this; + } + + @Override + public InsertOptionsBuilder routingKey(ByteBuffer routingKey) { + + super.routingKey(routingKey); + return this; + } + /** * Use light-weight transactions by applying {@code IF NOT EXISTS}. * @@ -319,7 +343,7 @@ public class InsertOptions extends WriteOptions { public InsertOptions build() { return new InsertOptions(this.consistencyLevel, this.executionProfileResolver, this.keyspace, this.pageSize, this.serialConsistencyLevel, this.timeout, this.ttl, this.timestamp, this.tracing, this.ifNotExists, - this.insertNulls); + this.insertNulls, this.idempotent, this.routingKeyspace, this.routingKey); } } } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/UpdateOptions.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/UpdateOptions.java index 242a45a4d..2c9b6a988 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/UpdateOptions.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/UpdateOptions.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2021 the original author or authors. + * Copyright 2017-2022 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. @@ -15,6 +15,7 @@ */ package org.springframework.data.cassandra.core; +import java.nio.ByteBuffer; import java.time.Duration; import java.time.Instant; import java.util.concurrent.TimeUnit; @@ -36,6 +37,7 @@ import com.datastax.oss.driver.api.core.CqlIdentifier; * @author Mark Paluch * @author Lukasz Antoniak * @author Tomasz Lelek + * @author Sam Lightfoot * @since 2.0 */ public class UpdateOptions extends WriteOptions { @@ -49,10 +51,11 @@ public class UpdateOptions extends WriteOptions { private UpdateOptions(@Nullable ConsistencyLevel consistencyLevel, ExecutionProfileResolver executionProfileResolver, @Nullable CqlIdentifier keyspace, @Nullable Integer pageSize, @Nullable ConsistencyLevel serialConsistencyLevel, Duration timeout, Duration ttl, @Nullable Long timestamp, @Nullable Boolean tracing, boolean ifExists, - @Nullable Filter ifCondition) { + @Nullable Filter ifCondition, @Nullable Boolean idempotent, @Nullable CqlIdentifier routingKeyspace, + @Nullable ByteBuffer routingKey) { super(consistencyLevel, executionProfileResolver, keyspace, pageSize, serialConsistencyLevel, timeout, ttl, - timestamp, tracing); + timestamp, tracing, idempotent, routingKeyspace, routingKey); this.ifExists = ifExists; this.ifCondition = ifCondition; @@ -249,6 +252,13 @@ public class UpdateOptions extends WriteOptions { return this; } + @Override + public UpdateOptionsBuilder idempotent(boolean idempotent) { + + super.idempotent(idempotent); + return this; + } + public UpdateOptionsBuilder ttl(int ttl) { super.ttl(ttl); @@ -269,6 +279,20 @@ public class UpdateOptions extends WriteOptions { return this; } + @Override + public UpdateOptionsBuilder routingKeyspace(CqlIdentifier routingKeyspace) { + + super.routingKeyspace(routingKeyspace); + return this; + } + + @Override + public UpdateOptionsBuilder routingKey(ByteBuffer routingKey) { + + super.routingKey(routingKey); + return this; + } + /** * Use light-weight transactions by applying {@code IF EXISTS}. Replaces a previous {@link #ifCondition(Filter)}. * @@ -333,7 +357,7 @@ public class UpdateOptions extends WriteOptions { public UpdateOptions build() { return new UpdateOptions(this.consistencyLevel, this.executionProfileResolver, this.keyspace, this.pageSize, this.serialConsistencyLevel, this.timeout, this.ttl, this.timestamp, this.tracing, this.ifExists, - this.ifCondition); + this.ifCondition, this.idempotent, this.routingKeyspace, this.routingKey); } } } 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 b88edb343..d63afb6c0 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 @@ -529,7 +529,6 @@ public class CqlTemplate extends CassandraAccessor implements CqlOperations { return hostMapper.mapHosts(getHosts()); } - /* (non-Javadoc) */ private Collection getHosts() { return getCurrentSession().getMetadata().getNodes().values(); } 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 b765daca2..fe8e76732 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 @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 the original author or authors. + * Copyright 2013-2022 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. @@ -15,6 +15,7 @@ */ package org.springframework.data.cassandra.core.cql; +import java.nio.ByteBuffer; import java.time.Duration; import java.util.concurrent.TimeUnit; @@ -34,6 +35,7 @@ import com.datastax.oss.driver.api.core.config.DriverExecutionProfile; * @author David Webb * @author Mark Paluch * @author Tomasz Lelek + * @author Sam Lightfoot */ public class QueryOptions { @@ -53,9 +55,16 @@ public class QueryOptions { private final @Nullable Boolean tracing; + private final @Nullable Boolean idempotent; + + private final @Nullable CqlIdentifier routingKeyspace; + + private final @Nullable ByteBuffer routingKey; + protected QueryOptions(@Nullable ConsistencyLevel consistencyLevel, ExecutionProfileResolver executionProfileResolver, @Nullable CqlIdentifier keyspace, @Nullable Integer pageSize, @Nullable ConsistencyLevel serialConsistencyLevel, - Duration timeout, @Nullable Boolean tracing) { + Duration timeout, @Nullable Boolean tracing, @Nullable Boolean idempotent, @Nullable CqlIdentifier routingKeyspace, + @Nullable ByteBuffer routingKey) { this.consistencyLevel = consistencyLevel; this.executionProfileResolver = executionProfileResolver; @@ -64,6 +73,9 @@ public class QueryOptions { this.serialConsistencyLevel = serialConsistencyLevel; this.timeout = timeout; this.tracing = tracing; + this.idempotent = idempotent; + this.routingKey = routingKey; + this.routingKeyspace = routingKeyspace; } /** @@ -160,6 +172,16 @@ public class QueryOptions { return this.tracing; } + /** + * @return whether query is idempotent. May be {@literal null} if not set. + * @since 3.3.2 + * @see com.datastax.oss.driver.api.core.cql.Statement#setIdempotent(Boolean) + */ + @Nullable + protected Boolean isIdempotent() { + return this.idempotent; + } + /** * @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. @@ -170,6 +192,26 @@ public class QueryOptions { return keyspace; } + /** + * @return the keyspace used for token-aware routing. May be {@literal null} if token-aware routing is disabled. + * @since 3.3.2 + * @see com.datastax.oss.driver.api.core.cql.Statement#setRoutingKeyspace(CqlIdentifier) + */ + @Nullable + protected CqlIdentifier getRoutingKeyspace() { + return this.routingKeyspace; + } + + /** + * @return the key used for token-aware routing. May be {@literal null} if token-aware routing is disabled. + * @since 3.3.2 + * @see com.datastax.oss.driver.api.core.cql.Statement#setRoutingKey(ByteBuffer) + */ + @Nullable + protected ByteBuffer getRoutingKey() { + return this.routingKey; + } + @Override public boolean equals(Object o) { @@ -207,6 +249,18 @@ public class QueryOptions { return false; } + if (!ObjectUtils.nullSafeEquals(idempotent, options.idempotent)) { + return false; + } + + if (!ObjectUtils.nullSafeEquals(routingKeyspace, options.routingKeyspace)) { + return false; + } + + if (!ObjectUtils.nullSafeEquals(routingKey, options.routingKey)) { + return false; + } + return ObjectUtils.nullSafeEquals(keyspace, options.keyspace); } @@ -218,7 +272,10 @@ public class QueryOptions { result = 31 * result + ObjectUtils.nullSafeHashCode(serialConsistencyLevel); result = 31 * result + ObjectUtils.nullSafeHashCode(timeout); result = 31 * result + ObjectUtils.nullSafeHashCode(tracing); + result = 31 * result + ObjectUtils.nullSafeHashCode(idempotent); result = 31 * result + ObjectUtils.nullSafeHashCode(keyspace); + result = 31 * result + ObjectUtils.nullSafeHashCode(routingKeyspace); + result = 31 * result + ObjectUtils.nullSafeHashCode(routingKey); return result; } @@ -236,6 +293,8 @@ public class QueryOptions { protected @Nullable CqlIdentifier keyspace; + protected @Nullable CqlIdentifier routingKeyspace; + protected @Nullable Integer pageSize; protected @Nullable ConsistencyLevel serialConsistencyLevel; @@ -244,6 +303,10 @@ public class QueryOptions { protected @Nullable Boolean tracing; + protected @Nullable Boolean idempotent; + + protected @Nullable ByteBuffer routingKey; + QueryOptionsBuilder() {} QueryOptionsBuilder(QueryOptions queryOptions) { @@ -255,6 +318,9 @@ public class QueryOptions { this.serialConsistencyLevel = queryOptions.serialConsistencyLevel; this.timeout = queryOptions.timeout; this.tracing = queryOptions.tracing; + this.idempotent = queryOptions.idempotent; + this.routingKeyspace = queryOptions.routingKeyspace; + this.routingKey = queryOptions.routingKey; } /** @@ -463,14 +529,54 @@ public class QueryOptions { return tracing(true); } + /** + * Set query execution idempotency. + * + * @param idempotent {@literal true} to mark the query as idempotent. + * @return {@code this} {@link QueryOptionsBuilder} + */ + public QueryOptionsBuilder idempotent(boolean idempotent) { + + this.idempotent = idempotent; + + return this; + } + + /** + * Set query routing keyspace. + * + * @param routingKeyspace the routing keyspace to use for token-aware routing. Can be {@literal null}. + * @return {@code this} {@link QueryOptionsBuilder} + */ + public QueryOptionsBuilder routingKeyspace(CqlIdentifier routingKeyspace) { + + this.routingKeyspace = routingKeyspace; + + return this; + } + + /** + * Set query routing key. + * + * @param routingKey the routing key to use for token-aware routing. Can be {@literal null}. + * @return {@code this} {@link QueryOptionsBuilder} + */ + public QueryOptionsBuilder routingKey(ByteBuffer routingKey) { + + this.routingKey = routingKey; + + 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.keyspace, this.pageSize, - this.serialConsistencyLevel, this.timeout, this.tracing); + return new QueryOptions(this.consistencyLevel, this.executionProfileResolver, this.keyspace, + this.pageSize, this.serialConsistencyLevel, this.timeout, this.tracing, this.idempotent, + this.routingKeyspace, this.routingKey); } } } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/QueryOptionsUtil.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/QueryOptionsUtil.java index 9fc2ea7f4..0a61e0f6d 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/QueryOptionsUtil.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/QueryOptionsUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2021 the original author or authors. + * Copyright 2016-2022 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. @@ -35,6 +35,7 @@ import com.datastax.oss.driver.api.querybuilder.update.UpdateStart; * @author Mark Paluch * @author Lukasz Antoniak * @author Tomasz Lelek + * @author Sam Lightfoot * @since 2.0 */ public abstract class QueryOptionsUtil { @@ -77,6 +78,19 @@ public abstract class QueryOptionsUtil { // statement wrapped in the conditional null check to avoid additional garbage and added GC pressure. statementToUse = statementToUse.setTracing(Boolean.TRUE.equals(queryOptions.getTracing())); } + + if (queryOptions.isIdempotent() != null) { + statementToUse = statementToUse.setIdempotent(queryOptions.isIdempotent()); + } + + if (queryOptions.getRoutingKeyspace() != null) { + statementToUse = statementToUse.setRoutingKeyspace(queryOptions.getRoutingKeyspace()); + } + + if (queryOptions.getRoutingKey() != null) { + statementToUse = statement.setRoutingKey(queryOptions.getRoutingKey()); + } + if (queryOptions.getKeyspace() != null) { if (statementToUse instanceof BoundStatement) { throw new IllegalArgumentException("Keyspace cannot be set for a BoundStatement"); 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 9e87d1856..ce0d8cee0 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 @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 the original author or authors. + * Copyright 2013-2022 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. @@ -15,6 +15,7 @@ */ package org.springframework.data.cassandra.core.cql; +import java.nio.ByteBuffer; import java.time.Duration; import java.time.Instant; import java.util.concurrent.TimeUnit; @@ -34,6 +35,7 @@ import com.datastax.oss.driver.api.core.CqlIdentifier; * @author Mark Paluch * @author Lukasz Antoniak * @author Tomasz Lelek + * @author Sam Lightfoot * @see QueryOptions */ public class WriteOptions extends QueryOptions { @@ -46,10 +48,10 @@ public class WriteOptions extends QueryOptions { protected WriteOptions(@Nullable ConsistencyLevel consistencyLevel, ExecutionProfileResolver executionProfileResolver, @Nullable CqlIdentifier keyspace, @Nullable Integer pageSize, @Nullable ConsistencyLevel serialConsistencyLevel, - Duration timeout, Duration ttl, - @Nullable Long timestamp, @Nullable Boolean tracing) { + Duration timeout, Duration ttl, @Nullable Long timestamp, @Nullable Boolean tracing, @Nullable Boolean idempotent, + @Nullable CqlIdentifier routingKeyspace, @Nullable ByteBuffer routingKey) { - super(consistencyLevel, executionProfileResolver, keyspace, pageSize, serialConsistencyLevel, timeout, tracing); + super(consistencyLevel, executionProfileResolver, keyspace, pageSize, serialConsistencyLevel, timeout, tracing, idempotent, routingKeyspace, routingKey); this.ttl = ttl; this.timestamp = timestamp; @@ -241,6 +243,27 @@ public class WriteOptions extends QueryOptions { return this; } + @Override + public WriteOptionsBuilder idempotent(boolean idempotent) { + + super.idempotent(idempotent); + return this; + } + + @Override + public WriteOptionsBuilder routingKeyspace(CqlIdentifier routingKeyspace) { + + super.routingKeyspace(routingKeyspace); + return this; + } + + @Override + public WriteOptionsBuilder routingKey(ByteBuffer routingKey) { + + super.routingKey(routingKey); + return this; + } + /** * Sets the time to live in seconds for write operations. * @@ -313,7 +336,8 @@ public class WriteOptions extends QueryOptions { */ public WriteOptions build() { return new WriteOptions(this.consistencyLevel, this.executionProfileResolver, this.keyspace, this.pageSize, - this.serialConsistencyLevel, this.timeout, this.ttl, this.timestamp, this.tracing); + this.serialConsistencyLevel, this.timeout, this.ttl, this.timestamp, this.tracing, this.idempotent, + this.routingKeyspace, this.routingKey); } } } 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 1783a117f..b57a37032 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 @@ -1,5 +1,5 @@ /* - * Copyright 2016-2021 the original author or authors. + * Copyright 2016-2022 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. @@ -17,6 +17,7 @@ package org.springframework.data.cassandra.core.cql; import static org.assertj.core.api.Assertions.*; +import java.nio.ByteBuffer; import java.time.Duration; import org.junit.jupiter.api.Test; @@ -29,6 +30,7 @@ import com.datastax.oss.driver.api.core.DefaultConsistencyLevel; * * @author Mark Paluch * @author Tomasz Lelek + * @author Sam Lightfoot */ class QueryOptionsUnitTests { @@ -41,6 +43,9 @@ class QueryOptionsUnitTests { .pageSize(10) // .tracing(true) // .keyspace(CqlIdentifier.fromCql("ks1")) // + .idempotent(true) + .routingKeyspace(CqlIdentifier.fromCql("rksl")) + .routingKey(ByteBuffer.allocate(1)) .build(); assertThat(queryOptions.getClass()).isEqualTo(QueryOptions.class); @@ -49,6 +54,9 @@ class QueryOptionsUnitTests { assertThat(queryOptions.getPageSize()).isEqualTo(10); assertThat(queryOptions.getTracing()).isTrue(); assertThat(queryOptions.getKeyspace()).isEqualTo(CqlIdentifier.fromCql("ks1")); + assertThat(queryOptions.isIdempotent()).isEqualTo(true); + assertThat(queryOptions.getRoutingKeyspace()).isEqualTo(CqlIdentifier.fromCql("rksl")); + assertThat(queryOptions.getRoutingKey()).isEqualTo(ByteBuffer.allocate(1)); } @Test // DATACASS-56 @@ -60,6 +68,9 @@ class QueryOptionsUnitTests { .pageSize(10) // .tracing(true) // .keyspace(CqlIdentifier.fromCql("ks1")) // + .idempotent(true) + .routingKeyspace(CqlIdentifier.fromCql("rksl")) + .routingKey(ByteBuffer.allocate(1)) .build(); QueryOptions mutated = queryOptions.mutate().timeout(Duration.ofSeconds(5)).build(); @@ -71,5 +82,8 @@ class QueryOptionsUnitTests { assertThat(mutated.getPageSize()).isEqualTo(10); assertThat(mutated.getTracing()).isTrue(); assertThat(mutated.getKeyspace()).isEqualTo(CqlIdentifier.fromCql("ks1")); + assertThat(mutated.isIdempotent()).isEqualTo(true); + assertThat(mutated.getRoutingKeyspace()).isEqualTo(CqlIdentifier.fromCql("rksl")); + assertThat(mutated.getRoutingKey()).isEqualTo(ByteBuffer.allocate(1)); } } 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 b40a006a0..95086966c 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 @@ -1,5 +1,5 @@ /* - * Copyright 2016-2021 the original author or authors. + * Copyright 2016-2022 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. @@ -18,6 +18,7 @@ package org.springframework.data.cassandra.core.cql; import static org.assertj.core.api.Assertions.*; import static org.mockito.Mockito.*; +import java.nio.ByteBuffer; import java.time.Duration; import java.util.concurrent.TimeUnit; @@ -38,6 +39,7 @@ import com.datastax.oss.driver.api.core.cql.SimpleStatement; * @author John Blum * @author Mark Paluch * @author Tomasz Lelek + * @author Sam Lightfoot */ @ExtendWith(MockitoExtension.class) class QueryOptionsUtilUnitTests { @@ -82,11 +84,17 @@ class QueryOptionsUtilUnitTests { when(simpleStatement.setPageSize(anyInt())).thenReturn(simpleStatement); when(simpleStatement.setTimeout(any())).thenReturn(simpleStatement); when(simpleStatement.setTracing(anyBoolean())).thenReturn(simpleStatement); + when(simpleStatement.setIdempotent(anyBoolean())).thenReturn(simpleStatement); + when(simpleStatement.setRoutingKeyspace(any(CqlIdentifier.class))).thenReturn(simpleStatement); + when(simpleStatement.setRoutingKey(any(ByteBuffer.class))).thenReturn(simpleStatement); QueryOptions queryOptions = QueryOptions.builder() // .pageSize(10) // .readTimeout(1, TimeUnit.MINUTES) // .withTracing() // + .idempotent(true) + .routingKeyspace(CqlIdentifier.fromCql("routing_ks")) + .routingKey(ByteBuffer.allocate(1)) .build(); QueryOptionsUtil.addQueryOptions(simpleStatement, queryOptions); @@ -94,6 +102,9 @@ class QueryOptionsUtilUnitTests { verify(simpleStatement).setTimeout(Duration.ofMinutes(1)); verify(simpleStatement).setPageSize(10); verify(simpleStatement).setTracing(true); + verify(simpleStatement).setIdempotent(true); + verify(simpleStatement).setRoutingKeyspace(CqlIdentifier.fromCql("routing_ks")); + verify(simpleStatement).setRoutingKey(ByteBuffer.allocate(1)); } @Test // DATACASS-767 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 f06db4276..307d22895 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 @@ -1,5 +1,5 @@ /* - * Copyright 2016-2021 the original author or authors. + * Copyright 2016-2022 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. @@ -17,6 +17,7 @@ package org.springframework.data.cassandra.core.cql; import static org.assertj.core.api.Assertions.*; +import java.nio.ByteBuffer; import java.time.Duration; import java.time.Instant; import java.time.LocalDateTime; @@ -31,6 +32,7 @@ import com.datastax.oss.driver.api.core.DefaultConsistencyLevel; * Unit tests for {@link WriteOptions}. * * @author Mark Paluch + * @author Sam Lightfoot */ class WriteOptionsUnitTests { @@ -44,7 +46,11 @@ class WriteOptionsUnitTests { .readTimeout(1) // .pageSize(10) // .withTracing() // - .keyspace(CqlIdentifier.fromCql("my_keyspace")).build(); + .keyspace(CqlIdentifier.fromCql("my_keyspace")) + .idempotent(true) + .routingKeyspace(CqlIdentifier.fromCql("routing_keyspace")) + .routingKey(ByteBuffer.allocate(1)) + .build(); assertThat(writeOptions.getTtl()).isEqualTo(Duration.ofSeconds(123)); assertThat(writeOptions.getTimestamp()).isEqualTo(1519000753); @@ -53,6 +59,10 @@ class WriteOptionsUnitTests { assertThat(writeOptions.getPageSize()).isEqualTo(10); assertThat(writeOptions.getTracing()).isTrue(); assertThat(writeOptions.getKeyspace()).isEqualTo(CqlIdentifier.fromCql("my_keyspace")); + assertThat(writeOptions.isIdempotent()).isEqualTo(true); + assertThat(writeOptions.getRoutingKeyspace()).isEqualTo( + CqlIdentifier.fromCql("routing_keyspace")); + assertThat(writeOptions.getRoutingKey()).isEqualTo(ByteBuffer.allocate(1)); } @Test // DATACASS-202 @@ -76,6 +86,9 @@ class WriteOptionsUnitTests { .readTimeout(1) // .pageSize(10) // .withTracing() // + .idempotent(true) + .routingKeyspace(CqlIdentifier.fromCql("routing_keyspace")) + .routingKey(ByteBuffer.allocate(1)) .build(); WriteOptions mutated = writeOptions.mutate().timeout(Duration.ofMillis(100)).build(); @@ -88,5 +101,9 @@ class WriteOptionsUnitTests { assertThat(mutated.getTimeout()).isEqualTo(Duration.ofMillis(100)); assertThat(mutated.getPageSize()).isEqualTo(10); assertThat(mutated.getTracing()).isTrue(); + assertThat(writeOptions.isIdempotent()).isEqualTo(true); + assertThat(writeOptions.getRoutingKeyspace()).isEqualTo( + CqlIdentifier.fromCql("routing_keyspace")); + assertThat(writeOptions.getRoutingKey()).isEqualTo(ByteBuffer.allocate(1)); } }