DATACOUCH-603 Do not cast query parameters in N1qlQueryCreator.
For IN and NOT_IN - they can take varargs, an array or a JsonArray Don't cast query criteria parameters, let parameter accessor handle that. Fixed conversion of query criteria values to parameters Cleaned up QueryCriteria Co-authored-by: mikereiche <michael.reiche@couchbase.com>
This commit is contained in:
@@ -26,6 +26,7 @@ import com.couchbase.client.java.json.JsonValue;
|
||||
import com.couchbase.client.java.query.QueryOptions;
|
||||
import com.couchbase.client.java.query.QueryScanConsistency;
|
||||
import org.springframework.data.couchbase.core.ReactiveCouchbaseTemplate;
|
||||
import org.springframework.data.couchbase.core.convert.CouchbaseConverter;
|
||||
import org.springframework.data.couchbase.core.mapping.CouchbasePersistentEntity;
|
||||
import org.springframework.data.couchbase.repository.query.StringBasedN1qlQueryParser;
|
||||
import org.springframework.data.couchbase.repository.support.MappingCouchbaseEntityInformation;
|
||||
@@ -189,7 +190,7 @@ public class Query {
|
||||
sb.deleteCharAt(sb.length() - 1);
|
||||
}
|
||||
|
||||
public void appendWhere(final StringBuilder sb, int[] paramIndexPtr) {
|
||||
public void appendWhere(final StringBuilder sb, int[] paramIndexPtr, CouchbaseConverter converter) {
|
||||
if (!criteria.isEmpty()) {
|
||||
appendWhereOrAnd(sb);
|
||||
boolean first = true;
|
||||
@@ -199,16 +200,11 @@ public class Query {
|
||||
} else {
|
||||
sb.append(" AND ");
|
||||
}
|
||||
sb.append(c.export(paramIndexPtr));
|
||||
sb.append(c.export(paramIndexPtr, parameters, converter));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void appendCriteria(StringBuilder sb, QueryCriteria criteria) {
|
||||
appendWhereOrAnd(sb);
|
||||
sb.append(criteria.export());
|
||||
}
|
||||
|
||||
public void appendWhereString(StringBuilder sb, String whereString) {
|
||||
appendWhereOrAnd(sb);
|
||||
sb.append(whereString);
|
||||
@@ -257,9 +253,9 @@ public class Query {
|
||||
return true; // is not quoted
|
||||
}
|
||||
|
||||
public String export() {
|
||||
public String export(int[]... paramIndexPtrHolder) { // used only by tests
|
||||
StringBuilder sb = new StringBuilder();
|
||||
appendWhere(sb, null);
|
||||
appendWhere(sb, paramIndexPtrHolder.length > 0 ? paramIndexPtrHolder[0] : null, null);
|
||||
appendSort(sb);
|
||||
appendSkipAndLimit(sb);
|
||||
return sb.toString();
|
||||
@@ -270,7 +266,7 @@ public class Query {
|
||||
final StringBuilder statement = new StringBuilder();
|
||||
appendString(statement, n1ql.selectEntity); // select ...
|
||||
appendWhereString(statement, n1ql.filter); // typeKey = typeValue
|
||||
appendWhere(statement, new int[] { 0 }); // criteria on this Query
|
||||
appendWhere(statement, new int[] { 0 }, template.getConverter()); // criteria on this Query
|
||||
appendSort(statement);
|
||||
appendSkipAndLimit(statement);
|
||||
return statement.toString();
|
||||
|
||||
@@ -20,6 +20,11 @@ import java.util.Formatter;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import com.couchbase.client.core.error.InvalidArgumentException;
|
||||
import com.couchbase.client.java.json.JsonArray;
|
||||
import com.couchbase.client.java.json.JsonObject;
|
||||
import com.couchbase.client.java.json.JsonValue;
|
||||
import org.springframework.data.couchbase.core.convert.CouchbaseConverter;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
@@ -60,6 +65,10 @@ public class QueryCriteria implements QueryCriteriaDefinition {
|
||||
this.format = format;
|
||||
}
|
||||
|
||||
Object[] getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Static factory method to create a Criteria using the provided key.
|
||||
*/
|
||||
@@ -68,8 +77,8 @@ public class QueryCriteria implements QueryCriteriaDefinition {
|
||||
}
|
||||
|
||||
private static QueryCriteria wrap(QueryCriteria criteria) {
|
||||
QueryCriteria qc = new QueryCriteria(new LinkedList<QueryCriteria>(), criteria.key, criteria.value, null,
|
||||
criteria.operator, criteria.format);
|
||||
QueryCriteria qc = new QueryCriteria(new LinkedList<>(), criteria.key, criteria.value, null, criteria.operator,
|
||||
criteria.format);
|
||||
return qc;
|
||||
}
|
||||
|
||||
@@ -167,7 +176,7 @@ public class QueryCriteria implements QueryCriteriaDefinition {
|
||||
public QueryCriteria notContaining(@Nullable Object o) {
|
||||
value = new QueryCriteria[] { wrap(containing(o)) };
|
||||
operator = "NOT";
|
||||
format = format = "not( %3$s )";
|
||||
format = "not( %3$s )";
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -196,7 +205,7 @@ public class QueryCriteria implements QueryCriteriaDefinition {
|
||||
operator = "IS_NOT_NULL";
|
||||
value = null;
|
||||
format = "%1$s is not null";
|
||||
return (QueryCriteria) this;
|
||||
return this;
|
||||
}
|
||||
|
||||
public QueryCriteria isMissing() {
|
||||
@@ -210,7 +219,7 @@ public class QueryCriteria implements QueryCriteriaDefinition {
|
||||
operator = "IS_NOT_MiSSING";
|
||||
value = null;
|
||||
format = "%1$s is not missing";
|
||||
return (QueryCriteria) this;
|
||||
return this;
|
||||
}
|
||||
|
||||
public QueryCriteria isValued() {
|
||||
@@ -224,68 +233,74 @@ public class QueryCriteria implements QueryCriteriaDefinition {
|
||||
operator = "IS_NOT_VALUED";
|
||||
value = null;
|
||||
format = "%1$s is not valued";
|
||||
return (QueryCriteria) this;
|
||||
return this;
|
||||
}
|
||||
|
||||
public QueryCriteria within(@Nullable Object o) {
|
||||
operator = "WITHIN";
|
||||
value = new Object[] { o };
|
||||
format = "%1$s within $3$s";
|
||||
return (QueryCriteria) this;
|
||||
format = "%1$s within %3$s";
|
||||
return this;
|
||||
}
|
||||
|
||||
public QueryCriteria between(@Nullable Object o1, @Nullable Object o2) {
|
||||
operator = "BETWEEN";
|
||||
value = new Object[] { o1, o2 };
|
||||
format = "%1$s between %3$s and %4$s";
|
||||
return (QueryCriteria) this;
|
||||
return this;
|
||||
}
|
||||
|
||||
public QueryCriteria in(@Nullable Object... o) {
|
||||
operator = "IN";
|
||||
value = o;
|
||||
StringBuilder sb = new StringBuilder("%1$s in ( [ ");
|
||||
for (int i = 1; i <= value.length; i++) { // format indices start at 1
|
||||
if (i > 1)
|
||||
sb.append(", ");
|
||||
sb.append("%" + (i + 2) + "$s"); // the first is fieldName, second is operator, args start at 3
|
||||
format = "%1$s in ( %3$s )";
|
||||
// IN takes a single argument that is a list
|
||||
if (o.length > 0) {
|
||||
if (o[0] instanceof JsonArray || o[0] instanceof List || o[0] instanceof Object[]) {
|
||||
if (o.length != 1) {
|
||||
throw new RuntimeException("IN cannot take multiple lists");
|
||||
}
|
||||
value = o;
|
||||
} else {
|
||||
value = new Object[1];
|
||||
value[0] = o; // JsonArray.from(o);
|
||||
}
|
||||
}
|
||||
format = sb.append(" ] )").toString();
|
||||
return (QueryCriteria) this;
|
||||
return this;
|
||||
}
|
||||
|
||||
public QueryCriteria notIn(@Nullable Object... o) {
|
||||
value = new QueryCriteria[] { wrap(in(o)) };
|
||||
operator = "NOT";
|
||||
format = format = "not( %3$s )"; // field = 1$, operator = 2$, value=$3, $4, ...
|
||||
return (QueryCriteria) this;
|
||||
format = "not( %3$s )"; // field = 1$, operator = 2$, value=$3, $4, ...
|
||||
return this;
|
||||
}
|
||||
|
||||
public QueryCriteria TRUE() { // true/false are reserved, use TRUE/FALSE
|
||||
value = null;
|
||||
operator = null;
|
||||
format = format = "%1$s"; // field = 1$, operator = 2$, value=$3, $4, ...
|
||||
return (QueryCriteria) this;
|
||||
format = "%1$s"; // field = 1$, operator = 2$, value=$3, $4, ...
|
||||
return this;
|
||||
}
|
||||
|
||||
public QueryCriteria FALSE() {
|
||||
value = new QueryCriteria[] { wrap(TRUE()) };
|
||||
operator = "not";
|
||||
format = format = "not( %3$s )";
|
||||
return (QueryCriteria) this;
|
||||
format = "not( %3$s )";
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* This exports the query criteria into a string to be appended to the beginning of an N1QL statement
|
||||
* This exports the query criteria chain into a string to be appended to the beginning of an N1QL statement
|
||||
*
|
||||
* @param paramIndexPtr - this is a reference to the parameter index to be used for positional parameters
|
||||
* There may already be positional parameters in the beginning of the statement,
|
||||
* so it may not always start at 1. If it has the value -1, the query is using
|
||||
* named parameters. If the pointer is null, the query is not using parameters.
|
||||
* @param paramIndexPtr - this is a reference to the parameter index to be used for positional parameters There may
|
||||
* already be positional parameters in the beginning of the statement, so it may not always start at 1. If it
|
||||
* has the value -1, the query is using named parameters. If the pointer is null, the query is not using
|
||||
* parameters.
|
||||
* @param parameters - parameters of the query. If operands are parameterized, their values are added to parameters
|
||||
* @return string containing part of N1QL query
|
||||
*/
|
||||
@Override
|
||||
public String export(int[] paramIndexPtr) {
|
||||
public String export(int[] paramIndexPtr, JsonValue parameters, CouchbaseConverter converter) {
|
||||
StringBuilder output = new StringBuilder();
|
||||
boolean first = true;
|
||||
for (QueryCriteria c : this.criteriaChain) {
|
||||
@@ -298,7 +313,7 @@ public class QueryCriteria implements QueryCriteriaDefinition {
|
||||
} else {
|
||||
first = false;
|
||||
}
|
||||
c.exportSingle(output, paramIndexPtr);
|
||||
c.exportSingle(output, paramIndexPtr, parameters, converter);
|
||||
}
|
||||
|
||||
return output.toString();
|
||||
@@ -310,12 +325,24 @@ public class QueryCriteria implements QueryCriteriaDefinition {
|
||||
* @return string containing part of N1QL query
|
||||
*/
|
||||
@Override
|
||||
public String export() {
|
||||
return export(null);
|
||||
public String export() { // used only by tests
|
||||
return export(null, null, null);
|
||||
|
||||
}
|
||||
|
||||
private StringBuilder exportSingle(StringBuilder sb, int[] paramIndexPtr) {
|
||||
/**
|
||||
* Appends the query criteria to a StringBuilder which will be appended to a N1QL statement
|
||||
*
|
||||
* @param sb - the string builder
|
||||
* @param paramIndexPtr - this is a reference to the parameter index to be used for positional parameters There may
|
||||
* already be positional parameters in the beginning of the statement, so it may not always start at 1. If it
|
||||
* has the value -1, the query is using named parameters. If the pointer is null, the query is not using
|
||||
* parameters.
|
||||
* @param parameters - parameters of the query. If operands are parameterized, their values are added to parameters
|
||||
* @return string containing part of N1QL query
|
||||
*/
|
||||
private StringBuilder exportSingle(StringBuilder sb, int[] paramIndexPtr, JsonValue parameters,
|
||||
CouchbaseConverter converter) {
|
||||
String fieldName = maybeQuote(key);
|
||||
int valueLen = value == null ? 0 : value.length;
|
||||
Object[] v = new Object[valueLen + 2];
|
||||
@@ -323,9 +350,9 @@ public class QueryCriteria implements QueryCriteriaDefinition {
|
||||
v[1] = operator;
|
||||
for (int i = 0; i < valueLen; i++) {
|
||||
if (value[i] instanceof QueryCriteria) {
|
||||
v[i + 2] = "(" + ((QueryCriteria) value[i]).export(paramIndexPtr) + ")";
|
||||
v[i + 2] = "(" + ((QueryCriteria) value[i]).export(paramIndexPtr, parameters, converter) + ")";
|
||||
} else {
|
||||
v[i + 2] = maybeWrapValue(key, value[i], paramIndexPtr);
|
||||
v[i + 2] = maybeWrapValue(key, value[i], paramIndexPtr, parameters, converter);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -340,24 +367,84 @@ public class QueryCriteria implements QueryCriteriaDefinition {
|
||||
return sb;
|
||||
}
|
||||
|
||||
private String maybeWrapValue(String key, Object value, int[] paramIndexPtr) {
|
||||
/**
|
||||
* Possibly convert an operand to a positional or named parameter
|
||||
*
|
||||
* @param paramIndexPtr - this is a reference to the parameter index to be used for positional parameters There may
|
||||
* already be positional parameters in the beginning of the statement, so it may not always start at 1. If it
|
||||
* has the value -1, the query is using named parameters. If the pointer is null, the query is not using
|
||||
* parameters.
|
||||
* @param parameters - parameters of the query. If operands are parameterized, their values are added to parameters
|
||||
* @return string containing part of N1QL query
|
||||
*/
|
||||
private String maybeWrapValue(String key, Object value, int[] paramIndexPtr, JsonValue parameters,
|
||||
CouchbaseConverter converter) {
|
||||
if (paramIndexPtr != null) {
|
||||
if (paramIndexPtr[0] >= 0) {
|
||||
JsonArray params = (JsonArray) parameters;
|
||||
// from StringBasedN1qlQueryParser.getPositionalPlaceholderValues()
|
||||
try {
|
||||
params.add(convert(converter, value));
|
||||
} catch (InvalidArgumentException iae) {
|
||||
if (value instanceof Object[]) {
|
||||
addAsArray(params, value, converter);
|
||||
} else {
|
||||
throw iae;
|
||||
}
|
||||
}
|
||||
return "$" + (++paramIndexPtr[0]); // these are generated in order
|
||||
} else {
|
||||
JsonObject params = (JsonObject) parameters;
|
||||
// from StringBasedN1qlQueryParser.getNamedPlaceholderValues()
|
||||
try {
|
||||
params.put(key, convert(converter, value));
|
||||
} catch (InvalidArgumentException iae) {
|
||||
if (value instanceof Object[]) {
|
||||
params.put(key, JsonArray.from((Object[]) value));
|
||||
} else {
|
||||
throw iae;
|
||||
}
|
||||
}
|
||||
return "$" + key;
|
||||
}
|
||||
}
|
||||
|
||||
// Did not convert to a parameter. Add quotes or whatever it might need.
|
||||
|
||||
if (value instanceof String) {
|
||||
return "\"" + value + "\"";
|
||||
} else if (value == null) {
|
||||
return "null";
|
||||
} else if (value instanceof Object[]) { // convert array into sequence of comma-separated values
|
||||
StringBuffer l = new StringBuffer();
|
||||
l.append("[");
|
||||
Object[] array = (Object[]) value;
|
||||
for (int i = 0; i < array.length; i++) {
|
||||
if (i > 0) {
|
||||
l.append(",");
|
||||
}
|
||||
l.append(maybeWrapValue(null, array[i], null, null, converter));
|
||||
}
|
||||
l.append("]");
|
||||
return l.toString();
|
||||
} else {
|
||||
return value.toString();
|
||||
}
|
||||
}
|
||||
|
||||
private static Object convert(CouchbaseConverter converter, Object value) {
|
||||
return converter != null ? converter.convertForWriteIfNeeded(value) : value;
|
||||
}
|
||||
|
||||
private void addAsArray(JsonArray posValues, Object o, CouchbaseConverter converter) {
|
||||
Object[] array = (Object[]) o;
|
||||
JsonArray ja = JsonValue.ja();
|
||||
for (Object e : array) {
|
||||
ja.add(String.valueOf(convert(converter, e)));
|
||||
}
|
||||
posValues.add(ja);
|
||||
}
|
||||
|
||||
private String maybeQuote(String value) {
|
||||
if (value == null || (value.startsWith("\"") && value.endsWith("\""))) {
|
||||
return value;
|
||||
|
||||
@@ -15,6 +15,9 @@
|
||||
*/
|
||||
package org.springframework.data.couchbase.core.query;
|
||||
|
||||
import com.couchbase.client.java.json.JsonValue;
|
||||
import org.springframework.data.couchbase.core.convert.CouchbaseConverter;
|
||||
|
||||
/**
|
||||
* @author Oliver Gierke
|
||||
* @author Christoph Strobl
|
||||
@@ -25,13 +28,15 @@ public interface QueryCriteriaDefinition {
|
||||
/**
|
||||
* This exports the query criteria into a string to be appended to the beginning of an N1QL statement
|
||||
*
|
||||
* @param paramIndexPtr - this is a reference to the parameter index to be used for positional parameters
|
||||
* There may already be positional parameters in the beginning of the statement,
|
||||
* so it may not always start at 1. If it has the value -1, the query is using
|
||||
* named parameters. If the pointer is null, the query is not using parameters.
|
||||
* @param paramIndexPtr - this is a reference to the parameter index to be used for positional parameters There may
|
||||
* already be positional parameters in the beginning of the statement, so it may not always start at 1. If it
|
||||
* has the value -1, the query is using named parameters. If the pointer is null, the query is not using
|
||||
* parameters.
|
||||
* @param parameters - query parameters. Criteria values that are converted to arguments are added to parameters
|
||||
* @param converter - converter to use for converting criteria values
|
||||
* @return string containing part of N1QL query
|
||||
*/
|
||||
String export(int[] paramIndexPtr);
|
||||
String export(int[] paramIndexPtr, JsonValue parameters, CouchbaseConverter converter);
|
||||
|
||||
/**
|
||||
* Export the query criteria to a string without using positional or named parameters.
|
||||
|
||||
@@ -66,7 +66,8 @@ public class StringQuery extends Query {
|
||||
} else { // named parameters or no parameters, no index required
|
||||
paramIndexPtr = new int[] { -1 };
|
||||
}
|
||||
appendWhere(statement, paramIndexPtr); // criteria on this Query - should be empty for StringQuery
|
||||
appendWhere(statement, paramIndexPtr, template.getConverter()); // criteria on this Query - should be empty for
|
||||
// StringQuery
|
||||
appendSort(statement);
|
||||
appendSkipAndLimit(statement);
|
||||
return statement.toString();
|
||||
|
||||
@@ -17,12 +17,8 @@ package org.springframework.data.couchbase.repository.query;
|
||||
|
||||
import static org.springframework.data.couchbase.core.query.QueryCriteria.*;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.Iterator;
|
||||
|
||||
import com.couchbase.client.core.error.InvalidArgumentException;
|
||||
import com.couchbase.client.java.json.JsonArray;
|
||||
import com.couchbase.client.java.json.JsonValue;
|
||||
import org.springframework.data.couchbase.core.convert.CouchbaseConverter;
|
||||
import org.springframework.data.couchbase.core.mapping.CouchbasePersistentProperty;
|
||||
import org.springframework.data.couchbase.core.query.Query;
|
||||
@@ -30,7 +26,6 @@ import org.springframework.data.couchbase.core.query.QueryCriteria;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.mapping.PersistentPropertyPath;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.data.repository.query.Parameter;
|
||||
import org.springframework.data.repository.query.ParameterAccessor;
|
||||
import org.springframework.data.repository.query.QueryMethod;
|
||||
import org.springframework.data.repository.query.parser.AbstractQueryCreator;
|
||||
@@ -59,8 +54,7 @@ public class N1qlQueryCreator extends AbstractQueryCreator<Query, QueryCriteria>
|
||||
|
||||
@Override
|
||||
protected QueryCriteria create(final Part part, final Iterator<Object> iterator) {
|
||||
PersistentPropertyPath<CouchbasePersistentProperty> path = context.getPersistentPropertyPath(
|
||||
part.getProperty());
|
||||
PersistentPropertyPath<CouchbasePersistentProperty> path = context.getPersistentPropertyPath(part.getProperty());
|
||||
CouchbasePersistentProperty property = path.getLeafProperty();
|
||||
return from(part, property, where(path.toDotPath()), iterator);
|
||||
}
|
||||
@@ -71,8 +65,7 @@ public class N1qlQueryCreator extends AbstractQueryCreator<Query, QueryCriteria>
|
||||
return create(part, iterator);
|
||||
}
|
||||
|
||||
PersistentPropertyPath<CouchbasePersistentProperty> path = context.getPersistentPropertyPath(
|
||||
part.getProperty());
|
||||
PersistentPropertyPath<CouchbasePersistentProperty> path = context.getPersistentPropertyPath(part.getProperty());
|
||||
CouchbasePersistentProperty property = path.getLeafProperty();
|
||||
|
||||
return from(part, property, base.and(path.toDotPath()), iterator);
|
||||
@@ -85,92 +78,70 @@ public class N1qlQueryCreator extends AbstractQueryCreator<Query, QueryCriteria>
|
||||
|
||||
@Override
|
||||
protected Query complete(QueryCriteria criteria, Sort sort) {
|
||||
JsonArray params = (JsonArray) getPositionalPlaceholderValues(accessor);
|
||||
return (criteria == null ? new Query() : new Query().addCriteria(criteria)).with(sort).setPositionalParameters(
|
||||
params);
|
||||
return (criteria == null ? new Query() : new Query().addCriteria(criteria)).with(sort);
|
||||
}
|
||||
|
||||
private QueryCriteria from(final Part part, final CouchbasePersistentProperty property,
|
||||
final QueryCriteria criteria, final Iterator<Object> parameters) {
|
||||
private QueryCriteria from(final Part part, final CouchbasePersistentProperty property, final QueryCriteria criteria,
|
||||
final Iterator<Object> parameters) {
|
||||
|
||||
final Part.Type type = part.getType();
|
||||
/*
|
||||
NEAR(new String[]{"IsNear", "Near"}),
|
||||
*/
|
||||
switch (type) {
|
||||
case GREATER_THAN:
|
||||
case AFTER:
|
||||
return criteria.gt(parameters.next());
|
||||
case GREATER_THAN_EQUAL:
|
||||
return criteria.gte(parameters.next());
|
||||
case LESS_THAN:
|
||||
case BEFORE:
|
||||
return criteria.lt(parameters.next());
|
||||
case LESS_THAN_EQUAL:
|
||||
return criteria.lte(parameters.next());
|
||||
case SIMPLE_PROPERTY:
|
||||
return criteria.eq(parameters.next());
|
||||
case NEGATING_SIMPLE_PROPERTY:
|
||||
return criteria.ne(parameters.next());
|
||||
case CONTAINING:
|
||||
return criteria.containing(parameters.next());
|
||||
case NOT_CONTAINING:
|
||||
return criteria.notContaining(parameters.next());
|
||||
case STARTING_WITH:
|
||||
return criteria.startingWith(parameters.next());
|
||||
case ENDING_WITH:
|
||||
return criteria.endingWith(parameters.next());
|
||||
case LIKE:
|
||||
return criteria.like(parameters.next());
|
||||
case NOT_LIKE:
|
||||
return criteria.notLike(parameters.next());
|
||||
case WITHIN:
|
||||
return criteria.within(parameters.next());
|
||||
case IS_NULL:
|
||||
return criteria.isNull(/*parameters.next()*/);
|
||||
case IS_NOT_NULL:
|
||||
return criteria.isNotNull(/*parameters.next()*/);
|
||||
case IS_EMPTY:
|
||||
return criteria.isNotValued(/*parameters.next()*/);
|
||||
case IS_NOT_EMPTY:
|
||||
return criteria.isValued(/*parameters.next()*/);
|
||||
case EXISTS:
|
||||
return criteria.isNotMissing(/*parameters.next()*/);
|
||||
case REGEX:
|
||||
return criteria.regex(parameters.next());
|
||||
case BETWEEN:
|
||||
return criteria.between(parameters.next(), parameters.next());
|
||||
case IN:
|
||||
return criteria.in((Object[]) parameters.next());
|
||||
case NOT_IN:
|
||||
return criteria.notIn((Object[]) parameters.next());
|
||||
case TRUE:
|
||||
return criteria.TRUE();
|
||||
case FALSE:
|
||||
return criteria.FALSE();
|
||||
default:
|
||||
throw new IllegalArgumentException("Unsupported keyword!");
|
||||
case GREATER_THAN:
|
||||
case AFTER:
|
||||
return criteria.gt(parameters.next());
|
||||
case GREATER_THAN_EQUAL:
|
||||
return criteria.gte(parameters.next());
|
||||
case LESS_THAN:
|
||||
case BEFORE:
|
||||
return criteria.lt(parameters.next());
|
||||
case LESS_THAN_EQUAL:
|
||||
return criteria.lte(parameters.next());
|
||||
case SIMPLE_PROPERTY:
|
||||
return criteria.eq(parameters.next());
|
||||
case NEGATING_SIMPLE_PROPERTY:
|
||||
return criteria.ne(parameters.next());
|
||||
case CONTAINING:
|
||||
return criteria.containing(parameters.next());
|
||||
case NOT_CONTAINING:
|
||||
return criteria.notContaining(parameters.next());
|
||||
case STARTING_WITH:
|
||||
return criteria.startingWith(parameters.next());
|
||||
case ENDING_WITH:
|
||||
return criteria.endingWith(parameters.next());
|
||||
case LIKE:
|
||||
return criteria.like(parameters.next());
|
||||
case NOT_LIKE:
|
||||
return criteria.notLike(parameters.next());
|
||||
case WITHIN:
|
||||
return criteria.within(parameters.next());
|
||||
case IS_NULL:
|
||||
return criteria.isNull(/*parameters.next()*/);
|
||||
case IS_NOT_NULL:
|
||||
return criteria.isNotNull(/*parameters.next()*/);
|
||||
case IS_EMPTY:
|
||||
return criteria.isNotValued(/*parameters.next()*/);
|
||||
case IS_NOT_EMPTY:
|
||||
return criteria.isValued(/*parameters.next()*/);
|
||||
case EXISTS:
|
||||
return criteria.isNotMissing(/*parameters.next()*/);
|
||||
case REGEX:
|
||||
return criteria.regex(parameters.next());
|
||||
case BETWEEN:
|
||||
return criteria.between(parameters.next(), parameters.next());
|
||||
case IN:
|
||||
return criteria.in(parameters.next());
|
||||
case NOT_IN:
|
||||
return criteria.notIn(parameters.next());
|
||||
case TRUE:
|
||||
return criteria.TRUE();
|
||||
case FALSE:
|
||||
return criteria.FALSE();
|
||||
default:
|
||||
throw new IllegalArgumentException("Unsupported keyword!");
|
||||
}
|
||||
}
|
||||
|
||||
// from StringN1qlQueryParser
|
||||
private JsonValue getPositionalPlaceholderValues(ParameterAccessor accessor) {
|
||||
JsonArray posValues = JsonArray.create();
|
||||
if (queryMethod == null)
|
||||
return posValues;
|
||||
for (Parameter parameter : this.queryMethod.getParameters().getBindableParameters()) {
|
||||
try {
|
||||
posValues.add(converter.convertForWriteIfNeeded(accessor.getBindableValue(parameter.getIndex())));
|
||||
} catch (InvalidArgumentException iae) {
|
||||
Object o = accessor.getBindableValue(parameter.getIndex());
|
||||
if (o instanceof Object[]) {
|
||||
Object[] array = (Object[]) o;
|
||||
for (Object e : array) {
|
||||
posValues.add(converter.convertForWriteIfNeeded(e));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return posValues;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -189,14 +189,14 @@ public class StringBasedN1qlQueryParser {
|
||||
if (checkNotQuoted(placeholder, namedMatcher.start(), namedMatcher.end(), quotes)) {
|
||||
LOGGER.trace("{}: Found named placeholder {}", this.queryMethod.getName(), placeholder);
|
||||
namedCount++;
|
||||
parameterNames.add(placeholder.substring(1));//save without the leading $
|
||||
parameterNames.add(placeholder.substring(1));// save without the leading $
|
||||
}
|
||||
}
|
||||
|
||||
if (posCount > 0 && namedCount > 0) { // actual values from parameterNames might be more useful
|
||||
throw new IllegalArgumentException("Using both named (" + namedCount + ") and positional (" + posCount
|
||||
+ ") placeholders is not supported, please choose one over the other in "
|
||||
+ queryMethod.getClass().getName() + "." + this.queryMethod.getName() + "()");
|
||||
+ ") placeholders is not supported, please choose one over the other in " + queryMethod.getClass().getName()
|
||||
+ "." + this.queryMethod.getName() + "()");
|
||||
}
|
||||
|
||||
if (posCount > 0) {
|
||||
@@ -211,8 +211,7 @@ public class StringBasedN1qlQueryParser {
|
||||
private boolean checkNotQuoted(String item, int start, int end, List<int[]> quotes) {
|
||||
for (int[] quote : quotes) {
|
||||
if (quote[0] <= start && quote[1] >= end) {
|
||||
LOGGER.trace("{}: potential placeholder {} is inside quotes, ignored", this.queryMethod.getName(),
|
||||
item);
|
||||
LOGGER.trace("{}: potential placeholder {} is inside quotes, ignored", this.queryMethod.getName(), item);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -220,7 +219,7 @@ public class StringBasedN1qlQueryParser {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Postional argument placeholders to use for parameters. $1, $2 etc.
|
||||
* Get Postional argument placeholders to use for parameters. $1, $2 etc.
|
||||
*
|
||||
* @param accessor
|
||||
* @return - JsonValue holding parameters.
|
||||
@@ -230,7 +229,7 @@ public class StringBasedN1qlQueryParser {
|
||||
for (Parameter parameter : this.queryMethod.getParameters().getBindableParameters()) {
|
||||
Object rawValue = accessor.getBindableValue(parameter.getIndex());
|
||||
Object value = couchbaseConverter.convertForWriteIfNeeded(rawValue);
|
||||
putPositionalValue(accessor, parameter, posValues, value);
|
||||
putPositionalValue(posValues, value);
|
||||
}
|
||||
return posValues;
|
||||
}
|
||||
@@ -251,22 +250,20 @@ public class StringBasedN1qlQueryParser {
|
||||
|
||||
if (placeholder != null && placeholder.charAt(0) == ':') {
|
||||
placeholder = placeholder.replaceFirst(":", "");
|
||||
putNamedValue(accessor, parameter, namedValues, placeholder, value);
|
||||
putNamedValue(namedValues, placeholder, value);
|
||||
if (pNames.contains(placeholder)) {
|
||||
pNames.remove(placeholder);
|
||||
} else {
|
||||
throw new RuntimeException(
|
||||
"parameter named " + placeholder + " does not match any named parameter " + parameterNames
|
||||
+ " in " + statement);
|
||||
throw new RuntimeException("parameter named " + placeholder + " does not match any named parameter "
|
||||
+ parameterNames + " in " + statement);
|
||||
}
|
||||
} else {
|
||||
if (parameter.getName().isPresent()) {
|
||||
putNamedValue(accessor, parameter, namedValues, parameter.getName().get(), value);
|
||||
putNamedValue(namedValues, parameter.getName().get(), value);
|
||||
} else {
|
||||
throw new RuntimeException(
|
||||
"cannot determine argument for named parameter. " + "Argument " + parameter.getIndex()
|
||||
+ " to " + queryMethod.getClass().getName() + "." + queryMethod.getName()
|
||||
+ "() needs @Param(\"name\") that matches a named parameter in " + statement);
|
||||
throw new RuntimeException("cannot determine argument for named parameter. " + "Argument "
|
||||
+ parameter.getIndex() + " to " + queryMethod.getClass().getName() + "." + queryMethod.getName()
|
||||
+ "() needs @Param(\"name\") that matches a named parameter in " + statement);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -278,18 +275,17 @@ public class StringBasedN1qlQueryParser {
|
||||
|
||||
protected JsonValue getPlaceholderValues(ParameterAccessor accessor) {
|
||||
switch (this.placeHolderType) {
|
||||
case NAMED:
|
||||
return getNamedPlaceholderValues(accessor);
|
||||
case POSITIONAL:
|
||||
return getPositionalPlaceholderValues(accessor);
|
||||
case NONE:
|
||||
default:
|
||||
return JsonArray.create();
|
||||
case NAMED:
|
||||
return getNamedPlaceholderValues(accessor);
|
||||
case POSITIONAL:
|
||||
return getPositionalPlaceholderValues(accessor);
|
||||
case NONE:
|
||||
default:
|
||||
return JsonArray.create();
|
||||
}
|
||||
}
|
||||
|
||||
private void putPositionalValue(ParameterAccessor accessor, Parameter parameter, JsonArray posValues,
|
||||
Object value) {
|
||||
private void putPositionalValue(JsonArray posValues, Object value) {
|
||||
try {
|
||||
posValues.add(value);
|
||||
} catch (InvalidArgumentException iae) {
|
||||
@@ -310,8 +306,7 @@ public class StringBasedN1qlQueryParser {
|
||||
posValues.add(ja);
|
||||
}
|
||||
|
||||
private void putNamedValue(ParameterAccessor accessor, Parameter parameter, JsonObject namedValues,
|
||||
String placeholder, Object value) {
|
||||
private void putNamedValue(JsonObject namedValues, String placeholder, Object value) {
|
||||
try {
|
||||
namedValues.put(placeholder, value);
|
||||
} catch (InvalidArgumentException iae) {
|
||||
|
||||
@@ -145,7 +145,7 @@ public class StringN1qlQueryCreator extends AbstractQueryCreator<Query, QueryCri
|
||||
final Part.Type type = part.getType();
|
||||
switch (type) {
|
||||
case SIMPLE_PROPERTY:
|
||||
return criteria; //.eq(parameters.next()); // this will be the dummy from PartTree
|
||||
return criteria; // this will be the dummy from PartTree
|
||||
default:
|
||||
throw new IllegalArgumentException("Unsupported keyword!");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user