Skip to content

Commit 862c963

Browse files
committed
DATAMONGO-1454 - Add support for exists projection in repository query methods.
We now support exists projections for query methods in query methods for derived and string queries. public PersonReposotiry extends Repository<Person, String> { boolean existsByFirstname(String firstname); @query(value = "{ 'lastname' : ?0 }", exists = true) boolean someExistQuery(String lastname); }
1 parent 6f6d016 commit 862c963

File tree

8 files changed

+134
-8
lines changed

8 files changed

+134
-8
lines changed

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,14 @@
6262
*/
6363
boolean count() default false;
6464

65+
/**
66+
* Returns whether the query defined should be executed as exists projection.
67+
*
68+
* @since 1.10
69+
* @return
70+
*/
71+
boolean exists() default false;
72+
6573
/**
6674
* Returns whether the query should delete matching documents.
6775
*

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

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@
2020
import org.springframework.data.mongodb.core.MongoOperations;
2121
import org.springframework.data.mongodb.core.query.Query;
2222
import org.springframework.data.mongodb.repository.query.MongoQueryExecution.CollectionExecution;
23+
import org.springframework.data.mongodb.repository.query.MongoQueryExecution.CountExecution;
2324
import org.springframework.data.mongodb.repository.query.MongoQueryExecution.DeleteExecution;
25+
import org.springframework.data.mongodb.repository.query.MongoQueryExecution.ExistsExecution;
2426
import org.springframework.data.mongodb.repository.query.MongoQueryExecution.GeoNearExecution;
2527
import org.springframework.data.mongodb.repository.query.MongoQueryExecution.PagedExecution;
2628
import org.springframework.data.mongodb.repository.query.MongoQueryExecution.PagingGeoNearExecution;
@@ -40,6 +42,7 @@
4042
* @author Oliver Gierke
4143
* @author Thomas Darimont
4244
* @author Christoph Strobl
45+
* @author Mark Paluch
4346
*/
4447
public abstract class AbstractMongoQuery implements RepositoryQuery {
4548

@@ -123,8 +126,12 @@ private MongoQueryExecution getExecutionToWrap(Query query, MongoParameterAccess
123126
return new CollectionExecution(operations, accessor.getPageable());
124127
} else if (method.isPageQuery()) {
125128
return new PagedExecution(operations, accessor.getPageable());
129+
} else if (isCountQuery()) {
130+
return new CountExecution(operations);
131+
} else if (isExistsQuery()) {
132+
return new ExistsExecution(operations);
126133
} else {
127-
return new SingleEntityExecution(operations, isCountQuery());
134+
return new SingleEntityExecution(operations);
128135
}
129136
}
130137

