Added Sub-Document mutations support (#1660)

Closes #1659
This commit is contained in:
Tigran Babloyan
2023-02-03 23:26:59 +04:00
committed by GitHub
parent 4fa6eb43d2
commit 020693e995
16 changed files with 2168 additions and 18 deletions

View File

@@ -27,20 +27,16 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.time.Duration;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import java.util.*;
import com.couchbase.client.core.error.TimeoutException;
import com.couchbase.client.core.msg.kv.DurabilityLevel;
import com.couchbase.client.core.retry.RetryReason;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.dao.InvalidDataAccessResourceUsageException;
import org.springframework.dao.OptimisticLockingFailureException;
import org.springframework.data.couchbase.core.ExecutableFindByIdOperation.ExecutableFindById;
import org.springframework.data.couchbase.core.ExecutableRemoveByIdOperation.ExecutableRemoveById;
@@ -460,6 +456,583 @@ class CouchbaseTemplateKeyValueIntegrationTests extends JavaIntegrationTests {
.one(modified.getId());
}
}
@Test
void mutateInByIdUpsert(){
try {
MutableUser user = new MutableUser(UUID.randomUUID().toString(), "firstname", "lastname");
user = couchbaseTemplate.insertById(MutableUser.class).one(user);
MutableUser mutableUser = new MutableUser(user.getId(), "", "");
mutableUser.setRoles(Collections.singletonList("ADMIN"));
couchbaseTemplate.mutateInById(MutableUser.class).withUpsertPaths("roles").one(mutableUser);
user = couchbaseTemplate.findById(MutableUser.class).one(user.getId());
assertEquals(user.getRoles(), mutableUser.getRoles());
} finally {
couchbaseTemplate.removeByQuery(MutableUser.class).withConsistency(QueryScanConsistency.REQUEST_PLUS).all();
}
}
@Test
void mutateInByIdUpsertWithCAS(){
try {
MutableUser user = new MutableUser(UUID.randomUUID().toString(), "firstname", "lastname");
user = couchbaseTemplate.insertById(MutableUser.class).one(user);
MutableUser mutableUser = new MutableUser(user.getId(), "", "");
mutableUser.setRoles(Collections.singletonList("ADMIN"));
mutableUser.setVersion(999);
// if case is incorrect then exception is thrown
assertThrows(OptimisticLockingFailureException.class, ()-> couchbaseTemplate.mutateInById(MutableUser.class)
.withCasProvided().withUpsertPaths("roles").one(mutableUser));
// success on correct cas
mutableUser.setVersion(user.getVersion());
couchbaseTemplate.mutateInById(MutableUser.class)
.withCasProvided().withUpsertPaths("roles").one(mutableUser);
user = couchbaseTemplate.findById(MutableUser.class).one(user.getId());
assertEquals(mutableUser.getRoles(), user.getRoles());
} finally {
couchbaseTemplate.removeByQuery(MutableUser.class).withConsistency(QueryScanConsistency.REQUEST_PLUS).all();
}
}
@Test
void mutateInByIdUpsertMultiple() {
try {
MutableUser user = new MutableUser(UUID.randomUUID().toString(), "firstname", "lastname");
user = couchbaseTemplate.insertById(MutableUser.class).one(user);
MutableUser mutableUser = new MutableUser(user.getId(), "", "");
mutableUser.setRoles(Collections.singletonList("ADMIN"));
Address address = new Address();
address.setCity("city");
address.setStreet("street");
mutableUser.setAddress(address);
couchbaseTemplate.mutateInById(MutableUser.class).withUpsertPaths("roles", "address.street").one(mutableUser);
user = couchbaseTemplate.findById(MutableUser.class).one(user.getId());
assertEquals(user.getRoles(), mutableUser.getRoles());
assertEquals(user.getAddress().getStreet(), mutableUser.getAddress().getStreet());
assertNull(user.getAddress().getCity());
} finally {
couchbaseTemplate.removeByQuery(MutableUser.class).withConsistency(QueryScanConsistency.REQUEST_PLUS).all();
}
}
@Test
void mutateInByIdUpsertMultipleWithDurability(){
try {
MutableUser user = new MutableUser(UUID.randomUUID().toString(), "firstname", "lastname");
user = couchbaseTemplate.insertById(MutableUser.class).one(user);
MutableUser mutableUser = new MutableUser(user.getId(), "", "");
mutableUser.setRoles(Collections.singletonList("ADMIN"));
Address address = new Address();
address.setCity("city");
address.setStreet("street");
mutableUser.setAddress(address);
couchbaseTemplate.mutateInById(MutableUser.class).withDurability(DurabilityLevel.MAJORITY).withUpsertPaths("roles", "address.street").one(mutableUser);
user = couchbaseTemplate.findById(MutableUser.class).one(user.getId());
assertEquals(user.getRoles(), mutableUser.getRoles());
assertEquals(user.getAddress().getStreet(), mutableUser.getAddress().getStreet());
assertNull(user.getAddress().getCity());
} finally {
couchbaseTemplate.removeByQuery(MutableUser.class).withConsistency(QueryScanConsistency.REQUEST_PLUS).all();
}
}
@Test
void mutateInByIdUpsertMultipleWithExpiry(){
try {
MutableUser user = new MutableUser(UUID.randomUUID().toString(), "firstname", "lastname");
user = couchbaseTemplate.insertById(MutableUser.class).one(user);
MutableUser mutableUser = new MutableUser(user.getId(), "", "");
mutableUser.setRoles(Collections.singletonList("ADMIN"));
Address address = new Address();
address.setCity("city");
address.setStreet("street");
mutableUser.setAddress(address);
couchbaseTemplate.mutateInById(MutableUser.class).withExpiry(Duration.ofSeconds(1)).withUpsertPaths("roles", "address.street").one(mutableUser);
user = couchbaseTemplate.findById(MutableUser.class).one(user.getId());
assertEquals(user.getRoles(), mutableUser.getRoles());
assertEquals(user.getAddress().getStreet(), mutableUser.getAddress().getStreet());
assertNull(user.getAddress().getCity());
// user should be gone
int tries = 0;
MutableUser foundUser;
do {
sleepSecs(2);
foundUser = couchbaseTemplate.findById(MutableUser.class).one(user.getId());
} while (tries++ < 5 && foundUser != null);
assertNull(foundUser);
} finally {
couchbaseTemplate.removeByQuery(MutableUser.class).withConsistency(QueryScanConsistency.REQUEST_PLUS).all();
}
}
@Test
void mutateInByIdReplace(){
try {
MutableUser user = new MutableUser(UUID.randomUUID().toString(), "firstname", "lastname");
user = couchbaseTemplate.insertById(MutableUser.class).one(user);
MutableUser mutableUser = new MutableUser(user.getId(), "othername", "");
couchbaseTemplate.mutateInById(MutableUser.class).withReplacePaths("firstname").one(mutableUser);
user = couchbaseTemplate.findById(MutableUser.class).one(user.getId());
assertEquals(mutableUser.getFirstname(), user.getFirstname());
} finally {
couchbaseTemplate.removeByQuery(MutableUser.class).withConsistency(QueryScanConsistency.REQUEST_PLUS).all();
}
}
@Test
void mutateInByIdReplaceWithCAS(){
try {
MutableUser user = new MutableUser(UUID.randomUUID().toString(), "firstname", "lastname");
user = couchbaseTemplate.insertById(MutableUser.class).one(user);
MutableUser mutableUser = new MutableUser(user.getId(), "othername", "");
mutableUser.setVersion(999);
// if case is incorrect then exception is thrown
assertThrows(OptimisticLockingFailureException.class, ()-> couchbaseTemplate.mutateInById(MutableUser.class).withCasProvided()
.withReplacePaths("firstname").one(mutableUser));
// success on correct cas
mutableUser.setVersion(user.getVersion());
couchbaseTemplate.mutateInById(MutableUser.class).withCasProvided().withReplacePaths("firstname").one(mutableUser);
user = couchbaseTemplate.findById(MutableUser.class).one(user.getId());
assertEquals(mutableUser.getFirstname(), user.getFirstname());
} finally {
couchbaseTemplate.removeByQuery(MutableUser.class).withConsistency(QueryScanConsistency.REQUEST_PLUS).all();
}
}
@Test
void mutateInByIdReplaceMultiple() {
try {
MutableUser user = new MutableUser(UUID.randomUUID().toString(), "firstname", "lastname");
Address address = new Address();
address.setCity("city");
address.setStreet("street");
user.setAddress(address);
user = couchbaseTemplate.insertById(MutableUser.class).one(user);
MutableUser mutableUser = new MutableUser(user.getId(), "othername", "");
mutableUser.setRoles(Collections.singletonList("ADMIN"));
Address mutableAddress = new Address();
mutableAddress.setCity("othercity");
mutableUser.setAddress(mutableAddress);
couchbaseTemplate.mutateInById(MutableUser.class).withReplacePaths("firstname", "address.city").one(mutableUser);
user = couchbaseTemplate.findById(MutableUser.class).one(user.getId());
assertEquals(mutableUser.getFirstname(), user.getFirstname());
assertEquals(user.getAddress().getCity(), mutableUser.getAddress().getCity());
} finally {
couchbaseTemplate.removeByQuery(MutableUser.class).withConsistency(QueryScanConsistency.REQUEST_PLUS).all();
}
}
@Test
void mutateInByIdReplaceMultipleWithDurability(){
try {
MutableUser user = new MutableUser(UUID.randomUUID().toString(), "firstname", "lastname");
Address address = new Address();
address.setCity("city");
address.setStreet("street");
user.setAddress(address);
user = couchbaseTemplate.insertById(MutableUser.class).one(user);
MutableUser mutableUser = new MutableUser(user.getId(), "othername", "");
mutableUser.setRoles(Collections.singletonList("ADMIN"));
Address mutableAddress = new Address();
mutableAddress.setCity("othercity");
mutableUser.setAddress(mutableAddress);
couchbaseTemplate.mutateInById(MutableUser.class).withDurability(DurabilityLevel.MAJORITY).withReplacePaths("firstname", "address.city").one(mutableUser);
user = couchbaseTemplate.findById(MutableUser.class).one(user.getId());
assertEquals(mutableUser.getFirstname(), user.getFirstname());
assertEquals(user.getAddress().getCity(), mutableUser.getAddress().getCity());
} finally {
couchbaseTemplate.removeByQuery(MutableUser.class).withConsistency(QueryScanConsistency.REQUEST_PLUS).all();
}
}
@Test
void mutateInByIdReplaceMultipleWithExpiry(){
try {
MutableUser user = new MutableUser(UUID.randomUUID().toString(), "firstname", "lastname");
Address address = new Address();
address.setCity("city");
user.setAddress(address);
user = couchbaseTemplate.insertById(MutableUser.class).one(user);
MutableUser mutableUser = new MutableUser(user.getId(), "othername", "");
mutableUser.setRoles(Collections.singletonList("ADMIN"));
Address mutableAddress = new Address();
mutableAddress.setCity("othercity");
mutableAddress.setStreet("street");
mutableUser.setAddress(mutableAddress);
couchbaseTemplate.mutateInById(MutableUser.class).withExpiry(Duration.ofSeconds(1)).withReplacePaths("firstname", "address.city").one(mutableUser);
user = couchbaseTemplate.findById(MutableUser.class).one(user.getId());
assertEquals(mutableUser.getFirstname(), user.getFirstname());
assertEquals(user.getAddress().getCity(), mutableUser.getAddress().getCity());
assertNull(user.getAddress().getStreet());
// user should be gone
int tries = 0;
MutableUser foundUser;
do {
sleepSecs(2);
foundUser = couchbaseTemplate.findById(MutableUser.class).one(user.getId());
} while (tries++ < 5 && foundUser != null);
assertNull(foundUser);
} finally {
couchbaseTemplate.removeByQuery(MutableUser.class).withConsistency(QueryScanConsistency.REQUEST_PLUS).all();
}
}
@Test
void mutateInByIdReplaceMissingPath(){
try {
MutableUser user = new MutableUser(UUID.randomUUID().toString(), "firstname", "lastname");
user = couchbaseTemplate.insertById(MutableUser.class).one(user);
MutableUser mutableUser = new MutableUser(user.getId(), "othername", "");
mutableUser.setRoles(Collections.singletonList("ADMIN"));
Address mutableAddress = new Address();
mutableAddress.setCity("othercity");
mutableAddress.setStreet("street");
mutableUser.setAddress(mutableAddress);
assertThrows(InvalidDataAccessResourceUsageException.class, ()-> couchbaseTemplate.mutateInById(MutableUser.class).withReplacePaths("roles", "address.city").one(mutableUser));
} finally {
couchbaseTemplate.removeByQuery(MutableUser.class).withConsistency(QueryScanConsistency.REQUEST_PLUS).all();
}
}
@Test
void mutateInByIdInsert(){
try {
MutableUser user = new MutableUser(UUID.randomUUID().toString(), "firstname", "lastname");
user = couchbaseTemplate.insertById(MutableUser.class).one(user);
MutableUser mutableUser = new MutableUser(user.getId(), "othername", "");
mutableUser.setRoles(Collections.singletonList("ADMIN"));
couchbaseTemplate.mutateInById(MutableUser.class).withInsertPaths("roles").one(mutableUser);
user = couchbaseTemplate.findById(MutableUser.class).one(user.getId());
assertEquals(mutableUser.getRoles(), user.getRoles());
assertNotEquals(mutableUser.getFirstname(), user.getFirstname());
} finally {
couchbaseTemplate.removeByQuery(MutableUser.class).withConsistency(QueryScanConsistency.REQUEST_PLUS).all();
}
}
@Test
void mutateInByIdInsertWithCAS(){
try {
MutableUser user = new MutableUser(UUID.randomUUID().toString(), "firstname", "lastname");
user = couchbaseTemplate.insertById(MutableUser.class).one(user);
MutableUser mutableUser = new MutableUser(user.getId(), "othername", "");
mutableUser.setRoles(Collections.singletonList("ADMIN"));
mutableUser.setVersion(999);
// if case is incorrect then exception is thrown
assertThrows(OptimisticLockingFailureException.class, ()-> couchbaseTemplate.mutateInById(MutableUser.class).withCasProvided()
.withInsertPaths("roles").one(mutableUser));
// success on correct cas
mutableUser.setVersion(user.getVersion());
couchbaseTemplate.mutateInById(MutableUser.class).withCasProvided().withInsertPaths("roles").one(mutableUser);
user = couchbaseTemplate.findById(MutableUser.class).one(user.getId());
assertEquals(mutableUser.getRoles(), user.getRoles());
} finally {
couchbaseTemplate.removeByQuery(MutableUser.class).withConsistency(QueryScanConsistency.REQUEST_PLUS).all();
}
}
@Test
void mutateInByIdInsertMultiple() {
try {
MutableUser user = new MutableUser(UUID.randomUUID().toString(), "firstname", "lastname");
user = couchbaseTemplate.insertById(MutableUser.class).one(user);
MutableUser mutableUser = new MutableUser(user.getId(), "othername", "");
mutableUser.setRoles(Collections.singletonList("ADMIN"));
Address mutableAddress = new Address();
mutableAddress.setCity("othercity");
mutableAddress.setStreet("street");
mutableUser.setAddress(mutableAddress);
couchbaseTemplate.mutateInById(MutableUser.class).withInsertPaths("roles", "address.city").one(mutableUser);
user = couchbaseTemplate.findById(MutableUser.class).one(user.getId());
assertEquals(mutableUser.getRoles(), user.getRoles());
assertEquals(user.getAddress().getCity(), mutableUser.getAddress().getCity());
assertNull(user.getAddress().getStreet());
} finally {
couchbaseTemplate.removeByQuery(MutableUser.class).withConsistency(QueryScanConsistency.REQUEST_PLUS).all();
}
}
@Test
void mutateInByIdInsertMultipleWithDurability(){
try {
MutableUser user = new MutableUser(UUID.randomUUID().toString(), "firstname", "lastname");
user = couchbaseTemplate.insertById(MutableUser.class).one(user);
MutableUser mutableUser = new MutableUser(user.getId(), "othername", "");
mutableUser.setRoles(Collections.singletonList("ADMIN"));
Address mutableAddress = new Address();
mutableAddress.setCity("othercity");
mutableAddress.setStreet("street");
mutableUser.setAddress(mutableAddress);
couchbaseTemplate.mutateInById(MutableUser.class).withDurability(DurabilityLevel.MAJORITY)
.withInsertPaths("address.city").one(mutableUser);
user = couchbaseTemplate.findById(MutableUser.class).one(user.getId());
assertEquals(user.getAddress().getCity(), mutableUser.getAddress().getCity());
assertNull(user.getAddress().getStreet());
} finally {
couchbaseTemplate.removeByQuery(MutableUser.class).withConsistency(QueryScanConsistency.REQUEST_PLUS).all();
}
}
@Test
void mutateInByIdInsertMultipleWithExpiry(){
try {
MutableUser user = new MutableUser(UUID.randomUUID().toString(), "firstname", "lastname");
user = couchbaseTemplate.insertById(MutableUser.class).one(user);
MutableUser mutableUser = new MutableUser(user.getId(), "othername", "");
mutableUser.setRoles(Collections.singletonList("ADMIN"));
Address mutableAddress = new Address();
mutableAddress.setCity("othercity");
mutableAddress.setStreet("street");
mutableUser.setAddress(mutableAddress);
couchbaseTemplate.mutateInById(MutableUser.class).withExpiry(Duration.ofSeconds(1))
.withInsertPaths("address.city").one(mutableUser);
user = couchbaseTemplate.findById(MutableUser.class).one(user.getId());
assertEquals(user.getAddress().getCity(), mutableUser.getAddress().getCity());
assertNull(user.getAddress().getStreet());
// user should be gone
int tries = 0;
MutableUser foundUser;
do {
sleepSecs(2);
foundUser = couchbaseTemplate.findById(MutableUser.class).one(user.getId());
} while (tries++ < 5 && foundUser != null);
assertNull(foundUser);
} finally {
couchbaseTemplate.removeByQuery(MutableUser.class).withConsistency(QueryScanConsistency.REQUEST_PLUS).all();
}
}
@Test
void mutateInByIdInsertMissingPath(){
try {
MutableUser user = new MutableUser(UUID.randomUUID().toString(), "firstname", "lastname");
user = couchbaseTemplate.insertById(MutableUser.class).one(user);
MutableUser mutableUser = new MutableUser(user.getId(), "othername", "");
assertThrows(InvalidDataAccessResourceUsageException.class, ()-> couchbaseTemplate.mutateInById(MutableUser.class).withInsertPaths("firstname").one(mutableUser));
} finally {
couchbaseTemplate.removeByQuery(MutableUser.class).withConsistency(QueryScanConsistency.REQUEST_PLUS).all();
}
}
@Test
void mutateInByIdRemove(){
try {
MutableUser user = new MutableUser(UUID.randomUUID().toString(), "firstname", "lastname");
user.setRoles(Collections.singletonList("ADMIN"));
user = couchbaseTemplate.insertById(MutableUser.class).one(user);
assertNotNull(user.getRoles());
couchbaseTemplate.mutateInById(MutableUser.class).withRemovePaths("roles").one(user);
user = couchbaseTemplate.findById(MutableUser.class).one(user.getId());
assertNull(user.getRoles());
} finally {
couchbaseTemplate.removeByQuery(MutableUser.class).withConsistency(QueryScanConsistency.REQUEST_PLUS).all();
}
}
@Test
void mutateInByIdRemoveWithCAS(){
try {
MutableUser user = new MutableUser(UUID.randomUUID().toString(), "firstname", "lastname");
user.setRoles(Collections.singletonList("ADMIN"));
user = couchbaseTemplate.insertById(MutableUser.class).one(user);
String userId = user.getId();
MutableUser mutableUser = new MutableUser(user.getId(), "othername", "otherlast");
mutableUser.setVersion(999);
// if case is incorrect then exception is thrown
assertThrows(OptimisticLockingFailureException.class, ()-> couchbaseTemplate.mutateInById(MutableUser.class).withCasProvided()
.withRemovePaths("roles").one(mutableUser));
// success on correct cas
user.setVersion(user.getVersion());
couchbaseTemplate.mutateInById(MutableUser.class).withCasProvided().withRemovePaths("roles").one(user);
user = couchbaseTemplate.findById(MutableUser.class).one(userId);
assertNull(user.getRoles());
} finally {
couchbaseTemplate.removeByQuery(MutableUser.class).withConsistency(QueryScanConsistency.REQUEST_PLUS).all();
}
}
@Test
void mutateInByIdRemoveMultiple() {
try {
MutableUser user = new MutableUser(UUID.randomUUID().toString(), "firstname", "lastname");
user.setRoles(Collections.singletonList("ADMIN"));
Address mutableAddress = new Address();
mutableAddress.setCity("othercity");
mutableAddress.setStreet("street");
user.setAddress(mutableAddress);
user = couchbaseTemplate.insertById(MutableUser.class).one(user);
couchbaseTemplate.mutateInById(MutableUser.class).withRemovePaths("roles", "address.city").one(user);
user = couchbaseTemplate.findById(MutableUser.class).one(user.getId());
assertNull(user.getRoles());
assertNull(user.getAddress().getCity());
} finally {
couchbaseTemplate.removeByQuery(MutableUser.class).withConsistency(QueryScanConsistency.REQUEST_PLUS).all();
}
}
@Test
void mutateInByIdRemoveMultipleWithDurability(){
try {
MutableUser user = new MutableUser(UUID.randomUUID().toString(), "firstname", "lastname");
user = couchbaseTemplate.insertById(MutableUser.class).one(user);
couchbaseTemplate.mutateInById(MutableUser.class).withDurability(DurabilityLevel.MAJORITY)
.withRemovePaths("lastname").one(user);
user = couchbaseTemplate.findById(MutableUser.class).one(user.getId());
assertNull(user.getLastname());
} finally {
couchbaseTemplate.removeByQuery(MutableUser.class).withConsistency(QueryScanConsistency.REQUEST_PLUS).all();
}
}
@Test
void mutateInByIdRemoveMultipleWithExpiry(){
try {
MutableUser user = new MutableUser(UUID.randomUUID().toString(), "firstname", "lastname");
user = couchbaseTemplate.insertById(MutableUser.class).one(user);
couchbaseTemplate.mutateInById(MutableUser.class).withExpiry(Duration.ofSeconds(1))
.withRemovePaths("lastname").one(user);
user = couchbaseTemplate.findById(MutableUser.class).one(user.getId());
assertNull(user.getLastname());
// user should be gone
int tries = 0;
MutableUser foundUser;
do {
sleepSecs(2);
foundUser = couchbaseTemplate.findById(MutableUser.class).one(user.getId());
} while (tries++ < 5 && foundUser != null);
assertNull(foundUser);
} finally {
couchbaseTemplate.removeByQuery(MutableUser.class).withConsistency(QueryScanConsistency.REQUEST_PLUS).all();
}
}
@Test
void mutateInByIdRemoveMissingPath(){
try {
MutableUser user = new MutableUser(UUID.randomUUID().toString(), "firstname", "lastname");
user = couchbaseTemplate.insertById(MutableUser.class).one(user);
MutableUser mutableUser = new MutableUser(user.getId(), "othername", "");
assertThrows(InvalidDataAccessResourceUsageException.class, ()-> couchbaseTemplate.mutateInById(MutableUser.class)
.withRemovePaths("roles").one(mutableUser));
} finally {
couchbaseTemplate.removeByQuery(MutableUser.class).withConsistency(QueryScanConsistency.REQUEST_PLUS).all();
}
}
@Test
void mutateInByIdChained(){
try {
MutableUser user = new MutableUser(UUID.randomUUID().toString(), "firstname", "lastname");
Address address = new Address();
address.setCity("city");
address.setStreet("street");
user.setAddress(address);
user = couchbaseTemplate.insertById(MutableUser.class).one(user);
MutableUser mutableUser = new MutableUser(user.getId(), "othername", "");
mutableUser.setRoles(Collections.singletonList("ADMIN"));
Address mAddress = new Address();
mAddress.setCity("othercity");
mAddress.setStreet("otherstreet");
mutableUser.setAddress(mAddress);
mutableUser.setSubuser(new MutableUser("subuser", "subfirstname", "sublastname"));
couchbaseTemplate.mutateInById(MutableUser.class)
.withInsertPaths("roles", "subuser.firstname")
.withRemovePaths("address.city")
.withUpsertPaths("firstname")
.withReplacePaths("address.street")
.one(mutableUser);
user = couchbaseTemplate.findById(MutableUser.class).one(user.getId());
assertNull(user.getAddress().getCity());
assertEquals(mAddress.getStreet(), user.getAddress().getStreet());
assertEquals(mutableUser.getRoles(), user.getRoles());
assertEquals(mutableUser.getFirstname(), user.getFirstname());
assertEquals(mutableUser.getSubuser().getFirstname(), user.getSubuser().getFirstname());
assertNull(user.getSubuser().getLastname());
} finally {
couchbaseTemplate.removeByQuery(MutableUser.class).withConsistency(QueryScanConsistency.REQUEST_PLUS).all();
}
}
@Test
void insertById() {

View File

@@ -28,20 +28,17 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.time.Duration;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import java.util.*;
import com.couchbase.client.core.error.TimeoutException;
import com.couchbase.client.core.msg.kv.DurabilityLevel;
import com.couchbase.client.core.retry.RetryReason;
import com.couchbase.client.java.query.QueryScanConsistency;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.dao.InvalidDataAccessResourceUsageException;
import org.springframework.dao.OptimisticLockingFailureException;
import org.springframework.data.couchbase.core.ReactiveFindByIdOperation.ReactiveFindById;
import org.springframework.data.couchbase.core.ReactiveRemoveByIdOperation.ReactiveRemoveById;
@@ -341,6 +338,592 @@ class ReactiveCouchbaseTemplateKeyValueIntegrationTests extends JavaIntegrationT
}
}
@Test
void mutateInByIdUpsert(){
try {
MutableUser user = new MutableUser(UUID.randomUUID().toString(), "firstname", "lastname");
user = reactiveCouchbaseTemplate.insertById(MutableUser.class).one(user).block();
MutableUser mutableUser = new MutableUser(user.getId(), "", "");
mutableUser.setRoles(Collections.singletonList("ADMIN"));
reactiveCouchbaseTemplate.mutateInById(MutableUser.class).withUpsertPaths("roles").one(mutableUser).block();
user = reactiveCouchbaseTemplate.findById(MutableUser.class).one(user.getId()).block();
assertEquals(user.getRoles(), mutableUser.getRoles());
} finally {
reactiveCouchbaseTemplate.removeByQuery(MutableUser.class).withConsistency(QueryScanConsistency.REQUEST_PLUS).all();
}
}
@Test
void mutateInByIdUpsertWithCAS(){
try {
MutableUser user = new MutableUser(UUID.randomUUID().toString(), "firstname", "lastname");
user = reactiveCouchbaseTemplate.insertById(MutableUser.class).one(user).block();
MutableUser mutableUser = new MutableUser(user.getId(), "", "");
mutableUser.setRoles(Collections.singletonList("ADMIN"));
mutableUser.setVersion(999);
// if case is incorrect then exception is thrown
assertThrows(OptimisticLockingFailureException.class, ()-> reactiveCouchbaseTemplate.mutateInById(MutableUser.class)
.withCasProvided().withUpsertPaths("roles").one(mutableUser).block());
// success on correct cas
mutableUser.setVersion(user.getVersion());
reactiveCouchbaseTemplate.mutateInById(MutableUser.class)
.withCasProvided().withUpsertPaths("roles").one(mutableUser).block();
user = reactiveCouchbaseTemplate.findById(MutableUser.class).one(user.getId()).block();
assertEquals(mutableUser.getRoles(), user.getRoles());
} finally {
reactiveCouchbaseTemplate.removeByQuery(MutableUser.class).withConsistency(QueryScanConsistency.REQUEST_PLUS).all();
}
}
@Test
void mutateInByIdUpsertMultiple() {
try {
MutableUser user = new MutableUser(UUID.randomUUID().toString(), "firstname", "lastname");
user = reactiveCouchbaseTemplate.insertById(MutableUser.class).one(user).block();
MutableUser mutableUser = new MutableUser(user.getId(), "", "");
mutableUser.setRoles(Collections.singletonList("ADMIN"));
Address address = new Address();
address.setCity("city");
address.setStreet("street");
mutableUser.setAddress(address);
reactiveCouchbaseTemplate.mutateInById(MutableUser.class).withUpsertPaths("roles", "address.street").one(mutableUser).block();
user = reactiveCouchbaseTemplate.findById(MutableUser.class).one(user.getId()).block();
assertEquals(user.getRoles(), mutableUser.getRoles());
assertEquals(user.getAddress().getStreet(), mutableUser.getAddress().getStreet());
assertNull(user.getAddress().getCity());
} finally {
reactiveCouchbaseTemplate.removeByQuery(MutableUser.class).withConsistency(QueryScanConsistency.REQUEST_PLUS).all();
}
}
@Test
void mutateInByIdUpsertMultipleWithDurability(){
try {
MutableUser user = new MutableUser(UUID.randomUUID().toString(), "firstname", "lastname");
user = reactiveCouchbaseTemplate.insertById(MutableUser.class).one(user).block();
MutableUser mutableUser = new MutableUser(user.getId(), "", "");
mutableUser.setRoles(Collections.singletonList("ADMIN"));
Address address = new Address();
address.setCity("city");
address.setStreet("street");
mutableUser.setAddress(address);
reactiveCouchbaseTemplate.mutateInById(MutableUser.class).withDurability(DurabilityLevel.MAJORITY)
.withUpsertPaths("roles", "address.street").one(mutableUser).block();
user = reactiveCouchbaseTemplate.findById(MutableUser.class).one(user.getId()).block();
assertEquals(user.getRoles(), mutableUser.getRoles());
assertEquals(user.getAddress().getStreet(), mutableUser.getAddress().getStreet());
assertNull(user.getAddress().getCity());
} finally {
reactiveCouchbaseTemplate.removeByQuery(MutableUser.class).withConsistency(QueryScanConsistency.REQUEST_PLUS).all();
}
}
@Test
void mutateInByIdUpsertMultipleWithExpiry(){
try {
MutableUser user = new MutableUser(UUID.randomUUID().toString(), "firstname", "lastname");
user = reactiveCouchbaseTemplate.insertById(MutableUser.class).one(user).block();
MutableUser mutableUser = new MutableUser(user.getId(), "", "");
mutableUser.setRoles(Collections.singletonList("ADMIN"));
Address address = new Address();
address.setCity("city");
address.setStreet("street");
mutableUser.setAddress(address);
reactiveCouchbaseTemplate.mutateInById(MutableUser.class).withExpiry(Duration.ofSeconds(1))
.withUpsertPaths("roles", "address.street").one(mutableUser).block();
user = reactiveCouchbaseTemplate.findById(MutableUser.class).one(user.getId()).block();
assertEquals(user.getRoles(), mutableUser.getRoles());
assertEquals(user.getAddress().getStreet(), mutableUser.getAddress().getStreet());
assertNull(user.getAddress().getCity());
// user should be gone
int tries = 0;
MutableUser foundUser;
do {
sleepSecs(2);
foundUser = reactiveCouchbaseTemplate.findById(MutableUser.class).one(user.getId()).block();
} while (tries++ < 5 && foundUser != null);
assertNull(foundUser);
} finally {
reactiveCouchbaseTemplate.removeByQuery(MutableUser.class).withConsistency(QueryScanConsistency.REQUEST_PLUS).all();
}
}
@Test
void mutateInByIdReplace(){
try {
MutableUser user = new MutableUser(UUID.randomUUID().toString(), "firstname", "lastname");
user = reactiveCouchbaseTemplate.insertById(MutableUser.class).one(user).block();
MutableUser mutableUser = new MutableUser(user.getId(), "othername", "");
reactiveCouchbaseTemplate.mutateInById(MutableUser.class).withReplacePaths("firstname").one(mutableUser).block();
user = reactiveCouchbaseTemplate.findById(MutableUser.class).one(user.getId()).block();
assertEquals(mutableUser.getFirstname(), user.getFirstname());
} finally {
reactiveCouchbaseTemplate.removeByQuery(MutableUser.class).withConsistency(QueryScanConsistency.REQUEST_PLUS).all();
}
}
@Test
void mutateInByIdReplaceWithCAS(){
try {
MutableUser user = new MutableUser(UUID.randomUUID().toString(), "firstname", "lastname");
user = reactiveCouchbaseTemplate.insertById(MutableUser.class).one(user).block();
MutableUser mutableUser = new MutableUser(user.getId(), "othername", "");
mutableUser.setVersion(999);
// if case is incorrect then exception is thrown
assertThrows(OptimisticLockingFailureException.class, ()-> reactiveCouchbaseTemplate.mutateInById(MutableUser.class).withCasProvided()
.withReplacePaths("firstname").one(mutableUser).block());
// success on correct cas
mutableUser.setVersion(user.getVersion());
reactiveCouchbaseTemplate.mutateInById(MutableUser.class).withCasProvided().withReplacePaths("firstname").one(mutableUser).block();
user = reactiveCouchbaseTemplate.findById(MutableUser.class).one(user.getId()).block();
assertEquals(mutableUser.getFirstname(), user.getFirstname());
} finally {
reactiveCouchbaseTemplate.removeByQuery(MutableUser.class).withConsistency(QueryScanConsistency.REQUEST_PLUS).all();
}
}
@Test
void mutateInByIdReplaceMultiple() {
try {
MutableUser user = new MutableUser(UUID.randomUUID().toString(), "firstname", "lastname");
Address address = new Address();
address.setCity("city");
address.setStreet("street");
user.setAddress(address);
user = reactiveCouchbaseTemplate.insertById(MutableUser.class).one(user).block();
MutableUser mutableUser = new MutableUser(user.getId(), "othername", "");
mutableUser.setRoles(Collections.singletonList("ADMIN"));
Address mutableAddress = new Address();
mutableAddress.setCity("othercity");
mutableUser.setAddress(mutableAddress);
reactiveCouchbaseTemplate.mutateInById(MutableUser.class).withReplacePaths("firstname", "address.city")
.one(mutableUser).block();
user = reactiveCouchbaseTemplate.findById(MutableUser.class).one(user.getId()).block();
assertEquals(mutableUser.getFirstname(), user.getFirstname());
assertEquals(user.getAddress().getCity(), mutableUser.getAddress().getCity());
} finally {
reactiveCouchbaseTemplate.removeByQuery(MutableUser.class).withConsistency(QueryScanConsistency.REQUEST_PLUS).all();
}
}
@Test
void mutateInByIdReplaceMultipleWithDurability(){
try {
MutableUser user = new MutableUser(UUID.randomUUID().toString(), "firstname", "lastname");
Address address = new Address();
address.setCity("city");
address.setStreet("street");
user.setAddress(address);
user = reactiveCouchbaseTemplate.insertById(MutableUser.class).one(user).block();
MutableUser mutableUser = new MutableUser(user.getId(), "othername", "");
mutableUser.setRoles(Collections.singletonList("ADMIN"));
Address mutableAddress = new Address();
mutableAddress.setCity("othercity");
mutableUser.setAddress(mutableAddress);
reactiveCouchbaseTemplate.mutateInById(MutableUser.class).withDurability(DurabilityLevel.MAJORITY)
.withReplacePaths("firstname", "address.city").one(mutableUser).block();
user = reactiveCouchbaseTemplate.findById(MutableUser.class).one(user.getId()).block();
assertEquals(mutableUser.getFirstname(), user.getFirstname());
assertEquals(user.getAddress().getCity(), mutableUser.getAddress().getCity());
} finally {
reactiveCouchbaseTemplate.removeByQuery(MutableUser.class).withConsistency(QueryScanConsistency.REQUEST_PLUS).all();
}
}
@Test
void mutateInByIdReplaceMultipleWithExpiry(){
try {
MutableUser user = new MutableUser(UUID.randomUUID().toString(), "firstname", "lastname");
Address address = new Address();
address.setCity("city");
user.setAddress(address);
user = reactiveCouchbaseTemplate.insertById(MutableUser.class).one(user).block();
MutableUser mutableUser = new MutableUser(user.getId(), "othername", "");
mutableUser.setRoles(Collections.singletonList("ADMIN"));
Address mutableAddress = new Address();
mutableAddress.setCity("othercity");
mutableAddress.setStreet("street");
mutableUser.setAddress(mutableAddress);
reactiveCouchbaseTemplate.mutateInById(MutableUser.class).withExpiry(Duration.ofSeconds(1))
.withReplacePaths("firstname", "address.city").one(mutableUser).block();
user = reactiveCouchbaseTemplate.findById(MutableUser.class).one(user.getId()).block();
assertEquals(mutableUser.getFirstname(), user.getFirstname());
assertEquals(user.getAddress().getCity(), mutableUser.getAddress().getCity());
assertNull(user.getAddress().getStreet());
// user should be gone
int tries = 0;
MutableUser foundUser;
do {
sleepSecs(2);
foundUser = reactiveCouchbaseTemplate.findById(MutableUser.class).one(user.getId()).block();
} while (tries++ < 5 && foundUser != null);
assertNull(foundUser);
} finally {
reactiveCouchbaseTemplate.removeByQuery(MutableUser.class).withConsistency(QueryScanConsistency.REQUEST_PLUS).all();
}
}
@Test
void mutateInByIdReplaceMissingPath(){
try {
MutableUser user = new MutableUser(UUID.randomUUID().toString(), "firstname", "lastname");
user = reactiveCouchbaseTemplate.insertById(MutableUser.class).one(user).block();
MutableUser mutableUser = new MutableUser(user.getId(), "othername", "");
mutableUser.setRoles(Collections.singletonList("ADMIN"));
Address mutableAddress = new Address();
mutableAddress.setCity("othercity");
mutableAddress.setStreet("street");
mutableUser.setAddress(mutableAddress);
assertThrows(InvalidDataAccessResourceUsageException.class,
()-> reactiveCouchbaseTemplate.mutateInById(MutableUser.class).withReplacePaths("roles", "address.city")
.one(mutableUser).block());
} finally {
reactiveCouchbaseTemplate.removeByQuery(MutableUser.class).withConsistency(QueryScanConsistency.REQUEST_PLUS).all();
}
}
@Test
void mutateInByIdInsert(){
try {
MutableUser user = new MutableUser(UUID.randomUUID().toString(), "firstname", "lastname");
user = reactiveCouchbaseTemplate.insertById(MutableUser.class).one(user).block();
MutableUser mutableUser = new MutableUser(user.getId(), "othername", "");
mutableUser.setRoles(Collections.singletonList("ADMIN"));
reactiveCouchbaseTemplate.mutateInById(MutableUser.class).withInsertPaths("roles").one(mutableUser).block();
user = reactiveCouchbaseTemplate.findById(MutableUser.class).one(user.getId()).block();
assertEquals(mutableUser.getRoles(), user.getRoles());
assertNotEquals(mutableUser.getFirstname(), user.getFirstname());
} finally {
reactiveCouchbaseTemplate.removeByQuery(MutableUser.class).withConsistency(QueryScanConsistency.REQUEST_PLUS).all();
}
}
@Test
void mutateInByIdInsertWithCAS(){
try {
MutableUser user = new MutableUser(UUID.randomUUID().toString(), "firstname", "lastname");
user = reactiveCouchbaseTemplate.insertById(MutableUser.class).one(user).block();
MutableUser mutableUser = new MutableUser(user.getId(), "othername", "");
mutableUser.setRoles(Collections.singletonList("ADMIN"));
mutableUser.setVersion(999);
// if case is incorrect then exception is thrown
assertThrows(OptimisticLockingFailureException.class, ()-> reactiveCouchbaseTemplate.mutateInById(MutableUser.class).withCasProvided()
.withInsertPaths("roles").one(mutableUser).block());
// success on correct cas
mutableUser.setVersion(user.getVersion());
reactiveCouchbaseTemplate.mutateInById(MutableUser.class).withCasProvided().withInsertPaths("roles").one(mutableUser).block();
user = reactiveCouchbaseTemplate.findById(MutableUser.class).one(user.getId()).block();
assertEquals(mutableUser.getRoles(), user.getRoles());
} finally {
reactiveCouchbaseTemplate.removeByQuery(MutableUser.class).withConsistency(QueryScanConsistency.REQUEST_PLUS).all();
}
}
@Test
void mutateInByIdInsertMultiple() {
try {
MutableUser user = new MutableUser(UUID.randomUUID().toString(), "firstname", "lastname");
user = reactiveCouchbaseTemplate.insertById(MutableUser.class).one(user).block();
MutableUser mutableUser = new MutableUser(user.getId(), "othername", "");
mutableUser.setRoles(Collections.singletonList("ADMIN"));
Address mutableAddress = new Address();
mutableAddress.setCity("othercity");
mutableAddress.setStreet("street");
mutableUser.setAddress(mutableAddress);
reactiveCouchbaseTemplate.mutateInById(MutableUser.class).withInsertPaths("roles", "address.city").one(mutableUser).block();
user = reactiveCouchbaseTemplate.findById(MutableUser.class).one(user.getId()).block();
assertEquals(mutableUser.getRoles(), user.getRoles());
assertEquals(user.getAddress().getCity(), mutableUser.getAddress().getCity());
assertNull(user.getAddress().getStreet());
} finally {
reactiveCouchbaseTemplate.removeByQuery(MutableUser.class).withConsistency(QueryScanConsistency.REQUEST_PLUS).all();
}
}
@Test
void mutateInByIdInsertMultipleWithDurability(){
try {
MutableUser user = new MutableUser(UUID.randomUUID().toString(), "firstname", "lastname");
user = reactiveCouchbaseTemplate.insertById(MutableUser.class).one(user).block();
MutableUser mutableUser = new MutableUser(user.getId(), "othername", "");
mutableUser.setRoles(Collections.singletonList("ADMIN"));
Address mutableAddress = new Address();
mutableAddress.setCity("othercity");
mutableAddress.setStreet("street");
mutableUser.setAddress(mutableAddress);
reactiveCouchbaseTemplate.mutateInById(MutableUser.class).withDurability(DurabilityLevel.MAJORITY)
.withInsertPaths("address.city").one(mutableUser).block();
user = reactiveCouchbaseTemplate.findById(MutableUser.class).one(user.getId()).block();
assertEquals(user.getAddress().getCity(), mutableUser.getAddress().getCity());
assertNull(user.getAddress().getStreet());
} finally {
reactiveCouchbaseTemplate.removeByQuery(MutableUser.class).withConsistency(QueryScanConsistency.REQUEST_PLUS).all();
}
}
@Test
void mutateInByIdInsertMultipleWithExpiry(){
try {
MutableUser user = new MutableUser(UUID.randomUUID().toString(), "firstname", "lastname");
user = reactiveCouchbaseTemplate.insertById(MutableUser.class).one(user).block();
MutableUser mutableUser = new MutableUser(user.getId(), "othername", "");
mutableUser.setRoles(Collections.singletonList("ADMIN"));
Address mutableAddress = new Address();
mutableAddress.setCity("othercity");
mutableAddress.setStreet("street");
mutableUser.setAddress(mutableAddress);
reactiveCouchbaseTemplate.mutateInById(MutableUser.class).withExpiry(Duration.ofSeconds(1))
.withInsertPaths("address.city").one(mutableUser).block();
user = reactiveCouchbaseTemplate.findById(MutableUser.class).one(user.getId()).block();
assertEquals(user.getAddress().getCity(), mutableUser.getAddress().getCity());
assertNull(user.getAddress().getStreet());
// user should be gone
int tries = 0;
MutableUser foundUser;
do {
sleepSecs(2);
foundUser = reactiveCouchbaseTemplate.findById(MutableUser.class).one(user.getId()).block();
} while (tries++ < 5 && foundUser != null);
assertNull(foundUser);
} finally {
reactiveCouchbaseTemplate.removeByQuery(MutableUser.class).withConsistency(QueryScanConsistency.REQUEST_PLUS).all();
}
}
@Test
void mutateInByIdInsertMissingPath(){
try {
MutableUser user = new MutableUser(UUID.randomUUID().toString(), "firstname", "lastname");
user = reactiveCouchbaseTemplate.insertById(MutableUser.class).one(user).block();
MutableUser mutableUser = new MutableUser(user.getId(), "othername", "");
assertThrows(InvalidDataAccessResourceUsageException.class, ()-> reactiveCouchbaseTemplate.mutateInById(MutableUser.class)
.withInsertPaths("firstname").one(mutableUser).block());
} finally {
reactiveCouchbaseTemplate.removeByQuery(MutableUser.class).withConsistency(QueryScanConsistency.REQUEST_PLUS).all();
}
}
@Test
void mutateInByIdRemove(){
try {
MutableUser user = new MutableUser(UUID.randomUUID().toString(), "firstname", "lastname");
user.setRoles(Collections.singletonList("ADMIN"));
user = reactiveCouchbaseTemplate.insertById(MutableUser.class).one(user).block();
assertNotNull(user.getRoles());
reactiveCouchbaseTemplate.mutateInById(MutableUser.class).withRemovePaths("roles").one(user).block();
user = reactiveCouchbaseTemplate.findById(MutableUser.class).one(user.getId()).block();
assertNull(user.getRoles());
} finally {
reactiveCouchbaseTemplate.removeByQuery(MutableUser.class).withConsistency(QueryScanConsistency.REQUEST_PLUS).all();
}
}
@Test
void mutateInByIdRemoveWithCAS(){
try {
MutableUser user = new MutableUser(UUID.randomUUID().toString(), "firstname", "lastname");
user.setRoles(Collections.singletonList("ADMIN"));
user = reactiveCouchbaseTemplate.insertById(MutableUser.class).one(user).block();
String userId = user.getId();
MutableUser mutableUser = new MutableUser(user.getId(), "othername", "otherlast");
mutableUser.setVersion(999);
// if case is incorrect then exception is thrown
assertThrows(OptimisticLockingFailureException.class, ()-> reactiveCouchbaseTemplate.mutateInById(MutableUser.class).withCasProvided()
.withRemovePaths("roles").one(mutableUser).block());
// success on correct cas
user.setVersion(user.getVersion());
reactiveCouchbaseTemplate.mutateInById(MutableUser.class).withCasProvided().withRemovePaths("roles").one(user).block();
user = reactiveCouchbaseTemplate.findById(MutableUser.class).one(userId).block();
assertNull(user.getRoles());
} finally {
reactiveCouchbaseTemplate.removeByQuery(MutableUser.class).withConsistency(QueryScanConsistency.REQUEST_PLUS).all();
}
}
@Test
void mutateInByIdRemoveMultiple() {
try {
MutableUser user = new MutableUser(UUID.randomUUID().toString(), "firstname", "lastname");
user.setRoles(Collections.singletonList("ADMIN"));
Address mutableAddress = new Address();
mutableAddress.setCity("othercity");
mutableAddress.setStreet("street");
user.setAddress(mutableAddress);
user = reactiveCouchbaseTemplate.insertById(MutableUser.class).one(user).block();
reactiveCouchbaseTemplate.mutateInById(MutableUser.class).withRemovePaths("roles", "address.city").one(user).block();
user = reactiveCouchbaseTemplate.findById(MutableUser.class).one(user.getId()).block();
assertNull(user.getRoles());
assertNull(user.getAddress().getCity());
} finally {
reactiveCouchbaseTemplate.removeByQuery(MutableUser.class).withConsistency(QueryScanConsistency.REQUEST_PLUS).all();
}
}
@Test
void mutateInByIdRemoveMultipleWithDurability(){
try {
MutableUser user = new MutableUser(UUID.randomUUID().toString(), "firstname", "lastname");
user = reactiveCouchbaseTemplate.insertById(MutableUser.class).one(user).block();
reactiveCouchbaseTemplate.mutateInById(MutableUser.class).withDurability(DurabilityLevel.MAJORITY)
.withRemovePaths("lastname").one(user).block();
user = reactiveCouchbaseTemplate.findById(MutableUser.class).one(user.getId()).block();
assertNull(user.getLastname());
} finally {
reactiveCouchbaseTemplate.removeByQuery(MutableUser.class).withConsistency(QueryScanConsistency.REQUEST_PLUS).all();
}
}
@Test
void mutateInByIdRemoveMultipleWithExpiry(){
try {
MutableUser user = new MutableUser(UUID.randomUUID().toString(), "firstname", "lastname");
user = reactiveCouchbaseTemplate.insertById(MutableUser.class).one(user).block();
reactiveCouchbaseTemplate.mutateInById(MutableUser.class).withExpiry(Duration.ofSeconds(1))
.withRemovePaths("lastname").one(user).block();
user = reactiveCouchbaseTemplate.findById(MutableUser.class).one(user.getId()).block();
assertNull(user.getLastname());
// user should be gone
int tries = 0;
MutableUser foundUser;
do {
sleepSecs(2);
foundUser = reactiveCouchbaseTemplate.findById(MutableUser.class).one(user.getId()).block();
} while (tries++ < 5 && foundUser != null);
assertNull(foundUser);
} finally {
reactiveCouchbaseTemplate.removeByQuery(MutableUser.class).withConsistency(QueryScanConsistency.REQUEST_PLUS).all();
}
}
@Test
void mutateInByIdRemoveMissingPath(){
try {
MutableUser user = new MutableUser(UUID.randomUUID().toString(), "firstname", "lastname");
user = reactiveCouchbaseTemplate.insertById(MutableUser.class).one(user).block();
MutableUser mutableUser = new MutableUser(user.getId(), "othername", "");
assertThrows(InvalidDataAccessResourceUsageException.class, ()-> reactiveCouchbaseTemplate.mutateInById(MutableUser.class)
.withRemovePaths("roles").one(mutableUser).block());
} finally {
reactiveCouchbaseTemplate.removeByQuery(MutableUser.class).withConsistency(QueryScanConsistency.REQUEST_PLUS).all();
}
}
@Test
void mutateInByIdChained(){
try {
MutableUser user = new MutableUser(UUID.randomUUID().toString(), "firstname", "lastname");
Address address = new Address();
address.setCity("city");
address.setStreet("street");
user.setAddress(address);
user = reactiveCouchbaseTemplate.insertById(MutableUser.class).one(user).block();
MutableUser mutableUser = new MutableUser(user.getId(), "othername", "");
mutableUser.setRoles(Collections.singletonList("ADMIN"));
Address mAddress = new Address();
mAddress.setCity("othercity");
mAddress.setStreet("otherstreet");
mutableUser.setAddress(mAddress);
mutableUser.setSubuser(new MutableUser("subuser", "subfirstname", "sublastname"));
reactiveCouchbaseTemplate.mutateInById(MutableUser.class)
.withInsertPaths("roles", "subuser.firstname")
.withRemovePaths("address.city")
.withUpsertPaths("firstname")
.withReplacePaths("address.street")
.one(mutableUser)
.block();
user = reactiveCouchbaseTemplate.findById(MutableUser.class).one(user.getId()).block();
assertNull(user.getAddress().getCity());
assertEquals(mAddress.getStreet(), user.getAddress().getStreet());
assertEquals(mutableUser.getRoles(), user.getRoles());
assertEquals(mutableUser.getFirstname(), user.getFirstname());
assertEquals(mutableUser.getSubuser().getFirstname(), user.getSubuser().getFirstname());
assertNull(user.getSubuser().getLastname());
} finally {
reactiveCouchbaseTemplate.removeByQuery(MutableUser.class).withConsistency(QueryScanConsistency.REQUEST_PLUS).all();
}
}
@Test
void insertById() {
User user = new User(UUID.randomUUID().toString(), "firstname", "lastname");

View File

@@ -0,0 +1,28 @@
package org.springframework.data.couchbase.domain;
import lombok.Getter;
import lombok.Setter;
import org.springframework.data.couchbase.core.mapping.Document;
import java.util.List;
@Document
public class MutableUser extends User{
public MutableUser(String id, String firstname, String lastname) {
super(id, firstname, lastname);
}
@Getter
@Setter
private Address address;
@Getter
@Setter
private MutableUser subuser;
@Getter
@Setter
private List<String> roles;
}