Skip to content

Commit

Permalink
Reduce method signatures in Reactive-/MongoOperations and add fluent …
Browse files Browse the repository at this point in the history
…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
  • Loading branch information
christophstrobl committed Sep 11, 2023
1 parent ea07e83 commit b4133c0
Show file tree
Hide file tree
Showing 9 changed files with 77 additions and 96 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,7 @@ public UpdateResult upsert() {

@Override
public UpdateResult replaceFirst() {

if (replacement != null) {
return template.replace(query, domainType, replacement,
findAndReplaceOptions != null ? findAndReplaceOptions : ReplaceOptions.none(), getCollectionName());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1783,8 +1783,6 @@ default <T> UpdateResult replace(Query query, T replacement) {
* @param replacement the replacement document. 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.
* @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 <T> UpdateResult replace(Query query, T replacement, String collectionName) {
Expand Down Expand Up @@ -1819,52 +1817,9 @@ default <T> UpdateResult replace(Query query, T replacement, ReplaceOptions opti
* @param replacement the replacement document. 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.
* @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 <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);
<T> UpdateResult replace(Query query, T replacement, ReplaceOptions options, String collectionName);

/**
* Returns the underlying {@link MongoConverter}.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2069,7 +2069,13 @@ public <T> List<T> findAllAndRemove(Query query, Class<T> entityClass, String co
}

@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) {

Assert.notNull(query, "Query must not be null");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1668,8 +1668,6 @@ default <T> Mono<UpdateResult> replace(Query query, T replacement) {
* @param replacement the replacement document. 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.
* @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 <T> Mono<UpdateResult> replace(Query query, T replacement, String collectionName) {
Expand Down Expand Up @@ -1708,48 +1706,7 @@ default <T> Mono<UpdateResult> replace(Query query, T replacement, ReplaceOption
* {@link #getCollectionName(Class) derived} from the given replacement value.
* @since 4.2
*/
default <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);
<T> Mono<UpdateResult> replace(Query query, 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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1961,7 +1961,13 @@ public <T> Flux<T> findAllAndRemove(Query query, Class<T> entityClass, String co
}

@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) {

MongoPersistentEntity<?> entity = mappingContext.getPersistentEntity(entityType);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,13 +72,30 @@ interface TerminatingFindAndModify<T> {
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.
*
* @author Mark Paluch
* @since 2.1
*/
interface TerminatingFindAndReplace<T> {
interface TerminatingFindAndReplace<T> extends TerminatingReplace {

/**
* Find, replace and return the first matching document.
Expand Down Expand Up @@ -202,14 +219,30 @@ interface FindAndModifyWithOptions<T> {
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}.
*
* @author Mark Paluch
* @author Christoph Strobl
* @since 2.1
*/
interface FindAndReplaceWithOptions<T> extends TerminatingFindAndReplace<T> {
interface FindAndReplaceWithOptions<T> extends TerminatingFindAndReplace<T>, ReplaceWithOptions {

/**
* Explicitly define {@link FindAndReplaceOptions} for the {@link Update}.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,17 @@ public FindAndReplaceWithProjection<T> withOptions(FindAndReplaceOptions options
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
public <R> FindAndReplaceWithOptions<R> as(Class<R> resultType) {

Expand All @@ -174,6 +185,18 @@ public <R> FindAndReplaceWithOptions<R> as(Class<R> 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) {
return template.doUpdate(getCollectionName(), query, update, domainType, upsert, multi);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ void replacesExistingDocumentWithRawDoc() {
void replacesExistingDocumentWithRawDocMappingQueryAgainstDomainType() {

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.getModifiedCount()).isEqualTo(1);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ void replacesExistingDocumentWithRawDoc() {
void replacesExistingDocumentWithRawDocMappingQueryAgainstDomainType() {

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 -> {
assertThat(it.getMatchedCount()).isEqualTo(1);
Expand Down

0 comments on commit b4133c0

Please sign in to comment.