You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by pp...@apache.org on 2022/08/15 17:47:27 UTC
[ignite-extensions] branch master updated: IGNITE-17051 Fixed execution of queries containing IN and NOT IN clauses (#170)
This is an automated email from the ASF dual-hosted git repository.
ppa pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ignite-extensions.git
The following commit(s) were added to refs/heads/master by this push:
new b2f0cda IGNITE-17051 Fixed execution of queries containing IN and NOT IN clauses (#170)
b2f0cda is described below
commit b2f0cda14695115f153b2a9fd9258ad6713f653b
Author: Mikhail Petrov <32...@users.noreply.github.com>
AuthorDate: Mon Aug 15 20:47:22 2022 +0300
IGNITE-17051 Fixed execution of queries containing IN and NOT IN clauses (#170)
---
.../springdata/repository/query/IgniteQuery.java | 31 +++-
.../repository/query/IgniteQueryGenerator.java | 21 ++-
.../repository/query/IgniteRepositoryQuery.java | 42 +++++-
.../springdata/repository/query/QueryUtils.java | 51 +++++++
.../springdata/repository/query/StringQuery.java | 59 +++++++-
.../support/IgniteRepositoryFactory.java | 12 +-
.../springdata/IgniteSpringDataCrudSelfTest.java | 166 +++++++++++++++++++++
.../ignite/springdata/misc/PersonRepository.java | 93 +++++++++++-
8 files changed, 458 insertions(+), 17 deletions(-)
diff --git a/modules/spring-data-ext/spring-data/src/main/java/org/apache/ignite/springdata/repository/query/IgniteQuery.java b/modules/spring-data-ext/spring-data/src/main/java/org/apache/ignite/springdata/repository/query/IgniteQuery.java
index 37bd3ce..978e1d7 100644
--- a/modules/spring-data-ext/spring-data/src/main/java/org/apache/ignite/springdata/repository/query/IgniteQuery.java
+++ b/modules/spring-data-ext/spring-data/src/main/java/org/apache/ignite/springdata/repository/query/IgniteQuery.java
@@ -58,27 +58,37 @@ public class IgniteQuery {
*/
private final boolean isAutogenerated;
+ /**
+ * Whether the query requires post-processing based on execution arguments.
+ */
+ private final boolean isParamDependent;
+
/**
* Type of option.
*/
private final Option option;
/**
- * @param qrySql the query string.
- * @param isFieldQuery Is field query.
- * @param isTextQuery Is a TextQuery
- * @param isAutogenerated query was autogenerated
- * @param option Option.
+ * @param qrySql the query string.
+ * @param isFieldQuery Is field query.
+ * @param isTextQuery Is a TextQuery
+ * @param isAutogenerated query was autogenerated
+ * @param isParamDependent Whether the query requires post-processing based on execution arguments.
+ * @param option Option.
*/
- public IgniteQuery(String qrySql,
+ public IgniteQuery(
+ String qrySql,
boolean isFieldQuery,
boolean isTextQuery,
boolean isAutogenerated,
- Option option) {
+ boolean isParamDependent,
+ Option option
+ ) {
this.qrySql = qrySql;
this.isFieldQuery = isFieldQuery;
this.isTextQuery = isTextQuery;
this.isAutogenerated = isAutogenerated;
+ this.isParamDependent = isParamDependent;
this.option = option;
}
@@ -127,6 +137,13 @@ public class IgniteQuery {
return option;
}
+ /**
+ * @return Whether the query requires post-processing based on execution arguments.
+ */
+ public boolean isParameterDependent() {
+ return isParamDependent;
+ }
+
/** */
@Override public String toString() {
return S.toString(IgniteQuery.class, this);
diff --git a/modules/spring-data-ext/spring-data/src/main/java/org/apache/ignite/springdata/repository/query/IgniteQueryGenerator.java b/modules/spring-data-ext/spring-data/src/main/java/org/apache/ignite/springdata/repository/query/IgniteQueryGenerator.java
index 6bf02bc..3bcfbb7 100644
--- a/modules/spring-data-ext/spring-data/src/main/java/org/apache/ignite/springdata/repository/query/IgniteQueryGenerator.java
+++ b/modules/spring-data-ext/spring-data/src/main/java/org/apache/ignite/springdata/repository/query/IgniteQueryGenerator.java
@@ -26,6 +26,9 @@ import org.springframework.data.repository.core.RepositoryMetadata;
import org.springframework.data.repository.query.parser.Part;
import org.springframework.data.repository.query.parser.PartTree;
+import static org.springframework.data.repository.query.parser.Part.Type.IN;
+import static org.springframework.data.repository.query.parser.Part.Type.NOT_IN;
+
/**
* Ignite query generator for Spring Data framework.
*/
@@ -100,7 +103,14 @@ public class IgniteQueryGenerator {
sql.append(parts.getMaxResults().intValue());
}
- return new IgniteQuery(sql.toString(), isCountOrFieldQuery, false, true, getOptions(mtd));
+ return new IgniteQuery(
+ sql.toString(),
+ isCountOrFieldQuery,
+ false,
+ true,
+ isParametersDependent(parts),
+ getOptions(mtd)
+ );
}
/**
@@ -273,4 +283,13 @@ public class IgniteQueryGenerator {
sql.append(")");
}
+
+ /**
+ * @param qryPartTree {@link PartTree} query representation.
+ * @return Whether the specified {@link PartTree} contains query part which string representation depends on
+ * query arguments.
+ */
+ private static boolean isParametersDependent(PartTree qryPartTree) {
+ return !qryPartTree.getParts(IN).isEmpty() || !qryPartTree.getParts(NOT_IN).isEmpty();
+ }
}
diff --git a/modules/spring-data-ext/spring-data/src/main/java/org/apache/ignite/springdata/repository/query/IgniteRepositoryQuery.java b/modules/spring-data-ext/spring-data/src/main/java/org/apache/ignite/springdata/repository/query/IgniteRepositoryQuery.java
index 069e1ec..02faf36 100644
--- a/modules/spring-data-ext/spring-data/src/main/java/org/apache/ignite/springdata/repository/query/IgniteRepositoryQuery.java
+++ b/modules/spring-data-ext/spring-data/src/main/java/org/apache/ignite/springdata/repository/query/IgniteRepositoryQuery.java
@@ -48,11 +48,13 @@ import org.apache.ignite.cache.query.SqlFieldsQuery;
import org.apache.ignite.cache.query.SqlQuery;
import org.apache.ignite.cache.query.TextQuery;
import org.apache.ignite.internal.util.GridUnsafe;
+import org.apache.ignite.internal.util.typedef.T2;
import org.apache.ignite.internal.util.typedef.internal.U;
import org.apache.ignite.springdata.proxy.IgniteCacheProxy;
import org.apache.ignite.springdata.proxy.IgniteClientCacheProxy;
import org.apache.ignite.springdata.repository.config.DynamicQueryConfig;
import org.apache.ignite.springdata.repository.query.StringQuery.ParameterBinding;
+import org.apache.ignite.springdata.repository.query.StringQuery.ParameterBindingParser;
import org.jetbrains.annotations.Nullable;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
@@ -479,9 +481,14 @@ public class IgniteRepositoryQuery implements RepositoryQuery {
return staticQuery;
if (cfg != null && (StringUtils.hasText(cfg.value()) || cfg.textQuery())) {
- return new IgniteQuery(cfg.value(),
- !cfg.textQuery() && (isFieldQuery(cfg.value()) || cfg.forceFieldsQuery()), cfg.textQuery(),
- false, IgniteQueryGenerator.getOptions(mtd));
+ return new IgniteQuery(
+ cfg.value(),
+ !cfg.textQuery() && (isFieldQuery(cfg.value()) || cfg.forceFieldsQuery()),
+ cfg.textQuery(),
+ false,
+ true,
+ IgniteQueryGenerator.getOptions(mtd)
+ );
}
throw new IllegalStateException("Unable to obtain a valid query. When passing dynamicQuery = true via org"
@@ -721,16 +728,22 @@ public class IgniteRepositoryQuery implements RepositoryQuery {
checkRequiredPageable(returnStgy, values);
if (!qry.isTextQuery()) {
+ boolean isParamDependent;
+
if (!qry.isAutogenerated()) {
StringQuery squery = new ExpressionBasedStringQuery(queryString, metadata, expressionParser);
queryString = squery.getQueryString();
parameters = extractBindableValues(parameters, getQueryMethod().getParameters(),
squery.getParameterBindings());
+
+ isParamDependent = isParameterDependent(squery);
}
else {
// remove dynamic projection from parameters
if (hasDynamicProjection)
parameters = ArrayUtils.remove(parameters, dynamicProjectionIndex);
+
+ isParamDependent = qry.isParameterDependent();
}
switch (qry.options()) {
@@ -751,6 +764,17 @@ public class IgniteRepositoryQuery implements RepositoryQuery {
default:
}
+ if (isParamDependent) {
+ T2<String, Object[]> parseRes = ParameterBindingParser.INSTANCE.processParameterDependentClauses(
+ queryString,
+ parameters
+ );
+
+ queryString = parseRes.get1();
+
+ parameters = parseRes.get2();
+ }
+
if (qry.isFieldQuery()) {
SqlFieldsQuery sqlFieldsQry = new SqlFieldsQuery(queryString);
sqlFieldsQry.setArgs(parameters);
@@ -970,4 +994,16 @@ public class IgniteRepositoryQuery implements RepositoryQuery {
return 0;
}
}
+
+ /**
+ * @return Whether specified query contains clauses which string representation depends on the query arguments.
+ */
+ private boolean isParameterDependent(StringQuery qry) {
+ for (ParameterBinding binding : qry.getParameterBindings()) {
+ if (binding instanceof StringQuery.InParameterBinding)
+ return true;
+ }
+
+ return false;
+ }
}
diff --git a/modules/spring-data-ext/spring-data/src/main/java/org/apache/ignite/springdata/repository/query/QueryUtils.java b/modules/spring-data-ext/spring-data/src/main/java/org/apache/ignite/springdata/repository/query/QueryUtils.java
index ba8c4aa..1457b5a 100644
--- a/modules/spring-data-ext/spring-data/src/main/java/org/apache/ignite/springdata/repository/query/QueryUtils.java
+++ b/modules/spring-data-ext/spring-data/src/main/java/org/apache/ignite/springdata/repository/query/QueryUtils.java
@@ -17,7 +17,13 @@
package org.apache.ignite.springdata.repository.query;
+import java.lang.reflect.Array;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
import java.util.HashSet;
+import java.util.List;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -306,4 +312,49 @@ public abstract class QueryUtils {
String projection = matcher.find() ? matcher.group(1) : "";
return projection.trim();
}
+
+ /**
+ * @param args Array of query arguments.
+ * @param argIdxs Indexes of the elements that should be expanded.
+ * @return Copy of the specified array with expanded elements that matches the specified indexes.
+ */
+ public static Object[] expandQueryArguments(Object[] args, List<Integer> argIdxs) {
+ Collections.sort(argIdxs);
+
+ List<Object> res = new ArrayList<>();
+
+ int prevIdx = 0;
+
+ for (Integer idx : argIdxs) {
+ copyTo(res, args, prevIdx, idx);
+
+ Object arg = args[idx];
+
+ if (arg.getClass().isArray()) {
+ for (int i = 0; i < Array.getLength(arg); i++)
+ res.add(Array.get(arg, i));
+ }
+ else if (arg instanceof Collection)
+ res.addAll((Collection<?>)arg);
+ else
+ res.add(arg);
+
+ prevIdx = idx + 1;
+ }
+
+ copyTo(res, args, prevIdx, args.length);
+
+ return res.toArray();
+ }
+
+ /**
+ * Copies elements of the specified array that lays in the specified bounds to the destination {@link List}.
+ * @param dest Destination.
+ * @param src Source.
+ * @param from Starting index (inclusively).
+ * @param to Finishing index (exclusively).
+ */
+ private static void copyTo(List<Object> dest, Object[] src, int from, int to) {
+ dest.addAll(Arrays.asList(src).subList(from, to));
+ }
}
diff --git a/modules/spring-data-ext/spring-data/src/main/java/org/apache/ignite/springdata/repository/query/StringQuery.java b/modules/spring-data-ext/spring-data/src/main/java/org/apache/ignite/springdata/repository/query/StringQuery.java
index b9f3aec..b83ad81 100644
--- a/modules/spring-data-ext/spring-data/src/main/java/org/apache/ignite/springdata/repository/query/StringQuery.java
+++ b/modules/spring-data-ext/spring-data/src/main/java/org/apache/ignite/springdata/repository/query/StringQuery.java
@@ -21,10 +21,13 @@ import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
+import java.util.Collections;
import java.util.List;
import java.util.function.BiFunction;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+import org.apache.ignite.internal.util.typedef.T2;
import org.jetbrains.annotations.Nullable;
import org.springframework.data.domain.Range;
import org.springframework.data.domain.Range.Bound;
@@ -282,8 +285,9 @@ class StringQuery implements DeclaredQuery {
usesJpaStyleParameters = true;
// named parameters (:param) will be untouched by spelExtractor, so replace them by ? as we don't
- // know position
- if (paramName != null)
+ // know position. We also replace the indexed parameters because query arguments will be rearranged to
+ // suite the proper order considering parameter indexes.
+ if (paramName != null || paramIdx != null)
replacement = "?";
if (usesJpaStyleParameters && queryMeta.usesJdbcStyleParameters) {
@@ -331,6 +335,57 @@ class StringQuery implements DeclaredQuery {
return resultingQry;
}
+ /**
+ * Post-process specified query clauses that depend on query arguments (e.g. '?' after IN and NOT IN clauses
+ * will be replaced with '(?, ? ...)' depending on the size of the collection corresponding to the initial query
+ * parameter.
+ *
+ * @param qry Query to parse.
+ * @param args Query arguments.
+ * @return Pair of values which represents parsed query and copy of query arguments updated to suite query
+ * parameters structure.
+ */
+ T2<String, Object[]> processParameterDependentClauses(String qry, Object[] args) {
+ Matcher matcher = PARAMETER_BINDING_PATTERN.matcher(qry);
+
+ StringBuffer parsedQry = new StringBuffer();
+
+ int argIdx = 0;
+
+ List<Integer> argIdxs = new ArrayList<>();
+
+ while (matcher.find()) {
+ String typeSrc = matcher.group(COMPARISION_TYPE_GROUP);
+
+ if (ParameterBindingType.of(typeSrc) == ParameterBindingType.IN) {
+ Object arg = args[argIdx];
+
+ int length;
+
+ if (arg.getClass().isArray())
+ length = Array.getLength(arg);
+ else if (arg instanceof Collection)
+ length = ((Collection<?>)arg).size();
+ else
+ length = 1;
+
+ String replacement = Collections.nCopies(length, "?")
+ .stream()
+ .collect(Collectors.joining(", ", "(", ")"));
+
+ matcher.appendReplacement(parsedQry, matcher.group(0).replaceFirst(Pattern.quote(matcher.group(2)), replacement));
+
+ argIdxs.add(argIdx);
+ }
+
+ ++argIdx;
+ }
+
+ matcher.appendTail(parsedQry);
+
+ return new T2<>(parsedQry.toString(), QueryUtils.expandQueryArguments(args, argIdxs));
+ }
+
/** */
private static SpelExtractor createSpelExtractor(String queryWithSpel,
boolean parametersShouldBeAccessedByIndex,
diff --git a/modules/spring-data-ext/spring-data/src/main/java/org/apache/ignite/springdata/repository/support/IgniteRepositoryFactory.java b/modules/spring-data-ext/spring-data/src/main/java/org/apache/ignite/springdata/repository/support/IgniteRepositoryFactory.java
index 6673560..7af32b9 100644
--- a/modules/spring-data-ext/spring-data/src/main/java/org/apache/ignite/springdata/repository/support/IgniteRepositoryFactory.java
+++ b/modules/spring-data-ext/spring-data/src/main/java/org/apache/ignite/springdata/repository/support/IgniteRepositoryFactory.java
@@ -139,9 +139,15 @@ public class IgniteRepositoryFactory extends RepositoryFactorySupport {
boolean annotatedIgniteQuery = !annotation.dynamicQuery() && (StringUtils.hasText(qryStr) || annotation
.textQuery());
- IgniteQuery query = annotatedIgniteQuery ? new IgniteQuery(qryStr,
- !annotation.textQuery() && (isFieldQuery(qryStr) || annotation.forceFieldsQuery()),
- annotation.textQuery(), false, IgniteQueryGenerator.getOptions(mtd)) : null;
+ IgniteQuery query = annotatedIgniteQuery
+ ? new IgniteQuery(
+ qryStr,
+ !annotation.textQuery() && (isFieldQuery(qryStr) || annotation.forceFieldsQuery()),
+ annotation.textQuery(),
+ false,
+ true,
+ IgniteQueryGenerator.getOptions(mtd))
+ : null;
if (key != QueryLookupStrategy.Key.CREATE) {
return new IgniteRepositoryQuery(metadata, query, mtd, factory, cache,
diff --git a/modules/spring-data-ext/spring-data/src/test/java/org/apache/ignite/springdata/IgniteSpringDataCrudSelfTest.java b/modules/spring-data-ext/spring-data/src/test/java/org/apache/ignite/springdata/IgniteSpringDataCrudSelfTest.java
index e317b7a..d21f878 100644
--- a/modules/spring-data-ext/spring-data/src/test/java/org/apache/ignite/springdata/IgniteSpringDataCrudSelfTest.java
+++ b/modules/spring-data-ext/spring-data/src/test/java/org/apache/ignite/springdata/IgniteSpringDataCrudSelfTest.java
@@ -18,6 +18,7 @@
package org.apache.ignite.springdata;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
@@ -31,6 +32,8 @@ import org.apache.ignite.springdata.misc.PersonRepository;
import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.data.domain.Sort;
/**
* CRUD tests.
@@ -445,4 +448,167 @@ public class IgniteSpringDataCrudSelfTest extends GridCommonAbstractTest {
List<Person> person = repo.findByFirstName("uniquePerson");
assertEquals(person.get(0).getSecondName(), "uniqueLastName");
}
+
+ /** */
+ @Test
+ public void testMethodBasedQueryWithInClauseAndListArgument() {
+ assertEquals(5, repo.findBySecondNameIn(Arrays.asList("uniqueLastName", "nonUniqueLastName")).size());
+ }
+
+ /** */
+ @Test
+ public void testMethodBasedQueryWithNotInClauseAndListArgument() {
+ assertEquals(CACHE_SIZE - 5, repo.findBySecondNameNotIn(Arrays.asList("uniqueLastName", "nonUniqueLastName")).size());
+ }
+
+ /** */
+ @Test
+ public void testMethodBasedQueryWithInClauseAndListArgumentWithSorting() {
+ assertEquals(
+ 5,
+ repo.findBySecondNameIn(
+ Arrays.asList("uniqueLastName", "nonUniqueLastName"),
+ Sort.by(Sort.Direction.DESC, "secondName")
+ ).size());
+ }
+
+ /** */
+ @Test
+ public void testMethodBasedQueryWithInClauseAndListArgumentWithPaging() {
+ assertEquals(
+ 5,
+ repo.findBySecondNameIn(
+ Arrays.asList("uniqueLastName", "nonUniqueLastName"),
+ PageRequest.of(0, 10)
+ ).getTotalElements()
+ );
+ }
+
+ /** */
+ @Test
+ public void testMethodBasedQueryWithInClauseAndListArgumentWithProjection() {
+ assertEquals(5, repo.findBySecondNameIn(PersonProjection.class, Arrays.asList("uniqueLastName", "nonUniqueLastName")).size());
+ }
+
+ /** */
+ @Test
+ public void testMethodBasedQueryWithInClauseAndArrayArgument() {
+ assertEquals(5, repo.findBySecondNameIn(new String[] {"uniqueLastName", "nonUniqueLastName"}).size());
+ }
+
+ /** */
+ @Test
+ public void testMethodBasedQueryWithInClauseAndSingleValueArgument() {
+ assertEquals(4, repo.findBySecondNameIn("nonUniqueLastName").size());
+ }
+
+ /** */
+ @Test
+ public void testMethodBasedQueryWithInClauseAlongsideEqualClause() {
+ assertEquals(
+ 4,
+ repo.findByFirstNameIsAndSecondNameIn(
+ "nonUniquePerson",
+ Arrays.asList("uniqueLastName", "nonUniqueLastName")
+ ).size()
+ );
+ }
+
+ /** */
+ @Test
+ public void testMethodBasedQueryWithMultipleInClauses() {
+ assertEquals(
+ 5,
+ repo.findBySecondNameInAndFirstNameIn(
+ Arrays.asList("uniqueLastName", "nonUniqueLastName"),
+ Arrays.asList("uniquePerson", "nonUniquePerson")
+ ).size()
+ );
+ }
+
+ /** */
+ @Test
+ public void testExplicitQueryWithInClauseAndListArgument() {
+ assertEquals(5, repo.selectInList(Arrays.asList("uniqueLastName", "nonUniqueLastName")).size());
+ }
+
+ /** */
+ @Test
+ public void testExplicitQueryWithNotInClauseAndListArgument() {
+ assertEquals(CACHE_SIZE - 5, repo.selectNotInList(Arrays.asList("uniqueLastName", "nonUniqueLastName")).size());
+ }
+
+ /** */
+ @Test
+ public void testExplicitQueryWithInClauseAndNamedListArgument() {
+ assertEquals(5, repo.selectInListWithNamedParameter(Arrays.asList("uniqueLastName", "nonUniqueLastName")).size());
+ }
+
+ /** */
+ @Test
+ public void testExplicitQueryWithInClauseAndNamedArrayArgument() {
+ assertEquals(5, repo.selectInArrayWithNamedParameter(new String[] {"uniqueLastName", "nonUniqueLastName"}).size());
+ }
+
+ /** */
+ @Test
+ public void testExplicitQueryWithInClauseAndNamedSingleValueArgument() {
+ assertEquals(1, repo.selectInSingleValueWithNamedParameter("uniqueLastName").size());
+ }
+
+ /** */
+ @Test
+ public void testExplicitQueryWithMultipleInClauses() {
+ assertEquals(
+ 5,
+ repo.selectWithMultipleInClauses(
+ Arrays.asList("uniqueLastName", "nonUniqueLastName"),
+ Arrays.asList("uniquePerson", "nonUniquePerson")
+ ).size()
+ );
+ }
+
+ /** */
+ @Test
+ public void testExplicitQueryWithInClauseAlongsideEqualClause() {
+ assertEquals(4, repo.selectWithInAndEqualClauses("nonUniquePerson", Arrays.asList("uniqueLastName", "nonUniqueLastName")).size());
+ }
+
+ /** */
+ @Test
+ public void testExplicitQueryWithInClauseAlongsideEqualClauseAndNamedArguments() {
+ assertEquals(
+ 4,
+ repo.selectWithInAndEqualClausesAndNamedArguments(
+ Arrays.asList("uniqueLastName", "nonUniqueLastName"), "nonUniquePerson").size());
+ }
+
+ /** */
+ @Test
+ public void testExplicitQueryWithInClauseAndSpellArgument() {
+ assertEquals(4, repo.selectInWithSpellClause(new Person("", "nonUniqueLastName"), "nonUniquePerson").size());
+ }
+
+ /** */
+ @Test
+ public void testExplicitQueryWithInClauseAndIndexedListArguments() {
+ assertEquals(4,
+ repo.selectInListWithMultipleIndexedParameter(
+ 0,
+ "nonUniquePerson",
+ Arrays.asList("uniqueLastName", "nonUniqueLastName")
+ ).size());
+ }
+
+ /** */
+ @Test
+ public void testExplicitQueryWithInClauseAndIndexedArrayArguments() {
+ assertEquals(5, repo.selectInArrayWithIndexedParameter(0, new String[] {"uniqueLastName", "nonUniqueLastName"}).size());
+ }
+
+ /** */
+ @Test
+ public void testExplicitQueryWithInClauseAndIndexedSingleValueArguments() {
+ assertEquals(1, repo.selectInSingleValueWithIndexedParameter(0, "uniqueLastName").size());
+ }
}
diff --git a/modules/spring-data-ext/spring-data/src/test/java/org/apache/ignite/springdata/misc/PersonRepository.java b/modules/spring-data-ext/spring-data/src/test/java/org/apache/ignite/springdata/misc/PersonRepository.java
index d68b9c9..cb2cece 100644
--- a/modules/spring-data-ext/spring-data/src/test/java/org/apache/ignite/springdata/misc/PersonRepository.java
+++ b/modules/spring-data-ext/spring-data/src/test/java/org/apache/ignite/springdata/misc/PersonRepository.java
@@ -20,11 +20,11 @@ package org.apache.ignite.springdata.misc;
import java.util.Collection;
import java.util.List;
-
import javax.cache.Cache;
import org.apache.ignite.springdata.repository.IgniteRepository;
import org.apache.ignite.springdata.repository.config.Query;
import org.apache.ignite.springdata.repository.config.RepositoryConfig;
+import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.repository.query.Param;
@@ -160,4 +160,95 @@ public interface PersonRepository extends IgniteRepository<Person, Integer> {
/** Produces a list of domain entity classes whose fields are obtained from the query result row. */
@Query(value = "SELECT firstName, birthday FROM Person", forceFieldsQuery = true)
public List<Person> queryWithIncompleteRowToEntityConversion();
+
+ /** */
+ public List<Cache.Entry<Integer, Person>> findBySecondNameIn(List<String> secondNames);
+
+ /** */
+ public List<Cache.Entry<Integer, Person>> findBySecondNameNotIn(List<String> secondNames);
+
+ /** */
+ public List<Cache.Entry<Integer, Person>> findBySecondNameIn(List<String> secondNames, Sort sort);
+
+ /** */
+ public <P> List<P> findBySecondNameIn(Class<P> dynamicProjection, List<String> secondNames);
+
+ /** */
+ public Page<Person> findBySecondNameIn(List<String> secondNames, Pageable pageable);
+
+ /** */
+ public List<Cache.Entry<Integer, Person>> findBySecondNameIn(String[] secondNames);
+
+ /** */
+ public List<Cache.Entry<Integer, Person>> findBySecondNameIn(String secondNames);
+
+ /** */
+ public List<Cache.Entry<Integer, Person>> findBySecondNameInAndFirstNameIn(List<String> secondNames, List<String> firstNames);
+
+ /** */
+ public List<Cache.Entry<Integer, Person>> findByFirstNameIsAndSecondNameIn(String firstNames, List<String> secondNames);
+
+ /** */
+ @Query(value = "SELECT * FROM Person WHERE secondName IN ?")
+ public List<Cache.Entry<Integer, Person>> selectInList(List<String> secondNames);
+
+ /** */
+ @Query(value = "SELECT * FROM Person WHERE secondName NOT IN ?")
+ public List<Cache.Entry<Integer, Person>> selectNotInList(List<String> secondNames);
+
+ /** */
+ @Query(value = "SELECT * FROM Person WHERE secondName IN :secondNames")
+ public List<Cache.Entry<Integer, Person>> selectInListWithNamedParameter(@Param("secondNames") List<String> secondNames);
+
+ /** */
+ @Query(value = "SELECT * FROM Person WHERE secondName IN :secondNames")
+ public List<Cache.Entry<Integer, Person>> selectInArrayWithNamedParameter(@Param("secondNames") String[] secondNames);
+
+ /** */
+ @Query(value = "SELECT * FROM Person WHERE secondName IN :secondNames")
+ public List<Cache.Entry<Integer, Person>> selectInSingleValueWithNamedParameter(@Param("secondNames") String secondNames);
+
+ /** */
+ @Query(value = "SELECT * FROM Person WHERE firstName IN :firstNames AND secondName IN :secondNames")
+ public List<Cache.Entry<Integer, Person>> selectWithMultipleInClauses(
+ @Param("secondNames") List<String> secondNames,
+ @Param("firstNames") List<String> firstNames
+ );
+
+ /** */
+ @Query(value = "SELECT * FROM Person WHERE firstName = ? AND secondName IN ?")
+ public List<Cache.Entry<Integer, Person>> selectWithInAndEqualClauses(
+ String firstName,
+ List<String> secondNames
+ );
+
+ /** */
+ @Query(value = "SELECT * FROM Person WHERE firstName = :name AND secondName IN :secondNames")
+ public List<Cache.Entry<Integer, Person>> selectWithInAndEqualClausesAndNamedArguments(
+ @Param("secondNames") List<String> secondNames,
+ @Param("name") String firstName
+ );
+
+ /** */
+ @Query(value = "SELECT * FROM Person WHERE firstName = :name AND secondName IN :#{#person.secondName}")
+ public List<Cache.Entry<Integer, Person>> selectInWithSpellClause(
+ @Param("person") Person person,
+ @Param("name") String firstName
+ );
+
+ /** */
+ @Query(value = "SELECT * FROM Person WHERE secondName IN ?3 AND firstName=?2")
+ public List<Cache.Entry<Integer, Person>> selectInListWithMultipleIndexedParameter(
+ int dummyArg,
+ String firstName,
+ List<String> secondNames
+ );
+
+ /** */
+ @Query(value = "SELECT * FROM Person WHERE secondName IN ?2")
+ public List<Cache.Entry<Integer, Person>> selectInArrayWithIndexedParameter(int dummyArg, String[] secondNames);
+
+ /** */
+ @Query(value = "SELECT * FROM Person WHERE secondName IN ?2")
+ public List<Cache.Entry<Integer, Person>> selectInSingleValueWithIndexedParameter(int dummyArg, String secondNames);
}