diff options
-rw-r--r-- | Firestore/Example/Tests/SpecTests/json/offline_spec_test.json | 254 | ||||
-rw-r--r-- | Firestore/Source/Core/FSTView.m | 26 |
2 files changed, 269 insertions, 11 deletions
diff --git a/Firestore/Example/Tests/SpecTests/json/offline_spec_test.json b/Firestore/Example/Tests/SpecTests/json/offline_spec_test.json index 3981cec..6cbbc80 100644 --- a/Firestore/Example/Tests/SpecTests/json/offline_spec_test.json +++ b/Firestore/Example/Tests/SpecTests/json/offline_spec_test.json @@ -459,5 +459,259 @@ ] } ] + }, + "Queries with limbo documents handle going offline.": { + "describeName": "Offline:", + "itName": "Queries with limbo documents handle going offline.", + "tags": [], + "config": { + "useGarbageCollection": true + }, + "steps": [ + { + "userListen": [ + 2, + { + "path": "collection", + "filters": [], + "orderBys": [] + } + ], + "stateExpect": { + "activeTargets": { + "2": { + "query": { + "path": "collection", + "filters": [], + "orderBys": [] + }, + "resumeToken": "" + } + } + } + }, + { + "watchAck": [ + 2 + ] + }, + { + "watchEntity": { + "docs": [ + [ + "collection/a", + 1000, + { + "key": "a" + } + ] + ], + "targets": [ + 2 + ] + } + }, + { + "watchCurrent": [ + [ + 2 + ], + "resume-token-1000" + ], + "watchSnapshot": 1000, + "expect": [ + { + "query": { + "path": "collection", + "filters": [], + "orderBys": [] + }, + "added": [ + [ + "collection/a", + 1000, + { + "key": "a" + } + ] + ], + "errorCode": 0, + "fromCache": false, + "hasPendingWrites": false + } + ] + }, + { + "watchReset": [ + 2 + ] + }, + { + "watchCurrent": [ + [ + 2 + ], + "resume-token-1001" + ], + "watchSnapshot": 1001, + "stateExpect": { + "limboDocs": [ + "collection/a" + ], + "activeTargets": { + "1": { + "query": { + "path": "collection/a", + "filters": [], + "orderBys": [] + }, + "resumeToken": "" + }, + "2": { + "query": { + "path": "collection", + "filters": [], + "orderBys": [] + }, + "resumeToken": "" + } + } + }, + "expect": [ + { + "query": { + "path": "collection", + "filters": [], + "orderBys": [] + }, + "errorCode": 0, + "fromCache": true, + "hasPendingWrites": false + } + ] + }, + { + "watchStreamClose": { + "error": { + "code": 14, + "message": "Simulated Backend Error" + } + }, + "stateExpect": { + "activeTargets": { + "1": { + "query": { + "path": "collection/a", + "filters": [], + "orderBys": [] + }, + "resumeToken": "" + }, + "2": { + "query": { + "path": "collection", + "filters": [], + "orderBys": [] + }, + "resumeToken": "resume-token-1001" + } + } + } + }, + { + "watchStreamClose": { + "error": { + "code": 14, + "message": "Simulated Backend Error" + } + } + }, + { + "watchStreamClose": { + "error": { + "code": 14, + "message": "Simulated Backend Error" + } + } + }, + { + "watchAck": [ + 2 + ] + }, + { + "watchEntity": { + "docs": [], + "targets": [ + 2 + ] + } + }, + { + "watchCurrent": [ + [ + 2 + ], + "resume-token-1001" + ], + "watchSnapshot": 1001 + }, + { + "watchAck": [ + 1 + ] + }, + { + "watchEntity": { + "docs": [], + "targets": [ + 1 + ] + } + }, + { + "watchCurrent": [ + [ + 1 + ], + "resume-token-1001" + ], + "watchSnapshot": 1001, + "expect": [ + { + "query": { + "path": "collection", + "filters": [], + "orderBys": [] + }, + "removed": [ + [ + "collection/a", + 1000, + { + "key": "a" + } + ] + ], + "errorCode": 0, + "fromCache": false, + "hasPendingWrites": false + } + ], + "stateExpect": { + "limboDocs": [], + "activeTargets": { + "2": { + "query": { + "path": "collection", + "filters": [], + "orderBys": [] + }, + "resumeToken": "resume-token-1001" + } + } + } + } + ] } } diff --git a/Firestore/Source/Core/FSTView.m b/Firestore/Source/Core/FSTView.m index 78019c6..d6b4558 100644 --- a/Firestore/Source/Core/FSTView.m +++ b/Firestore/Source/Core/FSTView.m @@ -312,8 +312,8 @@ static NSComparisonResult FSTCompareDocumentViewChangeTypes(FSTDocumentViewChang } return self.query.comparator(c1.document, c2.document); }]; - - NSArray<FSTLimboDocumentChange *> *limboChanges = [self applyTargetChange:targetChange]; + [self applyTargetChange:targetChange]; + NSArray<FSTLimboDocumentChange *> *limboChanges = [self updateLimboDocuments]; BOOL synced = self.limboDocuments.count == 0 && self.isCurrent; FSTSyncState newSyncState = synced ? FSTSyncStateSynced : FSTSyncStateLocal; BOOL syncStateChanged = newSyncState != self.syncState; @@ -378,10 +378,9 @@ static NSComparisonResult FSTCompareDocumentViewChangeTypes(FSTDocumentViewChang } /** - * Updates syncedDocuments, isAcked, and limbo docs based on the given change. - * @return the list of changes to which docs are in limbo. + * Updates syncedDocuments and current based on the given change. */ -- (NSArray<FSTLimboDocumentChange *> *)applyTargetChange:(nullable FSTTargetChange *)targetChange { +- (void)applyTargetChange:(nullable FSTTargetChange *)targetChange { if (targetChange) { FSTTargetMapping *targetMapping = targetChange.mapping; if ([targetMapping isKindOfClass:[FSTResetMapping class]]) { @@ -408,16 +407,21 @@ static NSComparisonResult FSTCompareDocumentViewChangeTypes(FSTDocumentViewChang break; } } +} + +/** Updates limboDocuments and returns any changes as FSTLimboDocumentChanges. */ +- (NSArray<FSTLimboDocumentChange *> *)updateLimboDocuments { + // We can only determine limbo documents when we're in-sync with the server. + if (!self.isCurrent) { + return @[]; + } - // Recompute the set of limbo docs. // TODO(klimt): Do this incrementally so that it's not quadratic when updating many documents. FSTDocumentKeySet *oldLimboDocuments = self.limboDocuments; self.limboDocuments = [FSTDocumentKeySet keySet]; - if (self.isCurrent) { - for (FSTDocument *doc in self.documentSet.documentEnumerator) { - if ([self shouldBeLimboDocumentKey:doc.key]) { - self.limboDocuments = [self.limboDocuments setByAddingObject:doc.key]; - } + for (FSTDocument *doc in self.documentSet.documentEnumerator) { + if ([self shouldBeLimboDocumentKey:doc.key]) { + self.limboDocuments = [self.limboDocuments setByAddingObject:doc.key]; } } |