DATACASS-466 - Align insert(…) and update(…) return types to their possible outcomes.

We now return WriteResult for insert(…) and update(…) methods accepting WriteOptions. Conditional writes return a state whether the operation was applied or not and this result is propagated via WriteResult to the caller.

Synchronous insert(…) and update(…) without WriteOptions methods do not return a value and are consistent with other Template API modules. The absence of an Exception indicates success. Asynchronous and reactive insert(…) and update(…) without WriteOptions continue to return the entity to make the entity accessible after operation completion.

Previously, we returned null if a lightweight transaction was not applied or suppressed the value value emission.
This commit is contained in:
Mark Paluch
2017-07-05 12:51:37 +02:00
committed by John Blum
parent 2f0f87e9c2
commit 0ccb64a686
20 changed files with 264 additions and 322 deletions

View File

@@ -237,11 +237,10 @@ public interface AsyncCassandraOperations {
*
* @param entity The entity to insert, must not be {@literal null}.
* @param options may be {@literal null}.
* @return the inserted entity or a {@literal null} inside of {@link ListenableFuture} if the {@code INSERT} operation
* was not applied.
* @return the {@link WriteResult} for this operation.
* @throws DataAccessException if there is any problem executing the query.
*/
<T> ListenableFuture<T> insert(T entity, InsertOptions options) throws DataAccessException;
ListenableFuture<WriteResult> insert(Object entity, InsertOptions options) throws DataAccessException;
/**
* Update the given entity and return the entity if the update was applied.
@@ -257,11 +256,10 @@ public interface AsyncCassandraOperations {
*
* @param entity The entity to update, must not be {@literal null}.
* @param options may be {@literal null}.
* @return the updated entity or a {@literal null} inside of {@link ListenableFuture}
* if the {@code UPDATE} operation was not applied.
* @return the {@link WriteResult} for this operation.
* @throws DataAccessException if there is any problem executing the query.
*/
<T> ListenableFuture<T> update(T entity, UpdateOptions options) throws DataAccessException;
ListenableFuture<WriteResult> update(Object entity, UpdateOptions options) throws DataAccessException;
/**
* Delete the given entity and return the entity if the delete was applied.
@@ -277,10 +275,10 @@ public interface AsyncCassandraOperations {
*
* @param entity must not be {@literal null}.
* @param options may be {@literal null}.
* @return the deleted entity.
* @return the {@link WriteResult} for this operation.
* @throws DataAccessException if there is any problem executing the query.
*/
<T> ListenableFuture<T> delete(T entity, QueryOptions options) throws DataAccessException;
ListenableFuture<WriteResult> delete(Object entity, QueryOptions options) throws DataAccessException;
/**
* Remove the given object from the table by id.

View File

@@ -195,7 +195,6 @@ public class AsyncCassandraTemplate implements AsyncCassandraOperations {
return this.statementFactory;
}
/* (non-Javadoc) */
private CqlIdentifier getTableName(Object entity) {
return getMappingContext().getRequiredPersistentEntity(ClassUtils.getUserClass(entity)).getTableName();
}
@@ -418,7 +417,7 @@ public class AsyncCassandraTemplate implements AsyncCassandraOperations {
*/
@Override
public <T> ListenableFuture<T> insert(T entity) {
return insert(entity, null);
return new MappingListenableFutureAdapter<>(insert(entity, null), writeResult -> entity);
}
/*
@@ -426,14 +425,14 @@ public class AsyncCassandraTemplate implements AsyncCassandraOperations {
* @see org.springframework.data.cassandra.core.AsyncCassandraOperations#insert(java.lang.Object, org.springframework.data.cassandra.core.InsertOptions)
*/
@Override
public <T> ListenableFuture<T> insert(T entity, InsertOptions options) {
public ListenableFuture<WriteResult> insert(Object entity, InsertOptions options) {
Assert.notNull(entity, "Entity must not be null");
Insert insert = QueryUtils.createInsertQuery(getTableName(entity).toCql(), entity, options, getConverter());
return new MappingListenableFutureAdapter<>(getAsyncCqlOperations().execute(new AsyncStatementCallback(insert)),
resultSet -> resultSet.wasApplied() ? entity : null);
WriteResult::of);
}
/*
@@ -442,7 +441,7 @@ public class AsyncCassandraTemplate implements AsyncCassandraOperations {
*/
@Override
public <T> ListenableFuture<T> update(T entity) {
return update(entity, null);
return new MappingListenableFutureAdapter<>(update(entity, null), writeResult -> entity);
}
/*
@@ -450,14 +449,14 @@ public class AsyncCassandraTemplate implements AsyncCassandraOperations {
* @see org.springframework.data.cassandra.core.AsyncCassandraOperations#update(java.lang.Object, org.springframework.data.cassandra.core.UpdateOptions)
*/
@Override
public <T> ListenableFuture<T> update(T entity, UpdateOptions options) {
public ListenableFuture<WriteResult> update(Object entity, UpdateOptions options) {
Assert.notNull(entity, "Entity must not be null");
Update update = QueryUtils.createUpdateQuery(getTableName(entity).toCql(), entity, options, getConverter());
return new MappingListenableFutureAdapter<>(getAsyncCqlOperations().execute(new AsyncStatementCallback(update)),
resultSet -> resultSet.wasApplied() ? entity : null);
WriteResult::of);
}
/*
@@ -466,7 +465,7 @@ public class AsyncCassandraTemplate implements AsyncCassandraOperations {
*/
@Override
public <T> ListenableFuture<T> delete(T entity) {
return delete(entity, null);
return new MappingListenableFutureAdapter<>(delete(entity, null), writeResult -> entity);
}
/*
@@ -474,14 +473,14 @@ public class AsyncCassandraTemplate implements AsyncCassandraOperations {
* @see org.springframework.data.cassandra.core.AsyncCassandraOperations#delete(java.lang.Object, org.springframework.data.cql.core.QueryOptions)
*/
@Override
public <T> ListenableFuture<T> delete(T entity, QueryOptions options) {
public ListenableFuture<WriteResult> delete(Object entity, QueryOptions options) {
Assert.notNull(entity, "Entity must not be null");
Delete delete = QueryUtils.createDeleteQuery(getTableName(entity).toCql(), entity, options, getConverter());
return new MappingListenableFutureAdapter<>(getAsyncCqlOperations().execute(new AsyncStatementCallback(delete)),
resultSet -> resultSet.wasApplied() ? entity : null);
WriteResult::of);
}
/*
@@ -518,12 +517,12 @@ public class AsyncCassandraTemplate implements AsyncCassandraOperations {
return new MappingListenableFutureAdapter<>(getAsyncCqlOperations().execute(truncate), aBoolean -> null);
}
private static class MappingListenableFutureAdapter<T, S>
static class MappingListenableFutureAdapter<T, S>
extends org.springframework.util.concurrent.ListenableFutureAdapter<T, S> {
private final Function<S, T> mapper;
public MappingListenableFutureAdapter(ListenableFuture<S> adaptee, Function<S, T> mapper) {
MappingListenableFutureAdapter(ListenableFuture<S> adaptee, Function<S, T> mapper) {
super(adaptee);
this.mapper = mapper;
}

View File

@@ -40,9 +40,10 @@ public interface CassandraBatchOperations {
/**
* Execute the batch. The batch can be executed only once.
*
* @return the {@link WriteResult} for the bulk operation.
* @throws IllegalStateException if the batch is executed after it was executed already.
*/
void execute();
WriteResult execute();
/**
* Apply a given {@code timestamp} to the whole batch.

View File

@@ -59,14 +59,15 @@ class CassandraBatchTemplate implements CassandraBatchOperations {
* @see org.springframework.data.cassandra.core.CassandraBatchOperations#execute()
*/
@Override
public void execute() {
public WriteResult execute() {
if (executed.compareAndSet(false, true)) {
operations.getCqlOperations().execute(batch);
return;
return WriteResult.of(operations.getCqlOperations().queryForResultSet(batch));
}
assertNotExecuted();
return null; // code won't reach this line
}
/* (non-Javadoc)

View File

@@ -258,58 +258,55 @@ public interface CassandraOperations {
* Insert the given entity and return the entity if the insert was applied.
*
* @param entity The entity to insert, must not be {@literal null}.
* @return the inserted entity.
* @throws DataAccessException if there is any problem executing the query.
*/
<T> T insert(T entity) throws DataAccessException;
void insert(Object entity) throws DataAccessException;
/**
* Insert the given entity applying {@link WriteOptions} and return the entity if the insert was applied.
*
* @param entity The entity to insert, must not be {@literal null}.
* @param options may be {@literal null}.
* @return the inserted entity or {@literal null} if the {@code INSERT} operation was not applied.
* @return the {@link WriteResult} for this operation.
* @throws DataAccessException if there is any problem executing the query.
*/
<T> T insert(T entity, InsertOptions options) throws DataAccessException;
WriteResult insert(Object entity, InsertOptions options) throws DataAccessException;
/**
* Update the given entity and return the entity if the update was applied.
*
* @param entity The entity to update, must not be {@literal null}.
* @return the updated entity.
* @throws DataAccessException if there is any problem executing the query.
*/
<T> T update(T entity) throws DataAccessException;
void update(Object entity) throws DataAccessException;
/**
* Update the given entity applying {@link WriteOptions} and return the entity if the update was applied.
*
* @param entity The entity to update, must not be {@literal null}.
* @param options may be {@literal null}.
* @return the updated entity or {@literal null} if the {@code UPDATE} operation was not applied.
* @return the {@link WriteResult} for this operation.
* @throws DataAccessException if there is any problem executing the query.
*/
<T> T update(T entity, UpdateOptions options) throws DataAccessException;
WriteResult update(Object entity, UpdateOptions options) throws DataAccessException;
/**
* Delete the given entity and return the entity if the delete was applied.
*
* @param entity must not be {@literal null}.
* @return the deleted entity.
* @throws DataAccessException if there is any problem executing the query.
*/
<T> T delete(T entity) throws DataAccessException;
void delete(Object entity) throws DataAccessException;
/**
* Delete the given entity applying {@link QueryOptions} and return the entity if the delete was applied.
*
* @param entity must not be {@literal null}.
* @param options may be {@literal null}.
* @return the deleted entity.
* @return the {@link WriteResult} for this operation.
* @throws DataAccessException if there is any problem executing the query.
*/
<T> T delete(T entity, QueryOptions options) throws DataAccessException;
WriteResult delete(Object entity, QueryOptions options) throws DataAccessException;
/**
* Remove the given object from the table by id.

View File

@@ -15,6 +15,9 @@
*/
package org.springframework.data.cassandra.core;
import lombok.NonNull;
import lombok.Value;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
@@ -425,8 +428,8 @@ public class CassandraTemplate implements CassandraOperations {
* @see org.springframework.data.cassandra.core.CassandraOperations#insert(java.lang.Object)
*/
@Override
public <T> T insert(T entity) {
return insert(entity, null);
public void insert(Object entity) {
insert(entity, null);
}
/*
@@ -434,13 +437,13 @@ public class CassandraTemplate implements CassandraOperations {
* @see org.springframework.data.cassandra.core.CassandraOperations#insert(java.lang.Object, org.springframework.data.cassandra.core.InsertOptions)
*/
@Override
public <T> T insert(T entity, InsertOptions options) {
public WriteResult insert(Object entity, InsertOptions options) {
Assert.notNull(entity, "Entity must not be null");
Insert insert = QueryUtils.createInsertQuery(getTableName(entity.getClass()).toCql(), entity, options, converter);
return getCqlOperations().execute(new StatementCallback<>(insert, entity));
return getCqlOperations().execute(new StatementCallback(insert));
}
/*
@@ -448,8 +451,8 @@ public class CassandraTemplate implements CassandraOperations {
* @see org.springframework.data.cassandra.core.CassandraOperations#update(java.lang.Object)
*/
@Override
public <T> T update(T entity) {
return update(entity, null);
public void update(Object entity) {
update(entity, null);
}
/*
@@ -457,13 +460,13 @@ public class CassandraTemplate implements CassandraOperations {
* @see org.springframework.data.cassandra.core.CassandraOperations#update(java.lang.Object, org.springframework.data.cassandra.core.UpdateOptions)
*/
@Override
public <T> T update(T entity, UpdateOptions options) {
public WriteResult update(Object entity, UpdateOptions options) {
Assert.notNull(entity, "Entity must not be null");
Update update = QueryUtils.createUpdateQuery(getTableName(entity.getClass()).toCql(), entity, options, converter);
return getCqlOperations().execute(new StatementCallback<>(update, entity));
return getCqlOperations().execute(new StatementCallback(update));
}
/*
@@ -471,8 +474,8 @@ public class CassandraTemplate implements CassandraOperations {
* @see org.springframework.data.cassandra.core.CassandraOperations#delete(java.lang.Object)
*/
@Override
public <T> T delete(T entity) {
return delete(entity, null);
public void delete(Object entity) {
delete(entity, null);
}
/*
@@ -480,13 +483,13 @@ public class CassandraTemplate implements CassandraOperations {
* @see org.springframework.data.cassandra.core.CassandraOperations#delete(java.lang.Object, org.springframework.data.cql.core.QueryOptions)
*/
@Override
public <T> T delete(T entity, QueryOptions options) {
public WriteResult delete(Object entity, QueryOptions options) {
Assert.notNull(entity, "Entity must not be null");
Delete delete = QueryUtils.createDeleteQuery(getTableName(entity.getClass()).toCql(), entity, options, converter);
return getCqlOperations().execute(new StatementCallback<>(delete, entity));
return getCqlOperations().execute(new StatementCallback(delete));
}
/*
@@ -559,19 +562,14 @@ public class CassandraTemplate implements CassandraOperations {
return StreamSupport.stream(iterable.spliterator(), false).collect(Collectors.toList());
}
private static class StatementCallback<T> implements SessionCallback<T>, CqlProvider {
@Value
static class StatementCallback implements SessionCallback<WriteResult>, CqlProvider {
private final Statement statement;
private final T entity;
StatementCallback(Statement statement, T entity) {
this.statement = statement;
this.entity = entity;
}
@NonNull Statement statement;
@Override
public T doInSession(Session session) throws DriverException, DataAccessException {
return session.execute(statement).wasApplied() ? entity : null;
public WriteResult doInSession(Session session) throws DriverException, DataAccessException {
return WriteResult.of(session.execute(statement));
}
@Override

View File

@@ -183,11 +183,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 or {@link Mono#empty()} if the {@code INSERT} operation was not applied.
* @return the {@link WriteResult} for this operation.
* @throws DataAccessException if there is any problem issuing the execution.
*/
<T> Mono<T> insert(T entity, InsertOptions options) throws DataAccessException;
Mono<WriteResult> insert(Object entity, InsertOptions options) throws DataAccessException;
/**
* Update the given entity and emit the entity if the update was applied.
*
@@ -202,11 +201,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 or {@link Mono#empty()} if the {@code UPDATE} operation was not applied.
* @return the {@link WriteResult} for this operation.
* @throws DataAccessException if there is any problem issuing the execution.
*/
<T> Mono<T> update(T entity, UpdateOptions options) throws DataAccessException;
Mono<WriteResult> update(Object entity, UpdateOptions options) throws DataAccessException;
/**
* Remove the given object from the table by id.
*
@@ -231,11 +229,10 @@ public interface ReactiveCassandraOperations {
*
* @param entity must not be {@literal null}.
* @param options may be {@literal null}.
* @return the deleted entity.
* @return the {@link WriteResult} for this operation.
* @throws DataAccessException if there is any problem issuing the execution.
*/
<T> Mono<T> delete(T entity, QueryOptions options) throws DataAccessException;
Mono<WriteResult> delete(Object entity, QueryOptions options) throws DataAccessException;
/**
* Execute a {@code TRUNCATE} query to remove all entities of a given class.
*

View File

@@ -15,6 +15,8 @@
*/
package org.springframework.data.cassandra.core;
import lombok.NonNull;
import lombok.Value;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@@ -374,7 +376,7 @@ public class ReactiveCassandraTemplate implements ReactiveCassandraOperations {
*/
@Override
public <T> Mono<T> insert(T entity) {
return insert(entity, null);
return insert(entity, null).map(writeResult -> entity);
}
/*
@@ -382,27 +384,13 @@ public class ReactiveCassandraTemplate implements ReactiveCassandraOperations {
* @see org.springframework.data.cassandra.core.ReactiveCassandraOperations#insert(java.lang.Object, org.springframework.data.cassandra.core.InsertOptions)
*/
@Override
public <T> Mono<T> insert(T entity, InsertOptions options) {
public Mono<WriteResult> insert(Object entity, InsertOptions options) {
Assert.notNull(entity, "Entity must not be null");
Insert insert = QueryUtils.createInsertQuery(getTableName(entity).toCql(), entity, options, getConverter());
class InsertCallback implements ReactiveSessionCallback<T>, CqlProvider {
@Override
public Publisher<T> doInSession(ReactiveSession session) throws DriverException, DataAccessException {
return session.execute(insert)
.flatMap(reactiveResultSet -> reactiveResultSet.wasApplied() ? Mono.just(entity) : Mono.empty());
}
@Override
public String getCql() {
return insert.toString();
}
}
return getReactiveCqlOperations().execute(new InsertCallback()).next();
return getReactiveCqlOperations().execute(new StatementCallback(insert)).next();
}
/*
@@ -411,7 +399,7 @@ public class ReactiveCassandraTemplate implements ReactiveCassandraOperations {
*/
@Override
public <T> Mono<T> update(T entity) {
return update(entity, null);
return update(entity, null).map(writeResult -> entity);
}
/*
@@ -419,27 +407,13 @@ public class ReactiveCassandraTemplate implements ReactiveCassandraOperations {
* @see org.springframework.data.cassandra.core.ReactiveCassandraOperations#update(java.lang.Object, org.springframework.data.cassandra.core.UpdateOptions)
*/
@Override
public <T> Mono<T> update(T entity, UpdateOptions options) {
public Mono<WriteResult> update(Object entity, UpdateOptions options) {
Assert.notNull(entity, "Entity must not be null");
Update update = QueryUtils.createUpdateQuery(getTableName(entity).toCql(), entity, options, converter);
class UpdateCallback implements ReactiveSessionCallback<T>, CqlProvider {
@Override
public Publisher<T> doInSession(ReactiveSession session) throws DriverException, DataAccessException {
return session.execute(update)
.flatMap(reactiveResultSet -> reactiveResultSet.wasApplied() ? Mono.just(entity) : Mono.empty());
}
@Override
public String getCql() {
return update.toString();
}
}
return getReactiveCqlOperations().execute(new UpdateCallback()).next();
return getReactiveCqlOperations().execute(new StatementCallback(update)).next();
}
/*
@@ -467,7 +441,7 @@ public class ReactiveCassandraTemplate implements ReactiveCassandraOperations {
*/
@Override
public <T> Mono<T> delete(T entity) {
return delete(entity, null);
return delete(entity, null).map(reactiveWriteResult -> entity);
}
/*
@@ -475,27 +449,13 @@ public class ReactiveCassandraTemplate implements ReactiveCassandraOperations {
* @see org.springframework.data.cassandra.core.ReactiveCassandraOperations#delete(java.lang.Object, org.springframework.data.cql.core.QueryOptions)
*/
@Override
public <T> Mono<T> delete(T entity, QueryOptions options) {
public Mono<WriteResult> delete(Object entity, QueryOptions options) {
Assert.notNull(entity, "Entity must not be null");
Delete delete = QueryUtils.createDeleteQuery(getTableName(entity).toCql(), entity, options, getConverter());
class DeleteCallback implements ReactiveSessionCallback<T>, CqlProvider {
@Override
public Publisher<T> doInSession(ReactiveSession session) throws DriverException, DataAccessException {
return session.execute(delete)
.flatMap(reactiveResultSet -> reactiveResultSet.wasApplied() ? Mono.just(entity) : Mono.empty());
}
@Override
public String getCql() {
return delete.toString();
}
}
return getReactiveCqlOperations().execute(new DeleteCallback()).next();
return getReactiveCqlOperations().execute(new StatementCallback(delete)).next();
}
/*
@@ -512,4 +472,26 @@ public class ReactiveCassandraTemplate implements ReactiveCassandraOperations {
return getReactiveCqlOperations().execute(truncate).then();
}
@Value
static class StatementCallback implements ReactiveSessionCallback<WriteResult>, CqlProvider {
@NonNull Statement statement;
@Override
public Publisher<WriteResult> doInSession(ReactiveSession session) throws DriverException, DataAccessException {
return session.execute(statement).flatMap(StatementCallback::toWriteResult);
}
@Override
public String getCql() {
return statement.toString();
}
private static Mono<WriteResult> toWriteResult(ReactiveResultSet resultSet) {
return resultSet.rows().collectList()
.map(rows -> new WriteResult(resultSet.getAllExecutionInfo(), resultSet.wasApplied(), rows));
}
}
}

View File

@@ -0,0 +1,97 @@
/*
* 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.ArrayList;
import java.util.Collections;
import java.util.List;
import org.springframework.util.Assert;
import com.datastax.driver.core.ExecutionInfo;
import com.datastax.driver.core.ResultSet;
import com.datastax.driver.core.Row;
/**
* The result of a write operation.
*
* @author Mark Paluch
* @since 2.0
* @see ResultSet
*/
public class WriteResult {
private final List<ExecutionInfo> executionInfo;
private final boolean wasApplied;
private final List<Row> rows;
WriteResult(List<ExecutionInfo> executionInfo, boolean wasApplied, List<Row> rows) {
this.executionInfo = executionInfo;
this.wasApplied = wasApplied;
this.rows = rows;
}
private WriteResult(ResultSet resultSet) {
this.executionInfo = resultSet.getAllExecutionInfo();
this.wasApplied = resultSet.wasApplied();
int limit = resultSet.getAvailableWithoutFetching();
List<Row> rows = new ArrayList<>(limit);
for (int i = 0; i < limit; i++) {
rows.add(resultSet.one());
}
this.rows = Collections.unmodifiableList(rows);
}
/**
* Create a {@link WriteResult} from {@link ResultSet}.
*
* @param resultSet must not be {@literal null}.
* @return the {@link WriteResult} for {@link ResultSet}.
*/
public static WriteResult of(ResultSet resultSet) {
Assert.notNull(resultSet, "ResultSet must not be null");
return new WriteResult(resultSet);
}
/**
* @return {@literal true} if the write was applied.
*/
public boolean wasApplied() {
return wasApplied;
}
/**
* @return the list of {@link ExecutionInfo}.
*/
public List<ExecutionInfo> getExecutionInfo() {
return executionInfo;
}
/**
* @return the {@link Row rows} returned by the write operation.
*/
public List<Row> getRows() {
return rows;
}
}

View File

@@ -123,7 +123,9 @@ public class SimpleCassandraRepository<T, ID> implements CassandraRepository<T,
Assert.notNull(entity, "Entity must not be null");
return operations.insert(entity);
operations.insert(entity);
return entity;
}
/* (non-Javadoc)
@@ -137,12 +139,8 @@ public class SimpleCassandraRepository<T, ID> implements CassandraRepository<T,
List<S> result = new ArrayList<>();
for (S entity : entities) {
S saved = operations.insert(entity);
if (saved != null) {
result.add(saved);
}
result.add(entity);
operations.insert(entity);
}
return result;

View File

@@ -114,9 +114,9 @@ public class AsyncCassandraTemplateIntegrationTests extends AbstractKeyspaceCrea
User user = new User("heisenberg", "Walter", "White");
ListenableFuture<User> inserted = template.insert(user, lwtOptions);
ListenableFuture<WriteResult> inserted = template.insert(user, lwtOptions);
assertThat(getUninterruptibly(inserted)).isEqualTo(user);
assertThat(getUninterruptibly(inserted).wasApplied()).isTrue();
}
@Test // DATACASS-250
@@ -130,9 +130,9 @@ public class AsyncCassandraTemplateIntegrationTests extends AbstractKeyspaceCrea
user.setFirstname("Walter Hartwell");
ListenableFuture<User> lwt = template.insert(user, lwtOptions);
ListenableFuture<WriteResult> lwt = template.insert(user, lwtOptions);
assertThat(getUninterruptibly(lwt)).isNull();
assertThat(getUninterruptibly(lwt).wasApplied()).isFalse();
assertThat(getUser(user.getId()).getFirstname()).isEqualTo("Walter");
}
@@ -168,9 +168,9 @@ public class AsyncCassandraTemplateIntegrationTests extends AbstractKeyspaceCrea
User user = new User("heisenberg", "Walter", "White");
ListenableFuture<User> lwt = template.update(user, lwtOptions);
ListenableFuture<WriteResult> lwt = template.update(user, lwtOptions);
assertThat(getUninterruptibly(lwt)).isNull();
assertThat(getUninterruptibly(lwt).wasApplied()).isFalse();
assertThat(getUser(user.getId())).isNull();
}
@@ -184,9 +184,9 @@ public class AsyncCassandraTemplateIntegrationTests extends AbstractKeyspaceCrea
user.setFirstname("Walter Hartwell");
ListenableFuture<User> updated = template.update(user, lwtOptions);
ListenableFuture<WriteResult> updated = template.update(user, lwtOptions);
assertThat(getUninterruptibly(updated)).isNotNull();
assertThat(getUninterruptibly(updated).wasApplied()).isTrue();
assertThat(getUser(user.getId()).getFirstname()).isEqualTo("Walter Hartwell");
}

View File

@@ -256,18 +256,6 @@ public class AsyncCassandraTemplateUnitTests {
}
}
@Test // DATACASS-292
public void insertShouldNotApplyInsert() {
when(resultSet.wasApplied()).thenReturn(false);
User user = new User("heisenberg", "Walter", "White");
ListenableFuture<User> future = template.insert(user);
assertThat(getUninterruptibly(future)).isNull();
}
@Test // DATACASS-292
public void updateShouldUpdateEntity() {
@@ -302,18 +290,6 @@ public class AsyncCassandraTemplateUnitTests {
}
}
@Test // DATACASS-292
public void updateShouldNotApplyUpdate() {
when(resultSet.wasApplied()).thenReturn(false);
User user = new User("heisenberg", "Walter", "White");
ListenableFuture<User> future = template.update(user);
assertThat(getUninterruptibly(future)).isNull();
}
@Test // DATACASS-292
public void deleteByIdShouldRemoveEntity() {
@@ -361,18 +337,6 @@ public class AsyncCassandraTemplateUnitTests {
}
}
@Test // DATACASS-292
public void deleteShouldNotApplyRemoval() {
when(resultSet.wasApplied()).thenReturn(false);
User user = new User("heisenberg", "Walter", "White");
ListenableFuture<User> future = template.delete(user);
assertThat(getUninterruptibly(future)).isNull();
}
@Test // DATACASS-292
public void truncateShouldRemoveEntities() {

View File

@@ -85,7 +85,7 @@ public class CassandraBatchTemplateIntegrationTests extends AbstractKeyspaceCrea
walter.setAge(100);
CassandraBatchOperations batchOperations = new CassandraBatchTemplate(template);
batchOperations.insert(Collections.singleton(walter), lwtOptions).insert(mike).execute();
WriteResult writeResult = 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);
@@ -94,6 +94,9 @@ public class CassandraBatchTemplateIntegrationTests extends AbstractKeyspaceCrea
assertThat(loadedWalter.getAge()).isEqualTo(42);
assertThat(loadedMike).isNotNull();
assertThat(writeResult.wasApplied()).isFalse();
assertThat(writeResult.getExecutionInfo()).isNotEmpty();
assertThat(writeResult.getRows()).isNotEmpty();
}
@Test // DATACASS-288
@@ -180,8 +183,11 @@ public class CassandraBatchTemplateIntegrationTests extends AbstractKeyspaceCrea
@Test // DATACASS-288
public void shouldUpdatesCollectionOfEntities() {
FlatGroup walter = template.insert(new FlatGroup("users", "0x1", "walter"));
FlatGroup mike = template.insert(new FlatGroup("users", "0x1", "mike"));
FlatGroup walter = new FlatGroup("users", "0x1", "walter");
FlatGroup mike = new FlatGroup("users", "0x1", "mike");
template.insert(walter);
template.insert(mike);
walter.setEmail("walter@white.com");
mike.setEmail("mike@sauls.com");

View File

@@ -140,9 +140,8 @@ public class CassandraTemplateIntegrationTests extends AbstractKeyspaceCreatingI
assertThat(template.selectOneById(user.getId(), User.class)).isNull();
User inserted = template.insert(user);
template.insert(user);
assertThat(inserted).isEqualTo(user);
assertThat(template.selectOneById(user.getId(), User.class)).isEqualTo(user);
}
@@ -153,9 +152,9 @@ public class CassandraTemplateIntegrationTests extends AbstractKeyspaceCreatingI
User user = new User("heisenberg", "Walter", "White");
User inserted = template.insert(user, lwtOptions);
template.insert(user, lwtOptions);
assertThat(inserted).isEqualTo(user);
assertThat(template.selectOneById(user.getId(), User.class)).isNotNull();
}
@Test // DATACASS-250
@@ -169,9 +168,9 @@ public class CassandraTemplateIntegrationTests extends AbstractKeyspaceCreatingI
user.setFirstname("Walter Hartwell");
User lwt = template.insert(user, lwtOptions);
WriteResult lwt = template.insert(user, lwtOptions);
assertThat(lwt).isNull();
assertThat(lwt.wasApplied()).isFalse();
assertThat(template.selectOneById(user.getId(), User.class).getFirstname()).isEqualTo("Walter");
}
@@ -194,9 +193,8 @@ public class CassandraTemplateIntegrationTests extends AbstractKeyspaceCreatingI
user.setFirstname("Walter Hartwell");
User updated = template.update(user);
template.update(user);
assertThat(updated).isNotNull();
assertThat(template.selectOneById(user.getId(), User.class)).isEqualTo(user);
}
@@ -207,9 +205,9 @@ public class CassandraTemplateIntegrationTests extends AbstractKeyspaceCreatingI
User user = new User("heisenberg", "Walter", "White");
User lwt = template.update(user, lwtOptions);
WriteResult lwt = template.update(user, lwtOptions);
assertThat(lwt).isNull();
assertThat(lwt.wasApplied()).isFalse();
assertThat(template.selectOneById(user.getId(), User.class)).isNull();
}
@@ -223,9 +221,9 @@ public class CassandraTemplateIntegrationTests extends AbstractKeyspaceCreatingI
user.setFirstname("Walter Hartwell");
User updated = template.update(user, lwtOptions);
WriteResult lwt = template.update(user, lwtOptions);
assertThat(updated).isNotNull();
assertThat(lwt.wasApplied()).isTrue();
assertThat(template.selectOneById(user.getId(), User.class).getFirstname()).isEqualTo("Walter Hartwell");
}
@@ -275,9 +273,8 @@ public class CassandraTemplateIntegrationTests extends AbstractKeyspaceCreatingI
User user = new User("heisenberg", "Walter", "White");
template.insert(user);
User deleted = template.delete(user);
template.delete(user);
assertThat(deleted).isNotNull();
assertThat(template.selectOneById(user.getId(), User.class)).isNull();
}

View File

@@ -196,9 +196,8 @@ public class CassandraTemplateUnitTests {
User user = new User("heisenberg", "Walter", "White");
User inserted = template.insert(user);
template.insert(user);
assertThat(inserted).isEqualTo(user);
verify(session).execute(statementCaptor.capture());
assertThat(statementCaptor.getValue().toString())
.isEqualTo("INSERT INTO users (firstname,id,lastname) VALUES ('Walter','heisenberg','White');");
@@ -213,9 +212,8 @@ public class CassandraTemplateUnitTests {
User user = new User("heisenberg", "Walter", "White");
User inserted = template.insert(user, insertOptions);
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;");
@@ -243,9 +241,9 @@ public class CassandraTemplateUnitTests {
User user = new User("heisenberg", "Walter", "White");
User inserted = template.insert(user);
WriteResult writeResult = template.insert(user, InsertOptions.builder().build());
assertThat(inserted).isNull();
assertThat(writeResult.wasApplied()).isFalse();
}
@Test // DATACASS-292
@@ -255,9 +253,8 @@ public class CassandraTemplateUnitTests {
User user = new User("heisenberg", "Walter", "White");
User updated = template.update(user);
template.update(user);
assertThat(updated).isEqualTo(user);
verify(session).execute(statementCaptor.capture());
assertThat(statementCaptor.getValue().toString())
.isEqualTo("UPDATE users SET firstname='Walter',lastname='White' WHERE id='heisenberg';");
@@ -272,9 +269,9 @@ public class CassandraTemplateUnitTests {
User user = new User("heisenberg", "Walter", "White");
User updated = template.update(user, updateOptions);
WriteResult writeResult = template.update(user, updateOptions);
assertThat(updated).isEqualTo(user);
assertThat(writeResult.wasApplied()).isTrue();
verify(session).execute(statementCaptor.capture());
assertThat(statementCaptor.getValue().toString())
.isEqualTo("UPDATE users SET firstname='Walter',lastname='White' WHERE id='heisenberg' IF EXISTS;");
@@ -295,18 +292,6 @@ public class CassandraTemplateUnitTests {
}
}
@Test // DATACASS-292
public void updateShouldNotApplyUpdate() {
when(resultSet.wasApplied()).thenReturn(false);
User user = new User("heisenberg", "Walter", "White");
User updated = template.update(user);
assertThat(updated).isNull();
}
@Test // DATACASS-292
public void deleteByIdShouldRemoveEntity() {
@@ -328,9 +313,8 @@ public class CassandraTemplateUnitTests {
User user = new User("heisenberg", "Walter", "White");
User deleted = template.delete(user);
template.delete(user);
assertThat(deleted).isEqualTo(user);
verify(session).execute(statementCaptor.capture());
assertThat(statementCaptor.getValue().toString()).isEqualTo("DELETE FROM users WHERE id='heisenberg';");
}
@@ -350,18 +334,6 @@ public class CassandraTemplateUnitTests {
}
}
@Test // DATACASS-292
public void deleteShouldNotApplyRemoval() {
when(resultSet.wasApplied()).thenReturn(false);
User user = new User("heisenberg", "Walter", "White");
User deleted = template.delete(user);
assertThat(deleted).isNull();
}
@Test // DATACASS-292
public void truncateShouldRemoveEntities() {

View File

@@ -83,9 +83,9 @@ public class ReactiveCassandraTemplateIntegrationTests extends AbstractKeyspaceC
User user = new User("heisenberg", "Walter", "White");
Mono<User> inserted = template.insert(user, lwtOptions);
Mono<WriteResult> inserted = template.insert(user, lwtOptions);
StepVerifier.create(inserted).expectNext(user).verifyComplete();
StepVerifier.create(inserted.map(WriteResult::wasApplied)).expectNext(true).verifyComplete();
}
@Test // DATACASS-250
@@ -95,11 +95,13 @@ public class ReactiveCassandraTemplateIntegrationTests extends AbstractKeyspaceC
User user = new User("heisenberg", "Walter", "White");
StepVerifier.create(template.insert(user, lwtOptions)).expectNext(user).verifyComplete();
StepVerifier.create(template.insert(user, lwtOptions).map(WriteResult::wasApplied)).expectNext(true)
.verifyComplete();
user.setFirstname("Walter Hartwell");
StepVerifier.create(template.insert(user, lwtOptions)).verifyComplete();
StepVerifier.create(template.insert(user, lwtOptions).map(WriteResult::wasApplied)).expectNext(false)
.verifyComplete();
verifyUser(user.getId()).consumeNextWith(it -> assertThat(it.getFirstname()).isEqualTo("Walter")).verifyComplete();
}
@@ -135,7 +137,8 @@ public class ReactiveCassandraTemplateIntegrationTests extends AbstractKeyspaceC
User user = new User("heisenberg", "Walter", "White");
StepVerifier.create(template.update(user, lwtOptions)).verifyComplete();
StepVerifier.create(template.update(user, lwtOptions).map(WriteResult::wasApplied)).expectNext(false)
.verifyComplete();
verifyUser(user.getId()).verifyComplete();
}

View File

@@ -166,6 +166,7 @@ public class ReactiveCassandraTemplateUnitTests {
public void insertShouldInsertEntity() {
when(reactiveResultSet.wasApplied()).thenReturn(true);
when(reactiveResultSet.rows()).thenReturn(Flux.just(row));
User user = new User("heisenberg", "Walter", "White");
StepVerifier.create(template.insert(user)).expectNext(user).verifyComplete();
@@ -189,20 +190,11 @@ public class ReactiveCassandraTemplateUnitTests {
}).verify();
}
@Test // DATACASS-335
public void insertShouldNotApplyInsert() {
when(reactiveResultSet.wasApplied()).thenReturn(false);
User user = new User("heisenberg", "Walter", "White");
StepVerifier.create(template.insert(user)).verifyComplete();
}
@Test // DATACASS-335
public void updateShouldUpdateEntity() {
when(reactiveResultSet.wasApplied()).thenReturn(true);
when(reactiveResultSet.rows()).thenReturn(Flux.just(row));
User user = new User("heisenberg", "Walter", "White");
@@ -213,20 +205,11 @@ public class ReactiveCassandraTemplateUnitTests {
.isEqualTo("UPDATE users SET firstname='Walter',lastname='White' WHERE id='heisenberg';");
}
@Test // DATACASS-335
public void updateShouldNotApplyUpdate() {
when(reactiveResultSet.wasApplied()).thenReturn(false);
User user = new User("heisenberg", "Walter", "White");
StepVerifier.create(template.update(user)).verifyComplete();
}
@Test // DATACASS-335
public void deleteShouldRemoveEntity() {
when(reactiveResultSet.wasApplied()).thenReturn(true);
when(reactiveResultSet.rows()).thenReturn(Flux.just(row));
User user = new User("heisenberg", "Walter", "White");
@@ -236,16 +219,6 @@ public class ReactiveCassandraTemplateUnitTests {
assertThat(statementCaptor.getValue().toString()).isEqualTo("DELETE FROM users WHERE id='heisenberg';");
}
@Test // DATACASS-335
public void deleteShouldNotApplyRemoval() {
when(reactiveResultSet.wasApplied()).thenReturn(false);
User user = new User("heisenberg", "Walter", "White");
StepVerifier.create(template.delete(user)).verifyComplete();
}
@Test // DATACASS-335
public void truncateShouldRemoveEntities() {

View File

@@ -58,23 +58,20 @@ public class CassandraTemplateMapIdProxyDelegateIntegrationTests extends Abstrac
// insert
SinglePkc inserted = new SinglePkc(uuid());
inserted.setValue(uuid());
SinglePkc saved = operations.insert(inserted);
assertThat(inserted).isSameAs(saved);
operations.insert(inserted);
// select
SinglePkcId id = id(SinglePkcId.class).key(saved.getKey());
SinglePkcId id = id(SinglePkcId.class).key(inserted.getKey());
SinglePkc selected = operations.selectOneById(id, SinglePkc.class);
assertThat(saved).isNotSameAs(selected);
assertThat(selected.getKey()).isEqualTo(saved.getKey());
assertThat(selected.getValue()).isEqualTo(saved.getValue());
assertThat(inserted).isNotSameAs(selected);
assertThat(selected.getKey()).isEqualTo(inserted.getKey());
assertThat(selected.getValue()).isEqualTo(inserted.getValue());
// update
selected.setValue(uuid());
SinglePkc updated = operations.update(selected);
assertThat(selected).isSameAs(updated);
operations.update(selected);
selected = operations.selectOneById(id, SinglePkc.class);
assertThat(updated).isNotSameAs(selected);
SinglePkc updated = operations.selectOneById(id, SinglePkc.class);
assertThat(selected.getValue()).isEqualTo(updated.getValue());
// delete
@@ -122,23 +119,20 @@ public class CassandraTemplateMapIdProxyDelegateIntegrationTests extends Abstrac
// insert
MultiPkc inserted = new MultiPkc(uuid(), uuid());
inserted.setValue(uuid());
MultiPkc saved = operations.insert(inserted);
assertThat(inserted).isSameAs(saved);
operations.insert(inserted);
// select
MultiPkcId id = id(MultiPkcId.class).key0(saved.getKey0()).key1(saved.getKey1());
MultiPkcId id = id(MultiPkcId.class).key0(inserted.getKey0()).key1(inserted.getKey1());
MultiPkc selected = operations.selectOneById(id, MultiPkc.class);
assertThat(saved).isNotSameAs(selected);
assertThat(selected.getKey0()).isEqualTo(saved.getKey0());
assertThat(selected.getKey1()).isEqualTo(saved.getKey1());
assertThat(selected.getValue()).isEqualTo(saved.getValue());
assertThat(selected.getKey0()).isEqualTo(inserted.getKey0());
assertThat(selected.getKey1()).isEqualTo(inserted.getKey1());
assertThat(selected.getValue()).isEqualTo(inserted.getValue());
// update
selected.setValue(uuid());
MultiPkc updated = operations.update(selected);
assertThat(selected).isSameAs(updated);
operations.update(selected);
selected = operations.selectOneById(id, MultiPkc.class);
MultiPkc updated = operations.selectOneById(id, MultiPkc.class);
assertThat(updated).isNotSameAs(selected);
assertThat(selected.getValue()).isEqualTo(updated.getValue());

View File

@@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.cassandra.test.integration.mapping.mapid.template;
import static org.assertj.core.api.Assertions.*;
@@ -58,22 +57,19 @@ public class CassandraTemplateMapIdIntegrationTest extends AbstractKeyspaceCreat
// insert
SinglePkc inserted = new SinglePkc(uuid());
inserted.setValue(uuid());
SinglePkc saved = operations.insert(inserted);
assertThat(inserted).isSameAs(saved);
operations.insert(inserted);
// select
MapId id = id("key", saved.getKey());
MapId id = id("key", inserted.getKey());
SinglePkc selected = operations.selectOneById(id, SinglePkc.class);
assertThat(saved).isNotSameAs(selected);
assertThat(selected.getKey()).isEqualTo(saved.getKey());
assertThat(selected.getValue()).isEqualTo(saved.getValue());
assertThat(selected.getKey()).isEqualTo(inserted.getKey());
assertThat(selected.getValue()).isEqualTo(inserted.getValue());
// update
selected.setValue(uuid());
SinglePkc updated = operations.update(selected);
assertThat(selected).isSameAs(updated);
operations.update(selected);
selected = operations.selectOneById(id, SinglePkc.class);
SinglePkc updated = operations.selectOneById(id, SinglePkc.class);
assertThat(updated).isNotSameAs(selected);
assertThat(selected.getValue()).isEqualTo(updated.getValue());
@@ -110,37 +106,6 @@ public class CassandraTemplateMapIdIntegrationTest extends AbstractKeyspaceCreat
}
}
@Test
public void testMultiPkc() {
// insert
MultiPkc inserted = new MultiPkc(uuid(), uuid());
inserted.setValue(uuid());
MultiPkc saved = operations.insert(inserted);
assertThat(inserted).isSameAs(saved);
// select
MapId id = id("key0", saved.getKey0()).with("key1", saved.getKey1());
MultiPkc selected = operations.selectOneById(id, MultiPkc.class);
assertThat(saved).isNotSameAs(selected);
assertThat(selected.getKey0()).isEqualTo(saved.getKey0());
assertThat(selected.getKey1()).isEqualTo(saved.getKey1());
assertThat(selected.getValue()).isEqualTo(saved.getValue());
// update
selected.setValue(uuid());
MultiPkc updated = operations.update(selected);
assertThat(selected).isSameAs(updated);
selected = operations.selectOneById(id, MultiPkc.class);
assertThat(updated).isNotSameAs(selected);
assertThat(selected.getValue()).isEqualTo(updated.getValue());
// delete
operations.delete(selected);
assertThat(operations.selectOneById(id, MultiPkc.class)).isNull();
}
@Table
public static class MultiPkc {

View File

@@ -1159,13 +1159,13 @@ 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, InsertOptions options)` Insert the object in an Apache Cassandra table applying `InsertOptions`.
* `void` *insert* `(Object objectToSave)` Insert the object in an Apache Cassandra table.
* `WriteResult` *insert* `(Object 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, UpdateOptions options)` Update the object in an Apache Cassandra table applying `UpdateOptions`.
* `void` *update* `(Object objectToSave)` Update the object in an Apache Cassandra table.
* `WriteResult` *update* `(Object 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. You can configure with `InsertOptions` and `UpdateOptions`
additional options such as TTL, consistency level and lightweight transactions.