diff --git a/src/main/java/org/springframework/data/couchbase/repository/support/SimpleCouchbaseRepository.java b/src/main/java/org/springframework/data/couchbase/repository/support/SimpleCouchbaseRepository.java index c91235d4b..44d2d39a8 100644 --- a/src/main/java/org/springframework/data/couchbase/repository/support/SimpleCouchbaseRepository.java +++ b/src/main/java/org/springframework/data/couchbase/repository/support/SimpleCouchbaseRepository.java @@ -16,14 +16,7 @@ package org.springframework.data.couchbase.repository.support; -import static org.springframework.data.couchbase.repository.support.Util.hasNonZeroVersionProperty; - -import java.util.Collection; -import java.util.List; -import java.util.Objects; -import java.util.Optional; -import java.util.stream.Collectors; - +import com.couchbase.client.java.query.QueryScanConsistency; import org.springframework.data.couchbase.core.CouchbaseOperations; import org.springframework.data.couchbase.core.query.Query; import org.springframework.data.couchbase.repository.CouchbaseRepository; @@ -36,7 +29,13 @@ import org.springframework.data.util.Streamable; import org.springframework.util.Assert; -import com.couchbase.client.java.query.QueryScanConsistency; +import java.util.Collection; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.stream.Collectors; + +import static org.springframework.data.couchbase.repository.support.Util.hasNonZeroVersionProperty; /** * Repository base implementation for Couchbase. @@ -44,6 +43,7 @@ * @author Michael Nitschinger * @author Mark Paluch * @author Jens Schauder + * @author Jonathan Massuchetti */ public class SimpleCouchbaseRepository implements CouchbaseRepository { @@ -190,7 +190,8 @@ private List findAll(Query query) { } private QueryScanConsistency buildQueryScanConsistency() { - QueryScanConsistency scanConsistency = QueryScanConsistency.NOT_BOUNDED; + QueryScanConsistency scanConsistency = null; + if (crudMethodMetadata.getScanConsistency() != null) { scanConsistency = crudMethodMetadata.getScanConsistency().query(); } diff --git a/src/main/java/org/springframework/data/couchbase/repository/support/SimpleReactiveCouchbaseRepository.java b/src/main/java/org/springframework/data/couchbase/repository/support/SimpleReactiveCouchbaseRepository.java index 7cf8320e5..845d5e1bd 100644 --- a/src/main/java/org/springframework/data/couchbase/repository/support/SimpleReactiveCouchbaseRepository.java +++ b/src/main/java/org/springframework/data/couchbase/repository/support/SimpleReactiveCouchbaseRepository.java @@ -16,15 +16,7 @@ package org.springframework.data.couchbase.repository.support; -import static org.springframework.data.couchbase.repository.support.Util.hasNonZeroVersionProperty; - -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; - -import java.util.List; -import java.util.Objects; -import java.util.stream.Collectors; - +import com.couchbase.client.java.query.QueryScanConsistency; import org.reactivestreams.Publisher; import org.springframework.data.couchbase.core.CouchbaseOperations; import org.springframework.data.couchbase.core.ReactiveCouchbaseOperations; @@ -34,8 +26,14 @@ import org.springframework.data.domain.Sort; import org.springframework.data.util.Streamable; import org.springframework.util.Assert; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; -import com.couchbase.client.java.query.QueryScanConsistency; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +import static org.springframework.data.couchbase.repository.support.Util.hasNonZeroVersionProperty; /** * Reactive repository base implementation for Couchbase. @@ -46,6 +44,7 @@ * @author David Kelly * @author Douglas Six * @author Jens Schauder + * @author Jonathan Massuchetti * @since 3.0 */ public class SimpleReactiveCouchbaseRepository implements ReactiveCouchbaseRepository { @@ -206,7 +205,8 @@ private Flux findAll(Query query) { } private QueryScanConsistency buildQueryScanConsistency() { - QueryScanConsistency scanConsistency = QueryScanConsistency.NOT_BOUNDED; + QueryScanConsistency scanConsistency = null; + if (crudMethodMetadata.getScanConsistency() != null) { scanConsistency = crudMethodMetadata.getScanConsistency().query(); } diff --git a/src/test/java/org/springframework/data/couchbase/domain/AirportDefaultConsistencyRepository.java b/src/test/java/org/springframework/data/couchbase/domain/AirportDefaultConsistencyRepository.java new file mode 100644 index 000000000..a7aa85302 --- /dev/null +++ b/src/test/java/org/springframework/data/couchbase/domain/AirportDefaultConsistencyRepository.java @@ -0,0 +1,32 @@ +/* + * Copyright 2017-2021 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 org.springframework.data.couchbase.repository.CouchbaseRepository; +import org.springframework.stereotype.Repository; + +/** + * Airport repository for testing default consistency
+ * + * @author Jonathan Massuchetti + */ +@Repository +public interface AirportDefaultConsistencyRepository extends CouchbaseRepository { + + Airport iata(String iata); + +} diff --git a/src/test/java/org/springframework/data/couchbase/domain/AirportRepository.java b/src/test/java/org/springframework/data/couchbase/domain/AirportRepository.java index 0265fe7c8..d849d32e3 100644 --- a/src/test/java/org/springframework/data/couchbase/domain/AirportRepository.java +++ b/src/test/java/org/springframework/data/couchbase/domain/AirportRepository.java @@ -43,10 +43,6 @@ @Repository public interface AirportRepository extends CouchbaseRepository { - // NOT_BOUNDED to test ScanConsistency - // @ScanConsistency(query = QueryScanConsistency.NOT_BOUNDED) - Airport iata(String iata); - @Override @ScanConsistency(query = QueryScanConsistency.REQUEST_PLUS) List findAll(); diff --git a/src/test/java/org/springframework/data/couchbase/domain/ReactiveAirportDefaultConsistencyRepository.java b/src/test/java/org/springframework/data/couchbase/domain/ReactiveAirportDefaultConsistencyRepository.java new file mode 100644 index 000000000..2ffbfab4b --- /dev/null +++ b/src/test/java/org/springframework/data/couchbase/domain/ReactiveAirportDefaultConsistencyRepository.java @@ -0,0 +1,42 @@ +/* + * Copyright 2017-2021 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 com.couchbase.client.java.json.JsonArray; +import com.couchbase.client.java.query.QueryScanConsistency; +import org.springframework.data.couchbase.repository.Query; +import org.springframework.data.couchbase.repository.ScanConsistency; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageImpl; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.data.repository.reactive.ReactiveSortingRepository; +import org.springframework.stereotype.Repository; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.util.ArrayList; + +/** + * template class for Reactive Couchbase operations + * + * @author Jonathan Massuchetti + */ +@Repository +public interface ReactiveAirportDefaultConsistencyRepository extends ReactiveSortingRepository { + +} diff --git a/src/test/java/org/springframework/data/couchbase/repository/CouchbaseRepositoryQueryIntegrationTests.java b/src/test/java/org/springframework/data/couchbase/repository/CouchbaseRepositoryQueryIntegrationTests.java index 72ec1bbe8..c9b1af668 100644 --- a/src/test/java/org/springframework/data/couchbase/repository/CouchbaseRepositoryQueryIntegrationTests.java +++ b/src/test/java/org/springframework/data/couchbase/repository/CouchbaseRepositoryQueryIntegrationTests.java @@ -16,30 +16,9 @@ package org.springframework.data.couchbase.repository; -import static com.couchbase.client.java.query.QueryScanConsistency.NOT_BOUNDED; -import static com.couchbase.client.java.query.QueryScanConsistency.REQUEST_PLUS; -import static java.util.Arrays.asList; -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.springframework.data.couchbase.config.BeanNames.COUCHBASE_TEMPLATE; - -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Locale; -import java.util.Optional; -import java.util.concurrent.Callable; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; -import java.util.stream.Collectors; - +import com.couchbase.client.core.error.CouchbaseException; +import com.couchbase.client.core.error.IndexExistsException; +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; @@ -57,15 +36,7 @@ import org.springframework.data.couchbase.core.query.N1QLExpression; import org.springframework.data.couchbase.core.query.Query; import org.springframework.data.couchbase.core.query.QueryCriteria; -import org.springframework.data.couchbase.domain.Address; -import org.springframework.data.couchbase.domain.Airport; -import org.springframework.data.couchbase.domain.AirportRepository; -import org.springframework.data.couchbase.domain.Iata; -import org.springframework.data.couchbase.domain.NaiveAuditorAware; -import org.springframework.data.couchbase.domain.Person; -import org.springframework.data.couchbase.domain.PersonRepository; -import org.springframework.data.couchbase.domain.User; -import org.springframework.data.couchbase.domain.UserRepository; +import org.springframework.data.couchbase.domain.*; import org.springframework.data.couchbase.domain.time.AuditingDateTimeProvider; import org.springframework.data.couchbase.repository.auditing.EnableCouchbaseAuditing; import org.springframework.data.couchbase.repository.config.EnableCouchbaseRepositories; @@ -82,9 +53,24 @@ import org.springframework.data.repository.core.support.DefaultRepositoryMetadata; import org.springframework.test.context.junit.jupiter.SpringJUnitConfig; -import com.couchbase.client.core.error.CouchbaseException; -import com.couchbase.client.core.error.IndexExistsException; -import com.couchbase.client.java.query.QueryScanConsistency; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Locale; +import java.util.Optional; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.stream.Collectors; + +import static com.couchbase.client.java.query.QueryScanConsistency.NOT_BOUNDED; +import static com.couchbase.client.java.query.QueryScanConsistency.REQUEST_PLUS; +import static java.util.Arrays.asList; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.*; +import static org.springframework.data.couchbase.config.BeanNames.COUCHBASE_TEMPLATE; /** * Repository tests @@ -92,6 +78,7 @@ * @author Michael Nitschinger * @author Michael Reiche * @author Jens Schauder + * @author Jonathan Massuchetti */ @SpringJUnitConfig(CouchbaseRepositoryQueryIntegrationTests.Config.class) @IgnoreWhen(missesCapabilities = Capabilities.QUERY, clusterTypes = ClusterType.MOCKED) @@ -101,6 +88,9 @@ public class CouchbaseRepositoryQueryIntegrationTests extends ClusterAwareIntegr @Autowired AirportRepository airportRepository; + @Autowired + AirportDefaultConsistencyRepository airportDefaultConsistencyRepository; + @Autowired UserRepository userRepository; @Autowired CouchbaseTemplate couchbaseTemplate; @@ -212,9 +202,9 @@ public void saveNotBounded() { Airport airport2 = null; for (int i = 1; i <= 100; i++) { // set version == 0 so save() will be an upsert, not a replace - Airport saved = airportRepository.save(vie.clearVersion()); + Airport saved = airportDefaultConsistencyRepository.save(vie.clearVersion()); try { - airport2 = airportRepository.iata(saved.getIata()); + airport2 = airportDefaultConsistencyRepository.iata(saved.getIata()); if (airport2 == null) { break; } @@ -227,14 +217,14 @@ public void saveNotBounded() { assertEquals(vie.getId(), removeResult.getId()); assertTrue(removeResult.getCas() != 0); assertTrue(removeResult.getMutationToken().isPresent()); - Airport airport3 = airportRepository.iata(vie.getIata()); + Airport airport3 = airportDefaultConsistencyRepository.iata(vie.getIata()); assertNull(airport3, "should have been removed"); } } assertNull(airport2, "airport2 should have likely been null at least once"); - Airport saved = airportRepository.save(vie.clearVersion()); + Airport saved = airportDefaultConsistencyRepository.save(vie.clearVersion()); couchbaseTemplate.findByQuery(Airport.class).withConsistency(REQUEST_PLUS).all(); - airport2 = airportRepository.iata(vie.getIata()); + airport2 = airportDefaultConsistencyRepository.iata(vie.getIata()); RemoveResult removeResult = couchbaseTemplate.removeById().one(saved.getId()); assertNotNull(airport2, "airport2 should have been found"); } @@ -244,7 +234,7 @@ public void saveNotBoundedRequestPlus() { ApplicationContext ac = new AnnotationConfigApplicationContext(ConfigRequestPlus.class); // the Config class has been modified, these need to be loaded again CouchbaseTemplate couchbaseTemplateRP = (CouchbaseTemplate) ac.getBean(COUCHBASE_TEMPLATE); - AirportRepository airportRepositoryRP = (AirportRepository) ac.getBean("airportRepository"); + AirportDefaultConsistencyRepository airportRepositoryRP = (AirportDefaultConsistencyRepository) ac.getBean("airportDefaultConsistencyRepository"); // save() followed by query with NOT_BOUNDED will result in not finding the document Airport vie = new Airport("airports::vie", "vie", "low9"); @@ -277,6 +267,28 @@ public void saveNotBoundedRequestPlus() { assertFalse(!airports.isEmpty(), "airports should have been empty"); } + @Test + public void saveNotBoundedRequestPlusWithDefaultRepository() { + ApplicationContext ac = new AnnotationConfigApplicationContext(ConfigRequestPlus.class); + // the Config class has been modified, these need to be loaded again + CouchbaseTemplate couchbaseTemplateRP = (CouchbaseTemplate) ac.getBean(COUCHBASE_TEMPLATE); + AirportDefaultConsistencyRepository airportRepositoryRP = (AirportDefaultConsistencyRepository) ac.getBean("airportDefaultConsistencyRepository"); + + List sizeBeforeTest = airportRepositoryRP.findAll(); + assertEquals(0, sizeBeforeTest.size()); + + for (int i = 1; i <= 100; i++) { + Airport vie = new Airport("airports::vie" + i, "vie" + i, "low9"); + airportRepositoryRP.save(vie); + } + + List allSaved = airportRepositoryRP.findAll(); + + airportRepository.deleteAll(); + + assertEquals(100, allSaved.size()); + } + @Test void findByTypeAlias() { Airport vie = null; diff --git a/src/test/java/org/springframework/data/couchbase/repository/ReactiveCouchbaseRepositoryQueryIntegrationTests.java b/src/test/java/org/springframework/data/couchbase/repository/ReactiveCouchbaseRepositoryQueryIntegrationTests.java index ed07c651c..1823f8ff3 100644 --- a/src/test/java/org/springframework/data/couchbase/repository/ReactiveCouchbaseRepositoryQueryIntegrationTests.java +++ b/src/test/java/org/springframework/data/couchbase/repository/ReactiveCouchbaseRepositoryQueryIntegrationTests.java @@ -16,35 +16,19 @@ package org.springframework.data.couchbase.repository; -import static java.util.Arrays.asList; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; -import reactor.test.StepVerifier; - -import java.time.Instant; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.UUID; -import java.util.concurrent.Callable; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; -import java.util.stream.Collectors; - +import com.couchbase.client.java.query.QueryScanConsistency; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Configuration; import org.springframework.dao.DataIntegrityViolationException; import org.springframework.dao.DataRetrievalFailureException; import org.springframework.data.couchbase.CouchbaseClientFactory; import org.springframework.data.couchbase.config.AbstractCouchbaseConfiguration; +import org.springframework.data.couchbase.core.ReactiveCouchbaseTemplate; import org.springframework.data.couchbase.domain.Airport; +import org.springframework.data.couchbase.domain.ReactiveAirportDefaultConsistencyRepository; import org.springframework.data.couchbase.domain.ReactiveAirportRepository; import org.springframework.data.couchbase.domain.ReactiveUserRepository; import org.springframework.data.couchbase.domain.User; @@ -55,12 +39,32 @@ import org.springframework.data.couchbase.util.JavaIntegrationTests; import org.springframework.data.domain.PageRequest; import org.springframework.test.context.junit.jupiter.SpringJUnitConfig; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; +import reactor.test.StepVerifier; + +import java.time.Instant; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.stream.Collectors; + +import static com.couchbase.client.java.query.QueryScanConsistency.REQUEST_PLUS; +import static java.util.Arrays.asList; +import static org.junit.jupiter.api.Assertions.*; +import static org.springframework.data.couchbase.config.BeanNames.REACTIVE_COUCHBASE_TEMPLATE; /** * template class for Reactive Couchbase operations * * @author Michael Nitschinger * @author Michael Reiche + * @author Jonathan Massuchetti */ @SpringJUnitConfig(ReactiveCouchbaseRepositoryQueryIntegrationTests.Config.class) @IgnoreWhen(missesCapabilities = Capabilities.QUERY, clusterTypes = ClusterType.MOCKED) @@ -249,6 +253,28 @@ void deleteAll() { } } + @Test + public void saveNotBoundedRequestPlusWithDefaultRepository() { + ApplicationContext ac = new AnnotationConfigApplicationContext(ConfigRequestPlus.class); + // the Config class has been modified, these need to be loaded again + ReactiveCouchbaseTemplate couchbaseTemplateRP = (ReactiveCouchbaseTemplate) ac.getBean(REACTIVE_COUCHBASE_TEMPLATE); + ReactiveAirportDefaultConsistencyRepository airportRepositoryRP = (ReactiveAirportDefaultConsistencyRepository) ac.getBean("reactiveAirportDefaultConsistencyRepository"); + + List sizeBeforeTest = airportRepositoryRP.findAll().collectList().block(); + assertEquals(0, sizeBeforeTest.size()); + + for (int i = 1; i <= 100; i++) { + Airport vie = new Airport("airports::vie" + i, "vie" + i, "low9"); + airportRepositoryRP.save(vie).block(); + } + + List allSaved = airportRepositoryRP.findAll().collectList().block(); + + airportRepository.deleteAll().block(); + + assertEquals(100, allSaved.size()); + } + @Configuration @EnableReactiveCouchbaseRepositories("org.springframework.data.couchbase") static class Config extends AbstractCouchbaseConfiguration { @@ -275,4 +301,33 @@ public String getBucketName() { } + @Configuration + @EnableReactiveCouchbaseRepositories("org.springframework.data.couchbase") + static class ConfigRequestPlus extends AbstractCouchbaseConfiguration { + + @Override + public String getConnectionString() { + return connectionString(); + } + + @Override + public String getUserName() { + return config().adminUsername(); + } + + @Override + public String getPassword() { + return config().adminPassword(); + } + + @Override + public String getBucketName() { + return bucketName(); + } + + @Override + public QueryScanConsistency getDefaultConsistency() { + return REQUEST_PLUS; + } + } }