Skip to content

Commit b3e0060

Browse files
committed
DATACOUCH-623 - Add replace() method to CouchbaseRepository for CAS usage.
1 parent e72cdba commit b3e0060

File tree

6 files changed

+74
-8
lines changed

6 files changed

+74
-8
lines changed

src/main/java/org/springframework/data/couchbase/repository/support/SimpleCouchbaseRepository.java

+8-3
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import org.springframework.data.couchbase.core.query.Query;
2727
import org.springframework.data.couchbase.repository.CouchbaseRepository;
2828
import org.springframework.data.couchbase.repository.query.CouchbaseEntityInformation;
29+
import static org.springframework.data.couchbase.repository.support.Util.hasNonZeroVersionProperty;
2930
import org.springframework.data.domain.Page;
3031
import org.springframework.data.domain.PageImpl;
3132
import org.springframework.data.domain.Pageable;
@@ -75,15 +76,19 @@ public SimpleCouchbaseRepository(final CouchbaseEntityInformation<T, String> ent
7576
@SuppressWarnings("unchecked")
7677
public <S extends T> S save(final S entity) {
7778
Assert.notNull(entity, "Entity must not be null!");
78-
return (S) couchbaseOperations.upsertById(entityInformation.getJavaType()).one(entity);
79+
// if entity has non-null, non-zero version property, then replace()
80+
if (hasNonZeroVersionProperty(entity, couchbaseOperations.getConverter())) {
81+
return (S) couchbaseOperations.replaceById(entityInformation.getJavaType()).one(entity);
82+
} else {
83+
return (S) couchbaseOperations.upsertById(entityInformation.getJavaType()).one(entity);
84+
}
7985
}
8086

8187
@Override
8288
@SuppressWarnings("unchecked")
8389
public <S extends T> Iterable<S> saveAll(final Iterable<S> entities) {
8490
Assert.notNull(entities, "The given Iterable of entities must not be null!");
85-
return (Iterable<S>) couchbaseOperations.upsertById(entityInformation.getJavaType())
86-
.all(Streamable.of(entities).toList());
91+
return Streamable.of(entities).stream().map((e) -> save(e)).collect(StreamUtils.toUnmodifiableList());
8792
}
8893

8994
@Override

src/main/java/org/springframework/data/couchbase/repository/support/SimpleReactiveCouchbaseRepository.java

+9-2
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import org.springframework.data.couchbase.core.query.Query;
3030
import org.springframework.data.couchbase.repository.ReactiveCouchbaseRepository;
3131
import org.springframework.data.couchbase.repository.query.CouchbaseEntityInformation;
32+
import static org.springframework.data.couchbase.repository.support.Util.hasNonZeroVersionProperty;
3233
import org.springframework.data.domain.Sort;
3334
import org.springframework.data.util.Streamable;
3435
import org.springframework.util.Assert;
@@ -75,9 +76,15 @@ public SimpleReactiveCouchbaseRepository(final CouchbaseEntityInformation<T, Str
7576
}
7677

7778
@SuppressWarnings("unchecked")
79+
@Override
7880
public <S extends T> Mono<S> save(final S entity) {
7981
Assert.notNull(entity, "Entity must not be null!");
80-
return (Mono<S>) operations.upsertById(entityInformation.getJavaType()).one(entity);
82+
// if entity has non-null version property, then replace()
83+
if (hasNonZeroVersionProperty(entity, operations.getConverter())) {
84+
return (Mono<S>) operations.replaceById(entityInformation.getJavaType()).one(entity);
85+
} else {
86+
return (Mono<S>) operations.upsertById(entityInformation.getJavaType()).one(entity);
87+
}
8188
}
8289

8390
@Override
@@ -89,7 +96,7 @@ public Flux<T> findAll(final Sort sort) {
8996
@Override
9097
public <S extends T> Flux<S> saveAll(final Iterable<S> entities) {
9198
Assert.notNull(entities, "The given Iterable of entities must not be null!");
92-
return (Flux<S>) operations.upsertById(entityInformation.getJavaType()).all(Streamable.of(entities).toList());
99+
return Flux.fromIterable(entities).flatMap(this::save);
93100
}
94101

95102
@SuppressWarnings("unchecked")
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package org.springframework.data.couchbase.repository.support;
2+
3+
import org.springframework.data.couchbase.core.convert.CouchbaseConverter;
4+
import org.springframework.data.couchbase.core.mapping.CouchbasePersistentEntity;
5+
import org.springframework.data.couchbase.core.mapping.CouchbasePersistentProperty;
6+
7+
public class Util {
8+
9+
public static boolean hasNonZeroVersionProperty(Object entity, CouchbaseConverter converter) {
10+
CouchbasePersistentEntity<?> mapperEntity = converter.getMappingContext().getPersistentEntity(entity.getClass());
11+
final CouchbasePersistentProperty versionProperty = mapperEntity.getVersionProperty();
12+
boolean hasVersionProperty = false;
13+
try {
14+
if (versionProperty != null && versionProperty.getField() != null) {
15+
Object versionValue = versionProperty.getField().get(entity);
16+
hasVersionProperty = versionValue != null && !versionValue.equals(Long.valueOf(0));
17+
}
18+
} catch (IllegalAccessException iae) {}
19+
return hasVersionProperty;
20+
}
21+
}

src/test/java/org/springframework/data/couchbase/domain/UserRepository.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
import java.util.List;
2020

21+
import org.springframework.data.couchbase.repository.CouchbaseRepository;
2122
import org.springframework.data.couchbase.repository.Query;
2223
import org.springframework.data.repository.PagingAndSortingRepository;
2324
import org.springframework.data.repository.query.Param;
@@ -30,7 +31,7 @@
3031
* @author Michael Reiche
3132
*/
3233
@Repository
33-
public interface UserRepository extends PagingAndSortingRepository<User, String> {
34+
public interface UserRepository extends CouchbaseRepository<User, String> {
3435

3536
List<User> findByFirstname(String firstname);
3637

src/test/java/org/springframework/data/couchbase/repository/CouchbaseRepositoryQueryIntegrationTests.java

+19-2
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,14 @@
3131
import org.junit.jupiter.api.Test;
3232
import org.springframework.beans.factory.annotation.Autowired;
3333
import org.springframework.context.annotation.Configuration;
34+
import org.springframework.dao.DataIntegrityViolationException;
3435
import org.springframework.data.couchbase.CouchbaseClientFactory;
3536
import org.springframework.data.couchbase.config.AbstractCouchbaseConfiguration;
3637
import org.springframework.data.couchbase.domain.Airport;
3738
import org.springframework.data.couchbase.domain.AirportRepository;
39+
import org.springframework.data.couchbase.domain.ReactiveUserRepository;
40+
import org.springframework.data.couchbase.domain.User;
41+
import org.springframework.data.couchbase.domain.UserRepository;
3842
import org.springframework.data.couchbase.repository.config.EnableCouchbaseRepositories;
3943
import org.springframework.data.couchbase.util.Capabilities;
4044
import org.springframework.data.couchbase.util.ClusterAwareIntegrationTests;
@@ -58,6 +62,8 @@ public class CouchbaseRepositoryQueryIntegrationTests extends ClusterAwareIntegr
5862

5963
@Autowired AirportRepository airportRepository;
6064

65+
@Autowired UserRepository userRepository;
66+
6167
@BeforeEach
6268
void beforeEach() {
6369
try {
@@ -118,6 +124,17 @@ void findBySimpleProperty() {
118124

119125
}
120126

127+
@Test
128+
public void testCas() {
129+
User user = new User("1", "Dave", "Wilson");
130+
userRepository.save(user);
131+
user.setVersion(user.getVersion() - 1);
132+
assertThrows(DataIntegrityViolationException.class, () -> userRepository.save(user));
133+
user.setVersion(0);
134+
userRepository.save(user);
135+
userRepository.delete(user);
136+
}
137+
121138
@Test
122139
void count() {
123140
String[] iatas = { "JFK", "IAD", "SFO", "SJC", "SEA", "LAX", "PHX" };
@@ -132,8 +149,8 @@ void count() {
132149
airportRepository.save(airport);
133150
}
134151

135-
Long count = airportRepository.countFancyExpression( Arrays.asList("JFK"), Arrays.asList("jfk"), false);
136-
assertEquals( 1, count);
152+
Long count = airportRepository.countFancyExpression(Arrays.asList("JFK"), Arrays.asList("jfk"), false);
153+
assertEquals(1, count);
137154

138155
long airportCount = airportRepository.count();
139156
assertEquals(7, airportCount);

src/test/java/org/springframework/data/couchbase/repository/ReactiveCouchbaseRepositoryQueryIntegrationTests.java

+15
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,14 @@
2929
import org.junit.jupiter.api.Test;
3030
import org.springframework.beans.factory.annotation.Autowired;
3131
import org.springframework.context.annotation.Configuration;
32+
import org.springframework.dao.DataIntegrityViolationException;
3233
import org.springframework.dao.DataRetrievalFailureException;
3334
import org.springframework.data.couchbase.CouchbaseClientFactory;
3435
import org.springframework.data.couchbase.config.AbstractCouchbaseConfiguration;
3536
import org.springframework.data.couchbase.domain.Airport;
3637
import org.springframework.data.couchbase.domain.ReactiveAirportRepository;
38+
import org.springframework.data.couchbase.domain.ReactiveUserRepository;
39+
import org.springframework.data.couchbase.domain.User;
3740
import org.springframework.data.couchbase.repository.config.EnableReactiveCouchbaseRepositories;
3841
import org.springframework.data.couchbase.util.Capabilities;
3942
import org.springframework.data.couchbase.util.ClusterAwareIntegrationTests;
@@ -56,6 +59,7 @@ public class ReactiveCouchbaseRepositoryQueryIntegrationTests extends ClusterAwa
5659
@Autowired CouchbaseClientFactory clientFactory;
5760

5861
@Autowired ReactiveAirportRepository airportRepository; // intellij flags "Could not Autowire", but it runs ok.
62+
@Autowired ReactiveUserRepository userRepository; // intellij flags "Could not Autowire", but it runs ok.
5963

6064
@BeforeEach
6165
void beforeEach() {
@@ -97,6 +101,17 @@ void findBySimpleProperty() {
97101
}
98102
}
99103

104+
@Test
105+
public void testCas() {
106+
User user = new User("1", "Dave", "Wilson");
107+
userRepository.save(user).block();
108+
user.setVersion(user.getVersion() - 1);
109+
assertThrows(DataIntegrityViolationException.class, () -> userRepository.save(user).block());
110+
user.setVersion(0);
111+
userRepository.save(user).block();
112+
userRepository.delete(user).block();
113+
}
114+
100115
@Test
101116
void count() {
102117
String[] iatas = { "JFK", "IAD", "SFO", "SJC", "SEA", "LAX", "PHX" };

0 commit comments

Comments
 (0)