You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@deltaspike.apache.org by jo...@apache.org on 2016/05/23 00:27:57 UTC

deltaspike git commit: DELTASPIKE-1152 Adding support for first and top in method name, including docs.

Repository: deltaspike
Updated Branches:
  refs/heads/master b02acc77e -> f632269f1


DELTASPIKE-1152 Adding support for first and top in method name, including docs.


Project: http://git-wip-us.apache.org/repos/asf/deltaspike/repo
Commit: http://git-wip-us.apache.org/repos/asf/deltaspike/commit/f632269f
Tree: http://git-wip-us.apache.org/repos/asf/deltaspike/tree/f632269f
Diff: http://git-wip-us.apache.org/repos/asf/deltaspike/diff/f632269f

Branch: refs/heads/master
Commit: f632269f12404626b0ae24b0fbf1c643b3aae8d9
Parents: b02acc7
Author: John D. Ament <jo...@apache.org>
Authored: Sun May 22 19:20:15 2016 -0400
Committer: John D. Ament <jo...@apache.org>
Committed: Sun May 22 20:28:00 2016 -0400

----------------------------------------------------------------------
 .../impl/handler/CdiQueryInvocationContext.java |  2 +-
 .../deltaspike/data/impl/meta/MethodPrefix.java | 81 +++++++++++---------
 .../data/impl/meta/RepositoryMethod.java        |  5 ++
 .../deltaspike/data/impl/param/Parameters.java  |  9 ++-
 .../data/impl/handler/QueryHandlerTest.java     | 33 +++++++-
 .../data/impl/meta/MethodPrefixTest.java        | 66 ++++++++++++++++
 .../data/test/service/SimpleRepository.java     |  4 +
 documentation/src/main/asciidoc/data.adoc       | 19 +++++
 8 files changed, 175 insertions(+), 44 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/deltaspike/blob/f632269f/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/handler/CdiQueryInvocationContext.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/handler/CdiQueryInvocationContext.java b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/handler/CdiQueryInvocationContext.java
