Skip to content

Commit 52be56d

Browse files
Support generating queries containing regular expressions during AOT run.
1 parent ad87510 commit 52be56d

File tree

6 files changed

+36
-7
lines changed

6 files changed

+36
-7
lines changed

spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/aot/MongoRepositoryContributor.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@
2727
import static org.springframework.data.mongodb.repository.aot.QueryBlocks.QueryCodeBlockBuilder;
2828

2929
import java.lang.reflect.Method;
30-
import java.util.Locale;
3130

3231
import org.apache.commons.logging.Log;
3332
import org.apache.commons.logging.LogFactory;
@@ -173,8 +172,7 @@ private QueryInteraction createStringQuery(RepositoryInformation repositoryInfor
173172
private static boolean backoff(MongoQueryMethod method) {
174173

175174
// TODO: namedQuery, Regex queries, queries accepting Shapes (e.g. within) or returning arrays.
176-
boolean skip = method.isSearchQuery() || method.getName().toLowerCase(Locale.ROOT).contains("regex")
177-
|| method.getReturnType().getType().isArray();
175+
boolean skip = method.isSearchQuery() || method.getReturnType().getType().isArray();
178176

179177
if (skip && logger.isDebugEnabled()) {
180178
logger.debug("Skipping AOT generation for [%s]. Method is either returning an array or a geo-near, regex query"

spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/MongoQueryCreator.java

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -221,8 +221,7 @@ private Criteria from(Part part, MongoPersistentProperty property, Criteria crit
221221
return createContainingCriteria(part, property, criteria.not(), parameters);
222222
case REGEX:
223223

224-
Object param = parameters.next();
225-
return param instanceof Pattern pattern ? criteria.regex(pattern) : criteria.regex(param.toString());
224+
return createPatternCriteria(criteria, parameters);
226225
case EXISTS:
227226
Object next = parameters.next();
228227
if (next instanceof Placeholder placeholder) {
@@ -257,8 +256,17 @@ private Criteria from(Part part, MongoPersistentProperty property, Criteria crit
257256
}
258257

259258
@NonNull
260-
private Criteria createNearCriteria(MongoPersistentProperty property, Criteria criteria, Iterator<Object> parameters) {
259+
private static Criteria createPatternCriteria(Criteria criteria, Iterator<Object> parameters) {
260+
Object param = parameters.next();
261+
if (param instanceof Placeholder) {
262+
return criteria.raw("$regex", param);
263+
}
264+
return param instanceof Pattern pattern ? criteria.regex(pattern) : criteria.regex(param.toString());
265+
}
261266

267+
@NonNull
268+
private Criteria createNearCriteria(MongoPersistentProperty property, Criteria criteria,
269+
Iterator<Object> parameters) {
262270

263271
Range<Distance> range = accessor.getDistanceRange();
264272
Optional<Distance> distance = range.getUpperBound().getValue();

spring-data-mongodb/src/test/java/example/aot/UserRepository.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import java.util.Objects;
2323
import java.util.Optional;
2424
import java.util.Set;
25+
import java.util.regex.Pattern;
2526
import java.util.stream.Stream;
2627

2728
import org.springframework.data.annotation.Id;
@@ -96,6 +97,8 @@ public interface UserRepository extends CrudRepository<User, String> {
9697

9798
List<User> findByLastnameNot(String lastname);
9899

100+
List<User> findByFirstnameRegex(Pattern pattern);
101+
99102
List<User> findTop2ByLastnameStartingWith(String lastname);
100103

101104
List<User> findByLastnameStartingWithOrderByUsername(String lastname);

spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/aot/AotFragmentTestConfigurationSupport.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,8 @@ private Object getFragmentFacadeProxy(Object fragment) {
9393
Method target = ReflectionUtils.findMethod(fragment.getClass(), method.getName(), method.getParameterTypes());
9494

9595
if (target == null) {
96-
throw new MethodNotImplementedException("Method [%s] is not implemented by [%s]".formatted(method, target));
96+
throw new MethodNotImplementedException(
97+
"Method [%s] is not implemented by [%s]".formatted(method, fragment.getClass()));
9798
}
9899

99100
try {

spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/aot/MongoRepositoryContributorTests.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import java.time.Instant;
2828
import java.util.List;
2929
import java.util.Optional;
30+
import java.util.regex.Pattern;
3031

3132
import org.bson.Document;
3233
import org.junit.jupiter.api.BeforeAll;
@@ -229,6 +230,13 @@ void testNot() {
229230
assertThat(users).extracting(User::getUsername).isNotEmpty().doesNotContain("luke", "vader");
230231
}
231232

233+
@Test // GH-4939
234+
void testRegex() {
235+
236+
List<User> lukes = fragment.findByFirstnameRegex(Pattern.compile(".*uk.*"));
237+
assertThat(lukes).extracting(User::getUsername).containsExactly("luke");
238+
}
239+
232240
@Test
233241
void testExistsCriteria() {
234242

spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/aot/QueryMethodContributionUnitTests.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222

2323
import java.lang.reflect.Method;
2424
import java.util.Arrays;
25+
import java.util.regex.Pattern;
2526

2627
import javax.lang.model.element.Modifier;
2728

@@ -204,6 +205,16 @@ void rendersExpressionUsingParameterName() throws NoSuchMethodException {
204205
.contains("Map.of(\"firstname\", firstname)");
205206
}
206207

208+
@Test // GH-4939
209+
void rendersRegexCriteria() throws NoSuchMethodException {
210+
211+
MethodSpec methodSpec = codeOf(UserRepository.class, "findByFirstnameRegex", Pattern.class);
212+
213+
assertThat(methodSpec.toString()) //
214+
.contains("createQuery(\"{'firstname':{'$regex':?0}}\"") //
215+
.contains("Object[]{ pattern }");
216+
}
217+
207218
private static MethodSpec codeOf(Class<?> repository, String methodName, Class<?>... args)
208219
throws NoSuchMethodException {
209220

0 commit comments

Comments
 (0)