diff --git a/src/main/java/org/springframework/data/repository/query/parser/PartTree.java b/src/main/java/org/springframework/data/repository/query/parser/PartTree.java index ce0bfb88d..4df00a70f 100644 --- a/src/main/java/org/springframework/data/repository/query/parser/PartTree.java +++ b/src/main/java/org/springframework/data/repository/query/parser/PartTree.java @@ -1,5 +1,5 @@ /* - * Copyright 2008-2015 the original author or authors. + * Copyright 2008-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -36,6 +36,7 @@ import org.springframework.util.StringUtils; * @author Oliver Gierke * @author Thomas Darimont * @author Christoph Strobl + * @author Mark Paluch */ public class PartTree implements Iterable { @@ -52,9 +53,10 @@ public class PartTree implements Iterable { private static final String KEYWORD_TEMPLATE = "(%s)(?=(\\p{Lu}|\\P{InBASIC_LATIN}))"; private static final String QUERY_PATTERN = "find|read|get|query|stream"; private static final String COUNT_PATTERN = "count"; + private static final String EXISTS_PATTERN = "exists"; private static final String DELETE_PATTERN = "delete|remove"; private static final Pattern PREFIX_TEMPLATE = Pattern.compile( // - "^(" + QUERY_PATTERN + "|" + COUNT_PATTERN + "|" + DELETE_PATTERN + ")((\\p{Lu}.*?))??By"); + "^(" + QUERY_PATTERN + "|" + COUNT_PATTERN + "|" + EXISTS_PATTERN + "|" + DELETE_PATTERN + ")((\\p{Lu}.*?))??By"); /** * The subject, for example "findDistinctUserByNameOrderByAge" would have the subject "DistinctUser". @@ -125,6 +127,16 @@ public class PartTree implements Iterable { return subject.isCountProjection(); } + /** + * Returns whether an exists projection shall be applied. + * + * @return + * @since 1.13 + */ + public Boolean isExistsProjection() { + return subject.isExistsProjection(); + } + /** * return true if the created {@link PartTree} is meant to be used for delete operation. * @@ -262,6 +274,7 @@ public class PartTree implements Iterable { private static final String DISTINCT = "Distinct"; private static final Pattern COUNT_BY_TEMPLATE = Pattern.compile("^count(\\p{Lu}.*?)??By"); + private static final Pattern EXISTS_BY_TEMPLATE = Pattern.compile("^(" + EXISTS_PATTERN + ")(\\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 + ")?" @@ -269,6 +282,7 @@ public class PartTree implements Iterable { private final boolean distinct; private final boolean count; + private final boolean exists; private final boolean delete; private final Integer maxResults; @@ -276,6 +290,7 @@ public class PartTree implements Iterable { this.distinct = subject == null ? false : subject.contains(DISTINCT); this.count = matches(subject, COUNT_BY_TEMPLATE); + this.exists = matches(subject, EXISTS_BY_TEMPLATE); this.delete = matches(subject, DELETE_BY_TEMPLATE); this.maxResults = returnMaxResultsIfFirstKSubjectOrNull(subject); } @@ -314,6 +329,16 @@ public class PartTree implements Iterable { return count; } + /** + * Returns {@literal true} if {@link Subject} matches {@link #EXISTS_BY_TEMPLATE}. + * + * @return + * @since 1.13 + */ + public boolean isExistsProjection() { + return exists; + } + public boolean isDistinct() { return distinct; } diff --git a/src/test/java/org/springframework/data/repository/query/parser/PartTreeUnitTests.java b/src/test/java/org/springframework/data/repository/query/parser/PartTreeUnitTests.java index f4f17dbaa..fa962539c 100644 --- a/src/test/java/org/springframework/data/repository/query/parser/PartTreeUnitTests.java +++ b/src/test/java/org/springframework/data/repository/query/parser/PartTreeUnitTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2008-2015 the original author or authors. + * Copyright 2008-2016 the original author or authors. * * Licensed 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 @@ -44,10 +44,11 @@ import org.springframework.data.repository.query.parser.PartTree.OrPart; * @author Thomas Darimont * @author Martin Baumgartner * @author Christoph Strobl + * @author Mark Paluch */ public class PartTreeUnitTests { - private String[] PREFIXES = { "find", "read", "get", "query", "stream", "count", "delete", "remove" }; + private String[] PREFIXES = { "find", "read", "get", "query", "stream", "count", "delete", "remove", "exists" }; @Test(expected = IllegalArgumentException.class) public void rejectsNullSource() throws Exception { @@ -436,6 +437,16 @@ public class PartTreeUnitTests { assertThat(tree.isCountProjection(), is(true)); } + /** + * @see DATACMNS-875 + */ + @Test + public void identifiesSimpleExistsByCorrectly() { + + PartTree tree = new PartTree("existsByLastname", User.class); + assertThat(tree.isExistsProjection(), is(true)); + } + /** * @see DATACMNS-399 */ @@ -652,6 +663,16 @@ public class PartTreeUnitTests { assertLimiting("countTop10DistinctUsersByLastname", User.class, false, null, true); } + /** + * @see DATACMNS-875 + */ + @Test + public void shouldNotSupportLimitingExistQueries() { + + assertLimiting("existsFirst10DistinctUsersByLastname", User.class, false, null, true); + assertLimiting("existsTop10DistinctUsersByLastname", User.class, false, null, true); + } + /** * @see DATACMNS-581 */