Skip to content

Commit 797a454

Browse files
committed
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.
1 parent 72886bb commit 797a454

14 files changed

+304
-113
lines changed

src/main/java/org/springframework/data/couchbase/repository/query/AbstractCouchbaseQuery.java

+5-1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import org.springframework.data.couchbase.core.CouchbaseOperations;
2020
import org.springframework.data.couchbase.core.ExecutableFindByQueryOperation.ExecutableFindByQuery;
2121
import org.springframework.data.couchbase.core.ExecutableFindByQueryOperation.TerminatingFindByQuery;
22+
import org.springframework.data.couchbase.core.ExecutableRemoveByQueryOperation.ExecutableRemoveByQuery;
2223
import org.springframework.data.couchbase.core.query.Query;
2324
import org.springframework.data.couchbase.repository.query.CouchbaseQueryExecution.DeleteExecution;
2425
import org.springframework.data.couchbase.repository.query.CouchbaseQueryExecution.PagedExecution;
@@ -43,6 +44,7 @@ public abstract class AbstractCouchbaseQuery extends AbstractCouchbaseQueryBase<
4344
implements RepositoryQuery {
4445

4546
private final ExecutableFindByQuery<?> findOperationWithProjection;
47+
private final ExecutableRemoveByQuery<?> removeOp;
4648

4749
/**
4850
* Creates a new {@link AbstractCouchbaseQuery} from the given {@link ReactiveCouchbaseQueryMethod} and
@@ -65,6 +67,8 @@ public AbstractCouchbaseQuery(CouchbaseQueryMethod method, CouchbaseOperations o
6567
ExecutableFindByQuery<?> findOp = operations.findByQuery(type);
6668
findOp = (ExecutableFindByQuery<?>) (findOp.inScope(method.getScope()).inCollection(method.getCollection()));
6769
this.findOperationWithProjection = findOp;
70+
this.removeOp = (ExecutableRemoveByQuery<?>) (operations.removeByQuery(type).inScope(method.getScope())
71+
.inCollection(method.getCollection()));
6872
}
6973

7074
/**
@@ -114,7 +118,7 @@ private CouchbaseQueryExecution getExecution(ParameterAccessor accessor, Convert
114118
private CouchbaseQueryExecution getExecutionToWrap(ParameterAccessor accessor, ExecutableFindByQuery<?> operation) {
115119

116120
if (isDeleteQuery()) {
117-
return new DeleteExecution(getOperations(), getQueryMethod());
121+
return new DeleteExecution(removeOp);
118122
} else if (isTailable(getQueryMethod())) {
119123
return (q, t, r, c) -> operation.as(r).matching(q.with(accessor.getPageable())).all(); // s/b tail() instead of
120124
// all()

src/main/java/org/springframework/data/couchbase/repository/query/AbstractReactiveCouchbaseQuery.java

+10-9
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2020-2021 the original author or authors.
2+
* Copyright 2020-2022 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -19,6 +19,7 @@
1919
import org.springframework.data.couchbase.core.ReactiveCouchbaseOperations;
2020
import org.springframework.data.couchbase.core.ReactiveFindByQueryOperation;
2121
import org.springframework.data.couchbase.core.ReactiveFindByQueryOperation.ReactiveFindByQuery;
22+
import org.springframework.data.couchbase.core.ReactiveRemoveByQueryOperation.ReactiveRemoveByQuery;
2223
import org.springframework.data.couchbase.core.query.Query;
2324
import org.springframework.data.couchbase.repository.query.ReactiveCouchbaseQueryExecution.DeleteExecution;
2425
import org.springframework.data.couchbase.repository.query.ReactiveCouchbaseQueryExecution.ResultProcessingExecution;
@@ -41,7 +42,8 @@
4142
public abstract class AbstractReactiveCouchbaseQuery extends AbstractCouchbaseQueryBase<ReactiveCouchbaseOperations>
4243
implements RepositoryQuery {
4344

44-
private final ReactiveFindByQuery<?> findOperationWithProjection;
45+
private final ReactiveFindByQuery<?> findOp;
46+
private final ReactiveRemoveByQuery<?> removeOp;
4547

4648
/**
4749
* Creates a new {@link AbstractReactiveCouchbaseQuery} from the given {@link ReactiveCouchbaseQueryMethod} and
@@ -62,9 +64,10 @@ public AbstractReactiveCouchbaseQuery(ReactiveCouchbaseQueryMethod method, React
6264

6365
EntityMetadata<?> metadata = method.getEntityInformation();
6466
Class<?> type = metadata.getJavaType();
65-
ReactiveFindByQuery<?> findOp = operations.findByQuery(type);
66-
findOp = (ReactiveFindByQuery<?>) (findOp.inScope(method.getScope()).inCollection(method.getCollection()));
67-
this.findOperationWithProjection = findOp;
67+
this.findOp = (ReactiveFindByQuery<?>) (operations.findByQuery(type).inScope(method.getScope())
68+
.inCollection(method.getCollection()));
69+
this.removeOp = (ReactiveRemoveByQuery<?>) (operations.removeByQuery(type).inScope(method.getScope())
70+
.inCollection(method.getCollection()));
6871
}
6972

7073
/**
@@ -83,10 +86,8 @@ protected Object doExecute(CouchbaseQueryMethod method, ResultProcessor processo
8386
// query = applyAnnotatedCollationIfPresent(query, accessor); // not yet implemented
8487
query = applyQueryMetaAttributesIfPresent(query, typeToRead);
8588

86-
ReactiveFindByQuery<?> find = findOperationWithProjection;
87-
8889
ReactiveCouchbaseQueryExecution execution = getExecution(accessor,
89-
new ResultProcessingConverter<>(processor, getOperations(), getInstantiators()), find);
90+
new ResultProcessingConverter<>(processor, getOperations(), getInstantiators()), findOp);
9091
return execution.execute(query, processor.getReturnedType().getDomainType(), typeToRead, null);
9192
}
9293

@@ -113,7 +114,7 @@ private ReactiveCouchbaseQueryExecution getExecutionToWrap(ParameterAccessor acc
113114
ReactiveFindByQuery<?> operation) {
114115

115116
if (isDeleteQuery()) {
116-
return new DeleteExecution(getOperations(), getQueryMethod());
117+
return new DeleteExecution(removeOp);
117118
} else if (isTailable(getQueryMethod())) {
118119
return (q, t, r, c) -> operation.as(r).matching(q.with(accessor.getPageable())).all(); // s/b tail() instead of
119120
// all()

src/main/java/org/springframework/data/couchbase/repository/query/CouchbaseQueryExecution.java

+6-9
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2020 the original author or authors.
2+
* Copyright 2020-2022 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -18,15 +18,14 @@
1818
import java.util.List;
1919

2020
import org.springframework.core.convert.converter.Converter;
21-
import org.springframework.data.couchbase.core.CouchbaseOperations;
2221
import org.springframework.data.couchbase.core.ExecutableFindByQueryOperation.ExecutableFindByQuery;
2322
import org.springframework.data.couchbase.core.ExecutableFindByQueryOperation.TerminatingFindByQuery;
23+
import org.springframework.data.couchbase.core.ExecutableRemoveByQueryOperation.ExecutableRemoveByQuery;
2424
import org.springframework.data.couchbase.core.query.Query;
2525
import org.springframework.data.domain.PageImpl;
2626
import org.springframework.data.domain.Pageable;
2727
import org.springframework.data.domain.Slice;
2828
import org.springframework.data.domain.SliceImpl;
29-
import org.springframework.data.repository.query.QueryMethod;
3029
import org.springframework.util.Assert;
3130

3231
/**
@@ -47,12 +46,10 @@ interface CouchbaseQueryExecution {
4746

4847
final class DeleteExecution implements CouchbaseQueryExecution {
4948

50-
private final CouchbaseOperations operations;
51-
private final QueryMethod method;
49+
private final ExecutableRemoveByQuery<?> removeOperation;
5250

53-
public DeleteExecution(CouchbaseOperations operations, QueryMethod method) {
54-
this.operations = operations;
55-
this.method = method;
51+
public DeleteExecution(ExecutableRemoveByQuery<?> removeOperation) {
52+
this.removeOperation = removeOperation;
5653
}
5754

5855
/*
@@ -61,7 +58,7 @@ public DeleteExecution(CouchbaseOperations operations, QueryMethod method) {
6158
*/
6259
@Override
6360
public Object execute(Query query, Class<?> type, Class<?> returnType, String collection) {
64-
return operations.removeByQuery(type).matching(query).all();
61+
return removeOperation.matching(query).all();
6562
}
6663

6764
}

