Skip to content

Commit 5933a82

Browse files
committed
Reinstate the getDefaultConsistency() method in the Configuration.
Closes #1243.
1 parent 37648c8 commit 5933a82

File tree

9 files changed

+151
-19
lines changed

9 files changed

+151
-19
lines changed

src/main/java/org/springframework/data/couchbase/config/AbstractCouchbaseConfiguration.java

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
import com.couchbase.client.java.env.ClusterEnvironment;
5858
import com.couchbase.client.java.json.JacksonTransformers;
5959
import com.couchbase.client.java.json.JsonValueModule;
60+
import com.couchbase.client.java.query.QueryScanConsistency;
6061
import com.fasterxml.jackson.databind.ObjectMapper;
6162

6263
/**
@@ -156,7 +157,8 @@ protected void configureEnvironment(final ClusterEnvironment.Builder builder) {
156157
@Bean(name = BeanNames.COUCHBASE_TEMPLATE)
157158
public CouchbaseTemplate couchbaseTemplate(CouchbaseClientFactory couchbaseClientFactory,
158159
MappingCouchbaseConverter mappingCouchbaseConverter, TranslationService couchbaseTranslationService) {
159-
return new CouchbaseTemplate(couchbaseClientFactory, mappingCouchbaseConverter, couchbaseTranslationService);
160+
return new CouchbaseTemplate(couchbaseClientFactory, mappingCouchbaseConverter, couchbaseTranslationService,
161+
getDefaultConsistency());
160162
}
161163

162164
public CouchbaseTemplate couchbaseTemplate(CouchbaseClientFactory couchbaseClientFactory,
@@ -167,8 +169,8 @@ public CouchbaseTemplate couchbaseTemplate(CouchbaseClientFactory couchbaseClien
167169
@Bean(name = BeanNames.REACTIVE_COUCHBASE_TEMPLATE)
168170
public ReactiveCouchbaseTemplate reactiveCouchbaseTemplate(CouchbaseClientFactory couchbaseClientFactory,
169171
MappingCouchbaseConverter mappingCouchbaseConverter, TranslationService couchbaseTranslationService) {
170-
return new ReactiveCouchbaseTemplate(couchbaseClientFactory, mappingCouchbaseConverter,
171-
couchbaseTranslationService);
172+
return new ReactiveCouchbaseTemplate(couchbaseClientFactory, mappingCouchbaseConverter, couchbaseTranslationService,
173+
getDefaultConsistency());
172174
}
173175

174176
public ReactiveCouchbaseTemplate reactiveCouchbaseTemplate(CouchbaseClientFactory couchbaseClientFactory,
@@ -376,4 +378,8 @@ private boolean nonShadowedJacksonPresent() {
376378
}
377379
}
378380

381+
public QueryScanConsistency getDefaultConsistency() {
382+
return null;
383+
}
384+
379385
}

src/main/java/org/springframework/data/couchbase/core/CouchbaseOperations.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
import org.springframework.data.couchbase.CouchbaseClientFactory;
2020
import org.springframework.data.couchbase.core.convert.CouchbaseConverter;
2121

22+
import com.couchbase.client.java.query.QueryScanConsistency;
23+
2224
/**
2325
* Defines common operations on the Couchbase data source, most commonly implemented by {@link CouchbaseTemplate}.
2426
*/
@@ -44,4 +46,8 @@ public interface CouchbaseOperations extends FluentCouchbaseOperations {
4446
*/
4547
CouchbaseClientFactory getCouchbaseClientFactory();
4648

49+
/**
50+
* Returns the default consistency to use for queries
51+
*/
52+
QueryScanConsistency getConsistency();
4753
}

src/main/java/org/springframework/data/couchbase/core/CouchbaseTemplate.java

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import org.springframework.lang.Nullable;
3333

3434
import com.couchbase.client.java.Collection;
35+
import com.couchbase.client.java.query.QueryScanConsistency;
3536