@@ -164,6 +171,14 @@ protected Query createCountQuery(ConvertingParameterAccessor accessor) {
164171
*/
165172
protected abstract boolean isCountQuery();
166173

174+
/**
175+
* Returns whether the query should get an exists projection applied.
176+
*
177+
* @return
178+
* @since 1.10
179+
*/
180+
protected abstract boolean isExistsQuery();
181+
167182
/**
168183
* Return weather the query should delete matching documents.
169184
*

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

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -163,15 +163,57 @@ public long get() {
163163
static final class SingleEntityExecution implements MongoQueryExecution {
164164

165165
private final MongoOperations operations;
166-
private final boolean countProjection;
167166

168167
/*
169168
* (non-Javadoc)
170169
* @see org.springframework.data.mongodb.repository.query.AbstractMongoQuery.Execution#execute(org.springframework.data.mongodb.core.query.Query, java.lang.Class, java.lang.String)
171170
*/
172171
@Override
173172
public Object execute(Query query, Class<?> type, String collection) {
174-
return countProjection ? operations.count(query, type, collection) : operations.findOne(query, type, collection);
173+
return operations.findOne(query, type, collection);
174+
}
175+
}
176+
177+
/**
178+
* {@link MongoQueryExecution} to perform a count projection.
179+
*
180+
* @author Oliver Gierke
181+
* @author Mark Paluch
182+
* @since 1.10
183+
*/
184+
@RequiredArgsConstructor
185+
static final class CountExecution implements MongoQueryExecution {
186+
187+
private final MongoOperations operations;
188+
189+
/*
190+
* (non-Javadoc)
191+
* @see org.springframework.data.mongodb.repository.query.AbstractMongoQuery.Execution#execute(org.springframework.data.mongodb.core.query.Query, java.lang.Class, java.lang.String)
192+
*/
193+
@Override
194+
public Object execute(Query query, Class<?> type, String collection) {
195+
return operations.count(query, type, collection);
196+
}
197+
}
198+
199+
/**
200+
* {@link MongoQueryExecution} to perform an exists projection.
201+
*
202+
* @author Mark Paluch
203+
* @since 1.10
204+
*/
205+
@RequiredArgsConstructor
206+
static final class ExistsExecution implements MongoQueryExecution {
207+
208+
private final MongoOperations operations;
209+
210+
/*
211+
* (non-Javadoc)
212+
* @see org.springframework.data.mongodb.repository.query.AbstractMongoQuery.Execution#execute(org.springframework.data.mongodb.core.query.Query, java.lang.Class, java.lang.String)
213+
*/
214+
@Override
215+
public Object execute(Query query, Class<?> type, String collection) {
216+
return operations.exists(query, type, collection);
175217
}
176218
}
177219

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

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2015 the original author or authors.
2+
* Copyright 2002-2016 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -38,6 +38,7 @@
3838
* @author Oliver Gierke
3939
* @author Christoph Strobl
4040
* @author Thomas Darimont
41+
* @author Mark Paluch
4142
*/
4243
public class PartTreeMongoQuery extends AbstractMongoQuery {
4344

@@ -139,6 +140,15 @@ protected boolean isCountQuery() {
139140
return tree.isCountProjection();
140141
}
141142

143+
/*
144+
* (non-Javadoc)
145+
* @see org.springframework.data.mongodb.repository.query.AbstractMongoQuery#isExistsQuery()
146+
*/
147+
@Override
148+
protected boolean isExistsQuery() {
149+
return tree.isExistsProjection();
150+
}
151+
142152
/*
143153
* (non-Javadoc)
144154
* @see org.springframework.data.mongodb.repository.query.AbstractMongoQuery#isDeleteQuery()

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

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2011-2015 the original author or authors.
2+
* Copyright 2011-2016 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -42,16 +42,18 @@
4242
* @author Oliver Gierke
4343
* @author Christoph Strobl
4444
* @author Thomas Darimont
45+
* @author Mark Paluch
4546
*/
4647
public class StringBasedMongoQuery extends AbstractMongoQuery {
4748

48-
private static final String COUND_AND_DELETE = "Manually defined query for %s cannot be both a count and delete query at the same time!";
49+
private static final String COUNT_EXISTS_AND_DELETE = "Manually defined query for %s cannot be a count and exists or delete query at the same time!";
4950
private static final Logger LOG = LoggerFactory.getLogger(StringBasedMongoQuery.class);
5051
private static final ParameterBindingParser BINDING_PARSER = ParameterBindingParser.INSTANCE;
5152

5253
private final String query;
5354
private final String fieldSpec;
5455
private final boolean isCountQuery;
56+
private final boolean isExistsQuery;
5557
private final boolean isDeleteQuery;
5658
private final List<ParameterBinding> queryParameterBindings;
5759
private final List<ParameterBinding> fieldSpecParameterBindings;
@@ -96,10 +98,11 @@ public StringBasedMongoQuery(String query, MongoQueryMethod method, MongoOperati
9698
method.getFieldSpecification(), this.fieldSpecParameterBindings);
9799

98100
this.isCountQuery = method.hasAnnotatedQuery() ? method.getQueryAnnotation().count() : false;
101+
this.isExistsQuery = method.hasAnnotatedQuery() ? method.getQueryAnnotation().exists() : false;
99102
this.isDeleteQuery = method.hasAnnotatedQuery() ? method.getQueryAnnotation().delete() : false;
100103

101-
if (isCountQuery && isDeleteQuery) {
102-
throw new IllegalArgumentException(String.format(COUND_AND_DELETE, method));
104+
if (hasTwoQueryExecutions(this.isCountQuery, this.isExistsQuery, this.isDeleteQuery)) {
105+
throw new IllegalArgumentException(String.format(COUNT_EXISTS_AND_DELETE, method));
103106
}
104107

105108
this.parameterBinder = new ExpressionEvaluatingParameterBinder(expressionParser, evaluationContextProvider);
@@ -135,6 +138,15 @@ protected boolean isCountQuery() {
135138
return isCountQuery;
136139
}
137140

141+
/*
142+
* (non-Javadoc)
143+
* @see org.springframework.data.mongodb.repository.query.AbstractMongoQuery#isExistsQuery()
144+
*/
145+
@Override
146+
protected boolean isExistsQuery() {
147+
return isExistsQuery;
148+
}
149+
138150
/*
139151
* (non-Javadoc)
140152
* @see org.springframework.data.mongodb.repository.query.AbstractMongoQuery#isDeleteQuery()
@@ -144,6 +156,10 @@ protected boolean isDeleteQuery() {
144156
return this.isDeleteQuery;
145157
}
146158

159+
private boolean hasTwoQueryExecutions(boolean isCountQuery, boolean isExistsQuery, boolean isDeleteQuery) {
160+
return isCountQuery ? (isExistsQuery || isDeleteQuery) : (isExistsQuery && isDeleteQuery);
161+
}
162+
147163
/**
148164
* A parser that extracts the parameter bindings from a given query string.
149165
*

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

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -588,6 +588,23 @@ public void executesAnnotatedCountProjection() {
588588
assertThat(repository.someCountQuery("Matthews"), is(2L));
589589
}
590590

591+
/**
592+
* @see DATAMONGO-1454
593+
*/
594+
@Test
595+
public void executesDerivedExistsProjectionToBoolean() {
596+
assertThat(repository.existsByFirstname("Oliver August"), is(true));
597+
assertThat(repository.existsByFirstname("Hans Peter"), is(false));
598+
}
599+
600+
/**
601+
* @see DATAMONGO-1454
602+
*/
603+
@Test
604+
public void executesAnnotatedExistProjection() {
605+
assertThat(repository.someExistQuery("Matthews"), is(true));
606+
}
607+
591608
/**
592609
* @see DATAMONGO-701
593610
*/

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
* @author Oliver Gierke
4343
* @author Thomas Darimont
4444
* @author Christoph Strobl
45+
* @author Mark Paluch
4546
*/
4647
public interface PersonRepository extends MongoRepository<Person, String>, QueryDslPredicateExecutor<Person> {
4748

@@ -250,6 +251,17 @@ public interface PersonRepository extends MongoRepository<Person, String>, Query
250251
@Query(value = "{ 'lastname' : ?0 }", count = true)
251252
long someCountQuery(String lastname);
252253

254+
/**
255+
* @see DATAMONGO-1454
256+
*/
257+
boolean existsByFirstname(String firstname);
258+
259+
/**
260+
* @see DATAMONGO-1454
261+
*/
262+
@Query(value = "{ 'lastname' : ?0 }", exists = true)
263+
boolean someExistQuery(String lastname);
264+
253265
/**
254266
* @see DATAMONGO-770
255267
*/

spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/query/AbstractMongoQueryUnitTests.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,7 @@ private MongoQueryFake createQueryForMethod(String methodName, Class<?>... param
312312
private static class MongoQueryFake extends AbstractMongoQuery {
313313

314314
private boolean isCountQuery;
315+
private boolean isExistsQuery;
315316
private boolean isDeleteQuery;
316317

317318
public MongoQueryFake(MongoQueryMethod method, MongoOperations operations) {
@@ -328,6 +329,11 @@ protected boolean isCountQuery() {
328329
return isCountQuery;
329330
}
330331

332+
@Override
333+
protected boolean isExistsQuery() {
334+
return false;
335+
}
336+
331337
@Override
332338
protected boolean isDeleteQuery() {
333339
return isDeleteQuery;

0 commit comments

Comments
 (0)