From aeee6935f5b29f98662feac34d6c308b90173f92 Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Mon, 21 Feb 2011 18:08:16 +0100 Subject: [PATCH] DATACMNS-15 - Added support to discover Distinct keyword. Query method names now support Distinct in method name prefixes. Beyond that I laxed the prefix constraints a little so that it can potentially contain anything before a 'By' separator: - findByLastname -> simply query - findUsersByLastname -> simple query - findUsersDistinctByFirstname -> distinct query - findDistinctUsersByFirstname -> distinct query - findDistinctByLastname -> distinct query --- .../repository/query/parser/PartTree.java | 51 +++++++++++++++---- .../query/parser/PartTreeUnitTests.java | 26 ++++++++++ src/main/resources/changelog.txt | 7 +++ 3 files changed, 75 insertions(+), 9 deletions(-) diff --git a/spring-data-commons-core/src/main/java/org/springframework/data/repository/query/parser/PartTree.java b/spring-data-commons-core/src/main/java/org/springframework/data/repository/query/parser/PartTree.java index e0e0116ca..0bf145a22 100644 --- a/spring-data-commons-core/src/main/java/org/springframework/data/repository/query/parser/PartTree.java +++ b/spring-data-commons-core/src/main/java/org/springframework/data/repository/query/parser/PartTree.java @@ -21,6 +21,7 @@ import static java.util.regex.Pattern.*; import java.util.ArrayList; import java.util.Iterator; import java.util.List; +import java.util.regex.Matcher; import java.util.regex.Pattern; import org.springframework.data.domain.Sort; @@ -40,11 +41,13 @@ import org.springframework.util.Assert; public class PartTree implements Iterable { private static final String ORDER_BY = "OrderBy"; - private static final String[] PREFIXES = new String[] { "findBy", "find", - "readBy", "read", "getBy", "get" }; - private static final String PREFIX_TEMPLATE = "^%s(?=[A-Z]).*"; private static final String KEYWORD_TEMPLATE = "(%s)(?=[A-Z])"; + private static final String DISTINCT = "Distinct"; + private static final Pattern PREFIX_TEMPLATE = Pattern + .compile("^(find|read|get)(\\p{Upper}.*?)??By"); + + private final boolean distinct; private final OrderBySource orderBySource; private final List nodes = new ArrayList(); @@ -61,6 +64,7 @@ public class PartTree implements Iterable { Assert.notNull(source); Assert.notNull(domainClass); + this.distinct = detectDistinct(source); String foo = strip(source); String[] parts = split(foo, ORDER_BY); @@ -109,6 +113,17 @@ public class PartTree implements Iterable { } + /** + * Returns whether we indicate distinct lookup of entities. + * + * @return + */ + public boolean isDistinct() { + + return distinct; + } + + /** * Splits the given text at the given keywords. Expects camelcase style to * only match concrete keywords and not derivatives of it. @@ -135,15 +150,33 @@ public class PartTree implements Iterable { */ private String strip(String methodName) { - for (String prefix : PREFIXES) { + Matcher matcher = PREFIX_TEMPLATE.matcher(methodName); - String regex = format(PREFIX_TEMPLATE, prefix); - if (methodName.matches(regex)) { - return methodName.substring(prefix.length()); - } + if (matcher.find()) { + return methodName.substring(matcher.group().length()); + } else { + return methodName; + } + } + + + /** + * Checks whether the given source string contains the {@link #DISTINCT} + * keyword in it's prefix. + * + * @param source + * @return + */ + private boolean detectDistinct(String source) { + + Matcher matcher = PREFIX_TEMPLATE.matcher(source); + + if (!matcher.find()) { + return false; } - return methodName; + String group = matcher.group(2); + return group != null && group.contains(DISTINCT); } /** diff --git a/spring-data-commons-core/src/test/java/org/springframework/data/repository/query/parser/PartTreeUnitTests.java b/spring-data-commons-core/src/test/java/org/springframework/data/repository/query/parser/PartTreeUnitTests.java index 05b44cdff..f7223d120 100644 --- a/spring-data-commons-core/src/test/java/org/springframework/data/repository/query/parser/PartTreeUnitTests.java +++ b/spring-data-commons-core/src/test/java/org/springframework/data/repository/query/parser/PartTreeUnitTests.java @@ -91,6 +91,32 @@ public class PartTreeUnitTests { } + @Test + public void detectsDistinctCorrectly() throws Exception { + + PartTree tree = new PartTree("findDistinctByLastname", User.class); + assertThat(tree.isDistinct(), is(true)); + + tree = new PartTree("findUsersDistinctByLastname", User.class); + assertThat(tree.isDistinct(), is(true)); + + tree = new PartTree("findDistinctUsersByLastname", User.class); + assertThat(tree.isDistinct(), is(true)); + + tree = new PartTree("findUsersByLastname", User.class); + assertThat(tree.isDistinct(), is(false)); + + tree = new PartTree("findByLastname", User.class); + assertThat(tree.isDistinct(), is(false)); + + // Check it's non-greedy (would strip everything until Order*By* + // otherwise) + tree = new PartTree("findByLastnameOrderByFirstnameDesc", User.class); + assertThat(tree.isDistinct(), is(false)); + assertThat(tree.getSort(), is(new Sort(Direction.DESC, "firstname"))); + } + + private void assertPart(PartTree tree, Part[]... parts) { Iterator iterator = tree.iterator(); diff --git a/src/main/resources/changelog.txt b/src/main/resources/changelog.txt index 91dbfe83a..7f62426a3 100644 --- a/src/main/resources/changelog.txt +++ b/src/main/resources/changelog.txt @@ -1,6 +1,13 @@ Spring Data Commons Changelog ============================================= +Changes in version 1.0.0.M4 +---------------------------------------- + +Repository +* Improved ParameterAccessor infrastructure +* Added support for 'Distinct' keyword in finder method names + Changes in version 1.0.0.M3 (2011-02-09) ----------------------------------------