3637
/**
3738
* Implements lower-level couchbase operations on top of the SDK with entity mapping capabilities.
@@ -49,18 +50,25 @@ public class CouchbaseTemplate implements CouchbaseOperations, ApplicationContex
4950
private final MappingContext<? extends CouchbasePersistentEntity<?>, CouchbasePersistentProperty> mappingContext;
5051
private final ReactiveCouchbaseTemplate reactiveCouchbaseTemplate;
5152
private @Nullable CouchbasePersistentEntityIndexCreator indexCreator;
53+
private QueryScanConsistency scanConsistency;
5254

5355
public CouchbaseTemplate(final CouchbaseClientFactory clientFactory, final CouchbaseConverter converter) {
5456
this(clientFactory, converter, new JacksonTranslationService());
5557
}
5658

5759
public CouchbaseTemplate(final CouchbaseClientFactory clientFactory, final CouchbaseConverter converter,
5860
final TranslationService translationService) {
61+
this(clientFactory, converter, translationService, null);
62+
}
63+
64+
public CouchbaseTemplate(final CouchbaseClientFactory clientFactory, final CouchbaseConverter converter,
65+
final TranslationService translationService, QueryScanConsistency scanConsistency) {
5966
this.clientFactory = clientFactory;
6067
this.converter = converter;
6168
this.templateSupport = new CouchbaseTemplateSupport(this, converter, translationService);
62-
this.reactiveCouchbaseTemplate = new ReactiveCouchbaseTemplate(clientFactory, converter, translationService);
63-
69+
this.reactiveCouchbaseTemplate = new ReactiveCouchbaseTemplate(clientFactory, converter, translationService,
70+
scanConsistency);
71+
this.scanConsistency = scanConsistency;
6472
this.mappingContext = this.converter.getMappingContext();
6573
if (mappingContext instanceof CouchbaseMappingContext) {
6674
CouchbaseMappingContext cmc = (CouchbaseMappingContext) mappingContext;
@@ -147,6 +155,11 @@ public CouchbaseClientFactory getCouchbaseClientFactory() {
147155
return clientFactory;
148156
}
149157

158+
@Override
159+
public QueryScanConsistency getConsistency() {
160+
return scanConsistency;
161+
}
162+
150163
/**
151164
* Provides access to a {@link Collection} on the configured {@link CouchbaseClientFactory}.
152165
*

src/main/java/org/springframework/data/couchbase/core/ReactiveCouchbaseOperations.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
import org.springframework.data.couchbase.CouchbaseClientFactory;
1919
import org.springframework.data.couchbase.core.convert.CouchbaseConverter;
2020

21+
import com.couchbase.client.java.query.QueryScanConsistency;
22+
2123
/**
2224
* Defines common operations on the Couchbase data source, most commonly implemented by
2325
* {@link ReactiveCouchbaseTemplate}.
@@ -47,4 +49,8 @@ public interface ReactiveCouchbaseOperations extends ReactiveFluentCouchbaseOper
4749
*/
4850
CouchbaseClientFactory getCouchbaseClientFactory();
4951

52+
/**
53+
* @return the default consistency to use for queries
54+
*/
55+
QueryScanConsistency getConsistency();
5056
}

src/main/java/org/springframework/data/couchbase/core/ReactiveCouchbaseTemplate.java

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import org.springframework.data.couchbase.core.support.PseudoArgs;
2929

3030
import com.couchbase.client.java.Collection;
31+
import com.couchbase.client.java.query.QueryScanConsistency;
3132

