DATACOUCH-645 - Support document expiryExpression. (#296)
Support document expiryExpression and make the initial expiry to be null instead of Zero in the fluent API. This allows a client to 'unset' the expiry from an annotation by explcitly setting withExpiry(Zero). Co-authored-by: mikereiche <michael.reiche@couchbase.com>
This commit is contained in:
@@ -36,7 +36,7 @@ public class ExecutableInsertByIdOperationSupport implements ExecutableInsertByI
|
||||
public <T> ExecutableInsertById<T> insertById(final Class<T> domainType) {
|
||||
Assert.notNull(domainType, "DomainType must not be null!");
|
||||
return new ExecutableInsertByIdSupport<>(template, domainType, null, PersistTo.NONE, ReplicateTo.NONE,
|
||||
DurabilityLevel.NONE, Duration.ofSeconds(0));
|
||||
DurabilityLevel.NONE, null);
|
||||
}
|
||||
|
||||
static class ExecutableInsertByIdSupport<T> implements ExecutableInsertById<T> {
|
||||
|
||||
@@ -36,7 +36,7 @@ public class ExecutableReplaceByIdOperationSupport implements ExecutableReplaceB
|
||||
public <T> ExecutableReplaceById<T> replaceById(final Class<T> domainType) {
|
||||
Assert.notNull(domainType, "DomainType must not be null!");
|
||||
return new ExecutableReplaceByIdSupport<>(template, domainType, null, PersistTo.NONE, ReplicateTo.NONE,
|
||||
DurabilityLevel.NONE, Duration.ZERO);
|
||||
DurabilityLevel.NONE, null);
|
||||
}
|
||||
|
||||
static class ExecutableReplaceByIdSupport<T> implements ExecutableReplaceById<T> {
|
||||
|
||||
@@ -36,7 +36,7 @@ public class ExecutableUpsertByIdOperationSupport implements ExecutableUpsertByI
|
||||
public <T> ExecutableUpsertById<T> upsertById(final Class<T> domainType) {
|
||||
Assert.notNull(domainType, "DomainType must not be null!");
|
||||
return new ExecutableUpsertByIdSupport<>(template, domainType, null, PersistTo.NONE, ReplicateTo.NONE,
|
||||
DurabilityLevel.NONE, Duration.ofSeconds(0));
|
||||
DurabilityLevel.NONE, null);
|
||||
}
|
||||
|
||||
static class ExecutableUpsertByIdSupport<T> implements ExecutableUpsertById<T> {
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
*/
|
||||
package org.springframework.data.couchbase.core;
|
||||
|
||||
import org.springframework.data.couchbase.core.mapping.Document;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
@@ -42,7 +41,7 @@ public class ReactiveInsertByIdOperationSupport implements ReactiveInsertByIdOpe
|
||||
public <T> ReactiveInsertById<T> insertById(final Class<T> domainType) {
|
||||
Assert.notNull(domainType, "DomainType must not be null!");
|
||||
return new ReactiveInsertByIdSupport<>(template, domainType, null, PersistTo.NONE, ReplicateTo.NONE,
|
||||
DurabilityLevel.NONE, Duration.ofSeconds(0));
|
||||
DurabilityLevel.NONE, null);
|
||||
}
|
||||
|
||||
static class ReactiveInsertByIdSupport<T> implements ReactiveInsertById<T> {
|
||||
@@ -72,7 +71,7 @@ public class ReactiveInsertByIdOperationSupport implements ReactiveInsertByIdOpe
|
||||
return Mono.just(object).flatMap(o -> {
|
||||
CouchbaseDocument converted = template.support().encodeEntity(o);
|
||||
return template.getCollection(collection).reactive()
|
||||
.insert(converted.getId(), converted.export(), buildInsertOptions()).map(result -> {
|
||||
.insert(converted.getId(), converted.export(), buildInsertOptions(converted)).map(result -> {
|
||||
Object updatedObject = template.support().applyUpdatedId(o, converted.getId());
|
||||
return (T) template.support().applyUpdatedCas(updatedObject, result.cas());
|
||||
});
|
||||
@@ -90,19 +89,17 @@ public class ReactiveInsertByIdOperationSupport implements ReactiveInsertByIdOpe
|
||||
return Flux.fromIterable(objects).flatMap(this::one);
|
||||
}
|
||||
|
||||
private InsertOptions buildInsertOptions() {
|
||||
private InsertOptions buildInsertOptions(CouchbaseDocument doc) { // CouchbaseDocument converted
|
||||
final InsertOptions options = InsertOptions.insertOptions();
|
||||
if (persistTo != PersistTo.NONE || replicateTo != ReplicateTo.NONE) {
|
||||
options.durability(persistTo, replicateTo);
|
||||
} else if (durabilityLevel != DurabilityLevel.NONE) {
|
||||
options.durability(durabilityLevel);
|
||||
}
|
||||
if (expiry != null && !expiry.isZero()) {
|
||||
if (expiry != null) {
|
||||
options.expiry(expiry);
|
||||
} else if (domainType.isAnnotationPresent(Document.class)) {
|
||||
Document documentAnn = domainType.getAnnotation(Document.class);
|
||||
long durationSeconds = documentAnn.expiryUnit().toSeconds(documentAnn.expiry());
|
||||
options.expiry(Duration.ofSeconds(durationSeconds));
|
||||
} else if (doc.getExpiration() != 0) {
|
||||
options.expiry(Duration.ofSeconds(doc.getExpiration()));
|
||||
}
|
||||
return options;
|
||||
}
|
||||
|
||||
@@ -22,7 +22,6 @@ import java.time.Duration;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.springframework.data.couchbase.core.mapping.CouchbaseDocument;
|
||||
import org.springframework.data.couchbase.core.mapping.Document;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import com.couchbase.client.core.msg.kv.DurabilityLevel;
|
||||
@@ -42,7 +41,7 @@ public class ReactiveReplaceByIdOperationSupport implements ReactiveReplaceByIdO
|
||||
public <T> ReactiveReplaceById<T> replaceById(final Class<T> domainType) {
|
||||
Assert.notNull(domainType, "DomainType must not be null!");
|
||||
return new ReactiveReplaceByIdSupport<>(template, domainType, null, PersistTo.NONE, ReplicateTo.NONE,
|
||||
DurabilityLevel.NONE, Duration.ZERO);
|
||||
DurabilityLevel.NONE, null);
|
||||
}
|
||||
|
||||
static class ReactiveReplaceByIdSupport<T> implements ReactiveReplaceById<T> {
|
||||
@@ -72,8 +71,8 @@ public class ReactiveReplaceByIdOperationSupport implements ReactiveReplaceByIdO
|
||||
return Mono.just(object).flatMap(o -> {
|
||||
CouchbaseDocument converted = template.support().encodeEntity(o);
|
||||
return template.getCollection(collection).reactive()
|
||||
.replace(converted.getId(), converted.export(), buildReplaceOptions(o)).map(result ->
|
||||
(T)template.support().applyUpdatedCas(o, result.cas()));
|
||||
.replace(converted.getId(), converted.export(), buildReplaceOptions(o, converted))
|
||||
.map(result -> (T) template.support().applyUpdatedCas(o, result.cas()));
|
||||
}).onErrorMap(throwable -> {
|
||||
if (throwable instanceof RuntimeException) {
|
||||
return template.potentiallyConvertRuntimeException((RuntimeException) throwable);
|
||||
@@ -88,19 +87,17 @@ public class ReactiveReplaceByIdOperationSupport implements ReactiveReplaceByIdO
|
||||
return Flux.fromIterable(objects).flatMap(this::one);
|
||||
}
|
||||
|
||||
private ReplaceOptions buildReplaceOptions(T object) {
|
||||
private ReplaceOptions buildReplaceOptions(T object, CouchbaseDocument doc) {
|
||||
final ReplaceOptions options = ReplaceOptions.replaceOptions();
|
||||
if (persistTo != PersistTo.NONE || replicateTo != ReplicateTo.NONE) {
|
||||
options.durability(persistTo, replicateTo);
|
||||
} else if (durabilityLevel != DurabilityLevel.NONE) {
|
||||
options.durability(durabilityLevel);
|
||||
}
|
||||
if (expiry != null && !expiry.isZero()) {
|
||||
if (expiry != null) {
|
||||
options.expiry(expiry);
|
||||
} else if (domainType.isAnnotationPresent(Document.class)) {
|
||||
Document documentAnn = domainType.getAnnotation(Document.class);
|
||||
long durationSeconds = documentAnn.expiryUnit().toSeconds(documentAnn.expiry());
|
||||
options.expiry(Duration.ofSeconds(durationSeconds));
|
||||
} else if (doc.getExpiration() != 0) {
|
||||
options.expiry(Duration.ofSeconds(doc.getExpiration()));
|
||||
}
|
||||
long cas = template.support().getCas(object);
|
||||
options.cas(cas);
|
||||
|
||||
@@ -15,9 +15,6 @@
|
||||
*/
|
||||
package org.springframework.data.couchbase.core;
|
||||
|
||||
import org.springframework.data.couchbase.core.mapping.CouchbasePersistentEntity;
|
||||
import org.springframework.data.couchbase.core.mapping.CouchbasePersistentProperty;
|
||||
import org.springframework.data.couchbase.core.mapping.Document;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
@@ -44,7 +41,7 @@ public class ReactiveUpsertByIdOperationSupport implements ReactiveUpsertByIdOpe
|
||||
public <T> ReactiveUpsertById<T> upsertById(final Class<T> domainType) {
|
||||
Assert.notNull(domainType, "DomainType must not be null!");
|
||||
return new ReactiveUpsertByIdSupport<>(template, domainType, null, PersistTo.NONE, ReplicateTo.NONE,
|
||||
DurabilityLevel.NONE, Duration.ofSeconds(0));
|
||||
DurabilityLevel.NONE, null);
|
||||
}
|
||||
|
||||
static class ReactiveUpsertByIdSupport<T> implements ReactiveUpsertById<T> {
|
||||
@@ -74,7 +71,7 @@ public class ReactiveUpsertByIdOperationSupport implements ReactiveUpsertByIdOpe
|
||||
return Mono.just(object).flatMap(o -> {
|
||||
CouchbaseDocument converted = template.support().encodeEntity(o);
|
||||
return template.getCollection(collection).reactive()
|
||||
.upsert(converted.getId(), converted.export(), buildUpsertOptions()).map(result -> {
|
||||
.upsert(converted.getId(), converted.export(), buildUpsertOptions(converted)).map(result -> {
|
||||
Object updatedObject = template.support().applyUpdatedId(o, converted.getId());
|
||||
return (T) template.support().applyUpdatedCas(updatedObject, result.cas());
|
||||
});
|
||||
@@ -92,19 +89,17 @@ public class ReactiveUpsertByIdOperationSupport implements ReactiveUpsertByIdOpe
|
||||
return Flux.fromIterable(objects).flatMap(this::one);
|
||||
}
|
||||
|
||||
private UpsertOptions buildUpsertOptions() {
|
||||
private UpsertOptions buildUpsertOptions(CouchbaseDocument doc) {
|
||||
final UpsertOptions options = UpsertOptions.upsertOptions();
|
||||
if (persistTo != PersistTo.NONE || replicateTo != ReplicateTo.NONE) {
|
||||
options.durability(persistTo, replicateTo);
|
||||
} else if (durabilityLevel != DurabilityLevel.NONE) {
|
||||
options.durability(durabilityLevel);
|
||||
}
|
||||
if (expiry != null && !expiry.isZero()) {
|
||||
if (expiry != null) {
|
||||
options.expiry(expiry);
|
||||
} else if (domainType.isAnnotationPresent(Document.class)) {
|
||||
Document documentAnn = domainType.getAnnotation(Document.class);
|
||||
long durationSeconds = documentAnn.expiryUnit().toSeconds(documentAnn.expiry());
|
||||
options.expiry(Duration.ofSeconds(durationSeconds));
|
||||
} else if (doc.getExpiration() != 0) {
|
||||
options.expiry(Duration.ofSeconds(doc.getExpiration()));
|
||||
}
|
||||
return options;
|
||||
}
|
||||
|
||||
@@ -27,9 +27,14 @@ import static org.springframework.data.couchbase.config.BeanNames.COUCHBASE_TEMP
|
||||
import static org.springframework.data.couchbase.config.BeanNames.REACTIVE_COUCHBASE_TEMPLATE;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.time.Duration;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import com.couchbase.client.java.manager.query.CreatePrimaryQueryIndexOptions;;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
@@ -37,14 +42,18 @@ import org.junit.jupiter.api.Test;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.dao.DataIntegrityViolationException;
|
||||
import org.springframework.dao.DataRetrievalFailureException;
|
||||
import org.springframework.dao.DuplicateKeyException;
|
||||
import org.springframework.data.couchbase.CouchbaseClientFactory;
|
||||
import org.springframework.data.couchbase.SimpleCouchbaseClientFactory;
|
||||
import org.springframework.data.couchbase.core.ExecutableReplaceByIdOperation.ExecutableReplaceById;
|
||||
import org.springframework.data.couchbase.core.ExecutableRemoveByIdOperation.ExecutableRemoveById;
|
||||
|
||||
import org.springframework.data.couchbase.domain.Config;
|
||||
import org.springframework.data.couchbase.domain.PersonValue;
|
||||
import org.springframework.data.couchbase.domain.User;
|
||||
import org.springframework.data.couchbase.domain.UserAnnotated;
|
||||
import org.springframework.data.couchbase.domain.UserAnnotated2;
|
||||
import org.springframework.data.couchbase.domain.UserAnnotated3;
|
||||
import org.springframework.data.couchbase.util.ClusterAwareIntegrationTests;
|
||||
import org.springframework.data.couchbase.util.ClusterType;
|
||||
import org.springframework.data.couchbase.util.IgnoreWhen;
|
||||
@@ -69,6 +78,8 @@ class CouchbaseTemplateKeyValueIntegrationTests extends ClusterAwareIntegrationT
|
||||
static void beforeAll() {
|
||||
couchbaseClientFactory = new SimpleCouchbaseClientFactory(connectionString(), authenticator(), bucketName());
|
||||
couchbaseClientFactory.getBucket().waitUntilReady(Duration.ofSeconds(10));
|
||||
couchbaseClientFactory.getCluster().queryIndexes().createPrimaryIndex(bucketName(),
|
||||
CreatePrimaryQueryIndexOptions.createPrimaryQueryIndexOptions().ignoreIfExists(true));
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
@@ -81,6 +92,9 @@ class CouchbaseTemplateKeyValueIntegrationTests extends ClusterAwareIntegrationT
|
||||
ApplicationContext ac = new AnnotationConfigApplicationContext(Config.class);
|
||||
couchbaseTemplate = (CouchbaseTemplate) ac.getBean(COUCHBASE_TEMPLATE);
|
||||
reactiveCouchbaseTemplate = (ReactiveCouchbaseTemplate) ac.getBean(REACTIVE_COUCHBASE_TEMPLATE);
|
||||
couchbaseTemplate.removeByQuery(User.class).all();
|
||||
couchbaseTemplate.removeByQuery(UserAnnotated.class).all();
|
||||
couchbaseTemplate.removeByQuery(UserAnnotated2.class).all();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -103,88 +117,84 @@ class CouchbaseTemplateKeyValueIntegrationTests extends ClusterAwareIntegrationT
|
||||
}
|
||||
|
||||
@Test
|
||||
void upsertWithDurability() {
|
||||
User user = new User(UUID.randomUUID().toString(), "firstname", "lastname");
|
||||
User modified = couchbaseTemplate.upsertById(User.class).withDurability(PersistTo.ACTIVE, ReplicateTo.NONE)
|
||||
.one(user);
|
||||
assertEquals(user, modified);
|
||||
User found = couchbaseTemplate.findById(User.class).one(user.getId());
|
||||
assertEquals(user, found);
|
||||
couchbaseTemplate.removeById().one(user.getId());
|
||||
}
|
||||
void withDurability()
|
||||
throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
|
||||
Class clazz = User.class; // for now, just User.class. There is no Durability annotation.
|
||||
// insert, replace, upsert
|
||||
for (OneAndAll<User> operator : new OneAndAll[] { couchbaseTemplate.insertById(clazz),
|
||||
couchbaseTemplate.replaceById(clazz), couchbaseTemplate.upsertById(clazz) }) {
|
||||
// create an entity of type clazz
|
||||
Constructor cons = clazz.getConstructor(String.class, String.class, String.class);
|
||||
User user = (User) cons.newInstance("" + operator.getClass().getSimpleName() + "_" + clazz.getSimpleName(),
|
||||
"firstname", "lastname");
|
||||
|
||||
@Test
|
||||
void upsertWithExpiry() {
|
||||
User user = new User(UUID.randomUUID().toString(), "firstname", "lastname");
|
||||
try {
|
||||
User modified = couchbaseTemplate.upsertById(User.class).withExpiry(Duration.ofSeconds(1)).one(user);
|
||||
assertEquals(user, modified);
|
||||
sleepSecs(2);
|
||||
if (clazz.equals(User.class)) { // User.java doesn't have an durability annotation
|
||||
operator = (OneAndAll) ((WithDurability<User>) operator).withDurability(PersistTo.ACTIVE, ReplicateTo.NONE);
|
||||
}
|
||||
|
||||
// if replace, we need to insert a document to replace
|
||||
if (operator instanceof ExecutableReplaceById) {
|
||||
couchbaseTemplate.insertById(User.class).one(user);
|
||||
}
|
||||
// call to insert/replace/update
|
||||
User returned = (User) operator.one(user);
|
||||
assertEquals(user, returned);
|
||||
User found = couchbaseTemplate.findById(User.class).one(user.getId());
|
||||
assertNull(found, "found should have been null as document should be expired");
|
||||
} finally {
|
||||
try {
|
||||
couchbaseTemplate.removeById().one(user.getId());
|
||||
} catch (DataRetrievalFailureException e) {
|
||||
//
|
||||
assertEquals(user, found);
|
||||
|
||||
if (operator instanceof ExecutableReplaceById) {
|
||||
couchbaseTemplate.removeById().withDurability(PersistTo.ACTIVE, ReplicateTo.NONE).one(user.getId());
|
||||
User removed = (User) couchbaseTemplate.findById(user.getClass()).one(user.getId());
|
||||
assertNull(removed, "found should have been null as document should be removed");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void upsertWithExpiryAnnotation() {
|
||||
UserAnnotated user = new UserAnnotated(UUID.randomUUID().toString(), "firstname", "lastname");
|
||||
try {
|
||||
UserAnnotated modified = couchbaseTemplate.upsertById(UserAnnotated.class).one(user);
|
||||
assertEquals(user, modified);
|
||||
sleepSecs(6);
|
||||
User found = couchbaseTemplate.findById(User.class).one(user.getId());
|
||||
assertNull(found, "found should have been null as document should be expired");
|
||||
} finally {
|
||||
try {
|
||||
couchbaseTemplate.removeById().one(user.getId());
|
||||
} catch (DataRetrievalFailureException e) {
|
||||
//
|
||||
}
|
||||
}
|
||||
}
|
||||
void withExpiryAndExpiryAnnotation()
|
||||
throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
|
||||
// ( withExpiry()<User>, expiry=1<UserAnnotated>, expiryExpression=${myExpiry}<UserAnnotated2> ) X ( insert,
|
||||
// replace, upsert )
|
||||
Set<User> users = new HashSet<>(); // set of all documents we will insert
|
||||
// Entity classes
|
||||
for (Class clazz : new Class[] { User.class, UserAnnotated.class, UserAnnotated2.class, UserAnnotated3.class }) {
|
||||
// insert, replace, upsert
|
||||
for (OneAndAll<User> operator : new OneAndAll[] { couchbaseTemplate.insertById(clazz),
|
||||
couchbaseTemplate.replaceById(clazz), couchbaseTemplate.upsertById(clazz) }) {
|
||||
|
||||
@Test
|
||||
void replaceWithExpiry() {
|
||||
User user = new User(UUID.randomUUID().toString(), "firstname", "lastname");
|
||||
try {
|
||||
User modified = couchbaseTemplate.upsertById(User.class).withExpiry(Duration.ofSeconds(1)).one(user);
|
||||
couchbaseTemplate.replaceById(User.class).withExpiry(Duration.ofSeconds(1)).one(user);
|
||||
assertEquals(user, modified);
|
||||
sleepSecs(2);
|
||||
User found = couchbaseTemplate.findById(User.class).one(user.getId());
|
||||
assertNull(found, "found should have been null as document should be expired");
|
||||
} finally {
|
||||
try {
|
||||
couchbaseTemplate.removeById().one(user.getId());
|
||||
} catch (DataRetrievalFailureException e) {
|
||||
//
|
||||
}
|
||||
}
|
||||
}
|
||||
// create an entity of type clazz
|
||||
Constructor cons = clazz.getConstructor(String.class, String.class, String.class);
|
||||
User user = (User) cons.newInstance("" + operator.getClass().getSimpleName() + "_" + clazz.getSimpleName(),
|
||||
"firstname", "lastname");
|
||||
|
||||
@Test
|
||||
void replaceWithExpiryAnnotation() {
|
||||
UserAnnotated user = new UserAnnotated(UUID.randomUUID().toString(), "firstname", "lastname");
|
||||
try {
|
||||
UserAnnotated modified = couchbaseTemplate.upsertById(UserAnnotated.class).one(user);
|
||||
modified = couchbaseTemplate.replaceById(UserAnnotated.class).one(user);
|
||||
assertEquals(user, modified);
|
||||
sleepSecs(6);
|
||||
User found = couchbaseTemplate.findById(UserAnnotated.class).one(user.getId());
|
||||
assertNull(found, "found should have been null as document should be expired");
|
||||
} finally {
|
||||
try {
|
||||
couchbaseTemplate.removeById().one(user.getId());
|
||||
} catch (DataRetrievalFailureException e) {
|
||||
//
|
||||
if (clazz.equals(User.class)) { // User.java doesn't have an expiry annotation
|
||||
operator = (OneAndAll) ((WithExpiry<User>) operator).withExpiry(Duration.ofSeconds(1));
|
||||
} else if (clazz.equals(UserAnnotated3.class)) { // override the expiry from the annotation with no expiry
|
||||
operator = (OneAndAll) ((WithExpiry<User>) operator).withExpiry(Duration.ofSeconds(0));
|
||||
}
|
||||
|
||||
// if replace or remove, we need to insert a document to replace
|
||||
if (operator instanceof ExecutableReplaceById || operator instanceof ExecutableRemoveById) {
|
||||
couchbaseTemplate.insertById(User.class).one(user);
|
||||
}
|
||||
// call to insert/replace/update
|
||||
User returned = operator.one(user);
|
||||
assertEquals(user, returned);
|
||||
users.add(user);
|
||||
}
|
||||
}
|
||||
// check that they are gone after a few seconds.
|
||||
sleepSecs(4);
|
||||
for (User user : users) {
|
||||
User found = couchbaseTemplate.findById(user.getClass()).one(user.getId());
|
||||
if (found instanceof UserAnnotated3) {
|
||||
assertNotNull(found, "found should be non null as it was set to have no expirty");
|
||||
} else {
|
||||
assertNull(found, "found should have been null as document should be expired");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -227,10 +237,7 @@ class CouchbaseTemplateKeyValueIntegrationTests extends ClusterAwareIntegrationT
|
||||
User user = new User(UUID.randomUUID().toString(), "firstname", "lastname");
|
||||
User inserted = couchbaseTemplate.insertById(User.class).one(user);
|
||||
assertEquals(user, inserted);
|
||||
|
||||
assertThrows(DuplicateKeyException.class, () -> couchbaseTemplate.insertById(User.class).one(user));
|
||||
couchbaseTemplate.removeById().one(user.getId());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -239,47 +246,7 @@ class CouchbaseTemplateKeyValueIntegrationTests extends ClusterAwareIntegrationT
|
||||
User inserted = couchbaseTemplate.insertById(User.class).withDurability(PersistTo.ACTIVE, ReplicateTo.NONE)
|
||||
.one(user);
|
||||
assertEquals(user, inserted);
|
||||
|
||||
assertThrows(DuplicateKeyException.class, () -> couchbaseTemplate.insertById(User.class).one(user));
|
||||
couchbaseTemplate.removeById().one(user.getId());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void insertByIdwithExpiry() {
|
||||
User user = new User(UUID.randomUUID().toString(), "firstname", "lastname");
|
||||
try {
|
||||
User inserted = couchbaseTemplate.insertById(User.class).withExpiry(Duration.ofSeconds(1)).one(user);
|
||||
assertEquals(user, inserted);
|
||||
sleepSecs(2);
|
||||
User found = couchbaseTemplate.findById(User.class).one(user.getId());
|
||||
assertNull(found, "found should have been null as document should be expired");
|
||||
} finally {
|
||||
try {
|
||||
couchbaseTemplate.removeById().one(user.getId());
|
||||
} catch (DataRetrievalFailureException e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void insertWithExpiryAnnotation() {
|
||||
UserAnnotated user = new UserAnnotated(UUID.randomUUID().toString(), "firstname", "lastname");
|
||||
try {
|
||||
UserAnnotated inserted = couchbaseTemplate.insertById(UserAnnotated.class).one(user);
|
||||
assertEquals(user, inserted);
|
||||
sleepSecs(6);
|
||||
User found = couchbaseTemplate.findById(User.class).one(user.getId());
|
||||
assertNull(found, "found should have been null as document should be expired");
|
||||
} finally {
|
||||
try {
|
||||
couchbaseTemplate.removeById().one(user.getId());
|
||||
} catch (DataRetrievalFailureException e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -292,52 +259,44 @@ class CouchbaseTemplateKeyValueIntegrationTests extends ClusterAwareIntegrationT
|
||||
assertEquals(user, inserted);
|
||||
|
||||
assertTrue(couchbaseTemplate.existsById().one(id));
|
||||
couchbaseTemplate.removeById().one(user.getId());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
@IgnoreWhen(clusterTypes = ClusterType.MOCKED)
|
||||
void saveAndFindImmutableById() {
|
||||
PersonValue personValue = new PersonValue(null, 123, "f", "l");
|
||||
System.out.println("personValue: " + personValue);
|
||||
// personValue = personValue.withVersion(123);
|
||||
PersonValue personValue = new PersonValue(UUID.randomUUID().toString(), 123, "f", "l");
|
||||
PersonValue inserted = null;
|
||||
PersonValue upserted = null;
|
||||
PersonValue replaced = null;
|
||||
|
||||
try {
|
||||
inserted = couchbaseTemplate.insertById(PersonValue.class).one(personValue);
|
||||
assertNotEquals(0, inserted.getVersion());
|
||||
PersonValue foundInserted = couchbaseTemplate.findById(PersonValue.class).one(inserted.getId());
|
||||
assertNotNull(foundInserted, "inserted personValue not found");
|
||||
assertEquals(inserted, foundInserted);
|
||||
|
||||
inserted = couchbaseTemplate.insertById(PersonValue.class).one(personValue);
|
||||
assertNotEquals(0, inserted.getVersion());
|
||||
PersonValue foundInserted = couchbaseTemplate.findById(PersonValue.class).one(inserted.getId());
|
||||
assertNotNull(foundInserted, "inserted personValue not found");
|
||||
assertEquals(inserted, foundInserted);
|
||||
// upsert will insert
|
||||
couchbaseTemplate.removeById().one(inserted.getId());
|
||||
upserted = couchbaseTemplate.upsertById(PersonValue.class).one(inserted);
|
||||
assertNotEquals(0, upserted.getVersion());
|
||||
PersonValue foundUpserted = couchbaseTemplate.findById(PersonValue.class).one(upserted.getId());
|
||||
assertNotNull(foundUpserted, "upserted personValue not found");
|
||||
assertEquals(upserted, foundUpserted);
|
||||
|
||||
// upsert will be inserted
|
||||
couchbaseTemplate.removeById().one(inserted.getId());
|
||||
upserted = couchbaseTemplate.upsertById(PersonValue.class).one(inserted);
|
||||
assertNotEquals(0, upserted.getVersion());
|
||||
PersonValue foundUpserted = couchbaseTemplate.findById(PersonValue.class).one(upserted.getId());
|
||||
assertNotNull(foundUpserted, "upserted personValue not found");
|
||||
assertEquals(upserted, foundUpserted);
|
||||
// upsert will replace
|
||||
upserted = couchbaseTemplate.upsertById(PersonValue.class).one(inserted);
|
||||
assertNotEquals(0, upserted.getVersion());
|
||||
PersonValue foundUpserted2 = couchbaseTemplate.findById(PersonValue.class).one(upserted.getId());
|
||||
assertNotNull(foundUpserted2, "upserted personValue not found");
|
||||
assertEquals(upserted, foundUpserted2);
|
||||
|
||||
// upsert will be replaced
|
||||
upserted = couchbaseTemplate.upsertById(PersonValue.class).one(inserted);
|
||||
assertNotEquals(0, upserted.getVersion());
|
||||
PersonValue foundUpserted2 = couchbaseTemplate.findById(PersonValue.class).one(upserted.getId());
|
||||
assertNotNull(foundUpserted2, "upserted personValue not found");
|
||||
assertEquals(upserted, foundUpserted2);
|
||||
replaced = couchbaseTemplate.replaceById(PersonValue.class).one(upserted);
|
||||
assertNotEquals(0, replaced.getVersion());
|
||||
PersonValue foundReplaced = couchbaseTemplate.findById(PersonValue.class).one(replaced.getId());
|
||||
assertNotNull(foundReplaced, "replaced personValue not found");
|
||||
assertEquals(replaced, foundReplaced);
|
||||
|
||||
replaced = couchbaseTemplate.replaceById(PersonValue.class).one(upserted);
|
||||
assertNotEquals(0, replaced.getVersion());
|
||||
PersonValue foundReplaced = couchbaseTemplate.findById(PersonValue.class).one(replaced.getId());
|
||||
assertNotNull(foundReplaced, "replaced personValue not found");
|
||||
assertEquals(replaced, foundReplaced);
|
||||
|
||||
} finally {
|
||||
couchbaseTemplate.removeById().one(inserted.getId());
|
||||
}
|
||||
}
|
||||
|
||||
private void sleepSecs(int i) {
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 2020 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
|
||||
*
|
||||
* https://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.couchbase.domain;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.springframework.data.couchbase.core.mapping.Document;
|
||||
|
||||
/**
|
||||
* Annotated User entity for tests
|
||||
*
|
||||
* @author Michael Reiche
|
||||
*/
|
||||
|
||||
@Document(expiry=1, expiryUnit = TimeUnit.SECONDS)
|
||||
public class UserAnnotated3 extends User {
|
||||
|
||||
public UserAnnotated3(String id, String firstname, String lastname) {
|
||||
super(id, firstname, lastname);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user