Skip to content

Commit 0b45ed0

Browse files
author
Thomas Darimont
committed
DATAMONGO-1188 - Add suport for findAndModify in query derivation.
We now support findAndModify operations on derived query methods.
1 parent 946c6b3 commit 0b45ed0

File tree

10 files changed

+113
-3
lines changed

10 files changed

+113
-3
lines changed

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

+30
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import org.springframework.data.mongodb.core.MongoOperations;
3232
import org.springframework.data.mongodb.core.query.NearQuery;
3333
import org.springframework.data.mongodb.core.query.Query;
34+
import org.springframework.data.mongodb.core.query.Update;
3435
import org.springframework.data.repository.query.ParameterAccessor;
3536
import org.springframework.data.repository.query.RepositoryQuery;
3637
import org.springframework.data.util.CloseableIterator;
@@ -101,6 +102,11 @@ public Object execute(Object[] parameters) {
101102
} else if (method.isSliceQuery()) {
102103
return new SlicedExecution(accessor.getPageable()).execute(query);
103104
} else if (method.isCollectionQuery()) {
105+
106+
if (method.isModifyingQuery()) {
107+
return new UpdatingCollectionExecution(accessor.getPageable(), accessor.getUpdate()).execute(query);
108+
}
109+
104110
return new CollectionExecution(accessor.getPageable()).execute(query);
105111
} else if (method.isPageQuery()) {
106112
return new PagedExecution(accessor.getPageable()).execute(query);
@@ -194,6 +200,30 @@ public Object execute(Query query) {
194200
}
195201
}
196202

203+
/**
204+
* {@link Execution} for collection returning find and update queries.
205+
*
206+
* @author Thomas Darimont
207+
*/
208+
final class UpdatingCollectionExecution extends Execution {
209+
210+
private final Pageable pageable;
211+
private final Update update;
212+
213+
UpdatingCollectionExecution(Pageable pageable, Update update) {
214+
this.pageable = pageable;
215+
this.update = update;
216+
}
217+
218+
@Override
219+
Object execute(Query query) {
220+
221+
MongoEntityMetadata<?> metadata = method.getEntityInformation();
222+
return operations.findAndModify(query.with(pageable), update, metadata.getJavaType(),
223+
metadata.getCollectionName());
224+
}
225+
}
226+
197227
/**
198228
* {@link Execution} for {@link Slice} query methods.
199229
*

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

+8
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import org.springframework.data.mongodb.core.convert.MongoWriter;
3030
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
3131
import org.springframework.data.mongodb.core.query.TextCriteria;
32+
import org.springframework.data.mongodb.core.query.Update;
3233
import org.springframework.data.repository.query.ParameterAccessor;
3334
import org.springframework.data.util.TypeInformation;
3435
import org.springframework.util.Assert;
@@ -255,4 +256,11 @@ public interface PotentiallyConvertingIterator extends Iterator<Object> {
255256
Object nextConverted(MongoPersistentProperty property);
256257
}
257258

259+
/* (non-Javadoc)
260+
* @see org.springframework.data.mongodb.repository.query.MongoParameterAccessor#getUpdate()
261+
*/
262+
@Override
263+
public Update getUpdate() {
264+
return delegate.getUpdate();
265+
}
258266
}

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

+10
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,15 @@
1919
import org.springframework.data.geo.Distance;
2020
import org.springframework.data.geo.Point;
2121
import org.springframework.data.mongodb.core.query.TextCriteria;
22+
import org.springframework.data.mongodb.core.query.Update;
2223
import org.springframework.data.repository.query.ParameterAccessor;
2324