3233
/**
3334
* template class for Reactive Couchbase operations
@@ -43,18 +44,25 @@ public class ReactiveCouchbaseTemplate implements ReactiveCouchbaseOperations, A
4344
private final CouchbaseConverter converter;
4445
private final PersistenceExceptionTranslator exceptionTranslator;
4546
private final ReactiveCouchbaseTemplateSupport templateSupport;
46-
private ThreadLocal<PseudoArgs<?>> threadLocalArgs = null;
47+
private ThreadLocal<PseudoArgs<?>> threadLocalArgs = new ThreadLocal<>();
48+
private QueryScanConsistency scanConsistency;
4749

4850
public ReactiveCouchbaseTemplate(final CouchbaseClientFactory clientFactory, final CouchbaseConverter converter) {
4951
this(clientFactory, converter, new JacksonTranslationService());
5052
}
5153

5254
public ReactiveCouchbaseTemplate(final CouchbaseClientFactory clientFactory, final CouchbaseConverter converter,
5355
final TranslationService translationService) {
56+
this(clientFactory, converter, translationService, null);
57+
}
58+
59+
public ReactiveCouchbaseTemplate(final CouchbaseClientFactory clientFactory, final CouchbaseConverter converter,
60+
final TranslationService translationService, QueryScanConsistency scanConsistency) {
5461
this.clientFactory = clientFactory;
5562
this.converter = converter;
5663
this.exceptionTranslator = clientFactory.getExceptionTranslator();
5764
this.templateSupport = new ReactiveCouchbaseTemplateSupport(this, converter, translationService);
65+
this.scanConsistency = scanConsistency;
5866
}
5967

6068
@Override
@@ -182,4 +190,12 @@ public void setPseudoArgs(PseudoArgs<?> threadLocalArgs) {
182190
this.threadLocalArgs.set(threadLocalArgs);
183191
}
184192

193+
/**
194+
* {@inheritDoc}
195+
*/
196+
@Override
197+
public QueryScanConsistency getConsistency() {
198+
return scanConsistency;
199+
}
200+
185201
}

src/main/java/org/springframework/data/couchbase/core/ReactiveFindByQueryOperationSupport.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -206,8 +206,9 @@ public Flux<T> all() {
206206
}));
207207
}
208208

