DATACMNS-516 - Add support for limiting the query result in the query derivation mechanism.
We can now detect whether a given query method wants to limit the query results based on two new supported prefixes (findFirstBy…(…) and findFirstKBy…(…)) where "First" part can also be replaced by "Top" and an following optional K (which must be a decimal int) that denotes the maximal number of result rows to be retuned by the query. This can be used by the stores to allow queries like: - T findFirstBy…OrderBy…Asc -> smallest - T findFirstBy…OrderBy…Desc -> greatest - T findTopBy…OrderBy…Desc -> greatest - T findFirstBy…(Sort sort) -> general purpose - T findTopBy…(Sort sort) -> general purpose - List<T> findFirstKBy…OrderBy…Asc -> smallest K - List<T> findFirstKBy…OrderBy…Desc -> biggest K - List<T> findFirstKBy…(Sort sort) -> general purpose TOP K - List<T> findTopKBy…(Sort sort) -> general purpose TOP K The limiting expressions also support the Distinct expression. Also, for the queries limiting the result set to one instance, wrapping the result into an Optional is supported. If pagination or slicing is applied to a limiting query pagination (and the calculation of the number of pages available) is happening within the limited result. Original pull request: #85.
This commit is contained in:
committed by
Oliver Gierke
parent
d41da583e9
commit
1697c77f31
@@ -50,9 +50,11 @@ public class PartTree implements Iterable<OrPart> {
|
||||
* @see http://docs.oracle.com/javase/7/docs/api/java/util/regex/Pattern.html#ubc
|
||||
*/
|
||||
private static final String KEYWORD_TEMPLATE = "(%s)(?=(\\p{Lu}|\\P{InBASIC_LATIN}))";
|
||||
private static final String QUERY_PATTERN = "find|read|get|query";
|
||||
private static final String COUNT_PATTERN = "count";
|
||||
private static final String DELETE_PATTERN = "delete|remove";
|
||||
private static final Pattern PREFIX_TEMPLATE = Pattern.compile("^(find|read|get|count|query|" + DELETE_PATTERN
|
||||
+ ")(\\p{Lu}.*?)??By");
|
||||
private static final Pattern PREFIX_TEMPLATE = Pattern.compile( //
|
||||
"^(" + QUERY_PATTERN + "|" + COUNT_PATTERN + "|" + DELETE_PATTERN + ")((\\p{Lu}.*?))??By");
|
||||
|
||||
/**
|
||||
* The subject, for example "findDistinctUserByNameOrderByAge" would have the subject "DistinctUser".
|
||||
@@ -133,6 +135,26 @@ public class PartTree implements Iterable<OrPart> {
|
||||
return subject.isDelete();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return {@literal true} if the create {@link PartTree} is meant to be used for a query with limited maximal results.
|
||||
*
|
||||
* @return
|
||||
* @since 1.9
|
||||
*/
|
||||
public boolean isLimiting() {
|
||||
return getMaxResults() != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of maximal results to return or {@literal null} if not restricted.
|
||||
*
|
||||
* @return
|
||||
* @since 1.9
|
||||
*/
|
||||
public Integer getMaxResults() {
|
||||
return subject.getMaxResults();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an {@link Iterable} of all parts contained in the {@link PartTree}.
|
||||
*
|
||||
@@ -234,22 +256,48 @@ public class PartTree implements Iterable<OrPart> {
|
||||
* @author Phil Webb
|
||||
* @author Oliver Gierke
|
||||
* @author Christoph Strobl
|
||||
* @author Thomas Darimont
|
||||
*/
|
||||
private static class Subject {
|
||||
|
||||
private static final String DISTINCT = "Distinct";
|
||||
private static final Pattern COUNT_BY_TEMPLATE = Pattern.compile("^count(\\p{Lu}.*?)??By");
|
||||
private static final Pattern DELETE_BY_TEMPLATE = Pattern.compile("^(" + DELETE_PATTERN + ")(\\p{Lu}.*?)??By");
|
||||
private static final String LIMITING_QUERY_PATTERN = "(First|Top)(\\d*)?";
|
||||
private static final Pattern LIMITED_QUERY_TEMPLATE = Pattern.compile("^(" + QUERY_PATTERN + ")(" + DISTINCT + ")?"
|
||||
+ LIMITING_QUERY_PATTERN + "(\\p{Lu}.*?)??By");
|
||||
|
||||
private final boolean distinct;
|
||||
private final boolean count;
|
||||
private final boolean delete;
|
||||
private final Integer maxResults;
|
||||
|
||||
public Subject(String subject) {
|
||||
|
||||
this.distinct = subject == null ? false : subject.contains(DISTINCT);
|
||||
this.count = matches(subject, COUNT_BY_TEMPLATE);
|
||||
this.delete = matches(subject, DELETE_BY_TEMPLATE);
|
||||
this.maxResults = returnMaxResultsIfFirstKSubjectOrNull(subject);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param subject
|
||||
* @return
|
||||
* @since 1.9
|
||||
*/
|
||||
private Integer returnMaxResultsIfFirstKSubjectOrNull(String subject) {
|
||||
|
||||
if (subject == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Matcher grp = LIMITED_QUERY_TEMPLATE.matcher(subject);
|
||||
|
||||
if (!grp.find()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return StringUtils.hasText(grp.group(4)) ? Integer.valueOf(grp.group(4)) : 1;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -270,6 +318,10 @@ public class PartTree implements Iterable<OrPart> {
|
||||
return distinct;
|
||||
}
|
||||
|
||||
public Integer getMaxResults() {
|
||||
return maxResults;
|
||||
}
|
||||
|
||||
private final boolean matches(String subject, Pattern pattern) {
|
||||
return subject == null ? false : pattern.matcher(subject).find();
|
||||
}
|
||||
@@ -330,5 +382,4 @@ public class PartTree implements Iterable<OrPart> {
|
||||
return orderBySource;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user