From 3f15c10b8ffce5172c5efc20c3102bf28cfe6bc0 Mon Sep 17 00:00:00 2001 From: Michael Reiche <48999328+mikereiche@users.noreply.github.com> Date: Thu, 16 Jun 2022 15:20:40 -0700 Subject: [PATCH 1/2] Fix 1441 in 4_4_x - scope and collection not considered in repo delete. This is a more localized change than the one in main. Closes #1464. --- .../query/AbstractCouchbaseQuery.java | 6 +- .../query/AbstractReactiveCouchbaseQuery.java | 19 ++-- .../query/CouchbaseQueryExecution.java | 15 ++-- .../ReactiveCouchbaseQueryExecution.java | 14 ++- .../couchbase/domain/AirportRepository.java | 5 ++ .../domain/AirportRepositoryAnnotated.java | 26 ++++++ .../data/couchbase/domain/FluxTest.java | 10 +-- .../domain/ReactiveAirportRepository.java | 13 ++- .../ReactiveAirportRepositoryAnnotated.java | 26 ++++++ ...aseRepositoryKeyValueIntegrationTests.java | 8 +- ...chbaseRepositoryQueryIntegrationTests.java | 87 +++++++++--------- ...sitoryQueryCollectionIntegrationTests.java | 88 ++++++++++++++----- ...sitoryQueryCollectionIntegrationTests.java | 87 +++++++++++++++--- .../util/ClusterAwareIntegrationTests.java | 13 +++ 14 files changed, 304 insertions(+), 113 deletions(-) create mode 100644 src/test/java/org/springframework/data/couchbase/domain/AirportRepositoryAnnotated.java create mode 100644 src/test/java/org/springframework/data/couchbase/domain/ReactiveAirportRepositoryAnnotated.java diff --git a/src/main/java/org/springframework/data/couchbase/repository/query/AbstractCouchbaseQuery.java b/src/main/java/org/springframework/data/couchbase/repository/query/AbstractCouchbaseQuery.java index 4174eef53..989256a6e 100644 --- a/src/main/java/org/springframework/data/couchbase/repository/query/AbstractCouchbaseQuery.java +++ b/src/main/java/org/springframework/data/couchbase/repository/query/AbstractCouchbaseQuery.java @@ -19,6 +19,7 @@ import org.springframework.data.couchbase.core.CouchbaseOperations; import org.springframework.data.couchbase.core.ExecutableFindByQueryOperation.ExecutableFindByQuery; import org.springframework.data.couchbase.core.ExecutableFindByQueryOperation.TerminatingFindByQuery; +import org.springframework.data.couchbase.core.ExecutableRemoveByQueryOperation.ExecutableRemoveByQuery; import org.springframework.data.couchbase.core.query.Query; import org.springframework.data.couchbase.repository.query.CouchbaseQueryExecution.DeleteExecution; import org.springframework.data.couchbase.repository.query.CouchbaseQueryExecution.PagedExecution; @@ -43,6 +44,7 @@ public abstract class AbstractCouchbaseQuery extends AbstractCouchbaseQueryBase< implements RepositoryQuery { private final ExecutableFindByQuery findOperationWithProjection; + private final ExecutableRemoveByQuery removeOp; /** * Creates a new {@link AbstractCouchbaseQuery} from the given {@link ReactiveCouchbaseQueryMethod} and @@ -65,6 +67,8 @@ public AbstractCouchbaseQuery(CouchbaseQueryMethod method, CouchbaseOperations o ExecutableFindByQuery findOp = operations.findByQuery(type); findOp = (ExecutableFindByQuery) (findOp.inScope(method.getScope()).inCollection(method.getCollection())); this.findOperationWithProjection = findOp; + this.removeOp = (ExecutableRemoveByQuery) (operations.removeByQuery(type).inScope(method.getScope()) + .inCollection(method.getCollection())); } /** @@ -114,7 +118,7 @@ private CouchbaseQueryExecution getExecution(ParameterAccessor accessor, Convert private CouchbaseQueryExecution getExecutionToWrap(ParameterAccessor accessor, ExecutableFindByQuery operation) { if (isDeleteQuery()) { - return new DeleteExecution(getOperations(), getQueryMethod()); + return new DeleteExecution(removeOp); } else if (isTailable(getQueryMethod())) { return (q, t, r, c) -> operation.as(r).matching(q.with(accessor.getPageable())).all(); // s/b tail() instead of // all() diff --git a/src/main/java/org/springframework/data/couchbase/repository/query/AbstractReactiveCouchbaseQuery.java b/src/main/java/org/springframework/data/couchbase/repository/query/AbstractReactiveCouchbaseQuery.java index 878e44a8b..c9a32a7e7 100644 --- a/src/main/java/org/springframework/data/couchbase/repository/query/AbstractReactiveCouchbaseQuery.java +++ b/src/main/java/org/springframework/data/couchbase/repository/query/AbstractReactiveCouchbaseQuery.java @@ -1,5 +1,5 @@ /* - * Copyright 2020-2021 the original author or authors. + * Copyright 2020-2022 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. @@ -19,6 +19,7 @@ import org.springframework.data.couchbase.core.ReactiveCouchbaseOperations; import org.springframework.data.couchbase.core.ReactiveFindByQueryOperation; import org.springframework.data.couchbase.core.ReactiveFindByQueryOperation.ReactiveFindByQuery; +import org.springframework.data.couchbase.core.ReactiveRemoveByQueryOperation.ReactiveRemoveByQuery; import org.springframework.data.couchbase.core.query.Query; import org.springframework.data.couchbase.repository.query.ReactiveCouchbaseQueryExecution.DeleteExecution; import org.springframework.data.couchbase.repository.query.ReactiveCouchbaseQueryExecution.ResultProcessingExecution; @@ -41,7 +42,8 @@ public abstract class AbstractReactiveCouchbaseQuery extends AbstractCouchbaseQueryBase implements RepositoryQuery { - private final ReactiveFindByQuery findOperationWithProjection; + private final ReactiveFindByQuery findOp; + private final ReactiveRemoveByQuery removeOp; /** * Creates a new {@link AbstractReactiveCouchbaseQuery} from the given {@link ReactiveCouchbaseQueryMethod} and @@ -62,9 +64,10 @@ public AbstractReactiveCouchbaseQuery(ReactiveCouchbaseQueryMethod method, React EntityMetadata metadata = method.getEntityInformation(); Class type = metadata.getJavaType(); - ReactiveFindByQuery findOp = operations.findByQuery(type); - findOp = (ReactiveFindByQuery) (findOp.inScope(method.getScope()).inCollection(method.getCollection())); - this.findOperationWithProjection = findOp; + this.findOp = (ReactiveFindByQuery) (operations.findByQuery(type).inScope(method.getScope()) + .inCollection(method.getCollection())); + this.removeOp = (ReactiveRemoveByQuery) (operations.removeByQuery(type).inScope(method.getScope()) + .inCollection(method.getCollection())); } /** @@ -83,10 +86,8 @@ protected Object doExecute(CouchbaseQueryMethod method, ResultProcessor processo // query = applyAnnotatedCollationIfPresent(query, accessor); // not yet implemented query = applyQueryMetaAttributesIfPresent(query, typeToRead); - ReactiveFindByQuery find = findOperationWithProjection; - ReactiveCouchbaseQueryExecution execution = getExecution(accessor, - new ResultProcessingConverter<>(processor, getOperations(), getInstantiators()), find); + new ResultProcessingConverter<>(processor, getOperations(), getInstantiators()), findOp); return execution.execute(query, processor.getReturnedType().getDomainType(), typeToRead, null); } @@ -113,7 +114,7 @@ private ReactiveCouchbaseQueryExecution getExecutionToWrap(ParameterAccessor acc ReactiveFindByQuery operation) { if (isDeleteQuery()) { - return new DeleteExecution(getOperations(), getQueryMethod()); + return new DeleteExecution(removeOp); } else if (isTailable(getQueryMethod())) { return (q, t, r, c) -> operation.as(r).matching(q.with(accessor.getPageable())).all(); // s/b tail() instead of // all() diff --git a/src/main/java/org/springframework/data/couchbase/repository/query/CouchbaseQueryExecution.java b/src/main/java/org/springframework/data/couchbase/repository/query/CouchbaseQueryExecution.java index a2204879e..3205f46e7 100644 --- a/src/main/java/org/springframework/data/couchbase/repository/query/CouchbaseQueryExecution.java +++ b/src/main/java/org/springframework/data/couchbase/repository/query/CouchbaseQueryExecution.java @@ -1,5 +1,5 @@ /* - * Copyright 2020 the original author or authors. + * Copyright 2020-2022 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. @@ -18,15 +18,14 @@ import java.util.List; import org.springframework.core.convert.converter.Converter; -import org.springframework.data.couchbase.core.CouchbaseOperations; import org.springframework.data.couchbase.core.ExecutableFindByQueryOperation.ExecutableFindByQuery; import org.springframework.data.couchbase.core.ExecutableFindByQueryOperation.TerminatingFindByQuery; +import org.springframework.data.couchbase.core.ExecutableRemoveByQueryOperation.ExecutableRemoveByQuery; import org.springframework.data.couchbase.core.query.Query; import org.springframework.data.domain.PageImpl; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Slice; import org.springframework.data.domain.SliceImpl; -import org.springframework.data.repository.query.QueryMethod; import org.springframework.util.Assert; /** @@ -47,12 +46,10 @@ interface CouchbaseQueryExecution { final class DeleteExecution implements CouchbaseQueryExecution { - private final CouchbaseOperations operations; - private final QueryMethod method; + private final ExecutableRemoveByQuery removeOperation; - public DeleteExecution(CouchbaseOperations operations, QueryMethod method) { - this.operations = operations; - this.method = method; + public DeleteExecution(ExecutableRemoveByQuery removeOperation) { + this.removeOperation = removeOperation; } /* @@ -61,7 +58,7 @@ public DeleteExecution(CouchbaseOperations operations, QueryMethod method) { */ @Override public Object execute(Query query, Class type, Class returnType, String collection) { - return operations.removeByQuery(type).matching(query).all(); + return removeOperation.matching(query).all(); } } diff --git a/src/main/java/org/springframework/data/couchbase/repository/query/ReactiveCouchbaseQueryExecution.java b/src/main/java/org/springframework/data/couchbase/repository/query/ReactiveCouchbaseQueryExecution.java index 7194c6951..ab5361d29 100644 --- a/src/main/java/org/springframework/data/couchbase/repository/query/ReactiveCouchbaseQueryExecution.java +++ b/src/main/java/org/springframework/data/couchbase/repository/query/ReactiveCouchbaseQueryExecution.java @@ -1,5 +1,5 @@ /* - * Copyright 2020 the original author or authors. + * Copyright 2020-2022 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. @@ -16,7 +16,7 @@ package org.springframework.data.couchbase.repository.query; import org.springframework.core.convert.converter.Converter; -import org.springframework.data.couchbase.core.ReactiveCouchbaseOperations; +import org.springframework.data.couchbase.core.ReactiveRemoveByQueryOperation; import org.springframework.data.couchbase.core.query.Query; import org.springframework.util.Assert; @@ -39,12 +39,10 @@ interface ReactiveCouchbaseQueryExecution { final class DeleteExecution implements ReactiveCouchbaseQueryExecution { - private final ReactiveCouchbaseOperations operations; - private final CouchbaseQueryMethod method; + private final ReactiveRemoveByQueryOperation.ReactiveRemoveByQuery removeOp; - public DeleteExecution(ReactiveCouchbaseOperations operations, CouchbaseQueryMethod method) { - this.operations = operations; - this.method = method; + public DeleteExecution(ReactiveRemoveByQueryOperation.ReactiveRemoveByQuery removeOp) { + this.removeOp = removeOp; } /* @@ -53,7 +51,7 @@ public DeleteExecution(ReactiveCouchbaseOperations operations, CouchbaseQueryMet */ @Override public Object execute(Query query, Class type, Class returnType, String collection) { - return operations.removeByQuery(type)/*.inCollection(collection)*/.matching(query).all(); + return removeOp.matching(query).all(); } } 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 9a66f5efa..16b73f53d 100644 --- a/src/test/java/org/springframework/data/couchbase/domain/AirportRepository.java +++ b/src/test/java/org/springframework/data/couchbase/domain/AirportRepository.java @@ -104,6 +104,11 @@ List findByIataInAndIcaoIn(java.util.Collection size, java.util @ScanConsistency(query = QueryScanConsistency.REQUEST_PLUS) List deleteByIata(String iata); + @Query("#{#n1ql.delete} WHERE #{#n1ql.filter} and iata = $1 #{#n1ql.returning}") + @ScanConsistency(query = QueryScanConsistency.REQUEST_PLUS) + @Collection("bogus_collection") + List deleteByIataAnnotated(String iata); + @Query("SELECT __cas, * from #{#n1ql.bucket} where iata = $1") @ScanConsistency(query = QueryScanConsistency.REQUEST_PLUS) List getAllByIataNoID(String iata); diff --git a/src/test/java/org/springframework/data/couchbase/domain/AirportRepositoryAnnotated.java b/src/test/java/org/springframework/data/couchbase/domain/AirportRepositoryAnnotated.java new file mode 100644 index 000000000..4ee4bb6f4 --- /dev/null +++ b/src/test/java/org/springframework/data/couchbase/domain/AirportRepositoryAnnotated.java @@ -0,0 +1,26 @@ +/* + * Copyright 2022 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.Collection; + +/** + * AirportRepository with collection annotation + * + * @author Michael Reiche + */ +@Collection("my_collection2") +public interface AirportRepositoryAnnotated extends AirportRepository {} diff --git a/src/test/java/org/springframework/data/couchbase/domain/FluxTest.java b/src/test/java/org/springframework/data/couchbase/domain/FluxTest.java index ee0bb1cc2..66f88e408 100644 --- a/src/test/java/org/springframework/data/couchbase/domain/FluxTest.java +++ b/src/test/java/org/springframework/data/couchbase/domain/FluxTest.java @@ -105,7 +105,7 @@ public void beforeEach() { static List keyList = Arrays.asList("a", "b", "c", "d", "e"); static Collection collection; static ReactiveCollection rCollection; - @Autowired ReactiveAirportRepository airportRepository; // intellij flags "Could not Autowire", but it runs ok. + @Autowired ReactiveAirportRepository reactiveAirportRepository; // intellij flags "Could not Autowire", runs ok AtomicInteger rCat = new AtomicInteger(0); AtomicInteger rFlat = new AtomicInteger(0); @@ -136,7 +136,7 @@ public void cbse() { listOfLists.add(list); } Flux af = Flux.fromIterable(listOfLists).concatMap(catalogToStore -> Flux.fromIterable(catalogToStore) - .parallel(4).runOn(Schedulers.parallel()).concatMap((entity) -> airportRepository.save(entity))); + .parallel(4).runOn(Schedulers.parallel()).concatMap((entity) -> reactiveAirportRepository.save(entity))); List saved = af.collectList().block(); System.out.println("results.size() : " + saved.size()); @@ -152,7 +152,7 @@ public void cbse() { e.printStackTrace(); throw e; } - List airports = airportRepository.findAll().collectList().block(); + List airports = reactiveAirportRepository.findAll().collectList().block(); assertEquals(0, airports.size(), "should have been all deleted"); } @@ -164,11 +164,11 @@ public void pairIdAndResult() { for (int i = 0; i < 5; i++) { list.add(a.withId(UUID.randomUUID().toString())); } - Flux af = Flux.fromIterable(list).concatMap((entity) -> airportRepository.save(entity)); + Flux af = Flux.fromIterable(list).concatMap((entity) -> reactiveAirportRepository.save(entity)); List saved = af.collectList().block(); System.out.println("results.size() : " + saved.size()); Flux>> pairFlux = Flux.fromIterable(list) - .map((airport) -> Pair.of(airport.getId(), airportRepository.findById(airport.getId()))); + .map((airport) -> Pair.of(airport.getId(), reactiveAirportRepository.findById(airport.getId()))); List>> airportPairs = pairFlux.collectList().block(); for (Pair> airportPair : airportPairs) { System.out.println("id: " + airportPair.getFirst() + " airport: " + airportPair.getSecond().block()); diff --git a/src/test/java/org/springframework/data/couchbase/domain/ReactiveAirportRepository.java b/src/test/java/org/springframework/data/couchbase/domain/ReactiveAirportRepository.java index 59426ec27..005b3f51e 100644 --- a/src/test/java/org/springframework/data/couchbase/domain/ReactiveAirportRepository.java +++ b/src/test/java/org/springframework/data/couchbase/domain/ReactiveAirportRepository.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2021 the original author or authors. + * Copyright 2017-2022 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. @@ -21,6 +21,8 @@ import java.util.ArrayList; +import org.springframework.data.couchbase.core.RemoveResult; +import org.springframework.data.couchbase.repository.Collection; import org.springframework.data.couchbase.repository.DynamicProxyable; import org.springframework.data.couchbase.repository.Query; import org.springframework.data.couchbase.repository.ReactiveCouchbaseRepository; @@ -99,6 +101,15 @@ public interface ReactiveAirportRepository @ScanConsistency(query = QueryScanConsistency.REQUEST_PLUS) Mono findByIata(String iata); + @Query("#{#n1ql.delete} WHERE #{#n1ql.filter} and iata = $1 #{#n1ql.returning}") + @ScanConsistency(query = QueryScanConsistency.REQUEST_PLUS) + Flux deleteByIata(String iata); + + @Query("#{#n1ql.delete} WHERE #{#n1ql.filter} and iata = $1 #{#n1ql.returning}") + @ScanConsistency(query = QueryScanConsistency.REQUEST_PLUS) + @Collection("bogus_collection") + Flux deleteByIataAnnotated(String iata); + // This is not efficient. See findAllByIataLike for efficient reactive paging default public Mono> findAllAirportsPaged(Pageable pageable) { return count().flatMap(airportCount -> { diff --git a/src/test/java/org/springframework/data/couchbase/domain/ReactiveAirportRepositoryAnnotated.java b/src/test/java/org/springframework/data/couchbase/domain/ReactiveAirportRepositoryAnnotated.java new file mode 100644 index 000000000..05e154347 --- /dev/null +++ b/src/test/java/org/springframework/data/couchbase/domain/ReactiveAirportRepositoryAnnotated.java @@ -0,0 +1,26 @@ +/* + * Copyright 2022 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.Collection; + +/** + * AirportRepository with collection annotation + * + * @author Michael Reiche + */ +@Collection("my_collection2") +public interface ReactiveAirportRepositoryAnnotated extends ReactiveAirportRepository{} diff --git a/src/test/java/org/springframework/data/couchbase/repository/ReactiveCouchbaseRepositoryKeyValueIntegrationTests.java b/src/test/java/org/springframework/data/couchbase/repository/ReactiveCouchbaseRepositoryKeyValueIntegrationTests.java index a547dd747..cd8d42589 100644 --- a/src/test/java/org/springframework/data/couchbase/repository/ReactiveCouchbaseRepositoryKeyValueIntegrationTests.java +++ b/src/test/java/org/springframework/data/couchbase/repository/ReactiveCouchbaseRepositoryKeyValueIntegrationTests.java @@ -60,7 +60,7 @@ public class ReactiveCouchbaseRepositoryKeyValueIntegrationTests extends Cluster @Autowired ReactiveUserRepository userRepository; - @Autowired ReactiveAirportRepository airportRepository; + @Autowired ReactiveAirportRepository reactiveAirportRepository; @Autowired ReactiveAirlineRepository airlineRepository; @@ -108,13 +108,13 @@ void findByIdAudited() { Airport vie = null; try { vie = new Airport("airports::vie", "vie", "low2"); - Airport saved = airportRepository.save(vie).block(); - Airport airport1 = airportRepository.findById(saved.getId()).block(); + Airport saved = reactiveAirportRepository.save(vie).block(); + Airport airport1 = reactiveAirportRepository.findById(saved.getId()).block(); assertEquals(airport1, saved); assertEquals(saved.getCreatedBy(), ReactiveNaiveAuditorAware.AUDITOR); // ReactiveNaiveAuditorAware will provide // this } finally { - airportRepository.delete(vie).block(); + reactiveAirportRepository.delete(vie).block(); } } 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 c088b0d47..05a0160dc 100644 --- a/src/test/java/org/springframework/data/couchbase/repository/ReactiveCouchbaseRepositoryQueryIntegrationTests.java +++ b/src/test/java/org/springframework/data/couchbase/repository/ReactiveCouchbaseRepositoryQueryIntegrationTests.java @@ -72,7 +72,8 @@ public class ReactiveCouchbaseRepositoryQueryIntegrationTests extends JavaIntegr @Autowired CouchbaseClientFactory clientFactory; - @Autowired ReactiveAirportRepository airportRepository; // intellij flags "Could not Autowire", but it runs ok. + @Autowired ReactiveAirportRepository reactiveAirportRepository; // intellij flags "Could not Autowire", but it runs + // ok. @Autowired ReactiveUserRepository userRepository; // intellij flags "Could not Autowire", but it runs ok. @Test @@ -81,18 +82,18 @@ void shouldSaveAndFindAll() { Airport jfk = null; try { vie = new Airport("airports::vie", "vie", "low1"); - airportRepository.save(vie).block(); + reactiveAirportRepository.save(vie).block(); jfk = new Airport("airports::jfk", "JFK", "xxxx"); - airportRepository.save(jfk).block(); + reactiveAirportRepository.save(jfk).block(); - List all = airportRepository.findAll().toStream().collect(Collectors.toList()); + List all = reactiveAirportRepository.findAll().toStream().collect(Collectors.toList()); assertFalse(all.isEmpty()); assertTrue(all.stream().anyMatch(a -> a.getId().equals("airports::vie"))); assertTrue(all.stream().anyMatch(a -> a.getId().equals("airports::jfk"))); } finally { - airportRepository.delete(vie).block(); - airportRepository.delete(jfk).block(); + reactiveAirportRepository.delete(vie).block(); + reactiveAirportRepository.delete(jfk).block(); } } @@ -101,20 +102,20 @@ void findBySimpleProperty() { Airport vie = null; try { vie = new Airport("airports::vie", "vie", "low2"); - airportRepository.save(vie).block(); - List airports1 = airportRepository.findAllByIata("vie").collectList().block(); + reactiveAirportRepository.save(vie).block(); + List airports1 = reactiveAirportRepository.findAllByIata("vie").collectList().block(); assertEquals(1, airports1.size()); - List airports2 = airportRepository.findAllByIata("vie").collectList().block(); + List airports2 = reactiveAirportRepository.findAllByIata("vie").collectList().block(); assertEquals(1, airports2.size()); - vie = airportRepository.save(vie).block(); - List airports = airportRepository.findAllByIata("vie").collectList().block(); + vie = reactiveAirportRepository.save(vie).block(); + List airports = reactiveAirportRepository.findAllByIata("vie").collectList().block(); assertEquals(1, airports.size()); - Airport airport1 = airportRepository.findById(airports.get(0).getId()).block(); + Airport airport1 = reactiveAirportRepository.findById(airports.get(0).getId()).block(); assertEquals(airport1.getIata(), vie.getIata()); - Airport airport2 = airportRepository.findByIata(airports.get(0).getIata()).block(); + Airport airport2 = reactiveAirportRepository.findByIata(airports.get(0).getIata()).block(); assertEquals(airport1.getId(), vie.getId()); } finally { - airportRepository.delete(vie).block(); + reactiveAirportRepository.delete(vie).block(); } } @@ -133,27 +134,27 @@ public void testCas() { @Test void limitTest() { Airport vie = new Airport("airports::vie", "vie", "low3"); - Airport saved1 = airportRepository.save(vie).block(); - Airport saved2 = airportRepository.save(vie.withId(UUID.randomUUID().toString())).block(); + Airport saved1 = reactiveAirportRepository.save(vie).block(); + Airport saved2 = reactiveAirportRepository.save(vie.withId(UUID.randomUUID().toString())).block(); try { - airportRepository.findAll().collectList().block(); // findAll has QueryScanConsistency; - Mono airport = airportRepository.findPolicySnapshotByPolicyIdAndEffectiveDateTime("any", 0); + reactiveAirportRepository.findAll().collectList().block(); // findAll has QueryScanConsistency; + Mono airport = reactiveAirportRepository.findPolicySnapshotByPolicyIdAndEffectiveDateTime("any", 0); System.out.println("------------------------------"); System.out.println(airport.block()); System.out.println("------------------------------"); - Flux airports = airportRepository.findPolicySnapshotAll(); + Flux airports = reactiveAirportRepository.findPolicySnapshotAll(); System.out.println(airports.collectList().block()); System.out.println("------------------------------"); Mono ap = getPolicyByIdAndEffectiveDateTime("x", Instant.now()); System.out.println(ap.block()); } finally { - airportRepository.delete(saved1).block(); - airportRepository.delete(saved2).block(); + reactiveAirportRepository.delete(saved1).block(); + reactiveAirportRepository.delete(saved2).block(); } } public Mono getPolicyByIdAndEffectiveDateTime(String policyId, Instant effectiveDateTime) { - return airportRepository + return reactiveAirportRepository .findPolicySnapshotByPolicyIdAndEffectiveDateTime(policyId, effectiveDateTime.toEpochMilli()) // .map(Airport::getEntity) .doOnError( @@ -177,36 +178,36 @@ void count() { Callable[] suppliers = new Callable[iatas.size()]; for (String iata : iatas) { Airport airport = new Airport("airports::" + iata, iata, iata.toLowerCase() /* lcao */); - airportRepository.save(airport).block(); + reactiveAirportRepository.save(airport).block(); } int page = 0; - airportRepository.findAllByIataLike("S%", PageRequest.of(page++, 2)).as(StepVerifier::create) // + reactiveAirportRepository.findAllByIataLike("S%", PageRequest.of(page++, 2)).as(StepVerifier::create) // .expectNextMatches(a -> { return iatas.contains(a.getIata()); }).expectNextMatches(a -> iatas.contains(a.getIata())).verifyComplete(); - airportRepository.findAllByIataLike("S%", PageRequest.of(page++, 2)).as(StepVerifier::create) // + reactiveAirportRepository.findAllByIataLike("S%", PageRequest.of(page++, 2)).as(StepVerifier::create) // .expectNextMatches(a -> iatas.contains(a.getIata())).verifyComplete(); - Long airportCount = airportRepository.count().block(); + Long airportCount = reactiveAirportRepository.count().block(); assertEquals(iatas.size(), airportCount); - airportCount = airportRepository.countByIataIn("JFK", "IAD", "SFO").block(); + airportCount = reactiveAirportRepository.countByIataIn("JFK", "IAD", "SFO").block(); assertEquals(3, airportCount); - airportCount = airportRepository.countByIcaoAndIataIn("jfk", "JFK", "IAD", "SFO", "XXX").block(); + airportCount = reactiveAirportRepository.countByIcaoAndIataIn("jfk", "JFK", "IAD", "SFO", "XXX").block(); assertEquals(1, airportCount); - airportCount = airportRepository.countByIataIn("XXX").block(); + airportCount = reactiveAirportRepository.countByIataIn("XXX").block(); assertEquals(0, airportCount); } finally { for (String iata : iatas) { Airport airport = new Airport("airports::" + iata, iata, iata.toLowerCase() /* lcao */); try { - airportRepository.delete(airport).block(); + reactiveAirportRepository.delete(airport).block(); } catch (DataRetrievalFailureException drfe) { System.out.println("Failed to delete: " + airport); } @@ -224,17 +225,17 @@ void deleteAllById() { try { // This failed once against Capella - not sure why. - airportRepository.saveAll(asList(vienna, frankfurt, losAngeles)).blockLast(); + reactiveAirportRepository.saveAll(asList(vienna, frankfurt, losAngeles)).blockLast(); - airportRepository.deleteAllById(asList(vienna.getId(), losAngeles.getId())).as(StepVerifier::create) + reactiveAirportRepository.deleteAllById(asList(vienna.getId(), losAngeles.getId())).as(StepVerifier::create) .verifyComplete(); - airportRepository.findAll().as(StepVerifier::create).expectNext(frankfurt).verifyComplete(); + reactiveAirportRepository.findAll().as(StepVerifier::create).expectNext(frankfurt).verifyComplete(); } finally { - List airports = airportRepository.findAll().collectList().block(); // .as(StepVerifier::create).expectNext(frankfurt).verifyComplete(); + List airports = reactiveAirportRepository.findAll().collectList().block(); // .as(StepVerifier::create).expectNext(frankfurt).verifyComplete(); System.out.println(airports); - airportRepository.deleteAll().block(); + reactiveAirportRepository.deleteAll().block(); } } @@ -246,14 +247,14 @@ void deleteAll() { Airport losAngeles = new Airport("airports::lax", "lax", "KLAX"); try { - airportRepository.saveAll(asList(vienna, frankfurt, losAngeles)).blockLast(); + reactiveAirportRepository.saveAll(asList(vienna, frankfurt, losAngeles)).blockLast(); - airportRepository.deleteAll().as(StepVerifier::create).verifyComplete(); + reactiveAirportRepository.deleteAll().as(StepVerifier::create).verifyComplete(); - airportRepository.findAll().as(StepVerifier::create).verifyComplete(); + reactiveAirportRepository.findAll().as(StepVerifier::create).verifyComplete(); } finally { - airportRepository.deleteAll().block(); + reactiveAirportRepository.deleteAll().block(); } } @@ -263,13 +264,13 @@ void deleteOne() { Airport vienna = new Airport("airports::vie", "vie", "LOWW"); try { - Airport ap = airportRepository.save(vienna).block(); + Airport ap = reactiveAirportRepository.save(vienna).block(); assertEquals(vienna.getId(), ap.getId(), "should have saved what was provided"); - airportRepository.delete(vienna).as(StepVerifier::create).verifyComplete(); + reactiveAirportRepository.delete(vienna).as(StepVerifier::create).verifyComplete(); - airportRepository.findAll().as(StepVerifier::create).verifyComplete(); + reactiveAirportRepository.findAll().as(StepVerifier::create).verifyComplete(); } finally { - airportRepository.deleteAll().block(); + reactiveAirportRepository.deleteAll().block(); } } diff --git a/src/test/java/org/springframework/data/couchbase/repository/query/CouchbaseRepositoryQueryCollectionIntegrationTests.java b/src/test/java/org/springframework/data/couchbase/repository/query/CouchbaseRepositoryQueryCollectionIntegrationTests.java index 748401ce3..6dee1b6e3 100644 --- a/src/test/java/org/springframework/data/couchbase/repository/query/CouchbaseRepositoryQueryCollectionIntegrationTests.java +++ b/src/test/java/org/springframework/data/couchbase/repository/query/CouchbaseRepositoryQueryCollectionIntegrationTests.java @@ -16,6 +16,7 @@ package org.springframework.data.couchbase.repository.query; import static com.couchbase.client.core.io.CollectionIdentifier.DEFAULT_SCOPE; +import static com.couchbase.client.java.query.QueryScanConsistency.REQUEST_PLUS; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; @@ -29,13 +30,12 @@ import org.junit.jupiter.api.BeforeEach; 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.dao.DataRetrievalFailureException; import org.springframework.data.couchbase.domain.Address; import org.springframework.data.couchbase.domain.AddressAnnotated; import org.springframework.data.couchbase.domain.Airport; import org.springframework.data.couchbase.domain.AirportRepository; +import org.springframework.data.couchbase.domain.AirportRepositoryAnnotated; import org.springframework.data.couchbase.domain.Config; import org.springframework.data.couchbase.domain.User; import org.springframework.data.couchbase.domain.UserCol; @@ -48,13 +48,14 @@ import org.springframework.data.couchbase.util.ClusterType; import org.springframework.data.couchbase.util.CollectionAwareIntegrationTests; import org.springframework.data.couchbase.util.IgnoreWhen; +import org.springframework.test.context.junit.jupiter.SpringJUnitConfig; import com.couchbase.client.core.error.IndexFailureException; import com.couchbase.client.core.io.CollectionIdentifier; import com.couchbase.client.java.json.JsonArray; import com.couchbase.client.java.query.QueryOptions; -import com.couchbase.client.java.query.QueryScanConsistency; +@SpringJUnitConfig(Config.class) @IgnoreWhen(missesCapabilities = { Capabilities.QUERY, Capabilities.COLLECTIONS }, clusterTypes = ClusterType.MOCKED) public class CouchbaseRepositoryQueryCollectionIntegrationTests extends CollectionAwareIntegrationTests { @@ -62,6 +63,7 @@ public class CouchbaseRepositoryQueryCollectionIntegrationTests extends Collecti @Autowired UserColRepository userColRepository; // initialized in beforeEach() @Autowired UserSubmissionAnnotatedRepository userSubmissionAnnotatedRepository; // initialized in beforeEach() @Autowired UserSubmissionUnannotatedRepository userSubmissionUnannotatedRepository; // initialized in beforeEach() + @Autowired AirportRepositoryAnnotated airportRepositoryAnnotated; @BeforeAll public static void beforeAll() { @@ -86,14 +88,9 @@ public void beforeEach() { // then do processing for this class couchbaseTemplate.removeByQuery(User.class).inCollection(collectionName).all(); couchbaseTemplate.removeByQuery(UserCol.class).inScope(otherScope).inCollection(otherCollection).all(); - ApplicationContext ac = new AnnotationConfigApplicationContext(Config.class); - // seems that @Autowired is not adequate, so ... - airportRepository = (AirportRepository) ac.getBean("airportRepository"); - userColRepository = (UserColRepository) ac.getBean("userColRepository"); - userSubmissionAnnotatedRepository = (UserSubmissionAnnotatedRepository) ac - .getBean("userSubmissionAnnotatedRepository"); - userSubmissionUnannotatedRepository = (UserSubmissionUnannotatedRepository) ac - .getBean("userSubmissionUnannotatedRepository"); + couchbaseTemplate.removeByQuery(Airport.class).inCollection(collectionName).all(); + couchbaseTemplate.removeByQuery(Airport.class).inCollection(collectionName2).all(); + couchbaseTemplate.findByQuery(Airport.class).withConsistency(REQUEST_PLUS).inCollection(collectionName).all(); } @AfterEach @@ -149,8 +146,7 @@ void findBySimplePropertyWithCollection() { // valid scope, collection in options Airport airport2 = ar.withCollection(collectionName) - .withOptions(QueryOptions.queryOptions().scanConsistency(QueryScanConsistency.REQUEST_PLUS)) - .iata(vie.getIata()); + .withOptions(QueryOptions.queryOptions().scanConsistency(REQUEST_PLUS)).iata(vie.getIata()); assertEquals(saved, airport2); // given bad collectionName in fluent @@ -159,8 +155,7 @@ void findBySimplePropertyWithCollection() { // given bad scopeName in fluent assertThrows(IndexFailureException.class, () -> ar.withScope("bogusScope").iata(vie.getIata())); - Airport airport6 = ar.withOptions(QueryOptions.queryOptions().scanConsistency(QueryScanConsistency.REQUEST_PLUS)) - .iata(vie.getIata()); + Airport airport6 = ar.withOptions(QueryOptions.queryOptions().scanConsistency(REQUEST_PLUS)).iata(vie.getIata()); assertEquals(saved, airport6); } catch (Exception e) { @@ -180,8 +175,8 @@ void findBySimplePropertyWithOptions() { try { Airport saved = ar.save(vie); - Airport airport3 = ar.withOptions( - QueryOptions.queryOptions().scanConsistency(QueryScanConsistency.REQUEST_PLUS).parameters(positionalParams)) + Airport airport3 = ar + .withOptions(QueryOptions.queryOptions().scanConsistency(REQUEST_PLUS).parameters(positionalParams)) .iata(vie.getIata()); assertEquals(saved, airport3); @@ -278,8 +273,7 @@ void findPlusN1qlJoinBothAnnotated() throws Exception { address1 = couchbaseTemplate.insertById(AddressAnnotated.class).inScope(scopeName).one(address1); address2 = couchbaseTemplate.insertById(AddressAnnotated.class).inScope(scopeName).one(address2); address3 = couchbaseTemplate.insertById(AddressAnnotated.class).inScope(scopeName).one(address3); - couchbaseTemplate.findByQuery(AddressAnnotated.class).withConsistency(QueryScanConsistency.REQUEST_PLUS) - .inScope(scopeName).all(); + couchbaseTemplate.findByQuery(AddressAnnotated.class).withConsistency(REQUEST_PLUS).inScope(scopeName).all(); // scope for AddressesAnnotated in N1qlJoin comes from userSubmissionAnnotatedRepository. List users = userSubmissionAnnotatedRepository.findByUsername(user.getUsername()); @@ -333,8 +327,7 @@ void findPlusN1qlJoinUnannotated() throws Exception { address1 = couchbaseTemplate.insertById(AddressAnnotated.class).inScope(scopeName).one(address1); address2 = couchbaseTemplate.insertById(AddressAnnotated.class).inScope(scopeName).one(address2); address3 = couchbaseTemplate.insertById(AddressAnnotated.class).inScope(scopeName).one(address3); - couchbaseTemplate.findByQuery(AddressAnnotated.class).withConsistency(QueryScanConsistency.REQUEST_PLUS) - .inScope(scopeName).all(); + couchbaseTemplate.findByQuery(AddressAnnotated.class).withConsistency(REQUEST_PLUS).inScope(scopeName).all(); // scope for AddressesAnnotated in N1qlJoin comes from userSubmissionAnnotatedRepository. List users = userSubmissionUnannotatedRepository.findByUsername(user.getUsername()); @@ -359,4 +352,57 @@ void findPlusN1qlJoinUnannotated() throws Exception { } } + @Test + void stringDeleteCollectionTest() { + Airport airport = new Airport(loc(), "vie", "abc"); + Airport otherAirport = new Airport(loc(), "xxx", "xyz"); + try { + airport = airportRepository.withScope(scopeName).withCollection(collectionName).save(airport); + otherAirport = airportRepository.withScope(scopeName).withCollection(collectionName).save(otherAirport); + assertEquals(1, + airportRepository.withScope(scopeName).withCollection(collectionName).deleteByIata(airport.getIata()).size()); + } catch (Exception e) { + e.printStackTrace(); + throw e; + } finally { + airportRepository.withScope(scopeName).withCollection(collectionName).deleteById(otherAirport.getId()); + } + } + + @Test + void stringDeleteWithRepositoryAnnotationTest() { + Airport airport = new Airport(loc(), "vie", "abc"); + Airport otherAirport = new Airport(loc(), "xxx", "xyz"); + try { + airport = airportRepositoryAnnotated.withScope(scopeName).save(airport); + otherAirport = airportRepositoryAnnotated.withScope(scopeName).save(otherAirport); + // don't specify a collection - should get collection from AirportRepositoryAnnotated + assertEquals(1, airportRepositoryAnnotated.withScope(scopeName).deleteByIata(airport.getIata()).size()); + } catch (Exception e) { + e.printStackTrace(); + throw e; + } finally { + // this will fail if the above didn't use collectionName2 + airportRepository.withScope(scopeName).withCollection(collectionName2).deleteById(otherAirport.getId()); + } + } + + @Test + void stringDeleteWithMethodAnnotationTest() { + Airport airport = new Airport(loc(), "vie", "abc"); + Airport otherAirport = new Airport(loc(), "xxx", "xyz"); + try { + Airport airportSaved = airportRepositoryAnnotated.withScope(scopeName).save(airport); + Airport otherAirportSaved = airportRepositoryAnnotated.withScope(scopeName).save(otherAirport); + // don't specify a collection - should get collection from deleteByIataAnnotated method + assertThrows(IndexFailureException.class, () -> assertEquals(1, + airportRepositoryAnnotated.withScope(scopeName).deleteByIataAnnotated(airport.getIata()).size())); + } catch (Exception e) { + e.printStackTrace(); + throw e; + } finally { + // this will fail if the above didn't use collectionName2 + airportRepository.withScope(scopeName).withCollection(collectionName2).deleteById(otherAirport.getId()); + } + } } diff --git a/src/test/java/org/springframework/data/couchbase/repository/query/ReactiveCouchbaseRepositoryQueryCollectionIntegrationTests.java b/src/test/java/org/springframework/data/couchbase/repository/query/ReactiveCouchbaseRepositoryQueryCollectionIntegrationTests.java index 51f6a5efe..2a0b25b56 100644 --- a/src/test/java/org/springframework/data/couchbase/repository/query/ReactiveCouchbaseRepositoryQueryCollectionIntegrationTests.java +++ b/src/test/java/org/springframework/data/couchbase/repository/query/ReactiveCouchbaseRepositoryQueryCollectionIntegrationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2021 the original author or authors. + * Copyright 2017-2022 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. @@ -15,6 +15,7 @@ */ package org.springframework.data.couchbase.repository.query; +import static com.couchbase.client.java.query.QueryScanConsistency.REQUEST_PLUS; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; @@ -26,12 +27,11 @@ import org.junit.jupiter.api.BeforeEach; 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.dao.DataRetrievalFailureException; import org.springframework.data.couchbase.domain.Airport; import org.springframework.data.couchbase.domain.Config; import org.springframework.data.couchbase.domain.ReactiveAirportRepository; +import org.springframework.data.couchbase.domain.ReactiveAirportRepositoryAnnotated; import org.springframework.data.couchbase.domain.ReactiveUserColRepository; import org.springframework.data.couchbase.domain.User; import org.springframework.data.couchbase.domain.UserCol; @@ -39,6 +39,7 @@ import org.springframework.data.couchbase.util.ClusterType; import org.springframework.data.couchbase.util.CollectionAwareIntegrationTests; import org.springframework.data.couchbase.util.IgnoreWhen; +import org.springframework.test.context.junit.jupiter.SpringJUnitConfig; import com.couchbase.client.core.error.IndexFailureException; import com.couchbase.client.core.io.CollectionIdentifier; @@ -46,11 +47,18 @@ import com.couchbase.client.java.query.QueryOptions; import com.couchbase.client.java.query.QueryScanConsistency; +/** + * Reactive Repository Query tests with Collections + * + * @author Michael Reiche + */ +@SpringJUnitConfig(Config.class) @IgnoreWhen(missesCapabilities = { Capabilities.QUERY, Capabilities.COLLECTIONS }, clusterTypes = ClusterType.MOCKED) public class ReactiveCouchbaseRepositoryQueryCollectionIntegrationTests extends CollectionAwareIntegrationTests { - @Autowired ReactiveAirportRepository airportRepository; + @Autowired ReactiveAirportRepository reactiveAirportRepository; @Autowired ReactiveUserColRepository userColRepository; + @Autowired ReactiveAirportRepositoryAnnotated reactiveAirportRepositoryAnnotated; @BeforeAll public static void beforeAll() { @@ -75,11 +83,9 @@ public void beforeEach() { // then do processing for this class couchbaseTemplate.removeByQuery(User.class).inCollection(collectionName).all(); couchbaseTemplate.removeByQuery(UserCol.class).inScope(otherScope).inCollection(otherCollection).all(); - - ApplicationContext ac = new AnnotationConfigApplicationContext(Config.class); - // seems that @Autowired is not adequate, so ... - airportRepository = (ReactiveAirportRepository) ac.getBean("reactiveAirportRepository"); - userColRepository = (ReactiveUserColRepository) ac.getBean("reactiveUserColRepository"); + couchbaseTemplate.removeByQuery(Airport.class).inCollection(collectionName).all(); + couchbaseTemplate.removeByQuery(Airport.class).inCollection(collectionName2).all(); + couchbaseTemplate.findByQuery(Airport.class).withConsistency(REQUEST_PLUS).inCollection(collectionName).all(); } @AfterEach @@ -94,7 +100,7 @@ public void afterEach() { @Test public void myTest() { - ReactiveAirportRepository ar = airportRepository.withScope(scopeName).withCollection(collectionName); + ReactiveAirportRepository ar = reactiveAirportRepository.withScope(scopeName).withCollection(collectionName); Airport vie = new Airport("airports::vie", "vie", "loww"); try { Airport saved = ar.save(vie).block(); @@ -119,7 +125,7 @@ void findBySimplePropertyWithCollection() { Airport vie = new Airport("airports::vie", "vie", "loww"); // create proxy with scope, collection - ReactiveAirportRepository ar = airportRepository.withScope(scopeName).withCollection(collectionName); + ReactiveAirportRepository ar = reactiveAirportRepository.withScope(scopeName).withCollection(collectionName); try { Airport saved = ar.save(vie).block(); @@ -150,7 +156,7 @@ void findBySimplePropertyWithCollection() { void findBySimplePropertyWithOptions() { Airport vie = new Airport("airports::vie", "vie", "loww"); - ReactiveAirportRepository ar = airportRepository.withScope(scopeName).withCollection(collectionName); + ReactiveAirportRepository ar = reactiveAirportRepository.withScope(scopeName).withCollection(collectionName); JsonArray positionalParams = JsonArray.create().add("\"this parameter will be overridden\""); try { Airport saved = ar.save(vie).block(); @@ -212,4 +218,61 @@ public void testScopeCollectionRepoWith() { } catch (DataRetrievalFailureException drfe) {} } } + + @Test + void stringDeleteCollectionTest() { + Airport airport = new Airport(loc(), "vie", "abc"); + Airport otherAirport = new Airport(loc(), "xxx", "xyz"); + try { + airport = reactiveAirportRepository.withScope(scopeName).withCollection(collectionName).save(airport).block(); + otherAirport = reactiveAirportRepository.withScope(scopeName).withCollection(collectionName).save(otherAirport) + .block(); + assertEquals(1, reactiveAirportRepository.withScope(scopeName).withCollection(collectionName) + .deleteByIata(airport.getIata()).collectList().block().size()); + } catch (Exception e) { + e.printStackTrace(); + throw e; + } finally { + reactiveAirportRepository.withScope(scopeName).withCollection(collectionName).deleteById(otherAirport.getId()); + } + } + + @Test + void stringDeleteWithRepositoryAnnotationTest() { + Airport airport = new Airport(loc(), "vie", "abc"); + Airport otherAirport = new Airport(loc(), "xxx", "xyz"); + try { + airport = reactiveAirportRepositoryAnnotated.withScope(scopeName).save(airport).block(); + otherAirport = reactiveAirportRepositoryAnnotated.withScope(scopeName).save(otherAirport).block(); + // don't specify a collection - should get collection from AirportRepositoryAnnotated + assertEquals(1, reactiveAirportRepositoryAnnotated.withScope(scopeName).deleteByIata(airport.getIata()) + .collectList().block().size()); + } catch (Exception e) { + e.printStackTrace(); + throw e; + } finally { + // this will fail if the above didn't use collectionName2 + reactiveAirportRepository.withScope(scopeName).withCollection(collectionName2).deleteById(otherAirport.getId()); + } + } + + @Test + void stringDeleteWithMethodAnnotationTest() { + Airport airport = new Airport(loc(), "vie", "abc"); + Airport otherAirport = new Airport(loc(), "xxx", "xyz"); + try { + Airport airportSaved = reactiveAirportRepositoryAnnotated.withScope(scopeName).save(airport).block(); + Airport otherAirportSaved = reactiveAirportRepositoryAnnotated.withScope(scopeName).save(otherAirport).block(); + // don't specify a collection - should get collection from deleteByIataAnnotated method + assertThrows(IndexFailureException.class, () -> assertEquals(1, reactiveAirportRepositoryAnnotated + .withScope(scopeName).deleteByIataAnnotated(airport.getIata()).collectList().block().size())); + } catch (Exception e) { + e.printStackTrace(); + throw e; + } finally { + // this will fail if the above didn't use collectionName2 + reactiveAirportRepository.withScope(scopeName).withCollection(collectionName2).deleteById(otherAirport.getId()); + } + } + } diff --git a/src/test/java/org/springframework/data/couchbase/util/ClusterAwareIntegrationTests.java b/src/test/java/org/springframework/data/couchbase/util/ClusterAwareIntegrationTests.java index 27a8669e8..82fdfc2e2 100644 --- a/src/test/java/org/springframework/data/couchbase/util/ClusterAwareIntegrationTests.java +++ b/src/test/java/org/springframework/data/couchbase/util/ClusterAwareIntegrationTests.java @@ -24,6 +24,7 @@ import java.util.List; import java.util.Optional; import java.util.Set; +import java.util.UUID; import java.util.stream.Collectors; import org.junit.jupiter.api.AfterAll; @@ -49,6 +50,8 @@ /** * Parent class which drives all dynamic integration tests based on the configured cluster setup. * + * @author Michael Reiche + * * @since 2.0.0 */ @ExtendWith(ClusterInvocationProvider.class) @@ -215,4 +218,14 @@ private static void callSuper(Object createdHere, Class annotationClass) { } } + /** + * @return unique identifier for line - to use as key for documents to identify where they were created + */ + public static String loc() { + String uuid = UUID.randomUUID().toString(); + String uid = uuid.substring(uuid.length() - 4); + StackTraceElement ste = Thread.currentThread().getStackTrace()[2]; + return ste.getClassName() + ":" + ste.getMethodName() + ":" + ste.getLineNumber() + ":" + uid; + } + } From 33e32fc5640e5d13c240730002bfabc0881e0aa5 Mon Sep 17 00:00:00 2001 From: Michael Reiche <48999328+mikereiche@users.noreply.github.com> Date: Fri, 17 Jun 2022 11:04:44 -0700 Subject: [PATCH 2/2] Update ReactiveAirportRepository.java --- .../data/couchbase/domain/ReactiveAirportRepository.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/java/org/springframework/data/couchbase/domain/ReactiveAirportRepository.java b/src/test/java/org/springframework/data/couchbase/domain/ReactiveAirportRepository.java index 005b3f51e..1cfde81fd 100644 --- a/src/test/java/org/springframework/data/couchbase/domain/ReactiveAirportRepository.java +++ b/src/test/java/org/springframework/data/couchbase/domain/ReactiveAirportRepository.java @@ -101,11 +101,11 @@ public interface ReactiveAirportRepository @ScanConsistency(query = QueryScanConsistency.REQUEST_PLUS) Mono findByIata(String iata); - @Query("#{#n1ql.delete} WHERE #{#n1ql.filter} and iata = $1 #{#n1ql.returning}") + @Query("#{#n1ql.delete} WHERE #{#n1ql.filter} and iata = $1 #{#n1ql.returning}") @ScanConsistency(query = QueryScanConsistency.REQUEST_PLUS) Flux deleteByIata(String iata); - @Query("#{#n1ql.delete} WHERE #{#n1ql.filter} and iata = $1 #{#n1ql.returning}") + @Query("#{#n1ql.delete} WHERE #{#n1ql.filter} and iata = $1 #{#n1ql.returning}") @ScanConsistency(query = QueryScanConsistency.REQUEST_PLUS) @Collection("bogus_collection") Flux deleteByIataAnnotated(String iata);