index 4505f6a..9f032e5 100644
--- a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/handler/CdiQueryInvocationContext.java
+++ b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/handler/CdiQueryInvocationContext.java
@@ -60,7 +60,7 @@ public class CdiQueryInvocationContext implements QueryInvocationContext
     {
         this.entityManager = entityManager;
         this.args = args == null ? new Object[]{} : args;
-        this.params = Parameters.create(method, this.args);
+        this.params = Parameters.create(method, this.args, repoMethod);
         this.proxy = proxy;
         this.method = method;
         this.repoMethod = repoMethod;

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/f632269f/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/meta/MethodPrefix.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/meta/MethodPrefix.java b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/meta/MethodPrefix.java
index e421087..37f73b5 100644
--- a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/meta/MethodPrefix.java
+++ b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/meta/MethodPrefix.java
@@ -20,6 +20,9 @@ package org.apache.deltaspike.data.impl.meta;
 
 import org.apache.deltaspike.data.api.SingleResultType;
 
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
 public class MethodPrefix
 {
     public static final String DEFAULT_PREFIX = "findBy";
@@ -28,13 +31,22 @@ public class MethodPrefix
     public static final String DEFAULT_DELETE_PREFIX = "deleteBy";
     public static final String DEFAULT_REMOVE_PREFIX = "removeBy";
 
+    private static final String FIND_FIRST_PREFIX = "find(First|Top)(\\d+)By";
+    private static final String FIND_FIRST_PREFIX_PATTERN = FIND_FIRST_PREFIX + "(.+)";
+    private static final Pattern DIGIT_PATTERN = Pattern.compile("\\d+");
+
     private final String customPrefix;
     private final String methodName;
+    private int definedMaxResults = 0;
 
     public MethodPrefix(String customPrefix, String methodName)
     {
         this.customPrefix = customPrefix;
         this.methodName = methodName;
+        if (this.methodName != null)
+        {
+            this.parseMaxResults();
+        }
     }
 
     public String removePrefix(String queryPart)
@@ -91,54 +103,46 @@ public class MethodPrefix
                 this.getPrefix().equalsIgnoreCase(DEFAULT_REMOVE_PREFIX);
     }
 
-    private static enum KnownQueryPrefix
+    public int getDefinedMaxResults()
     {
-        DEFAULT(DEFAULT_PREFIX)
-        {
-            @Override
-            public SingleResultType getStyle()
-            {
-                return SingleResultType.JPA;
-            }
-        },
-        OPTIONAL(DEFAULT_OPT_PREFIX)
-        {
-            @Override
-            public SingleResultType getStyle()
-            {
-                return SingleResultType.OPTIONAL;
-            }
-        },
-        ANY(DEFAULT_ANY_PREFIX)
+        return definedMaxResults;
+    }
+
+    private void parseMaxResults()
+    {
+        if (this.methodName.matches(FIND_FIRST_PREFIX_PATTERN))
         {
-            @Override
-            public SingleResultType getStyle()
+            Matcher matcher = DIGIT_PATTERN.matcher(this.methodName);
+            if (matcher.find())
             {
-                return SingleResultType.ANY;
+                this.definedMaxResults = Integer.parseInt(matcher.group());
             }
-        },
-        DELETE_DEFAULT(DEFAULT_DELETE_PREFIX)
+        }
+    }
+
+    private enum KnownQueryPrefix
+    {
+        DEFAULT(DEFAULT_PREFIX, SingleResultType.JPA),
+        FIND_FIRST(FIND_FIRST_PREFIX, SingleResultType.JPA)
         {
             @Override
-            public SingleResultType getStyle()
+            public String removePrefix(String queryPart)
             {
-                return SingleResultType.ANY;
+                return queryPart.replaceFirst(FIND_FIRST_PREFIX,"");
             }
         },
-        REMOVE_DEFAULT(DEFAULT_REMOVE_PREFIX)
-        {
-            @Override
-            public SingleResultType getStyle()
-            {
-                return SingleResultType.ANY;
-            }
-        };
+        OPTIONAL(DEFAULT_OPT_PREFIX,SingleResultType.OPTIONAL),
+        ANY(DEFAULT_ANY_PREFIX, SingleResultType.ANY),
+        DELETE_DEFAULT(DEFAULT_DELETE_PREFIX, SingleResultType.ANY),
+        REMOVE_DEFAULT(DEFAULT_REMOVE_PREFIX, SingleResultType.ANY);
 
         private final String prefix;
+        private final SingleResultType singleResultType;
 
-        private KnownQueryPrefix(String prefix)
+        KnownQueryPrefix(String prefix, SingleResultType singleResultType)
         {
             this.prefix = prefix;
+            this.singleResultType = singleResultType;
         }
 
         public String removePrefix(String queryPart)
@@ -151,10 +155,17 @@ public class MethodPrefix
             return prefix;
         }
 