209-
private QueryOptions buildOptions(QueryOptions options) {
210-
QueryOptions opts = query.buildQueryOptions(options, scanConsistency);
209+
public QueryOptions buildOptions(QueryOptions options) {
210+
QueryScanConsistency qsc = scanConsistency != null ? scanConsistency : template.getConsistency();
211+
QueryOptions opts = query.buildQueryOptions(options, qsc);
211212
return opts;
212213
}
213214

src/main/java/org/springframework/data/couchbase/core/ReactiveRemoveByQueryOperationSupport.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,8 @@ public Flux<RemoveResult> all() {
9090
}
9191

9292
private QueryOptions buildQueryOptions(QueryOptions options) {
93-
return query.buildQueryOptions(options, scanConsistency);
93+
QueryScanConsistency qsc = scanConsistency != null ? scanConsistency : template.getConsistency();
94+
return query.buildQueryOptions(options, qsc);
9495
}
9596

9697
@Override

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,6 @@
6060
// @ScanConsistency(query = QueryScanConsistency.REQUEST_PLUS)
6161
public interface AirportRepository extends CouchbaseRepository<Airport, String>, DynamicProxyable<AirportRepository> {
6262

63-
// override an annotate with REQUEST_PLUS
6463
@Override
6564
@ScanConsistency(query = QueryScanConsistency.REQUEST_PLUS)
6665
List<Airport> findAll();

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

Lines changed: 93 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616

1717
package org.springframework.data.couchbase.repository;
1818

19+
import static com.couchbase.client.java.query.QueryScanConsistency.NOT_BOUNDED;
20+
import static com.couchbase.client.java.query.QueryScanConsistency.REQUEST_PLUS;
1921
import static java.util.Arrays.asList;
2022
import static org.assertj.core.api.Assertions.assertThat;
2123
import static org.junit.jupiter.api.Assertions.assertEquals;
@@ -25,6 +27,7 @@
2527
import static org.junit.jupiter.api.Assertions.assertNull;
2628
import static org.junit.jupiter.api.Assertions.assertThrows;
2729
import static org.junit.jupiter.api.Assertions.assertTrue;
30+
import static org.springframework.data.couchbase.config.BeanNames.COUCHBASE_TEMPLATE;
2831

2932
import junit.framework.AssertionFailedError;
3033

@@ -46,6 +49,8 @@
4649

4750
import org.junit.jupiter.api.Test;
4851
import org.springframework.beans.factory.annotation.Autowired;
52+
import org.springframework.context.ApplicationContext;
53+
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
4954
import org.springframework.context.annotation.Bean;
5055
import org.springframework.context.annotation.Configuration;
5156
import org.springframework.dao.DataIntegrityViolationException;
@@ -267,6 +272,44 @@ void findBySimplePropertyReturnType() {
267272
}
268273
}
269274

275+
@Test
276+
public void saveNotBoundedRequestPlus() {
277+
ApplicationContext ac = new AnnotationConfigApplicationContext(ConfigRequestPlus.class);
278+
// the Config class has been modified, these need to be loaded again
279+
CouchbaseTemplate couchbaseTemplateRP = (CouchbaseTemplate) ac.getBean(COUCHBASE_TEMPLATE);
280+
AirportRepository airportRepositoryRP = (AirportRepository) ac.getBean("airportRepository");
281+
282+
// save() followed by query with NOT_BOUNDED will result in not finding the document
283+
Airport vie = new Airport("airports::vie", "vie", "low9");
284+
Airport airport2 = null;
285+
for (int i = 1; i <= 100; i++) {
286+
// set version == 0 so save() will be an upsert, not a replace
287+
Airport saved = airportRepositoryRP.save(vie.clearVersion());
288+
try {
289+
airport2 = airportRepositoryRP.iata(saved.getIata());
290+
if (airport2 == null) {
291+
break;
292+
}
293+
} catch (DataRetrievalFailureException drfe) {
294+
airport2 = null; //
295+
} finally {
296+
// airportRepository.delete(vie);
297+
// instead of delete, use removeResult to test QueryOptions.consistentWith()
298+
RemoveResult removeResult = couchbaseTemplateRP.removeById().one(vie.getId());
299+
assertEquals(vie.getId(), removeResult.getId());
300+
assertTrue(removeResult.getCas() != 0);
301+
assertTrue(removeResult.getMutationToken().isPresent());
302+
Airport airport3 = airportRepositoryRP.iata(vie.getIata());
303+
assertNull(airport3, "should have been removed");
304+
}
305+
}
306+
assertNotNull(airport2, "airport2 should have never been null");
307+
Airport saved = airportRepositoryRP.save(vie.clearVersion());
308+
List<Airport> airports = couchbaseTemplateRP.findByQuery(Airport.class).withConsistency(NOT_BOUNDED).all();
309+
RemoveResult removeResult = couchbaseTemplateRP.removeById().one(saved.getId());
310+
assertFalse(!airports.isEmpty(), "airports should have been empty");
311+
}
312+
270313
@Test
271314
void findByTypeAlias() {
272315
Airport vie = null;
@@ -386,9 +429,7 @@ public void saveNotBounded() {
386429
// set version == 0 so save() will be an upsert, not a replace
387430
Airport saved = airportRepository.save(vie.clearVersion());
388431
try {
389-
airport2 = airportRepository
390-
.withOptions(QueryOptions.queryOptions().scanConsistency(QueryScanConsistency.NOT_BOUNDED))
391-
.iata(saved.getIata());
432+
airport2 = airportRepository.iata(saved.getIata());
392433
if (airport2 == null) {
393434
break;
394435
}
@@ -401,14 +442,16 @@ public void saveNotBounded() {
401442
assertEquals(vie.getId(), removeResult.getId());
402443
assertTrue(removeResult.getCas() != 0);
403444
assertTrue(removeResult.getMutationToken().isPresent());
404-
Airport airport3 = airportRepository
405-
.withOptions(QueryOptions.queryOptions().scanConsistency(QueryScanConsistency.REQUEST_PLUS)
406-
.consistentWith(MutationState.from(removeResult.getMutationToken().get())))
407-
.iata(vie.getIata());
445+
Airport airport3 = airportRepository.iata(vie.getIata());
408446
assertNull(airport3, "should have been removed");
409447
}
410448
}
411449
assertNull(airport2, "airport2 should have likely been null at least once");
450+
Airport saved = airportRepository.save(vie.clearVersion());
451+
couchbaseTemplate.findByQuery(Airport.class).withConsistency(REQUEST_PLUS).all();
452+
airport2 = airportRepository.iata(vie.getIata());
453+
RemoveResult removeResult = couchbaseTemplate.removeById().one(saved.getId());
454+
assertNotNull(airport2, "airport2 should have been found");
412455
}
413456

414457
@Test
@@ -474,7 +517,7 @@ void count() {
474517
airportRepository.saveAll(
475518
Arrays.stream(iatas).map((iata) -> new Airport("airports::" + iata, iata, iata.toLowerCase(Locale.ROOT)))
476519
.collect(Collectors.toSet()));
477-
couchbaseTemplate.findByQuery(Airport.class).withConsistency(QueryScanConsistency.REQUEST_PLUS).all();
520+
couchbaseTemplate.findByQuery(Airport.class).withConsistency(REQUEST_PLUS).all();
478521
Long count = airportRepository.countFancyExpression(asList("JFK"), asList("jfk"), false);
479522
assertEquals(1, count);
480523

@@ -677,7 +720,7 @@ void deleteAllById() {
677720
void couchbaseRepositoryQuery() throws Exception {
678721
User user = new User("1", "Dave", "Wilson");
679722
userRepository.save(user);
680-
couchbaseTemplate.findByQuery(User.class).withConsistency(QueryScanConsistency.REQUEST_PLUS)
723+
couchbaseTemplate.findByQuery(User.class).withConsistency(REQUEST_PLUS)
681724
.matching(QueryCriteria.where("firstname").is("Dave").and("`1`").is("`1`")).all();
682725
String input = "findByFirstname";
683726
Method method = UserRepository.class.getMethod(input, String.class);
@@ -809,4 +852,45 @@ public ValidatingCouchbaseEventListener validationEventListener() {
809852
return new ValidatingCouchbaseEventListener(validator());
810853
}
811854
}
855+
856+
@Configuration
857+
@EnableCouchbaseRepositories("org.springframework.data.couchbase")
858+
@EnableCouchbaseAuditing(auditorAwareRef = "auditorAwareRef", dateTimeProviderRef = "dateTimeProviderRef")
859+
static class ConfigRequestPlus extends AbstractCouchbaseConfiguration {
860+
861+
@Override
862+
public String getConnectionString() {
863+
return connectionString();
864+
}
865+
866+
@Override
867+
public String getUserName() {
868+
return config().adminUsername();
869+
}
870+
871+
@Override
872+
public String getPassword() {
873+
return config().adminPassword();
874+
}
875+
876+
@Override
877+
public String getBucketName() {
878+
return bucketName();
879+
}
880+
881+
@Bean(name = "auditorAwareRef")
882+
public NaiveAuditorAware testAuditorAware() {
883+
return new NaiveAuditorAware();
884+
}
885+
886+
@Bean(name = "dateTimeProviderRef")
887+
public DateTimeProvider testDateTimeProvider() {
888+
return new AuditingDateTimeProvider();
889+
}
890+
891+
@Override
892+
public QueryScanConsistency getDefaultConsistency() {
893+
return REQUEST_PLUS;
894+
}
895+
}
812896
}

0 commit comments

Comments
 (0)