Skip to content

Commit fab72ee

Browse files
authored
DATACOUCH-615 Use query in removeByQuery (#264)
* DATACOUCH-615 Use query in removeByQuery Use provided query instead of hardcoded statement. * DATACOUCH-615 Better method naming in Query class * DATACOUCH-615 Replace hard-coded meta fields * DATACOUCH-615 Test findByQuery.matching * DATACOUCH-615 Remove failing test
1 parent 2a06578 commit fab72ee

File tree

7 files changed

+54
-28
lines changed

7 files changed

+54
-28
lines changed

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ public Mono<Boolean> exists() {
121121
}
122122

123123
private String assembleEntityQuery(final boolean count) {
124-
return query.toN1qlString(template, this.domainType, count);
124+
return query.toN1qlSelectString(template, this.domainType, count);
125125
}
126126

127127
}

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

+7-9
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
*/
1616
package org.springframework.data.couchbase.core;
1717

18+
import org.springframework.data.couchbase.core.support.TemplateUtils;
1819
import reactor.core.publisher.Flux;
1920

2021
import java.util.Optional;
@@ -58,14 +59,7 @@ static class ReactiveRemoveByQuerySupport<T> implements ReactiveRemoveByQuery<T>
5859
@Override
5960
public Flux<RemoveResult> all() {
6061
return Flux.defer(() -> {
61-
String bucket = "`" + template.getBucketName() + "`";
62-
63-
String typeKey = template.getConverter().getTypeKey();
64-
String typeValue = template.support().getJavaNameForEntity(domainType);
65-
String where = " WHERE `" + typeKey + "` = \"" + typeValue + "\"";
66-
67-
String returning = " RETURNING meta().*";
68-
String statement = "DELETE FROM " + bucket + " " + where + returning;
62+
String statement = assembleDeleteQuery();
6963

7064
return template.getCouchbaseClientFactory().getCluster().reactive().query(statement, buildQueryOptions())
7165
.onErrorMap(throwable -> {
@@ -75,7 +69,7 @@ public Flux<RemoveResult> all() {
7569
return throwable;
7670
}
7771
}).flatMapMany(ReactiveQueryResult::rowsAsObject)
78-
.map(row -> new RemoveResult(row.getString("id"), row.getLong("cas"), Optional.empty()));
72+
.map(row -> new RemoveResult(row.getString(TemplateUtils.SELECT_ID), row.getLong(TemplateUtils.SELECT_CAS), Optional.empty()));
7973
});
8074
}
8175

@@ -97,6 +91,10 @@ public RemoveByQueryWithQuery<T> consistentWith(final QueryScanConsistency scanC
9791
return new ReactiveRemoveByQuerySupport<>(template, domainType, query, scanConsistency);
9892
}
9993

94+
private String assembleDeleteQuery() {
95+
return query.toN1qlRemoveString(template, this.domainType);
96+
}
97+
10098
}
10199

102100
}

src/main/java/org/springframework/data/couchbase/core/query/Query.java

+11-1
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,7 @@ public String export() {
243243
return sb.toString();
244244
}
245245

