DATACOUCH-137 - queryDerivation for N1QL annotated methods.

Abstracted the N1QL-based variants in AbstractN1qlBasedQuery. This implementation doesn't recognize QueryParams or QueryPlan anymore in the method parameters so that the method signatures are not store-dependent.

Added query derivation from PartTree to N1QL query, using N1qlQueryCreator.

Unit tested the mapping between a Part.Type and the corresponding N1QL Expression.
This commit is contained in:
Simon Baslé
2015-07-07 19:41:27 +02:00
parent 9deaf6b480
commit c29727595c
12 changed files with 947 additions and 109 deletions

View File

@@ -18,10 +18,13 @@ package org.springframework.data.couchbase.repository;
import static org.junit.Assert.*;
import java.util.Arrays;
import com.couchbase.client.java.Bucket;
import com.couchbase.client.java.view.Stale;
import com.couchbase.client.java.view.ViewQuery;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -101,6 +104,8 @@ public class SimpleCouchbaseRepositoryTests {
}
@Test
@Ignore("View based query with copy of params from a ViewQuery in the method parameter not implemented")
//TODO re-enable test once ViewQuery parameters other than designDoc/viewName can be copied
public void shouldFindCustom() {
Iterable<User> users = repository.customViewQuery(ViewQuery.from("", "").limit(2).stale(Stale.FALSE));
int size = 0;
@@ -133,4 +138,12 @@ public class SimpleCouchbaseRepositoryTests {
}
}
@Test
public void shouldFindFromDeriveQueryWithRegexpAndIn() {
User user = repository.findByUsernameRegexAndUsernameIn("uname-[123]", Arrays.asList("uname-2", "uname-4"));
assertNotNull(user);
assertEquals("testuser-2", user.getKey());
assertEquals("uname-2", user.getUsername());
}
}

View File

@@ -16,6 +16,8 @@
package org.springframework.data.couchbase.repository;
import java.util.List;
import com.couchbase.client.java.view.ViewQuery;
import org.springframework.data.couchbase.core.view.N1QL;
@@ -35,4 +37,7 @@ public interface UserRepository extends CouchbaseRepository<User, String> {
@N1QL("SELECT * FROM $BUCKET$ WHERE username = $1")
User findByUsernameBadSelect(String username);
@N1QL
User findByUsernameRegexAndUsernameIn(String regex, List<String> sample);
}

View File

@@ -18,6 +18,8 @@ package org.springframework.data.couchbase.config;
import org.springframework.beans.factory.xml.NamespaceHandler;
import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
import org.springframework.data.couchbase.repository.config.CouchbaseRepositoryConfigurationExtension;
import org.springframework.data.repository.config.RepositoryBeanDefinitionParser;
/**
* {@link NamespaceHandler} for Couchbase configuration.
@@ -33,7 +35,8 @@ public class CouchbaseNamespaceHandler extends NamespaceHandlerSupport {
* Register bean definition parsers in the namespace handler.
*/
public final void init() {
//TODO repositories (CouchbaseRepositoryConfigurationExtension and RepositoryBeanDefinitionParser)
CouchbaseRepositoryConfigurationExtension extension = new CouchbaseRepositoryConfigurationExtension();
registerBeanDefinitionParser("repositories", new RepositoryBeanDefinitionParser(extension));
registerBeanDefinitionParser("env", new CouchbaseEnvironmentParser());
registerBeanDefinitionParser("cluster", new CouchbaseClusterParser());
registerBeanDefinitionParser("bucket", new CouchbaseBucketParser());

View File

@@ -16,7 +16,9 @@
package org.springframework.data.couchbase.core.mapping;
import org.springframework.core.convert.converter.Converter;
import org.springframework.data.mapping.PersistentProperty;
import org.springframework.data.mapping.context.PersistentPropertyPath;
/**
* Represents a property part of an entity that needs to be persisted.
@@ -32,4 +34,16 @@ public interface CouchbasePersistentProperty extends PersistentProperty<Couchbas
*/
String getFieldName();
/**
* A converter that can be used to extract the {@link #getFieldName() fieldName}, eg. when one wants
* a path from {@link PersistentPropertyPath#toDotPath(Converter)} made of field names.
*/
Converter<? super CouchbasePersistentProperty,String> FIELD_NAME = new Converter<CouchbasePersistentProperty, String>() {
@Override
public String convert(CouchbasePersistentProperty source) {
return source.getFieldName();
}
};
}

View File

