diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/AsyncCassandraOperations.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/AsyncCassandraOperations.java index aa6652019..bcc58430b 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/AsyncCassandraOperations.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/AsyncCassandraOperations.java @@ -37,7 +37,10 @@ import com.datastax.driver.core.Statement; * @author John Blum * @since 2.0 * @see AsyncCassandraTemplate - * @see CassandraOperations + * @see AsyncCqlOperations + * @see Statement + * @see InsertOptions + * @see UpdateOptions */ public interface AsyncCassandraOperations { @@ -234,10 +237,11 @@ public interface AsyncCassandraOperations { * * @param entity The entity to insert, must not be {@literal null}. * @param options may be {@literal null}. - * @return the inserted entity. + * @return the inserted entity or a {@literal null} inside of {@link ListenableFuture} if the {@code INSERT} operation + * was not applied. * @throws DataAccessException if there is any problem executing the query. */ - ListenableFuture insert(T entity, WriteOptions options) throws DataAccessException; + ListenableFuture insert(T entity, InsertOptions options) throws DataAccessException; /** * Update the given entity and return the entity if the update was applied. @@ -253,10 +257,11 @@ public interface AsyncCassandraOperations { * * @param entity The entity to update, must not be {@literal null}. * @param options may be {@literal null}. - * @return the updated entity. + * @return the updated entityor a {@literal null} inside of {@link ListenableFuture} if the {@code UPDATE} operation + * was not applied. * @throws DataAccessException if there is any problem executing the query. */ - ListenableFuture update(T entity, WriteOptions options) throws DataAccessException; + ListenableFuture update(T entity, UpdateOptions options) throws DataAccessException; /** * Delete the given entity and return the entity if the delete was applied. diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/AsyncCassandraTemplate.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/AsyncCassandraTemplate.java index 5542eddd3..e2596998d 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/AsyncCassandraTemplate.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/AsyncCassandraTemplate.java @@ -36,7 +36,6 @@ import org.springframework.data.cql.core.CqlIdentifier; import org.springframework.data.cql.core.CqlProvider; import org.springframework.data.cql.core.GuavaListenableFutureAdapter; import org.springframework.data.cql.core.QueryOptions; -import org.springframework.data.cql.core.WriteOptions; import org.springframework.data.cql.core.session.DefaultSessionFactory; import org.springframework.data.cql.core.session.SessionFactory; import org.springframework.data.cql.support.CqlExceptionTranslator; @@ -424,10 +423,10 @@ public class AsyncCassandraTemplate implements AsyncCassandraOperations { /* * (non-Javadoc) - * @see org.springframework.data.cassandra.core.AsyncCassandraOperations#insert(java.lang.Object, org.springframework.data.cql.core.WriteOptions) + * @see org.springframework.data.cassandra.core.AsyncCassandraOperations#insert(java.lang.Object, org.springframework.data.cassandra.core.InsertOptions) */ @Override - public ListenableFuture insert(T entity, WriteOptions options) { + public ListenableFuture insert(T entity, InsertOptions options) { Assert.notNull(entity, "Entity must not be null"); @@ -448,10 +447,10 @@ public class AsyncCassandraTemplate implements AsyncCassandraOperations { /* * (non-Javadoc) - * @see org.springframework.data.cassandra.core.AsyncCassandraOperations#update(java.lang.Object, org.springframework.data.cql.core.WriteOptions) + * @see org.springframework.data.cassandra.core.AsyncCassandraOperations#update(java.lang.Object, org.springframework.data.cassandra.core.UpdateOptions) */ @Override - public ListenableFuture update(T entity, WriteOptions options) { + public ListenableFuture update(T entity, UpdateOptions options) { Assert.notNull(entity, "Entity must not be null"); diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/CassandraOperations.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/CassandraOperations.java index 1067d3b0f..07b9e4dbb 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/CassandraOperations.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/CassandraOperations.java @@ -41,6 +41,8 @@ import com.datastax.driver.core.Statement; * @see CassandraTemplate * @see CqlOperations * @see Statement + * @see InsertOptions + * @see UpdateOptions */ public interface CassandraOperations { @@ -266,10 +268,10 @@ public interface CassandraOperations { * * @param entity The entity to insert, must not be {@literal null}. * @param options may be {@literal null}. - * @return the inserted entity. + * @return the inserted entity or {@literal null} if the {@code INSERT} operation was not applied. * @throws DataAccessException if there is any problem executing the query. */ - T insert(T entity, WriteOptions options) throws DataAccessException; + T insert(T entity, InsertOptions options) throws DataAccessException; /** * Update the given entity and return the entity if the update was applied. @@ -285,10 +287,10 @@ public interface CassandraOperations { * * @param entity The entity to update, must not be {@literal null}. * @param options may be {@literal null}. - * @return the updated entity. + * @return the updated entity or {@literal null} if the {@code UPDATE} operation was not applied. * @throws DataAccessException if there is any problem executing the query. */ - T update(T entity, WriteOptions options) throws DataAccessException; + T update(T entity, UpdateOptions options) throws DataAccessException; /** * Delete the given entity and return the entity if the delete was applied. diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/CassandraTemplate.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/CassandraTemplate.java index 2e8aa8330..34e650b5b 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/CassandraTemplate.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/CassandraTemplate.java @@ -37,7 +37,6 @@ import org.springframework.data.cql.core.CqlProvider; import org.springframework.data.cql.core.CqlTemplate; import org.springframework.data.cql.core.QueryOptions; import org.springframework.data.cql.core.SessionCallback; -import org.springframework.data.cql.core.WriteOptions; import org.springframework.data.cql.core.session.DefaultSessionFactory; import org.springframework.data.cql.core.session.SessionFactory; import org.springframework.data.mapping.context.MappingContext; @@ -433,10 +432,10 @@ public class CassandraTemplate implements CassandraOperations { /* * (non-Javadoc) - * @see org.springframework.data.cassandra.core.CassandraOperations#insert(java.lang.Object, org.springframework.data.cql.core.WriteOptions) + * @see org.springframework.data.cassandra.core.CassandraOperations#insert(java.lang.Object, org.springframework.data.cassandra.core.InsertOptions) */ @Override - public T insert(T entity, WriteOptions options) { + public T insert(T entity, InsertOptions options) { Assert.notNull(entity, "Entity must not be null"); @@ -456,10 +455,10 @@ public class CassandraTemplate implements CassandraOperations { /* * (non-Javadoc) - * @see org.springframework.data.cassandra.core.CassandraOperations#update(java.lang.Object, org.springframework.data.cql.core.WriteOptions) + * @see org.springframework.data.cassandra.core.CassandraOperations#update(java.lang.Object, org.springframework.data.cassandra.core.UpdateOptions) */ @Override - public T update(T entity, WriteOptions options) { + public T update(T entity, UpdateOptions options) { Assert.notNull(entity, "Entity must not be null"); 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 new file mode 100644 index 000000000..82e8a10db --- /dev/null +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/InsertOptions.java @@ -0,0 +1,172 @@ +/* + * Copyright 2017 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.cassandra.core; + +import java.util.concurrent.TimeUnit; + +import org.springframework.data.cql.core.WriteOptions; + +/** + * Extension to {@link WriteOptions} for use with {@code INSERT} operations. + * + * @author Mark Paluch + * @since 2.0 + */ +public class InsertOptions extends WriteOptions { + + private boolean ifNotExists; + + /** + * Creates new {@link InsertOptions}. + */ + InsertOptions() {} + + /** + * Create a new {@link InsertOptionsBuilder}. + * + * @return a new {@link InsertOptionsBuilder}. + */ + public static InsertOptionsBuilder builder() { + return new InsertOptionsBuilder(); + } + + /** + * @return {@literal true} to apply {@code IF NOT EXISTS} to {@code INSERT} operations. + */ + public boolean isIfNotExists() { + return ifNotExists; + } + + /** + * Builder for {@link InsertOptions}. + * + * @author Mark Paluch + * @since 2.0 + */ + public static class InsertOptionsBuilder extends WriteOptionsBuilder { + + private boolean ifNotExists; + + private InsertOptionsBuilder() {} + + /* + * (non-Javadoc) + * @see org.springframework.data.cql.core.QueryOptions.QueryOptionsBuilder#consistencyLevel(com.datastax.driver.core.ConsistencyLevel) + */ + @Override + public InsertOptionsBuilder consistencyLevel(com.datastax.driver.core.ConsistencyLevel consistencyLevel) { + return (InsertOptionsBuilder) super.consistencyLevel(consistencyLevel); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.cql.core.QueryOptions.QueryOptionsBuilder#retryPolicy(org.springframework.data.cql.core.RetryPolicy) + */ + @Override + public InsertOptionsBuilder retryPolicy(com.datastax.driver.core.policies.RetryPolicy driverRetryPolicy) { + return (InsertOptionsBuilder) super.retryPolicy(driverRetryPolicy); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.cql.core.QueryOptions.QueryOptionsBuilder#fetchSize(int) + */ + @Override + public InsertOptionsBuilder fetchSize(int fetchSize) { + return (InsertOptionsBuilder) super.fetchSize(fetchSize); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.cql.core.QueryOptions.QueryOptionsBuilder#readTimeout(long) + */ + @Override + public InsertOptionsBuilder readTimeout(long readTimeout) { + return (InsertOptionsBuilder) super.readTimeout(readTimeout); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.cql.core.QueryOptions.QueryOptionsBuilder#readTimeout(long, java.util.concurrent.TimeUnit) + */ + @Override + public InsertOptionsBuilder readTimeout(long readTimeout, TimeUnit timeUnit) { + return (InsertOptionsBuilder) super.readTimeout(readTimeout, timeUnit); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.cql.core.QueryOptions.QueryOptionsBuilder#tracing(boolean) + */ + @Override + public InsertOptionsBuilder tracing(boolean tracing) { + return (InsertOptionsBuilder) super.tracing(tracing); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.cql.core.QueryOptions.QueryOptionsBuilder#withTracing() + */ + @Override + public InsertOptionsBuilder withTracing() { + return (InsertOptionsBuilder) super.withTracing(); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.cql.core.WriteOptions.WriteOptionsBuilder#ttl(int) + */ + public InsertOptionsBuilder ttl(int ttl) { + return (InsertOptionsBuilder) super.ttl(ttl); + } + + /** + * Use light-weight transactions by applying {@code IF NOT EXISTS}. + * + * @return {@code this} {@link InsertOptionsBuilder} + */ + public InsertOptionsBuilder withIfNotExists() { + return ifNotExists(true); + } + + /** + * Use light-weight transactions by applying {@code IF NOT EXISTS}. + * + * @param ifNotExists {@literal true} to enable {@code IF NOT EXISTS}. + * @return {@code this} {@link InsertOptionsBuilder} + */ + public InsertOptionsBuilder ifNotExists(boolean ifNotExists) { + + this.ifNotExists = ifNotExists; + + return this; + } + + /** + * Builds a new {@link InsertOptions} with the configured values. + * + * @return a new {@link InsertOptions} with the configured values + */ + public InsertOptions build() { + + InsertOptions insertOptions = applyOptions(new InsertOptions()); + + insertOptions.ifNotExists = ifNotExists; + + return insertOptions; + } + } +} diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/QueryUtils.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/QueryUtils.java index dea220093..8d514cd45 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/QueryUtils.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/QueryUtils.java @@ -55,6 +55,15 @@ class QueryUtils { Insert insert = QueryOptionsUtil.addWriteOptions(QueryBuilder.insertInto(tableName), options); + if (options instanceof InsertOptions) { + + InsertOptions insertOptions = (InsertOptions) options; + + if (insertOptions.isIfNotExists()) { + insert = insert.ifNotExists(); + } + } + entityWriter.write(objectToUpdate, insert); return insert; @@ -79,6 +88,15 @@ class QueryUtils { Update update = QueryOptionsUtil.addWriteOptions(QueryBuilder.update(tableName), options); + if (options instanceof UpdateOptions) { + + UpdateOptions updateOptions = (UpdateOptions) options; + + if (updateOptions.isIfExists()) { + update.where().ifExists(); + } + } + entityWriter.write(objectToUpdate, update); return update; diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/ReactiveCassandraOperations.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/ReactiveCassandraOperations.java index 89bdf9911..0c430cb91 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/ReactiveCassandraOperations.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/ReactiveCassandraOperations.java @@ -36,6 +36,10 @@ import com.datastax.driver.core.Statement; * @author Mark Paluch * @since 2.0 * @see ReactiveCassandraTemplate + * @see ReactiveCqlOperations + * @see Statement + * @see InsertOptions + * @see UpdateOptions * @see Flux * @see Mono */ @@ -180,10 +184,10 @@ public interface ReactiveCassandraOperations { * * @param entity The entity to insert, must not be {@literal null}. * @param options may be {@literal null}. - * @@return the inserted entity. + * @return the inserted entity or {@link Mono#empty()} if the {@code INSERT} operation was not applied. * @throws DataAccessException if there is any problem issuing the execution. */ - Mono insert(T entity, WriteOptions options) throws DataAccessException; + Mono insert(T entity, InsertOptions options) throws DataAccessException; /** * Insert the given entities and emit the entity if the insert was applied. @@ -199,10 +203,10 @@ public interface ReactiveCassandraOperations { * * @param entities The entities to insert, must not be {@literal null}. * @param options may be {@literal null}. - * @return the inserted entities. + * @return the inserted entities. Does not emit items for which the {@code INSERT} operation was not applied. * @throws DataAccessException if there is any problem issuing the execution. */ - Flux insert(Publisher entities, WriteOptions options) throws DataAccessException; + Flux insert(Publisher entities, InsertOptions options) throws DataAccessException; /** * Update the given entity and emit the entity if the update was applied. @@ -218,10 +222,10 @@ public interface ReactiveCassandraOperations { * * @param entity The entity to update, must not be {@literal null}. * @param options may be {@literal null}. - * @return the updated entity. + * @return the updated entity or {@link Mono#empty()} if the {@code UPDATE} operation was not applied. * @throws DataAccessException if there is any problem issuing the execution. */ - Mono update(T entity, WriteOptions options) throws DataAccessException; + Mono update(T entity, UpdateOptions options) throws DataAccessException; /** * Update the given entities and emit the entity if the update was applied. @@ -237,10 +241,10 @@ public interface ReactiveCassandraOperations { * * @param entities The entities to update. * @param options may be {@literal null}. - * @return the updated entities. + * @return the updated entities. Does not emit items for which the {@code UPDATE} operation was not applied. * @throws DataAccessException if there is any problem issuing the execution. */ - Flux update(Publisher entities, WriteOptions options) throws DataAccessException; + Flux update(Publisher entities, UpdateOptions options) throws DataAccessException; /** * Remove the given object from the table by id. diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/ReactiveCassandraTemplate.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/ReactiveCassandraTemplate.java index b868db606..8eda48a98 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/ReactiveCassandraTemplate.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/ReactiveCassandraTemplate.java @@ -34,7 +34,6 @@ import org.springframework.data.cql.core.QueryOptions; import org.springframework.data.cql.core.ReactiveCqlOperations; import org.springframework.data.cql.core.ReactiveCqlTemplate; import org.springframework.data.cql.core.ReactiveSessionCallback; -import org.springframework.data.cql.core.WriteOptions; import org.springframework.data.cql.core.session.DefaultReactiveSessionFactory; import org.springframework.data.cql.core.session.ReactiveResultSet; import org.springframework.data.cql.core.session.ReactiveSession; @@ -380,10 +379,10 @@ public class ReactiveCassandraTemplate implements ReactiveCassandraOperations { /* * (non-Javadoc) - * @see org.springframework.data.cassandra.core.ReactiveCassandraOperations#insert(java.lang.Object, org.springframework.data.cql.core.WriteOptions) + * @see org.springframework.data.cassandra.core.ReactiveCassandraOperations#insert(java.lang.Object, org.springframework.data.cassandra.core.InsertOptions) */ @Override - public Mono insert(T entity, WriteOptions options) { + public Mono insert(T entity, InsertOptions options) { Assert.notNull(entity, "Entity must not be null"); @@ -417,10 +416,10 @@ public class ReactiveCassandraTemplate implements ReactiveCassandraOperations { /* * (non-Javadoc) - * @see org.springframework.data.cassandra.core.ReactiveCassandraOperations#insert(org.reactivestreams.Publisher, org.springframework.data.cql.core.WriteOptions) + * @see org.springframework.data.cassandra.core.ReactiveCassandraOperations#insert(org.reactivestreams.Publisher, org.springframework.data.cassandra.core.InsertOptions) */ @Override - public Flux insert(Publisher entities, WriteOptions options) { + public Flux insert(Publisher entities, InsertOptions options) { Assert.notNull(entities, "Entity publisher must not be null"); @@ -438,10 +437,10 @@ public class ReactiveCassandraTemplate implements ReactiveCassandraOperations { /* * (non-Javadoc) - * @see org.springframework.data.cassandra.core.ReactiveCassandraOperations#update(java.lang.Object, org.springframework.data.cql.core.WriteOptions) + * @see org.springframework.data.cassandra.core.ReactiveCassandraOperations#update(java.lang.Object, org.springframework.data.cassandra.core.UpdateOptions) */ @Override - public Mono update(T entity, WriteOptions options) { + public Mono update(T entity, UpdateOptions options) { Assert.notNull(entity, "Entity must not be null"); @@ -475,10 +474,10 @@ public class ReactiveCassandraTemplate implements ReactiveCassandraOperations { /* * (non-Javadoc) - * @see org.springframework.data.cassandra.core.ReactiveCassandraOperations#update(org.reactivestreams.Publisher, org.springframework.data.cql.core.WriteOptions) + * @see org.springframework.data.cassandra.core.ReactiveCassandraOperations#update(org.reactivestreams.Publisher, org.springframework.data.cassandra.core.UpdateOptions) */ @Override - public Flux update(Publisher entities, WriteOptions options) { + public Flux update(Publisher entities, UpdateOptions options) { Assert.notNull(entities, "Entity publisher must not be null"); 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 new file mode 100644 index 000000000..813777a28 --- /dev/null +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/UpdateOptions.java @@ -0,0 +1,172 @@ +/* + * Copyright 2017 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.cassandra.core; + +import java.util.concurrent.TimeUnit; + +import org.springframework.data.cql.core.WriteOptions; + +/** + * Extension to {@link WriteOptions} for use with {@code UPDATE} operations. + * + * @author Mark Paluch + * @since 2.0 + */ +public class UpdateOptions extends WriteOptions { + + private boolean ifExists; + + /** + * Creates new {@link UpdateOptions}. + */ + UpdateOptions() {} + + /** + * Create a new {@link UpdateOptionsBuilder}. + * + * @return a new {@link UpdateOptionsBuilder}. + */ + public static UpdateOptionsBuilder builder() { + return new UpdateOptionsBuilder(); + } + + /** + * @return {@literal true} to apply {@code IF EXISTS} to {@code UPDATE} operations. + */ + public boolean isIfExists() { + return ifExists; + } + + /** + * Builder for {@link UpdateOptions}. + * + * @author Mark Paluch + * @since 2.0 + */ + public static class UpdateOptionsBuilder extends WriteOptionsBuilder { + + private boolean ifExists; + + private UpdateOptionsBuilder() {} + + /* + * (non-Javadoc) + * @see org.springframework.data.cql.core.QueryOptions.QueryOptionsBuilder#consistencyLevel(com.datastax.driver.core.ConsistencyLevel) + */ + @Override + public UpdateOptionsBuilder consistencyLevel(com.datastax.driver.core.ConsistencyLevel consistencyLevel) { + return (UpdateOptionsBuilder) super.consistencyLevel(consistencyLevel); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.cql.core.QueryOptions.QueryOptionsBuilder#retryPolicy(org.springframework.data.cql.core.RetryPolicy) + */ + @Override + public UpdateOptionsBuilder retryPolicy(com.datastax.driver.core.policies.RetryPolicy driverRetryPolicy) { + return (UpdateOptionsBuilder) super.retryPolicy(driverRetryPolicy); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.cql.core.QueryOptions.QueryOptionsBuilder#fetchSize(int) + */ + @Override + public UpdateOptionsBuilder fetchSize(int fetchSize) { + return (UpdateOptionsBuilder) super.fetchSize(fetchSize); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.cql.core.QueryOptions.QueryOptionsBuilder#readTimeout(long) + */ + @Override + public UpdateOptionsBuilder readTimeout(long readTimeout) { + return (UpdateOptionsBuilder) super.readTimeout(readTimeout); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.cql.core.QueryOptions.QueryOptionsBuilder#readTimeout(long, java.util.concurrent.TimeUnit) + */ + @Override + public UpdateOptionsBuilder readTimeout(long readTimeout, TimeUnit timeUnit) { + return (UpdateOptionsBuilder) super.readTimeout(readTimeout, timeUnit); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.cql.core.QueryOptions.QueryOptionsBuilder#tracing(boolean) + */ + @Override + public UpdateOptionsBuilder tracing(boolean tracing) { + return (UpdateOptionsBuilder) super.tracing(tracing); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.cql.core.QueryOptions.QueryOptionsBuilder#withTracing() + */ + @Override + public UpdateOptionsBuilder withTracing() { + return (UpdateOptionsBuilder) super.withTracing(); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.cql.core.WriteOptions.WriteOptionsBuilder#ttl(int) + */ + public UpdateOptionsBuilder ttl(int ttl) { + return (UpdateOptionsBuilder) super.ttl(ttl); + } + + /** + * Use light-weight transactions by applying {@code IF EXISTS}. + * + * @return {@code this} {@link UpdateOptionsBuilder} + */ + public UpdateOptionsBuilder withIfExists() { + return ifExists(true); + } + + /** + * Use light-weight transactions by applying {@code IF EXISTS}. + * + * @param ifNotExists {@literal true} to enable {@code IF EXISTS}. + * @return {@code this} {@link UpdateOptionsBuilder} + */ + public UpdateOptionsBuilder ifExists(boolean ifNotExists) { + + this.ifExists = ifNotExists; + + return this; + } + + /** + * Builds a new {@link UpdateOptions} with the configured values. + * + * @return a new {@link UpdateOptions} with the configured values + */ + public UpdateOptions build() { + + UpdateOptions insertOptions = applyOptions(new UpdateOptions()); + + insertOptions.ifExists = ifExists; + + return insertOptions; + } + } +} diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cql/core/QueryOptions.java b/spring-data-cassandra/src/main/java/org/springframework/data/cql/core/QueryOptions.java index 7f54c45ce..96848cdf8 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cql/core/QueryOptions.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cql/core/QueryOptions.java @@ -313,7 +313,9 @@ public class QueryOptions { return applyOptions(new QueryOptions()); } - T applyOptions(T queryOptions) { + protected T applyOptions(T options) { + + QueryOptions queryOptions = (QueryOptions) options; queryOptions.setConsistencyLevel(consistencyLevel); queryOptions.setRetryPolicy(retryPolicy); @@ -330,7 +332,7 @@ public class QueryOptions { queryOptions.setTracing(tracing); } - return queryOptions; + return options; } } } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cql/core/WriteOptions.java b/spring-data-cassandra/src/main/java/org/springframework/data/cql/core/WriteOptions.java index bd562a9a8..13eba4cd2 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cql/core/WriteOptions.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cql/core/WriteOptions.java @@ -95,7 +95,7 @@ public class WriteOptions extends QueryOptions { private Integer ttl; - private WriteOptionsBuilder() {} + protected WriteOptionsBuilder() {} /* * (non-Javadoc) @@ -177,12 +177,16 @@ public class WriteOptions extends QueryOptions { * @return a new {@link WriteOptions} with the configured values */ public WriteOptions build() { + return applyOptions(new WriteOptions()); + } - WriteOptions queryOptions = applyOptions(new WriteOptions()); + @Override + protected T applyOptions(T queryOptions) { - queryOptions.setTtl(ttl); + WriteOptions writeOptions = (WriteOptions) queryOptions; + writeOptions.setTtl(ttl); - return queryOptions; + return super.applyOptions(queryOptions); } } } diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/AsyncCassandraTemplateIntegrationTests.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/AsyncCassandraTemplateIntegrationTests.java index 29426aee5..87f49d4bf 100644 --- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/AsyncCassandraTemplateIntegrationTests.java +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/AsyncCassandraTemplateIntegrationTests.java @@ -99,12 +99,41 @@ public class AsyncCassandraTemplateIntegrationTests extends AbstractKeyspaceCrea User user = new User("heisenberg", "Walter", "White"); - assertThat(getUninterruptibly(template.selectOneById(user.getId(), User.class))).isNull(); + assertThat(getUser(user.getId())).isNull(); ListenableFuture insert = template.insert(user); assertThat(getUninterruptibly(insert)).isEqualTo(user); - assertThat(getUninterruptibly(template.selectOneById(user.getId(), User.class))).isEqualTo(user); + assertThat(getUser(user.getId())).isEqualTo(user); + } + + @Test // DATACASS-250 + public void insertShouldCreateEntityWithLwt() { + + InsertOptions lwtOptions = InsertOptions.builder().withIfNotExists().build(); + + User user = new User("heisenberg", "Walter", "White"); + + ListenableFuture inserted = template.insert(user, lwtOptions); + + assertThat(getUninterruptibly(inserted)).isEqualTo(user); + } + + @Test // DATACASS-250 + public void insertShouldNotUpdateEntityWithLwt() { + + InsertOptions lwtOptions = InsertOptions.builder().withIfNotExists().build(); + + User user = new User("heisenberg", "Walter", "White"); + + getUninterruptibly(template.insert(user, lwtOptions)); + + user.setFirstname("Walter Hartwell"); + + ListenableFuture lwt = template.insert(user, lwtOptions); + + assertThat(getUninterruptibly(lwt)).isNull(); + assertThat(getUser(user.getId()).getFirstname()).isEqualTo("Walter"); } @Test // DATACASS-292 @@ -125,10 +154,40 @@ public class AsyncCassandraTemplateIntegrationTests extends AbstractKeyspaceCrea getUninterruptibly(template.insert(user)); user.setFirstname("Walter Hartwell"); + User updated = getUninterruptibly(template.update(user)); assertThat(updated).isNotNull(); - assertThat(getUninterruptibly(template.selectOneById(user.getId(), User.class))).isEqualTo(user); + assertThat(getUser(user.getId())).isEqualTo(user); + } + + @Test // DATACASS-292 + public void updateShouldNotCreateEntityWithLwt() { + + UpdateOptions lwtOptions = UpdateOptions.builder().withIfExists().build(); + + User user = new User("heisenberg", "Walter", "White"); + + ListenableFuture lwt = template.update(user, lwtOptions); + + assertThat(getUninterruptibly(lwt)).isNull(); + assertThat(getUser(user.getId())).isNull(); + } + + @Test // DATACASS-292 + public void updateShouldUpdateEntityWithLwt() { + + UpdateOptions lwtOptions = UpdateOptions.builder().withIfExists().build(); + + User user = new User("heisenberg", "Walter", "White"); + getUninterruptibly(template.insert(user)); + + user.setFirstname("Walter Hartwell"); + + ListenableFuture updated = template.update(user, lwtOptions); + + assertThat(getUninterruptibly(updated)).isNotNull(); + assertThat(getUser(user.getId()).getFirstname()).isEqualTo("Walter Hartwell"); } @Test // DATACASS-343 @@ -142,8 +201,7 @@ public class AsyncCassandraTemplateIntegrationTests extends AbstractKeyspaceCrea template.update(query, Update.empty().set("firstname", "Walter Hartwell"), User.class)); assertThat(result).isTrue(); - assertThat(getUninterruptibly(template.selectOneById(user.getId(), User.class)).getFirstname()) - .isEqualTo("Walter Hartwell"); + assertThat(getUser(user.getId()).getFirstname()).isEqualTo("Walter Hartwell"); } @Test // DATACASS-343 @@ -155,7 +213,7 @@ public class AsyncCassandraTemplateIntegrationTests extends AbstractKeyspaceCrea Query query = Query.query(Criteria.where("id").is("heisenberg")); assertThat(getUninterruptibly(template.delete(query, User.class))).isTrue(); - assertThat(getUninterruptibly(template.selectOneById(user.getId(), User.class))).isNull(); + assertThat(getUser(user.getId())).isNull(); } @Test // DATACASS-343 @@ -168,7 +226,7 @@ public class AsyncCassandraTemplateIntegrationTests extends AbstractKeyspaceCrea assertThat(getUninterruptibly(template.delete(query, User.class))).isTrue(); - User loaded = getUninterruptibly(template.selectOneById(user.getId(), User.class)); + User loaded = getUser(user.getId()); assertThat(loaded.getFirstname()).isEqualTo("Walter"); assertThat(loaded.getLastname()).isNull(); } @@ -182,7 +240,7 @@ public class AsyncCassandraTemplateIntegrationTests extends AbstractKeyspaceCrea User deleted = getUninterruptibly(template.delete(user)); assertThat(deleted).isNotNull(); - assertThat(getUninterruptibly(template.selectOneById(user.getId(), User.class))).isNull(); + assertThat(getUser(user.getId())).isNull(); } @Test // DATACASS-292 @@ -194,7 +252,11 @@ public class AsyncCassandraTemplateIntegrationTests extends AbstractKeyspaceCrea Boolean deleted = getUninterruptibly(template.deleteById(user.getId(), User.class)); assertThat(deleted).isTrue(); - assertThat(getUninterruptibly(template.selectOneById(user.getId(), User.class))).isNull(); + assertThat(getUser(user.getId())).isNull(); + } + + private User getUser(String id) { + return getUninterruptibly(template.selectOneById(id, User.class)); } private static T getUninterruptibly(Future future) { diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/CassandraBatchTemplateIntegrationTests.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/CassandraBatchTemplateIntegrationTests.java index 20a75555e..58cf1d0f2 100644 --- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/CassandraBatchTemplateIntegrationTests.java +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/CassandraBatchTemplateIntegrationTests.java @@ -19,6 +19,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assert.fail; import java.util.Arrays; +import java.util.Collections; import java.util.concurrent.TimeUnit; import org.junit.Before; @@ -72,6 +73,29 @@ public class CassandraBatchTemplateIntegrationTests extends AbstractKeyspaceCrea assertThat(loaded.getId().getUsername()).isEqualTo(walter.getId().getUsername()); } + @Test // DATACASS-288 + public void shouldInsertEntitiesWithLwt() { + + InsertOptions lwtOptions = InsertOptions.builder().withIfNotExists().build(); + + Group previousWalter = new Group(new GroupKey("users", "0x1", "walter")); + previousWalter.setAge(42); + template.insert(previousWalter); + + walter.setAge(100); + + CassandraBatchOperations batchOperations = new CassandraBatchTemplate(template); + batchOperations.insert(Collections.singleton(walter), lwtOptions).insert(mike).execute(); + + Group loadedWalter = template.selectOneById(walter.getId(), Group.class); + Group loadedMike = template.selectOneById(mike.getId(), Group.class); + + assertThat(loadedWalter.getId().getUsername()).isEqualTo(walter.getId().getUsername()); + assertThat(loadedWalter.getAge()).isEqualTo(42); + + assertThat(loadedMike).isNotNull(); + } + @Test // DATACASS-288 public void shouldInsertCollectionOfEntities() { 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 c77cf4ac9..1e17afb09 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 @@ -146,6 +146,35 @@ public class CassandraTemplateIntegrationTests extends AbstractKeyspaceCreatingI assertThat(template.selectOneById(user.getId(), User.class)).isEqualTo(user); } + @Test // DATACASS-250 + public void insertShouldCreateEntityWithLwt() { + + InsertOptions lwtOptions = InsertOptions.builder().withIfNotExists().build(); + + User user = new User("heisenberg", "Walter", "White"); + + User inserted = template.insert(user, lwtOptions); + + assertThat(inserted).isEqualTo(user); + } + + @Test // DATACASS-250 + public void insertShouldNotUpdateEntityWithLwt() { + + InsertOptions lwtOptions = InsertOptions.builder().withIfNotExists().build(); + + User user = new User("heisenberg", "Walter", "White"); + + template.insert(user, lwtOptions); + + user.setFirstname("Walter Hartwell"); + + User lwt = template.insert(user, lwtOptions); + + assertThat(lwt).isNull(); + assertThat(template.selectOneById(user.getId(), User.class).getFirstname()).isEqualTo("Walter"); + } + @Test // DATACASS-292 public void shouldInsertAndCountEntities() { @@ -171,6 +200,35 @@ public class CassandraTemplateIntegrationTests extends AbstractKeyspaceCreatingI assertThat(template.selectOneById(user.getId(), User.class)).isEqualTo(user); } + @Test // DATACASS-292 + public void updateShouldNotCreateEntityWithLwt() { + + UpdateOptions lwtOptions = UpdateOptions.builder().withIfExists().build(); + + User user = new User("heisenberg", "Walter", "White"); + + User lwt = template.update(user, lwtOptions); + + assertThat(lwt).isNull(); + assertThat(template.selectOneById(user.getId(), User.class)).isNull(); + } + + @Test // DATACASS-292 + public void updateShouldUpdateEntityWithLwt() { + + UpdateOptions lwtOptions = UpdateOptions.builder().withIfExists().build(); + + User user = new User("heisenberg", "Walter", "White"); + template.insert(user); + + user.setFirstname("Walter Hartwell"); + + User updated = template.update(user, lwtOptions); + + assertThat(updated).isNotNull(); + assertThat(template.selectOneById(user.getId(), User.class).getFirstname()).isEqualTo("Walter Hartwell"); + } + @Test // DATACASS-343 public void updateShouldUpdateEntityByQuery() { diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/CassandraTemplateUnitTests.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/CassandraTemplateUnitTests.java index 94bcd5fa5..797a2f49c 100644 --- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/CassandraTemplateUnitTests.java +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/CassandraTemplateUnitTests.java @@ -204,6 +204,23 @@ public class CassandraTemplateUnitTests { .isEqualTo("INSERT INTO users (firstname,id,lastname) VALUES ('Walter','heisenberg','White');"); } + @Test // DATACASS-250 + public void insertShouldInsertWithOptionsEntity() { + + InsertOptions insertOptions = InsertOptions.builder().withIfNotExists().build(); + + when(resultSet.wasApplied()).thenReturn(true); + + User user = new User("heisenberg", "Walter", "White"); + + User inserted = template.insert(user, insertOptions); + + assertThat(inserted).isEqualTo(user); + verify(session).execute(statementCaptor.capture()); + assertThat(statementCaptor.getValue().toString()) + .isEqualTo("INSERT INTO users (firstname,id,lastname) VALUES ('Walter','heisenberg','White') IF NOT EXISTS;"); + } + @Test // DATACASS-292 public void insertShouldTranslateException() throws Exception { @@ -246,6 +263,23 @@ public class CassandraTemplateUnitTests { .isEqualTo("UPDATE users SET firstname='Walter',lastname='White' WHERE id='heisenberg';"); } + @Test // DATACASS-250 + public void updateShouldUpdateEntityWithOptions() { + + when(resultSet.wasApplied()).thenReturn(true); + + UpdateOptions updateOptions = UpdateOptions.builder().withIfExists().build(); + + User user = new User("heisenberg", "Walter", "White"); + + User updated = template.update(user, updateOptions); + + assertThat(updated).isEqualTo(user); + verify(session).execute(statementCaptor.capture()); + assertThat(statementCaptor.getValue().toString()) + .isEqualTo("UPDATE users SET firstname='Walter',lastname='White' WHERE id='heisenberg' IF EXISTS;"); + } + @Test // DATACASS-292 public void updateShouldTranslateException() throws Exception { 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 new file mode 100644 index 000000000..736909e85 --- /dev/null +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/InsertOptionsUnitTests.java @@ -0,0 +1,40 @@ +/* + * Copyright 2017 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.cassandra.core; + +import static org.assertj.core.api.Assertions.*; + +import org.junit.Test; + +/** + * Unit tests for {@link InsertOptions}. + * + * @author Mark Paluch + */ +public class InsertOptionsUnitTests { + + @Test // DATACASS-250 + public void shouldConfigureInsertOptions() { + + InsertOptions insertOptions = InsertOptions.builder() // + .ttl(10) // + .withIfNotExists() // + .build(); + + assertThat(insertOptions.getTtl()).isEqualTo(10); + assertThat(insertOptions.isIfNotExists()).isTrue(); + } +} diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/ReactiveCassandraTemplateIntegrationTests.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/ReactiveCassandraTemplateIntegrationTests.java index 1b874374a..e996606b9 100644 --- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/ReactiveCassandraTemplateIntegrationTests.java +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/ReactiveCassandraTemplateIntegrationTests.java @@ -20,6 +20,7 @@ import static org.assertj.core.api.Assertions.*; import reactor.core.publisher.Mono; import reactor.core.scheduler.Schedulers; import reactor.test.StepVerifier; +import reactor.test.StepVerifier.FirstStep; import org.junit.Before; import org.junit.Test; @@ -68,11 +69,39 @@ public class ReactiveCassandraTemplateIntegrationTests extends AbstractKeyspaceC User user = new User("heisenberg", "Walter", "White"); Mono insert = template.insert(user); - StepVerifier.create(template.selectOneById(user.getId(), User.class)).verifyComplete(); + verifyUser(user.getId()).verifyComplete(); StepVerifier.create(insert).expectNext(user).verifyComplete(); - StepVerifier.create(template.selectOneById(user.getId(), User.class)).expectNext(user).verifyComplete(); + verifyUser(user.getId()).expectNext(user).verifyComplete(); + } + + @Test // DATACASS-250 + public void insertShouldCreateEntityWithLwt() { + + InsertOptions lwtOptions = InsertOptions.builder().withIfNotExists().build(); + + User user = new User("heisenberg", "Walter", "White"); + + Mono inserted = template.insert(user, lwtOptions); + + StepVerifier.create(inserted).expectNext(user).verifyComplete(); + } + + @Test // DATACASS-250 + public void insertShouldNotUpdateEntityWithLwt() { + + InsertOptions lwtOptions = InsertOptions.builder().withIfNotExists().build(); + + User user = new User("heisenberg", "Walter", "White"); + + StepVerifier.create(template.insert(user, lwtOptions)).expectNext(user).verifyComplete(); + + user.setFirstname("Walter Hartwell"); + + StepVerifier.create(template.insert(user, lwtOptions)).verifyComplete(); + + verifyUser(user.getId()).consumeNextWith(it -> assertThat(it.getFirstname()).isEqualTo("Walter")).verifyComplete(); } @Test // DATACASS-335 @@ -96,7 +125,35 @@ public class ReactiveCassandraTemplateIntegrationTests extends AbstractKeyspaceC StepVerifier.create(template.insert(user)).expectNextCount(1).verifyComplete(); - StepVerifier.create(template.selectOneById(user.getId(), User.class)).expectNext(user).verifyComplete(); + verifyUser(user.getId()).expectNext(user).verifyComplete(); + } + + @Test // DATACASS-292 + public void updateShouldNotCreateEntityWithLwt() { + + UpdateOptions lwtOptions = UpdateOptions.builder().withIfExists().build(); + + User user = new User("heisenberg", "Walter", "White"); + + StepVerifier.create(template.update(user, lwtOptions)).verifyComplete(); + + verifyUser(user.getId()).verifyComplete(); + } + + @Test // DATACASS-292 + public void updateShouldUpdateEntityWithLwt() { + + UpdateOptions lwtOptions = UpdateOptions.builder().withIfExists().build(); + + User user = new User("heisenberg", "Walter", "White"); + StepVerifier.create(template.insert(user)).expectNextCount(1).verifyComplete(); + + user.setFirstname("Walter Hartwell"); + + StepVerifier.create(template.update(user, lwtOptions)).expectNextCount(1).verifyComplete(); + + verifyUser(user.getId()).consumeNextWith(it -> assertThat(it.getFirstname()).isEqualTo("Walter Hartwell")) + .verifyComplete(); } @Test // DATACASS-343 @@ -149,7 +206,7 @@ public class ReactiveCassandraTemplateIntegrationTests extends AbstractKeyspaceC StepVerifier.create(template.delete(user)).expectNext(user).verifyComplete(); - StepVerifier.create(template.selectOneById(user.getId(), User.class)).verifyComplete(); + verifyUser(user.getId()).verifyComplete(); } @Test // DATACASS-335 @@ -161,7 +218,7 @@ public class ReactiveCassandraTemplateIntegrationTests extends AbstractKeyspaceC StepVerifier.create(template.deleteById(user.getId(), User.class)).expectNext(true).verifyComplete(); - StepVerifier.create(template.selectOneById(user.getId(), User.class)).verifyComplete(); + verifyUser(user.getId()).verifyComplete(); } @Test // DATACASS-343 @@ -199,4 +256,8 @@ public class ReactiveCassandraTemplateIntegrationTests extends AbstractKeyspaceC assertThat(template.selectOne(query, UserToken.class).block()).isEqualTo(token1); } + + private FirstStep verifyUser(String userId) { + return StepVerifier.create(template.selectOneById(userId, User.class)); + } } 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 new file mode 100644 index 000000000..2764585d5 --- /dev/null +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/UpdateOptionsUnitTests.java @@ -0,0 +1,40 @@ +/* + * Copyright 2017 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.cassandra.core; + +import static org.assertj.core.api.Assertions.*; + +import org.junit.Test; + +/** + * Unit tests for {@link UpdateOptions}. + * + * @author Mark Paluch + */ +public class UpdateOptionsUnitTests { + + @Test // DATACASS-250 + public void shouldConfigureInsertOptions() { + + UpdateOptions insertOptions = UpdateOptions.builder() // + .ttl(10) // + .withIfExists() // + .build(); + + assertThat(insertOptions.getTtl()).isEqualTo(10); + assertThat(insertOptions.isIfExists()).isTrue(); + } +} diff --git a/src/main/asciidoc/new-features.adoc b/src/main/asciidoc/new-features.adoc index f684001b9..cd61c94fa 100644 --- a/src/main/asciidoc/new-features.adoc +++ b/src/main/asciidoc/new-features.adoc @@ -5,6 +5,7 @@ == What's new in Spring Data for Apache Cassandra 2.0 * `Update` and `Query` objects. * CRUD repository interface renaming: `CassandraRepository` using `MapId` is now renamed to `MapIdCassandraRepository`. `TypedIdCassandraRepository` is renamed to `CassandraRepository`. +* Lightweight transactions via `InsertOptions` and `UpdateOptions` using the Template API. [[new-features.1-5-0]] == What's new in Spring Data for Apache Cassandra 1.5 diff --git a/src/main/asciidoc/reference/cassandra.adoc b/src/main/asciidoc/reference/cassandra.adoc index 4c5525f95..ce6d13102 100644 --- a/src/main/asciidoc/reference/cassandra.adoc +++ b/src/main/asciidoc/reference/cassandra.adoc @@ -1160,14 +1160,15 @@ Person qp = cassandraTemplate.selectOne(query(where("age").is(33)), Person.class The insert/save operations available to you are listed below. * `T` *insert* `(T objectToSave)` Insert the object in an Apache Cassandra table. -* `T` *insert* `(T objectToSave, WriteOptions writeOptions)` Insert the object in an Apache Cassandra table applying `WriteOptions`. +* `T` *insert* `(T objectToSave, InsertOptions options)` Insert the object in an Apache Cassandra table applying `InsertOptions`. A similar set of update operations is listed below * `T` *update* `(T objectToSave)` Update the object in an Apache Cassandra table. -* `T` *update* `(T objectToSave, WriteOptions writeOptions)` Update the object in an Apache Cassandra table applying `WriteOptions`. +* `T` *update* `(T objectToSave, UpdateOptions options)` Update the object in an Apache Cassandra table applying `UpdateOptions`. -Then, there is always the old fashioned way. You can write your own CQL statements. +Then, there is always the old fashioned way. You can write your own CQL statements. You can configure with `InsertOptions` and `UpdateOptions` +additional options such as TTL, consistency level and lightweight transactions. [source,java] ----