diff --git a/Firestore/Example/Tests/Model/FSTMutationTests.mm b/Firestore/Example/Tests/Model/FSTMutationTests.mm index 9794930b7b6..4d00c16ef5d 100644 --- a/Firestore/Example/Tests/Model/FSTMutationTests.mm +++ b/Firestore/Example/Tests/Model/FSTMutationTests.mm @@ -60,7 +60,8 @@ - (void)testAppliesSetsToDocuments { FSTDocument *baseDoc = FSTTestDoc("collection/key", 0, docData, NO); FSTMutation *set = FSTTestSetMutation(@"collection/key", @{@"bar" : @"bar-value"}); - FSTMaybeDocument *setDoc = [set applyTo:baseDoc baseDocument:baseDoc localWriteTime:_timestamp]; + FSTMaybeDocument *setDoc = + [set applyToLocalDocument:baseDoc baseDocument:baseDoc localWriteTime:_timestamp]; NSDictionary *expectedData = @{@"bar" : @"bar-value"}; XCTAssertEqualObjects(setDoc, FSTTestDoc("collection/key", 0, expectedData, YES)); @@ -72,7 +73,7 @@ - (void)testAppliesPatchesToDocuments { FSTMutation *patch = FSTTestPatchMutation("collection/key", @{@"foo.bar" : @"new-bar-value"}, {}); FSTMaybeDocument *patchedDoc = - [patch applyTo:baseDoc baseDocument:baseDoc localWriteTime:_timestamp]; + [patch applyToLocalDocument:baseDoc baseDocument:baseDoc localWriteTime:_timestamp]; NSDictionary *expectedData = @{@"foo" : @{@"bar" : @"new-bar-value"}, @"baz" : @"baz-value"}; XCTAssertEqualObjects(patchedDoc, FSTTestDoc("collection/key", 0, expectedData, YES)); @@ -88,7 +89,7 @@ - (void)testDeletesValuesFromTheFieldMask { value:[FSTObjectValue objectValue] precondition:Precondition::None()]; FSTMaybeDocument *patchedDoc = - [patch applyTo:baseDoc baseDocument:baseDoc localWriteTime:_timestamp]; + [patch applyToLocalDocument:baseDoc baseDocument:baseDoc localWriteTime:_timestamp]; NSDictionary *expectedData = @{@"foo" : @{@"baz" : @"baz-value"}}; XCTAssertEqualObjects(patchedDoc, FSTTestDoc("collection/key", 0, expectedData, YES)); @@ -100,7 +101,7 @@ - (void)testPatchesPrimitiveValue { FSTMutation *patch = FSTTestPatchMutation("collection/key", @{@"foo.bar" : @"new-bar-value"}, {}); FSTMaybeDocument *patchedDoc = - [patch applyTo:baseDoc baseDocument:baseDoc localWriteTime:_timestamp]; + [patch applyToLocalDocument:baseDoc baseDocument:baseDoc localWriteTime:_timestamp]; NSDictionary *expectedData = @{@"foo" : @{@"bar" : @"new-bar-value"}, @"baz" : @"baz-value"}; XCTAssertEqualObjects(patchedDoc, FSTTestDoc("collection/key", 0, expectedData, YES)); @@ -110,7 +111,7 @@ - (void)testPatchingDeletedDocumentsDoesNothing { FSTMaybeDocument *baseDoc = FSTTestDeletedDoc("collection/key", 0); FSTMutation *patch = FSTTestPatchMutation("collection/key", @{@"foo" : @"bar"}, {}); FSTMaybeDocument *patchedDoc = - [patch applyTo:baseDoc baseDocument:baseDoc localWriteTime:_timestamp]; + [patch applyToLocalDocument:baseDoc baseDocument:baseDoc localWriteTime:_timestamp]; XCTAssertEqualObjects(patchedDoc, baseDoc); } @@ -121,7 +122,7 @@ - (void)testAppliesLocalServerTimestampTransformToDocuments { FSTMutation *transform = FSTTestTransformMutation( @"collection/key", @{@"foo.bar" : [FIRFieldValue fieldValueForServerTimestamp]}); FSTMaybeDocument *transformedDoc = - [transform applyTo:baseDoc baseDocument:baseDoc localWriteTime:_timestamp]; + [transform applyToLocalDocument:baseDoc baseDocument:baseDoc localWriteTime:_timestamp]; // Server timestamps aren't parsed, so we manually insert it. FSTObjectValue *expectedData = FSTTestObjectValue( @@ -297,7 +298,7 @@ - (void)transformBaseDoc:(NSDictionary *)baseData FSTMutation *transform = FSTTestTransformMutation(@"collection/key", transformData); FSTMaybeDocument *transformedDoc = - [transform applyTo:baseDoc baseDocument:baseDoc localWriteTime:_timestamp]; + [transform applyToLocalDocument:baseDoc baseDocument:baseDoc localWriteTime:_timestamp]; FSTDocument *expectedDoc = [FSTDocument documentWithData:FSTTestObjectValue(expectedData) key:FSTTestDocKey(@"collection/key") @@ -318,10 +319,8 @@ - (void)testAppliesServerAckedServerTimestampTransformToDocuments { initWithVersion:testutil::Version(1) transformResults:@[ [FSTTimestampValue timestampValue:_timestamp] ]]; - FSTMaybeDocument *transformedDoc = [transform applyTo:baseDoc - baseDocument:baseDoc - localWriteTime:_timestamp - mutationResult:mutationResult]; + FSTMaybeDocument *transformedDoc = + [transform applyToRemoteDocument:baseDoc mutationResult:mutationResult]; NSDictionary *expectedData = @{@"foo" : @{@"bar" : _timestamp.dateValue}, @"baz" : @"baz-value"}; XCTAssertEqualObjects(transformedDoc, FSTTestDoc("collection/key", 0, expectedData, NO)); @@ -341,10 +340,8 @@ - (void)testAppliesServerAckedArrayTransformsToDocuments { initWithVersion:testutil::Version(1) transformResults:@[ [FSTNullValue nullValue], [FSTNullValue nullValue] ]]; - FSTMaybeDocument *transformedDoc = [transform applyTo:baseDoc - baseDocument:baseDoc - localWriteTime:_timestamp - mutationResult:mutationResult]; + FSTMaybeDocument *transformedDoc = + [transform applyToRemoteDocument:baseDoc mutationResult:mutationResult]; NSDictionary *expectedData = @{@"array_1" : @[ @1, @2, @3 ], @"array_2" : @[ @"b" ]}; XCTAssertEqualObjects(transformedDoc, FSTTestDoc("collection/key", 0, expectedData, NO)); @@ -356,7 +353,7 @@ - (void)testDeleteDeletes { FSTMutation *mutation = FSTTestDeleteMutation(@"collection/key"); FSTMaybeDocument *result = - [mutation applyTo:baseDoc baseDocument:baseDoc localWriteTime:_timestamp]; + [mutation applyToLocalDocument:baseDoc baseDocument:baseDoc localWriteTime:_timestamp]; XCTAssertEqualObjects(result, FSTTestDeletedDoc("collection/key", 0)); } @@ -367,10 +364,7 @@ - (void)testSetWithMutationResult { FSTMutation *set = FSTTestSetMutation(@"collection/key", @{@"foo" : @"new-bar"}); FSTMutationResult *mutationResult = [[FSTMutationResult alloc] initWithVersion:testutil::Version(4) transformResults:nil]; - FSTMaybeDocument *setDoc = [set applyTo:baseDoc - baseDocument:baseDoc - localWriteTime:_timestamp - mutationResult:mutationResult]; + FSTMaybeDocument *setDoc = [set applyToRemoteDocument:baseDoc mutationResult:mutationResult]; NSDictionary *expectedData = @{@"foo" : @"new-bar"}; XCTAssertEqualObjects(setDoc, FSTTestDoc("collection/key", 0, expectedData, NO)); @@ -383,10 +377,8 @@ - (void)testPatchWithMutationResult { FSTMutation *patch = FSTTestPatchMutation("collection/key", @{@"foo" : @"new-bar"}, {}); FSTMutationResult *mutationResult = [[FSTMutationResult alloc] initWithVersion:testutil::Version(4) transformResults:nil]; - FSTMaybeDocument *patchedDoc = [patch applyTo:baseDoc - baseDocument:baseDoc - localWriteTime:_timestamp - mutationResult:mutationResult]; + FSTMaybeDocument *patchedDoc = + [patch applyToRemoteDocument:baseDoc mutationResult:mutationResult]; NSDictionary *expectedData = @{@"foo" : @"new-bar"}; XCTAssertEqualObjects(patchedDoc, FSTTestDoc("collection/key", 0, expectedData, NO)); @@ -396,10 +388,8 @@ - (void)testPatchWithMutationResult { do { \ FSTMutationResult *mutationResult = \ [[FSTMutationResult alloc] initWithVersion:testutil::Version(0) transformResults:nil]; \ - FSTMaybeDocument *actual = [mutation applyTo:base \ - baseDocument:base \ - localWriteTime:_timestamp \ - mutationResult:mutationResult]; \ + FSTMaybeDocument *actual = \ + [mutation applyToRemoteDocument:base mutationResult:mutationResult]; \ XCTAssertEqualObjects(actual, expected); \ } while (0); diff --git a/Firestore/Source/Local/FSTLocalDocumentsView.mm b/Firestore/Source/Local/FSTLocalDocumentsView.mm index 60c26486a4f..170095bda5d 100644 --- a/Firestore/Source/Local/FSTLocalDocumentsView.mm +++ b/Firestore/Source/Local/FSTLocalDocumentsView.mm @@ -72,7 +72,7 @@ - (nullable FSTMaybeDocument *)documentForKey:(const DocumentKey &)key inBatches:(NSArray *)batches { FSTMaybeDocument *_Nullable document = [self.remoteDocumentCache entryForKey:key]; for (FSTMutationBatch *batch in batches) { - document = [batch applyTo:document documentKey:key]; + document = [batch applyToLocalDocument:document documentKey:key]; } return document; @@ -129,8 +129,9 @@ - (FSTDocumentDictionary *)documentsMatchingCollectionQuery:(FSTQuery *)query { FSTDocumentKey *key = static_cast(mutation.key); // baseDoc may be nil for the documents that weren't yet written to the backend. FSTMaybeDocument *baseDoc = results[key]; - FSTMaybeDocument *mutatedDoc = - [mutation applyTo:baseDoc baseDocument:baseDoc localWriteTime:batch.localWriteTime]; + FSTMaybeDocument *mutatedDoc = [mutation applyToLocalDocument:baseDoc + baseDocument:baseDoc + localWriteTime:batch.localWriteTime]; if (!mutatedDoc || [mutatedDoc isKindOfClass:[FSTDeletedDocument class]]) { results = [results dictionaryByRemovingObjectForKey:key]; diff --git a/Firestore/Source/Local/FSTLocalStore.mm b/Firestore/Source/Local/FSTLocalStore.mm index 709ec545a96..24dd6c31b48 100644 --- a/Firestore/Source/Local/FSTLocalStore.mm +++ b/Firestore/Source/Local/FSTLocalStore.mm @@ -552,7 +552,7 @@ - (void)applyBatchResult:(FSTMutationBatchResult *)batchResult { "docVersions should contain every doc in the write."); const SnapshotVersion &ackVersion = ackVersionIter->second; if (!doc || doc.version < ackVersion) { - doc = [batch applyTo:doc documentKey:docKey mutationBatchResult:batchResult]; + doc = [batch applyToRemoteDocument:doc documentKey:docKey mutationBatchResult:batchResult]; if (!doc) { HARD_ASSERT(!remoteDoc, "Mutation batch %s applied to document %s resulted in nil.", batch, remoteDoc); diff --git a/Firestore/Source/Model/FSTMutation.h b/Firestore/Source/Model/FSTMutation.h index 0f4a2203bee..569dc0caf4f 100644 --- a/Firestore/Source/Model/FSTMutation.h +++ b/Firestore/Source/Model/FSTMutation.h @@ -79,15 +79,11 @@ NS_ASSUME_NONNULL_BEGIN NS_DESIGNATED_INITIALIZER; /** - * Applies this mutation to the given FSTDocument, FSTDeletedDocument or nil, if we don't have - * information about this document. Both the input and returned documents can be nil. + * Applies this mutation to the given FSTDocument, FSTDeletedDocument or nil for the purposes of + * computing a new remote document. Both the input and returned documents can be nil. * * @param maybeDoc The current state of the document to mutate. The input document should be nil if * it does not currently exist. - * @param baseDoc The state of the document prior to this mutation batch. The input document should - * be nil if it the document did not exist. - * @param localWriteTime A timestamp indicating the local write time of the batch this mutation is - * a part of. * @param mutationResult Optional result info from the backend. If omitted, it's assumed that * this is merely a local (latency-compensated) application, and the resulting document will * have its hasLocalMutations flag set. @@ -122,18 +118,23 @@ NS_ASSUME_NONNULL_BEGIN * apply the transform if the prior mutation resulted in an FSTDocument (always true for an * FSTSetMutation, but not necessarily for an FSTPatchMutation). */ -- (nullable FSTMaybeDocument *)applyTo:(nullable FSTMaybeDocument *)maybeDoc - baseDocument:(nullable FSTMaybeDocument *)baseDoc - localWriteTime:(FIRTimestamp *)localWriteTime - mutationResult:(nullable FSTMutationResult *)mutationResult; +- (nullable FSTMaybeDocument *)applyToRemoteDocument:(nullable FSTMaybeDocument *)maybeDoc + mutationResult:(FSTMutationResult *)mutationResult; /** - * A helper version of applyTo for applying mutations locally (without a mutation result from the - * backend). + * Applies this mutation to the given MaybeDocument for the purposes of computing the new local view + * of a document. Both the input and returned documents can be null. + * + * @param maybeDoc The current state of the document to mutate. The input document should be nil if + * it does not currently exist. + * @param baseDoc The state of the document prior to this mutation batch. The input document should + * be nil if it the document did not exist. + * @param localWriteTime A timestamp indicating the local write time of the batch this mutation is + * a part of. */ -- (nullable FSTMaybeDocument *)applyTo:(nullable FSTMaybeDocument *)maybeDoc - baseDocument:(nullable FSTMaybeDocument *)baseDoc - localWriteTime:(nullable FIRTimestamp *)localWriteTime; +- (nullable FSTMaybeDocument *)applyToLocalDocument:(nullable FSTMaybeDocument *)maybeDoc + baseDocument:(nullable FSTMaybeDocument *)baseDoc + localWriteTime:(FIRTimestamp *)localWriteTime; - (const firebase::firestore::model::DocumentKey &)key; diff --git a/Firestore/Source/Model/FSTMutation.mm b/Firestore/Source/Model/FSTMutation.mm index 4b2ba83336c..a5b925278cf 100644 --- a/Firestore/Source/Model/FSTMutation.mm +++ b/Firestore/Source/Model/FSTMutation.mm @@ -84,18 +84,15 @@ - (instancetype)initWithKey:(DocumentKey)key precondition:(Precondition)precondi return self; } -- (nullable FSTMaybeDocument *)applyTo:(nullable FSTMaybeDocument *)maybeDoc - baseDocument:(nullable FSTMaybeDocument *)baseDoc - localWriteTime:(FIRTimestamp *)localWriteTime - mutationResult:(nullable FSTMutationResult *)mutationResult { +- (nullable FSTMaybeDocument *)applyToRemoteDocument:(nullable FSTMaybeDocument *)maybeDoc + mutationResult:(FSTMutationResult *)mutationResult { @throw FSTAbstractMethodException(); // NOLINT } -- (nullable FSTMaybeDocument *)applyTo:(nullable FSTMaybeDocument *)maybeDoc - baseDocument:(nullable FSTMaybeDocument *)baseDoc - localWriteTime:(nullable FIRTimestamp *)localWriteTime { - return - [self applyTo:maybeDoc baseDocument:baseDoc localWriteTime:localWriteTime mutationResult:nil]; +- (nullable FSTMaybeDocument *)applyToLocalDocument:(nullable FSTMaybeDocument *)maybeDoc + baseDocument:(nullable FSTMaybeDocument *)baseDoc + localWriteTime:(FIRTimestamp *)localWriteTime { + @throw FSTAbstractMethodException(); // NOLINT } - (const DocumentKey &)key { @@ -144,10 +141,34 @@ - (NSUInteger)hash { return Hash(self.key, self.precondition, [self.value hash]); } -- (nullable FSTMaybeDocument *)applyTo:(nullable FSTMaybeDocument *)maybeDoc - baseDocument:(nullable FSTMaybeDocument *)baseDoc - localWriteTime:(FIRTimestamp *)localWriteTime - mutationResult:(nullable FSTMutationResult *)mutationResult { +- (nullable FSTMaybeDocument *)applyToLocalDocument:(nullable FSTMaybeDocument *)maybeDoc + baseDocument:(nullable FSTMaybeDocument *)baseDoc + localWriteTime:(FIRTimestamp *)localWriteTime { + if (!self.precondition.IsValidFor(maybeDoc)) { + return maybeDoc; + } + + if (!maybeDoc || [maybeDoc isMemberOfClass:[FSTDeletedDocument class]]) { + // If the document didn't exist before, create it. + return [FSTDocument documentWithData:self.value + key:self.key + version:SnapshotVersion::None() + hasLocalMutations:YES]; + } + + HARD_ASSERT([maybeDoc isMemberOfClass:[FSTDocument class]], "Unknown MaybeDocument type %s", + [maybeDoc class]); + FSTDocument *doc = (FSTDocument *)maybeDoc; + + HARD_ASSERT(doc.key == self.key, "Can only set a document with the same key"); + return [FSTDocument documentWithData:self.value + key:doc.key + version:doc.version + hasLocalMutations:YES]; +} + +- (nullable FSTMaybeDocument *)applyToRemoteDocument:(nullable FSTMaybeDocument *)maybeDoc + mutationResult:(FSTMutationResult *)mutationResult { if (mutationResult) { HARD_ASSERT(!mutationResult.transformResults, "Transform results received by FSTSetMutation."); } @@ -156,13 +177,12 @@ - (nullable FSTMaybeDocument *)applyTo:(nullable FSTMaybeDocument *)maybeDoc return maybeDoc; } - BOOL hasLocalMutations = (mutationResult == nil); if (!maybeDoc || [maybeDoc isMemberOfClass:[FSTDeletedDocument class]]) { // If the document didn't exist before, create it. return [FSTDocument documentWithData:self.value key:self.key version:SnapshotVersion::None() - hasLocalMutations:hasLocalMutations]; + hasLocalMutations:NO]; } HARD_ASSERT([maybeDoc isMemberOfClass:[FSTDocument class]], "Unknown MaybeDocument type %s", @@ -173,7 +193,7 @@ - (nullable FSTMaybeDocument *)applyTo:(nullable FSTMaybeDocument *)maybeDoc return [FSTDocument documentWithData:self.value key:doc.key version:doc.version - hasLocalMutations:hasLocalMutations]; + hasLocalMutations:NO]; } @end @@ -223,15 +243,38 @@ - (NSString *)description { self.value, self.precondition.description()]; } -- (nullable FSTMaybeDocument *)applyTo:(nullable FSTMaybeDocument *)maybeDoc - baseDocument:(nullable FSTMaybeDocument *)baseDoc - localWriteTime:(FIRTimestamp *)localWriteTime - mutationResult:(nullable FSTMutationResult *)mutationResult { - if (mutationResult) { - HARD_ASSERT(!mutationResult.transformResults, - "Transform results received by FSTPatchMutation."); +- (nullable FSTMaybeDocument *)applyToLocalDocument:(nullable FSTMaybeDocument *)maybeDoc + baseDocument:(nullable FSTMaybeDocument *)baseDoc + localWriteTime:(FIRTimestamp *)localWriteTime { + if (!self.precondition.IsValidFor(maybeDoc)) { + return maybeDoc; } + if (!maybeDoc || [maybeDoc isMemberOfClass:[FSTDeletedDocument class]]) { + // Precondition applied, so create the document if necessary + const DocumentKey &key = maybeDoc ? maybeDoc.key : self.key; + SnapshotVersion version = maybeDoc ? maybeDoc.version : SnapshotVersion::None(); + maybeDoc = [FSTDocument documentWithData:[FSTObjectValue objectValue] + key:key + version:std::move(version) + hasLocalMutations:YES]; + } + + HARD_ASSERT([maybeDoc isMemberOfClass:[FSTDocument class]], "Unknown MaybeDocument type %s", + [maybeDoc class]); + FSTDocument *doc = (FSTDocument *)maybeDoc; + + HARD_ASSERT(doc.key == self.key, "Can only patch a document with the same key"); + + FSTObjectValue *newData = [self patchObjectValue:doc.data]; + return + [FSTDocument documentWithData:newData key:doc.key version:doc.version hasLocalMutations:YES]; +} + +- (nullable FSTMaybeDocument *)applyToRemoteDocument:(nullable FSTMaybeDocument *)maybeDoc + mutationResult:(FSTMutationResult *)mutationResult { + HARD_ASSERT(!mutationResult.transformResults, "Transform results received by FSTPatchMutation."); + if (!self.precondition.IsValidFor(maybeDoc)) { return maybeDoc; } @@ -329,15 +372,33 @@ - (NSString *)description { self.precondition.description()]; } -- (nullable FSTMaybeDocument *)applyTo:(nullable FSTMaybeDocument *)maybeDoc - baseDocument:(nullable FSTMaybeDocument *)baseDoc - localWriteTime:(FIRTimestamp *)localWriteTime - mutationResult:(nullable FSTMutationResult *)mutationResult { - if (mutationResult) { - HARD_ASSERT(mutationResult.transformResults, - "Transform results missing for FSTTransformMutation."); +- (nullable FSTMaybeDocument *)applyToLocalDocument:(nullable FSTMaybeDocument *)maybeDoc + baseDocument:(nullable FSTMaybeDocument *)baseDoc + localWriteTime:(FIRTimestamp *)localWriteTime { + if (!self.precondition.IsValidFor(maybeDoc)) { + return maybeDoc; } + // We only support transforms with precondition exists, so we can only apply it to an existing + // document + HARD_ASSERT([maybeDoc isMemberOfClass:[FSTDocument class]], "Unknown MaybeDocument type %s", + [maybeDoc class]); + FSTDocument *doc = (FSTDocument *)maybeDoc; + + HARD_ASSERT(doc.key == self.key, "Can only transform a document with the same key"); + + NSArray *transformResults = + [self localTransformResultsWithBaseDocument:baseDoc writeTime:localWriteTime]; + FSTObjectValue *newData = [self transformObject:doc.data transformResults:transformResults]; + return + [FSTDocument documentWithData:newData key:doc.key version:doc.version hasLocalMutations:YES]; +} + +- (nullable FSTMaybeDocument *)applyToRemoteDocument:(nullable FSTMaybeDocument *)maybeDoc + mutationResult:(FSTMutationResult *)mutationResult { + HARD_ASSERT(mutationResult.transformResults, + "Transform results missing for FSTTransformMutation."); + if (!self.precondition.IsValidFor(maybeDoc)) { return maybeDoc; } @@ -350,21 +411,13 @@ - (nullable FSTMaybeDocument *)applyTo:(nullable FSTMaybeDocument *)maybeDoc HARD_ASSERT(doc.key == self.key, "Can only transform a document with the same key"); - BOOL hasLocalMutations = (mutationResult == nil); - NSArray *transformResults; - if (mutationResult) { - transformResults = - [self serverTransformResultsWithBaseDocument:baseDoc - serverTransformResults:mutationResult.transformResults]; - } else { - transformResults = - [self localTransformResultsWithBaseDocument:baseDoc writeTime:localWriteTime]; - } + NSArray *transformResults = + [self serverTransformResultsWithBaseDocument:maybeDoc + serverTransformResults:mutationResult.transformResults]; + FSTObjectValue *newData = [self transformObject:doc.data transformResults:transformResults]; - return [FSTDocument documentWithData:newData - key:doc.key - version:doc.version - hasLocalMutations:hasLocalMutations]; + return + [FSTDocument documentWithData:newData key:doc.key version:doc.version hasLocalMutations:NO]; } /** @@ -465,10 +518,22 @@ - (NSString *)description { self.key.ToString().c_str(), self.precondition.description()]; } -- (nullable FSTMaybeDocument *)applyTo:(nullable FSTMaybeDocument *)maybeDoc - baseDocument:(nullable FSTMaybeDocument *)baseDoc - localWriteTime:(FIRTimestamp *)localWriteTime - mutationResult:(nullable FSTMutationResult *)mutationResult { +- (nullable FSTMaybeDocument *)applyToLocalDocument:(nullable FSTMaybeDocument *)maybeDoc + baseDocument:(nullable FSTMaybeDocument *)baseDoc + localWriteTime:(FIRTimestamp *)localWriteTime { + if (!self.precondition.IsValidFor(maybeDoc)) { + return maybeDoc; + } + + if (maybeDoc) { + HARD_ASSERT(maybeDoc.key == self.key, "Can only delete a document with the same key"); + } + + return [FSTDeletedDocument documentWithKey:self.key version:SnapshotVersion::None()]; +} + +- (nullable FSTMaybeDocument *)applyToRemoteDocument:(nullable FSTMaybeDocument *)maybeDoc + mutationResult:(FSTMutationResult *)mutationResult { if (mutationResult) { HARD_ASSERT(!mutationResult.transformResults, "Transform results received by FSTDeleteMutation."); diff --git a/Firestore/Source/Model/FSTMutationBatch.h b/Firestore/Source/Model/FSTMutationBatch.h index 384540e2d48..d8dadc131d0 100644 --- a/Firestore/Source/Model/FSTMutationBatch.h +++ b/Firestore/Source/Model/FSTMutationBatch.h @@ -65,7 +65,8 @@ extern const firebase::firestore::model::BatchId kFSTBatchIDUnknown; - (id)init NS_UNAVAILABLE; /** - * Applies all the mutations in this FSTMutationBatch to the specified document. + * Applies all the mutations in this FSTMutationBatch to the specified document to create a new + * remote document. * * @param maybeDoc The document to apply mutations to. * @param documentKey The key of the document to apply mutations to. @@ -73,16 +74,18 @@ extern const firebase::firestore::model::BatchId kFSTBatchIDUnknown; * it's assumed that this is a local (latency-compensated) application and documents will have * their hasLocalMutations flag set. */ -- (FSTMaybeDocument *_Nullable)applyTo:(FSTMaybeDocument *_Nullable)maybeDoc - documentKey:(const firebase::firestore::model::DocumentKey &)documentKey - mutationBatchResult:(FSTMutationBatchResult *_Nullable)mutationBatchResult; +- (FSTMaybeDocument *_Nullable) + applyToRemoteDocument:(FSTMaybeDocument *_Nullable)maybeDoc + documentKey:(const firebase::firestore::model::DocumentKey &)documentKey + mutationBatchResult:(FSTMutationBatchResult *_Nullable)mutationBatchResult; /** * A helper version of applyTo for applying mutations locally (without a mutation batch result from * the backend). */ -- (FSTMaybeDocument *_Nullable)applyTo:(FSTMaybeDocument *_Nullable)maybeDoc - documentKey:(const firebase::firestore::model::DocumentKey &)documentKey; +- (FSTMaybeDocument *_Nullable) + applyToLocalDocument:(FSTMaybeDocument *_Nullable)maybeDoc + documentKey:(const firebase::firestore::model::DocumentKey &)documentKey; /** * Returns YES if this mutation batch has already been removed from the mutation queue. diff --git a/Firestore/Source/Model/FSTMutationBatch.mm b/Firestore/Source/Model/FSTMutationBatch.mm index d981aff15c4..db848ba9bad 100644 --- a/Firestore/Source/Model/FSTMutationBatch.mm +++ b/Firestore/Source/Model/FSTMutationBatch.mm @@ -75,35 +75,44 @@ - (NSString *)description { self.batchID, self.localWriteTime, self.mutations]; } -- (FSTMaybeDocument *_Nullable)applyTo:(FSTMaybeDocument *_Nullable)maybeDoc - documentKey:(const DocumentKey &)documentKey - mutationBatchResult:(FSTMutationBatchResult *_Nullable)mutationBatchResult { +- (FSTMaybeDocument *_Nullable)applyToRemoteDocument:(FSTMaybeDocument *_Nullable)maybeDoc + documentKey:(const DocumentKey &)documentKey + mutationBatchResult: + (FSTMutationBatchResult *_Nullable)mutationBatchResult { HARD_ASSERT(!maybeDoc || maybeDoc.key == documentKey, "applyTo: key %s doesn't match maybeDoc key %s", documentKey.ToString(), maybeDoc.key.ToString()); - FSTMaybeDocument *baseDoc = maybeDoc; - if (mutationBatchResult) { - HARD_ASSERT(mutationBatchResult.mutationResults.count == self.mutations.count, - "Mismatch between mutations length (%s) and results length (%s)", - self.mutations.count, mutationBatchResult.mutationResults.count); - } + + HARD_ASSERT(mutationBatchResult.mutationResults.count == self.mutations.count, + "Mismatch between mutations length (%s) and results length (%s)", + self.mutations.count, mutationBatchResult.mutationResults.count); for (NSUInteger i = 0; i < self.mutations.count; i++) { FSTMutation *mutation = self.mutations[i]; - FSTMutationResult *_Nullable mutationResult = mutationBatchResult.mutationResults[i]; + FSTMutationResult *mutationResult = mutationBatchResult.mutationResults[i]; if (mutation.key == documentKey) { - maybeDoc = [mutation applyTo:maybeDoc - baseDocument:baseDoc - localWriteTime:self.localWriteTime - mutationResult:mutationResult]; + maybeDoc = [mutation applyToRemoteDocument:maybeDoc mutationResult:mutationResult]; } } return maybeDoc; } -- (FSTMaybeDocument *_Nullable)applyTo:(FSTMaybeDocument *_Nullable)maybeDoc - documentKey:(const DocumentKey &)documentKey { - return [self applyTo:maybeDoc documentKey:documentKey mutationBatchResult:nil]; +- (FSTMaybeDocument *_Nullable)applyToLocalDocument:(FSTMaybeDocument *_Nullable)maybeDoc + documentKey:(const DocumentKey &)documentKey { + HARD_ASSERT(!maybeDoc || maybeDoc.key == documentKey, + "applyTo: key %s doesn't match maybeDoc key %s", documentKey.ToString(), + maybeDoc.key.ToString()); + FSTMaybeDocument *baseDoc = maybeDoc; + + for (NSUInteger i = 0; i < self.mutations.count; i++) { + FSTMutation *mutation = self.mutations[i]; + if (mutation.key == documentKey) { + maybeDoc = [mutation applyToLocalDocument:maybeDoc + baseDocument:baseDoc + localWriteTime:self.localWriteTime]; + } + } + return maybeDoc; } - (BOOL)isTombstone {