@@ -16,13 +16,10 @@
package org.springframework.data.couchbase.repository.query;
import java.util.Iterator;
import java.util.List;
import com.couchbase.client.java.document.json.JsonArray;
import com.couchbase.client.java.query.Query;
import com.couchbase.client.java.query.QueryParams;
import com.couchbase.client.java.query.QueryPlan;
import com.couchbase.client.java.query.Statement;
import org.springframework.data.couchbase.core.CouchbaseOperations;
@@ -38,7 +35,7 @@ import org.springframework.data.util.StreamUtils;
*/
public abstract class AbstractN1qlBasedQuery implements RepositoryQuery {
private final CouchbaseQueryMethod queryMethod;
protected final CouchbaseQueryMethod queryMethod;
private final CouchbaseOperations couchbaseOperations;
protected AbstractN1qlBasedQuery(CouchbaseQueryMethod queryMethod, CouchbaseOperations couchbaseOperations) {
@@ -46,45 +43,28 @@ public abstract class AbstractN1qlBasedQuery implements RepositoryQuery {
this.couchbaseOperations = couchbaseOperations;
}
protected abstract Statement getStatement();
protected abstract Statement getStatement(ParameterAccessor accessor);
protected abstract JsonArray getPlaceholderValues(ParameterAccessor accessor);
@Override
public Object execute(Object[] parameters) {
Statement statement = getStatement();
ParameterAccessor accessor = new ParametersParameterAccessor(queryMethod.getParameters(), parameters);
Statement statement = getStatement(accessor);
JsonArray queryPlaceholderValues = getPlaceholderValues(accessor);
ParameterAccessor parameterAccessor = new ParametersParameterAccessor(queryMethod.getParameters(), parameters);
Query query = buildQuery(statement, parameterAccessor.iterator());
Query query = buildQuery(statement, queryPlaceholderValues);
return executeDependingOnType(query, queryMethod, queryMethod.isPageQuery(), queryMethod.isModifyingQuery(),
queryMethod.isSliceQuery());
}
protected static Query buildQuery(Statement statement, Iterator<Object> paramIterator) {
JsonArray queryValues = JsonArray.create();
QueryParams queryParams = null;
QueryPlan preparedPayload = null;
while (paramIterator.hasNext()) {
Object next = paramIterator.next();
if (next instanceof QueryParams) {
queryParams = (QueryParams) next;
}
else if (next instanceof QueryPlan) {
preparedPayload = (QueryPlan) next;
}
else {
queryValues.add(next);
}
}
protected static Query buildQuery(Statement statement, JsonArray queryPlaceholderValues) {
Query query;
if (preparedPayload != null) {
query = Query.prepared(preparedPayload, queryValues.isEmpty() ? null : queryValues, queryParams);
}
else if (!queryValues.isEmpty()) {
query = Query.parametrized(statement, queryValues, queryParams);
if (!queryPlaceholderValues.isEmpty()) {
query = Query.parametrized(statement, queryPlaceholderValues);
}
else {
query = Query.simple(statement, queryParams);
query = Query.simple(statement);
}
return query;
@@ -123,4 +103,8 @@ public abstract class AbstractN1qlBasedQuery implements RepositoryQuery {
public CouchbaseQueryMethod getQueryMethod() {
return this.queryMethod;
}
protected CouchbaseOperations getCouchbaseOperations() {
return this.couchbaseOperations;
}
}

View File

@@ -16,6 +16,8 @@
package org.springframework.data.couchbase.repository.query;
import java.lang.reflect.Method;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.data.couchbase.core.mapping.CouchbasePersistentEntity;
import org.springframework.data.couchbase.core.mapping.CouchbasePersistentProperty;
@@ -26,8 +28,6 @@ import org.springframework.data.repository.core.RepositoryMetadata;
import org.springframework.data.repository.query.QueryMethod;
import org.springframework.util.StringUtils;
import java.lang.reflect.Method;
/**
* Represents a query method with couchbase extensions, allowing to discover
* if View-based query or N1QL-based query must be used.

View File

@@ -0,0 +1,301 @@
/*
* Copyright 2012-2015 the original author or authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.couchbase.repository.query;
import static com.couchbase.client.java.query.dsl.Expression.s;
import static com.couchbase.client.java.query.dsl.Expression.x;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import com.couchbase.client.java.document.json.JsonArray;
import com.couchbase.client.java.query.dsl.Expression;
import com.couchbase.client.java.query.dsl.functions.StringFunctions;
import com.couchbase.client.java.query.dsl.path.LimitPath;
import com.couchbase.client.java.query.dsl.path.OrderByPath;
import com.couchbase.client.java.query.dsl.path.WherePath;
import org.springframework.data.couchbase.core.convert.CouchbaseConverter;
import org.springframework.data.couchbase.core.mapping.CouchbasePersistentEntity;
import org.springframework.data.couchbase.core.mapping.CouchbasePersistentProperty;
import org.springframework.data.domain.Sort;
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.data.mapping.context.PersistentPropertyPath;
import org.springframework.data.repository.query.ParameterAccessor;
import org.springframework.data.repository.query.parser.AbstractQueryCreator;
import org.springframework.data.repository.query.parser.Part;
import org.springframework.data.repository.query.parser.PartTree;
/**
* This {@link AbstractQueryCreator Query Creator} is responsible for parsing a {@link PartTree} (representing
* a method name) into the WHERE clause of a N1QL query.
* <p>
* In the following, "field" represents the path in JSON deduced from the part of the method name. "a" and "b" represent
* the values of next consumed method parameters. "array" represent a {@link JsonArray} constructed from the next method
* parameter value (if a collection or array, contained values are used to fill the array, otherwise it's a single item
* array).
* <br/>
* Here are the {@link Part.Type} supported (<code>field</code>:
* <ul>
* <li><b>BETWEEN:</b> field BETWEEN a AND b</li>
* <li><b>IS_NOT_NULL:</b> field IS NOT NULL</li>
* <li><b>IS_NULL:</b> field IS NULL</li>
* <li><b>NEGATING_SIMPLE_PROPERTY:</b> - field != a</li>
* <li><b>SIMPLE_PROPERTY:</b> - field = a</li>
* <li><b>LESS_THAN:</b> field &lt; a</li>
* <li><b>LESS_THAN_EQUAL:</b> field &lt;= a</li>
* <li><b>GREATER_THAN_EQUAL:</b> field &gt;= a</li>
* <li><b>GREATER_THAN:</b> field &gt; a</li>
* <li><b>BEFORE:</b> field &lt; a</li>
* <li><b>AFTER:</b> field &gt; a</li>
* <li><b>NOT_LIKE:</b> field NOT LIKE "a" - a should be a String containing % and _ (matching n and 1 characters)</li>
* <li><b>LIKE:</b> field LIKE "a" - a should be a String containing % and _ (matching n and 1 characters)</li>
* <li><b>STARTING_WITH:</b> field LIKE "a%" - a should be a String prefix</li>
* <li><b>ENDING_WITH:</b> field LIKE "%a" - a should be a String suffix</li>
* <li><b>NOT_CONTAINING:</b> field NOT LIKE "%a%" - a should be a String</li>
* <li><b>CONTAINING:</b> field LIKE "%a%" - a should be a String</li>
* <li><b>NOT_IN:</b> field NOT IN array - note that the next parameter value (or its children if a collection/array)
* should be compatible for storage in a {@link JsonArray})</li>
* <li><b>IN:</b> field IN array - note that the next parameter value (or its children if a collection/array) should
* be compatible for storage in a {@link JsonArray})</li>
* <li><b>TRUE:</b> field = TRUE</li>
* <li><b>FALSE:</b> field = FALSE</li>
* <li><b>REGEX:</b> REGEXP_LIKE(field, "a") - note that the ignoreCase is ignored here, a is a regular expression
* in String form</li>
* <li><b>EXISTS:</b> field IS NOT MISSING - used to verify that the JSON contains this attribute</li>
* </ul>
* <br/>
* The following are not supported and will throw an {@link IllegalArgumentException} if encountered:
* <ul>
* <li><b>NEAR, WITHIN:</b> geospatial is not supported in N1QL as of now</li>
* </ul>
* </p>
*
* @author Simon Baslé
*/
public class N1qlQueryCreator extends AbstractQueryCreator<LimitPath, Expression> {
private final ParameterAccessor accessor;
private final WherePath selectFrom;
private final MappingContext<? extends CouchbasePersistentEntity<?>, CouchbasePersistentProperty> context;
public N1qlQueryCreator(PartTree tree, ParameterAccessor parameters, WherePath selectFrom,
CouchbaseConverter converter) {
super(tree, parameters);
this.accessor = parameters;
this.selectFrom = selectFrom;
this.context = converter.getMappingContext();
}
@Override
protected Expression create(Part part, Iterator<Object> iterator) {
PersistentPropertyPath<CouchbasePersistentProperty> path = context.getPersistentPropertyPath(part.getProperty());
return prepareExpression(part, path, iterator);
}
@Override
protected Expression and(Part part, Expression base, Iterator<Object> iterator) {
if (base == null) {
return create(part, iterator);
}
return base.and(create(part, iterator));
}
@Override
protected Expression or(Expression base, Expression criteria) {
return base.or(criteria);
}
@Override
protected LimitPath complete(Expression criteria, Sort sort) {
OrderByPath selectFromWhere = selectFrom.where(criteria);
if (sort != null) {
List<com.couchbase.client.java.query.dsl.Sort> cbSortList = new ArrayList<com.couchbase.client.java.query.dsl.Sort>();
for (Sort.Order order : sort) {
if (order.isAscending()) {
cbSortList.add(com.couchbase.client.java.query.dsl.Sort.asc(order.getProperty()));
} else {
cbSortList.add(com.couchbase.client.java.query.dsl.Sort.desc(order.getProperty()));
}
}
com.couchbase.client.java.query.dsl.Sort[] cbSorts =
cbSortList.toArray(new com.couchbase.client.java.query.dsl.Sort[cbSortList.size()]);
return selectFromWhere.orderBy(cbSorts);
}
return selectFrom.where(criteria);
}
protected static Expression prepareExpression(Part part, PersistentPropertyPath<CouchbasePersistentProperty> path,
Iterator<Object> parameterValues) {
//FIXME use conversions for the parameters and types
//get the whole doted path with fieldNames instead of potentially wrong propNames
String fieldNamePath = path.toDotPath(CouchbasePersistentProperty.FIELD_NAME);
//deal with ignore case
boolean ignoreCase = false;
Class<?> leafType = 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;
}
return createExpression(part.getType(), fieldNamePath, ignoreCase, parameterValues);
}
protected static Expression createExpression(Part.Type partType, String fieldNamePath, boolean ignoreCase, Iterator<Object> parameterValues) {
//create the left hand side of the expression, taking ignoreCase into account
Expression left = ignoreCase ? StringFunctions.lower(x(fieldNamePath)) : x(fieldNamePath);
switch (partType) {
case BETWEEN:
return left.between(leftAndRight(parameterValues, ignoreCase));
case IS_NOT_NULL:
return left.isNotNull();
case IS_NULL:
return left.isNull();
case NEGATING_SIMPLE_PROPERTY:
return left.ne(right(parameterValues, ignoreCase));
case SIMPLE_PROPERTY:
return left.eq(right(parameterValues, ignoreCase));
case BEFORE:
case LESS_THAN:
return left.lt(right(parameterValues, ignoreCase));
case LESS_THAN_EQUAL:
return left.lte(right(parameterValues, ignoreCase));
case GREATER_THAN_EQUAL:
return left.gte(right(parameterValues, ignoreCase));
case AFTER:
case GREATER_THAN:
return left.gt(right(parameterValues, ignoreCase));
case NOT_LIKE:
return left.notLike(right(parameterValues, ignoreCase));
case LIKE:
return left.like(right(parameterValues, ignoreCase));
case STARTING_WITH:
return left.like(like(parameterValues, ignoreCase, false, true));
case ENDING_WITH:
return left.like(like(parameterValues, ignoreCase, true, false));
case NOT_CONTAINING:
return left.notLike(like(parameterValues, ignoreCase, true, true));
case CONTAINING:
return left.like(like(parameterValues, ignoreCase, true, true));
case NOT_IN:
return left.notIn(rightArray(parameterValues));
case IN:
return left.in(rightArray(parameterValues));
case TRUE:
return left.eq(true);
case FALSE:
return left.eq(false);
case REGEX:
return regexp(fieldNamePath, parameterValues);
case EXISTS:
return left.isNotMissing();
case WITHIN:
case NEAR:
default:
throw new IllegalArgumentException("Unsupported keyword");
}
}
protected static Expression regexp(String left, Iterator<Object> parameterValues) {
//TODO migrate to using the Functions util class when 2.0-dp2 / 2.0 GA
Object next = parameterValues.next();
String pattern;
if (next == null) {
pattern = "";
} else {
pattern = String.valueOf(next);
}
return x("REGEXP_LIKE(" + left + ", \"" + pattern + "\")");
}
protected static Expression leftAndRight(Iterator<Object> parameterValues, boolean ignoreCase) {
return right(parameterValues, ignoreCase).and(right(parameterValues, ignoreCase));
}
protected static Expression like(Iterator<Object> parameterValues, boolean ignoreCase,
boolean anyPrefix, boolean anySuffix) {
Object next = parameterValues.next();
if (next == null) {
return Expression.NULL();
}
Expression converted;
if (next instanceof String) {
String pattern = (String) next;
if (anyPrefix) {
pattern = "%" + pattern;
}
if (anySuffix) {
pattern = pattern + "%";
}
converted = s(pattern);
} else {
converted = x(String.valueOf(next));
}
if (ignoreCase) {
return StringFunctions.lower(converted);
}
return converted;
}
protected static Expression right(Iterator<Object> parameterValues, boolean ignoreCase) {
Object next = parameterValues.next();
if (next == null) {
return Expression.NULL();
}
Expression converted;
if (next instanceof String) {
converted = s((String) next);
} else {
converted = x(String.valueOf(next));
}
if (ignoreCase) {
return StringFunctions.lower(converted);
}
return converted;
}
protected static JsonArray rightArray(Iterator<Object> parameterValues) {
Object next = parameterValues.next();
Object[] values;
if (next instanceof Collection) {
values = ((Collection<?>) next).toArray();
} else if (next.getClass().isArray()) {
values = (Object[]) next;
} else {
values = new Object[] {next};
}
return JsonArray.from(values);
}
}

View File

@@ -0,0 +1,73 @@
/*
* Copyright 2012-2015 the original author or authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.couchbase.repository.query;
import static com.couchbase.client.java.query.Select.select;
import static com.couchbase.client.java.query.dsl.Expression.i;
import static com.couchbase.client.java.query.dsl.Expression.path;
import static com.couchbase.client.java.query.dsl.functions.AggregateFunctions.count;
import static com.couchbase.client.java.query.dsl.functions.MetaFunctions.meta;
import com.couchbase.client.java.document.json.JsonArray;
import com.couchbase.client.java.query.Statement;
import com.couchbase.client.java.query.dsl.Expression;
import com.couchbase.client.java.query.dsl.path.FromPath;
import com.couchbase.client.java.query.dsl.path.LimitPath;
import com.couchbase.client.java.query.dsl.path.WherePath;
import org.springframework.data.couchbase.core.CouchbaseOperations;
import org.springframework.data.repository.query.ParameterAccessor;
import org.springframework.data.repository.query.parser.PartTree;
public class PartTreeN1qlBasedQuery extends AbstractN1qlBasedQuery {
private final PartTree partTree;
public PartTreeN1qlBasedQuery(CouchbaseQueryMethod queryMethod, CouchbaseOperations couchbaseOperations) {
super(queryMethod, couchbaseOperations);
this.partTree = new PartTree(queryMethod.getName(), queryMethod.getEntityInformation().getJavaType());
}
@Override
protected JsonArray getPlaceholderValues(ParameterAccessor accessor) {
return JsonArray.empty();
}
@Override
protected Statement getStatement(ParameterAccessor accessor) {
Expression bucket = i(getCouchbaseOperations().getCouchbaseBucket().name());
Expression metaId = path(meta(bucket), "id").as(CouchbaseOperations.SELECT_ID);
Expression metaCas = path(meta(bucket), "cas").as(CouchbaseOperations.SELECT_CAS);
FromPath select;
if (partTree.isCountProjection()) {
select = select(count("*"));
} else {
select = select(metaId, metaCas, path(bucket, "*"));
}
WherePath selectFrom = select.from(bucket);
N1qlQueryCreator queryCreator = new N1qlQueryCreator(partTree, accessor, selectFrom, getCouchbaseOperations().getConverter());
LimitPath selectFromWhereOrderBy = queryCreator.createQuery();
if (partTree.isLimiting()) {
return selectFromWhereOrderBy.limit(partTree.getMaxResults());
} else {
return selectFromWhereOrderBy;
}
}
}

View File

@@ -16,10 +16,12 @@
package org.springframework.data.couchbase.repository.query;
import com.couchbase.client.java.document.json.JsonArray;
import com.couchbase.client.java.query.Query;
import com.couchbase.client.java.query.Statement;
import org.springframework.data.couchbase.core.CouchbaseOperations;
import org.springframework.data.repository.query.ParameterAccessor;
import org.springframework.data.repository.query.RepositoryQuery;
/**
@@ -63,7 +65,17 @@ public class StringN1qlBasedQuery extends AbstractN1qlBasedQuery {
}
@Override
public Statement getStatement() {
protected JsonArray getPlaceholderValues(ParameterAccessor accessor) {
JsonArray values = JsonArray.create();
for (Object value : accessor) {
values.add(value);
}
return values;
}
@Override
public Statement getStatement(ParameterAccessor accessor) {
return this.statement;
}
}

View File

@@ -24,6 +24,7 @@ import org.springframework.data.couchbase.core.mapping.CouchbasePersistentEntity
import org.springframework.data.couchbase.core.mapping.CouchbasePersistentProperty;
import org.springframework.data.couchbase.repository.query.CouchbaseEntityInformation;
import org.springframework.data.couchbase.repository.query.CouchbaseQueryMethod;
import org.springframework.data.couchbase.repository.query.PartTreeN1qlBasedQuery;
import org.springframework.data.couchbase.repository.query.StringN1qlBasedQuery;
import org.springframework.data.couchbase.repository.query.ViewBasedCouchbaseQuery;
import org.springframework.data.mapping.context.MappingContext;
@@ -32,6 +33,7 @@ import org.springframework.data.repository.core.NamedQueries;
import org.springframework.data.repository.core.RepositoryInformation;
import org.springframework.data.repository.core.RepositoryMetadata;
import org.springframework.data.repository.core.support.RepositoryFactorySupport;
import org.springframework.data.repository.query.EvaluationContextProvider;
import org.springframework.data.repository.query.QueryLookupStrategy;
import org.springframework.data.repository.query.RepositoryQuery;
import org.springframework.util.Assert;
@@ -121,7 +123,7 @@ public class CouchbaseRepositoryFactory extends RepositoryFactorySupport {
}
@Override
protected QueryLookupStrategy getQueryLookupStrategy(QueryLookupStrategy.Key key) {
protected QueryLookupStrategy getQueryLookupStrategy(QueryLookupStrategy.Key key, EvaluationContextProvider contextProvider) {
return new CouchbaseQueryLookupStrategy();
}
@@ -141,8 +143,7 @@ public class CouchbaseRepositoryFactory extends RepositoryFactorySupport {
String namedQuery = namedQueries.getQuery(namedQueryName);
return new StringN1qlBasedQuery(namedQuery, queryMethod, couchbaseOperations);
} else {
//FIXME return new PartBasedN1qlQuery(queryMethod, couchbaseOperations, namedQueries);
return new StringN1qlBasedQuery("SELECT 1", queryMethod, couchbaseOperations);
return new PartTreeN1qlBasedQuery(queryMethod, couchbaseOperations);
}
}
return new ViewBasedCouchbaseQuery(queryMethod, couchbaseOperations);

View File

@@ -4,68 +4,28 @@ import static com.couchbase.client.java.query.Select.select;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;
import com.couchbase.client.java.document.json.JsonArray;
import com.couchbase.client.java.document.json.JsonObject;
import com.couchbase.client.java.query.ParametrizedQuery;
import com.couchbase.client.java.query.PreparedQuery;
import com.couchbase.client.java.query.Query;
import com.couchbase.client.java.query.QueryParams;
import com.couchbase.client.java.query.QueryPlan;
import com.couchbase.client.java.query.Select;
import com.couchbase.client.java.query.SimpleQuery;
import com.couchbase.client.java.query.Statement;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.mockito.Mockito;
import org.springframework.data.couchbase.UnitTestApplicationConfig;
import org.springframework.data.couchbase.core.mapping.CouchbasePersistentEntity;
import org.springframework.data.couchbase.core.mapping.CouchbasePersistentProperty;
import org.springframework.data.domain.Page;
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.data.repository.core.RepositoryMetadata;
import org.springframework.data.repository.query.Parameters;
import org.springframework.data.repository.query.QueryMethod;
import org.springframework.data.util.ReflectionUtils;
public class AbstractN1qlBasedQueryTest {
@Test
public void testQueryPlanShouldProducePreparedQuery() throws Exception {
Statement st = select("*");
QueryPlan plan = new QueryPlan(JsonObject.create());
List<Object> params = new ArrayList<Object>(2);
params.add("test");
params.add(plan);
Query query = AbstractN1qlBasedQuery.buildQuery(st, params.iterator());
JsonObject queryObject = query.n1ql();
assertTrue(query instanceof PreparedQuery);
assertEquals(plan, query.statement());
assertNull(query.params());
assertNotNull(queryObject.get("args"));
assertEquals(1, queryObject.getArray("args").size());
assertEquals("test", queryObject.getArray("args").getString(0));
params.add(QueryParams.build());
query = AbstractN1qlBasedQuery.buildQuery(st, params.iterator());
assertNotNull(query.params());
}
@Test
public void testEmptyArgumentsShouldProduceSimpleQuery() throws Exception {
Statement st = select("*");
List<Object> params = Collections.emptyList();
Query query = AbstractN1qlBasedQuery.buildQuery(st, params.iterator());
Query query = AbstractN1qlBasedQuery.buildQuery(st, JsonArray.empty());
JsonObject queryObject = query.n1ql();
assertTrue(query instanceof SimpleQuery);
assertEquals(st.toString(), query.statement().toString());
assertNull(query.params());
@@ -73,53 +33,36 @@ public class AbstractN1qlBasedQueryTest {
}
@Test
public void testOnlyQueryParamsShouldProduceSimpleQuery() {
Statement st = select("*");
QueryParams queryParams = QueryParams.build().scanWait(1, TimeUnit.DAYS);
List<Object> params = new ArrayList<Object>(1);
params.add(queryParams);
Query query = AbstractN1qlBasedQuery.buildQuery(st, params.iterator());
JsonObject queryObject = query.n1ql();
assertTrue(query instanceof SimpleQuery);
assertEquals(st.toString(), query.statement().toString());
assertEquals(queryParams, query.params());
assertFalse(queryObject.containsKey("args"));
}
@Test
public void testSimpleArgumentsShouldProduceParametrizedQuery() throws Exception {
public void testSimpleArgumentShouldProduceParametrizedQuery() throws Exception {
Statement st = select("*");
List<Object> params = new ArrayList<Object>(2);
params.add(123L);
params.add("test");
Query query = AbstractN1qlBasedQuery.buildQuery(st, params.iterator());
JsonArray placeholderValues = JsonArray.from(params);
Query query = AbstractN1qlBasedQuery.buildQuery(st, placeholderValues);
JsonObject queryObject = query.n1ql();
assertTrue(query instanceof ParametrizedQuery);
assertEquals(st.toString(), query.statement().toString());
assertNull(query.params());
assertTrue(queryObject.containsKey("args"));
JsonArray args = queryObject.getArray("args");
assertEquals(2, args.size());
assertEquals(123L, args.get(0));
assertEquals("test", args.get(1));
assertEquals(1, args.size());
assertEquals("test", args.get(0));
}
@Test
public void testSimpleArgumentsAndQueryParamsShouldProduceParametrizedQuery() throws Exception {
public void testMultipleArgumentsShouldProduceParametrizedQuery() throws Exception {
Statement st = select("*");
QueryParams queryParams = QueryParams.build().withContextId("toto");
List<Object> params = new ArrayList<Object>(2);
params.add(123L);
params.add(queryParams);
params.add("test");
Query query = AbstractN1qlBasedQuery.buildQuery(st, params.iterator());
JsonArray placeholderValues = JsonArray.from(params);
Query query = AbstractN1qlBasedQuery.buildQuery(st, placeholderValues);
JsonObject queryObject = query.n1ql();
assertTrue(query instanceof ParametrizedQuery);
assertEquals(st.toString(), query.statement().toString());
assertEquals(queryParams, query.params());
assertNull(query.params());
assertTrue(queryObject.containsKey("args"));
JsonArray args = queryObject.getArray("args");
assertEquals(2, args.size());

View File

@@ -0,0 +1,489 @@
package org.springframework.data.couchbase.repository.query;
import static org.junit.Assert.assertEquals;
import static org.springframework.data.couchbase.repository.query.N1qlQueryCreator.createExpression;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import com.couchbase.client.java.query.dsl.Expression;
import org.junit.Test;
import org.springframework.data.repository.query.parser.Part;
public class N1qlQueryCreatorTest {
//==== The tests below check mapping between a Part.Type and the corresponding N1QL expression ====
@Test
public void testBETWEEN() throws Exception {
Part.Type keyword = Part.Type.BETWEEN;
Iterator<Object> values = Arrays.<Object>asList("a", "b", 1, 2, "c", "d").iterator();
String expected = "doc.field BETWEEN \"a\" AND \"b\"";
String expectedNum = "doc.field BETWEEN 1 AND 2";
String expectedIgnoreCase = "LOWER(doc.field) BETWEEN LOWER(\"c\") AND LOWER(\"d\")";
Expression exp = createExpression(keyword, "doc.field", false, values);
Expression expNum = createExpression(keyword, "doc.field", false, values);
Expression expIgnoreCase = createExpression(keyword, "doc.field", true, values);
assertEquals(expected, exp.toString());
assertEquals(expectedNum, expNum.toString());
assertEquals(expectedIgnoreCase, expIgnoreCase.toString());
}
@Test
public void testIS_NOT_NULL() throws Exception {
Part.Type keyword = Part.Type.IS_NOT_NULL;
Iterator<Object> values = Arrays.<Object>asList("a", 1, "b").iterator();
String expected = "doc.field IS NOT NULL";
String expectedNum = "doc.field IS NOT NULL";
String expectedIgnoreCase = "LOWER(doc.field) IS NOT NULL";
Expression exp = createExpression(keyword, "doc.field", false, values);
Expression expNum = createExpression(keyword, "doc.field", false, values);
Expression expIgnoreCase = createExpression(keyword, "doc.field", true, values);
assertEquals(expected, exp.toString());
assertEquals(expectedNum, expNum.toString());
assertEquals(expectedIgnoreCase, expIgnoreCase.toString());
}
@Test
public void testIS_NULL() throws Exception {
Part.Type keyword = Part.Type.IS_NULL;
Iterator<Object> values = Arrays.<Object>asList("a", 1, "b").iterator();
String expected = "doc.field IS NULL";
String expectedNum = "doc.field IS NULL";
String expectedIgnoreCase = "LOWER(doc.field) IS NULL";
Expression exp = createExpression(keyword, "doc.field", false, values);
Expression expNum = createExpression(keyword, "doc.field", false, values);
Expression expIgnoreCase = createExpression(keyword, "doc.field", true, values);
assertEquals(expected, exp.toString());
assertEquals(expectedNum, expNum.toString());
assertEquals(expectedIgnoreCase, expIgnoreCase.toString());
}
@Test
public void testLESS_THAN() throws Exception {
Part.Type keyword = Part.Type.LESS_THAN;
Iterator<Object> values = Arrays.<Object>asList("a", 1, "b").iterator();
String expected = "doc.field < \"a\"";
String expectedNum = "doc.field < 1";
String expectedIgnoreCase = "LOWER(doc.field) < LOWER(\"b\")";
Expression exp = createExpression(keyword, "doc.field", false, values);
Expression expNum = createExpression(keyword, "doc.field", false, values);
Expression expIgnoreCase = createExpression(keyword, "doc.field", true, values);
assertEquals(expected, exp.toString());
assertEquals(expectedNum, expNum.toString());
assertEquals(expectedIgnoreCase, expIgnoreCase.toString());
}
@Test
public void testLESS_THAN_EQUAL() throws Exception {
Part.Type keyword = Part.Type.LESS_THAN_EQUAL;
Iterator<Object> values = Arrays.<Object>asList("a", 1, "b").iterator();
String expected = "doc.field <= \"a\"";
String expectedNum = "doc.field <= 1";
String expectedIgnoreCase = "LOWER(doc.field) <= LOWER(\"b\")";
Expression exp = createExpression(keyword, "doc.field", false, values);
Expression expNum = createExpression(keyword, "doc.field", false, values);
Expression expIgnoreCase = createExpression(keyword, "doc.field", true, values);
assertEquals(expected, exp.toString());
assertEquals(expectedNum, expNum.toString());
assertEquals(expectedIgnoreCase, expIgnoreCase.toString());
}
@Test
public void testGREATER_THAN() throws Exception {
Part.Type keyword = Part.Type.GREATER_THAN;
Iterator<Object> values = Arrays.<Object>asList("a", 1, "b").iterator();
String expected = "doc.field > \"a\"";
String expectedNum = "doc.field > 1";
String expectedIgnoreCase = "LOWER(doc.field) > LOWER(\"b\")";
Expression exp = createExpression(keyword, "doc.field", false, values);
Expression expNum = createExpression(keyword, "doc.field", false, values);
Expression expIgnoreCase = createExpression(keyword, "doc.field", true, values);
assertEquals(expected, exp.toString());
assertEquals(expectedNum, expNum.toString());
assertEquals(expectedIgnoreCase, expIgnoreCase.toString());
}
@Test
public void testGREATER_THAN_EQUAL() throws Exception {
Part.Type keyword = Part.Type.GREATER_THAN_EQUAL;
Iterator<Object> values = Arrays.<Object>asList("a", 1, "b").iterator();
String expected = "doc.field >= \"a\"";
String expectedNum = "doc.field >= 1";
String expectedIgnoreCase = "LOWER(doc.field) >= LOWER(\"b\")";
Expression exp = createExpression(keyword, "doc.field", false, values);
Expression expNum = createExpression(keyword, "doc.field", false, values);
Expression expIgnoreCase = createExpression(keyword, "doc.field", true, values);
assertEquals(expected, exp.toString());
assertEquals(expectedNum, expNum.toString());
assertEquals(expectedIgnoreCase, expIgnoreCase.toString());
}
@Test
public void testBEFORE() throws Exception {
Part.Type keyword = Part.Type.BEFORE;
Iterator<Object> values = Arrays.<Object>asList("a", 1, "b").iterator();
String expected = "doc.field < \"a\"";
String expectedNum = "doc.field < 1";
String expectedIgnoreCase = "LOWER(doc.field) < LOWER(\"b\")";
Expression exp = createExpression(keyword, "doc.field", false, values);
Expression expNum = createExpression(keyword, "doc.field", false, values);
Expression expIgnoreCase = createExpression(keyword, "doc.field", true, values);
assertEquals(expected, exp.toString());
assertEquals(expectedNum, expNum.toString());
assertEquals(expectedIgnoreCase, expIgnoreCase.toString());
}
@Test
public void testAFTER() throws Exception {
Part.Type keyword = Part.Type.AFTER;
Iterator<Object> values = Arrays.<Object>asList("a", 1, "b").iterator();
String expected = "doc.field > \"a\"";
String expectedNum = "doc.field > 1";
String expectedIgnoreCase = "LOWER(doc.field) > LOWER(\"b\")";
Expression exp = createExpression(keyword, "doc.field", false, values);
Expression expNum = createExpression(keyword, "doc.field", false, values);
Expression expIgnoreCase = createExpression(keyword, "doc.field", true, values);
assertEquals(expected, exp.toString());
assertEquals(expectedNum, expNum.toString());
assertEquals(expectedIgnoreCase, expIgnoreCase.toString());
}
@Test
public void testNOT_LIKE() throws Exception {
Part.Type keyword = Part.Type.NOT_LIKE;
Iterator<Object> values = Arrays.<Object>asList("a", 1, "b").iterator();
String expected = "doc.field NOT LIKE \"a\"";
String expectedNum = "doc.field NOT LIKE 1";
String expectedIgnoreCase = "LOWER(doc.field) NOT LIKE LOWER(\"b\")";
Expression exp = createExpression(keyword, "doc.field", false, values);
Expression expNum = createExpression(keyword, "doc.field", false, values);
Expression expIgnoreCase = createExpression(keyword, "doc.field", true, values);
assertEquals(expected, exp.toString());
assertEquals(expectedNum, expNum.toString());
assertEquals(expectedIgnoreCase, expIgnoreCase.toString());
}
@Test
public void testLIKE() throws Exception {
Part.Type keyword = Part.Type.LIKE;
Iterator<Object> values = Arrays.<Object>asList("a", 1, "b").iterator();
String expected = "doc.field LIKE \"a\"";
String expectedNum = "doc.field LIKE 1";
String expectedIgnoreCase = "LOWER(doc.field) LIKE LOWER(\"b\")";
Expression exp = createExpression(keyword, "doc.field", false, values);
Expression expNum = createExpression(keyword, "doc.field", false, values);
Expression expIgnoreCase = createExpression(keyword, "doc.field", true, values);
assertEquals(expected, exp.toString());
assertEquals(expectedNum, expNum.toString());
assertEquals(expectedIgnoreCase, expIgnoreCase.toString());
}
@Test
public void testSTARTING_WITH() throws Exception {
Part.Type keyword = Part.Type.STARTING_WITH;
Iterator<Object> values = Arrays.<Object>asList("a", 1, "b").iterator();
String expected = "doc.field LIKE \"a%\"";
String expectedNum = "doc.field LIKE 1";
String expectedIgnoreCase = "LOWER(doc.field) LIKE LOWER(\"b%\")";
Expression exp = createExpression(keyword, "doc.field", false, values);
Expression expNum = createExpression(keyword, "doc.field", false, values);
Expression expIgnoreCase = createExpression(keyword, "doc.field", true, values);
assertEquals(expected, exp.toString());
assertEquals(expectedNum, expNum.toString());
assertEquals(expectedIgnoreCase, expIgnoreCase.toString());
}
@Test
public void testENDING_WITH() throws Exception {
Part.Type keyword = Part.Type.ENDING_WITH;
Iterator<Object> values = Arrays.<Object>asList("a", 1, "b").iterator();
String expected = "doc.field LIKE \"%a\"";
String expectedNum = "doc.field LIKE 1";
String expectedIgnoreCase = "LOWER(doc.field) LIKE LOWER(\"%b\")";
Expression exp = createExpression(keyword, "doc.field", false, values);
Expression expNum = createExpression(keyword, "doc.field", false, values);
Expression expIgnoreCase = createExpression(keyword, "doc.field", true, values);
assertEquals(expected, exp.toString());
assertEquals(expectedNum, expNum.toString());
assertEquals(expectedIgnoreCase, expIgnoreCase.toString());
}
@Test
public void testNOT_CONTAINING() throws Exception {
Part.Type keyword = Part.Type.NOT_CONTAINING;
Iterator<Object> values = Arrays.<Object>asList("a", 1, "b").iterator();
String expected = "doc.field NOT LIKE \"%a%\"";
String expectedNum = "doc.field NOT LIKE 1";
String expectedIgnoreCase = "LOWER(doc.field) NOT LIKE LOWER(\"%b%\")";
Expression exp = createExpression(keyword, "doc.field", false, values);
Expression expNum = createExpression(keyword, "doc.field", false, values);
Expression expIgnoreCase = createExpression(keyword, "doc.field", true, values);
assertEquals(expected, exp.toString());
assertEquals(expectedNum, expNum.toString());
assertEquals(expectedIgnoreCase, expIgnoreCase.toString());
}
@Test
public void testCONTAINING() throws Exception {
Part.Type keyword = Part.Type.CONTAINING;
Iterator<Object> values = Arrays.<Object>asList("a", 1, "b").iterator();
String expected = "doc.field LIKE \"%a%\"";
String expectedNum = "doc.field LIKE 1";
String expectedIgnoreCase = "LOWER(doc.field) LIKE LOWER(\"%b%\")";
Expression exp = createExpression(keyword, "doc.field", false, values);
Expression expNum = createExpression(keyword, "doc.field", false, values);
Expression expIgnoreCase = createExpression(keyword, "doc.field", true, values);
assertEquals(expected, exp.toString());
assertEquals(expectedNum, expNum.toString());
assertEquals(expectedIgnoreCase, expIgnoreCase.toString());
}
@Test
public void testNOT_IN() throws Exception {
Part.Type keyword = Part.Type.NOT_IN;
Iterator<Object> values = Arrays.<Object>asList("a", 1, "b").iterator();
String expected = "doc.field NOT IN [\"a\"]";
String expectedNum = "doc.field NOT IN [1]";
String expectedIgnoreCase = "LOWER(doc.field) NOT IN [\"b\"]";
Expression exp = createExpression(keyword, "doc.field", false, values);
Expression expNum = createExpression(keyword, "doc.field", false, values);
Expression expIgnoreCase = createExpression(keyword, "doc.field", true, values);
assertEquals(expected, exp.toString());
assertEquals(expectedNum, expNum.toString());
assertEquals(expectedIgnoreCase, expIgnoreCase.toString());
}
@Test
public void testNOTINwithCollection() throws Exception {
Part.Type keyword = Part.Type.NOT_IN;
List<Object> val1 = Arrays.<Object>asList("av1", "av2");
List<Object> val2 = Arrays.<Object>asList("bv1", "bv2");
Iterator<Object> values = Arrays.<Object>asList(val1, val2).iterator();
String expected = "doc.field NOT IN [\"av1\",\"av2\"]";
String expectedIgnoreCase = "LOWER(doc.field) NOT IN [\"bv1\",\"bv2\"]";
Expression exp = createExpression(keyword, "doc.field", false, values);
Expression expIgnoreCase = createExpression(keyword, "doc.field", true, values);
assertEquals(expected, exp.toString());
assertEquals(expectedIgnoreCase, expIgnoreCase.toString());
}
@Test
public void testNOTINwithArray() throws Exception {
Part.Type keyword = Part.Type.NOT_IN;
String[] val1 = {"av1", "av2"};
String[] val2 = {"bv1", "bv2"};
Iterator<Object> values = Arrays.<Object>asList(val1, val2).iterator();
String expected = "doc.field NOT IN [\"av1\",\"av2\"]";
String expectedIgnoreCase = "LOWER(doc.field) NOT IN [\"bv1\",\"bv2\"]";
Expression exp = createExpression(keyword, "doc.field", false, values);
Expression expIgnoreCase = createExpression(keyword, "doc.field", true, values);
assertEquals(expected, exp.toString());
assertEquals(expectedIgnoreCase, expIgnoreCase.toString());
}
@Test
public void testIN() throws Exception {
Part.Type keyword = Part.Type.IN;
Iterator<Object> values = Arrays.<Object>asList("a", 1, "b").iterator();
String expected = "doc.field IN [\"a\"]";
String expectedNum = "doc.field IN [1]";
String expectedIgnoreCase = "LOWER(doc.field) IN [\"b\"]";
Expression exp = createExpression(keyword, "doc.field", false, values);
Expression expNum = createExpression(keyword, "doc.field", false, values);
Expression expIgnoreCase = createExpression(keyword, "doc.field", true, values);
assertEquals(expected, exp.toString());
assertEquals(expectedNum, expNum.toString());
assertEquals(expectedIgnoreCase, expIgnoreCase.toString());
}
@Test
public void testINwithCollection() throws Exception {
Part.Type keyword = Part.Type.IN;
List<Object> val1 = Arrays.<Object>asList("av1", "av2");
List<Object> val2 = Arrays.<Object>asList("bv1", "bv2");
Iterator<Object> values = Arrays.<Object>asList(val1, val2).iterator();
String expected = "doc.field IN [\"av1\",\"av2\"]";
String expectedIgnoreCase = "LOWER(doc.field) IN [\"bv1\",\"bv2\"]";
Expression exp = createExpression(keyword, "doc.field", false, values);
Expression expIgnoreCase = createExpression(keyword, "doc.field", true, values);
assertEquals(expected, exp.toString());
assertEquals(expectedIgnoreCase, expIgnoreCase.toString());
}
@Test
public void testINwithArray() throws Exception {
Part.Type keyword = Part.Type.IN;
String[] val1 = {"av1", "av2"};
String[] val2 = {"bv1", "bv2"};
Iterator<Object> values = Arrays.<Object>asList(val1, val2).iterator();
String expected = "doc.field IN [\"av1\",\"av2\"]";
String expectedIgnoreCase = "LOWER(doc.field) IN [\"bv1\",\"bv2\"]";
Expression exp = createExpression(keyword, "doc.field", false, values);
Expression expIgnoreCase = createExpression(keyword, "doc.field", true, values);
assertEquals(expected, exp.toString());
assertEquals(expectedIgnoreCase, expIgnoreCase.toString());
}
@Test(expected = IllegalArgumentException.class)
public void testNEAR() throws Exception {
Part.Type keyword = Part.Type.NEAR;
Iterator<Object> values = Arrays.<Object>asList("a", 1, "b").iterator();
Expression exp = createExpression(keyword, "doc.field", true, values);
}
@Test(expected = IllegalArgumentException.class)
public void testWITHIN() throws Exception {
Part.Type keyword = Part.Type.WITHIN;
Iterator<Object> values = Arrays.<Object>asList("a", 1, "b").iterator();
Expression exp = createExpression(keyword, "doc.field", false, values);
}
@Test
public void testREGEX() throws Exception {
Part.Type keyword = Part.Type.REGEX;
Iterator<Object> values = Arrays.<Object>asList("a", 1, "b").iterator();
String expected = "REGEXP_LIKE(doc.field, \"a\")";
String expectedNum = "REGEXP_LIKE(doc.field, \"1\")";
String expectedIgnoreCase = "REGEXP_LIKE(doc.field, \"b\")";
Expression exp = createExpression(keyword, "doc.field", false, values);
Expression expNum = createExpression(keyword, "doc.field", false, values);
Expression expIgnoreCase = createExpression(keyword, "doc.field", true, values);
assertEquals(expected, exp.toString());
assertEquals(expectedNum, expNum.toString());
assertEquals(expectedIgnoreCase, expIgnoreCase.toString());
}
@Test
public void testEXISTS() throws Exception {
Part.Type keyword = Part.Type.EXISTS;
Iterator<Object> values = Arrays.<Object>asList("a", 1, "b").iterator();
String expected = "doc.field IS NOT MISSING";
String expectedNum = "doc.field IS NOT MISSING";
String expectedIgnoreCase = "LOWER(doc.field) IS NOT MISSING";
Expression exp = createExpression(keyword, "doc.field", false, values);
Expression expNum = createExpression(keyword, "doc.field", false, values);
Expression expIgnoreCase = createExpression(keyword, "doc.field", true, values);
assertEquals(expected, exp.toString());
assertEquals(expectedNum, expNum.toString());
assertEquals(expectedIgnoreCase, expIgnoreCase.toString());
}
@Test
public void testTRUE() throws Exception {
Part.Type keyword = Part.Type.TRUE;
Iterator<Object> values = Arrays.<Object>asList("a", 1, "b").iterator();
String expected = "doc.field = TRUE";
String expectedNum = "doc.field = TRUE";
String expectedIgnoreCase = "LOWER(doc.field) = TRUE";
Expression exp = createExpression(keyword, "doc.field", false, values);
Expression expNum = createExpression(keyword, "doc.field", false, values);
Expression expIgnoreCase = createExpression(keyword, "doc.field", true, values);
assertEquals(expected, exp.toString());
assertEquals(expectedNum, expNum.toString());
assertEquals(expectedIgnoreCase, expIgnoreCase.toString());
}
@Test
public void testFALSE() throws Exception {
Part.Type keyword = Part.Type.FALSE;
Iterator<Object> values = Arrays.<Object>asList("a", 1, "b").iterator();
String expected = "doc.field = FALSE";
String expectedNum = "doc.field = FALSE";
String expectedIgnoreCase = "LOWER(doc.field) = FALSE";
Expression exp = createExpression(keyword, "doc.field", false, values);
Expression expNum = createExpression(keyword, "doc.field", false, values);
Expression expIgnoreCase = createExpression(keyword, "doc.field", true, values);
assertEquals(expected, exp.toString());
assertEquals(expectedNum, expNum.toString());
assertEquals(expectedIgnoreCase, expIgnoreCase.toString());
}
@Test
public void testNEGATING_SIMPLE_PROPERTY() throws Exception {
Part.Type keyword = Part.Type.NEGATING_SIMPLE_PROPERTY;
Iterator<Object> values = Arrays.<Object>asList("a", 1, "b").iterator();
String expected = "doc.field != \"a\"";
String expectedNum = "doc.field != 1";
String expectedIgnoreCase = "LOWER(doc.field) != LOWER(\"b\")";
Expression exp = createExpression(keyword, "doc.field", false, values);
Expression expNum = createExpression(keyword, "doc.field", false, values);
Expression expIgnoreCase = createExpression(keyword, "doc.field", true, values);
assertEquals(expected, exp.toString());
assertEquals(expectedNum, expNum.toString());
assertEquals(expectedIgnoreCase, expIgnoreCase.toString());
}
@Test
public void testSIMPLE_PROPERTY() throws Exception {
Part.Type keyword = Part.Type.SIMPLE_PROPERTY;
Iterator<Object> values = Arrays.<Object>asList("a", 1, "b").iterator();
String expected = "doc.field = \"a\"";
String expectedNum = "doc.field = 1";
String expectedIgnoreCase = "LOWER(doc.field) = LOWER(\"b\")";
Expression exp = createExpression(keyword, "doc.field", false, values);
Expression expNum = createExpression(keyword, "doc.field", false, values);
Expression expIgnoreCase = createExpression(keyword, "doc.field", true, values);
assertEquals(expected, exp.toString());
assertEquals(expectedNum, expNum.toString());
assertEquals(expectedIgnoreCase, expIgnoreCase.toString());
}
}