From 6f12450be6a9830ed5734627d9c5c5e7ec93a39a Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Tue, 1 Mar 2011 21:16:55 +0100 Subject: [PATCH] Changed @Query based queries to use index parameters. Using indexed parameters allows having a single method parameter to be bound to multiple placeholders. --- .../repository/StringBasedMongoQuery.java | 56 ++++++++++++++----- ...tractPersonRepositoryIntegrationTests.java | 2 +- .../mongodb/repository/PersonRepository.java | 2 +- .../StringBasedMongoQueryUnitTests.java | 4 +- .../repository/StubParameterAccessor.java | 15 +++-- 5 files changed, 56 insertions(+), 23 deletions(-) diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/repository/StringBasedMongoQuery.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/repository/StringBasedMongoQuery.java index 6f1cfe41c..5af669064 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/repository/StringBasedMongoQuery.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/repository/StringBasedMongoQuery.java @@ -15,10 +15,10 @@ */ package org.springframework.data.document.mongodb.repository; -import java.util.Iterator; import java.util.regex.Matcher; import java.util.regex.Pattern; +import org.bson.types.ObjectId; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.data.document.mongodb.MongoTemplate; @@ -32,10 +32,11 @@ import org.springframework.data.document.mongodb.query.Query; */ public class StringBasedMongoQuery extends AbstractMongoQuery { - private static final Pattern PLACEHOLDER = Pattern.compile("\\?"); + private static final Pattern PLACEHOLDER = Pattern.compile("\\?(\\d+)"); private static final Logger LOG = LoggerFactory.getLogger(StringBasedMongoQuery.class); - + private final String query; + private final String fieldSpec; /** * Creates a new {@link StringBasedMongoQuery}. @@ -46,6 +47,7 @@ public class StringBasedMongoQuery extends AbstractMongoQuery { public StringBasedMongoQuery(MongoQueryMethod method, MongoTemplate template) { super(method, template); this.query = method.getAnnotatedQuery(); + this.fieldSpec = method.getFieldSpecification(); } /* @@ -57,19 +59,45 @@ public class StringBasedMongoQuery extends AbstractMongoQuery { */ @Override protected Query createQuery(ConvertingParameterAccessor accessor) { - - Matcher matcher = PLACEHOLDER.matcher(query); - Iterator iterator = accessor.iterator(); - String result = null; - - while (matcher.find()) { - String group = matcher.group(); - result = query.replace(group, String.format("\"%s\"", iterator.next())); + + String queryString = replacePlaceholders(query, accessor); + + Query query = null; + + if (fieldSpec != null) { + String fieldString = replacePlaceholders(fieldSpec, accessor); + query = new BasicQuery(queryString, fieldString); + } else { + query = new BasicQuery(queryString); } - - Query query = new BasicQuery(result); + LOG.debug("Created query {}", query.getQueryObject()); - + return query; } + + private String replacePlaceholders(String input, ConvertingParameterAccessor accessor) { + + Matcher matcher = PLACEHOLDER.matcher(input); + String result = null; + + while (matcher.find()) { + String group = matcher.group(); + int index = Integer.parseInt(matcher.group(1)); + result = input.replace(group, getParameterWithIndex(accessor, index)); + } + + return result; + } + + private String getParameterWithIndex(ConvertingParameterAccessor accessor, int index) { + Object parameter = accessor.getBindableValue(index); + if (parameter instanceof String || parameter.getClass().isEnum()) { + return String.format("\"%s\"", parameter); + } else if (parameter instanceof ObjectId){ + return String.format("{ '$oid' : '%s' }", parameter); + } + + return parameter.toString(); + } } diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/repository/AbstractPersonRepositoryIntegrationTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/repository/AbstractPersonRepositoryIntegrationTests.java index 14e31afe0..f4c3be616 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/repository/AbstractPersonRepositoryIntegrationTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/repository/AbstractPersonRepositoryIntegrationTests.java @@ -87,7 +87,7 @@ public abstract class AbstractPersonRepositoryIntegrationTests { } @Test - public void finsPersonsByFirstname() { + public void findsPersonsByFirstname() { List result = repository.findByThePersonsFirstname("Leroi"); assertThat(result.size(), is(1)); diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/repository/PersonRepository.java b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/repository/PersonRepository.java index b04bb88c5..9eb934c69 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/repository/PersonRepository.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/repository/PersonRepository.java @@ -44,7 +44,7 @@ public interface PersonRepository extends MongoRepository { * @param firstname * @return */ - @Query("{ 'firstname' : ? }") + @Query("{ 'firstname' : ?0 }") List findByThePersonsFirstname(String firstname); diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/repository/StringBasedMongoQueryUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/repository/StringBasedMongoQueryUnitTests.java index 3072315a9..2255b932f 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/repository/StringBasedMongoQueryUnitTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/repository/StringBasedMongoQueryUnitTests.java @@ -52,7 +52,7 @@ public class StringBasedMongoQueryUnitTests { public void testname() throws Exception { Method method = SampleRepository.class.getMethod("findByLastname", String.class); - MongoQueryMethod queryMethod = new MongoQueryMethod(method); + MongoQueryMethod queryMethod = new MongoQueryMethod(method, Person.class); StringBasedMongoQuery mongoQuery = new StringBasedMongoQuery(queryMethod, template); ConvertingParameterAccessor accesor = StubParameterAccessor.getAccessor(converter, "Matthews"); @@ -64,7 +64,7 @@ public class StringBasedMongoQueryUnitTests { private interface SampleRepository { - @Query("{ 'lastname' : ? }") + @Query("{ 'lastname' : ?0 }") Person findByLastname(String lastname); } } diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/repository/StubParameterAccessor.java b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/repository/StubParameterAccessor.java index 83acc5cca..1eedfc13c 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/repository/StubParameterAccessor.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/repository/StubParameterAccessor.java @@ -30,6 +30,8 @@ import org.springframework.data.repository.query.ParameterAccessor; */ class StubParameterAccessor implements ParameterAccessor { + private final Object[] values; + /** * Creates a new {@link ConvertingParameterAccessor} backed by a {@link StubParameterAccessor} simply returning the * given parameters converted but unfiltered. @@ -42,11 +44,7 @@ class StubParameterAccessor implements ParameterAccessor { return new ConvertingParameterAccessor(converter, new StubParameterAccessor(parameters)); } - - /** - * - */ - private Object[] values; + public StubParameterAccessor(Object... values) { this.values = values; @@ -60,6 +58,13 @@ class StubParameterAccessor implements ParameterAccessor { public Pageable getPageable() { return null; } + + /* (non-Javadoc) + * @see org.springframework.data.repository.query.ParameterAccessor#getBindableParameter(int) + */ + public Object getBindableValue(int index) { + return values[index]; + } /* * (non-Javadoc)