Add support for ignoreCase in queries derived from method names.
Closes #984, #1481.
This commit is contained in:
@@ -17,7 +17,6 @@ package com.querydsl.couchbase.document;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.springframework.data.couchbase.core.query.QueryCriteria;
|
||||
@@ -48,8 +47,6 @@ import com.querydsl.core.types.Visitor;
|
||||
*/
|
||||
public abstract class CouchbaseDocumentSerializer implements Visitor<Object, Void> {
|
||||
|
||||
boolean workInProgress = true;
|
||||
|
||||
public Object handle(Expression<?> expression) {
|
||||
return expression.accept(this, null);
|
||||
}
|
||||
@@ -167,25 +164,22 @@ public abstract class CouchbaseDocumentSerializer implements Visitor<Object, Voi
|
||||
return QueryCriteria.where(asDBKey(expr, 0)).startingWith(asDBValue(expr, 1));
|
||||
} else if (op == Ops.STARTS_WITH_IC) {
|
||||
// return asDocument(asDBKey(expr, 0), new CBRegularExpression("^" + regexValue(expr, 1), "i"));
|
||||
return QueryCriteria.where(asDBKey(expr, 0)).upper()
|
||||
.startingWith(asDBValue(expr, 1).toString().toUpperCase(Locale.ROOT));
|
||||
return QueryCriteria.where(asDBKey(expr, 0)).startingWith(true, asDBValue(expr, 1).toString());
|
||||
} else if (op == Ops.ENDS_WITH) {
|
||||
// return asDocument(asDBKey(expr, 0), new CBRegularExpression(regexValue(expr, 1) + "$"));
|
||||
return QueryCriteria.where(asDBKey(expr, 0)).endingWith(asDBValue(expr, 1));
|
||||
} else if (op == Ops.ENDS_WITH_IC) {
|
||||
// return asDocument(asDBKey(expr, 0), new CBRegularExpression(regexValue(expr, 1) + "$", "i"));
|
||||
return QueryCriteria.where(asDBKey(expr, 0)).upper()
|
||||
.endingWith(asDBValue(expr, 1).toString().toUpperCase(Locale.ROOT));
|
||||
return QueryCriteria.where(asDBKey(expr, 0)).endingWith(true, asDBValue(expr, 1).toString());
|
||||
} else if (op == Ops.EQ_IGNORE_CASE) {
|
||||
// return asDocument(asDBKey(expr, 0), new CBRegularExpression("^" + regexValue(expr, 1) + "$", "i"));
|
||||
return QueryCriteria.where(asDBKey(expr, 0)).upper().eq(asDBValue(expr, 1).toString().toUpperCase(Locale.ROOT));
|
||||
return QueryCriteria.where(asDBKey(expr, 0)).eq(true, asDBValue(expr, 1).toString());
|
||||
} else if (op == Ops.STRING_CONTAINS) {
|
||||
// return asDocument(asDBKey(expr, 0), new CBRegularExpression(".*" + regexValue(expr, 1) + ".*"));
|
||||
return QueryCriteria.where(asDBKey(expr, 0)).containing(asDBValue(expr, 1));
|
||||
} else if (op == Ops.STRING_CONTAINS_IC) {
|
||||
// return asDocument(asDBKey(expr, 0), new CBRegularExpression(".*" + regexValue(expr, 1) + ".*", "i"));
|
||||
return QueryCriteria.where(asDBKey(expr, 0)).upper()
|
||||
.containing(asDBValue(expr, 1).toString().toUpperCase(Locale.ROOT));
|
||||
return QueryCriteria.where(asDBKey(expr, 0)).containing(true, asDBValue(expr, 1).toString());
|
||||
/*
|
||||
} else if (op == Ops.MATCHES) {
|
||||
//return asDocument(asDBKey(expr, 0), new CBRegularExpression(asDBValue(expr, 1).toString()));
|
||||
@@ -201,7 +195,7 @@ public abstract class CouchbaseDocumentSerializer implements Visitor<Object, Voi
|
||||
} else if (op == Ops.LIKE_IC) {
|
||||
// String regex = ExpressionUtils.likeToRegex((Expression) expr.getArg(1)).toString();
|
||||
// return asDocument(asDBKey(expr, 0), new CBRegularExpression(regex, "i"));
|
||||
return QueryCriteria.where(asDBKey(expr, 0)).upper().like(asDBValue(expr, 1).toString().toUpperCase(Locale.ROOT));
|
||||
return QueryCriteria.where(asDBKey(expr, 0)).like(true, asDBValue(expr, 1).toString());
|
||||
} else if (op == Ops.BETWEEN) {
|
||||
// Document value = new Document("$gte", this.asDBValue(expr, 1));
|
||||
// value.append("$lte", this.asDBValue(expr, 2));
|
||||
|
||||
@@ -507,6 +507,39 @@ public class MappingCouchbaseConverter extends AbstractCouchbaseConverter implem
|
||||
|
||||
target.setExpiration((int) (entity.getExpiryDuration().getSeconds()));
|
||||
|
||||
writeToTargetDocument(target, entity, accessor, idProperty, versionProperty, prefixes, suffixes, idAttributes);
|
||||
|
||||
if (idProperty != null && target.getId() == null) {
|
||||
String id = accessor.getProperty(idProperty, String.class);
|
||||
if (idProperty.isAnnotationPresent(GeneratedValue.class) && (id == null || id.equals(""))) {
|
||||
generatedValueInfo = idProperty.findAnnotation(GeneratedValue.class);
|
||||
String generatedId = generateId(generatedValueInfo, prefixes, suffixes, idAttributes);
|
||||
target.setId(generatedId);
|
||||
// this is not effective if id is Immutable, and accessor.setProperty() returns a new object in getBean()
|
||||
accessor.setProperty(idProperty, generatedId);
|
||||
} else {
|
||||
target.setId(id);
|
||||
}
|
||||
}
|
||||
|
||||
entity.doWithAssociations(new AssociationHandler<CouchbasePersistentProperty>() {
|
||||
@Override
|
||||
public void doWithAssociation(final Association<CouchbasePersistentProperty> association) {
|
||||
CouchbasePersistentProperty inverseProp = association.getInverse();
|
||||
Class<?> type = inverseProp.getType();
|
||||
Object propertyObj = accessor.getProperty(inverseProp, type);
|
||||
if (null != propertyObj) {
|
||||
writePropertyInternal(propertyObj, target, inverseProp, false);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
private void writeToTargetDocument(final CouchbaseDocument target, final CouchbasePersistentEntity<?> entity,
|
||||
final ConvertingPropertyAccessor<Object> accessor, final CouchbasePersistentProperty idProperty,
|
||||
final CouchbasePersistentProperty versionProperty, final TreeMap<Integer, String> prefixes,
|
||||
final TreeMap<Integer, String> suffixes, final TreeMap<Integer, String> idAttributes) {
|
||||
entity.doWithProperties(new PropertyHandler<CouchbasePersistentProperty>() {
|
||||
@Override
|
||||
public void doWithPersistentProperty(final CouchbasePersistentProperty prop) {
|
||||
@@ -550,32 +583,6 @@ public class MappingCouchbaseConverter extends AbstractCouchbaseConverter implem
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (idProperty != null && target.getId() == null) {
|
||||
String id = accessor.getProperty(idProperty, String.class);
|
||||
if (idProperty.isAnnotationPresent(GeneratedValue.class) && (id == null || id.equals(""))) {
|
||||
generatedValueInfo = idProperty.findAnnotation(GeneratedValue.class);
|
||||
String generatedId = generateId(generatedValueInfo, prefixes, suffixes, idAttributes);
|
||||
target.setId(generatedId);
|
||||
// this is not effective if id is Immutable, and accessor.setProperty() returns a new object in getBean()
|
||||
accessor.setProperty(idProperty, generatedId);
|
||||
} else {
|
||||
target.setId(id);
|
||||
}
|
||||
}
|
||||
|
||||
entity.doWithAssociations(new AssociationHandler<CouchbasePersistentProperty>() {
|
||||
@Override
|
||||
public void doWithAssociation(final Association<CouchbasePersistentProperty> association) {
|
||||
CouchbasePersistentProperty inverseProp = association.getInverse();
|
||||
Class<?> type = inverseProp.getType();
|
||||
Object propertyObj = accessor.getProperty(inverseProp, type);
|
||||
if (null != propertyObj) {
|
||||
writePropertyInternal(propertyObj, target, inverseProp, false);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -22,12 +22,13 @@ import java.util.Collections;
|
||||
import java.util.Formatter;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import com.couchbase.client.core.error.CouchbaseException;
|
||||
import org.springframework.data.couchbase.core.convert.CouchbaseConverter;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import com.couchbase.client.core.error.CouchbaseException;
|
||||
import com.couchbase.client.core.error.InvalidArgumentException;
|
||||
import com.couchbase.client.java.json.JsonArray;
|
||||
import com.couchbase.client.java.json.JsonObject;
|
||||
@@ -158,7 +159,7 @@ public class QueryCriteria implements QueryCriteriaDefinition {
|
||||
QueryCriteria qc = wrap(criteria);
|
||||
newThis.criteriaChain.add(qc);
|
||||
qc.setChainOperator(ChainOperator.AND);
|
||||
newThis.chainOperator = ChainOperator.AND;// otherwise we get "A chain operator must be present when chaining"
|
||||
newThis.chainOperator = ChainOperator.AND;// otherwise we get "A chain operator must be present when chaining"
|
||||
return newThis;
|
||||
}
|
||||
|
||||
@@ -200,54 +201,92 @@ public class QueryCriteria implements QueryCriteriaDefinition {
|
||||
qc.criteriaChain = newThis.criteriaChain;
|
||||
newThis.criteriaChain.add(qc);
|
||||
qc.setChainOperator(ChainOperator.OR);
|
||||
newThis.chainOperator = ChainOperator.OR;// otherwise we get "A chain operator must be present when chaining"
|
||||
newThis.chainOperator = ChainOperator.OR;// otherwise we get "A chain operator must be present when chaining"
|
||||
return newThis;
|
||||
}
|
||||
|
||||
public QueryCriteria eq(@Nullable Object o) {
|
||||
return is(o);
|
||||
return eq(false, o);
|
||||
}
|
||||
|
||||
public QueryCriteria eq(boolean ignoreCase, @Nullable Object o) {
|
||||
return is(ignoreCase, o);
|
||||
}
|
||||
|
||||
public QueryCriteria is(@Nullable Object o) {
|
||||
return is(false, o);
|
||||
};
|
||||
|
||||
public QueryCriteria is(boolean ignoreCase, @Nullable Object o) {
|
||||
operator = "=";
|
||||
value = new Object[] { o };
|
||||
format = ignoreCase ? "lower(%1$s) %2$s %3$s" : "%1$s %2$s %3$s";
|
||||
value = new Object[] { ignoreCase ? o.toString().toLowerCase(Locale.ROOT) : o };
|
||||
return this;
|
||||
}
|
||||
|
||||
public QueryCriteria ne(@Nullable Object o) {
|
||||
return ne(false, o);
|
||||
}
|
||||
|
||||
public QueryCriteria ne(boolean ignoreCase, @Nullable Object o) {
|
||||
operator = "!=";
|
||||
value = new Object[] { o };
|
||||
format = ignoreCase ? "lower(%1$s) %2$s %3$s" : "%1$s %2$s %3$s";
|
||||
value = new Object[] { ignoreCase ? o.toString().toLowerCase(Locale.ROOT) : o };
|
||||
return this;
|
||||
}
|
||||
|
||||
public QueryCriteria lt(@Nullable Object o) {
|
||||
return lt(false, o);
|
||||
}
|
||||
|
||||
public QueryCriteria lt(boolean ignoreCase, @Nullable Object o) {
|
||||
operator = "<";
|
||||
value = new Object[] { o };
|
||||
format = ignoreCase ? "lower(%1$s) %2$s %3$s" : "%1$s %2$s %3$s";
|
||||
value = new Object[] { ignoreCase ? o.toString().toLowerCase(Locale.ROOT) : o };
|
||||
return this;
|
||||
}
|
||||
|
||||
public QueryCriteria lte(@Nullable Object o) {
|
||||
return lte(false, o);
|
||||
}
|
||||
|
||||
public QueryCriteria lte(boolean ignoreCase, @Nullable Object o) {
|
||||
operator = "<=";
|
||||
value = new Object[] { o };
|
||||
format = ignoreCase ? "lower(%1$s) %2$s %3$s" : "%1$s %2$s %3$s";
|
||||
value = new Object[] { ignoreCase ? o.toString().toLowerCase(Locale.ROOT) : o };
|
||||
return this;
|
||||
}
|
||||
|
||||
public QueryCriteria gt(@Nullable Object o) {
|
||||
return gt(false, o);
|
||||
}
|
||||
|
||||
public QueryCriteria gt(boolean ignoreCase, @Nullable Object o) {
|
||||
operator = ">";
|
||||
value = new Object[] { o };
|
||||
format = ignoreCase ? "lower(%1$s) %2$s %3$s" : "%1$s %2$s %3$s";
|
||||
value = new Object[] { ignoreCase ? o.toString().toLowerCase(Locale.ROOT) : o };
|
||||
return this;
|
||||
}
|
||||
|
||||
public QueryCriteria gte(@Nullable Object o) {
|
||||
return gte(false, o);
|
||||
}
|
||||
|
||||
public QueryCriteria gte(boolean ignoreCase, @Nullable Object o) {
|
||||
operator = ">=";
|
||||
value = new Object[] { o };
|
||||
format = ignoreCase ? "lower(%1$s) %2$s %3$s" : "%1$s %2$s %3$s";
|
||||
value = new Object[] { ignoreCase ? o.toString().toLowerCase(Locale.ROOT) : o };
|
||||
return this;
|
||||
}
|
||||
|
||||
public QueryCriteria startingWith(@Nullable Object o) {
|
||||
operator = "STARTING_WITH";
|
||||
value = new Object[] { o };
|
||||
format = "%1$s like (%3$s||\"%%\")";
|
||||
return startingWith(false, o);
|
||||
}
|
||||
|
||||
public QueryCriteria startingWith(boolean ignoreCase, @Nullable Object o) {
|
||||
operator = "like";
|
||||
value = new Object[] { ignoreCase ? o.toString().toLowerCase(Locale.ROOT) : o };
|
||||
format = ignoreCase ? "lower(%1$s) %2$s (%3$s||\"%%\")" : "%1$s %2$s (%3$s||\"%%\")";
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -259,9 +298,13 @@ public class QueryCriteria implements QueryCriteriaDefinition {
|
||||
}
|
||||
|
||||
public QueryCriteria endingWith(@Nullable Object o) {
|
||||
operator = "ENDING_WITH";
|
||||
value = new Object[] { o };
|
||||
format = "%1$s like (\"%%\"||%3$s)";
|
||||
return endingWith(false, o);
|
||||
}
|
||||
|
||||
public QueryCriteria endingWith(boolean ignoreCase, @Nullable Object o) {
|
||||
operator = "like";
|
||||
value = new Object[] { ignoreCase ? o.toString().toLowerCase(Locale.ROOT) : o };
|
||||
format = ignoreCase ? "lower(%1$s) %2$s (\"%%\"||%3$s)" : "%1$s %2$s (\"%%\"||%3$s)";
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -273,23 +316,38 @@ public class QueryCriteria implements QueryCriteriaDefinition {
|
||||
}
|
||||
|
||||
public QueryCriteria containing(@Nullable Object o) {
|
||||
operator = "CONTAINS";
|
||||
value = new Object[] { o };
|
||||
format = "contains(%1$s, %3$s)";
|
||||
return containing(false, o);
|
||||
}
|
||||
|
||||
public QueryCriteria containing(boolean ignoreCase, @Nullable Object o) {
|
||||
operator = "contains";
|
||||
value = new Object[] { ignoreCase ? o.toString().toLowerCase(Locale.ROOT) : o };
|
||||
format = ignoreCase ? "%2$s(lower(%1$s), %3$s)" : "%2$s(%1$s, %3$s)";
|
||||
return this;
|
||||
}
|
||||
|
||||
public QueryCriteria arrayContaining(@Nullable Object o) {
|
||||
operator = "ARRAY_CONTAINING";
|
||||
return arrayContaining(false, o);
|
||||
}
|
||||
|
||||
public QueryCriteria arrayContaining(boolean ignoreCase, @Nullable Object o) {
|
||||
operator = "array_containing";
|
||||
if (ignoreCase) {
|
||||
throw new CouchbaseException("ignoreCase not supported in IN and NOT_IN");
|
||||
}
|
||||
value = new Object[] { o };
|
||||
format = "array_containing(%1$s, %3$s)";
|
||||
return this;
|
||||
}
|
||||
|
||||
public QueryCriteria notContaining(@Nullable Object o) {
|
||||
replaceThisAsWrapperOf(containing(o));
|
||||
operator = "NOT";
|
||||
format = "not( %3$s )";
|
||||
return notContaining(false, o);
|
||||
}
|
||||
|
||||
public QueryCriteria notContaining(boolean ignoreCase, @Nullable Object o) {
|
||||
replaceThisAsWrapperOf(containing(ignoreCase, o));
|
||||
operator = "not";
|
||||
format = "%2$s %3$s";
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -297,8 +355,6 @@ public class QueryCriteria implements QueryCriteriaDefinition {
|
||||
replaceThisAsWrapperOf(this);
|
||||
operator = "NOT";
|
||||
format = "not( %3$s )";
|
||||
// criteriaChain = new LinkedList<>();
|
||||
// criteriaChain.add(this);
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -310,16 +366,23 @@ public class QueryCriteria implements QueryCriteriaDefinition {
|
||||
}
|
||||
|
||||
public QueryCriteria like(@Nullable Object o) {
|
||||
operator = "LIKE";
|
||||
value = new Object[] { o };
|
||||
format = "%1$s like %3$s";
|
||||
return like(false, o);
|
||||
}
|
||||
|
||||
public QueryCriteria like(boolean ignoreCase, @Nullable Object o) {
|
||||
operator = "like";
|
||||
value = new Object[] { ignoreCase ? o.toString().toLowerCase(Locale.ROOT) : o };
|
||||
format = ignoreCase ? "lower(%1$s) %2$s %3$s" : "%1$s %2$s %3$s";
|
||||
return this;
|
||||
}
|
||||
|
||||
public QueryCriteria notLike(@Nullable Object o) {
|
||||
operator = "NOTLIKE";
|
||||
value = new Object[] { o };
|
||||
format = "not(%1$s like %3$s)";
|
||||
return notLike(false, o);
|
||||
}
|
||||
|
||||
public QueryCriteria notLike(boolean ignoreCase, @Nullable Object o) {
|
||||
replaceThisAsWrapperOf(like(ignoreCase, o));
|
||||
this.negate();
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -365,23 +428,35 @@ public class QueryCriteria implements QueryCriteriaDefinition {
|
||||
return this;
|
||||
}
|
||||
|
||||
public QueryCriteria within(@Nullable Object o) {
|
||||
operator = "WITHIN";
|
||||
value = new Object[] { o };
|
||||
format = "%1$s within %3$s";
|
||||
public QueryCriteria within(boolean ignoreCase, @Nullable Object o) {
|
||||
operator = "within";
|
||||
value = new Object[] { ignoreCase ? o.toString().toLowerCase(Locale.ROOT) : o };
|
||||
format = ignoreCase ? "lower(%1$s) %2$s %3$s" : "%1$s %2$s %3$s";
|
||||
return this;
|
||||
}
|
||||
|
||||
public QueryCriteria between(@Nullable Object o1, @Nullable Object o2) {
|
||||
return between(false, o1, o2);
|
||||
}
|
||||
|
||||
public QueryCriteria between(boolean ignoreCase, @Nullable Object o1, @Nullable Object o2) {
|
||||
operator = "BETWEEN";
|
||||
value = new Object[] { o1, o2 };
|
||||
format = "%1$s between %3$s and %4$s";
|
||||
value = new Object[] { ignoreCase ? o1.toString().toLowerCase(Locale.ROOT) : o1,
|
||||
ignoreCase ? o2.toString().toLowerCase(Locale.ROOT) : o2 };
|
||||
format = ignoreCase ? "lower(%1$s) between %3$s and %4$s" : "%1$s between %3$s and %4$s";
|
||||
return this;
|
||||
}
|
||||
|
||||
public QueryCriteria in(@Nullable Object... o) {
|
||||
operator = "IN";
|
||||
format = "%1$s in %3$s";
|
||||
return in(false, o);
|
||||
}
|
||||
|
||||
public QueryCriteria in(boolean ignoreCase, @Nullable Object... o) {
|
||||
operator = "in";
|
||||
if (ignoreCase) {
|
||||
throw new CouchbaseException("ignoreCase not supported in IN and NOT_IN");
|
||||
}
|
||||
format = "%1$s %2$s %3$s";
|
||||
value = new Object[1];
|
||||
if (o.length > 0) {
|
||||
if (o[0] instanceof JsonArray || o[0] instanceof List || o[0] instanceof Object[]) {
|
||||
@@ -405,7 +480,7 @@ public class QueryCriteria implements QueryCriteriaDefinition {
|
||||
} else {
|
||||
// see QueryCriteriaTests.testNestedNotIn() - if arg to notIn is not cast to Object
|
||||
// notIn((Object) new String[] { "Alabama", "Florida" }));
|
||||
throw new CouchbaseException("unhandled parameters "+o);
|
||||
throw new CouchbaseException("unhandled parameters " + o);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -414,7 +489,11 @@ public class QueryCriteria implements QueryCriteriaDefinition {
|
||||
}
|
||||
|
||||
public QueryCriteria notIn(@Nullable Object... o) {
|
||||
return in(o).negate();
|
||||
return in(false, o).negate();
|
||||
}
|
||||
|
||||
public QueryCriteria notIn(boolean ignoreCase, @Nullable Object... o) {
|
||||
return in(ignoreCase, o).negate();
|
||||
}
|
||||
|
||||
public QueryCriteria TRUE() { // true/false are reserved, use TRUE/FALSE
|
||||
|
||||
@@ -30,6 +30,7 @@ import org.springframework.data.couchbase.core.mapping.CouchbasePersistentProper
|
||||
import org.springframework.data.couchbase.core.query.N1QLExpression;
|
||||
import org.springframework.data.couchbase.core.query.Query;
|
||||
import org.springframework.data.couchbase.core.query.QueryCriteria;
|
||||
import org.springframework.data.couchbase.repository.query.support.N1qlUtils;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
@@ -126,7 +127,25 @@ public class N1qlQueryCreator extends AbstractQueryCreator<Query, QueryCriteria>
|
||||
|
||||
private QueryCriteria from(final Part part, final CouchbasePersistentProperty property, final QueryCriteria criteria,
|
||||
final Iterator<Object> parameters) {
|
||||
// deal with ignore case
|
||||
PersistentPropertyPath<CouchbasePersistentProperty> path = N1qlUtils.getPathWithAlternativeFieldNames(converter,
|
||||
part.getProperty());
|
||||
|
||||
// get the whole doted path with fieldNames instead of potentially wrong propNames
|
||||
String fieldNamePath = N1qlUtils.getDottedPathWithAlternativeFieldNames(path);
|
||||
|
||||
boolean ignoreCase = false;
|
||||
Class<?> leafType = converter.getWriteClassFor(path.getLeafProperty().getType());
|
||||
boolean isString = leafType == String.class;
|
||||
if (part.shouldIgnoreCase() == Part.IgnoreCaseType.WHEN_POSSIBLE) {
|
||||
ignoreCase = isString;
|
||||
} else if (part.shouldIgnoreCase() == Part.IgnoreCaseType.ALWAYS) {
|
||||
if (!isString) {
|
||||
throw new IllegalArgumentException(
|
||||
String.format("Part %s must be of type String but was %s", fieldNamePath, leafType));
|
||||
}
|
||||
ignoreCase = true;
|
||||
}
|
||||
final Part.Type type = part.getType();
|
||||
/*
|
||||
NEAR(new String[]{"IsNear", "Near"}),
|
||||
@@ -134,32 +153,32 @@ public class N1qlQueryCreator extends AbstractQueryCreator<Query, QueryCriteria>
|
||||
switch (type) {
|
||||
case GREATER_THAN:
|
||||
case AFTER:
|
||||
return criteria.gt(parameters.next());
|
||||
return criteria.gt(ignoreCase, parameters.next());
|
||||
case GREATER_THAN_EQUAL:
|
||||
return criteria.gte(parameters.next());
|
||||
return criteria.gte(ignoreCase, parameters.next());
|
||||
case LESS_THAN:
|
||||
case BEFORE:
|
||||
return criteria.lt(parameters.next());
|
||||
return criteria.lt(ignoreCase, parameters.next());
|
||||
case LESS_THAN_EQUAL:
|
||||
return criteria.lte(parameters.next());
|
||||
return criteria.lte(ignoreCase, parameters.next());
|
||||
case SIMPLE_PROPERTY:
|
||||
return criteria.eq(parameters.next());
|
||||
return criteria.eq(ignoreCase, parameters.next());
|
||||
case NEGATING_SIMPLE_PROPERTY:
|
||||
return criteria.ne(parameters.next());
|
||||
return criteria.ne(ignoreCase, parameters.next());
|
||||
case CONTAINING:
|
||||
return criteria.containing(parameters.next());
|
||||
return criteria.containing(ignoreCase, parameters.next());
|
||||
case NOT_CONTAINING:
|
||||
return criteria.notContaining(parameters.next());
|
||||
return criteria.notContaining(ignoreCase, parameters.next());
|
||||
case STARTING_WITH:
|
||||
return criteria.startingWith(parameters.next());
|
||||
return criteria.startingWith(ignoreCase, parameters.next());
|
||||
case ENDING_WITH:
|
||||
return criteria.endingWith(parameters.next());
|
||||
return criteria.endingWith(ignoreCase, parameters.next());
|
||||
case LIKE:
|
||||
return criteria.like(parameters.next());
|
||||
return criteria.like(ignoreCase, parameters.next());
|
||||
case NOT_LIKE:
|
||||
return criteria.notLike(parameters.next());
|
||||
return criteria.notLike(ignoreCase, parameters.next());
|
||||
case WITHIN:
|
||||
return criteria.within(parameters.next());
|
||||
return criteria.within(ignoreCase, parameters.next());
|
||||
case IS_NULL:
|
||||
return criteria.isNull(/*parameters.next()*/);
|
||||
case IS_NOT_NULL:
|
||||
@@ -173,11 +192,11 @@ public class N1qlQueryCreator extends AbstractQueryCreator<Query, QueryCriteria>
|
||||
case REGEX:
|
||||
return criteria.regex(parameters.next());
|
||||
case BETWEEN:
|
||||
return criteria.between(parameters.next(), parameters.next());
|
||||
return criteria.between(ignoreCase, parameters.next(), parameters.next());
|
||||
case IN:
|
||||
return criteria.in(parameters.next());
|
||||
return criteria.in(ignoreCase, new Object[] { parameters.next() });
|
||||
case NOT_IN:
|
||||
return criteria.notIn(parameters.next());
|
||||
return criteria.notIn(ignoreCase, new Object[] { parameters.next() });
|
||||
case TRUE:
|
||||
return criteria.TRUE();
|
||||
case FALSE:
|
||||
|
||||
@@ -174,7 +174,7 @@ class QueryCriteriaTests {
|
||||
@Test
|
||||
void testNotContaining() {
|
||||
QueryCriteria c = where(i("name")).notContaining("Elvis");
|
||||
assertEquals("not( (contains(`name`, \"Elvis\")) )", c.export());
|
||||
assertEquals("not (contains(`name`, \"Elvis\"))", c.export());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -192,7 +192,7 @@ class QueryCriteriaTests {
|
||||
@Test
|
||||
void testNotLike() {
|
||||
QueryCriteria c = where(i("name")).notLike("%Elvis%");
|
||||
assertEquals("not(`name` like \"%Elvis%\")", c.export());
|
||||
assertEquals("not( ( (`name` like \"%Elvis%\")) )", c.export());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -43,6 +43,8 @@ public interface UserRepository extends CouchbaseRepository<User, String> {
|
||||
|
||||
List<User> findByFirstname(String firstname);
|
||||
|
||||
List<User> findByFirstnameIgnoreCase(String firstname);
|
||||
|
||||
Stream<User> findByLastname(String lastname);
|
||||
|
||||
List<User> findByFirstnameIn(String... firstnames);
|
||||
|
||||
@@ -255,7 +255,7 @@ public class CouchbaseRepositoryQuerydslIntegrationTests extends JavaIntegration
|
||||
.filter(a -> a.getName().toUpperCase().startsWith(united.getName().toUpperCase().substring(0, 5)))
|
||||
.toArray(Airline[]::new)),
|
||||
"[unexpected] -> [missing]");
|
||||
assertEquals(" WHERE UPPER(name) like ($1||\"%\")", bq(predicate));
|
||||
assertEquals(" WHERE lower(name) like ($1||\"%\")", bq(predicate));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -281,7 +281,7 @@ public class CouchbaseRepositoryQuerydslIntegrationTests extends JavaIntegration
|
||||
.filter(a -> a.getName().toUpperCase().endsWith(united.getName().toUpperCase().substring(1)))
|
||||
.toArray(Airline[]::new)),
|
||||
"[unexpected] -> [missing]");
|
||||
assertEquals(" WHERE UPPER(name) like (\"%\"||$1)", bq(predicate));
|
||||
assertEquals(" WHERE lower(name) like (\"%\"||$1)", bq(predicate));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -293,7 +293,7 @@ public class CouchbaseRepositoryQuerydslIntegrationTests extends JavaIntegration
|
||||
assertNull(comprises(result,
|
||||
Arrays.stream(saved).filter(a -> a.getName().equalsIgnoreCase(flyByNight.getName())).toArray(Airline[]::new)),
|
||||
"[unexpected] -> [missing]");
|
||||
assertEquals(" WHERE UPPER(name) = $1", bq(predicate));
|
||||
assertEquals(" WHERE lower(name) = $1", bq(predicate));
|
||||
}
|
||||
{
|
||||
BooleanExpression predicate = airline.name.equalsIgnoreCase(united.getName());
|
||||
@@ -302,7 +302,7 @@ public class CouchbaseRepositoryQuerydslIntegrationTests extends JavaIntegration
|
||||
comprises(result,
|
||||
Arrays.stream(saved).filter(a -> a.getName().equalsIgnoreCase(united.getName())).toArray(Airline[]::new)),
|
||||
"[unexpected] -> [missing]");
|
||||
assertEquals(" WHERE UPPER(name) = $1", bq(predicate));
|
||||
assertEquals(" WHERE lower(name) = $1", bq(predicate));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -329,7 +329,7 @@ public class CouchbaseRepositoryQuerydslIntegrationTests extends JavaIntegration
|
||||
.filter(a -> a.getName().toUpperCase(Locale.ROOT).contains("united".toUpperCase(Locale.ROOT)))
|
||||
.toArray(Airline[]::new)),
|
||||
"[unexpected] -> [missing]");
|
||||
assertEquals(" WHERE contains(UPPER(name), $1)", bq(predicate));
|
||||
assertEquals(" WHERE contains(lower(name), $1)", bq(predicate));
|
||||
|
||||
}
|
||||
}
|
||||
@@ -356,7 +356,7 @@ public class CouchbaseRepositoryQuerydslIntegrationTests extends JavaIntegration
|
||||
.filter(a -> a.getName().toUpperCase(Locale.ROOT).endsWith("Airlines".toUpperCase(Locale.ROOT)))
|
||||
.toArray(Airline[]::new)),
|
||||
"[unexpected] -> [missing]");
|
||||
assertEquals(" WHERE UPPER(name) like $1", bq(predicate));
|
||||
assertEquals(" WHERE lower(name) like $1", bq(predicate));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ import static org.springframework.data.couchbase.core.query.QueryCriteria.where;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -81,6 +82,21 @@ class N1qlQueryCreatorTests {
|
||||
assertEquals(query.export(), " WHERE " + where(i("firstname")).is("Oliver").export());
|
||||
}
|
||||
|
||||
@Test
|
||||
void createsQueryCorrectlyIgnoreCase() throws Exception {
|
||||
String input = "findByFirstnameIgnoreCase";
|
||||
PartTree tree = new PartTree(input, User.class);
|
||||
Method method = UserRepository.class.getMethod(input, String.class);
|
||||
QueryMethod queryMethod = new QueryMethod(method, new DefaultRepositoryMetadata(UserRepository.class),
|
||||
new SpelAwareProxyProjectionFactory());
|
||||
N1qlQueryCreator creator = new N1qlQueryCreator(tree, getAccessor(getParameters(method), "Oliver"), queryMethod,
|
||||
converter, bucketName);
|
||||
Query query = creator.createQuery();
|
||||
|
||||
assertEquals(query.export(),
|
||||
" WHERE " + where("lower(" + i("firstname") + ")").is("Oliver".toLowerCase(Locale.ROOT)).export());
|
||||
}
|
||||
|
||||
@Test
|
||||
void createsQueryFieldAnnotationCorrectly() throws Exception {
|
||||
String input = "findByMiddlename";
|
||||
|
||||
Reference in New Issue
Block a user