diff --git a/src/main/java/org/springframework/data/couchbase/core/RxJavaCouchbaseTemplate.java b/src/main/java/org/springframework/data/couchbase/core/RxJavaCouchbaseTemplate.java index 2d68c21f..3e1bcfc0 100644 --- a/src/main/java/org/springframework/data/couchbase/core/RxJavaCouchbaseTemplate.java +++ b/src/main/java/org/springframework/data/couchbase/core/RxJavaCouchbaseTemplate.java @@ -228,9 +228,20 @@ public class RxJavaCouchbaseTemplate implements RxJavaCouchbaseOperations { break; } return persistFunction.call(toJsonDocument(objectToPersist), persistTo, replicateTo) - .flatMap(storedDoc -> Observable.just(storedDoc != null && storedDoc.cas() != 0 - ? setVersion(objectToPersist, storedDoc.cas()) - : objectToPersist)) + .flatMap(storedDoc -> { + if (storedDoc != null) { + if (storedDoc.cas() != 0) { + setVersion(objectToPersist, storedDoc.cas()); + } + // Only set the id if the objectToPersist doesn't have it. That only + // happens when you have generated ids, and you are first persisting the + // document. + if (storedDoc.id() != null && getId(objectToPersist) == null) { + setId(objectToPersist, storedDoc.id()); + } + } + return Observable.just(objectToPersist); + }) .onErrorResumeNext(e -> { if (e instanceof DocumentAlreadyExistsException) { throw new OptimisticLockingFailureException(persistType.springDataOperationName + @@ -256,6 +267,10 @@ public class RxJavaCouchbaseTemplate implements RxJavaCouchbaseOperations { return mappingContext.getRequiredPersistentEntity(object.getClass()).getVersionProperty(); } + private CouchbasePersistentProperty idProperty(T object) { + return mappingContext.getRequiredPersistentEntity(object.getClass()).getIdProperty(); + } + private Long getVersion(T object) { CouchbasePersistentProperty versionProperty = versionProperty(object); @@ -278,6 +293,24 @@ public class RxJavaCouchbaseTemplate implements RxJavaCouchbaseOperations { return accessor.getBean(); } + private String getId(T object) { + CouchbasePersistentProperty idProperty = idProperty(object); + return idProperty == null + ? null // + : getPropertyAccessor(object).getProperty(idProperty, String.class); + } + + private T setId(T object, String id) { + + CouchbasePersistentProperty idProperty = idProperty(object); + if (idProperty == null) { + return object; + } + final ConvertingPropertyAccessor accessor = getPropertyAccessor(object); + accessor.setProperty(idProperty, id); + return accessor.getBean(); + } + private Observable doRemove(T objectToRemove, final PersistTo persistTo, final ReplicateTo replicateTo) { if(objectToRemove instanceof String) { return client.remove((String) objectToRemove, persistTo, replicateTo) diff --git a/src/test/java/org/springframework/data/couchbase/repository/ReactivePlace.java b/src/test/java/org/springframework/data/couchbase/repository/ReactivePlace.java new file mode 100644 index 00000000..54705217 --- /dev/null +++ b/src/test/java/org/springframework/data/couchbase/repository/ReactivePlace.java @@ -0,0 +1,38 @@ +package org.springframework.data.couchbase.repository; + +import com.couchbase.client.java.repository.annotation.Field; +import com.couchbase.client.java.repository.annotation.Id; +import org.springframework.data.couchbase.core.mapping.id.GeneratedValue; +import org.springframework.data.couchbase.core.mapping.id.GenerationStrategy; + +/** + * @author David Kelly + */ +public class ReactivePlace { + @Id + @GeneratedValue(strategy= GenerationStrategy.UNIQUE) + public String id; + + @Field("name") + public String name; + + public String getId() { + return id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public void setId(String id) { + this.id = id; + } + + public ReactivePlace(String name) { + this.name = name; + } +} diff --git a/src/test/java/org/springframework/data/couchbase/repository/ReactivePlaceRepository.java b/src/test/java/org/springframework/data/couchbase/repository/ReactivePlaceRepository.java new file mode 100644 index 00000000..08bd0ffa --- /dev/null +++ b/src/test/java/org/springframework/data/couchbase/repository/ReactivePlaceRepository.java @@ -0,0 +1,20 @@ +package org.springframework.data.couchbase.repository; + +import org.springframework.data.couchbase.core.query.N1qlPrimaryIndexed; +import org.springframework.data.couchbase.core.query.Query; +import org.springframework.data.couchbase.core.query.ViewIndexed; +import reactor.core.publisher.Flux; + +import java.util.List; + +/** + * @author David Kelly + */ +@N1qlPrimaryIndexed +public interface ReactivePlaceRepository extends ReactiveCouchbaseRepository { + + @Query("#{#n1ql.selectEntity} WHERE name = $1") + Flux findByName(String name); + +} + diff --git a/src/test/java/org/springframework/data/couchbase/repository/ReactivePlaceTests.java b/src/test/java/org/springframework/data/couchbase/repository/ReactivePlaceTests.java new file mode 100644 index 00000000..77cdd7b5 --- /dev/null +++ b/src/test/java/org/springframework/data/couchbase/repository/ReactivePlaceTests.java @@ -0,0 +1,57 @@ +package org.springframework.data.couchbase.repository; + +import com.couchbase.client.java.Bucket; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TestName; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.couchbase.ContainerResourceRunner; +import org.springframework.data.couchbase.ReactiveIntegrationTestApplicationConfig; +import org.springframework.data.couchbase.repository.config.ReactiveRepositoryOperationsMapping; +import org.springframework.data.couchbase.repository.support.IndexManager; +import org.springframework.data.couchbase.repository.support.ReactiveCouchbaseRepositoryFactory; +import org.springframework.data.repository.core.support.ReactiveRepositoryFactorySupport; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.TestExecutionListeners; + +import static junit.framework.TestCase.assertNull; +import static org.junit.Assert.assertNotNull; +import static org.springframework.data.couchbase.CouchbaseTestHelper.getRepositoryWithRetry; + +/** + * @author David Kelly + */ +@RunWith(ContainerResourceRunner.class) +@ContextConfiguration(classes = ReactiveIntegrationTestApplicationConfig.class) +@TestExecutionListeners(SimpleReactiveCouchbaseRepositoryListener.class) +public class ReactivePlaceTests { + @Rule + public TestName testName = new TestName(); + + @Autowired + private Bucket client; + + @Autowired + private ReactiveRepositoryOperationsMapping operationsMapping; + + @Autowired + private IndexManager indexManager; + + private ReactivePlaceRepository repository; + + @Before + public void setup() throws Exception { + ReactiveRepositoryFactorySupport factory = new ReactiveCouchbaseRepositoryFactory(operationsMapping, indexManager); + repository = getRepositoryWithRetry(factory, ReactivePlaceRepository.class); + } + + @Test + public void shouldReturnGeneratedId() { + ReactivePlace place = new ReactivePlace("somePlace"); + assertNull(place.getId()); + ReactivePlace returned = repository.save(place).block(); + assertNotNull(returned.getId()); + } +}