DATACASS-573 - Add mutation support for immutable types.
We now return new instances that are potentially created by wither/Kotlin copy(…) methods when reading immutable properties.
This commit is contained in:
committed by
Oliver Gierke
parent
c843293fa5
commit
fbcf50e27a
@@ -292,11 +292,11 @@ public interface AsyncCassandraOperations {
|
||||
*
|
||||
* @param entity The entity to insert, must not be {@literal null}.
|
||||
* @param options must not be {@literal null}.
|
||||
* @return the {@link WriteResult} for this operation.
|
||||
* @return the {@link EntityWriteResult} for this operation.
|
||||
* @throws DataAccessException if there is any problem executing the query.
|
||||
* @see InsertOptions#empty()
|
||||
*/
|
||||
ListenableFuture<WriteResult> insert(Object entity, InsertOptions options) throws DataAccessException;
|
||||
<T> ListenableFuture<EntityWriteResult<T>> insert(T entity, InsertOptions options) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Update the given entity and return the entity if the update was applied.
|
||||
@@ -312,11 +312,11 @@ public interface AsyncCassandraOperations {
|
||||
*
|
||||
* @param entity The entity to update, must not be {@literal null}.
|
||||
* @param options must not be {@literal null}.
|
||||
* @return the {@link WriteResult} for this operation.
|
||||
* @return the {@link EntityWriteResult} for this operation.
|
||||
* @throws DataAccessException if there is any problem executing the query.
|
||||
* @see UpdateOptions#empty()
|
||||
*/
|
||||
ListenableFuture<WriteResult> update(Object entity, UpdateOptions options) throws DataAccessException;
|
||||
<T> ListenableFuture<EntityWriteResult<T>> update(T entity, UpdateOptions options) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Delete the given entity and return the entity if the delete was applied.
|
||||
|
||||
@@ -497,7 +497,7 @@ public class AsyncCassandraTemplate implements AsyncCassandraOperations, Applica
|
||||
* @see org.springframework.data.cassandra.core.AsyncCassandraOperations#insert(java.lang.Object, org.springframework.data.cassandra.core.InsertOptions)
|
||||
*/
|
||||
@Override
|
||||
public ListenableFuture<WriteResult> insert(Object entity, InsertOptions options) {
|
||||
public <T> ListenableFuture<EntityWriteResult<T>> insert(T entity, InsertOptions options) {
|
||||
|
||||
Assert.notNull(entity, "Entity must not be null");
|
||||
Assert.notNull(options, "InsertOptions must not be null");
|
||||
@@ -511,7 +511,7 @@ public class AsyncCassandraTemplate implements AsyncCassandraOperations, Applica
|
||||
return new MappingListenableFutureAdapter<>(getAsyncCqlOperations().execute(new AsyncStatementCallback(insert)),
|
||||
resultSet -> {
|
||||
maybeEmitEvent(new AfterSaveEvent<>(entity, tableName));
|
||||
return WriteResult.of(resultSet);
|
||||
return EntityWriteResult.of(resultSet, entity);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -520,14 +520,14 @@ public class AsyncCassandraTemplate implements AsyncCassandraOperations, Applica
|
||||
*/
|
||||
@Override
|
||||
public <T> ListenableFuture<T> update(T entity) {
|
||||
return new MappingListenableFutureAdapter<>(update(entity, UpdateOptions.empty()), writeResult -> entity);
|
||||
return new MappingListenableFutureAdapter<>(update(entity, UpdateOptions.empty()), EntityWriteResult::getEntity);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.cassandra.core.AsyncCassandraOperations#update(java.lang.Object, org.springframework.data.cassandra.core.UpdateOptions)
|
||||
*/
|
||||
@Override
|
||||
public ListenableFuture<WriteResult> update(Object entity, UpdateOptions options) {
|
||||
public <T> ListenableFuture<EntityWriteResult<T>> update(T entity, UpdateOptions options) {
|
||||
|
||||
Assert.notNull(entity, "Entity must not be null");
|
||||
Assert.notNull(options, "UpdateOptions must not be null");
|
||||
@@ -540,7 +540,7 @@ public class AsyncCassandraTemplate implements AsyncCassandraOperations, Applica
|
||||
return new MappingListenableFutureAdapter<>(getAsyncCqlOperations().execute(new AsyncStatementCallback(update)),
|
||||
resultSet -> {
|
||||
maybeEmitEvent(new AfterSaveEvent<>(entity, tableName));
|
||||
return WriteResult.of(resultSet);
|
||||
return EntityWriteResult.of(resultSet, entity);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -310,39 +310,41 @@ public interface CassandraOperations extends FluentCassandraOperations {
|
||||
* 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.
|
||||
*/
|
||||
void insert(Object entity) throws DataAccessException;
|
||||
<T> T insert(T 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 must not be {@literal null}.
|
||||
* @return the {@link WriteResult} for this operation.
|
||||
* @return the {@link EntityWriteResult} for this operation.
|
||||
* @throws DataAccessException if there is any problem executing the query.
|
||||
* @see InsertOptions#empty()
|
||||
*/
|
||||
WriteResult insert(Object entity, InsertOptions options) throws DataAccessException;
|
||||
<T> EntityWriteResult<T> insert(T 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.
|
||||
*/
|
||||
void update(Object entity) throws DataAccessException;
|
||||
<T> T update(T 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 must not be {@literal null}.
|
||||
* @return the {@link WriteResult} for this operation.
|
||||
* @return the {@link EntityWriteResult} for this operation.
|
||||
* @throws DataAccessException if there is any problem executing the query.
|
||||
* @see UpdateOptions#empty()
|
||||
*/
|
||||
WriteResult update(Object entity, UpdateOptions options) throws DataAccessException;
|
||||
<T> EntityWriteResult<T> update(T entity, UpdateOptions options) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Delete the given entity and return the entity if the delete was applied.
|
||||
|
||||
@@ -531,15 +531,15 @@ public class CassandraTemplate implements CassandraOperations, ApplicationEventP
|
||||
* @see org.springframework.data.cassandra.core.CassandraOperations#insert(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public void insert(Object entity) {
|
||||
insert(entity, InsertOptions.empty());
|
||||
public <T> T insert(T entity) {
|
||||
return insert(entity, InsertOptions.empty()).getEntity();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.cassandra.core.CassandraOperations#insert(java.lang.Object, org.springframework.data.cassandra.core.InsertOptions)
|
||||
*/
|
||||
@Override
|
||||
public WriteResult insert(Object entity, InsertOptions options) {
|
||||
public <T> EntityWriteResult<T> insert(T entity, InsertOptions options) {
|
||||
|
||||
Assert.notNull(entity, "Entity must not be null");
|
||||
Assert.notNull(options, "InsertOptions must not be null");
|
||||
@@ -547,7 +547,7 @@ public class CassandraTemplate implements CassandraOperations, ApplicationEventP
|
||||
return doInsert(entity, options, getTableName(entity));
|
||||
}
|
||||
|
||||
WriteResult doInsert(Object entity, WriteOptions options, CqlIdentifier tableName) {
|
||||
<T> EntityWriteResult<T> doInsert(T entity, WriteOptions options, CqlIdentifier tableName) {
|
||||
|
||||
CassandraPersistentEntity<?> persistentEntity = getRequiredPersistentEntity(entity.getClass());
|
||||
|
||||
@@ -560,22 +560,22 @@ public class CassandraTemplate implements CassandraOperations, ApplicationEventP
|
||||
|
||||
maybeEmitEvent(new AfterSaveEvent<>(entity, tableName));
|
||||
|
||||
return result;
|
||||
return EntityWriteResult.of(result, entity);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.cassandra.core.CassandraOperations#update(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public void update(Object entity) {
|
||||
update(entity, UpdateOptions.empty());
|
||||
public <T> T update(T entity) {
|
||||
return update(entity, UpdateOptions.empty()).getEntity();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.cassandra.core.CassandraOperations#update(java.lang.Object, org.springframework.data.cassandra.core.UpdateOptions)
|
||||
*/
|
||||
@Override
|
||||
public WriteResult update(Object entity, UpdateOptions options) {
|
||||
public <T> EntityWriteResult<T> update(T entity, UpdateOptions options) {
|
||||
|
||||
Assert.notNull(entity, "Entity must not be null");
|
||||
Assert.notNull(options, "UpdateOptions must not be null");
|
||||
@@ -590,7 +590,7 @@ public class CassandraTemplate implements CassandraOperations, ApplicationEventP
|
||||
|
||||
maybeEmitEvent(new AfterSaveEvent<>(entity, tableName));
|
||||
|
||||
return result;
|
||||
return EntityWriteResult.of(result, entity);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright 2018 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.List;
|
||||
|
||||
import com.datastax.driver.core.ExecutionInfo;
|
||||
import com.datastax.driver.core.ResultSet;
|
||||
import com.datastax.driver.core.Row;
|
||||
|
||||
/**
|
||||
* The result of a write operation for an entity.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @since 2.1
|
||||
* @see WriteResult
|
||||
*/
|
||||
public class EntityWriteResult<T> extends WriteResult {
|
||||
|
||||
private final T entity;
|
||||
|
||||
EntityWriteResult(List<ExecutionInfo> executionInfo, boolean wasApplied, List<Row> rows, T entity) {
|
||||
super(executionInfo, wasApplied, rows);
|
||||
this.entity = entity;
|
||||
}
|
||||
|
||||
EntityWriteResult(ResultSet resultSet, T entity) {
|
||||
super(resultSet);
|
||||
this.entity = entity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@link EntityWriteResult} from {@link WriteResult} and an entity.
|
||||
*
|
||||
* @param result must not be {@literal null}.
|
||||
* @param entity must not be {@literal null}.
|
||||
* @return the {@link EntityWriteResult} for {@link WriteResult} and an entity.
|
||||
*/
|
||||
static <T> EntityWriteResult<T> of(WriteResult result, T entity) {
|
||||
return new EntityWriteResult<>(result.getExecutionInfo(), result.wasApplied(), result.getRows(), entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@link EntityWriteResult} from {@link ResultSet} and an entity.
|
||||
*
|
||||
* @param resultSet must not be {@literal null}.
|
||||
* @param entity must not be {@literal null}.
|
||||
* @return the {@link EntityWriteResult} for {@link ResultSet} and an entity.
|
||||
*/
|
||||
static <T> EntityWriteResult<T> of(ResultSet resultSet, T entity) {
|
||||
return new EntityWriteResult<>(resultSet, entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the entity associated with this write operation result.
|
||||
*/
|
||||
public T getEntity() {
|
||||
return entity;
|
||||
}
|
||||
}
|
||||
@@ -114,10 +114,11 @@ public interface ExecutableInsertOperation {
|
||||
* Insert exactly one {@link Object}.
|
||||
*
|
||||
* @param object {@link Object} to insert; must not be {@literal null}.
|
||||
* @return the {@link EntityWriteResult} for this operation.
|
||||
* @throws IllegalArgumentException if {@link Object} is {@literal null}.
|
||||
* @see org.springframework.data.cassandra.core.WriteResult
|
||||
* @see org.springframework.data.cassandra.core.EntityWriteResult
|
||||
*/
|
||||
WriteResult one(T object);
|
||||
EntityWriteResult<T> one(T object);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -91,7 +91,7 @@ class ExecutableInsertOperationSupport implements ExecutableInsertOperation {
|
||||
* @see org.springframework.data.cassandra.core.ExecutableInsertOperation.TerminatingInsert#one(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public WriteResult one(T object) {
|
||||
public EntityWriteResult<T> one(T object) {
|
||||
|
||||
Assert.notNull(object, "Object must not be null");
|
||||
|
||||
|
||||
@@ -254,11 +254,11 @@ public interface ReactiveCassandraOperations extends ReactiveFluentCassandraOper
|
||||
*
|
||||
* @param entity The entity to insert, must not be {@literal null}.
|
||||
* @param options must not be {@literal null}.
|
||||
* @return the {@link WriteResult} for this operation.
|
||||
* @return the {@link EntityWriteResult} for this operation.
|
||||
* @throws DataAccessException if there is any problem issuing the execution.
|
||||
* @see InsertOptions#empty()
|
||||
*/
|
||||
Mono<WriteResult> insert(Object entity, InsertOptions options) throws DataAccessException;
|
||||
<T> Mono<EntityWriteResult<T>> insert(T entity, InsertOptions options) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Update the given entity and emit the entity if the update was applied.
|
||||
@@ -274,11 +274,11 @@ public interface ReactiveCassandraOperations extends ReactiveFluentCassandraOper
|
||||
*
|
||||
* @param entity The entity to update, must not be {@literal null}.
|
||||
* @param options must not be {@literal null}.
|
||||
* @return the {@link WriteResult} for this operation.
|
||||
* @return the {@link EntityWriteResult} for this operation.
|
||||
* @throws DataAccessException if there is any problem issuing the execution.
|
||||
* @see UpdateOptions#empty()
|
||||
*/
|
||||
Mono<WriteResult> update(Object entity, UpdateOptions options) throws DataAccessException;
|
||||
<T> Mono<EntityWriteResult<T>> update(T entity, UpdateOptions options) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Delete the given entity and emit the entity if the delete was applied.
|
||||
|
||||
@@ -461,14 +461,14 @@ public class ReactiveCassandraTemplate implements ReactiveCassandraOperations, A
|
||||
*/
|
||||
@Override
|
||||
public <T> Mono<T> insert(T entity) {
|
||||
return insert(entity, InsertOptions.empty()).map(writeResult -> entity);
|
||||
return insert(entity, InsertOptions.empty()).map(EntityWriteResult::getEntity);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.cassandra.core.ReactiveCassandraOperations#insert(java.lang.Object, org.springframework.data.cassandra.core.InsertOptions)
|
||||
*/
|
||||
@Override
|
||||
public Mono<WriteResult> insert(Object entity, InsertOptions options) {
|
||||
public <T> Mono<EntityWriteResult<T>> insert(T entity, InsertOptions options) {
|
||||
|
||||
Assert.notNull(entity, "Entity must not be null");
|
||||
Assert.notNull(options, "InsertOptions must not be null");
|
||||
@@ -476,15 +476,18 @@ public class ReactiveCassandraTemplate implements ReactiveCassandraOperations, A
|
||||
return doInsert(entity, options, getTableName(entity));
|
||||
}
|
||||
|
||||
Mono<WriteResult> doInsert(Object entity, WriteOptions options, CqlIdentifier tableName) {
|
||||
<T> Mono<EntityWriteResult<T>> doInsert(T entity, WriteOptions options, CqlIdentifier tableName) {
|
||||
|
||||
CassandraPersistentEntity<?> persistentEntity = getRequiredPersistentEntity(entity.getClass());
|
||||
|
||||
Insert insert = QueryUtils.createInsertQuery(tableName.toCql(), entity, options, getConverter(), persistentEntity);
|
||||
|
||||
// noinspection ConstantConditions
|
||||
Mono<WriteResult> result = getReactiveCqlOperations().execute(new StatementCallback(insert))
|
||||
.doOnSubscribe(it -> maybeEmitEvent(new BeforeSaveEvent<>(entity, tableName, insert))).next();
|
||||
Mono<EntityWriteResult<T>> result = getReactiveCqlOperations() //
|
||||
.execute(new StatementCallback(insert)) //
|
||||
.doOnSubscribe(it -> maybeEmitEvent(new BeforeSaveEvent<>(entity, tableName, insert))) //
|
||||
.map(it -> EntityWriteResult.of(it, entity)) //
|
||||
.next();
|
||||
|
||||
return result.doOnNext(it -> maybeEmitEvent(new AfterSaveEvent<>(entity, tableName)));
|
||||
}
|
||||
@@ -501,7 +504,7 @@ public class ReactiveCassandraTemplate implements ReactiveCassandraOperations, A
|
||||
* @see org.springframework.data.cassandra.core.ReactiveCassandraOperations#update(java.lang.Object, org.springframework.data.cassandra.core.UpdateOptions)
|
||||
*/
|
||||
@Override
|
||||
public Mono<WriteResult> update(Object entity, UpdateOptions options) {
|
||||
public <T> Mono<EntityWriteResult<T>> update(T entity, UpdateOptions options) {
|
||||
|
||||
Assert.notNull(entity, "Entity must not be null");
|
||||
Assert.notNull(options, "UpdateOptions must not be null");
|
||||
@@ -509,8 +512,11 @@ public class ReactiveCassandraTemplate implements ReactiveCassandraOperations, A
|
||||
CqlIdentifier tableName = getTableName(entity);
|
||||
Update update = QueryUtils.createUpdateQuery(tableName.toCql(), entity, options, getConverter());
|
||||
|
||||
Mono<WriteResult> result = getReactiveCqlOperations().execute(new StatementCallback(update))
|
||||
.doOnSubscribe(it -> maybeEmitEvent(new BeforeSaveEvent<>(entity, tableName, update))).next();
|
||||
Mono<EntityWriteResult<T>> result = getReactiveCqlOperations() //
|
||||
.execute(new StatementCallback(update)) //
|
||||
.doOnSubscribe(it -> maybeEmitEvent(new BeforeSaveEvent<>(entity, tableName, update))) //
|
||||
.map(it -> EntityWriteResult.of(it, entity)) //
|
||||
.next();
|
||||
|
||||
return result.doOnNext(it -> maybeEmitEvent(new AfterSaveEvent<>(entity, tableName)));
|
||||
}
|
||||
@@ -535,8 +541,10 @@ public class ReactiveCassandraTemplate implements ReactiveCassandraOperations, A
|
||||
CqlIdentifier tableName = getTableName(entity);
|
||||
Delete delete = QueryUtils.createDeleteQuery(tableName.toCql(), entity, options, getConverter());
|
||||
|
||||
Mono<WriteResult> result = getReactiveCqlOperations().execute(new StatementCallback(delete))
|
||||
.doOnSubscribe(it -> maybeEmitEvent(new BeforeDeleteEvent<>(delete, entity.getClass(), tableName))).next();
|
||||
Mono<WriteResult> result = getReactiveCqlOperations() //
|
||||
.execute(new StatementCallback(delete)) //
|
||||
.doOnSubscribe(it -> maybeEmitEvent(new BeforeDeleteEvent<>(delete, entity.getClass(), tableName))) //
|
||||
.next();
|
||||
|
||||
return result.doOnNext(it -> maybeEmitEvent(new AfterDeleteEvent<>(delete, entity.getClass(), tableName)));
|
||||
}
|
||||
|
||||
@@ -118,11 +118,12 @@ public interface ReactiveInsertOperation {
|
||||
* Insert exactly one {@link Object}.
|
||||
*
|
||||
* @param object {@link Object} to insert; must not be {@literal null}.
|
||||
* @return the {@link EntityWriteResult} for this operation.
|
||||
* @throws IllegalArgumentException if {@link Object} is {@literal null}.
|
||||
* @see org.springframework.data.cassandra.core.WriteResult
|
||||
* @see org.springframework.data.cassandra.core.EntityWriteResult
|
||||
* @see reactor.core.publisher.Mono
|
||||
*/
|
||||
Mono<WriteResult> one(T object);
|
||||
Mono<EntityWriteResult<T>> one(T object);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -19,7 +19,6 @@ import lombok.AccessLevel;
|
||||
import lombok.NonNull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.experimental.FieldDefaults;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.data.cassandra.core.cql.CqlIdentifier;
|
||||
@@ -86,7 +85,7 @@ class ReactiveInsertOperationSupport implements ReactiveInsertOperation {
|
||||
* @see org.springframework.data.cassandra.core.ReactiveInsertOperation.TerminatingInsert#one(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public Mono<WriteResult> one(T object) {
|
||||
public Mono<EntityWriteResult<T>> one(T object) {
|
||||
|
||||
Assert.notNull(object, "Object must not be null");
|
||||
|
||||
|
||||
@@ -35,7 +35,9 @@ import com.datastax.driver.core.Row;
|
||||
public class WriteResult {
|
||||
|
||||
private final boolean wasApplied;
|
||||
|
||||
private final List<ExecutionInfo> executionInfo;
|
||||
|
||||
private final List<Row> rows;
|
||||
|
||||
WriteResult(List<ExecutionInfo> executionInfo, boolean wasApplied, List<Row> rows) {
|
||||
@@ -45,7 +47,7 @@ public class WriteResult {
|
||||
this.rows = rows;
|
||||
}
|
||||
|
||||
private WriteResult(ResultSet resultSet) {
|
||||
WriteResult(ResultSet resultSet) {
|
||||
|
||||
this.executionInfo = resultSet.getAllExecutionInfo();
|
||||
this.wasApplied = resultSet.wasApplied();
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
*/
|
||||
package org.springframework.data.cassandra.core.convert;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
@@ -23,8 +25,8 @@ import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.function.Function;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanClassLoaderAware;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
@@ -57,9 +59,6 @@ import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.datastax.driver.core.CodecRegistry;
|
||||
import com.datastax.driver.core.DataType;
|
||||
import com.datastax.driver.core.Row;
|
||||
@@ -277,9 +276,10 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
|
||||
|
||||
S instance = instantiator.createInstance(entity, parameterValueProvider);
|
||||
|
||||
readProperties(entity, valueProvider, newConvertingPropertyAccessor(instance, entity));
|
||||
ConvertingPropertyAccessor propertyAccessor = newConvertingPropertyAccessor(instance, entity);
|
||||
readProperties(entity, valueProvider, propertyAccessor);
|
||||
|
||||
return instance;
|
||||
return (S) propertyAccessor.getBean();
|
||||
}
|
||||
|
||||
private void readProperties(CassandraPersistentEntity<?> entity, CassandraValueProvider valueProvider,
|
||||
@@ -309,10 +309,11 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
|
||||
}
|
||||
|
||||
// now recurse on using the key this time
|
||||
readProperties(keyEntity, valueProvider, newConvertingPropertyAccessor(key, keyEntity));
|
||||
ConvertingPropertyAccessor pkPropertyAccessor = newConvertingPropertyAccessor(key, keyEntity);
|
||||
readProperties(keyEntity, valueProvider, pkPropertyAccessor);
|
||||
|
||||
// now that the key's properties have been populated, set the key property on the entity
|
||||
propertyAccessor.setProperty(property, key);
|
||||
propertyAccessor.setProperty(property, pkPropertyAccessor.getBean());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -77,9 +77,7 @@ public class SimpleCassandraRepository<T, ID> implements CassandraRepository<T,
|
||||
|
||||
Assert.notNull(entity, "Entity must not be null");
|
||||
|
||||
operations.insert(entity, INSERT_NULLS);
|
||||
|
||||
return entity;
|
||||
return operations.insert(entity, INSERT_NULLS).getEntity();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
@@ -93,9 +91,7 @@ public class SimpleCassandraRepository<T, ID> implements CassandraRepository<T,
|
||||
List<S> result = new ArrayList<>();
|
||||
|
||||
for (S entity : entities) {
|
||||
|
||||
result.add(entity);
|
||||
operations.insert(entity, INSERT_NULLS);
|
||||
result.add(operations.insert(entity, INSERT_NULLS).getEntity());
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -121,9 +117,7 @@ public class SimpleCassandraRepository<T, ID> implements CassandraRepository<T,
|
||||
|
||||
Assert.notNull(entity, "Entity must not be null");
|
||||
|
||||
operations.insert(entity);
|
||||
|
||||
return entity;
|
||||
return operations.insert(entity);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
@@ -137,8 +131,7 @@ public class SimpleCassandraRepository<T, ID> implements CassandraRepository<T,
|
||||
List<S> result = new ArrayList<>();
|
||||
|
||||
for (S entity : entities) {
|
||||
operations.insert(entity);
|
||||
result.add(entity);
|
||||
result.add(operations.insert(entity));
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
@@ -15,8 +15,8 @@
|
||||
*/
|
||||
package org.springframework.data.cassandra.core;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.springframework.data.cassandra.core.query.Criteria.where;
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
import static org.springframework.data.cassandra.core.query.Criteria.*;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashSet;
|
||||
@@ -25,7 +25,6 @@ import java.util.concurrent.Future;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.data.cassandra.core.convert.MappingCassandraConverter;
|
||||
import org.springframework.data.cassandra.core.cql.AsyncCqlTemplate;
|
||||
import org.springframework.data.cassandra.core.query.CassandraPageRequest;
|
||||
@@ -120,7 +119,7 @@ public class AsyncCassandraTemplateIntegrationTests extends AbstractKeyspaceCrea
|
||||
|
||||
User user = new User("heisenberg", "Walter", "White");
|
||||
|
||||
ListenableFuture<WriteResult> inserted = template.insert(user, lwtOptions);
|
||||
ListenableFuture<EntityWriteResult<User>> inserted = template.insert(user, lwtOptions);
|
||||
|
||||
assertThat(getUninterruptibly(inserted).wasApplied()).isTrue();
|
||||
}
|
||||
@@ -136,7 +135,7 @@ public class AsyncCassandraTemplateIntegrationTests extends AbstractKeyspaceCrea
|
||||
|
||||
user.setFirstname("Walter Hartwell");
|
||||
|
||||
ListenableFuture<WriteResult> lwt = template.insert(user, lwtOptions);
|
||||
ListenableFuture<EntityWriteResult<User>> lwt = template.insert(user, lwtOptions);
|
||||
|
||||
assertThat(getUninterruptibly(lwt).wasApplied()).isFalse();
|
||||
assertThat(getUser(user.getId()).getFirstname()).isEqualTo("Walter");
|
||||
@@ -147,9 +146,10 @@ public class AsyncCassandraTemplateIntegrationTests extends AbstractKeyspaceCrea
|
||||
|
||||
User user = new User("heisenberg", "Walter", "White");
|
||||
|
||||
getUninterruptibly(template.insert(user));
|
||||
User result = getUninterruptibly(template.insert(user));
|
||||
|
||||
ListenableFuture<Long> count = template.count(User.class);
|
||||
assertThat(result).isSameAs(user);
|
||||
assertThat(getUninterruptibly(count)).isEqualTo(1L);
|
||||
}
|
||||
|
||||
@@ -196,7 +196,7 @@ public class AsyncCassandraTemplateIntegrationTests extends AbstractKeyspaceCrea
|
||||
|
||||
User user = new User("heisenberg", "Walter", "White");
|
||||
|
||||
ListenableFuture<WriteResult> lwt = template.update(user, lwtOptions);
|
||||
ListenableFuture<EntityWriteResult<User>> lwt = template.update(user, lwtOptions);
|
||||
|
||||
assertThat(getUninterruptibly(lwt).wasApplied()).isFalse();
|
||||
assertThat(getUser(user.getId())).isNull();
|
||||
@@ -212,9 +212,10 @@ public class AsyncCassandraTemplateIntegrationTests extends AbstractKeyspaceCrea
|
||||
|
||||
user.setFirstname("Walter Hartwell");
|
||||
|
||||
ListenableFuture<WriteResult> updated = template.update(user, lwtOptions);
|
||||
ListenableFuture<EntityWriteResult<User>> updated = template.update(user, lwtOptions);
|
||||
|
||||
assertThat(getUninterruptibly(updated).wasApplied()).isTrue();
|
||||
assertThat(getUninterruptibly(updated).getEntity()).isSameAs(user);
|
||||
assertThat(getUser(user.getId()).getFirstname()).isEqualTo("Walter Hartwell");
|
||||
}
|
||||
|
||||
|
||||
@@ -146,31 +146,33 @@ public class CassandraTemplateIntegrationTests extends AbstractKeyspaceCreatingI
|
||||
assertThat(loaded).isEqualTo(token1);
|
||||
}
|
||||
|
||||
@Test // DATACASS-292
|
||||
@Test // DATACASS-292, DATACASS-573
|
||||
public void insertShouldInsertEntity() {
|
||||
|
||||
User user = new User("heisenberg", "Walter", "White");
|
||||
|
||||
assertThat(template.selectOneById(user.getId(), User.class)).isNull();
|
||||
|
||||
template.insert(user);
|
||||
User result = template.insert(user);
|
||||
|
||||
assertThat(result).isSameAs(user);
|
||||
assertThat(template.selectOneById(user.getId(), User.class)).isEqualTo(user);
|
||||
}
|
||||
|
||||
@Test // DATACASS-250
|
||||
@Test // DATACASS-250, DATACASS-573
|
||||
public void insertShouldCreateEntityWithLwt() {
|
||||
|
||||
InsertOptions lwtOptions = InsertOptions.builder().withIfNotExists().build();
|
||||
|
||||
User user = new User("heisenberg", "Walter", "White");
|
||||
|
||||
template.insert(user, lwtOptions);
|
||||
EntityWriteResult<User> result = template.insert(user, lwtOptions);
|
||||
|
||||
assertThat(result.getEntity()).isSameAs(user);
|
||||
assertThat(template.selectOneById(user.getId(), User.class)).isNotNull();
|
||||
}
|
||||
|
||||
@Test // DATACASS-250
|
||||
@Test // DATACASS-250, DATACASS-573
|
||||
public void insertShouldNotUpdateEntityWithLwt() {
|
||||
|
||||
InsertOptions lwtOptions = InsertOptions.builder().withIfNotExists().build();
|
||||
@@ -181,7 +183,7 @@ public class CassandraTemplateIntegrationTests extends AbstractKeyspaceCreatingI
|
||||
|
||||
user.setFirstname("Walter Hartwell");
|
||||
|
||||
WriteResult lwt = template.insert(user, lwtOptions);
|
||||
EntityWriteResult<User> lwt = template.insert(user, lwtOptions);
|
||||
|
||||
assertThat(lwt.wasApplied()).isFalse();
|
||||
assertThat(template.selectOneById(user.getId(), User.class).getFirstname()).isEqualTo("Walter");
|
||||
@@ -239,7 +241,7 @@ public class CassandraTemplateIntegrationTests extends AbstractKeyspaceCreatingI
|
||||
assertThat(template.exists(Query.query(where("id").is("foo")), User.class)).isFalse();
|
||||
}
|
||||
|
||||
@Test // DATACASS-292
|
||||
@Test // DATACASS-292, DATACASS-573
|
||||
public void updateShouldUpdateEntity() {
|
||||
|
||||
User user = new User("heisenberg", "Walter", "White");
|
||||
@@ -247,8 +249,9 @@ public class CassandraTemplateIntegrationTests extends AbstractKeyspaceCreatingI
|
||||
|
||||
user.setFirstname("Walter Hartwell");
|
||||
|
||||
template.update(user);
|
||||
User result = template.update(user);
|
||||
|
||||
assertThat(result).isSameAs(user);
|
||||
assertThat(template.selectOneById(user.getId(), User.class)).isEqualTo(user);
|
||||
}
|
||||
|
||||
|
||||
@@ -92,16 +92,20 @@ public class ReactiveCassandraTemplateIntegrationTests extends AbstractKeyspaceC
|
||||
verifyUser(user.getId()).expectNext(user).verifyComplete();
|
||||
}
|
||||
|
||||
@Test // DATACASS-250
|
||||
@Test // DATACASS-250, DATACASS-573
|
||||
public void insertShouldCreateEntityWithLwt() {
|
||||
|
||||
InsertOptions lwtOptions = InsertOptions.builder().withIfNotExists().build();
|
||||
|
||||
User user = new User("heisenberg", "Walter", "White");
|
||||
|
||||
Mono<WriteResult> inserted = template.insert(user, lwtOptions);
|
||||
Mono<EntityWriteResult<User>> inserted = template.insert(user, lwtOptions);
|
||||
|
||||
StepVerifier.create(inserted.map(WriteResult::wasApplied)).expectNext(true).verifyComplete();
|
||||
StepVerifier.create(inserted).consumeNextWith(actual -> {
|
||||
|
||||
assertThat(actual.wasApplied()).isTrue();
|
||||
assertThat(actual.getEntity()).isSameAs(user);
|
||||
}).verifyComplete();
|
||||
}
|
||||
|
||||
@Test // DATACASS-250
|
||||
|
||||
@@ -15,18 +15,16 @@
|
||||
*/
|
||||
package org.springframework.data.cassandra.core;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import java.util.Collections;
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.test.StepVerifier;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.cassandra.core.convert.MappingCassandraConverter;
|
||||
import org.springframework.data.cassandra.core.cql.CqlIdentifier;
|
||||
@@ -90,21 +88,26 @@ public class ReactiveInsertOperationSupportIntegrationTests extends AbstractKeys
|
||||
this.template.insert(Person.class).inTable((String) null);
|
||||
}
|
||||
|
||||
@Test // DATACASS-485
|
||||
@Test // DATACASS-485, DATACASS-573
|
||||
public void insertOne() {
|
||||
|
||||
Mono<WriteResult> writeResult = this.template.insert(Person.class).inTable("person").one(han);
|
||||
Mono<EntityWriteResult<Person>> writeResult = this.template.insert(Person.class).inTable("person").one(han);
|
||||
|
||||
StepVerifier.create(writeResult).consumeNextWith(actual -> {
|
||||
|
||||
assertThat(actual.wasApplied()).isTrue();
|
||||
assertThat(actual.getEntity()).isSameAs(han);
|
||||
}).verifyComplete();
|
||||
|
||||
StepVerifier.create(writeResult.map(WriteResult::wasApplied)).expectNext(true).verifyComplete();
|
||||
StepVerifier.create(template.selectOneById(han.id, Person.class)).expectNext(han).verifyComplete();
|
||||
}
|
||||
|
||||
@Test // DATACASS-485
|
||||
@Test // DATACASS-485, DATACASS-573
|
||||
public void insertOneWithOptions() {
|
||||
|
||||
this.template.insert(Person.class).inTable("person").one(han);
|
||||
|
||||
Mono<WriteResult> writeResult = this.template
|
||||
Mono<EntityWriteResult<Person>> writeResult = this.template
|
||||
.insert(Person.class).inTable("person")
|
||||
.withOptions(InsertOptions.builder().withIfNotExists().build())
|
||||
.one(han);
|
||||
|
||||
@@ -211,7 +211,7 @@ public class SimpleCassandraRepositoryIntegrationTests extends AbstractKeyspaceC
|
||||
assertThat(repository.count()).isEqualTo(3);
|
||||
}
|
||||
|
||||
@Test // DATACASS-396
|
||||
@Test // DATACASS-396, DATACASS-573
|
||||
public void saveEntityShouldUpdateExistingEntity() {
|
||||
|
||||
dave.setFirstname("Hello, Dave");
|
||||
@@ -219,7 +219,7 @@ public class SimpleCassandraRepositoryIntegrationTests extends AbstractKeyspaceC
|
||||
|
||||
User saved = repository.save(dave);
|
||||
|
||||
assertThat(saved).isEqualTo(saved);
|
||||
assertThat(saved).isSameAs(saved);
|
||||
|
||||
Optional<User> loaded = repository.findById(dave.getId());
|
||||
|
||||
@@ -257,14 +257,14 @@ public class SimpleCassandraRepositoryIntegrationTests extends AbstractKeyspaceC
|
||||
assertThat(loaded).contains(User);
|
||||
}
|
||||
|
||||
@Test // DATACASS-396, DATACASS-416
|
||||
@Test // DATACASS-396, DATACASS-416, DATACASS-573
|
||||
public void saveIterableOfNewEntitiesShouldInsertEntity() {
|
||||
|
||||
repository.deleteAll();
|
||||
|
||||
List<User> saved = repository.saveAll(Arrays.asList(dave, oliver, boyd));
|
||||
|
||||
assertThat(saved).hasSize(3);
|
||||
assertThat(saved).hasSize(3).contains(dave, oliver, boyd);
|
||||
|
||||
assertThat(repository.count()).isEqualTo(3);
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.cassandra.core.CassandraOperations;
|
||||
import org.springframework.data.cassandra.core.EntityWriteResult;
|
||||
import org.springframework.data.cassandra.core.InsertOptions;
|
||||
import org.springframework.data.cassandra.core.convert.MappingCassandraConverter;
|
||||
import org.springframework.data.cassandra.core.cql.CqlOperations;
|
||||
@@ -63,6 +64,7 @@ public class SimpleCassandraRepositoryUnitTests {
|
||||
@Mock CqlOperations cqlOperations;
|
||||
@Mock UserTypeResolver userTypeResolver;
|
||||
@Mock UserType userType;
|
||||
@Mock EntityWriteResult writeResult;
|
||||
|
||||
@Captor ArgumentCaptor<Insert> insertCaptor;
|
||||
|
||||
@@ -71,7 +73,7 @@ public class SimpleCassandraRepositoryUnitTests {
|
||||
mappingContext.setUserTypeResolver(userTypeResolver);
|
||||
}
|
||||
|
||||
@Test // DATACASS-428, DATACASS-560
|
||||
@Test // DATACASS-428, DATACASS-560, DATACASS-573
|
||||
public void saveShouldInsertNewPrimaryKeyOnlyEntity() {
|
||||
|
||||
CassandraPersistentEntity<?> entity = converter.getMappingContext().getRequiredPersistentEntity(SimplePerson.class);
|
||||
@@ -81,12 +83,15 @@ public class SimpleCassandraRepositoryUnitTests {
|
||||
|
||||
SimplePerson person = new SimplePerson();
|
||||
|
||||
when(cassandraOperations.insert(eq(person), any())).thenReturn(writeResult);
|
||||
when(writeResult.getEntity()).thenReturn(person);
|
||||
|
||||
repository.save(person);
|
||||
|
||||
verify(cassandraOperations).insert(person, InsertOptions.builder().withInsertNulls().build());
|
||||
}
|
||||
|
||||
@Test // DATACASS-428, DATACASS-560
|
||||
@Test // DATACASS-428, DATACASS-560, DATACASS-573
|
||||
public void saveShouldUpdateNewEntity() {
|
||||
|
||||
CassandraPersistentEntity<?> entity = converter.getMappingContext().getRequiredPersistentEntity(Person.class);
|
||||
@@ -96,12 +101,15 @@ public class SimpleCassandraRepositoryUnitTests {
|
||||
|
||||
Person person = new Person();
|
||||
|
||||
when(cassandraOperations.insert(eq(person), any())).thenReturn(writeResult);
|
||||
when(writeResult.getEntity()).thenReturn(person);
|
||||
|
||||
repository.save(person);
|
||||
|
||||
verify(cassandraOperations).insert(person, InsertOptions.builder().withInsertNulls().build());
|
||||
}
|
||||
|
||||
@Test // DATACASS-428, DATACASS-560
|
||||
@Test // DATACASS-428, DATACASS-560, DATACASS-573
|
||||
public void saveShouldUpdateExistingEntity() {
|
||||
|
||||
CassandraPersistentEntity<?> entity = converter.getMappingContext().getRequiredPersistentEntity(Person.class);
|
||||
@@ -113,6 +121,9 @@ public class SimpleCassandraRepositoryUnitTests {
|
||||
person.setFirstname("foo");
|
||||
person.setLastname("bar");
|
||||
|
||||
when(cassandraOperations.insert(eq(person), any())).thenReturn(writeResult);
|
||||
when(writeResult.getEntity()).thenReturn(person);
|
||||
|
||||
repository.save(person);
|
||||
|
||||
verify(cassandraOperations).insert(person, InsertOptions.builder().withInsertNulls().build());
|
||||
|
||||
Reference in New Issue
Block a user