246-
public String toN1qlString(ReactiveCouchbaseTemplate template, Class domainClass, boolean isCount) {
246+
public String toN1qlSelectString(ReactiveCouchbaseTemplate template, Class domainClass, boolean isCount) {
247247
StringBasedN1qlQueryParser.N1qlSpelValues n1ql = getN1qlSpelValues(template, domainClass, isCount);
248248
final StringBuilder statement = new StringBuilder();
249249
appendString(statement, n1ql.selectEntity); // select ...
@@ -254,6 +254,16 @@ public String toN1qlString(ReactiveCouchbaseTemplate template, Class domainClass
254254
return statement.toString();
255255
}
256256

257+
public String toN1qlRemoveString(ReactiveCouchbaseTemplate template, Class domainClass) {
258+
StringBasedN1qlQueryParser.N1qlSpelValues n1ql = getN1qlSpelValues(template, domainClass, false);
259+
final StringBuilder statement = new StringBuilder();
260+
appendString(statement, n1ql.delete); // delete ...
261+
appendWhereString(statement, n1ql.filter); // typeKey = typeValue
262+
appendWhere(statement, null); // criteria on this Query
263+
appendString(statement, n1ql.returning);
264+
return statement.toString();
265+
}
266+
257267
StringBasedN1qlQueryParser.N1qlSpelValues getN1qlSpelValues(ReactiveCouchbaseTemplate template, Class domainClass,
258268
boolean isCount) {
259269
String typeKey = template.getConverter().getTypeKey();

src/main/java/org/springframework/data/couchbase/core/query/StringQuery.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ private void appendInlineN1qlStatement(final StringBuilder sb) {
5252
}
5353

5454
@Override
55-
public String toN1qlString(ReactiveCouchbaseTemplate template, Class domainClass, boolean isCount) {
55+
public String toN1qlSelectString(ReactiveCouchbaseTemplate template, Class domainClass, boolean isCount) {
5656
final StringBuilder statement = new StringBuilder();
5757
appendInlineN1qlStatement(statement); // apply the string statement
5858
// To use generated parameters for literals

src/test/java/org/springframework/data/couchbase/core/CouchbaseTemplateQueryIntegrationTests.java

+31-4
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,10 @@
3232
import org.junit.jupiter.api.Test;
3333
import org.springframework.context.ApplicationContext;
3434
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
35-
import org.springframework.dao.DataRetrievalFailureException;
3635
import org.springframework.data.couchbase.CouchbaseClientFactory;
3736
import org.springframework.data.couchbase.SimpleCouchbaseClientFactory;
37+
import org.springframework.data.couchbase.core.query.Query;
38+
import org.springframework.data.couchbase.core.query.QueryCriteria;
3839
import org.springframework.data.couchbase.domain.Config;
3940
import org.springframework.data.couchbase.domain.NaiveAuditorAware;
4041
import org.springframework.data.couchbase.domain.User;
@@ -46,13 +47,13 @@
4647

4748
import com.couchbase.client.core.error.IndexExistsException;
4849
import com.couchbase.client.java.query.QueryScanConsistency;
49-
import reactor.core.publisher.Mono;
5050

5151
/**
5252
* Query tests Theses tests rely on a cb server running
5353
*
5454
* @author Michael Nitschinger
5555
* @author Michael Reiche
56+
* @author Haris Alesevic
5657
*/
5758
@IgnoreWhen(missesCapabilities = Capabilities.QUERY, clusterTypes = ClusterType.MOCKED)
5859
class CouchbaseTemplateQueryIntegrationTests extends ClusterAwareIntegrationTests {
@@ -82,10 +83,12 @@ void beforeEach() {
8283
ApplicationContext ac = new AnnotationConfigApplicationContext(Config.class);
8384
couchbaseTemplate = (CouchbaseTemplate) ac.getBean(COUCHBASE_TEMPLATE);
8485
reactiveCouchbaseTemplate = (ReactiveCouchbaseTemplate) ac.getBean(REACTIVE_COUCHBASE_TEMPLATE);
86+
// ensure each test starts with clean state
87+
couchbaseTemplate.removeByQuery(User.class).all();
8588
}
8689

8790
@Test
88-
void findByQuery() {
91+
void findByQueryAll() {
8992
try {
9093
User user1 = new User(UUID.randomUUID().toString(), "user1", "user1");
9194
User user2 = new User(UUID.randomUUID().toString(), "user2", "user2");
@@ -128,7 +131,7 @@ void findByQuery() {
128131
}
129132

130133
@Test
131-
void removeByQuery() {
134+
void removeByQueryAll() {
132135
User user1 = new User(UUID.randomUUID().toString(), "user1", "user1");
133136
User user2 = new User(UUID.randomUUID().toString(), "user2", "user2");
134137

@@ -144,4 +147,28 @@ void removeByQuery() {
144147

145148
}
146149

150+
@Test
151+
void removeByMatchingQuery() {
152+
User user1 = new User(UUID.randomUUID().toString(), "user1", "user1");
153+
User user2 = new User(UUID.randomUUID().toString(), "user2", "user2");
154+
User specialUser = new User(UUID.randomUUID().toString(), "special", "special");
155+
156+
couchbaseTemplate.upsertById(User.class).all(Arrays.asList(user1, user2, specialUser));
157+
158+
assertTrue(couchbaseTemplate.existsById().one(user1.getId()));
159+
assertTrue(couchbaseTemplate.existsById().one(user2.getId()));
160+
assertTrue(couchbaseTemplate.existsById().one(specialUser.getId()));
161+
162+
Query nonSpecialUsers = new Query(QueryCriteria.where("firstname").notLike("special"));
163+
164+
couchbaseTemplate.removeByQuery(User.class).consistentWith(QueryScanConsistency.REQUEST_PLUS)
165+
.matching(nonSpecialUsers)
166+
.all();
167+
168+
assertNull(couchbaseTemplate.findById(User.class).one(user1.getId()));
169+
assertNull(couchbaseTemplate.findById(User.class).one(user2.getId()));
170+
assertNotNull(couchbaseTemplate.findById(User.class).one(specialUser.getId()));
171+
172+
}
173+
147174
}

src/test/java/org/springframework/data/couchbase/repository/query/StringN1qlQueryCreatorMockedTests.java

+2-10
Original file line numberDiff line numberDiff line change
@@ -22,22 +22,16 @@
2222
import org.springframework.context.annotation.Configuration;
2323
import org.springframework.data.couchbase.config.AbstractCouchbaseConfiguration;
2424
import org.springframework.data.couchbase.core.CouchbaseTemplate;
25-
import org.springframework.data.couchbase.core.ExecutableFindByQueryOperation;
2625
import org.springframework.data.couchbase.core.convert.CouchbaseConverter;
2726
import org.springframework.data.couchbase.core.convert.MappingCouchbaseConverter;
2827
import org.springframework.data.couchbase.core.mapping.CouchbaseMappingContext;
2928
import org.springframework.data.couchbase.core.mapping.CouchbasePersistentEntity;
3029
import org.springframework.data.couchbase.core.mapping.CouchbasePersistentProperty;
3130
import org.springframework.data.couchbase.core.query.Query;
32-
import org.springframework.data.couchbase.domain.Airline;
33-
import org.springframework.data.couchbase.domain.AirlineRepository;
3431
import org.springframework.data.couchbase.domain.User;
3532
import org.springframework.data.couchbase.domain.UserRepository;
3633
import org.springframework.data.couchbase.repository.config.EnableCouchbaseRepositories;
37-
import org.springframework.data.couchbase.util.Capabilities;
3834
import org.springframework.data.couchbase.util.ClusterAwareIntegrationTests;
39-
import org.springframework.data.couchbase.util.ClusterType;
40-
import org.springframework.data.couchbase.util.IgnoreWhen;
4135
import org.springframework.data.mapping.context.MappingContext;
4236
import org.springframework.data.projection.SpelAwareProxyProjectionFactory;
4337
import org.springframework.data.repository.core.NamedQueries;
@@ -46,9 +40,7 @@
4640
import org.springframework.data.repository.query.*;
4741

4842
import java.lang.reflect.Method;
49-
import java.util.Optional;
5043
import java.util.Properties;
51-
import java.util.UUID;
5244

5345
import static org.junit.jupiter.api.Assertions.assertEquals;
5446
import static org.junit.jupiter.api.Assertions.fail;
@@ -88,7 +80,7 @@ void createsQueryCorrectly() throws Exception {
8880
Query query = creator.createQuery();
8981
assertEquals(
9082
"SELECT META(`travel-sample`).id AS __id, META(`travel-sample`).cas AS __cas, `travel-sample`.* FROM `travel-sample` where `_class` = \"org.springframework.data.couchbase.domain.User\" and firstname = $1 and lastname = $2",
91-
query.toN1qlString(couchbaseTemplate.reactive(), User.class, false));
83+
query.toN1qlSelectString(couchbaseTemplate.reactive(), User.class, false));
9284
}
9385

9486
@Test
@@ -106,7 +98,7 @@ void createsQueryCorrectly2() throws Exception {
10698
Query query = creator.createQuery();
10799
assertEquals(
108100
"SELECT META(`travel-sample`).id AS __id, META(`travel-sample`).cas AS __cas, `travel-sample`.* FROM `travel-sample` where `_class` = \"org.springframework.data.couchbase.domain.User\" and (firstname = $first or lastname = $last)",
109-
query.toN1qlString(couchbaseTemplate.reactive(), User.class, false));
101+
query.toN1qlSelectString(couchbaseTemplate.reactive(), User.class, false));
110102
}
111103

112104
@Test

src/test/java/org/springframework/data/couchbase/repository/query/StringN1qlQueryCreatorTests.java

+1-2
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525

2626
import org.junit.jupiter.api.BeforeEach;
2727
import org.junit.jupiter.api.Test;
28-
import org.springframework.beans.factory.annotation.Autowired;
2928
import org.springframework.context.ApplicationContext;
3029
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
3130
import org.springframework.context.annotation.Configuration;
@@ -91,7 +90,7 @@ void findUsingStringNq1l() throws Exception {
9190
queryMethod, converter, config().bucketname(), QueryMethodEvaluationContextProvider.DEFAULT, namedQueries);
9291

9392
Query query = creator.createQuery();
94-
System.out.println(query.toN1qlString(couchbaseTemplate.reactive(), Airline.class, false));
93+
System.out.println(query.toN1qlSelectString(couchbaseTemplate.reactive(), Airline.class, false));
9594

9695
try {
9796
Thread.sleep(3000);

0 commit comments

Comments
 (0)