Pass on FullDocumentBeforeChange option to change stream iterable/publisher.

This commit ensures to pass on a potentially set FullDocumentBeforeChange option to the change stream iterable/publisher.
It also corrects false optional behavior within the change stream task which did some defaulting though the actual value is an optional one that must not be present.

Original pull request: #4541
Closes #4495
This commit is contained in:
Christoph Strobl
2023-11-02 11:41:19 +01:00
committed by Mark Paluch
parent 69285151a0
commit bf54054ad5
5 changed files with 50 additions and 10 deletions

View File

@@ -168,6 +168,7 @@ class ReactiveChangeStreamOperationSupport implements ReactiveChangeStreamOperat
}
});
options.getFullDocumentLookup().ifPresent(builder::fullDocumentLookup);
options.getFullDocumentBeforeChangeLookup().ifPresent(builder::fullDocumentBeforeChangeLookup);
options.getCollation().ifPresent(builder::collation);
if (options.isResumeAfter()) {

View File

@@ -2050,6 +2050,10 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
publisher = options.getCollation().map(Collation::toMongoCollation).map(publisher::collation)
.orElse(publisher);
publisher = options.getResumeBsonTimestamp().map(publisher::startAtOperationTime).orElse(publisher);
if(options.getFullDocumentBeforeChangeLookup().isPresent()) {
publisher = publisher.fullDocumentBeforeChange(options.getFullDocumentBeforeChangeLookup().get());
}
return publisher.fullDocument(options.getFullDocumentLookup().orElse(fullDocument));
}) //
.flatMapMany(publisher -> Flux.from(publisher)

View File

@@ -37,7 +37,6 @@ import org.springframework.data.mongodb.core.aggregation.TypeBasedAggregationOpe
import org.springframework.data.mongodb.core.aggregation.TypedAggregation;
import org.springframework.data.mongodb.core.convert.MongoConverter;
import org.springframework.data.mongodb.core.convert.QueryMapper;
import org.springframework.data.mongodb.core.messaging.ChangeStreamRequest.ChangeStreamRequestOptions;
import org.springframework.data.mongodb.core.messaging.Message.MessageProperties;
import org.springframework.data.mongodb.core.messaging.SubscriptionRequest.RequestOptions;
import org.springframework.lang.Nullable;
@@ -88,7 +87,7 @@ class ChangeStreamTask extends CursorReadingTask<ChangeStreamDocument<Document>,
Collation collation = null;
FullDocument fullDocument = ClassUtils.isAssignable(Document.class, targetType) ? FullDocument.DEFAULT
: FullDocument.UPDATE_LOOKUP;
FullDocumentBeforeChange fullDocumentBeforeChange = FullDocumentBeforeChange.DEFAULT;
FullDocumentBeforeChange fullDocumentBeforeChange = null;
BsonTimestamp startAt = null;
boolean resumeAfter = true;
@@ -116,8 +115,9 @@ class ChangeStreamTask extends CursorReadingTask<ChangeStreamDocument<Document>,
.orElseGet(() -> ClassUtils.isAssignable(Document.class, targetType) ? FullDocument.DEFAULT
: FullDocument.UPDATE_LOOKUP);
fullDocumentBeforeChange = changeStreamOptions.getFullDocumentBeforeChangeLookup()
.orElse(FullDocumentBeforeChange.DEFAULT);
if(changeStreamOptions.getFullDocumentBeforeChangeLookup().isPresent()) {
fullDocumentBeforeChange = changeStreamOptions.getFullDocumentBeforeChangeLookup().get();
}
startAt = changeStreamOptions.getResumeBsonTimestamp().orElse(null);
}
@@ -158,7 +158,9 @@ class ChangeStreamTask extends CursorReadingTask<ChangeStreamDocument<Document>,
}
iterable = iterable.fullDocument(fullDocument);
iterable = iterable.fullDocumentBeforeChange(fullDocumentBeforeChange);
if(fullDocumentBeforeChange != null) {
iterable = iterable.fullDocumentBeforeChange(fullDocumentBeforeChange);
}
return iterable.iterator();
}

View File

