diff --git a/src/main/antora/modules/ROOT/pages/repositories.adoc b/src/main/antora/modules/ROOT/pages/repositories.adoc index 46566e7..fd1e757 100644 --- a/src/main/antora/modules/ROOT/pages/repositories.adoc +++ b/src/main/antora/modules/ROOT/pages/repositories.adoc @@ -5,4 +5,3 @@ This chapter explains the basic foundations of Spring Data repositories and KeyV Before continuing to the specifics, make sure you have a sound understanding of the basic concepts. The goal of the Spring Data repository abstraction is to significantly reduce the amount of boilerplate code required to implement data access layers for various persistence stores. - diff --git a/src/main/java/org/springframework/data/keyvalue/repository/query/PredicateQueryCreator.java b/src/main/java/org/springframework/data/keyvalue/repository/query/PredicateQueryCreator.java index 81f3ef9..e486bfd 100644 --- a/src/main/java/org/springframework/data/keyvalue/repository/query/PredicateQueryCreator.java +++ b/src/main/java/org/springframework/data/keyvalue/repository/query/PredicateQueryCreator.java @@ -42,6 +42,7 @@ import org.springframework.util.ObjectUtils; * * @author Christoph Strobl * @author Tom Van Wemmel + * @author Mark Paluch * @since 3.3 */ public class PredicateQueryCreator extends AbstractQueryCreator>, Predicate> { @@ -55,68 +56,47 @@ public class PredicateQueryCreator extends AbstractQueryCreator create(Part part, Iterator iterator) { - switch (part.getType()) { - case TRUE: - return PredicateBuilder.propertyValueOf(part).isTrue(); - case FALSE: - return PredicateBuilder.propertyValueOf(part).isFalse(); - case SIMPLE_PROPERTY: - return PredicateBuilder.propertyValueOf(part).isEqualTo(iterator.next()); - case NEGATING_SIMPLE_PROPERTY: - return PredicateBuilder.propertyValueOf(part).isEqualTo(iterator.next()).negate(); - case IS_NULL: - return PredicateBuilder.propertyValueOf(part).isNull(); - case IS_NOT_NULL: - return PredicateBuilder.propertyValueOf(part).isNotNull(); - case LIKE: - return PredicateBuilder.propertyValueOf(part).contains(iterator.next()); - case NOT_LIKE: - return PredicateBuilder.propertyValueOf(part).contains(iterator.next()).negate(); - case STARTING_WITH: - return PredicateBuilder.propertyValueOf(part).startsWith(iterator.next()); - case AFTER: - case GREATER_THAN: - return PredicateBuilder.propertyValueOf(part).isGreaterThan(iterator.next()); - case GREATER_THAN_EQUAL: - return PredicateBuilder.propertyValueOf(part).isGreaterThanEqual(iterator.next()); - case BEFORE: - case LESS_THAN: - return PredicateBuilder.propertyValueOf(part).isLessThan(iterator.next()); - case LESS_THAN_EQUAL: - return PredicateBuilder.propertyValueOf(part).isLessThanEqual(iterator.next()); - case ENDING_WITH: - return PredicateBuilder.propertyValueOf(part).endsWith(iterator.next()); - case BETWEEN: - return PredicateBuilder.propertyValueOf(part).isGreaterThan(iterator.next()) - .and(PredicateBuilder.propertyValueOf(part).isLessThan(iterator.next())); - case REGEX: - return PredicateBuilder.propertyValueOf(part).matches(iterator.next()); - case IN: - return PredicateBuilder.propertyValueOf(part).in(iterator.next()); - case NOT_IN: - return PredicateBuilder.propertyValueOf(part).in(iterator.next()).negate(); - default: - throw new InvalidDataAccessApiUsageException(String.format("Found invalid part '%s' in query", part.getType())); + PredicateBuilder builder = PredicateBuilder.propertyValueOf(part); - } + return switch (part.getType()) { + case TRUE -> builder.isTrue(); + case FALSE -> builder.isFalse(); + case SIMPLE_PROPERTY -> builder.isEqualTo(iterator.next()); + case NEGATING_SIMPLE_PROPERTY -> builder.isEqualTo(iterator.next()).negate(); + case IS_NULL -> builder.isNull(); + case IS_NOT_NULL -> builder.isNotNull(); + case LIKE -> builder.contains(iterator.next()); + case NOT_LIKE -> builder.contains(iterator.next()).negate(); + case STARTING_WITH -> builder.startsWith(iterator.next()); + case AFTER, GREATER_THAN -> builder.isGreaterThan(iterator.next()); + case GREATER_THAN_EQUAL -> builder.isGreaterThanEqual(iterator.next()); + case BEFORE, LESS_THAN -> builder.isLessThan(iterator.next()); + case LESS_THAN_EQUAL -> builder.isLessThanEqual(iterator.next()); + case ENDING_WITH -> builder.endsWith(iterator.next()); + case BETWEEN -> builder.isGreaterThan(iterator.next()).and(builder.isLessThan(iterator.next())); + case REGEX -> builder.matches(iterator.next()); + case IN -> builder.in(iterator.next()); + case NOT_IN -> builder.in(iterator.next()).negate(); + default -> + throw new InvalidDataAccessApiUsageException(String.format("Found invalid part '%s' in query", part.getType())); + }; } @Override + @SuppressWarnings({ "unchecked", "rawtypes" }) protected Predicate and(Part part, Predicate base, Iterator iterator) { return base.and((Predicate) create(part, iterator)); } @Override + @SuppressWarnings({ "unchecked", "rawtypes" }) protected Predicate or(Predicate base, Predicate criteria) { return base.or((Predicate) criteria); } @Override protected KeyValueQuery> complete(@Nullable Predicate criteria, Sort sort) { - if (criteria == null) { - return new KeyValueQuery<>(it -> true, sort); - } - return new KeyValueQuery<>(criteria, sort); + return criteria == null ? new KeyValueQuery<>(it -> true, sort) : new KeyValueQuery<>(criteria, sort); } static class PredicateBuilder { @@ -127,6 +107,7 @@ public class PredicateQueryCreator extends AbstractQueryCreator Comparator comparator() { return (Comparator) COMPARATOR; } @@ -165,19 +146,19 @@ public class PredicateQueryCreator extends AbstractQueryCreator isLessThan(Object value) { - return new ValueComparingPredicate(part.getProperty(), o -> comparator().compare(o, value) == -1 ? true : false); + return new ValueComparingPredicate(part.getProperty(), o -> comparator().compare(o, value) < 0); } public Predicate isLessThanEqual(Object value) { - return new ValueComparingPredicate(part.getProperty(), o -> comparator().compare(o, value) <= 0 ? true : false); + return new ValueComparingPredicate(part.getProperty(), o -> comparator().compare(o, value) <= 0); } public Predicate isGreaterThan(Object value) { - return new ValueComparingPredicate(part.getProperty(), o -> comparator().compare(o, value) == 1 ? true : false); + return new ValueComparingPredicate(part.getProperty(), o -> comparator().compare(o, value) > 0); } public Predicate isGreaterThanEqual(Object value) { - return new ValueComparingPredicate(part.getProperty(), o -> comparator().compare(o, value) >= 0 ? true : false); + return new ValueComparingPredicate(part.getProperty(), o -> comparator().compare(o, value) >= 0); } public Predicate matches(Pattern pattern) { @@ -217,8 +198,9 @@ public class PredicateQueryCreator extends AbstractQueryCreator collection) { if (o instanceof Collection subSet) { - collection.containsAll(subSet); + return collection.containsAll(subSet); } + return collection.contains(o); } if (ObjectUtils.isArray(value)) { @@ -246,7 +228,7 @@ public class PredicateQueryCreator extends AbstractQueryCreator map) { - return map.values().contains(value); + return map.containsValue(value); } if (value == null) { diff --git a/src/main/java/org/springframework/data/keyvalue/repository/query/SpelQueryCreator.java b/src/main/java/org/springframework/data/keyvalue/repository/query/SpelQueryCreator.java index f481ba6..4e1158b 100644 --- a/src/main/java/org/springframework/data/keyvalue/repository/query/SpelQueryCreator.java +++ b/src/main/java/org/springframework/data/keyvalue/repository/query/SpelQueryCreator.java @@ -119,10 +119,14 @@ public class SpelQueryCreator extends AbstractQueryCreator list = new ArrayList<>(); + List list = new ArrayList<>(); list.add(ROBB.firstname); assertThat(evaluate("findByFirstnameIn", list).against(ROBB)).isTrue(); @@ -295,7 +295,7 @@ public abstract class AbstractQueryCreatorTestBase list = new ArrayList<>(); + List list = new ArrayList<>(); list.add(ROBB.firstname); assertThat(evaluate("findByFirstnameIn", list).against(JON)).isFalse(); @@ -304,7 +304,7 @@ public abstract class AbstractQueryCreatorTestBase list = new ArrayList<>(); + List list = new ArrayList<>(); list.add(null); assertThat(evaluate("findByFirstnameIn", list).against(JON)).isFalse(); @@ -313,7 +313,7 @@ public abstract class AbstractQueryCreatorTestBase list = new ArrayList<>(); + List list = new ArrayList<>(); list.add(ROBB.firstname); assertThat(evaluate("findByFirstnameIn", list).against(new PredicateQueryCreatorUnitTests.Person(null, 10))) @@ -323,7 +323,7 @@ public abstract class AbstractQueryCreatorTestBase list = new ArrayList<>(); + List list = new ArrayList<>(); list.add(null); boolean contains = list.contains(null); @@ -335,7 +335,7 @@ public abstract class AbstractQueryCreatorTestBase list = new ArrayList<>(); + List list = new ArrayList<>(); list.add(ROBB.firstname); assertThat(evaluate("findByFirstnameNotIn", list).against(JON)).isTrue(); @@ -344,7 +344,7 @@ public abstract class AbstractQueryCreatorTestBase list = new ArrayList<>(); + List list = new ArrayList<>(); list.add(ROBB.firstname); assertThat(evaluate("findByFirstnameNotIn", list).against(ROBB)).isFalse(); @@ -353,7 +353,7 @@ public abstract class AbstractQueryCreatorTestBase list = new ArrayList<>(); + List list = new ArrayList<>(); list.add(null); assertThat(evaluate("findByFirstnameNotIn", list).against(JON)).isTrue(); @@ -362,7 +362,7 @@ public abstract class AbstractQueryCreatorTestBase list = new ArrayList<>(); + List list = new ArrayList<>(); list.add(ROBB.firstname); assertThat(evaluate("findByFirstnameNotIn", list).against(new PredicateQueryCreatorUnitTests.Person(null, 10))) @@ -372,7 +372,7 @@ public abstract class AbstractQueryCreatorTestBase list = new ArrayList<>(); + List list = new ArrayList<>(); list.add(null); assertThat(evaluate("findByFirstnameNotIn", list).against(new PredicateQueryCreatorUnitTests.Person(null, 10))) @@ -407,7 +407,7 @@ public abstract class AbstractQueryCreatorTestBase type, String methodName, Class[] argTypes) throws NoSuchMethodException { + + for (Method declaredMethod : type.getDeclaredMethods()) { + + if (!declaredMethod.getName().equals(methodName)) { + continue; + } + + if (declaredMethod.getParameterCount() != argTypes.length) { + continue; + } + + Class[] types = declaredMethod.getParameterTypes(); + + boolean assigable = true; + for (int i = 0; i < types.length; i++) { + + if (!types[i].isAssignableFrom(argTypes[i])) { + assigable = false; + break; + } + } + + if (assigable) { + return declaredMethod; + } + } + + throw new NoSuchMethodException("Method " + methodName + " not found in " + type); + } + protected abstract QUERY_CREATOR queryCreator(PartTree partTree, ParametersParameterAccessor accessor); protected abstract KeyValueQuery finalizeQuery(KeyValueQuery query, Object... args); @@ -490,10 +521,10 @@ public abstract class AbstractQueryCreatorTestBase in); + Person findByFirstnameIn(List in); // Type.NOT_IN - Person findByFirstnameNotIn(ArrayList in); + Person findByFirstnameNotIn(List in); }