-        public abstract SingleResultType getStyle();
+        public SingleResultType getStyle()
+        {
+            return this.singleResultType;
+        }
 
         public static KnownQueryPrefix fromMethodName(String name)
         {
+            if (name.matches(FIND_FIRST_PREFIX_PATTERN))
+            {
+                return FIND_FIRST;
+            }
             for (KnownQueryPrefix mapping : values())
             {
                 if (name.startsWith(mapping.getPrefix()))

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/f632269f/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/meta/RepositoryMethod.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/meta/RepositoryMethod.java b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/meta/RepositoryMethod.java
index f56ffaf..08cedd8 100644
--- a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/meta/RepositoryMethod.java
+++ b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/meta/RepositoryMethod.java
@@ -223,6 +223,11 @@ public class RepositoryMethod
         return mapper != null;
     }
 
+    public int getDefinedMaxResults()
+    {
+        return this.methodPrefix.getDefinedMaxResults();
+    }
+
     public SingleResultType getSingleResultStyle()
     {
         if (method.isAnnotationPresent(Query.class))

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/f632269f/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/param/Parameters.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/param/Parameters.java b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/param/Parameters.java
index 76b8dae..d5e74b8 100644
--- a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/param/Parameters.java
+++ b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/param/Parameters.java
@@ -32,6 +32,7 @@ import org.apache.deltaspike.data.api.FirstResult;
 import org.apache.deltaspike.data.api.MaxResults;
 import org.apache.deltaspike.data.api.QueryParam;
 import org.apache.deltaspike.data.api.mapping.QueryInOutMapper;
+import org.apache.deltaspike.data.impl.meta.RepositoryMethod;
 
 /**
  * Convenience class to manage method and query parameters.
@@ -61,9 +62,9 @@ public final class Parameters
         return new Parameters(empty, DEFAULT_MAX, DEFAULT_FIRST);
     }
 
-    public static Parameters create(Method method, Object[] parameters)
+    public static Parameters create(Method method, Object[] parameters, RepositoryMethod repositoryMethod)
     {
-        int max = extractSizeRestriction(method);
+        int max = extractSizeRestriction(method, repositoryMethod);
         int first = DEFAULT_FIRST;
         List<Parameter> result = new ArrayList<Parameter>(parameters.length);
         int paramIndex = 1;
@@ -142,13 +143,13 @@ public final class Parameters
         return firstResult;
     }
 
-    private static int extractSizeRestriction(Method method)
+    private static int extractSizeRestriction(Method method, RepositoryMethod repositoryMethod)
     {
         if (method.isAnnotationPresent(org.apache.deltaspike.data.api.Query.class))
         {
             return method.getAnnotation(org.apache.deltaspike.data.api.Query.class).max();
         }
-        return 0;
+        return repositoryMethod.getDefinedMaxResults();
     }
 
     @SuppressWarnings("unchecked")

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/f632269f/deltaspike/modules/data/impl/src/test/java/org/apache/deltaspike/data/impl/handler/QueryHandlerTest.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/data/impl/src/test/java/org/apache/deltaspike/data/impl/handler/QueryHandlerTest.java b/deltaspike/modules/data/impl/src/test/java/org/apache/deltaspike/data/impl/handler/QueryHandlerTest.java
index 89b9397..f7b8ccd 100644
--- a/deltaspike/modules/data/impl/src/test/java/org/apache/deltaspike/data/impl/handler/QueryHandlerTest.java
+++ b/deltaspike/modules/data/impl/src/test/java/org/apache/deltaspike/data/impl/handler/QueryHandlerTest.java
@@ -27,11 +27,8 @@ import static org.junit.Assert.assertTrue;
 
 import java.util.List;
 
-import javax.enterprise.inject.Produces;
 import javax.inject.Inject;
-import javax.persistence.EntityManager;
 import javax.persistence.NonUniqueResultException;
-import javax.persistence.PersistenceContext;
 
 import org.apache.deltaspike.data.test.TransactionalTestCase;
 import org.apache.deltaspike.data.test.domain.Simple;
@@ -455,12 +452,40 @@ public class QueryHandlerTest extends TransactionalTestCase
         builder.createSimple(name);
 
         // when
-        Simple result = repo.findByNameIgnoreCase("should_create_case_insensitive_query_for_equals");
+        Simple result = repo.findByNameIgnoreCase(name.toLowerCase());
 
         // then
         assertEquals(name, result.getName());
     }
 
+    @Test
+    public void should_find_first_2()
+    {
+        final String name = "Should_Create_Case_Insensitive_Query_for_Equals";
+        builder.createSimple(name);
+        builder.createSimple(name);
+        builder.createSimple(name);
+        builder.createSimple("this is something else");
+
+        List<Simple> result = repo.findFirst2ByName(name);
+
+        assertEquals(2, result.size());
+    }
+
+    @Test
+    public void should_find_top_2()
+    {
+        final String name = "Should_Create_Case_Insensitive_Query_for_Equals";
+        builder.createSimple(name);
+        builder.createSimple(name);
+        builder.createSimple(name);
+        builder.createSimple("this is something else");
+
+        List<Simple> result = repo.findTop2ByName(name);
+
+        assertEquals(2, result.size());
+    }
+
     @Before
     public void setup()
     {

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/f632269f/deltaspike/modules/data/impl/src/test/java/org/apache/deltaspike/data/impl/meta/MethodPrefixTest.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/data/impl/src/test/java/org/apache/deltaspike/data/impl/meta/MethodPrefixTest.java b/deltaspike/modules/data/impl/src/test/java/org/apache/deltaspike/data/impl/meta/MethodPrefixTest.java
new file mode 100644
index 0000000..04e1aa1
--- /dev/null
+++ b/deltaspike/modules/data/impl/src/test/java/org/apache/deltaspike/data/impl/meta/MethodPrefixTest.java
@@ -0,0 +1,66 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.deltaspike.data.impl.meta;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+public class MethodPrefixTest
+{
+    @Test
+    public void shouldParseArbitraryMethodFindPrefix()
+    {
+        MethodPrefix methodPrefix = new MethodPrefix("","findTop20ByName");
+
+        String resultingQuery = methodPrefix.removePrefix("findTop20ByName");
+
+        assertEquals("Name", resultingQuery);
+    }
+
+    @Test
+    public void shouldParseFirst20MethodFindPrefix()
+    {
+        MethodPrefix methodPrefix = new MethodPrefix("","findFirst20ByName");
+
+        String resultingQuery = methodPrefix.removePrefix("findFirst20ByName");
+
+        assertEquals("Name", resultingQuery);
+    }
+
+    @Test
+    public void shouldParseDefinedMaxResults()
+    {
+        MethodPrefix methodPrefix = new MethodPrefix("","findFirst20ByName");
+
+        int maxResults = methodPrefix.getDefinedMaxResults();
+
+        assertEquals(20, maxResults);
+    }
+
+    @Test
+    public void shouldNotParseNonMatchingMethodName()
+    {
+        MethodPrefix methodPrefix = new MethodPrefix("","findAnyByName");
+
+        int maxResults = methodPrefix.getDefinedMaxResults();
+
+        assertEquals(0, maxResults);
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/f632269f/deltaspike/modules/data/impl/src/test/java/org/apache/deltaspike/data/test/service/SimpleRepository.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/data/impl/src/test/java/org/apache/deltaspike/data/test/service/SimpleRepository.java b/deltaspike/modules/data/impl/src/test/java/org/apache/deltaspike/data/test/service/SimpleRepository.java
index ebadd20..62dcb24 100755
--- a/deltaspike/modules/data/impl/src/test/java/org/apache/deltaspike/data/test/service/SimpleRepository.java
+++ b/deltaspike/modules/data/impl/src/test/java/org/apache/deltaspike/data/test/service/SimpleRepository.java
@@ -85,6 +85,10 @@ public abstract class SimpleRepository extends AbstractEntityRepository<Simple,
 
     public abstract Simple findAnyByName(String name);
 
+    public abstract List<Simple> findFirst2ByName(String name);
+
+    public abstract List<Simple> findTop2ByName(String name);
+
     public abstract List<Simple> findByOrderByCounterAscIdDesc();
 
     @Query(value = "SELECT * from SIMPLE_TABLE s WHERE s.name = ?1", isNative = true)

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/f632269f/documentation/src/main/asciidoc/data.adoc
----------------------------------------------------------------------
diff --git a/documentation/src/main/asciidoc/data.adoc b/documentation/src/main/asciidoc/data.adoc
index 6f7f76c..904a468 100644
--- a/documentation/src/main/asciidoc/data.adoc
+++ b/documentation/src/main/asciidoc/data.adoc
@@ -521,6 +521,25 @@ public interface PersonRepository extends EntityRepository<Person, Long>
 } 
 ------------------------------------------------------------------------------
 
+=== Query Limits
+
+Starting with Apache DeltaSpike 1.6.2, you can apply query limits using method
+expressions.  They can be applied using `First` or `Top` keywords, in a method
+like this
+
+[source,java]
+------------------------------------------------------------------------------
+@Repository
+public interface PersonRepository extends EntityRepository<Person, Long>
+{
+
+    List<Person> findFirst2ByLastNameOrderByAgeAscLastNameDesc(String lastName);
+
+    List<Person> findTop2ByLastNameOrderByAgeAscLastNameDesc(String lastName);
+
+}
+------------------------------------------------------------------------------
+
 === Nested Properties
 
 To create a comparison on a nested property, the traversal parts can be