Skip to content

Commit d4a3910

Browse files
committed
Merge branch 'datacouch_1288_querydsl_support' of github.com:spring-projects/spring-data-couchbase into datacouch_1288_querydsl_support
2 parents 64724cd + 5a8d65c commit d4a3910

File tree

3 files changed

+39
-121
lines changed

3 files changed

+39
-121
lines changed

src/main/java/com/querydsl/couchbase/document/CouchbaseDocumentSerializer.java

+22-113
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ public Object handle(Expression<?> expression) {
5454
return expression.accept(this, null);
5555
}
5656

57+
// TODO
5758
public Sort toSort(List<OrderSpecifier<?>> orderBys) {
5859
Sort sort = Sort.unsorted();
5960
for (OrderSpecifier<?> orderBy : orderBys) {
@@ -99,12 +100,12 @@ private String regexValue(Operation<?> expr, int index) {
99100

100101
protected QueryCriteriaDefinition asDocument(String key, Object value) {
101102
QueryCriteria qc = null;
102-
if (1 == 1) {
103+
if (workInProgress) {
103104
throw new UnsupportedOperationException("Wrong path to create this criteria " + key);
104105
}
105-
if (key.equals("$and") || key.equals("$or") /* value instanceof QueryCriteria[] */) {
106+
if (key.equals(Ops.AND) || key.equals(Ops.OR)) {
106107
throw new UnsupportedOperationException("Wrong path to create this criteria " + key);
107-
} else if (key.equals("$in") /* value instanceof QueryCriteria[] */) {
108+
} else if (key.equals(Ops.IN)) {
108109
throw new RuntimeException(("not supported"));
109110
} else {
110111
qc = QueryCriteria.where(key).is(value);
@@ -122,21 +123,14 @@ public Object visit(Operation<?> expr, Void context) {
122123
Operation<?> lhs = (Operation<?>) expr.getArg(0);
123124
if (lhs.getOperator() == Ops.COL_SIZE || lhs.getOperator() == Ops.ARRAY_SIZE
124125
|| lhs.getOperator() == Ops.STRING_LENGTH) {
125-
// return asDocument(asDBKey(lhs, 0), asDocument("$size", asDBValue(expr, 1)));
126126
return QueryCriteria.where(asDBKey(expr, 0)).is(asDBValue(expr, 1));
127127
} else {
128128
throw new UnsupportedOperationException("Illegal operation " + expr);
129129
}
130130
} else if (expr.getArg(0) instanceof Path) {
131-
/*
132-
Path<?> path = (Path<?>) expr.getArg(0);
133-
Constant<?> constant = (Constant<?>) expr.getArg(1);
134-
return asDocument(asDBKey(expr, 0), convert(path, constant));
135-
*/
136131
return QueryCriteria.where(asDBKey(expr, 0)).is(asDBValue(expr, 1));
137132
}
138133
} else if (op == Ops.STRING_IS_EMPTY) {
139-
// return asDocument(asDBKey(expr, 0), "");
140134
return QueryCriteria.where(asDBKey(expr, 0)).isNotValued().or(asDBKey(expr, 0)).is("");
141135
} else if (op == Ops.NOT) {
142136
// Handle the not's child
@@ -148,64 +142,41 @@ public Object visit(Operation<?> expr, Void context) {
148142
context);
149143
} else {
150144
QueryCriteria arg = (QueryCriteria) handle(expr.getArg(0));
151-
return arg.negate(); // negate(arg);
145+
return arg.negate();
152146
}
153147

154148
} else if (op == Ops.AND) {
155-
// return asDocument("$and", collectConnectorArgs("$and", expr));
156-
return collectConnectorArgs("$and", expr);
149+
return collectConnectorArgs(Ops.AND, expr);
157150
} else if (op == Ops.OR) {
158-
// return asDocument("$or", collectConnectorArgs("$or", expr));
159-
return collectConnectorArgs("$or", expr);
151+
return collectConnectorArgs(Ops.OR, expr);
160152
} else if (op == Ops.NE) {
161-
// Path<?> path = (Path<?>) expr.getArg(0);
162-
// Constant<?> constant = (Constant<?>) expr.getArg(1);
163-
// return asDocument(asDBKey(expr, 0), asDocument("$ne", convert(path, constant)));
164153
return QueryCriteria.where(asDBKey(expr, 0)).ne(asDBValue(expr, 1));
165154
} else if (op == Ops.STARTS_WITH) {
166-
// return asDocument(asDBKey(expr, 0), new CBRegularExpression("^" + regexValue(expr, 1)));
167155
return QueryCriteria.where(asDBKey(expr, 0)).startingWith(asDBValue(expr, 1));
168156
} else if (op == Ops.STARTS_WITH_IC) {
169-
// return asDocument(asDBKey(expr, 0), new CBRegularExpression("^" + regexValue(expr, 1), "i"));
170157
return QueryCriteria.where(asDBKey(expr, 0)).upper()
171158
.startingWith(asDBValue(expr, 1).toString().toUpperCase(Locale.ROOT));
172159
} else if (op == Ops.ENDS_WITH) {
173-
// return asDocument(asDBKey(expr, 0), new CBRegularExpression(regexValue(expr, 1) + "$"));
174160
return QueryCriteria.where(asDBKey(expr, 0)).endingWith(asDBValue(expr, 1));
175161
} else if (op == Ops.ENDS_WITH_IC) {
176-
// return asDocument(asDBKey(expr, 0), new CBRegularExpression(regexValue(expr, 1) + "$", "i"));
177162
return QueryCriteria.where(asDBKey(expr, 0)).upper()
178163
.endingWith(asDBValue(expr, 1).toString().toUpperCase(Locale.ROOT));
179164
} else if (op == Ops.EQ_IGNORE_CASE) {
180-
// return asDocument(asDBKey(expr, 0), new CBRegularExpression("^" + regexValue(expr, 1) + "$", "i"));
181165
return QueryCriteria.where(asDBKey(expr, 0)).upper().eq(asDBValue(expr, 1).toString().toUpperCase(Locale.ROOT));
182166
} else if (op == Ops.STRING_CONTAINS) {
183-
// return asDocument(asDBKey(expr, 0), new CBRegularExpression(".*" + regexValue(expr, 1) + ".*"));
184167
return QueryCriteria.where(asDBKey(expr, 0)).containing(asDBValue(expr, 1));
185168
} else if (op == Ops.STRING_CONTAINS_IC) {
186-
// return asDocument(asDBKey(expr, 0), new CBRegularExpression(".*" + regexValue(expr, 1) + ".*", "i"));
187169
return QueryCriteria.where(asDBKey(expr, 0)).upper()
188170
.containing(asDBValue(expr, 1).toString().toUpperCase(Locale.ROOT));
189-
/*
190-
} else if (op == Ops.MATCHES) {
191-
//return asDocument(asDBKey(expr, 0), new CBRegularExpression(asDBValue(expr, 1).toString()));
192-
return QueryCriteria.where(asDBKey(expr, 0)).like(asDBValue(expr,1));
193-
} else if (op == Ops.MATCHES_IC) {
194-
//return asDocument(asDBKey(expr, 0), new CBRegularExpression(asDBValue(expr, 1).toString(), "i"));
195-
return QueryCriteria.where("UPPER("+asDBKey(expr, 0)+")").like("UPPER("+asDBValue(expr,1)+")");
196-
*/
171+
} else if (op == Ops.MATCHES) {
172+
return QueryCriteria.where(asDBKey(expr, 0)).regex(asDBValue(expr, 1));
173+
} else if (op == Ops.MATCHES_IC) {
174+
return QueryCriteria.where("UPPER(" + asDBKey(expr, 0) + ")").regex("UPPER(" + asDBValue(expr, 1) + ")");
197175
} else if (op == Ops.LIKE) {
198-
// String regex = ExpressionUtils.likeToRegex((Expression) expr.getArg(1)).toString();
199-
// return asDocument(asDBKey(expr, 0), new CBRegularExpression(regex));
200176
return QueryCriteria.where(asDBKey(expr, 0)).like(asDBValue(expr, 1));
201177
} else if (op == Ops.LIKE_IC) {
202-
// String regex = ExpressionUtils.likeToRegex((Expression) expr.getArg(1)).toString();
203-
// return asDocument(asDBKey(expr, 0), new CBRegularExpression(regex, "i"));
204178
return QueryCriteria.where(asDBKey(expr, 0)).upper().like(asDBValue(expr, 1).toString().toUpperCase(Locale.ROOT));
205179
} else if (op == Ops.BETWEEN) {
206-
// Document value = new Document("$gte", this.asDBValue(expr, 1));
207-
// value.append("$lte", this.asDBValue(expr, 2));
208-
// return this.asDocument(this.asDBKey(expr, 0), value);
209180
return QueryCriteria.where(asDBKey(expr, 0)).between(asDBValue(expr, 1), asDBValue(expr, 2));
210181
} else if (op == Ops.IN) {
211182
int constIndex = 0;
@@ -217,16 +188,13 @@ public Object visit(Operation<?> expr, Void context) {
217188
if (Collection.class.isAssignableFrom(expr.getArg(constIndex).getType())) {
218189
@SuppressWarnings("unchecked") // guarded by previous check
219190
Collection<?> values = ((Constant<? extends Collection<?>>) expr.getArg(constIndex)).getConstant();
220-
// return asDocument(asDBKey(expr, exprIndex), asDocument("$in", values));
221191
return QueryCriteria.where(asDBKey(expr, exprIndex)).in(values);
222-
} else { // I think framework already converts IN to EQ if arg is not a collection
223-
// Path<?> path = (Path<?>) expr.getArg(exprIndex);
224-
// Constant<?> constant = (Constant<?>) expr.getArg(constIndex);
225-
// return asDocument(asDBKey(expr, exprIndex), convert(path, constant));
192+
} else { // framework already converts IN to EQ if arg is not a collection
193+
if (workInProgress)
194+
throw new RuntimeException("good, we are testing in -> eq");
226195
Object value = expr.getArg(constIndex);
227196
return QueryCriteria.where(asDBKey(expr, exprIndex)).eq(value);
228197
}
229-
230198
} else if (op == Ops.NOT_IN) {
231199
int constIndex = 0;
232200
int exprIndex = 1;
@@ -237,93 +205,35 @@ public Object visit(Operation<?> expr, Void context) {
237205
if (Collection.class.isAssignableFrom(expr.getArg(constIndex).getType())) {
238206
@SuppressWarnings("unchecked") // guarded by previous check
239207
Collection<?> values = ((Constant<? extends Collection<?>>) expr.getArg(constIndex)).getConstant();
240-
// return asDocument(asDBKey(expr, exprIndex), asDocument("$nin", values));
241208
return QueryCriteria.where(asDBKey(expr, exprIndex)).notIn(values);
242-
} else { // I think framework already converts NOT_IN to NE if arg is not a collection
243-
// Path<?> path = (Path<?>) expr.getArg(exprIndex);
244-
// Constant<?> constant = (Constant<?>) expr.getArg(constIndex);
245-
// return asDocument(asDBKey(expr, exprIndex), asDocument("$ne", convert(path, constant)));
209+
} else { // framework already converts NOT_IN to NE if arg is not a collection
210+
if (workInProgress)
211+
throw new RuntimeException("good, we are testing not_in -> ne");
246212
Object value = expr.getArg(constIndex);
247213
return QueryCriteria.where(asDBKey(expr, exprIndex)).ne(value);
248214
}
249-
250215
} else if (op == Ops.COL_IS_EMPTY) {
251-
// List<Object> list = new ArrayList<Object>(2);
252-
// list.add(asDocument(asDBKey(expr, 0), new ArrayList<Object>()));
253-
// list.add(asDocument(asDBKey(expr, 0), asDocument("$exists", false)));
254-
// return asDocument("$or", list);
255216
return QueryCriteria.where(asDBKey(expr, 0)).isNotValued();
256217
} else if (op == Ops.LT) {
257-
// return asDocument(asDBKey(expr, 0), asDocument("$lt", asDBValue(expr, 1)));
258218
return QueryCriteria.where(asDBKey(expr, 0)).lt(asDBValue(expr, 1));
259219
} else if (op == Ops.GT) {
260-
// return asDocument(asDBKey(expr, 0), asDocument("$gt", asDBValue(expr, 1)));
261220
return QueryCriteria.where(asDBKey(expr, 0)).gt(asDBValue(expr, 1));
262221
} else if (op == Ops.LOE) {
263-
// return asDocument(asDBKey(expr, 0), asDocument("$lte", asDBValue(expr, 1)));
264222
return QueryCriteria.where(asDBKey(expr, 0)).lte(asDBValue(expr, 1));
265223
} else if (op == Ops.GOE) {
266-
// return asDocument(asDBKey(expr, 0), asDocument("$gte", asDBValue(expr, 1)));
267224
return QueryCriteria.where(asDBKey(expr, 0)).gte(asDBValue(expr, 1));
268225
} else if (op == Ops.IS_NULL) {
269-
// return asDocument(asDBKey(expr, 0), asDocument("$exists", false));
270226
return QueryCriteria.where(asDBKey(expr, 0)).isNull();
271227
} else if (op == Ops.IS_NOT_NULL) {
272-
// return asDocument(asDBKey(expr, 0), asDocument("$exists", true));
273228
return QueryCriteria.where(asDBKey(expr, 0)).isNotNull();
274229
} else if (op == Ops.CONTAINS_KEY) { // TODO not sure about this one
275-
Path<?> path = (Path<?>) expr.getArg(0);
276-
// Expression<?> key = expr.getArg(1);
277-
// return asDocument(visit(path, context) + "." + key.toString(), asDocument("$exists", true));
278230
return QueryCriteria.where("meta().id"/*asDBKey(expr, 0)*/).eq(asDBKey(expr, 1));
279231
} else if (op == Ops.STRING_LENGTH) {
280232
return "LENGTH(" + asDBKey(expr, 0) + ")";// QueryCriteria.where(asDBKey(expr, 0)).size();
281233
}
282-
283-
throw new UnsupportedOperationException("Illegal operation " + expr);
234+
throw new UnsupportedOperationException("Unsupported operation " + expr);
284235
}
285236

286-
/* TODO -- need later
287-
private Object negate(QueryCriteriaDefinition arg) {
288-
List<Object> list = new ArrayList<Object>();
289-
for (Map.Entry<String, Object> entry : arg.entrySet()) {
290-
if (entry.getKey().equals("$or")) {
291-
list.add(asDocument("$nor", entry.getValue()));
292-
293-
} else if (entry.getKey().equals("$and")) {
294-
List<Object> list2 = new ArrayList<Object>();
295-
for (Object o : ((Collection) entry.getValue())) {
296-
list2.add(negate((QueryCriteriaDefinition) o));
297-
}
298-
list.add(asDocument("$or", list2));
299-
300-
} else if (entry.getValue() instanceof Pattern || entry.getValue() instanceof CBRegularExpression) {
301-
list.add(asDocument(entry.getKey(), asDocument("$not", entry.getValue())));
302-
303-
} else if (entry.getValue() instanceof QueryCriteriaDefinition) {
304-
list.add(negate(entry.getKey(), (QueryCriteriaDefinition) entry.getValue()));
305-
306-
} else {
307-
list.add(asDocument(entry.getKey(), asDocument("$ne", entry.getValue())));
308-
}
309-
}
310-
return list.size() == 1 ? list.get(0) : asDocument("$or", list);
311-
}
312-
313-
private Object negate(String key, QueryCriteriaDefinition value) {
314-
if (value.size() == 1) {
315-
return asDocument(key, asDocument("$not", value));
316-
} else {
317-
List<Object> list2 = new ArrayList<Object>();
318-
for (Map.Entry<String, Object> entry2 : value.entrySet()) {
319-
list2.add(asDocument(key, asDocument("$not", asDocument(entry2.getKey(), entry2.getValue()))));
320-
}
321-
return asDocument("$or", list2);
322-
}
323-
}
324-
*/
325-
326-
/* TODO -- need later
327237
protected Object convert(Path<?> property, Constant<?> constant) {
328238
if (isReference(property)) {
329239
return asReference(constant.getConstant());
@@ -332,12 +242,11 @@ protected Object convert(Path<?> property, Constant<?> constant) {
332242
return asReferenceKey(property.getMetadata().getParent().getType(), constant.getConstant());
333243
} else if (constant.getType().equals(String.class) && isImplicitObjectIdConversion()) {
334244
String id = (String) constant.getConstant();
335-
return ObjectId.isValid(id) ? new ObjectId(id) : id;
245+
return id;
336246
}
337247
}
338248
return visit(constant, null);
339249
}
340-
*/
341250

342251
protected boolean isImplicitObjectIdConversion() {
343252
return true;
@@ -390,16 +299,16 @@ public Object visit(ParamExpression<?> expr, Void context) {
390299
throw new UnsupportedOperationException();
391300
}
392301

393-
private QueryCriteriaDefinition collectConnectorArgs(String operator, Operation<?> operation) {
302+
private QueryCriteriaDefinition collectConnectorArgs(Ops operator, Operation<?> operation) {
394303
QueryCriteria first = null;
395304
for (Expression<?> exp : operation.getArgs()) {
396305
QueryCriteria document = (QueryCriteria) handle(exp);
397306
if (first == null) {
398307
first = document;
399308
} else {
400-
if (operator.equals("$or")) {
309+
if (operator.equals(Ops.OR)) {
401310
first = first.or(document);
402-
} else if (operator.equals("$and")) {
311+
} else if (operator.equals(Ops.AND)) {
403312
first = first.and(document);
404313
}
405314
}

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

+4-8
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,11 @@
2323
import java.util.LinkedList;
2424
import java.util.List;
2525

26-
import com.couchbase.client.core.error.CouchbaseException;
2726
import org.springframework.data.couchbase.core.convert.CouchbaseConverter;
2827
import org.springframework.lang.Nullable;
2928
import org.springframework.util.CollectionUtils;
3029

30+
import com.couchbase.client.core.error.CouchbaseException;
3131
import com.couchbase.client.core.error.InvalidArgumentException;
3232
import com.couchbase.client.java.json.JsonArray;
3333
import com.couchbase.client.java.json.JsonObject;
@@ -142,7 +142,6 @@ public QueryCriteria and(String key) {
142142
}
143143

144144
public QueryCriteria and(N1QLExpression key) {
145-
// this.criteriaChain.getLast().setChainOperator(ChainOperator.AND);
146145
return new QueryCriteria(this.criteriaChain, key, null, ChainOperator.AND);
147146
}
148147

@@ -158,7 +157,7 @@ public QueryCriteria and(QueryCriteria criteria) {
158157
QueryCriteria qc = wrap(criteria);
159158
newThis.criteriaChain.add(qc);
160159
qc.setChainOperator(ChainOperator.AND);
161-
newThis.chainOperator = ChainOperator.AND;// otherwise we get "A chain operator must be present when chaining"
160+
newThis.chainOperator = ChainOperator.AND;// otherwise we get "A chain operator must be present when chaining"
162161
return newThis;
163162
}
164163

@@ -183,7 +182,6 @@ public QueryCriteria or(String key) {
183182
}
184183

185184
public QueryCriteria or(N1QLExpression key) {
186-
// this.criteriaChain.getLast().setChainOperator(ChainOperator.OR);
187185
return new QueryCriteria(this.criteriaChain, key, null, ChainOperator.OR);
188186
}
189187

@@ -200,7 +198,7 @@ public QueryCriteria or(QueryCriteria criteria) {
200198
qc.criteriaChain = newThis.criteriaChain;
201199
newThis.criteriaChain.add(qc);
202200
qc.setChainOperator(ChainOperator.OR);
203-
newThis.chainOperator = ChainOperator.OR;// otherwise we get "A chain operator must be present when chaining"
201+
newThis.chainOperator = ChainOperator.OR;// otherwise we get "A chain operator must be present when chaining"
204202
return newThis;
205203
}
206204

@@ -297,8 +295,6 @@ public QueryCriteria negate() {
297295
replaceThisAsWrapperOf(this);
298296
operator = "NOT";
299297
format = "not( %3$s )";
300-
// criteriaChain = new LinkedList<>();
301-
// criteriaChain.add(this);
302298
return this;
303299
}
304300

@@ -405,7 +401,7 @@ public QueryCriteria in(@Nullable Object... o) {
405401
} else {
406402
// see QueryCriteriaTests.testNestedNotIn() - if arg to notIn is not cast to Object
407403
// notIn((Object) new String[] { "Alabama", "Florida" }));
408-
throw new CouchbaseException("unhandled parameters "+o);
404+
throw new CouchbaseException("unhandled parameters " + o);
409405
}
410406
}
411407

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

+13
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,19 @@ void testContainsIgnoreCase() {
333333
}
334334
}
335335

336+
@Test
337+
void testMatches() {
338+
{
339+
BooleanExpression predicate = airline.name.matches("[Uu]nited.*");
340+
Iterable<Airline> result = airlineRepository.findAll(predicate);
341+
assertNull(
342+
comprises(result, Arrays.stream(saved).filter(a -> a.getName().matches("[Uu]nited.*")).toArray(Airline[]::new)),
343+
"[unexpected] -> [missing]");
344+
assertEquals(" WHERE regexp_like(name, $1)", bq(predicate));
345+
}
346+
}
347+
348+
336349
@Test
337350
void testLike() {
338351
{

0 commit comments

Comments
 (0)