src/main/java/org/springframework/data/couchbase/repository/query/ReactiveCouchbaseQueryExecution.java

+6-8
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2020 the original author or authors.
2+
* Copyright 2020-2022 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,7 +16,7 @@
1616
package org.springframework.data.couchbase.repository.query;
1717

1818
import org.springframework.core.convert.converter.Converter;
19-
import org.springframework.data.couchbase.core.ReactiveCouchbaseOperations;
19+
import org.springframework.data.couchbase.core.ReactiveRemoveByQueryOperation;
2020
import org.springframework.data.couchbase.core.query.Query;
2121
import org.springframework.util.Assert;
2222

@@ -39,12 +39,10 @@ interface ReactiveCouchbaseQueryExecution {
3939

4040
final class DeleteExecution implements ReactiveCouchbaseQueryExecution {
4141

42-
private final ReactiveCouchbaseOperations operations;
43-
private final CouchbaseQueryMethod method;
42+
private final ReactiveRemoveByQueryOperation.ReactiveRemoveByQuery removeOp;
4443

45-
public DeleteExecution(ReactiveCouchbaseOperations operations, CouchbaseQueryMethod method) {
46-
this.operations = operations;
47-
this.method = method;
44+
public DeleteExecution(ReactiveRemoveByQueryOperation.ReactiveRemoveByQuery<?> removeOp) {
45+
this.removeOp = removeOp;
4846
}
4947

5048
/*
@@ -53,7 +51,7 @@ public DeleteExecution(ReactiveCouchbaseOperations operations, CouchbaseQueryMet
5351
*/
5452
@Override
5553
public Object execute(Query query, Class<?> type, Class<?> returnType, String collection) {
56-
return operations.removeByQuery(type)/*.inCollection(collection)*/.matching(query).all();
54+
return removeOp.matching(query).all();
5755
}
5856

5957
}

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

+5
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,11 @@ List<Airport> findByIataInAndIcaoIn(java.util.Collection<String> size, java.util
104104
@ScanConsistency(query = QueryScanConsistency.REQUEST_PLUS)
105105
List<RemoveResult> deleteByIata(String iata);
106106

107+
@Query("#{#n1ql.delete} WHERE #{#n1ql.filter} and iata = $1 #{#n1ql.returning}")
108+
@ScanConsistency(query = QueryScanConsistency.REQUEST_PLUS)
109+
@Collection("bogus_collection")
110+
List<RemoveResult> deleteByIataAnnotated(String iata);
111+
107112
@Query("SELECT __cas, * from #{#n1ql.bucket} where iata = $1")
108113
@ScanConsistency(query = QueryScanConsistency.REQUEST_PLUS)
109114
List<Airport> getAllByIataNoID(String iata);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/*
2+
* Copyright 2022 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.data.couchbase.domain;
17+
18+
import org.springframework.data.couchbase.repository.Collection;
19+
20+
/**
21+
* AirportRepository with collection annotation
22+
*
23+
* @author Michael Reiche
24+
*/
25+
@Collection("my_collection2")
26+
public interface AirportRepositoryAnnotated extends AirportRepository {}

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

+5-5
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ public void beforeEach() {
105105
static List<String> keyList = Arrays.asList("a", "b", "c", "d", "e");
106106
static Collection collection;
107107
static ReactiveCollection rCollection;
108-
@Autowired ReactiveAirportRepository airportRepository; // intellij flags "Could not Autowire", but it runs ok.
108+
@Autowired ReactiveAirportRepository reactiveAirportRepository; // intellij flags "Could not Autowire", runs ok
109109

110110
AtomicInteger rCat = new AtomicInteger(0);
111111
AtomicInteger rFlat = new AtomicInteger(0);
@@ -136,7 +136,7 @@ public void cbse() {
136136
listOfLists.add(list);
137137
}
138138
Flux<Object> af = Flux.fromIterable(listOfLists).concatMap(catalogToStore -> Flux.fromIterable(catalogToStore)
139-
.parallel(4).runOn(Schedulers.parallel()).concatMap((entity) -> airportRepository.save(entity)));
139+
.parallel(4).runOn(Schedulers.parallel()).concatMap((entity) -> reactiveAirportRepository.save(entity)));
140140
List<Object> saved = af.collectList().block();
141141
System.out.println("results.size() : " + saved.size());
142142

@@ -152,7 +152,7 @@ public void cbse() {
152152
e.printStackTrace();
153153
throw e;
154154
}
155-
List<Airport> airports = airportRepository.findAll().collectList().block();
155+
List<Airport> airports = reactiveAirportRepository.findAll().collectList().block();
156156
assertEquals(0, airports.size(), "should have been all deleted");
157157
}
158158

@@ -164,11 +164,11 @@ public void pairIdAndResult() {
164164
for (int i = 0; i < 5; i++) {
165165
list.add(a.withId(UUID.randomUUID().toString()));
166166
}
167-
Flux<Object> af = Flux.fromIterable(list).concatMap((entity) -> airportRepository.save(entity));
167+
Flux<Object> af = Flux.fromIterable(list).concatMap((entity) -> reactiveAirportRepository.save(entity));
168168
List<Object> saved = af.collectList().block();
169169
System.out.println("results.size() : " + saved.size());
170170
Flux<Pair<String, Mono<Airport>>> pairFlux = Flux.fromIterable(list)
171-
.map((airport) -> Pair.of(airport.getId(), airportRepository.findById(airport.getId())));
171+
.map((airport) -> Pair.of(airport.getId(), reactiveAirportRepository.findById(airport.getId())));
172172
List<Pair<String, Mono<Airport>>> airportPairs = pairFlux.collectList().block();
173173
for (Pair<String, Mono<Airport>> airportPair : airportPairs) {
174174
System.out.println("id: " + airportPair.getFirst() + " airport: " + airportPair.getSecond().block());

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

+12-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2017-2021 the original author or authors.
2+
* Copyright 2017-2022 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -21,6 +21,8 @@
2121

2222
import java.util.ArrayList;
2323

24+
import org.springframework.data.couchbase.core.RemoveResult;
25+
import org.springframework.data.couchbase.repository.Collection;
2426
import org.springframework.data.couchbase.repository.DynamicProxyable;
2527
import org.springframework.data.couchbase.repository.Query;
2628
import org.springframework.data.couchbase.repository.ReactiveCouchbaseRepository;
@@ -99,6 +101,15 @@ public interface ReactiveAirportRepository
99101
@ScanConsistency(query = QueryScanConsistency.REQUEST_PLUS)
100102
Mono<Airport> findByIata(String iata);
101103

104+
@Query("#{#n1ql.delete} WHERE #{#n1ql.filter} and iata = $1 #{#n1ql.returning}")
105+
@ScanConsistency(query = QueryScanConsistency.REQUEST_PLUS)
106+
Flux<RemoveResult> deleteByIata(String iata);
107+
108+
@Query("#{#n1ql.delete} WHERE #{#n1ql.filter} and iata = $1 #{#n1ql.returning}")
109+
@ScanConsistency(query = QueryScanConsistency.REQUEST_PLUS)
110+
@Collection("bogus_collection")
111+
Flux<RemoveResult> deleteByIataAnnotated(String iata);
112+
102113
// This is not efficient. See findAllByIataLike for efficient reactive paging
103114
default public Mono<Page<Airport>> findAllAirportsPaged(Pageable pageable) {
104115
return count().flatMap(airportCount -> {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/*
2+
* Copyright 2022 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.data.couchbase.domain;
17+
18+
import org.springframework.data.couchbase.repository.Collection;
19+
20+
/**
21+
* AirportRepository with collection annotation
22+
*
23+
* @author Michael Reiche
24+
*/
25+
@Collection("my_collection2")
26+
public interface ReactiveAirportRepositoryAnnotated extends ReactiveAirportRepository{}

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

+4-4
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ public class ReactiveCouchbaseRepositoryKeyValueIntegrationTests extends Cluster
6060

6161
@Autowired ReactiveUserRepository userRepository;
6262

63-
@Autowired ReactiveAirportRepository airportRepository;
63+
@Autowired ReactiveAirportRepository reactiveAirportRepository;
6464

6565
@Autowired ReactiveAirlineRepository airlineRepository;
6666

@@ -108,13 +108,13 @@ void findByIdAudited() {
108108
Airport vie = null;
109109
try {
110110
vie = new Airport("airports::vie", "vie", "low2");
111-
Airport saved = airportRepository.save(vie).block();
112-
Airport airport1 = airportRepository.findById(saved.getId()).block();
111+
Airport saved = reactiveAirportRepository.save(vie).block();
112+
Airport airport1 = reactiveAirportRepository.findById(saved.getId()).block();
113113
assertEquals(airport1, saved);
114114
assertEquals(saved.getCreatedBy(), ReactiveNaiveAuditorAware.AUDITOR); // ReactiveNaiveAuditorAware will provide
115115
// this
116116
} finally {
117-
airportRepository.delete(vie).block();
117+
reactiveAirportRepository.delete(vie).block();
118118
}
119119
}
120120

0 commit comments

Comments
 (0)