2425
/**
2526
* Mongo-specific {@link ParameterAccessor} exposing a maximum distance parameter.
2627
*
2728
* @author Oliver Gierke
2829
* @author Christoph Strobl
30+
* @author Thomas Darimont
2931
*/
3032
public interface MongoParameterAccessor extends ParameterAccessor {
3133

@@ -51,4 +53,12 @@ public interface MongoParameterAccessor extends ParameterAccessor {
5153
* @since 1.6
5254
*/
5355
TextCriteria getFullText();
56+
57+
/**
58+
* Returns the {@link Update} to be used for findAndUpdate query.
59+
*
60+
* @return
61+
* @since 1.7
62+
*/
63+
Update getUpdate();
5464
}

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

+11-3
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import org.springframework.data.geo.Distance;
2525
import org.springframework.data.geo.Point;
2626
import org.springframework.data.mongodb.core.query.TextCriteria;
27+
import org.springframework.data.mongodb.core.query.Update;
2728
import org.springframework.data.mongodb.repository.Near;
2829
import org.springframework.data.mongodb.repository.query.MongoParameters.MongoParameter;
2930
import org.springframework.data.repository.query.Parameter;
@@ -36,12 +37,14 @@
3637
*
3738
* @author Oliver Gierke
3839
* @author Christoph Strobl
40+
* @author Thomas Darimont
3941
*/
4042
public class MongoParameters extends Parameters<MongoParameters, MongoParameter> {
4143

4244
private final int rangeIndex;
4345
private final int maxDistanceIndex;
4446
private final Integer fullTextIndex;
47+
private final int updateIndex;
4548

4649
private Integer nearIndex;
4750

@@ -63,6 +66,7 @@ public MongoParameters(Method method, boolean isGeoNearMethod) {
6366

6467
this.rangeIndex = getTypeIndex(parameterTypeInfo, Range.class, Distance.class);
6568
this.maxDistanceIndex = this.rangeIndex == -1 ? getTypeIndex(parameterTypeInfo, Distance.class, null) : -1;
69+
this.updateIndex = parameterTypes.indexOf(Update.class);
6670

6771
if (this.nearIndex == null && isGeoNearMethod) {
6872
this.nearIndex = getNearIndex(parameterTypes);
@@ -72,14 +76,15 @@ public MongoParameters(Method method, boolean isGeoNearMethod) {
7276
}
7377

7478
private MongoParameters(List<MongoParameter> parameters, int maxDistanceIndex, Integer nearIndex,
75-
Integer fullTextIndex, int rangeIndex) {
79+
Integer fullTextIndex, int rangeIndex, int updateIndex) {
7680

7781
super(parameters);
7882

7983
this.nearIndex = nearIndex;
8084
this.fullTextIndex = fullTextIndex;
8185
this.maxDistanceIndex = maxDistanceIndex;
8286
this.rangeIndex = rangeIndex;
87+
this.updateIndex = updateIndex;
8388
}
8489

8590
private final int getNearIndex(List<Class<?>> parameterTypes) {
@@ -188,7 +193,8 @@ public int getRangeIndex() {
188193
*/
189194
@Override
190195
protected MongoParameters createFrom(List<MongoParameter> parameters) {
191-
return new MongoParameters(parameters, this.maxDistanceIndex, this.nearIndex, this.fullTextIndex, this.rangeIndex);
196+
return new MongoParameters(parameters, this.maxDistanceIndex, this.nearIndex, this.fullTextIndex, this.rangeIndex,
197+
this.updateIndex);
192198
}
193199

194200
private int getTypeIndex(List<TypeInformation<?>> parameterTypes, Class<?> type, Class<?> componentType) {
@@ -259,7 +265,9 @@ private boolean isPoint() {
259265
private boolean hasNearAnnotation() {
260266
return parameter.getParameterAnnotation(Near.class) != null;
261267
}
262-
263268
}
264269

270+
public int getUpdateIndex() {
271+
return updateIndex;
272+
}
265273
}

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

+9
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import org.springframework.data.geo.Point;
2121
import org.springframework.data.mongodb.core.query.Term;
2222
import org.springframework.data.mongodb.core.query.TextCriteria;
23+
import org.springframework.data.mongodb.core.query.Update;
2324
import org.springframework.data.repository.query.ParametersParameterAccessor;
2425
import org.springframework.util.Assert;
2526
import org.springframework.util.ClassUtils;
@@ -29,6 +30,7 @@
2930
*
3031
* @author Oliver Gierke
3132
* @author Christoph Strobl
33+
* @author Thomas Darimont
3234
*/
3335
public class MongoParametersParameterAccessor extends ParametersParameterAccessor implements MongoParameterAccessor {
3436

@@ -121,4 +123,11 @@ protected TextCriteria potentiallyConvertFullText(Object fullText) {
121123
"Expected full text parameter to be one of String, Term or TextCriteria but found %s.",
122124
ClassUtils.getShortName(fullText.getClass())));
123125
}
126+
127+
@Override
128+
public Update getUpdate() {
129+
130+
int updateIndex = method.getParameters().getUpdateIndex();
131+
return updateIndex == -1 ? null : (Update) getValue(updateIndex);
132+
}
124133
}

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

+8
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import org.springframework.data.mapping.context.MappingContext;
2828
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
2929
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
30+
import org.springframework.data.mongodb.core.query.Update;
3031
import org.springframework.data.mongodb.repository.Meta;
3132
import org.springframework.data.mongodb.repository.Query;
3233
import org.springframework.data.repository.core.RepositoryMetadata;
@@ -233,4 +234,11 @@ public org.springframework.data.mongodb.core.query.Meta getQueryMetaAttributes()
233234

234235
return metaAttributes;
235236
}
237+
238+
@Override
239+
public boolean isModifyingQuery() {
240+
241+
Class<?>[] parameterTypes = this.method.getParameterTypes();
242+
return parameterTypes.length > 0 && parameterTypes[parameterTypes.length - 1] == Update.class;
243+
}
236244
}

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

+17
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
import org.springframework.data.geo.Polygon;
5252
import org.springframework.data.mongodb.core.MongoOperations;
5353
import org.springframework.data.mongodb.core.query.BasicQuery;
54+
import org.springframework.data.mongodb.core.query.Update;
5455
import org.springframework.data.mongodb.repository.Person.Sex;
5556
import org.springframework.data.querydsl.QSort;
5657
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@@ -1183,4 +1184,20 @@ public void executesGeoNearQueryForResultsCorrectlyWhenGivenMinAndMaxDistance()
11831184
GeoResults<Person> results = repository.findPersonByLocationNear(new Point(-73.99, 40.73), range);
11841185
assertThat(results.getContent().isEmpty(), is(false));
11851186
}
1187+
1188+
/**
1189+
* @see DATAMONGO-1188
1190+
*/
1191+
@Test
1192+
public void shouldSupportFindAndModfiyForQueryDerivation() {
1193+
1194+
List<Person> result = repository.findAndModifyByFirstname("Dave", new Update().inc("visits", 42));
1195+
1196+
assertThat(result.size(), is(1));
1197+
assertThat(result.get(0), is(dave));
1198+
1199+
Person dave = repository.findOne(result.get(0).getId());
1200+
1201+
assertThat(dave.visits, is(42));
1202+
}
11861203
}

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

