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 7ce8b8ba8..774e4d233 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-2013 the original author or authors. + * Copyright 2008-2014 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. @@ -35,10 +35,14 @@ import org.springframework.util.StringUtils; * * @author Oliver Gierke * @author Thomas Darimont + * @author Christoph Strobl */ public class PartTree implements Iterable { - private static final Pattern PREFIX_TEMPLATE = Pattern.compile("^(find|read|get|count|query)(\\p{Lu}.*?)??By"); + 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"); /* * We look for a pattern of: keyword followed by @@ -121,6 +125,16 @@ public class PartTree implements Iterable { return subject.isCountProjection(); } + /** + * return true if the created {@link PartTree} is meant to be used for delete operation. + * + * @return + * @since 1.8 + */ + public Boolean isDelete() { + return subject.isDelete(); + } + /** * Returns an {@link Iterable} of all parts contained in the {@link PartTree}. * @@ -221,19 +235,33 @@ public class PartTree implements Iterable { * * @author Phil Webb * @author Oliver Gierke + * @author Christoph Strobl */ 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 final boolean distinct; private final boolean count; + private final boolean delete; public Subject(String subject) { this.distinct = subject == null ? false : subject.contains(DISTINCT); - this.count = subject == null ? false : COUNT_BY_TEMPLATE.matcher(subject).find(); + this.count = matches(subject, COUNT_BY_TEMPLATE); + this.delete = matches(subject, DELETE_BY_TEMPLATE); + } + + /** + * Returns {@literal true} if {@link Subject} matches {@link #DELETE_BY_TEMPLATE}. + * + * @return + * @since 1.8 + */ + public Boolean isDelete() { + return delete; } public boolean isCountProjection() { @@ -243,6 +271,10 @@ public class PartTree implements Iterable { public boolean isDistinct() { return distinct; } + + private final boolean matches(String subject, Pattern pattern) { + return subject == null ? false : pattern.matcher(subject).find(); + } } /** 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 ff006cae7..aed7498f1 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 @@ -42,10 +42,11 @@ import org.springframework.data.repository.query.parser.PartTree.OrPart; * @author Phillip Webb * @author Thomas Darimont * @author Martin Baumgartner + * @author Christoph Strobl */ public class PartTreeUnitTests { - private String[] PREFIXES = { "find", "read", "get", "query" }; + private String[] PREFIXES = { "find", "read", "get", "query", "count", "delete", "remove" }; @Test(expected = IllegalArgumentException.class) public void rejectsNullSource() throws Exception { @@ -296,7 +297,7 @@ public class PartTreeUnitTests { public void parsesBeforeKeywordCorrectly() { assertType(Arrays.asList("birthdayBefore", "birthdayIsBefore"), Type.BEFORE, "birthday"); } - + /** * @see DATACMNS-433 */ @@ -304,7 +305,7 @@ public class PartTreeUnitTests { public void parsesLikeKeywordCorrectly() { assertType(asList("activeLike", "activeIsLike"), LIKE, "active"); } - + /** * @see DATACMNS-433 */ @@ -512,6 +513,46 @@ public class PartTreeUnitTests { assertThat(tree.getSort(), is(new Sort(Direction.ASC, "lastname"))); } + /** + * @see DATACMNS-448 + */ + @Test + public void identifiesSimpleDeleteByCorrectly() { + + PartTree tree = new PartTree("deleteByLastname", User.class); + assertThat(tree.isDelete(), is(true)); + } + + /** + * @see DATACMNS-448 + */ + @Test + public void identifiesExtendedDeleteByCorrectly() { + + PartTree tree = new PartTree("deleteUserByLastname", User.class); + assertThat(tree.isDelete(), is(true)); + } + + /** + * @see DATACMNS-448 + */ + @Test + public void identifiesSimpleRemoveByCorrectly() { + + PartTree tree = new PartTree("removeByLastname", User.class); + assertThat(tree.isDelete(), is(true)); + } + + /** + * @see DATACMNS-448 + */ + @Test + public void identifiesExtendedRemoveByCorrectly() { + + PartTree tree = new PartTree("removeUserByLastname", User.class); + assertThat(tree.isDelete(), is(true)); + } + private static void assertType(Iterable sources, Type type, String property) { assertType(sources, type, property, 1, true); }