@@ -20,8 +20,6 @@ import static org.mockito.Mockito.*;
import static org.springframework.data.mongodb.core.aggregation.Aggregation.*;
import static org.springframework.data.mongodb.test.util.Assertions.assertThat;
import com.mongodb.WriteConcern;
import org.springframework.data.mongodb.core.MongoTemplateUnitTests.Sith;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.test.StepVerifier;
@@ -101,6 +99,7 @@ import org.springframework.util.CollectionUtils;
import com.mongodb.MongoClientSettings;
import com.mongodb.ReadConcern;
import com.mongodb.ReadPreference;
import com.mongodb.WriteConcern;
import com.mongodb.client.model.CountOptions;
import com.mongodb.client.model.CreateCollectionOptions;
import com.mongodb.client.model.DeleteOptions;
@@ -110,6 +109,7 @@ import com.mongodb.client.model.FindOneAndUpdateOptions;
import com.mongodb.client.model.ReplaceOptions;
import com.mongodb.client.model.TimeSeriesGranularity;
import com.mongodb.client.model.UpdateOptions;
import com.mongodb.client.model.changestream.FullDocumentBeforeChange;
import com.mongodb.client.result.DeleteResult;
import com.mongodb.client.result.InsertManyResult;
import com.mongodb.client.result.InsertOneResult;
@@ -1604,6 +1604,25 @@ public class ReactiveMongoTemplateUnitTests {
verify(changeStreamPublisher).startAfter(eq(token));
}
@Test // GH-4495
void changeStreamOptionFullDocumentBeforeChangeShouldBeApplied() {
when(factory.getMongoDatabase(anyString())).thenReturn(Mono.just(db));
when(collection.watch(any(Class.class))).thenReturn(changeStreamPublisher);
when(changeStreamPublisher.batchSize(anyInt())).thenReturn(changeStreamPublisher);
when(changeStreamPublisher.startAfter(any())).thenReturn(changeStreamPublisher);
when(changeStreamPublisher.fullDocument(any())).thenReturn(changeStreamPublisher);
when(changeStreamPublisher.fullDocumentBeforeChange(any())).thenReturn(changeStreamPublisher);
template
.changeStream("database", "collection", ChangeStreamOptions.builder().fullDocumentBeforeChangeLookup(FullDocumentBeforeChange.REQUIRED).build(), Object.class)
.subscribe();
verify(changeStreamPublisher).fullDocumentBeforeChange(eq(FullDocumentBeforeChange.REQUIRED));
}
@Test // GH-4462
void replaceShouldUseCollationWhenPresent() {

View File

@@ -27,7 +27,6 @@ import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
import org.springframework.data.mongodb.core.convert.MongoConverter;
@@ -39,6 +38,7 @@ import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoCursor;
import com.mongodb.client.MongoDatabase;
import com.mongodb.client.model.changestream.ChangeStreamDocument;
import com.mongodb.client.model.changestream.FullDocumentBeforeChange;
/**
* @author Christoph Strobl
@@ -68,8 +68,6 @@ class ChangeStreamTaskUnitTests {
when(mongoCollection.watch(eq(Document.class))).thenReturn(changeStreamIterable);
when(changeStreamIterable.fullDocument(any())).thenReturn(changeStreamIterable);
when(changeStreamIterable.fullDocumentBeforeChange(any())).thenReturn(changeStreamIterable);
}
@Test // DATAMONGO-2258
@@ -125,6 +123,22 @@ class ChangeStreamTaskUnitTests {
verify(changeStreamIterable).startAfter(eq(resumeToken));
}
@Test // GH-4495
void shouldApplyFullDocumentBeforeChangeToChangeStream() {
when(changeStreamIterable.fullDocumentBeforeChange(any())).thenReturn(changeStreamIterable);
ChangeStreamRequest request = ChangeStreamRequest.builder() //
.collection("start-wars") //
.fullDocumentBeforeChangeLookup(FullDocumentBeforeChange.REQUIRED) //
.publishTo(message -> {}) //
.build();
initTask(request, Document.class);
verify(changeStreamIterable).fullDocumentBeforeChange(eq(FullDocumentBeforeChange.REQUIRED));
}
private MongoCursor<ChangeStreamDocument<Document>> initTask(ChangeStreamRequest request, Class<?> targetType) {
ChangeStreamTask task = new ChangeStreamTask(template, request, targetType, er -> {});