+10
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@ public enum Sex {
6666

6767
Credentials credentials;
6868

69+
int visits;
70+
6971
public Person() {
7072

7173
this(null, null);
@@ -245,6 +247,14 @@ public void setCoworker(User coworker) {
245247
this.coworker = coworker;
246248
}
247249

250+
public int getVisits() {
251+
return visits;
252+
}
253+
254+
public void setVisits(int visits) {
255+
this.visits = visits;
256+
}
257+
248258
/*
249259
* (non-Javadoc)
250260
*

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

+3
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import org.springframework.data.geo.GeoResults;
3333
import org.springframework.data.geo.Point;
3434
import org.springframework.data.geo.Polygon;
35+
import org.springframework.data.mongodb.core.query.Update;
3536
import org.springframework.data.mongodb.repository.Person.Sex;
3637
import org.springframework.data.querydsl.QueryDslPredicateExecutor;
3738

@@ -333,4 +334,6 @@ public interface PersonRepository extends MongoRepository<Person, String>, Query
333334
*/
334335
@Query("{ firstname : { $in : ?0 }}")
335336
Stream<Person> findByCustomQueryWithStreamingCursorByFirstnames(List<String> firstnames);
337+
338+
List<Person> findAndModifyByFirstname(String firstname, Update update);
336339
}

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

+7
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,15 @@
2525
import org.springframework.data.geo.Point;
2626
import org.springframework.data.mongodb.core.convert.MongoWriter;
2727
import org.springframework.data.mongodb.core.query.TextCriteria;
28+
import org.springframework.data.mongodb.core.query.Update;
2829
import org.springframework.data.repository.query.ParameterAccessor;
2930

3031
/**
3132
* Simple {@link ParameterAccessor} that returns the given parameters unfiltered.
3233
*
3334
* @author Oliver Gierke
3435
* @author Christoh Strobl
36+
* @author Thomas Darimont
3537
*/
3638
class StubParameterAccessor implements MongoParameterAccessor {
3739

@@ -129,4 +131,9 @@ public Point getGeoNearLocation() {
129131
public TextCriteria getFullText() {
130132
return null;
131133
}
134+
135+
@Override
136+
public Update getUpdate() {
137+
return null;
138+
}
132139
}

0 commit comments

Comments
 (0)