Browse Source

Reduce method signatures in Reactive-/MongoOperations and add fluent reactive api variant.

Narrow the scope of exposed methods on MongoOperations interface. The broader replace API variant has been moved to a protected method allowing users to hook into the implementation and (if needed) expose it.

See: #4462
Original Pull Request: #4463
pull/4498/head
Christoph Strobl 2 years ago
parent
commit
b4133c03e2
No known key found for this signature in database
GPG Key ID: 8CC1AB53391458C8
  1. 1
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ExecutableUpdateOperationSupport.java
  2. 47
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoOperations.java
  3. 8
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java
  4. 45
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReactiveMongoOperations.java
  5. 8
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReactiveMongoTemplate.java
  6. 37
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReactiveUpdateOperation.java
  7. 23
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReactiveUpdateOperationSupport.java
  8. 2
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoTemplateReplaceTests.java
  9. 2
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/ReactiveMongoTemplateReplaceTests.java

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

@ -188,6 +188,7 @@ class ExecutableUpdateOperationSupport implements ExecutableUpdateOperation {
@Override @Override
public UpdateResult replaceFirst() { public UpdateResult replaceFirst() {
if (replacement != null) { if (replacement != null) {
return template.replace(query, domainType, replacement, return template.replace(query, domainType, replacement,
findAndReplaceOptions != null ? findAndReplaceOptions : ReplaceOptions.none(), getCollectionName()); findAndReplaceOptions != null ? findAndReplaceOptions : ReplaceOptions.none(), getCollectionName());

47
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoOperations.java

@ -1783,8 +1783,6 @@ public interface MongoOperations extends FluentMongoOperations {
* @param replacement the replacement document. Must not be {@literal null}. * @param replacement the replacement document. Must not be {@literal null}.
* @param collectionName the collection to query. Must not be {@literal null}. * @param collectionName the collection to query. Must not be {@literal null}.
* @return the {@link UpdateResult} which lets you access the results of the previous replacement. * @return the {@link UpdateResult} which lets you access the results of the previous replacement.
* @throws org.springframework.data.mapping.MappingException if the collection name cannot be
* {@link #getCollectionName(Class) derived} from the given replacement value.
* @since 4.2 * @since 4.2
*/ */
default <T> UpdateResult replace(Query query, T replacement, String collectionName) { default <T> UpdateResult replace(Query query, T replacement, String collectionName) {
@ -1819,52 +1817,9 @@ public interface MongoOperations extends FluentMongoOperations {
* @param replacement the replacement document. Must not be {@literal null}. * @param replacement the replacement document. Must not be {@literal null}.
* @param options the {@link ReplaceOptions} holding additional information. Must not be {@literal null}. * @param options the {@link ReplaceOptions} holding additional information. Must not be {@literal null}.
* @return the {@link UpdateResult} which lets you access the results of the previous replacement. * @return the {@link UpdateResult} which lets you access the results of the previous replacement.
* @throws org.springframework.data.mapping.MappingException if the collection name cannot be
* {@link #getCollectionName(Class) derived} from the given replacement value.
* @since 4.2 * @since 4.2
*/ */
default <T> UpdateResult replace(Query query, T replacement, ReplaceOptions options, String collectionName) { <T> UpdateResult replace(Query query, T replacement, ReplaceOptions options, String collectionName);
Assert.notNull(replacement, "Replacement must not be null");
return replace(query, (Class<T>) ClassUtils.getUserClass(replacement), replacement, options, collectionName);
}
/**
* Replace a single document matching the {@link Criteria} of given {@link Query} with the {@code replacement}
* document taking {@link ReplaceOptions} into account.
*
* @param query the {@link Query} class that specifies the {@link Criteria} used to find a document. The query may
* contain an index {@link Query#withHint(String) hint} or the {@link Query#collation(Collation) collation}
* to use. Must not be {@literal null}.
* @param entityType the type used for mapping the {@link Query} to domain type fields and deriving the collection
* @param replacement the replacement document. Must not be {@literal null}.
* @param options the {@link ReplaceOptions} holding additional information. Must not be {@literal null}.
* from. Must not be {@literal null}.
* @return the {@link UpdateResult} which lets you access the results of the previous replacement.
* @throws org.springframework.data.mapping.MappingException if the collection name cannot be
* {@link #getCollectionName(Class) derived} from the given replacement value.
* @since 4.2
*/
default <S,T> UpdateResult replace(Query query, Class<S> entityType, T replacement, ReplaceOptions options) {
return replace(query, entityType, replacement, options, getCollectionName(ClassUtils.getUserClass(entityType)));
}
/**
* Replace a single document matching the {@link Criteria} of given {@link Query} with the {@code replacement}
* document taking {@link ReplaceOptions} into account.
*
* @param query the {@link Query} class that specifies the {@link Criteria} used to find a document. The query may
* contain an index {@link Query#withHint(String) hint} or the {@link Query#collation(Collation) collation}
* to use. Must not be {@literal null}.
* @param entityType the type used for mapping the {@link Query} to domain type fields. Must not be {@literal null}.
* @param replacement the replacement document. Must not be {@literal null}.
* @param options the {@link ReplaceOptions} holding additional information. Must not be {@literal null}.
* @param collectionName the collection to query. Must not be {@literal null}.
* @return the {@link UpdateResult} which lets you access the results of the previous replacement.
* @since 4.2
*/
<S,T> UpdateResult replace(Query query, Class<S> entityType, T replacement, ReplaceOptions options,
String collectionName);
/** /**
* Returns the underlying {@link MongoConverter}. * Returns the underlying {@link MongoConverter}.

8
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java

@ -2069,7 +2069,13 @@ public class MongoTemplate
} }
@Override @Override
public <S, T> UpdateResult replace(Query query, Class<S> entityType, T replacement, ReplaceOptions options, public <T> UpdateResult replace(Query query, T replacement, ReplaceOptions options, String collectionName){
Assert.notNull(replacement, "Replacement must not be null");
return replace(query, (Class<T>) ClassUtils.getUserClass(replacement), replacement, options, collectionName);
}
protected <S, T> UpdateResult replace(Query query, Class<S> entityType, T replacement, ReplaceOptions options,
String collectionName) { String collectionName) {
Assert.notNull(query, "Query must not be null"); Assert.notNull(query, "Query must not be null");

45
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReactiveMongoOperations.java

@ -1668,8 +1668,6 @@ public interface ReactiveMongoOperations extends ReactiveFluentMongoOperations {
* @param replacement the replacement document. Must not be {@literal null}. * @param replacement the replacement document. Must not be {@literal null}.
* @param collectionName the collection to query. Must not be {@literal null}. * @param collectionName the collection to query. Must not be {@literal null}.
* @return the {@link UpdateResult} which lets you access the results of the previous replacement. * @return the {@link UpdateResult} which lets you access the results of the previous replacement.
* @throws org.springframework.data.mapping.MappingException if the collection name cannot be
* {@link #getCollectionName(Class) derived} from the given replacement value.
* @since 4.2 * @since 4.2
*/ */
default <T> Mono<UpdateResult> replace(Query query, T replacement, String collectionName) { default <T> Mono<UpdateResult> replace(Query query, T replacement, String collectionName) {
@ -1708,48 +1706,7 @@ public interface ReactiveMongoOperations extends ReactiveFluentMongoOperations {
* {@link #getCollectionName(Class) derived} from the given replacement value. * {@link #getCollectionName(Class) derived} from the given replacement value.
* @since 4.2 * @since 4.2
*/ */
default <T> Mono<UpdateResult> replace(Query query, T replacement, ReplaceOptions options, String collectionName) { <T> Mono<UpdateResult> replace(Query query, T replacement, ReplaceOptions options, String collectionName);
Assert.notNull(replacement, "Replacement must not be null");
return replace(query, (Class<T>) ClassUtils.getUserClass(replacement), replacement, options, collectionName);
}
/**
* Replace a single document matching the {@link Criteria} of given {@link Query} with the {@code replacement}
* document taking {@link ReplaceOptions} into account.
*
* @param query the {@link Query} class that specifies the {@link Criteria} used to find a document. The query may
* contain an index {@link Query#withHint(String) hint} or the {@link Query#collation(Collation) collation}
* to use. Must not be {@literal null}.
* @param entityType the type used for mapping the {@link Query} to domain type fields and deriving the collection
* @param replacement the replacement document. Must not be {@literal null}.
* @param options the {@link ReplaceOptions} holding additional information. Must not be {@literal null}.
* from. Must not be {@literal null}.
* @return the {@link UpdateResult} which lets you access the results of the previous replacement.
* @throws org.springframework.data.mapping.MappingException if the collection name cannot be
* {@link #getCollectionName(Class) derived} from the given replacement value.
* @since 4.2
*/
default <S,T> Mono<UpdateResult> replace(Query query, Class<S> entityType, T replacement, ReplaceOptions options) {
return replace(query, entityType, replacement, options, getCollectionName(ClassUtils.getUserClass(entityType)));
}
/**
* Replace a single document matching the {@link Criteria} of given {@link Query} with the {@code replacement}
* document taking {@link ReplaceOptions} into account.
*
* @param query the {@link Query} class that specifies the {@link Criteria} used to find a document. The query may
* contain an index {@link Query#withHint(String) hint} or the {@link Query#collation(Collation) collation}
* to use. Must not be {@literal null}.
* @param entityType the type used for mapping the {@link Query} to domain type fields. Must not be {@literal null}.
* @param replacement the replacement document. Must not be {@literal null}.
* @param options the {@link ReplaceOptions} holding additional information. Must not be {@literal null}.
* @param collectionName the collection to query. Must not be {@literal null}.
* @return the {@link UpdateResult} which lets you access the results of the previous replacement.
* @since 4.2
*/
<S,T> Mono<UpdateResult> replace(Query query, Class<S> entityType, T replacement, ReplaceOptions options,
String collectionName);
/** /**
* Map the results of an ad-hoc query on the collection for the entity class to a stream of objects of the specified * Map the results of an ad-hoc query on the collection for the entity class to a stream of objects of the specified

8
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReactiveMongoTemplate.java

@ -1961,7 +1961,13 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
} }
@Override @Override
public <S,T> Mono<UpdateResult> replace(Query query, Class<S> entityType, T replacement, ReplaceOptions options, public <T> Mono<UpdateResult> replace(Query query, T replacement, ReplaceOptions options, String collectionName) {
Assert.notNull(replacement, "Replacement must not be null");
return replace(query, (Class<T>) ClassUtils.getUserClass(replacement), replacement, options, collectionName);
}
protected <S,T> Mono<UpdateResult> replace(Query query, Class<S> entityType, T replacement, ReplaceOptions options,
String collectionName) { String collectionName) {
MongoPersistentEntity<?> entity = mappingContext.getPersistentEntity(entityType); MongoPersistentEntity<?> entity = mappingContext.getPersistentEntity(entityType);

37
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReactiveUpdateOperation.java

@ -72,13 +72,30 @@ public interface ReactiveUpdateOperation {
Mono<T> findAndModify(); Mono<T> findAndModify();
} }
/**
* Trigger <a href="https://docs.mongodb.com/manual/reference/method/db.collection.replaceOne/">replaceOne</a>
* execution by calling one of the terminating methods.
*
* @author Christoph Strobl
* @since 4.2
*/
interface TerminatingReplace {
/**
* Find first and replace/upsert.
*
* @return never {@literal null}.
*/
Mono<UpdateResult> replaceFirst();
}
/** /**
* Compose findAndReplace execution by calling one of the terminating methods. * Compose findAndReplace execution by calling one of the terminating methods.
* *
* @author Mark Paluch * @author Mark Paluch
* @since 2.1 * @since 2.1
*/ */
interface TerminatingFindAndReplace<T> { interface TerminatingFindAndReplace<T> extends TerminatingReplace {
/** /**
* Find, replace and return the first matching document. * Find, replace and return the first matching document.
@ -202,6 +219,22 @@ public interface ReactiveUpdateOperation {
TerminatingFindAndModify<T> withOptions(FindAndModifyOptions options); TerminatingFindAndModify<T> withOptions(FindAndModifyOptions options);
} }
/**
* @author Christoph Strobl
* @since 4.2
*/
interface ReplaceWithOptions extends TerminatingReplace {
/**
* Explicitly define {@link ReplaceOptions}.
*
* @param options must not be {@literal null}.
* @return new instance of {@link FindAndReplaceOptions}.
* @throws IllegalArgumentException if options is {@literal null}.
*/
TerminatingReplace withOptions(ReplaceOptions options);
}
/** /**
* Define {@link FindAndReplaceOptions}. * Define {@link FindAndReplaceOptions}.
* *
@ -209,7 +242,7 @@ public interface ReactiveUpdateOperation {
* @author Christoph Strobl * @author Christoph Strobl
* @since 2.1 * @since 2.1
*/ */
interface FindAndReplaceWithOptions<T> extends TerminatingFindAndReplace<T> { interface FindAndReplaceWithOptions<T> extends TerminatingFindAndReplace<T>, ReplaceWithOptions {
/** /**
* Explicitly define {@link FindAndReplaceOptions} for the {@link Update}. * Explicitly define {@link FindAndReplaceOptions} for the {@link Update}.

23
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReactiveUpdateOperationSupport.java

@ -165,6 +165,17 @@ class ReactiveUpdateOperationSupport implements ReactiveUpdateOperation {
replacement, targetType); replacement, targetType);
} }
@Override
public TerminatingReplace withOptions(ReplaceOptions options) {
FindAndReplaceOptions target = new FindAndReplaceOptions();
if (options.isUpsert()) {
target.upsert();
}
return new ReactiveUpdateSupport<>(template, domainType, query, update, collection, findAndModifyOptions,
target, replacement, targetType);
}
@Override @Override
public <R> FindAndReplaceWithOptions<R> as(Class<R> resultType) { public <R> FindAndReplaceWithOptions<R> as(Class<R> resultType) {
@ -174,6 +185,18 @@ class ReactiveUpdateOperationSupport implements ReactiveUpdateOperation {
findAndReplaceOptions, replacement, resultType); findAndReplaceOptions, replacement, resultType);
} }
@Override
public Mono <UpdateResult> replaceFirst() {
if (replacement != null) {
return template.replace(query, domainType, replacement,
findAndReplaceOptions != null ? findAndReplaceOptions : ReplaceOptions.none(), getCollectionName());
}
return template.replace(query, domainType, update,
findAndReplaceOptions != null ? findAndReplaceOptions : ReplaceOptions.none(), getCollectionName());
}
private Mono<UpdateResult> doUpdate(boolean multi, boolean upsert) { private Mono<UpdateResult> doUpdate(boolean multi, boolean upsert) {
return template.doUpdate(getCollectionName(), query, update, domainType, upsert, multi); return template.doUpdate(getCollectionName(), query, update, domainType, upsert, multi);
} }

2
spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoTemplateReplaceTests.java

@ -114,7 +114,7 @@ public class MongoTemplateReplaceTests {
void replacesExistingDocumentWithRawDocMappingQueryAgainstDomainType() { void replacesExistingDocumentWithRawDocMappingQueryAgainstDomainType() {
UpdateResult result = template.replace(query(where("name").is("Central Perk Cafe")), Restaurant.class, UpdateResult result = template.replace(query(where("name").is("Central Perk Cafe")), Restaurant.class,
Document.parse("{ 'r-name' : 'Central Pork Cafe', 'Borough' : 'Manhattan' }"), ReplaceOptions.none()); Document.parse("{ 'r-name' : 'Central Pork Cafe', 'Borough' : 'Manhattan' }"), ReplaceOptions.none(), template.getCollectionName(Restaurant.class));
assertThat(result.getMatchedCount()).isEqualTo(1); assertThat(result.getMatchedCount()).isEqualTo(1);
assertThat(result.getModifiedCount()).isEqualTo(1); assertThat(result.getModifiedCount()).isEqualTo(1);

2
spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/ReactiveMongoTemplateReplaceTests.java

@ -128,7 +128,7 @@ public class ReactiveMongoTemplateReplaceTests {
void replacesExistingDocumentWithRawDocMappingQueryAgainstDomainType() { void replacesExistingDocumentWithRawDocMappingQueryAgainstDomainType() {
Mono<UpdateResult> result = template.replace(query(where("name").is("Central Perk Cafe")), Restaurant.class, Mono<UpdateResult> result = template.replace(query(where("name").is("Central Perk Cafe")), Restaurant.class,
Document.parse("{ 'r-name' : 'Central Pork Cafe', 'Borough' : 'Manhattan' }"), ReplaceOptions.none()); Document.parse("{ 'r-name' : 'Central Pork Cafe', 'Borough' : 'Manhattan' }"), ReplaceOptions.none(), template.getCollectionName(Restaurant.class));
result.as(StepVerifier::create).consumeNextWith(it -> { result.as(StepVerifier::create).consumeNextWith(it -> {
assertThat(it.getMatchedCount()).isEqualTo(1); assertThat(it.getMatchedCount()).isEqualTo(1);

Loading…
Cancel
Save