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:
@@ -19,7 +19,18 @@ package org.springframework.data.couchbase.core.query;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.springframework.data.couchbase.core.query.QueryCriteria.*;
|
||||
|
||||
import com.couchbase.client.java.json.JsonArray;
|
||||
import com.couchbase.client.java.json.JsonObject;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.data.couchbase.domain.User;
|
||||
import org.springframework.data.couchbase.domain.UserRepository;
|
||||
import org.springframework.data.couchbase.repository.query.N1qlQueryCreator;
|
||||
import org.springframework.data.repository.query.parser.PartTree;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
class QueryCriteriaTests {
|
||||
|
||||
@@ -56,21 +67,25 @@ class QueryCriteriaTests {
|
||||
@Test
|
||||
void testNestedAndCriteria() {
|
||||
QueryCriteria c = where("name").is("Bubba").and(where("age").gt(12).or("country").is("Austria"));
|
||||
assertEquals("`name` = \"Bubba\" and (`age` > 12 or `country` = \"Austria\")", c.export());
|
||||
JsonArray parameters = JsonArray.create();
|
||||
assertEquals("`name` = $1 and (`age` > $2 or `country` = $3)", c.export(new int[1], parameters, null));
|
||||
assertEquals("[\"Bubba\",12,\"Austria\"]", parameters.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testNestedOrCriteria() {
|
||||
QueryCriteria c = where("name").is("Bubba").or(where("age").gt(12).or("country").is("Austria"));
|
||||
assertEquals("`name` = \"Bubba\" or (`age` > 12 or `country` = \"Austria\")", c.export());
|
||||
JsonArray parameters = JsonArray.create();
|
||||
assertEquals("`name` = $1 or (`age` > $2 or `country` = $3)", c.export(new int[1], parameters, null));
|
||||
assertEquals("[\"Bubba\",12,\"Austria\"]", parameters.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testNestedNotIn() {
|
||||
QueryCriteria c = where("name").is("Bubba").or(where("age").gt(12).or("country").is("Austria")).and(
|
||||
where("state").notIn(new String[] { "Alabama", "Florida" }));
|
||||
QueryCriteria c = where("name").is("Bubba").or(where("age").gt(12).or("country").is("Austria"))
|
||||
.and(where("state").notIn(new String[] { "Alabama", "Florida" }));
|
||||
assertEquals("`name` = \"Bubba\" or (`age` > 12 or `country` = \"Austria\") and "
|
||||
+ "(not( (`state` in ( [ \"Alabama\", \"Florida\" ] )) ))", c.export());
|
||||
+ "(not( (`state` in ( [\"Alabama\",\"Florida\"] )) ))", c.export());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -110,13 +125,13 @@ class QueryCriteriaTests {
|
||||
}
|
||||
|
||||
/* cannot do this properly yet because in arg to when() in
|
||||
* startingWith() cannot be a QueryCriteria
|
||||
* startingWith() cannot be a QueryCriteria
|
||||
@Test
|
||||
void testStartingWithExpr() {
|
||||
QueryCriteria c = where("name").startingWith(where("name").plus("xxx"));
|
||||
assertEquals("`name` like (((`name` || "xxx") || ""%""))", c.export());
|
||||
}
|
||||
*/
|
||||
*/
|
||||
|
||||
@Test
|
||||
void testEndingWith() {
|
||||
@@ -204,14 +219,22 @@ class QueryCriteriaTests {
|
||||
|
||||
@Test
|
||||
void testIn() {
|
||||
QueryCriteria c = where("name").in(new String[] { "gump", "davis" });
|
||||
assertEquals("`name` in ( [ \"gump\", \"davis\" ] )", c.export());
|
||||
String[] args = new String[] { "gump", "davis" };
|
||||
QueryCriteria c = where("name").in(args);
|
||||
assertEquals("`name` in ( [\"gump\",\"davis\"] )", c.export());
|
||||
JsonArray parameters = JsonArray.create();
|
||||
assertEquals("`name` in ( $1 )", c.export(new int[1], parameters, null));
|
||||
assertEquals(arrayToString(args), parameters.get(0).toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testNotIn() {
|
||||
QueryCriteria c = where("name").notIn(new String[] { "gump", "davis" });
|
||||
assertEquals("not( (`name` in ( [ \"gump\", \"davis\" ] )) )", c.export());
|
||||
String[] args = new String[] { "gump", "davis" };
|
||||
QueryCriteria c = where("name").notIn(args);
|
||||
assertEquals("not( (`name` in ( [\"gump\",\"davis\"] )) )", c.export());
|
||||
JsonArray parameters = JsonArray.create();
|
||||
assertEquals("not( (`name` in ( $1 )) )", c.export(new int[1], parameters, null));
|
||||
assertEquals(arrayToString(args), parameters.get(0).toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -225,4 +248,28 @@ class QueryCriteriaTests {
|
||||
QueryCriteria c = where("name").FALSE();
|
||||
assertEquals("not( (`name`) )", c.export());
|
||||
}
|
||||
|
||||
private String arrayToString(Object[] array) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if (array != null) {
|
||||
sb.append("[");
|
||||
boolean first = true;
|
||||
for (Object e : array) {
|
||||
if (!first) {
|
||||
sb.append(",");
|
||||
}
|
||||
first = false;
|
||||
if (e instanceof Number)
|
||||
sb.append(e);
|
||||
else {
|
||||
sb.append("\"");
|
||||
sb.append(e);
|
||||
sb.append("\"");
|
||||
}
|
||||
}
|
||||
sb.append("]");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ package org.springframework.data.couchbase.domain;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.couchbase.client.java.json.JsonArray;
|
||||
import org.springframework.data.couchbase.repository.Query;
|
||||
import org.springframework.data.repository.PagingAndSortingRepository;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
@@ -34,6 +35,10 @@ public interface UserRepository extends PagingAndSortingRepository<User, String>
|
||||
|
||||
List<User> findByFirstname(String firstname);
|
||||
|
||||
List<User> findByFirstnameIn(String... firstnames);
|
||||
|
||||
List<User> findByFirstnameIn(JsonArray firstnames);
|
||||
|
||||
List<User> findByFirstnameAndLastname(String firstname, String lastname);
|
||||
|
||||
@Query("#{#n1ql.selectEntity} where #{#n1ql.filter} and firstname = $1 and lastname = $2")
|
||||
|
||||
@@ -19,7 +19,13 @@ import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.springframework.data.couchbase.core.query.QueryCriteria.*;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import com.couchbase.client.java.json.JsonArray;
|
||||
import com.couchbase.client.java.json.JsonObject;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.data.couchbase.core.convert.CouchbaseConverter;
|
||||
@@ -62,6 +68,69 @@ class N1qlQueryCreatorTests {
|
||||
assertEquals(query.export(), " WHERE " + where("firstname").is("Oliver").export());
|
||||
}
|
||||
|
||||
@Test
|
||||
void queryParametersArray() throws Exception {
|
||||
String input = "findByFirstnameIn";
|
||||
PartTree tree = new PartTree(input, User.class);
|
||||
Method method = UserRepository.class.getMethod(input, String[].class);
|
||||
Query expected = (new Query()).addCriteria(where("firstname").in("Oliver", "Charles"));
|
||||
N1qlQueryCreator creator = new N1qlQueryCreator(tree,
|
||||
getAccessor(getParameters(method), new Object[] { new Object[] { "Oliver", "Charles" } }), null, converter);
|
||||
Query query = creator.createQuery();
|
||||
|
||||
// Query expected = (new Query()).addCriteria(where("firstname").in("Oliver", "Charles"));
|
||||
assertEquals(expected.export(new int[1]), query.export(new int[1]));
|
||||
JsonObject expectedOptions = JsonObject.create();
|
||||
expected.buildQueryOptions(null).build().injectParams(expectedOptions);
|
||||
JsonObject actualOptions = JsonObject.create();
|
||||
expected.buildQueryOptions(null).build().injectParams(actualOptions);
|
||||
assertEquals(expectedOptions.removeKey("client_context_id"), actualOptions.removeKey("client_context_id"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void queryParametersJsonArray() throws Exception {
|
||||
String input = "findByFirstnameIn";
|
||||
PartTree tree = new PartTree(input, User.class);
|
||||
Method method = UserRepository.class.getMethod(input, JsonArray.class);
|
||||
|
||||
JsonArray jsonArray = JsonArray.create();
|
||||
jsonArray.add("Oliver");
|
||||
jsonArray.add("Charles");
|
||||
N1qlQueryCreator creator = new N1qlQueryCreator(tree, getAccessor(getParameters(method), jsonArray), null,
|
||||
converter);
|
||||
Query query = creator.createQuery();
|
||||
|
||||
Query expected = (new Query()).addCriteria(where("firstname").in("Oliver", "Charles"));
|
||||
assertEquals(expected.export(new int[1]), query.export(new int[1]));
|
||||
JsonObject expectedOptions = JsonObject.create();
|
||||
expected.buildQueryOptions(null).build().injectParams(expectedOptions);
|
||||
JsonObject actualOptions = JsonObject.create();
|
||||
expected.buildQueryOptions(null).build().injectParams(actualOptions);
|
||||
assertEquals(expectedOptions.removeKey("client_context_id"), actualOptions.removeKey("client_context_id"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void queryParametersList() throws Exception {
|
||||
String input = "findByFirstnameIn";
|
||||
PartTree tree = new PartTree(input, User.class);
|
||||
Method method = UserRepository.class.getMethod(input, String[].class);
|
||||
List<String> list = new LinkedList<>();
|
||||
list.add("Oliver");
|
||||
list.add("Charles");
|
||||
N1qlQueryCreator creator = new N1qlQueryCreator(tree, getAccessor(getParameters(method), new Object[] { list }),
|
||||
null, converter);
|
||||
Query query = creator.createQuery();
|
||||
|
||||
Query expected = (new Query()).addCriteria(where("firstname").in("Oliver", "Charles"));
|
||||
|
||||
assertEquals(expected.export(new int[1]), query.export(new int[1]));
|
||||
JsonObject expectedOptions = JsonObject.create();
|
||||
expected.buildQueryOptions(null).build().injectParams(expectedOptions);
|
||||
JsonObject actualOptions = JsonObject.create();
|
||||
expected.buildQueryOptions(null).build().injectParams(actualOptions);
|
||||
assertEquals(expectedOptions.removeKey("client_context_id"), actualOptions.removeKey("client_context_id"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void createsAndQueryCorrectly() throws Exception {
|
||||
String input = "findByFirstnameAndLastname";
|
||||
@@ -71,7 +140,7 @@ class N1qlQueryCreatorTests {
|
||||
converter);
|
||||
Query query = creator.createQuery();
|
||||
|
||||
assertEquals(query.export(), " WHERE " + where("firstname").is("John").and("lastname").is("Doe").export());
|
||||
assertEquals(" WHERE " + where("firstname").is("John").and("lastname").is("Doe").export(), query.export());
|
||||
}
|
||||
|
||||
private ParameterAccessor getAccessor(Parameters<?, ?> params, Object... values) {
|
||||
|
||||
Reference in New Issue
Block a user