Browse Source

Support hints on `Update`.

This commit makes sure to read query hints and apply them to the MongoDB UpdateOptions when running an update via Reactive-/MongoTemplate.

Original pull request: #4311
Closes: #3218
pull/4323/head
Christoph Strobl 3 years ago committed by Mark Paluch
parent
commit
cd63501680
No known key found for this signature in database
GPG Key ID: 4406B84C1661DCD1
  1. 18
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/HintFunction.java
  2. 1
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/QueryOperations.java
  3. 22
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoTemplateUnitTests.java
  4. 21
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/ReactiveMongoTemplateUnitTests.java
  5. 1
      src/main/asciidoc/reference/mongodb.adoc

18
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/HintFunction.java

@ -27,6 +27,7 @@ import org.springframework.util.StringUtils; @@ -27,6 +27,7 @@ import org.springframework.util.StringUtils;
* Function object to apply a query hint. Can be an index name or a BSON document.
*
* @author Mark Paluch
* @author Christoph Strobl
* @since 4.1
*/
class HintFunction {
@ -67,6 +68,23 @@ class HintFunction { @@ -67,6 +68,23 @@ class HintFunction {
return (hint instanceof String hintString && StringUtils.hasText(hintString)) || hint instanceof Bson;
}
/**
* Apply the hint to consumers depending on the hint format if {@link #isPresent() present}.
*
* @param registryProvider
* @param stringConsumer
* @param bsonConsumer
* @param <R>
*/
public <R> void ifPresent(@Nullable CodecRegistryProvider registryProvider, Function<String, R> stringConsumer,
Function<Bson, R> bsonConsumer) {
if (!isPresent()) {
return;
}
apply(registryProvider, stringConsumer, bsonConsumer);
}
/**
* Apply the hint to consumers depending on the hint format.
*

1
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/QueryOperations.java

@ -715,6 +715,7 @@ class QueryOperations { @@ -715,6 +715,7 @@ class QueryOperations {
.arrayFilters(update.getArrayFilters().stream().map(ArrayFilter::asDocument).collect(Collectors.toList()));
}
HintFunction.from(getQuery().getHint()).ifPresent(codecRegistryProvider, options::hintString, options::hint);
applyCollation(domainType, options::collation);
if (callback != null) {

22
spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoTemplateUnitTests.java

@ -978,6 +978,28 @@ public class MongoTemplateUnitTests extends MongoOperationsUnitTests { @@ -978,6 +978,28 @@ public class MongoTemplateUnitTests extends MongoOperationsUnitTests {
assertThat(options.getValue().getCollation().getLocale()).isEqualTo("fr");
}
@Test // GH-3218
void updateUsesHintStringFromQuery() {
template.updateFirst(new Query().withHint("index-1"), new Update().set("spring", "data"), Human.class);
ArgumentCaptor<UpdateOptions> options = ArgumentCaptor.forClass(UpdateOptions.class);
verify(collection).updateOne(any(Bson.class), any(Bson.class), options.capture());
assertThat(options.getValue().getHintString()).isEqualTo("index-1");
}
@Test // GH-3218
void updateUsesHintDocumentFromQuery() {
template.updateFirst(new Query().withHint("{ name : 1 }"), new Update().set("spring", "data"), Human.class);
ArgumentCaptor<UpdateOptions> options = ArgumentCaptor.forClass(UpdateOptions.class);
verify(collection).updateOne(any(Bson.class), any(Bson.class), options.capture());
assertThat(options.getValue().getHint()).isEqualTo(new Document("name", 1));
}
@Test // DATAMONGO-1518
void replaceOneShouldUseCollationWhenPresent() {

21
spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/ReactiveMongoTemplateUnitTests.java

@ -350,7 +350,28 @@ public class ReactiveMongoTemplateUnitTests { @@ -350,7 +350,28 @@ public class ReactiveMongoTemplateUnitTests {
verify(collection).updateMany(any(), any(Bson.class), options.capture());
assertThat(options.getValue().getCollation().getLocale()).isEqualTo("fr");
}
@Test // GH-3218
void updateUsesHintStringFromQuery() {
template.updateFirst(new Query().withHint("index-1"), new Update().set("spring", "data"), Person.class).subscribe();
ArgumentCaptor<UpdateOptions> options = ArgumentCaptor.forClass(UpdateOptions.class);
verify(collection).updateOne(any(Bson.class), any(Bson.class), options.capture());
assertThat(options.getValue().getHintString()).isEqualTo("index-1");
}
@Test // GH-3218
void updateUsesHintDocumentFromQuery() {
template.updateFirst(new Query().withHint("{ firstname : 1 }"), new Update().set("spring", "data"), Person.class).subscribe();
ArgumentCaptor<UpdateOptions> options = ArgumentCaptor.forClass(UpdateOptions.class);
verify(collection).updateOne(any(Bson.class), any(Bson.class), options.capture());
assertThat(options.getValue().getHint()).isEqualTo(new Document("firstname", 1));
}
@Test // DATAMONGO-1518

1
src/main/asciidoc/reference/mongodb.adoc

@ -922,6 +922,7 @@ Most methods return the `Update` object to provide a fluent style for the API. @@ -922,6 +922,7 @@ Most methods return the `Update` object to provide a fluent style for the API.
* *updateMulti*: Updates all objects that match the query document criteria with the updated document.
WARNING: `updateFirst` does not support ordering. Please use <<mongo-template.find-and-upsert, findAndModify>> to apply `Sort`.
NOTE: Index hints for the update operation can be provided via `Query.withHint(...)`.
[[mongodb-template-update.update]]
==== Methods in the `Update` Class

Loading…
Cancel
Save