From 80a40bd5be56342ba6287d8711264dc65c82ec49 Mon Sep 17 00:00:00 2001 From: Rich Gowman Date: Wed, 10 Jan 2018 16:49:34 -0500 Subject: [PATCH 01/12] GetOptions for controlling offline behaviour. Add option to allow the user to control where DocumentReference.getDocument() fetches from. By default, it fetches from the server (if possible) and falls back to the local cache. It's now possible to alternatively fetch from the local cache only, or to fetch from the server only (though in the server only case, latency compensation is still enabled). Still TODO: Also enable this for CollectionReferenece.getDocuments(). --- .../Firestore.xcodeproj/project.pbxproj | 4 + .../Tests/Core/FSTQueryListenerTests.m | 18 +- .../Integration/API/FIRGetOptionsTests.m | 297 ++++++++++++++++++ .../Tests/SpecTests/FSTSyncEngineTestDriver.m | 4 +- .../Tests/Util/FSTIntegrationTestCase.h | 3 + .../Tests/Util/FSTIntegrationTestCase.mm | 6 +- Firestore/Source/API/FIRDocumentReference.m | 13 + Firestore/Source/API/FIRGetOptions+Internal.h | 28 ++ Firestore/Source/API/FIRGetOptions.m | 36 +++ Firestore/Source/Core/FSTFirestoreClient.h | 8 + Firestore/Source/Core/FSTFirestoreClient.m | 14 + .../Source/Public/FIRDocumentReference.h | 6 + Firestore/Source/Public/FIRGetOptions.h | 69 ++++ 13 files changed, 499 insertions(+), 7 deletions(-) create mode 100644 Firestore/Example/Tests/Integration/API/FIRGetOptionsTests.m create mode 100644 Firestore/Source/API/FIRGetOptions+Internal.h create mode 100644 Firestore/Source/API/FIRGetOptions.m create mode 100644 Firestore/Source/Public/FIRGetOptions.h diff --git a/Firestore/Example/Firestore.xcodeproj/project.pbxproj b/Firestore/Example/Firestore.xcodeproj/project.pbxproj index 06f790c1449..503d62a3b81 100644 --- a/Firestore/Example/Firestore.xcodeproj/project.pbxproj +++ b/Firestore/Example/Firestore.xcodeproj/project.pbxproj @@ -59,6 +59,7 @@ 6003F5B1195388D20070C39A /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F58D195388D20070C39A /* Foundation.framework */; }; 6003F5B2195388D20070C39A /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F591195388D20070C39A /* UIKit.framework */; }; 6003F5BA195388D20070C39A /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 6003F5B8195388D20070C39A /* InfoPlist.strings */; }; + 61CC13FA2007D0C90021F5BF /* FIRGetOptionsTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 61CC13F82007D0C20021F5BF /* FIRGetOptionsTests.m */; }; 61E1D8B11FCF6C5700753285 /* StringViewTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 61E1D8AF1FCF6AF500753285 /* StringViewTests.mm */; }; 6ED54761B845349D43DB6B78 /* Pods_Firestore_Example.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 75A6FE51C1A02DF38F62FAAD /* Pods_Firestore_Example.framework */; }; 71719F9F1E33DC2100824A3D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 71719F9D1E33DC2100824A3D /* LaunchScreen.storyboard */; }; @@ -235,6 +236,7 @@ 6003F5AF195388D20070C39A /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; }; 6003F5B7195388D20070C39A /* Tests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Tests-Info.plist"; sourceTree = ""; }; 6003F5B9195388D20070C39A /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; + 61CC13F82007D0C20021F5BF /* FIRGetOptionsTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FIRGetOptionsTests.m; sourceTree = ""; }; 61E1D8AF1FCF6AF500753285 /* StringViewTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = StringViewTests.mm; sourceTree = ""; }; 69F6A10DBD6187489481CD76 /* Pods_Firestore_Tests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Firestore_Tests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 71719F9E1E33DC2100824A3D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; @@ -723,6 +725,7 @@ DE51B1BC1F0D48AC0013853F /* API */ = { isa = PBXGroup; children = ( + 61CC13F82007D0C20021F5BF /* FIRGetOptionsTests.m */, DE51B1BD1F0D48AC0013853F /* FIRCursorTests.m */, DE51B1BE1F0D48AC0013853F /* FIRDatabaseTests.m */, DE51B1BF1F0D48AC0013853F /* FIRFieldsTests.m */, @@ -1281,6 +1284,7 @@ 54E928251F33953400C1953E /* FSTEventAccumulator.m in Sources */, DE03B2ED1F214BA200A30B9C /* FSTSmokeTests.m in Sources */, DE03B2F31F214BAA00A30B9C /* FIRQueryTests.m in Sources */, + 61CC13FA2007D0C90021F5BF /* FIRGetOptionsTests.m in Sources */, DE03B35E1F21586C00A30B9C /* FSTHelpers.m in Sources */, DE03B2F51F214BAA00A30B9C /* FIRTypeTests.m in Sources */, DE03B2EF1F214BAA00A30B9C /* FIRCursorTests.m in Sources */, diff --git a/Firestore/Example/Tests/Core/FSTQueryListenerTests.m b/Firestore/Example/Tests/Core/FSTQueryListenerTests.m index 4856b5fa462..e91dd057325 100644 --- a/Firestore/Example/Tests/Core/FSTQueryListenerTests.m +++ b/Firestore/Example/Tests/Core/FSTQueryListenerTests.m @@ -172,7 +172,8 @@ - (void)testDoesNotRaiseEventsForMetadataChangesUnlessSpecified { FSTListenOptions *options = [[FSTListenOptions alloc] initWithIncludeQueryMetadataChanges:YES includeDocumentMetadataChanges:NO - waitForSyncWhenOnline:NO]; + waitForSyncWhenOnline:NO + getOptions:[FIRGetOptions defaultOptions]]; FSTQueryListener *filteredListener = [self listenToQuery:query accumulatingSnapshots:filteredAccum]; @@ -212,7 +213,8 @@ - (void)testRaisesDocumentMetadataEventsOnlyWhenSpecified { FSTListenOptions *options = [[FSTListenOptions alloc] initWithIncludeQueryMetadataChanges:NO includeDocumentMetadataChanges:YES - waitForSyncWhenOnline:NO]; + waitForSyncWhenOnline:NO + getOptions:[FIRGetOptions defaultOptions]]; FSTQueryListener *filteredListener = [self listenToQuery:query accumulatingSnapshots:filteredAccum]; @@ -262,7 +264,9 @@ - (void)testRaisesQueryMetadataEventsOnlyWhenHasPendingWritesOnTheQueryChanges { FSTListenOptions *options = [[FSTListenOptions alloc] initWithIncludeQueryMetadataChanges:YES includeDocumentMetadataChanges:NO - waitForSyncWhenOnline:NO]; + waitForSyncWhenOnline:NO + getOptions:[FIRGetOptions defaultOptions]]; + FSTQueryListener *fullListener = [self listenToQuery:query options:options accumulatingSnapshots:fullAccum]; @@ -329,7 +333,9 @@ - (void)testWillWaitForSyncIfOnline { [self listenToQuery:query options:[[FSTListenOptions alloc] initWithIncludeQueryMetadataChanges:NO includeDocumentMetadataChanges:NO - waitForSyncWhenOnline:YES] + waitForSyncWhenOnline:YES + getOptions:[FIRGetOptions defaultOptions]] + accumulatingSnapshots:events]; FSTView *view = [[FSTView alloc] initWithQuery:query remoteDocuments:[FSTDocumentKeySet keySet]]; @@ -372,7 +378,9 @@ - (void)testWillRaiseInitialEventWhenGoingOffline { [self listenToQuery:query options:[[FSTListenOptions alloc] initWithIncludeQueryMetadataChanges:NO includeDocumentMetadataChanges:NO - waitForSyncWhenOnline:YES] + waitForSyncWhenOnline:YES + getOptions:[FIRGetOptions defaultOptions]] + accumulatingSnapshots:events]; FSTView *view = [[FSTView alloc] initWithQuery:query remoteDocuments:[FSTDocumentKeySet keySet]]; diff --git a/Firestore/Example/Tests/Integration/API/FIRGetOptionsTests.m b/Firestore/Example/Tests/Integration/API/FIRGetOptionsTests.m new file mode 100644 index 00000000000..7a83f26d1e2 --- /dev/null +++ b/Firestore/Example/Tests/Integration/API/FIRGetOptionsTests.m @@ -0,0 +1,297 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@import FirebaseFirestore; + +#import +#import + +#import "Firestore/Example/Tests/Util/FSTIntegrationTestCase.h" +#import "Firestore/Source/API/FIRFirestore+Internal.h" +#import "Firestore/Source/Core/FSTFirestoreClient.h" + +@interface FIRGetOptionsTests : FSTIntegrationTestCase +@end + +@implementation FIRGetOptionsTests + +- (void)testGetDocumentWhileOnlineWithDefaultGetOptions { + FIRDocumentReference *doc = [self documentRef]; + + // set document to a known value + NSDictionary *initialData = @{@"key" : @"value"}; + [self writeDocumentRef:doc data:initialData]; + + // get doc and ensure that it exists, is *not* from the cache, and matches + // the initialData. + FIRDocumentSnapshot *result = [self readDocumentForRef:doc]; + XCTAssertTrue(result.exists); + XCTAssertFalse(result.metadata.fromCache); + XCTAssertEqualObjects(result.data, initialData); +} + +- (void)testGetDocumentWhileOfflineWithDefaultGetOptions { + FIRDocumentReference *doc = [self documentRef]; + + // set document to a known value + NSDictionary *initialData = @{@"key1" : @"value1"}; + [self writeDocumentRef:doc data:initialData]; + + // go offline for the rest of this test + [self disableNetwork]; + + // update the doc (though don't wait for a server response. We're offline; so + // that ain't happening!). This allows us to further distinguished cached vs + // server responses below. + NSDictionary *newData = @{@"key2" : @"value2"}; + [doc setData:newData completion:^(NSError *_Nullable error) { + XCTAssertTrue(false, "Because we're offline, this should never occur."); + }]; + + // get doc and ensure it exists, *is* from the cache, and matches the + // newData. + FIRDocumentSnapshot *result = [self readDocumentForRef:doc]; + XCTAssertTrue(result.exists); + XCTAssertTrue(result.metadata.fromCache); + XCTAssertEqualObjects(result.data, newData); +} + +- (void)testGetDocumentWhileOnlineCacheOnly { + FIRDocumentReference *doc = [self documentRef]; + + // set document to a known value + NSDictionary *initialData = @{@"key" : @"value"}; + [self writeDocumentRef:doc data:initialData]; + + // get doc and ensure that it exists, *is* from the cache, and matches + // the initialData. + FIRDocumentSnapshot *result = [self readDocumentForRef:doc getOptions:[[FIRGetOptions alloc] initWithSource:FIRCache]]; + XCTAssertTrue(result.exists); + XCTAssertTrue(result.metadata.fromCache); + XCTAssertEqualObjects(result.data, initialData); +} + +- (void)testGetDocumentWhileOfflineCacheOnly { + FIRDocumentReference *doc = [self documentRef]; + + // set document to a known value + NSDictionary *initialData = @{@"key1" : @"value1"}; + [self writeDocumentRef:doc data:initialData]; + + // go offline for the rest of this test + [self disableNetwork]; + + // update the doc (though don't wait for a server response. We're offline; so + // that ain't happening!). This allows us to further distinguished cached vs + // server responses below. + NSDictionary *newData = @{@"key2" : @"value2"}; + [doc setData:newData completion:^(NSError *_Nullable error) { + XCTFail("Because we're offline, this should never occur."); + }]; + + // get doc and ensure it exists, *is* from the cache, and matches the + // newData. + FIRDocumentSnapshot *result = [self readDocumentForRef:doc getOptions:[[FIRGetOptions alloc] initWithSource:FIRCache]]; + XCTAssertTrue(result.exists); + XCTAssertTrue(result.metadata.fromCache); + XCTAssertEqualObjects(result.data, newData); +} + +- (void)testGetDocumentWhileOnlineServerOnly { + FIRDocumentReference *doc = [self documentRef]; + + // set document to a known value + NSDictionary *initialData = @{@"key" : @"value"}; + [self writeDocumentRef:doc data:initialData]; + + // get doc and ensure that it exists, is *not* from the cache, and matches + // the initialData. + FIRDocumentSnapshot *result = [self readDocumentForRef:doc getOptions:[[FIRGetOptions alloc] initWithSource:FIRServer]]; + XCTAssertTrue(result.exists); + XCTAssertFalse(result.metadata.fromCache); + XCTAssertEqualObjects(result.data, initialData); +} + +- (void)testGetDocumentWhileOfflineServerOnly { + FIRDocumentReference *doc = [self documentRef]; + + // set document to a known value + NSDictionary *initialData = @{@"key1" : @"value1"}; + [self writeDocumentRef:doc data:initialData]; + + // go offline for the rest of this test + [self disableNetwork]; + + // update the doc (though don't wait for a server response. We're offline; so + // that ain't happening!). This allows us to further distinguished cached vs + // server responses below. + NSDictionary *newData = @{@"key2" : @"value2"}; + [doc setData:newData completion:^(NSError *_Nullable error) { + XCTAssertTrue(false, "Because we're offline, this should never occur."); + }]; + + // attempt to get doc and ensure it cannot be retreived + XCTestExpectation *failedGetDocCompletion = [self expectationWithDescription:@"failedGetDoc"]; + [doc getDocumentWithOptions:[[FIRGetOptions alloc] initWithSource:FIRServer] completion:^(FIRDocumentSnapshot *snapshot, NSError *error) { + XCTAssertNotNil(error); + XCTAssertEqualObjects(error.domain, FIRFirestoreErrorDomain); + XCTAssertEqual(error.code, FIRFirestoreErrorCodeUnavailable); + [failedGetDocCompletion fulfill]; + }]; + [self awaitExpectations]; +} + +- (void)testGetDocumentWhileOfflineWithDifferentGetOptions { + FIRDocumentReference *doc = [self documentRef]; + + // set document to a known value + NSDictionary *initialData = @{@"key1" : @"value1"}; + [self writeDocumentRef:doc data:initialData]; + + // go offline for the rest of this test + [self disableNetwork]; + + // update the doc (though don't wait for a server response. We're offline; so + // that ain't happening!). This allows us to further distinguished cached vs + // server responses below. + NSDictionary *newData = @{@"key2" : @"value2"}; + [doc setData:newData completion:^(NSError *_Nullable error) { + XCTAssertTrue(false, "Because we're offline, this should never occur."); + }]; + + // Create an initial listener for this query (to attempt to disrupt the gets below) and wait for the listener to be fully initialized before continuing. + XCTestExpectation *listenerReady = [self expectationWithDescription:@"listenerReady"]; + [doc addSnapshotListener:^(FIRDocumentSnapshot *snapshot, NSError *error) { + [listenerReady fulfill]; + }]; + [self awaitExpectations]; + + // get doc (from cache) and ensure it exists, *is* from the cache, and + // matches the newData. + FIRDocumentSnapshot *result = [self readDocumentForRef:doc getOptions:[[FIRGetOptions alloc] initWithSource:FIRCache]]; + XCTAssertTrue(result.exists); + XCTAssertTrue(result.metadata.fromCache); + XCTAssertEqualObjects(result.data, newData); + + // attempt to get doc (with default get options) + result = [self readDocumentForRef:doc getOptions:[[FIRGetOptions alloc] initWithSource:FIRDefault]]; + XCTAssertTrue(result.exists); + XCTAssertTrue(result.metadata.fromCache); + XCTAssertEqualObjects(result.data, newData); + + // attempt to get doc (from the server) and ensure it cannot be retreived + XCTestExpectation *failedGetDocCompletion = [self expectationWithDescription:@"failedGetDoc"]; + [doc getDocumentWithOptions:[[FIRGetOptions alloc] initWithSource:FIRServer] completion:^(FIRDocumentSnapshot *snapshot, NSError *error) { + XCTAssertNotNil(error); + XCTAssertEqualObjects(error.domain, FIRFirestoreErrorDomain); + XCTAssertEqual(error.code, FIRFirestoreErrorCodeUnavailable); + [failedGetDocCompletion fulfill]; + }]; + [self awaitExpectations]; +} + +- (void)testGetNonExistingDocWhileOnlineWithDefaultGetOptions { + FIRDocumentReference *doc = [self documentRef]; + + // get doc and ensure that it does not exist and is *not* from the cache. + FIRDocumentSnapshot* snapshot = [self readDocumentForRef:doc]; + XCTAssertFalse(snapshot.exists); + XCTAssertFalse(snapshot.metadata.fromCache); +} + +- (void)testGetNonExistingDocWhileOfflineWithDefaultGetOptions { + FIRDocumentReference *doc = [self documentRef]; + + // go offline for the rest of this test + [self disableNetwork]; + + // attempt to get doc. Currently, this is expected to fail. In the future, we + // might consider adding support for negative cache hits so that we know + // certain documents *don't* exist. + XCTestExpectation *getNonExistingDocCompletion = [self expectationWithDescription:@"getNonExistingDoc"]; + [doc getDocumentWithCompletion:^(FIRDocumentSnapshot *snapshot, NSError *error) { + XCTAssertNotNil(error); + XCTAssertEqualObjects(error.domain, FIRFirestoreErrorDomain); + XCTAssertEqual(error.code, FIRFirestoreErrorCodeUnavailable); + [getNonExistingDocCompletion fulfill]; + }]; + [self awaitExpectations]; +} + +- (void)testGetNonExistingDocWhileOnlineCacheOnly { + FIRDocumentReference *doc = [self documentRef]; + + // attempt to get doc. Currently, this is expected to fail. In the future, we + // might consider adding support for negative cache hits so that we know + // certain documents *don't* exist. + XCTestExpectation *getNonExistingDocCompletion = [self expectationWithDescription:@"getNonExistingDoc"]; + [doc getDocumentWithOptions:[[FIRGetOptions alloc] initWithSource:FIRCache] completion:^(FIRDocumentSnapshot *snapshot, NSError *error) { + XCTAssertNotNil(error); + XCTAssertEqualObjects(error.domain, FIRFirestoreErrorDomain); + XCTAssertEqual(error.code, FIRFirestoreErrorCodeUnavailable); + [getNonExistingDocCompletion fulfill]; + }]; + [self awaitExpectations]; +} + +- (void)testGetNonExistingDocWhileOfflineCacheOnly { + FIRDocumentReference *doc = [self documentRef]; + + // go offline for the rest of this test + [self disableNetwork]; + + // attempt to get doc. Currently, this is expected to fail. In the future, we + // might consider adding support for negative cache hits so that we know + // certain documents *don't* exist. + XCTestExpectation *getNonExistingDocCompletion = [self expectationWithDescription:@"getNonExistingDoc"]; + [doc getDocumentWithOptions:[[FIRGetOptions alloc] initWithSource:FIRCache] completion:^(FIRDocumentSnapshot *snapshot, NSError *error) { + XCTAssertNotNil(error); + XCTAssertEqualObjects(error.domain, FIRFirestoreErrorDomain); + XCTAssertEqual(error.code, FIRFirestoreErrorCodeUnavailable); + [getNonExistingDocCompletion fulfill]; + }]; + [self awaitExpectations]; +} + +- (void)testGetNonExistingDocWhileOnlineServerOnly { + FIRDocumentReference *doc = [self documentRef]; + + // get doc and ensure that it does not exist and is *not* from the cache. + FIRDocumentSnapshot* snapshot = [self readDocumentForRef:doc getOptions:[[FIRGetOptions alloc] initWithSource:FIRServer]]; + XCTAssertFalse(snapshot.exists); + XCTAssertFalse(snapshot.metadata.fromCache); +} + +- (void)testGetNonExistingDocWhileOfflineServerOnly { + FIRDocumentReference *doc = [self documentRef]; + + // go offline for the rest of this test + [self disableNetwork]; + + // attempt to get doc. Currently, this is expected to fail. In the future, we + // might consider adding support for negative cache hits so that we know + // certain documents *don't* exist. + XCTestExpectation *getNonExistingDocCompletion = [self expectationWithDescription:@"getNonExistingDoc"]; + [doc getDocumentWithOptions:[[FIRGetOptions alloc] initWithSource:FIRServer] completion:^(FIRDocumentSnapshot *snapshot, NSError *error) { + XCTAssertNotNil(error); + XCTAssertEqualObjects(error.domain, FIRFirestoreErrorDomain); + XCTAssertEqual(error.code, FIRFirestoreErrorCodeUnavailable); + [getNonExistingDocCompletion fulfill]; + }]; + [self awaitExpectations]; +} + +@end diff --git a/Firestore/Example/Tests/SpecTests/FSTSyncEngineTestDriver.m b/Firestore/Example/Tests/SpecTests/FSTSyncEngineTestDriver.m index da6393321a3..58e978ba275 100644 --- a/Firestore/Example/Tests/SpecTests/FSTSyncEngineTestDriver.m +++ b/Firestore/Example/Tests/SpecTests/FSTSyncEngineTestDriver.m @@ -243,7 +243,9 @@ - (FSTTargetID)addUserListenerWithQuery:(FSTQuery *)query { // TODO(dimond): Change spec tests to verify isFromCache on snapshots FSTListenOptions *options = [[FSTListenOptions alloc] initWithIncludeQueryMetadataChanges:YES includeDocumentMetadataChanges:YES - waitForSyncWhenOnline:NO]; + waitForSyncWhenOnline:NO + getOptions:[FIRGetOptions defaultOptions]]; + FSTQueryListener *listener = [[FSTQueryListener alloc] initWithQuery:query options:options diff --git a/Firestore/Example/Tests/Util/FSTIntegrationTestCase.h b/Firestore/Example/Tests/Util/FSTIntegrationTestCase.h index ac5425308ce..66bd60c923e 100644 --- a/Firestore/Example/Tests/Util/FSTIntegrationTestCase.h +++ b/Firestore/Example/Tests/Util/FSTIntegrationTestCase.h @@ -23,6 +23,7 @@ @class FIRCollectionReference; @class FIRDocumentSnapshot; @class FIRDocumentReference; +@class FIRGetOptions; @class FIRQuerySnapshot; @class FIRFirestore; @class FIRFirestoreSettings; @@ -72,6 +73,8 @@ extern "C" { - (FIRDocumentSnapshot *)readDocumentForRef:(FIRDocumentReference *)ref; +- (FIRDocumentSnapshot *)readDocumentForRef:(FIRDocumentReference *)ref getOptions:(FIRGetOptions *)getOptions; + - (FIRQuerySnapshot *)readDocumentSetForRef:(FIRQuery *)query; - (FIRDocumentSnapshot *)readSnapshotForRef:(FIRDocumentReference *)query diff --git a/Firestore/Example/Tests/Util/FSTIntegrationTestCase.mm b/Firestore/Example/Tests/Util/FSTIntegrationTestCase.mm index ef15056c5af..e6edbf9e38e 100644 --- a/Firestore/Example/Tests/Util/FSTIntegrationTestCase.mm +++ b/Firestore/Example/Tests/Util/FSTIntegrationTestCase.mm @@ -209,10 +209,14 @@ - (void)readerAndWriterOnDocumentRef:(void (^)(NSString *path, } - (FIRDocumentSnapshot *)readDocumentForRef:(FIRDocumentReference *)ref { + return [self readDocumentForRef:ref getOptions:[FIRGetOptions defaultOptions]]; +} + +- (FIRDocumentSnapshot *)readDocumentForRef:(FIRDocumentReference *)ref getOptions:(FIRGetOptions *)getOptions { __block FIRDocumentSnapshot *result; XCTestExpectation *expectation = [self expectationWithDescription:@"getData"]; - [ref getDocumentWithCompletion:^(FIRDocumentSnapshot *doc, NSError *_Nullable error) { + [ref getDocumentWithOptions:getOptions completion:^(FIRDocumentSnapshot *doc, NSError *_Nullable error) { XCTAssertNil(error); result = doc; [expectation fulfill]; diff --git a/Firestore/Source/API/FIRDocumentReference.m b/Firestore/Source/API/FIRDocumentReference.m index 87e66318a03..d0e4612c48c 100644 --- a/Firestore/Source/API/FIRDocumentReference.m +++ b/Firestore/Source/API/FIRDocumentReference.m @@ -24,6 +24,7 @@ #import "Firestore/Source/API/FIRDocumentReference+Internal.h" #import "Firestore/Source/API/FIRDocumentSnapshot+Internal.h" #import "Firestore/Source/API/FIRFirestore+Internal.h" +#import "Firestore/Source/API/FIRGetOptions+Internal.h" #import "Firestore/Source/API/FIRListenerRegistration+Internal.h" #import "Firestore/Source/API/FIRSetOptions+Internal.h" #import "Firestore/Source/API/FSTUserDataConverter.h" @@ -209,6 +210,16 @@ - (void)deleteDocumentWithCompletion:(nullable void (^)(NSError *_Nullable error - (void)getDocumentWithCompletion:(void (^)(FIRDocumentSnapshot *_Nullable document, NSError *_Nullable error))completion { + return [self getDocumentWithOptions:[FIRGetOptions defaultOptions] completion:completion]; +} + +- (void)getDocumentWithOptions:(FIRGetOptions *)options completion:(void (^)(FIRDocumentSnapshot *_Nullable document, + NSError *_Nullable error))completion { + if (options.source == FIRCache) { + [self.firestore.client getDocumentFromLocalCache:self completion:completion]; + return; + } + FSTListenOptions *listenOptions = [[FSTListenOptions alloc] initWithIncludeQueryMetadataChanges:YES includeDocumentMetadataChanges:YES @@ -244,6 +255,8 @@ - (void)getDocumentWithCompletion:(void (^)(FIRDocumentSnapshot *_Nullable docum NSLocalizedDescriptionKey : @"Failed to get document because the client is offline.", }]); + } else if (snapshot.exists && snapshot.metadata.fromCache && options.source == FIRServer) { + completion(nil, [NSError errorWithDomain:FIRFirestoreErrorDomain code:FIRFirestoreErrorCodeUnavailable userInfo:@{NSLocalizedDescriptionKey: @"Failed to get document from server."}]); } else { completion(snapshot, nil); } diff --git a/Firestore/Source/API/FIRGetOptions+Internal.h b/Firestore/Source/API/FIRGetOptions+Internal.h new file mode 100644 index 00000000000..ad5c4b3e9fe --- /dev/null +++ b/Firestore/Source/API/FIRGetOptions+Internal.h @@ -0,0 +1,28 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FIRGetOptions.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRGetOptions () + +/** Where getDocument[s] calls should get their data from. */ +@property(nonatomic, readonly, getter=source) FIRSource source; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Firestore/Source/API/FIRGetOptions.m b/Firestore/Source/API/FIRGetOptions.m new file mode 100644 index 00000000000..c63396206b1 --- /dev/null +++ b/Firestore/Source/API/FIRGetOptions.m @@ -0,0 +1,36 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "Firestore/Source/API/FIRGetOptions+Internal.h" + +NS_ASSUME_NONNULL_BEGIN + +@implementation FIRGetOptions + ++ (FIRGetOptions *)defaultOptions { + return [[FIRGetOptions alloc] initWithSource:FIRDefault]; +} + +- (instancetype)initWithSource:(FIRSource)source { + if (self = [super init]) { + _source = source; + } + return self; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Firestore/Source/Core/FSTFirestoreClient.h b/Firestore/Source/Core/FSTFirestoreClient.h index 0ecf2f6b108..4afac251e50 100644 --- a/Firestore/Source/Core/FSTFirestoreClient.h +++ b/Firestore/Source/Core/FSTFirestoreClient.h @@ -20,6 +20,8 @@ #import "Firestore/Source/Core/FSTViewSnapshot.h" #import "Firestore/Source/Remote/FSTRemoteStore.h" +@class FIRDocumentReference; +@class FIRDocumentSnapshot; @class FSTDatabaseID; @class FSTDatabaseInfo; @class FSTDispatchQueue; @@ -70,6 +72,12 @@ NS_ASSUME_NONNULL_BEGIN /** Stops listening to a query previously listened to. */ - (void)removeListener:(FSTQueryListener *)listener; +/** + * Retrieves a document from the cache via the indicated completion. If the doc + * doesn't exist, an error will be sent to the completion. + */ +- (void)getDocumentFromLocalCache:(FIRDocumentReference *)doc completion:(void (^)(FIRDocumentSnapshot *_Nullable document, NSError *_Nullable error))completion; + /** Write mutations. completion will be notified when it's written to the backend. */ - (void)writeMutations:(NSArray *)mutations completion:(nullable FSTVoidErrorBlock)completion; diff --git a/Firestore/Source/Core/FSTFirestoreClient.m b/Firestore/Source/Core/FSTFirestoreClient.m index fff644da62d..c4e309d4db0 100644 --- a/Firestore/Source/Core/FSTFirestoreClient.m +++ b/Firestore/Source/Core/FSTFirestoreClient.m @@ -16,6 +16,7 @@ #import "Firestore/Source/Core/FSTFirestoreClient.h" +#import "FIRFirestoreErrors.h" #import "Firestore/Source/Auth/FSTCredentialsProvider.h" #import "Firestore/Source/Core/FSTDatabaseInfo.h" #import "Firestore/Source/Core/FSTEventManager.h" @@ -34,6 +35,8 @@ #import "Firestore/Source/Util/FSTClasses.h" #import "Firestore/Source/Util/FSTDispatchQueue.h" #import "Firestore/Source/Util/FSTLogger.h" +#import "Firestore/Source/API/FIRDocumentReference+Internal.h" +#import "Firestore/Source/API/FIRDocumentSnapshot+Internal.h" NS_ASSUME_NONNULL_BEGIN @@ -249,6 +252,17 @@ - (void)removeListener:(FSTQueryListener *)listener { }]; } +- (void)getDocumentFromLocalCache:(FIRDocumentReference *)doc completion:(void (^)(FIRDocumentSnapshot *_Nullable document, NSError *_Nullable error))completion { + [self.workerDispatchQueue dispatchAsync:^{ + FSTMaybeDocument *maybeDoc = [self.localStore readDocument:doc.key]; + if (maybeDoc) { + completion([FIRDocumentSnapshot snapshotWithFirestore:doc.firestore documentKey:doc.key document:(FSTDocument *)maybeDoc fromCache:YES], nil); + } else { + completion(nil, [NSError errorWithDomain:FIRFirestoreErrorDomain code:FIRFirestoreErrorCodeUnavailable userInfo:@{NSLocalizedDescriptionKey: @"Failed to get document from server.",}]); + } + }]; +} + - (void)writeMutations:(NSArray *)mutations completion:(nullable FSTVoidErrorBlock)completion { [self.workerDispatchQueue dispatchAsync:^{ diff --git a/Firestore/Source/Public/FIRDocumentReference.h b/Firestore/Source/Public/FIRDocumentReference.h index 7fcc7a873ae..fc4ffc13fad 100644 --- a/Firestore/Source/Public/FIRDocumentReference.h +++ b/Firestore/Source/Public/FIRDocumentReference.h @@ -21,6 +21,7 @@ @class FIRFirestore; @class FIRCollectionReference; @class FIRDocumentSnapshot; +@class FIRGetOptions; @class FIRSetOptions; NS_ASSUME_NONNULL_BEGIN @@ -195,6 +196,11 @@ NS_SWIFT_NAME(DocumentReference) - (void)getDocumentWithCompletion:(FIRDocumentSnapshotBlock)completion NS_SWIFT_NAME(getDocument(completion:)); +// clang-format off +- (void)getDocumentWithOptions:(FIRGetOptions *)options completion:(FIRDocumentSnapshotBlock)completion + NS_SWIFT_NAME(getDocument(options:completion:)); +// clang-format on + /** * Attaches a listener for DocumentSnapshot events. * diff --git a/Firestore/Source/Public/FIRGetOptions.h b/Firestore/Source/Public/FIRGetOptions.h new file mode 100644 index 00000000000..8965506c505 --- /dev/null +++ b/Firestore/Source/Public/FIRGetOptions.h @@ -0,0 +1,69 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +/** + * An options object that configures the behavior of + * `DocumentReference.getDocument()` and `CollectionReference.getDocuments()`. + * By providing a `GetOptions` object the `getDocument[s]` methods can be + * configured to fetch results only from the server, only from the local cache, + * or attempt the server and fall back to the cache (which is the default). + */ +NS_SWIFT_NAME(GetOptions) +@interface FIRGetOptions : NSObject + +/** + * Returns the default options. + * + * Equiavlent to `[[FIRGetOptions alloc] initWithSource:FIRDefault]` in + * objective-c. + */ ++ (FIRGetOptions *)defaultOptions NS_SWIFT_NAME(defaultOptions()); + +/** + * Describes whether we should get from server or cache. + * + * Setting the GetOption source to FIRDefault, if online, causes Firestore to + * try to give a consistent (server-retrieved) snapshot, or else revert to the + * cache to provide a value. + * + * FIRServer causes Firestore to avoid the cache (generating an error if a + * value cannot be retrieved from the server). The cache will be updated if the + * RPC succeeds. Latency compensation still occurs (implying that if the cache + * is more up to date, then it's values will be merged into the results). + * + * FIRCache causes Firestore to immediately return a value from the cache, + * ignoring the server completely (implying that the returned value may be + * stale with respect to the value on the server.) For a single document, the + * get will fail if the document doesn't exist. + */ +typedef NS_ENUM(NSUInteger, FIRSource) { + FIRDefault, + FIRServer, + FIRCache +} NS_SWIFT_NAME(Source); + +/** + * Initializes the get options with the specified source. + */ +- (instancetype)initWithSource:(FIRSource)source NS_SWIFT_NAME(init(source:)); + +@end + +NS_ASSUME_NONNULL_END From 6d29de2646bfad1f5c8b643ce55dee61f6c84f9a Mon Sep 17 00:00:00 2001 From: Rich Gowman Date: Wed, 10 Jan 2018 19:15:35 -0500 Subject: [PATCH 02/12] GetOptions for controlling offline behaviour (pt2) Enable GetOptions for CollectionReference / Query .getDocuments(). --- .../Integration/API/FIRGetOptionsTests.m | 289 +++++++++++++++++- .../Tests/Util/FSTIntegrationTestCase.h | 2 + .../Tests/Util/FSTIntegrationTestCase.mm | 6 +- Firestore/Source/API/FIRQuery.m | 17 +- Firestore/Source/Core/FSTFirestoreClient.h | 8 + Firestore/Source/Core/FSTFirestoreClient.m | 24 ++ Firestore/Source/Public/FIRQuery.h | 4 + 7 files changed, 340 insertions(+), 10 deletions(-) diff --git a/Firestore/Example/Tests/Integration/API/FIRGetOptionsTests.m b/Firestore/Example/Tests/Integration/API/FIRGetOptionsTests.m index 7a83f26d1e2..e6d81c45210 100644 --- a/Firestore/Example/Tests/Integration/API/FIRGetOptionsTests.m +++ b/Firestore/Example/Tests/Integration/API/FIRGetOptionsTests.m @@ -43,6 +43,28 @@ - (void)testGetDocumentWhileOnlineWithDefaultGetOptions { XCTAssertEqualObjects(result.data, initialData); } +- (void)testGetDocumentsWhileOnlineWithDefaultGetOptions { + FIRCollectionReference *col = [self collectionRef]; + + // set a few documents to known values + NSDictionary *> *initialDocs = @{ + @"doc1": @{@"key1" : @"value1"}, + @"doc2": @{@"key2" : @"value2"}, + @"doc3": @{@"key3" : @"value3"} + }; + [self writeAllDocuments:initialDocs toCollection:col]; + + // get docs and ensure they are *not* from the cache, and match the + // initialDocs. + FIRQuerySnapshot *result = [self readDocumentSetForRef:col]; + XCTAssertFalse(result.metadata.fromCache); + XCTAssertEqualObjects(FIRQuerySnapshotGetData(result), (@[ + @{@"key1" : @"value1"}, + @{@"key2" : @"value2"}, + @{@"key3" : @"value3"} + ])); +} + - (void)testGetDocumentWhileOfflineWithDefaultGetOptions { FIRDocumentReference *doc = [self documentRef]; @@ -69,6 +91,38 @@ - (void)testGetDocumentWhileOfflineWithDefaultGetOptions { XCTAssertEqualObjects(result.data, newData); } +- (void)testGetDocumentsWhileOfflineWithDefaultGetOptions { + FIRCollectionReference *col = [self collectionRef]; + + // set a few documents to known values + NSDictionary *> *initialDocs = @{ + @"doc1": @{@"key1" : @"value1"}, + @"doc2": @{@"key2" : @"value2"}, + @"doc3": @{@"key3" : @"value3"} + }; + [self writeAllDocuments:initialDocs toCollection:col]; + + // go offline for the rest of this test + [self disableNetwork]; + + // update the docs (though don't wait for a server response. We're offline; so + // that ain't happening!). This allows us to further distinguished cached vs + // server responses below. + [[col documentWithPath:@"doc2"] setData:@{@"key2b": @"value2b"} options:FIRSetOptions.merge]; + [[col documentWithPath:@"doc3"] setData:@{@"key3b" : @"value3b"}]; + [[col documentWithPath:@"doc4"] setData:@{@"key4" : @"value4"}]; + + // get docs and ensure they *are* from the cache, and matches the updated data. + FIRQuerySnapshot *result = [self readDocumentSetForRef:col]; + XCTAssertTrue(result.metadata.fromCache); + XCTAssertEqualObjects(FIRQuerySnapshotGetData(result), (@[ + @{@"key1": @"value1"}, + @{@"key2": @"value2", @"key2b": @"value2b"}, + @{@"key3b": @"value3b"}, + @{@"key4": @"value4"} + ])); +} + - (void)testGetDocumentWhileOnlineCacheOnly { FIRDocumentReference *doc = [self documentRef]; @@ -84,6 +138,28 @@ - (void)testGetDocumentWhileOnlineCacheOnly { XCTAssertEqualObjects(result.data, initialData); } +- (void)testGetDocumentsWhileOnlineCacheOnly { + FIRCollectionReference *col = [self collectionRef]; + + // set a few documents to a known value + NSDictionary *> *initialDocs = @{ + @"doc1": @{@"key1" : @"value1"}, + @"doc2": @{@"key2" : @"value2"}, + @"doc3": @{@"key3" : @"value3"}, + }; + [self writeAllDocuments:initialDocs toCollection:col]; + + // get docs and ensure they *are* from the cache, and matches the + // initialDocs. + FIRQuerySnapshot *result = [self readDocumentSetForRef:col getOptions:[[FIRGetOptions alloc] initWithSource:FIRCache]]; + XCTAssertTrue(result.metadata.fromCache); + XCTAssertEqualObjects(FIRQuerySnapshotGetData(result), (@[ + @{@"key1": @"value1"}, + @{@"key2": @"value2"}, + @{@"key3": @"value3"}, + ])); +} + - (void)testGetDocumentWhileOfflineCacheOnly { FIRDocumentReference *doc = [self documentRef]; @@ -110,6 +186,39 @@ - (void)testGetDocumentWhileOfflineCacheOnly { XCTAssertEqualObjects(result.data, newData); } +- (void)testGetDocumentsWhileOfflineCacheOnly { + FIRCollectionReference *col = [self collectionRef]; + + // set a few documents to a known value + NSDictionary *> *initialDocs = @{ + @"doc1": @{@"key1" : @"value1"}, + @"doc2": @{@"key2" : @"value2"}, + @"doc3": @{@"key3" : @"value3"}, + }; + [self writeAllDocuments:initialDocs toCollection:col]; + + // go offline for the rest of this test + [self disableNetwork]; + + // update the docs (though don't wait for a server response. We're offline; so + // that ain't happening!). This allows us to further distinguished cached vs + // server responses below. + [[col documentWithPath:@"doc2"] setData:@{@"key2b": @"value2b"} options:FIRSetOptions.merge]; + [[col documentWithPath:@"doc3"] setData:@{@"key3b" : @"value3b"}]; + [[col documentWithPath:@"doc4"] setData:@{@"key4" : @"value4"}]; + + // get docs and ensure they *are* from the cache, and matches the updated + // data. + FIRQuerySnapshot *result = [self readDocumentSetForRef:col getOptions:[[FIRGetOptions alloc] initWithSource:FIRCache]]; + XCTAssertTrue(result.metadata.fromCache); + XCTAssertEqualObjects(FIRQuerySnapshotGetData(result), (@[ + @{@"key1": @"value1"}, + @{@"key2": @"value2", @"key2b": @"value2b"}, + @{@"key3b": @"value3b"}, + @{@"key4": @"value4"} + ])); +} + - (void)testGetDocumentWhileOnlineServerOnly { FIRDocumentReference *doc = [self documentRef]; @@ -125,6 +234,28 @@ - (void)testGetDocumentWhileOnlineServerOnly { XCTAssertEqualObjects(result.data, initialData); } +- (void)testGetDocumentsWhileOnlineServerOnly { + FIRCollectionReference *col = [self collectionRef]; + + // set a few documents to a known value + NSDictionary *> *initialDocs = @{ + @"doc1": @{@"key1" : @"value1"}, + @"doc2": @{@"key2" : @"value2"}, + @"doc3": @{@"key3" : @"value3"}, + }; + [self writeAllDocuments:initialDocs toCollection:col]; + + // get docs and ensure they are *not* from the cache, and matches the + // initialData. + FIRQuerySnapshot *result = [self readDocumentSetForRef:col getOptions:[[FIRGetOptions alloc] initWithSource:FIRServer]]; + XCTAssertFalse(result.metadata.fromCache); + XCTAssertEqualObjects(FIRQuerySnapshotGetData(result), (@[ + @{@"key1": @"value1"}, + @{@"key2": @"value2"}, + @{@"key3": @"value3"}, + ])); +} + - (void)testGetDocumentWhileOfflineServerOnly { FIRDocumentReference *doc = [self documentRef]; @@ -135,14 +266,6 @@ - (void)testGetDocumentWhileOfflineServerOnly { // go offline for the rest of this test [self disableNetwork]; - // update the doc (though don't wait for a server response. We're offline; so - // that ain't happening!). This allows us to further distinguished cached vs - // server responses below. - NSDictionary *newData = @{@"key2" : @"value2"}; - [doc setData:newData completion:^(NSError *_Nullable error) { - XCTAssertTrue(false, "Because we're offline, this should never occur."); - }]; - // attempt to get doc and ensure it cannot be retreived XCTestExpectation *failedGetDocCompletion = [self expectationWithDescription:@"failedGetDoc"]; [doc getDocumentWithOptions:[[FIRGetOptions alloc] initWithSource:FIRServer] completion:^(FIRDocumentSnapshot *snapshot, NSError *error) { @@ -154,6 +277,31 @@ - (void)testGetDocumentWhileOfflineServerOnly { [self awaitExpectations]; } +- (void)testGetDocumentsWhileOfflineServerOnly { + FIRCollectionReference *col = [self collectionRef]; + + // set a few documents to a known value + NSDictionary *> *initialDocs = @{ + @"doc1": @{@"key1" : @"value1"}, + @"doc2": @{@"key2" : @"value2"}, + @"doc3": @{@"key3" : @"value3"}, + }; + [self writeAllDocuments:initialDocs toCollection:col]; + + // go offline for the rest of this test + [self disableNetwork]; + + // attempt to get docs and ensure they cannot be retreived + XCTestExpectation *failedGetDocsCompletion = [self expectationWithDescription:@"failedGetDocs"]; + [col getDocumentsWithOptions:[[FIRGetOptions alloc] initWithSource:FIRServer] completion:^(FIRQuerySnapshot *snapshot, NSError *error) { + XCTAssertNotNil(error); + XCTAssertEqualObjects(error.domain, FIRFirestoreErrorDomain); + XCTAssertEqual(error.code, FIRFirestoreErrorCodeUnavailable); + [failedGetDocsCompletion fulfill]; + }]; + [self awaitExpectations]; +} + - (void)testGetDocumentWhileOfflineWithDifferentGetOptions { FIRDocumentReference *doc = [self documentRef]; @@ -203,6 +351,68 @@ - (void)testGetDocumentWhileOfflineWithDifferentGetOptions { [self awaitExpectations]; } +- (void)testGetDocumentsWhileOfflineWithDifferentGetOptions { + FIRCollectionReference *col = [self collectionRef]; + + // set a few documents to a known value + NSDictionary *> *initialDocs = @{ + @"doc1": @{@"key1" : @"value1"}, + @"doc2": @{@"key2" : @"value2"}, + @"doc3": @{@"key3" : @"value3"}, + }; + [self writeAllDocuments:initialDocs toCollection:col]; + + // go offline for the rest of this test + [self disableNetwork]; + + // update the docs (though don't wait for a server response. We're offline; so + // that ain't happening!). This allows us to further distinguished cached vs + // server responses below. + [[col documentWithPath:@"doc2"] setData:@{@"key2b": @"value2b"} options:FIRSetOptions.merge]; + [[col documentWithPath:@"doc3"] setData:@{@"key3b" : @"value3b"}]; + [[col documentWithPath:@"doc4"] setData:@{@"key4" : @"value4"}]; + + // Create an initial listener for this query (to attempt to disrupt the gets + // below) and wait for the listener to be fully initialized before + // continuing. + XCTestExpectation *listenerReady = [self expectationWithDescription:@"listenerReady"]; + [col addSnapshotListener:^(FIRQuerySnapshot *snapshot, NSError *error) { + [listenerReady fulfill]; + }]; + [self awaitExpectations]; + + // get docs (from cache) and ensure they *are* from the cache, and + // matches the updated data. + FIRQuerySnapshot *result = [self readDocumentSetForRef:col getOptions:[[FIRGetOptions alloc] initWithSource:FIRCache]]; + XCTAssertTrue(result.metadata.fromCache); + XCTAssertEqualObjects(FIRQuerySnapshotGetData(result), (@[ + @{@"key1": @"value1"}, + @{@"key2": @"value2", @"key2b": @"value2b"}, + @{@"key3b": @"value3b"}, + @{@"key4": @"value4"} + ])); + + // attempt to get docs (with default get options) + result = [self readDocumentSetForRef:col getOptions:[[FIRGetOptions alloc] initWithSource:FIRDefault]]; + XCTAssertTrue(result.metadata.fromCache); + XCTAssertEqualObjects(FIRQuerySnapshotGetData(result), (@[ + @{@"key1": @"value1"}, + @{@"key2": @"value2", @"key2b": @"value2b"}, + @{@"key3b": @"value3b"}, + @{@"key4": @"value4"} + ])); + + // attempt to get docs (from the server) and ensure they cannot be retreived + XCTestExpectation *failedGetDocsCompletion = [self expectationWithDescription:@"failedGetDocs"]; + [col getDocumentsWithOptions:[[FIRGetOptions alloc] initWithSource:FIRServer] completion:^(FIRQuerySnapshot *snapshot, NSError *error) { + XCTAssertNotNil(error); + XCTAssertEqualObjects(error.domain, FIRFirestoreErrorDomain); + XCTAssertEqual(error.code, FIRFirestoreErrorCodeUnavailable); + [failedGetDocsCompletion fulfill]; + }]; + [self awaitExpectations]; +} + - (void)testGetNonExistingDocWhileOnlineWithDefaultGetOptions { FIRDocumentReference *doc = [self documentRef]; @@ -212,6 +422,14 @@ - (void)testGetNonExistingDocWhileOnlineWithDefaultGetOptions { XCTAssertFalse(snapshot.metadata.fromCache); } +- (void)testGetNonExistingDocsWhileOnlineWithDefaultGetOptions { + FIRCollectionReference *col = [self collectionRef]; + + // get docs and ensure that they are *not* from the cache. + FIRQuerySnapshot* snapshot = [self readDocumentSetForRef:col]; + XCTAssertFalse(snapshot.metadata.fromCache); +} + - (void)testGetNonExistingDocWhileOfflineWithDefaultGetOptions { FIRDocumentReference *doc = [self documentRef]; @@ -231,6 +449,17 @@ - (void)testGetNonExistingDocWhileOfflineWithDefaultGetOptions { [self awaitExpectations]; } +- (void)testGetNonExistingDocsWhileOfflineWithDefaultGetOptions { + FIRCollectionReference *col = [self collectionRef]; + + // go offline for the rest of this test + [self disableNetwork]; + + // get docs and ensure they *are* from the cache. + FIRQuerySnapshot *snapshot = [self readDocumentSetForRef:col]; + XCTAssertTrue(snapshot.metadata.fromCache); +} + - (void)testGetNonExistingDocWhileOnlineCacheOnly { FIRDocumentReference *doc = [self documentRef]; @@ -247,6 +476,14 @@ - (void)testGetNonExistingDocWhileOnlineCacheOnly { [self awaitExpectations]; } +- (void)testGetNonExistingDocsWhileOnlineCacheOnly { + FIRCollectionReference *col = [self collectionRef]; + + // get docs and ensure they *are* from the cache. + FIRQuerySnapshot *snapshot = [self readDocumentSetForRef:col getOptions:[[FIRGetOptions alloc] initWithSource:FIRCache]]; + XCTAssertTrue(snapshot.metadata.fromCache); +} + - (void)testGetNonExistingDocWhileOfflineCacheOnly { FIRDocumentReference *doc = [self documentRef]; @@ -266,6 +503,17 @@ - (void)testGetNonExistingDocWhileOfflineCacheOnly { [self awaitExpectations]; } +- (void)testGetNonExistingDocsWhileOfflineCacheOnly { + FIRCollectionReference *col = [self collectionRef]; + + // go offline for the rest of this test + [self disableNetwork]; + + // get docs and ensure they *are* from the cache. + FIRQuerySnapshot *snapshot = [self readDocumentSetForRef:col getOptions:[[FIRGetOptions alloc] initWithSource:FIRCache]]; + XCTAssertTrue(snapshot.metadata.fromCache); +} + - (void)testGetNonExistingDocWhileOnlineServerOnly { FIRDocumentReference *doc = [self documentRef]; @@ -275,6 +523,14 @@ - (void)testGetNonExistingDocWhileOnlineServerOnly { XCTAssertFalse(snapshot.metadata.fromCache); } +- (void)testGetNonExistingDocsWhileOnlineServerOnly { + FIRCollectionReference *col = [self collectionRef]; + + // get docs and ensure that they are *not* from the cache. + FIRQuerySnapshot* snapshot = [self readDocumentSetForRef:col getOptions:[[FIRGetOptions alloc] initWithSource:FIRServer]]; + XCTAssertFalse(snapshot.metadata.fromCache); +} + - (void)testGetNonExistingDocWhileOfflineServerOnly { FIRDocumentReference *doc = [self documentRef]; @@ -294,4 +550,21 @@ - (void)testGetNonExistingDocWhileOfflineServerOnly { [self awaitExpectations]; } +- (void)testGetNonExistingDocsWhileOfflineServerOnly { + FIRCollectionReference *col = [self collectionRef]; + + // go offline for the rest of this test + [self disableNetwork]; + + // attempt to get docs and ensure they cannot be retreived + XCTestExpectation *failedGetDocsCompletion = [self expectationWithDescription:@"failedGetDocs"]; + [col getDocumentsWithOptions:[[FIRGetOptions alloc] initWithSource:FIRServer] completion:^(FIRQuerySnapshot *snapshot, NSError *error) { + XCTAssertNotNil(error); + XCTAssertEqualObjects(error.domain, FIRFirestoreErrorDomain); + XCTAssertEqual(error.code, FIRFirestoreErrorCodeUnavailable); + [failedGetDocsCompletion fulfill]; + }]; + [self awaitExpectations]; +} + @end diff --git a/Firestore/Example/Tests/Util/FSTIntegrationTestCase.h b/Firestore/Example/Tests/Util/FSTIntegrationTestCase.h index 66bd60c923e..f47ff298414 100644 --- a/Firestore/Example/Tests/Util/FSTIntegrationTestCase.h +++ b/Firestore/Example/Tests/Util/FSTIntegrationTestCase.h @@ -77,6 +77,8 @@ extern "C" { - (FIRQuerySnapshot *)readDocumentSetForRef:(FIRQuery *)query; +- (FIRQuerySnapshot *)readDocumentSetForRef:(FIRQuery *)query getOptions:(FIRGetOptions *)getOptions; + - (FIRDocumentSnapshot *)readSnapshotForRef:(FIRDocumentReference *)query requireOnline:(BOOL)online; diff --git a/Firestore/Example/Tests/Util/FSTIntegrationTestCase.mm b/Firestore/Example/Tests/Util/FSTIntegrationTestCase.mm index e6edbf9e38e..b1de158d56c 100644 --- a/Firestore/Example/Tests/Util/FSTIntegrationTestCase.mm +++ b/Firestore/Example/Tests/Util/FSTIntegrationTestCase.mm @@ -227,10 +227,14 @@ - (FIRDocumentSnapshot *)readDocumentForRef:(FIRDocumentReference *)ref getOptio } - (FIRQuerySnapshot *)readDocumentSetForRef:(FIRQuery *)query { + return [self readDocumentSetForRef:query getOptions:[FIRGetOptions defaultOptions]]; +} + +- (FIRQuerySnapshot *)readDocumentSetForRef:(FIRQuery *)query getOptions:(FIRGetOptions *)getOptions { __block FIRQuerySnapshot *result; XCTestExpectation *expectation = [self expectationWithDescription:@"getData"]; - [query getDocumentsWithCompletion:^(FIRQuerySnapshot *documentSet, NSError *error) { + [query getDocumentsWithOptions:getOptions completion:^(FIRQuerySnapshot *documentSet, NSError *error) { XCTAssertNil(error); result = documentSet; [expectation fulfill]; diff --git a/Firestore/Source/API/FIRQuery.m b/Firestore/Source/API/FIRQuery.m index 2feca393948..00fd433f101 100644 --- a/Firestore/Source/API/FIRQuery.m +++ b/Firestore/Source/API/FIRQuery.m @@ -17,10 +17,12 @@ #import "FIRQuery.h" #import "FIRDocumentReference.h" +#import "FIRFirestoreErrors.h" #import "Firestore/Source/API/FIRDocumentReference+Internal.h" #import "Firestore/Source/API/FIRDocumentSnapshot+Internal.h" #import "Firestore/Source/API/FIRFieldPath+Internal.h" #import "Firestore/Source/API/FIRFirestore+Internal.h" +#import "Firestore/Source/API/FIRGetOptions+Internal.h" #import "Firestore/Source/API/FIRListenerRegistration+Internal.h" #import "Firestore/Source/API/FIRQuery+Internal.h" #import "Firestore/Source/API/FIRQuerySnapshot+Internal.h" @@ -130,6 +132,15 @@ - (NSUInteger)hash { - (void)getDocumentsWithCompletion:(void (^)(FIRQuerySnapshot *_Nullable snapshot, NSError *_Nullable error))completion { + [self getDocumentsWithOptions:[FIRGetOptions defaultOptions] completion:completion]; +} + +- (void)getDocumentsWithOptions:(FIRGetOptions *)getOptions completion:(void (^)(FIRQuerySnapshot *_Nullable snapshot, NSError *_Nullable error))completion { + if (getOptions.source == FIRCache) { + [self.firestore.client getDocumentsFromLocalCache:self completion:completion]; + return; + } + FSTListenOptions *options = [[FSTListenOptions alloc] initWithIncludeQueryMetadataChanges:YES includeDocumentMetadataChanges:YES waitForSyncWhenOnline:YES]; @@ -147,7 +158,11 @@ - (void)getDocumentsWithCompletion:(void (^)(FIRQuerySnapshot *_Nullable snapsho dispatch_semaphore_wait(registered, DISPATCH_TIME_FOREVER); [listenerRegistration remove]; - completion(snapshot, nil); + if (snapshot.metadata.fromCache && getOptions.source == FIRServer) { + completion(nil, [NSError errorWithDomain:FIRFirestoreErrorDomain code:FIRFirestoreErrorCodeUnavailable userInfo:@{NSLocalizedDescriptionKey: @"Failed to get documents from server."}]); + } else { + completion(snapshot, nil); + } }; listenerRegistration = [self addSnapshotListenerInternalWithOptions:options listener:listener]; diff --git a/Firestore/Source/Core/FSTFirestoreClient.h b/Firestore/Source/Core/FSTFirestoreClient.h index 4afac251e50..59ba5864893 100644 --- a/Firestore/Source/Core/FSTFirestoreClient.h +++ b/Firestore/Source/Core/FSTFirestoreClient.h @@ -22,6 +22,8 @@ @class FIRDocumentReference; @class FIRDocumentSnapshot; +@class FIRQuery; +@class FIRQuerySnapshot; @class FSTDatabaseID; @class FSTDatabaseInfo; @class FSTDispatchQueue; @@ -78,6 +80,12 @@ NS_ASSUME_NONNULL_BEGIN */ - (void)getDocumentFromLocalCache:(FIRDocumentReference *)doc completion:(void (^)(FIRDocumentSnapshot *_Nullable document, NSError *_Nullable error))completion; +/** + * Retrieves a (possibly empty) set of documents from the cache via the + * indicated completion. + */ +- (void)getDocumentsFromLocalCache:(FIRQuery *)query completion:(void (^)(FIRQuerySnapshot *_Nullable query, NSError *_Nullable error))completion; + /** Write mutations. completion will be notified when it's written to the backend. */ - (void)writeMutations:(NSArray *)mutations completion:(nullable FSTVoidErrorBlock)completion; diff --git a/Firestore/Source/Core/FSTFirestoreClient.m b/Firestore/Source/Core/FSTFirestoreClient.m index c4e309d4db0..1afcf2472cf 100644 --- a/Firestore/Source/Core/FSTFirestoreClient.m +++ b/Firestore/Source/Core/FSTFirestoreClient.m @@ -22,12 +22,15 @@ #import "Firestore/Source/Core/FSTEventManager.h" #import "Firestore/Source/Core/FSTSyncEngine.h" #import "Firestore/Source/Core/FSTTransaction.h" +#import "Firestore/Source/Core/FSTQuery.h" #import "Firestore/Source/Local/FSTEagerGarbageCollector.h" #import "Firestore/Source/Local/FSTLevelDB.h" #import "Firestore/Source/Local/FSTLocalSerializer.h" #import "Firestore/Source/Local/FSTLocalStore.h" #import "Firestore/Source/Local/FSTMemoryPersistence.h" #import "Firestore/Source/Local/FSTNoOpGarbageCollector.h" +#import "Firestore/Source/Model/FSTDocument.h" +#import "Firestore/Source/Model/FSTDocumentSet.h" #import "Firestore/Source/Remote/FSTDatastore.h" #import "Firestore/Source/Remote/FSTRemoteStore.h" #import "Firestore/Source/Remote/FSTSerializerBeta.h" @@ -37,6 +40,10 @@ #import "Firestore/Source/Util/FSTLogger.h" #import "Firestore/Source/API/FIRDocumentReference+Internal.h" #import "Firestore/Source/API/FIRDocumentSnapshot+Internal.h" +#import "Firestore/Source/API/FIRQuery+Internal.h" +#import "Firestore/Source/API/FIRQuerySnapshot+Internal.h" +#import "Firestore/Source/API/FIRSnapshotMetadata+Internal.h" + NS_ASSUME_NONNULL_BEGIN @@ -263,6 +270,23 @@ - (void)getDocumentFromLocalCache:(FIRDocumentReference *)doc completion:(void ( }]; } +- (void)getDocumentsFromLocalCache:(FIRQuery *)query completion:(void (^)(FIRQuerySnapshot *_Nullable query, NSError *_Nullable error))completion { + [self.workerDispatchQueue dispatchAsync:^{ + FSTDocumentDictionary *docs = [self.localStore executeQuery:query.query]; + + __block FSTDocumentSet *documents = [FSTDocumentSet documentSetWithComparator:query.query.comparator]; + FSTDocumentSet *oldDocuments = documents; + [docs enumerateKeysAndObjectsUsingBlock:^(FSTDocumentKey *key, FSTDocument *value, BOOL *stop) { + documents = [documents documentSetByAddingDocument:value]; + }]; + + FSTViewSnapshot *snapshot = [[FSTViewSnapshot alloc] initWithQuery:query.query documents:documents oldDocuments:oldDocuments documentChanges:@[] fromCache:YES hasPendingWrites:NO syncStateChanged:NO]; + FIRSnapshotMetadata *metadata = [FIRSnapshotMetadata snapshotMetadataWithPendingWrites:NO fromCache:YES]; + + completion([FIRQuerySnapshot snapshotWithFirestore:query.firestore originalQuery:query.query snapshot:snapshot metadata:metadata], nil); + }]; +} + - (void)writeMutations:(NSArray *)mutations completion:(nullable FSTVoidErrorBlock)completion { [self.workerDispatchQueue dispatchAsync:^{ diff --git a/Firestore/Source/Public/FIRQuery.h b/Firestore/Source/Public/FIRQuery.h index ff15ac6af08..b8da90f586c 100644 --- a/Firestore/Source/Public/FIRQuery.h +++ b/Firestore/Source/Public/FIRQuery.h @@ -20,6 +20,7 @@ @class FIRFieldPath; @class FIRFirestore; +@class FIRGetOptions; @class FIRQuerySnapshot; @class FIRDocumentSnapshot; @@ -90,6 +91,9 @@ NS_SWIFT_NAME(Query) - (void)getDocumentsWithCompletion:(FIRQuerySnapshotBlock)completion NS_SWIFT_NAME(getDocuments(completion:)); +- (void)getDocumentsWithOptions:(FIRGetOptions *)getOptions completion:(FIRQuerySnapshotBlock)completion + NS_SWIFT_NAME(getDocuments(options:completion:)); + /** * Attaches a listener for QuerySnapshot events. * From 30a513f4892c990a29e4f52cacf1ff23c77fce59 Mon Sep 17 00:00:00 2001 From: Rich Gowman Date: Tue, 16 Jan 2018 13:43:58 -0500 Subject: [PATCH 03/12] Address (easy) review feedback. Still have a few (more in depth) comments to address. --- .../Integration/API/FIRGetOptionsTests.m | 76 ++++++++++--------- .../Tests/Util/FSTIntegrationTestCase.h | 4 +- .../Tests/Util/FSTIntegrationTestCase.mm | 12 +-- Firestore/Source/API/FIRDocumentReference.m | 3 +- Firestore/Source/API/FIRQuery.m | 12 +-- Firestore/Source/Core/FSTFirestoreClient.m | 2 +- Firestore/Source/Public/FIRQuery.h | 2 +- 7 files changed, 57 insertions(+), 54 deletions(-) diff --git a/Firestore/Example/Tests/Integration/API/FIRGetOptionsTests.m b/Firestore/Example/Tests/Integration/API/FIRGetOptionsTests.m index e6d81c45210..1eca979bfd9 100644 --- a/Firestore/Example/Tests/Integration/API/FIRGetOptionsTests.m +++ b/Firestore/Example/Tests/Integration/API/FIRGetOptionsTests.m @@ -16,7 +16,6 @@ @import FirebaseFirestore; -#import #import #import "Firestore/Example/Tests/Util/FSTIntegrationTestCase.h" @@ -43,7 +42,7 @@ - (void)testGetDocumentWhileOnlineWithDefaultGetOptions { XCTAssertEqualObjects(result.data, initialData); } -- (void)testGetDocumentsWhileOnlineWithDefaultGetOptions { +- (void)testGetCollectionWhileOnlineWithDefaultGetOptions { FIRCollectionReference *col = [self collectionRef]; // set a few documents to known values @@ -91,7 +90,7 @@ - (void)testGetDocumentWhileOfflineWithDefaultGetOptions { XCTAssertEqualObjects(result.data, newData); } -- (void)testGetDocumentsWhileOfflineWithDefaultGetOptions { +- (void)testGetCollectionWhileOfflineWithDefaultGetOptions { FIRCollectionReference *col = [self collectionRef]; // set a few documents to known values @@ -132,13 +131,13 @@ - (void)testGetDocumentWhileOnlineCacheOnly { // get doc and ensure that it exists, *is* from the cache, and matches // the initialData. - FIRDocumentSnapshot *result = [self readDocumentForRef:doc getOptions:[[FIRGetOptions alloc] initWithSource:FIRCache]]; + FIRDocumentSnapshot *result = [self readDocumentForRef:doc options:[[FIRGetOptions alloc] initWithSource:FIRCache]]; XCTAssertTrue(result.exists); XCTAssertTrue(result.metadata.fromCache); XCTAssertEqualObjects(result.data, initialData); } -- (void)testGetDocumentsWhileOnlineCacheOnly { +- (void)testGetCollectionWhileOnlineCacheOnly { FIRCollectionReference *col = [self collectionRef]; // set a few documents to a known value @@ -151,7 +150,7 @@ - (void)testGetDocumentsWhileOnlineCacheOnly { // get docs and ensure they *are* from the cache, and matches the // initialDocs. - FIRQuerySnapshot *result = [self readDocumentSetForRef:col getOptions:[[FIRGetOptions alloc] initWithSource:FIRCache]]; + FIRQuerySnapshot *result = [self readDocumentSetForRef:col options:[[FIRGetOptions alloc] initWithSource:FIRCache]]; XCTAssertTrue(result.metadata.fromCache); XCTAssertEqualObjects(FIRQuerySnapshotGetData(result), (@[ @{@"key1": @"value1"}, @@ -180,13 +179,13 @@ - (void)testGetDocumentWhileOfflineCacheOnly { // get doc and ensure it exists, *is* from the cache, and matches the // newData. - FIRDocumentSnapshot *result = [self readDocumentForRef:doc getOptions:[[FIRGetOptions alloc] initWithSource:FIRCache]]; + FIRDocumentSnapshot *result = [self readDocumentForRef:doc options:[[FIRGetOptions alloc] initWithSource:FIRCache]]; XCTAssertTrue(result.exists); XCTAssertTrue(result.metadata.fromCache); XCTAssertEqualObjects(result.data, newData); } -- (void)testGetDocumentsWhileOfflineCacheOnly { +- (void)testGetCollectionWhileOfflineCacheOnly { FIRCollectionReference *col = [self collectionRef]; // set a few documents to a known value @@ -209,7 +208,7 @@ - (void)testGetDocumentsWhileOfflineCacheOnly { // get docs and ensure they *are* from the cache, and matches the updated // data. - FIRQuerySnapshot *result = [self readDocumentSetForRef:col getOptions:[[FIRGetOptions alloc] initWithSource:FIRCache]]; + FIRQuerySnapshot *result = [self readDocumentSetForRef:col options:[[FIRGetOptions alloc] initWithSource:FIRCache]]; XCTAssertTrue(result.metadata.fromCache); XCTAssertEqualObjects(FIRQuerySnapshotGetData(result), (@[ @{@"key1": @"value1"}, @@ -228,13 +227,13 @@ - (void)testGetDocumentWhileOnlineServerOnly { // get doc and ensure that it exists, is *not* from the cache, and matches // the initialData. - FIRDocumentSnapshot *result = [self readDocumentForRef:doc getOptions:[[FIRGetOptions alloc] initWithSource:FIRServer]]; + FIRDocumentSnapshot *result = [self readDocumentForRef:doc options:[[FIRGetOptions alloc] initWithSource:FIRServer]]; XCTAssertTrue(result.exists); XCTAssertFalse(result.metadata.fromCache); XCTAssertEqualObjects(result.data, initialData); } -- (void)testGetDocumentsWhileOnlineServerOnly { +- (void)testGetCollectionWhileOnlineServerOnly { FIRCollectionReference *col = [self collectionRef]; // set a few documents to a known value @@ -247,7 +246,7 @@ - (void)testGetDocumentsWhileOnlineServerOnly { // get docs and ensure they are *not* from the cache, and matches the // initialData. - FIRQuerySnapshot *result = [self readDocumentSetForRef:col getOptions:[[FIRGetOptions alloc] initWithSource:FIRServer]]; + FIRQuerySnapshot *result = [self readDocumentSetForRef:col options:[[FIRGetOptions alloc] initWithSource:FIRServer]]; XCTAssertFalse(result.metadata.fromCache); XCTAssertEqualObjects(FIRQuerySnapshotGetData(result), (@[ @{@"key1": @"value1"}, @@ -277,7 +276,7 @@ - (void)testGetDocumentWhileOfflineServerOnly { [self awaitExpectations]; } -- (void)testGetDocumentsWhileOfflineServerOnly { +- (void)testGetCollectionWhileOfflineServerOnly { FIRCollectionReference *col = [self collectionRef]; // set a few documents to a known value @@ -320,7 +319,7 @@ - (void)testGetDocumentWhileOfflineWithDifferentGetOptions { XCTAssertTrue(false, "Because we're offline, this should never occur."); }]; - // Create an initial listener for this query (to attempt to disrupt the gets below) and wait for the listener to be fully initialized before continuing. + // Create an initial listener for this query (to attempt to disrupt the gets below) and wait for the listener to deliver its initial snapshot before continuing. XCTestExpectation *listenerReady = [self expectationWithDescription:@"listenerReady"]; [doc addSnapshotListener:^(FIRDocumentSnapshot *snapshot, NSError *error) { [listenerReady fulfill]; @@ -329,13 +328,13 @@ - (void)testGetDocumentWhileOfflineWithDifferentGetOptions { // get doc (from cache) and ensure it exists, *is* from the cache, and // matches the newData. - FIRDocumentSnapshot *result = [self readDocumentForRef:doc getOptions:[[FIRGetOptions alloc] initWithSource:FIRCache]]; + FIRDocumentSnapshot *result = [self readDocumentForRef:doc options:[[FIRGetOptions alloc] initWithSource:FIRCache]]; XCTAssertTrue(result.exists); XCTAssertTrue(result.metadata.fromCache); XCTAssertEqualObjects(result.data, newData); // attempt to get doc (with default get options) - result = [self readDocumentForRef:doc getOptions:[[FIRGetOptions alloc] initWithSource:FIRDefault]]; + result = [self readDocumentForRef:doc options:[[FIRGetOptions alloc] initWithSource:FIRDefault]]; XCTAssertTrue(result.exists); XCTAssertTrue(result.metadata.fromCache); XCTAssertEqualObjects(result.data, newData); @@ -351,7 +350,7 @@ - (void)testGetDocumentWhileOfflineWithDifferentGetOptions { [self awaitExpectations]; } -- (void)testGetDocumentsWhileOfflineWithDifferentGetOptions { +- (void)testGetCollectionWhileOfflineWithDifferentGetOptions { FIRCollectionReference *col = [self collectionRef]; // set a few documents to a known value @@ -373,7 +372,7 @@ - (void)testGetDocumentsWhileOfflineWithDifferentGetOptions { [[col documentWithPath:@"doc4"] setData:@{@"key4" : @"value4"}]; // Create an initial listener for this query (to attempt to disrupt the gets - // below) and wait for the listener to be fully initialized before + // below) and wait for the listener to deliver its initial snapshot before // continuing. XCTestExpectation *listenerReady = [self expectationWithDescription:@"listenerReady"]; [col addSnapshotListener:^(FIRQuerySnapshot *snapshot, NSError *error) { @@ -383,7 +382,7 @@ - (void)testGetDocumentsWhileOfflineWithDifferentGetOptions { // get docs (from cache) and ensure they *are* from the cache, and // matches the updated data. - FIRQuerySnapshot *result = [self readDocumentSetForRef:col getOptions:[[FIRGetOptions alloc] initWithSource:FIRCache]]; + FIRQuerySnapshot *result = [self readDocumentSetForRef:col options:[[FIRGetOptions alloc] initWithSource:FIRCache]]; XCTAssertTrue(result.metadata.fromCache); XCTAssertEqualObjects(FIRQuerySnapshotGetData(result), (@[ @{@"key1": @"value1"}, @@ -393,7 +392,7 @@ - (void)testGetDocumentsWhileOfflineWithDifferentGetOptions { ])); // attempt to get docs (with default get options) - result = [self readDocumentSetForRef:col getOptions:[[FIRGetOptions alloc] initWithSource:FIRDefault]]; + result = [self readDocumentSetForRef:col options:[[FIRGetOptions alloc] initWithSource:FIRDefault]]; XCTAssertTrue(result.metadata.fromCache); XCTAssertEqualObjects(FIRQuerySnapshotGetData(result), (@[ @{@"key1": @"value1"}, @@ -422,11 +421,12 @@ - (void)testGetNonExistingDocWhileOnlineWithDefaultGetOptions { XCTAssertFalse(snapshot.metadata.fromCache); } -- (void)testGetNonExistingDocsWhileOnlineWithDefaultGetOptions { +- (void)testGetNonExistingCollectionWhileOnlineWithDefaultGetOptions { FIRCollectionReference *col = [self collectionRef]; - // get docs and ensure that they are *not* from the cache. + // get collection and ensure it's empty and that it's *not* from the cache. FIRQuerySnapshot* snapshot = [self readDocumentSetForRef:col]; + XCTAssertEqual(snapshot.count, 0); XCTAssertFalse(snapshot.metadata.fromCache); } @@ -449,14 +449,15 @@ - (void)testGetNonExistingDocWhileOfflineWithDefaultGetOptions { [self awaitExpectations]; } -- (void)testGetNonExistingDocsWhileOfflineWithDefaultGetOptions { +- (void)testGetNonExistingCollectionWhileOfflineWithDefaultGetOptions { FIRCollectionReference *col = [self collectionRef]; // go offline for the rest of this test [self disableNetwork]; - // get docs and ensure they *are* from the cache. + // get collection and ensure it's empty and that it *is* from the cache. FIRQuerySnapshot *snapshot = [self readDocumentSetForRef:col]; + XCTAssertEqual(snapshot.count, 0); XCTAssertTrue(snapshot.metadata.fromCache); } @@ -476,11 +477,12 @@ - (void)testGetNonExistingDocWhileOnlineCacheOnly { [self awaitExpectations]; } -- (void)testGetNonExistingDocsWhileOnlineCacheOnly { +- (void)testGetNonExistingCollectionWhileOnlineCacheOnly { FIRCollectionReference *col = [self collectionRef]; - // get docs and ensure they *are* from the cache. - FIRQuerySnapshot *snapshot = [self readDocumentSetForRef:col getOptions:[[FIRGetOptions alloc] initWithSource:FIRCache]]; + // get collection and ensure it's empty and that it *is* from the cache. + FIRQuerySnapshot *snapshot = [self readDocumentSetForRef:col options:[[FIRGetOptions alloc] initWithSource:FIRCache]]; + XCTAssertEqual(snapshot.count, 0); XCTAssertTrue(snapshot.metadata.fromCache); } @@ -503,14 +505,15 @@ - (void)testGetNonExistingDocWhileOfflineCacheOnly { [self awaitExpectations]; } -- (void)testGetNonExistingDocsWhileOfflineCacheOnly { +- (void)testGetNonExistingCollectionWhileOfflineCacheOnly { FIRCollectionReference *col = [self collectionRef]; // go offline for the rest of this test [self disableNetwork]; - // get docs and ensure they *are* from the cache. - FIRQuerySnapshot *snapshot = [self readDocumentSetForRef:col getOptions:[[FIRGetOptions alloc] initWithSource:FIRCache]]; + // get collection and ensure it's empty and that it *is* from the cache. + FIRQuerySnapshot *snapshot = [self readDocumentSetForRef:col options:[[FIRGetOptions alloc] initWithSource:FIRCache]]; + XCTAssertEqual(snapshot.count, 0); XCTAssertTrue(snapshot.metadata.fromCache); } @@ -518,16 +521,17 @@ - (void)testGetNonExistingDocWhileOnlineServerOnly { FIRDocumentReference *doc = [self documentRef]; // get doc and ensure that it does not exist and is *not* from the cache. - FIRDocumentSnapshot* snapshot = [self readDocumentForRef:doc getOptions:[[FIRGetOptions alloc] initWithSource:FIRServer]]; + FIRDocumentSnapshot* snapshot = [self readDocumentForRef:doc options:[[FIRGetOptions alloc] initWithSource:FIRServer]]; XCTAssertFalse(snapshot.exists); XCTAssertFalse(snapshot.metadata.fromCache); } -- (void)testGetNonExistingDocsWhileOnlineServerOnly { +- (void)testGetNonExistingCollectionWhileOnlineServerOnly { FIRCollectionReference *col = [self collectionRef]; - // get docs and ensure that they are *not* from the cache. - FIRQuerySnapshot* snapshot = [self readDocumentSetForRef:col getOptions:[[FIRGetOptions alloc] initWithSource:FIRServer]]; + // get collection and ensure that it's empty and that it's *not* from the cache. + FIRQuerySnapshot* snapshot = [self readDocumentSetForRef:col options:[[FIRGetOptions alloc] initWithSource:FIRServer]]; + XCTAssertEqual(snapshot.count, 0); XCTAssertFalse(snapshot.metadata.fromCache); } @@ -550,13 +554,13 @@ - (void)testGetNonExistingDocWhileOfflineServerOnly { [self awaitExpectations]; } -- (void)testGetNonExistingDocsWhileOfflineServerOnly { +- (void)testGetNonExistingCollectionWhileOfflineServerOnly { FIRCollectionReference *col = [self collectionRef]; // go offline for the rest of this test [self disableNetwork]; - // attempt to get docs and ensure they cannot be retreived + // attempt to get collection and ensure that it cannot be retreived XCTestExpectation *failedGetDocsCompletion = [self expectationWithDescription:@"failedGetDocs"]; [col getDocumentsWithOptions:[[FIRGetOptions alloc] initWithSource:FIRServer] completion:^(FIRQuerySnapshot *snapshot, NSError *error) { XCTAssertNotNil(error); diff --git a/Firestore/Example/Tests/Util/FSTIntegrationTestCase.h b/Firestore/Example/Tests/Util/FSTIntegrationTestCase.h index f47ff298414..1c256a46b64 100644 --- a/Firestore/Example/Tests/Util/FSTIntegrationTestCase.h +++ b/Firestore/Example/Tests/Util/FSTIntegrationTestCase.h @@ -73,11 +73,11 @@ extern "C" { - (FIRDocumentSnapshot *)readDocumentForRef:(FIRDocumentReference *)ref; -- (FIRDocumentSnapshot *)readDocumentForRef:(FIRDocumentReference *)ref getOptions:(FIRGetOptions *)getOptions; +- (FIRDocumentSnapshot *)readDocumentForRef:(FIRDocumentReference *)ref options:(FIRGetOptions *)options; - (FIRQuerySnapshot *)readDocumentSetForRef:(FIRQuery *)query; -- (FIRQuerySnapshot *)readDocumentSetForRef:(FIRQuery *)query getOptions:(FIRGetOptions *)getOptions; +- (FIRQuerySnapshot *)readDocumentSetForRef:(FIRQuery *)query options:(FIRGetOptions *)options; - (FIRDocumentSnapshot *)readSnapshotForRef:(FIRDocumentReference *)query requireOnline:(BOOL)online; diff --git a/Firestore/Example/Tests/Util/FSTIntegrationTestCase.mm b/Firestore/Example/Tests/Util/FSTIntegrationTestCase.mm index b1de158d56c..36542533f86 100644 --- a/Firestore/Example/Tests/Util/FSTIntegrationTestCase.mm +++ b/Firestore/Example/Tests/Util/FSTIntegrationTestCase.mm @@ -209,14 +209,14 @@ - (void)readerAndWriterOnDocumentRef:(void (^)(NSString *path, } - (FIRDocumentSnapshot *)readDocumentForRef:(FIRDocumentReference *)ref { - return [self readDocumentForRef:ref getOptions:[FIRGetOptions defaultOptions]]; + return [self readDocumentForRef:ref options:[FIRGetOptions defaultOptions]]; } -- (FIRDocumentSnapshot *)readDocumentForRef:(FIRDocumentReference *)ref getOptions:(FIRGetOptions *)getOptions { +- (FIRDocumentSnapshot *)readDocumentForRef:(FIRDocumentReference *)ref options:(FIRGetOptions *)options { __block FIRDocumentSnapshot *result; XCTestExpectation *expectation = [self expectationWithDescription:@"getData"]; - [ref getDocumentWithOptions:getOptions completion:^(FIRDocumentSnapshot *doc, NSError *_Nullable error) { + [ref getDocumentWithOptions:options completion:^(FIRDocumentSnapshot *doc, NSError *_Nullable error) { XCTAssertNil(error); result = doc; [expectation fulfill]; @@ -227,14 +227,14 @@ - (FIRDocumentSnapshot *)readDocumentForRef:(FIRDocumentReference *)ref getOptio } - (FIRQuerySnapshot *)readDocumentSetForRef:(FIRQuery *)query { - return [self readDocumentSetForRef:query getOptions:[FIRGetOptions defaultOptions]]; + return [self readDocumentSetForRef:query options:[FIRGetOptions defaultOptions]]; } -- (FIRQuerySnapshot *)readDocumentSetForRef:(FIRQuery *)query getOptions:(FIRGetOptions *)getOptions { +- (FIRQuerySnapshot *)readDocumentSetForRef:(FIRQuery *)query options:(FIRGetOptions *)options { __block FIRQuerySnapshot *result; XCTestExpectation *expectation = [self expectationWithDescription:@"getData"]; - [query getDocumentsWithOptions:getOptions completion:^(FIRQuerySnapshot *documentSet, NSError *error) { + [query getDocumentsWithOptions:options completion:^(FIRQuerySnapshot *documentSet, NSError *error) { XCTAssertNil(error); result = documentSet; [expectation fulfill]; diff --git a/Firestore/Source/API/FIRDocumentReference.m b/Firestore/Source/API/FIRDocumentReference.m index d0e4612c48c..2b7f3eb236d 100644 --- a/Firestore/Source/API/FIRDocumentReference.m +++ b/Firestore/Source/API/FIRDocumentReference.m @@ -247,7 +247,6 @@ - (void)getDocumentWithOptions:(FIRGetOptions *)options completion:(void (^)(FIR // offline. // 2) Actually call the completion handler with an error if the document doesn't exist when // you are offline. - // TODO(dimond): Use proper error domain completion(nil, [NSError errorWithDomain:FIRFirestoreErrorDomain code:FIRFirestoreErrorCodeUnavailable @@ -256,7 +255,7 @@ - (void)getDocumentWithOptions:(FIRGetOptions *)options completion:(void (^)(FIR @"Failed to get document because the client is offline.", }]); } else if (snapshot.exists && snapshot.metadata.fromCache && options.source == FIRServer) { - completion(nil, [NSError errorWithDomain:FIRFirestoreErrorDomain code:FIRFirestoreErrorCodeUnavailable userInfo:@{NSLocalizedDescriptionKey: @"Failed to get document from server."}]); + completion(nil, [NSError errorWithDomain:FIRFirestoreErrorDomain code:FIRFirestoreErrorCodeUnavailable userInfo:@{NSLocalizedDescriptionKey: @"Failed to get document from server. (However, this document does exist in the local cache. Run again without setting FIRServer in the GetOptions to retrieve the cached document.)"}]); } else { completion(snapshot, nil); } diff --git a/Firestore/Source/API/FIRQuery.m b/Firestore/Source/API/FIRQuery.m index 00fd433f101..7ea1dafb9af 100644 --- a/Firestore/Source/API/FIRQuery.m +++ b/Firestore/Source/API/FIRQuery.m @@ -135,13 +135,13 @@ - (void)getDocumentsWithCompletion:(void (^)(FIRQuerySnapshot *_Nullable snapsho [self getDocumentsWithOptions:[FIRGetOptions defaultOptions] completion:completion]; } -- (void)getDocumentsWithOptions:(FIRGetOptions *)getOptions completion:(void (^)(FIRQuerySnapshot *_Nullable snapshot, NSError *_Nullable error))completion { - if (getOptions.source == FIRCache) { +- (void)getDocumentsWithOptions:(FIRGetOptions *)options completion:(void (^)(FIRQuerySnapshot *_Nullable snapshot, NSError *_Nullable error))completion { + if (options.source == FIRCache) { [self.firestore.client getDocumentsFromLocalCache:self completion:completion]; return; } - FSTListenOptions *options = [[FSTListenOptions alloc] initWithIncludeQueryMetadataChanges:YES + FSTListenOptions *listenOptions = [[FSTListenOptions alloc] initWithIncludeQueryMetadataChanges:YES includeDocumentMetadataChanges:YES waitForSyncWhenOnline:YES]; @@ -158,14 +158,14 @@ - (void)getDocumentsWithOptions:(FIRGetOptions *)getOptions completion:(void (^) dispatch_semaphore_wait(registered, DISPATCH_TIME_FOREVER); [listenerRegistration remove]; - if (snapshot.metadata.fromCache && getOptions.source == FIRServer) { - completion(nil, [NSError errorWithDomain:FIRFirestoreErrorDomain code:FIRFirestoreErrorCodeUnavailable userInfo:@{NSLocalizedDescriptionKey: @"Failed to get documents from server."}]); + if (snapshot.metadata.fromCache && options.source == FIRServer) { + completion(nil, [NSError errorWithDomain:FIRFirestoreErrorDomain code:FIRFirestoreErrorCodeUnavailable userInfo:@{NSLocalizedDescriptionKey: @"Failed to get documents from server. (However, these documents may exist in the local cache. Run again without setting FIRServer in the GetOptions to retrieve the cached documents.)"}]); } else { completion(snapshot, nil); } }; - listenerRegistration = [self addSnapshotListenerInternalWithOptions:options listener:listener]; + listenerRegistration = [self addSnapshotListenerInternalWithOptions:listenOptions listener:listener]; dispatch_semaphore_signal(registered); } diff --git a/Firestore/Source/Core/FSTFirestoreClient.m b/Firestore/Source/Core/FSTFirestoreClient.m index 1afcf2472cf..8a5bf9d7b53 100644 --- a/Firestore/Source/Core/FSTFirestoreClient.m +++ b/Firestore/Source/Core/FSTFirestoreClient.m @@ -265,7 +265,7 @@ - (void)getDocumentFromLocalCache:(FIRDocumentReference *)doc completion:(void ( if (maybeDoc) { completion([FIRDocumentSnapshot snapshotWithFirestore:doc.firestore documentKey:doc.key document:(FSTDocument *)maybeDoc fromCache:YES], nil); } else { - completion(nil, [NSError errorWithDomain:FIRFirestoreErrorDomain code:FIRFirestoreErrorCodeUnavailable userInfo:@{NSLocalizedDescriptionKey: @"Failed to get document from server.",}]); + completion(nil, [NSError errorWithDomain:FIRFirestoreErrorDomain code:FIRFirestoreErrorCodeUnavailable userInfo:@{NSLocalizedDescriptionKey: @"Failed to get document from cache. (However, this document may exist on the server. Run again without setting FIRCache in the GetOptions to attempt to retrieve the document from the server.)",}]); } }]; } diff --git a/Firestore/Source/Public/FIRQuery.h b/Firestore/Source/Public/FIRQuery.h index b8da90f586c..28f91b1dc35 100644 --- a/Firestore/Source/Public/FIRQuery.h +++ b/Firestore/Source/Public/FIRQuery.h @@ -91,7 +91,7 @@ NS_SWIFT_NAME(Query) - (void)getDocumentsWithCompletion:(FIRQuerySnapshotBlock)completion NS_SWIFT_NAME(getDocuments(completion:)); -- (void)getDocumentsWithOptions:(FIRGetOptions *)getOptions completion:(FIRQuerySnapshotBlock)completion +- (void)getDocumentsWithOptions:(FIRGetOptions *)options completion:(FIRQuerySnapshotBlock)completion NS_SWIFT_NAME(getDocuments(options:completion:)); /** From c2395cc2ef86c57447e79317162f2647b09158b8 Mon Sep 17 00:00:00 2001 From: Rich Gowman Date: Fri, 12 Jan 2018 13:09:28 -0500 Subject: [PATCH 04/12] Remove mistaken changes to unittests. Artifacts of an earlier attempt at this. :( --- .../Example/Tests/Core/FSTQueryListenerTests.m | 18 +++++------------- .../Tests/SpecTests/FSTSyncEngineTestDriver.m | 4 +--- 2 files changed, 6 insertions(+), 16 deletions(-) diff --git a/Firestore/Example/Tests/Core/FSTQueryListenerTests.m b/Firestore/Example/Tests/Core/FSTQueryListenerTests.m index e91dd057325..4856b5fa462 100644 --- a/Firestore/Example/Tests/Core/FSTQueryListenerTests.m +++ b/Firestore/Example/Tests/Core/FSTQueryListenerTests.m @@ -172,8 +172,7 @@ - (void)testDoesNotRaiseEventsForMetadataChangesUnlessSpecified { FSTListenOptions *options = [[FSTListenOptions alloc] initWithIncludeQueryMetadataChanges:YES includeDocumentMetadataChanges:NO - waitForSyncWhenOnline:NO - getOptions:[FIRGetOptions defaultOptions]]; + waitForSyncWhenOnline:NO]; FSTQueryListener *filteredListener = [self listenToQuery:query accumulatingSnapshots:filteredAccum]; @@ -213,8 +212,7 @@ - (void)testRaisesDocumentMetadataEventsOnlyWhenSpecified { FSTListenOptions *options = [[FSTListenOptions alloc] initWithIncludeQueryMetadataChanges:NO includeDocumentMetadataChanges:YES - waitForSyncWhenOnline:NO - getOptions:[FIRGetOptions defaultOptions]]; + waitForSyncWhenOnline:NO]; FSTQueryListener *filteredListener = [self listenToQuery:query accumulatingSnapshots:filteredAccum]; @@ -264,9 +262,7 @@ - (void)testRaisesQueryMetadataEventsOnlyWhenHasPendingWritesOnTheQueryChanges { FSTListenOptions *options = [[FSTListenOptions alloc] initWithIncludeQueryMetadataChanges:YES includeDocumentMetadataChanges:NO - waitForSyncWhenOnline:NO - getOptions:[FIRGetOptions defaultOptions]]; - + waitForSyncWhenOnline:NO]; FSTQueryListener *fullListener = [self listenToQuery:query options:options accumulatingSnapshots:fullAccum]; @@ -333,9 +329,7 @@ - (void)testWillWaitForSyncIfOnline { [self listenToQuery:query options:[[FSTListenOptions alloc] initWithIncludeQueryMetadataChanges:NO includeDocumentMetadataChanges:NO - waitForSyncWhenOnline:YES - getOptions:[FIRGetOptions defaultOptions]] - + waitForSyncWhenOnline:YES] accumulatingSnapshots:events]; FSTView *view = [[FSTView alloc] initWithQuery:query remoteDocuments:[FSTDocumentKeySet keySet]]; @@ -378,9 +372,7 @@ - (void)testWillRaiseInitialEventWhenGoingOffline { [self listenToQuery:query options:[[FSTListenOptions alloc] initWithIncludeQueryMetadataChanges:NO includeDocumentMetadataChanges:NO - waitForSyncWhenOnline:YES - getOptions:[FIRGetOptions defaultOptions]] - + waitForSyncWhenOnline:YES] accumulatingSnapshots:events]; FSTView *view = [[FSTView alloc] initWithQuery:query remoteDocuments:[FSTDocumentKeySet keySet]]; diff --git a/Firestore/Example/Tests/SpecTests/FSTSyncEngineTestDriver.m b/Firestore/Example/Tests/SpecTests/FSTSyncEngineTestDriver.m index 58e978ba275..da6393321a3 100644 --- a/Firestore/Example/Tests/SpecTests/FSTSyncEngineTestDriver.m +++ b/Firestore/Example/Tests/SpecTests/FSTSyncEngineTestDriver.m @@ -243,9 +243,7 @@ - (FSTTargetID)addUserListenerWithQuery:(FSTQuery *)query { // TODO(dimond): Change spec tests to verify isFromCache on snapshots FSTListenOptions *options = [[FSTListenOptions alloc] initWithIncludeQueryMetadataChanges:YES includeDocumentMetadataChanges:YES - waitForSyncWhenOnline:NO - getOptions:[FIRGetOptions defaultOptions]]; - + waitForSyncWhenOnline:NO]; FSTQueryListener *listener = [[FSTQueryListener alloc] initWithQuery:query options:options From 76d0ae8582d3b6540244bac8896449639c2d7391 Mon Sep 17 00:00:00 2001 From: Rich Gowman Date: Tue, 16 Jan 2018 13:57:58 -0500 Subject: [PATCH 05/12] Prevent clang-format from breaking file --- Firestore/Source/Public/FIRQuery.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Firestore/Source/Public/FIRQuery.h b/Firestore/Source/Public/FIRQuery.h index 28f91b1dc35..0ddfe3c7150 100644 --- a/Firestore/Source/Public/FIRQuery.h +++ b/Firestore/Source/Public/FIRQuery.h @@ -91,8 +91,10 @@ NS_SWIFT_NAME(Query) - (void)getDocumentsWithCompletion:(FIRQuerySnapshotBlock)completion NS_SWIFT_NAME(getDocuments(completion:)); +// clang-format off - (void)getDocumentsWithOptions:(FIRGetOptions *)options completion:(FIRQuerySnapshotBlock)completion NS_SWIFT_NAME(getDocuments(options:completion:)); +// clang-format on /** * Attaches a listener for QuerySnapshot events. From 2a32091fac365eab58a71b1e61860f03d67c1a79 Mon Sep 17 00:00:00 2001 From: Rich Gowman Date: Tue, 16 Jan 2018 15:04:09 -0500 Subject: [PATCH 06/12] Run style.sh --- .../Integration/API/FIRGetOptionsTests.m | 287 ++++++++++-------- .../Tests/Util/FSTIntegrationTestCase.h | 3 +- .../Tests/Util/FSTIntegrationTestCase.mm | 25 +- Firestore/Source/API/FIRDocumentReference.m | 15 +- Firestore/Source/API/FIRQuery.m | 24 +- Firestore/Source/Core/FSTFirestoreClient.h | 8 +- Firestore/Source/Core/FSTFirestoreClient.m | 59 +++- Firestore/Source/Public/FIRGetOptions.h | 6 +- 8 files changed, 249 insertions(+), 178 deletions(-) diff --git a/Firestore/Example/Tests/Integration/API/FIRGetOptionsTests.m b/Firestore/Example/Tests/Integration/API/FIRGetOptionsTests.m index 1eca979bfd9..438b9c3c981 100644 --- a/Firestore/Example/Tests/Integration/API/FIRGetOptionsTests.m +++ b/Firestore/Example/Tests/Integration/API/FIRGetOptionsTests.m @@ -47,9 +47,9 @@ - (void)testGetCollectionWhileOnlineWithDefaultGetOptions { // set a few documents to known values NSDictionary *> *initialDocs = @{ - @"doc1": @{@"key1" : @"value1"}, - @"doc2": @{@"key2" : @"value2"}, - @"doc3": @{@"key3" : @"value3"} + @"doc1" : @{@"key1" : @"value1"}, + @"doc2" : @{@"key2" : @"value2"}, + @"doc3" : @{@"key3" : @"value3"} }; [self writeAllDocuments:initialDocs toCollection:col]; @@ -57,11 +57,9 @@ - (void)testGetCollectionWhileOnlineWithDefaultGetOptions { // initialDocs. FIRQuerySnapshot *result = [self readDocumentSetForRef:col]; XCTAssertFalse(result.metadata.fromCache); - XCTAssertEqualObjects(FIRQuerySnapshotGetData(result), (@[ - @{@"key1" : @"value1"}, - @{@"key2" : @"value2"}, - @{@"key3" : @"value3"} - ])); + XCTAssertEqualObjects( + FIRQuerySnapshotGetData(result), + (@[ @{@"key1" : @"value1"}, @{@"key2" : @"value2"}, @{@"key3" : @"value3"} ])); } - (void)testGetDocumentWhileOfflineWithDefaultGetOptions { @@ -78,9 +76,10 @@ - (void)testGetDocumentWhileOfflineWithDefaultGetOptions { // that ain't happening!). This allows us to further distinguished cached vs // server responses below. NSDictionary *newData = @{@"key2" : @"value2"}; - [doc setData:newData completion:^(NSError *_Nullable error) { - XCTAssertTrue(false, "Because we're offline, this should never occur."); - }]; + [doc setData:newData + completion:^(NSError *_Nullable error) { + XCTAssertTrue(false, "Because we're offline, this should never occur."); + }]; // get doc and ensure it exists, *is* from the cache, and matches the // newData. @@ -95,9 +94,9 @@ - (void)testGetCollectionWhileOfflineWithDefaultGetOptions { // set a few documents to known values NSDictionary *> *initialDocs = @{ - @"doc1": @{@"key1" : @"value1"}, - @"doc2": @{@"key2" : @"value2"}, - @"doc3": @{@"key3" : @"value3"} + @"doc1" : @{@"key1" : @"value1"}, + @"doc2" : @{@"key2" : @"value2"}, + @"doc3" : @{@"key3" : @"value3"} }; [self writeAllDocuments:initialDocs toCollection:col]; @@ -107,7 +106,7 @@ - (void)testGetCollectionWhileOfflineWithDefaultGetOptions { // update the docs (though don't wait for a server response. We're offline; so // that ain't happening!). This allows us to further distinguished cached vs // server responses below. - [[col documentWithPath:@"doc2"] setData:@{@"key2b": @"value2b"} options:FIRSetOptions.merge]; + [[col documentWithPath:@"doc2"] setData:@{@"key2b" : @"value2b"} options:FIRSetOptions.merge]; [[col documentWithPath:@"doc3"] setData:@{@"key3b" : @"value3b"}]; [[col documentWithPath:@"doc4"] setData:@{@"key4" : @"value4"}]; @@ -115,11 +114,9 @@ - (void)testGetCollectionWhileOfflineWithDefaultGetOptions { FIRQuerySnapshot *result = [self readDocumentSetForRef:col]; XCTAssertTrue(result.metadata.fromCache); XCTAssertEqualObjects(FIRQuerySnapshotGetData(result), (@[ - @{@"key1": @"value1"}, - @{@"key2": @"value2", @"key2b": @"value2b"}, - @{@"key3b": @"value3b"}, - @{@"key4": @"value4"} - ])); + @{@"key1" : @"value1"}, @{@"key2" : @"value2", @"key2b" : @"value2b"}, + @{@"key3b" : @"value3b"}, @{@"key4" : @"value4"} + ])); } - (void)testGetDocumentWhileOnlineCacheOnly { @@ -131,7 +128,8 @@ - (void)testGetDocumentWhileOnlineCacheOnly { // get doc and ensure that it exists, *is* from the cache, and matches // the initialData. - FIRDocumentSnapshot *result = [self readDocumentForRef:doc options:[[FIRGetOptions alloc] initWithSource:FIRCache]]; + FIRDocumentSnapshot *result = + [self readDocumentForRef:doc options:[[FIRGetOptions alloc] initWithSource:FIRCache]]; XCTAssertTrue(result.exists); XCTAssertTrue(result.metadata.fromCache); XCTAssertEqualObjects(result.data, initialData); @@ -142,21 +140,22 @@ - (void)testGetCollectionWhileOnlineCacheOnly { // set a few documents to a known value NSDictionary *> *initialDocs = @{ - @"doc1": @{@"key1" : @"value1"}, - @"doc2": @{@"key2" : @"value2"}, - @"doc3": @{@"key3" : @"value3"}, + @"doc1" : @{@"key1" : @"value1"}, + @"doc2" : @{@"key2" : @"value2"}, + @"doc3" : @{@"key3" : @"value3"}, }; [self writeAllDocuments:initialDocs toCollection:col]; // get docs and ensure they *are* from the cache, and matches the // initialDocs. - FIRQuerySnapshot *result = [self readDocumentSetForRef:col options:[[FIRGetOptions alloc] initWithSource:FIRCache]]; + FIRQuerySnapshot *result = + [self readDocumentSetForRef:col options:[[FIRGetOptions alloc] initWithSource:FIRCache]]; XCTAssertTrue(result.metadata.fromCache); XCTAssertEqualObjects(FIRQuerySnapshotGetData(result), (@[ - @{@"key1": @"value1"}, - @{@"key2": @"value2"}, - @{@"key3": @"value3"}, - ])); + @{@"key1" : @"value1"}, + @{@"key2" : @"value2"}, + @{@"key3" : @"value3"}, + ])); } - (void)testGetDocumentWhileOfflineCacheOnly { @@ -173,13 +172,15 @@ - (void)testGetDocumentWhileOfflineCacheOnly { // that ain't happening!). This allows us to further distinguished cached vs // server responses below. NSDictionary *newData = @{@"key2" : @"value2"}; - [doc setData:newData completion:^(NSError *_Nullable error) { - XCTFail("Because we're offline, this should never occur."); - }]; + [doc setData:newData + completion:^(NSError *_Nullable error) { + XCTFail("Because we're offline, this should never occur."); + }]; // get doc and ensure it exists, *is* from the cache, and matches the // newData. - FIRDocumentSnapshot *result = [self readDocumentForRef:doc options:[[FIRGetOptions alloc] initWithSource:FIRCache]]; + FIRDocumentSnapshot *result = + [self readDocumentForRef:doc options:[[FIRGetOptions alloc] initWithSource:FIRCache]]; XCTAssertTrue(result.exists); XCTAssertTrue(result.metadata.fromCache); XCTAssertEqualObjects(result.data, newData); @@ -190,9 +191,9 @@ - (void)testGetCollectionWhileOfflineCacheOnly { // set a few documents to a known value NSDictionary *> *initialDocs = @{ - @"doc1": @{@"key1" : @"value1"}, - @"doc2": @{@"key2" : @"value2"}, - @"doc3": @{@"key3" : @"value3"}, + @"doc1" : @{@"key1" : @"value1"}, + @"doc2" : @{@"key2" : @"value2"}, + @"doc3" : @{@"key3" : @"value3"}, }; [self writeAllDocuments:initialDocs toCollection:col]; @@ -202,20 +203,19 @@ - (void)testGetCollectionWhileOfflineCacheOnly { // update the docs (though don't wait for a server response. We're offline; so // that ain't happening!). This allows us to further distinguished cached vs // server responses below. - [[col documentWithPath:@"doc2"] setData:@{@"key2b": @"value2b"} options:FIRSetOptions.merge]; + [[col documentWithPath:@"doc2"] setData:@{@"key2b" : @"value2b"} options:FIRSetOptions.merge]; [[col documentWithPath:@"doc3"] setData:@{@"key3b" : @"value3b"}]; [[col documentWithPath:@"doc4"] setData:@{@"key4" : @"value4"}]; // get docs and ensure they *are* from the cache, and matches the updated // data. - FIRQuerySnapshot *result = [self readDocumentSetForRef:col options:[[FIRGetOptions alloc] initWithSource:FIRCache]]; + FIRQuerySnapshot *result = + [self readDocumentSetForRef:col options:[[FIRGetOptions alloc] initWithSource:FIRCache]]; XCTAssertTrue(result.metadata.fromCache); XCTAssertEqualObjects(FIRQuerySnapshotGetData(result), (@[ - @{@"key1": @"value1"}, - @{@"key2": @"value2", @"key2b": @"value2b"}, - @{@"key3b": @"value3b"}, - @{@"key4": @"value4"} - ])); + @{@"key1" : @"value1"}, @{@"key2" : @"value2", @"key2b" : @"value2b"}, + @{@"key3b" : @"value3b"}, @{@"key4" : @"value4"} + ])); } - (void)testGetDocumentWhileOnlineServerOnly { @@ -227,7 +227,8 @@ - (void)testGetDocumentWhileOnlineServerOnly { // get doc and ensure that it exists, is *not* from the cache, and matches // the initialData. - FIRDocumentSnapshot *result = [self readDocumentForRef:doc options:[[FIRGetOptions alloc] initWithSource:FIRServer]]; + FIRDocumentSnapshot *result = + [self readDocumentForRef:doc options:[[FIRGetOptions alloc] initWithSource:FIRServer]]; XCTAssertTrue(result.exists); XCTAssertFalse(result.metadata.fromCache); XCTAssertEqualObjects(result.data, initialData); @@ -238,21 +239,22 @@ - (void)testGetCollectionWhileOnlineServerOnly { // set a few documents to a known value NSDictionary *> *initialDocs = @{ - @"doc1": @{@"key1" : @"value1"}, - @"doc2": @{@"key2" : @"value2"}, - @"doc3": @{@"key3" : @"value3"}, + @"doc1" : @{@"key1" : @"value1"}, + @"doc2" : @{@"key2" : @"value2"}, + @"doc3" : @{@"key3" : @"value3"}, }; [self writeAllDocuments:initialDocs toCollection:col]; // get docs and ensure they are *not* from the cache, and matches the // initialData. - FIRQuerySnapshot *result = [self readDocumentSetForRef:col options:[[FIRGetOptions alloc] initWithSource:FIRServer]]; + FIRQuerySnapshot *result = + [self readDocumentSetForRef:col options:[[FIRGetOptions alloc] initWithSource:FIRServer]]; XCTAssertFalse(result.metadata.fromCache); XCTAssertEqualObjects(FIRQuerySnapshotGetData(result), (@[ - @{@"key1": @"value1"}, - @{@"key2": @"value2"}, - @{@"key3": @"value3"}, - ])); + @{@"key1" : @"value1"}, + @{@"key2" : @"value2"}, + @{@"key3" : @"value3"}, + ])); } - (void)testGetDocumentWhileOfflineServerOnly { @@ -267,12 +269,13 @@ - (void)testGetDocumentWhileOfflineServerOnly { // attempt to get doc and ensure it cannot be retreived XCTestExpectation *failedGetDocCompletion = [self expectationWithDescription:@"failedGetDoc"]; - [doc getDocumentWithOptions:[[FIRGetOptions alloc] initWithSource:FIRServer] completion:^(FIRDocumentSnapshot *snapshot, NSError *error) { - XCTAssertNotNil(error); - XCTAssertEqualObjects(error.domain, FIRFirestoreErrorDomain); - XCTAssertEqual(error.code, FIRFirestoreErrorCodeUnavailable); - [failedGetDocCompletion fulfill]; - }]; + [doc getDocumentWithOptions:[[FIRGetOptions alloc] initWithSource:FIRServer] + completion:^(FIRDocumentSnapshot *snapshot, NSError *error) { + XCTAssertNotNil(error); + XCTAssertEqualObjects(error.domain, FIRFirestoreErrorDomain); + XCTAssertEqual(error.code, FIRFirestoreErrorCodeUnavailable); + [failedGetDocCompletion fulfill]; + }]; [self awaitExpectations]; } @@ -281,9 +284,9 @@ - (void)testGetCollectionWhileOfflineServerOnly { // set a few documents to a known value NSDictionary *> *initialDocs = @{ - @"doc1": @{@"key1" : @"value1"}, - @"doc2": @{@"key2" : @"value2"}, - @"doc3": @{@"key3" : @"value3"}, + @"doc1" : @{@"key1" : @"value1"}, + @"doc2" : @{@"key2" : @"value2"}, + @"doc3" : @{@"key3" : @"value3"}, }; [self writeAllDocuments:initialDocs toCollection:col]; @@ -292,12 +295,13 @@ - (void)testGetCollectionWhileOfflineServerOnly { // attempt to get docs and ensure they cannot be retreived XCTestExpectation *failedGetDocsCompletion = [self expectationWithDescription:@"failedGetDocs"]; - [col getDocumentsWithOptions:[[FIRGetOptions alloc] initWithSource:FIRServer] completion:^(FIRQuerySnapshot *snapshot, NSError *error) { - XCTAssertNotNil(error); - XCTAssertEqualObjects(error.domain, FIRFirestoreErrorDomain); - XCTAssertEqual(error.code, FIRFirestoreErrorCodeUnavailable); - [failedGetDocsCompletion fulfill]; - }]; + [col getDocumentsWithOptions:[[FIRGetOptions alloc] initWithSource:FIRServer] + completion:^(FIRQuerySnapshot *snapshot, NSError *error) { + XCTAssertNotNil(error); + XCTAssertEqualObjects(error.domain, FIRFirestoreErrorDomain); + XCTAssertEqual(error.code, FIRFirestoreErrorCodeUnavailable); + [failedGetDocsCompletion fulfill]; + }]; [self awaitExpectations]; } @@ -315,11 +319,13 @@ - (void)testGetDocumentWhileOfflineWithDifferentGetOptions { // that ain't happening!). This allows us to further distinguished cached vs // server responses below. NSDictionary *newData = @{@"key2" : @"value2"}; - [doc setData:newData completion:^(NSError *_Nullable error) { - XCTAssertTrue(false, "Because we're offline, this should never occur."); - }]; + [doc setData:newData + completion:^(NSError *_Nullable error) { + XCTAssertTrue(false, "Because we're offline, this should never occur."); + }]; - // Create an initial listener for this query (to attempt to disrupt the gets below) and wait for the listener to deliver its initial snapshot before continuing. + // Create an initial listener for this query (to attempt to disrupt the gets below) and wait for + // the listener to deliver its initial snapshot before continuing. XCTestExpectation *listenerReady = [self expectationWithDescription:@"listenerReady"]; [doc addSnapshotListener:^(FIRDocumentSnapshot *snapshot, NSError *error) { [listenerReady fulfill]; @@ -328,7 +334,8 @@ - (void)testGetDocumentWhileOfflineWithDifferentGetOptions { // get doc (from cache) and ensure it exists, *is* from the cache, and // matches the newData. - FIRDocumentSnapshot *result = [self readDocumentForRef:doc options:[[FIRGetOptions alloc] initWithSource:FIRCache]]; + FIRDocumentSnapshot *result = + [self readDocumentForRef:doc options:[[FIRGetOptions alloc] initWithSource:FIRCache]]; XCTAssertTrue(result.exists); XCTAssertTrue(result.metadata.fromCache); XCTAssertEqualObjects(result.data, newData); @@ -341,12 +348,13 @@ - (void)testGetDocumentWhileOfflineWithDifferentGetOptions { // attempt to get doc (from the server) and ensure it cannot be retreived XCTestExpectation *failedGetDocCompletion = [self expectationWithDescription:@"failedGetDoc"]; - [doc getDocumentWithOptions:[[FIRGetOptions alloc] initWithSource:FIRServer] completion:^(FIRDocumentSnapshot *snapshot, NSError *error) { - XCTAssertNotNil(error); - XCTAssertEqualObjects(error.domain, FIRFirestoreErrorDomain); - XCTAssertEqual(error.code, FIRFirestoreErrorCodeUnavailable); - [failedGetDocCompletion fulfill]; - }]; + [doc getDocumentWithOptions:[[FIRGetOptions alloc] initWithSource:FIRServer] + completion:^(FIRDocumentSnapshot *snapshot, NSError *error) { + XCTAssertNotNil(error); + XCTAssertEqualObjects(error.domain, FIRFirestoreErrorDomain); + XCTAssertEqual(error.code, FIRFirestoreErrorCodeUnavailable); + [failedGetDocCompletion fulfill]; + }]; [self awaitExpectations]; } @@ -355,9 +363,9 @@ - (void)testGetCollectionWhileOfflineWithDifferentGetOptions { // set a few documents to a known value NSDictionary *> *initialDocs = @{ - @"doc1": @{@"key1" : @"value1"}, - @"doc2": @{@"key2" : @"value2"}, - @"doc3": @{@"key3" : @"value3"}, + @"doc1" : @{@"key1" : @"value1"}, + @"doc2" : @{@"key2" : @"value2"}, + @"doc3" : @{@"key3" : @"value3"}, }; [self writeAllDocuments:initialDocs toCollection:col]; @@ -367,7 +375,7 @@ - (void)testGetCollectionWhileOfflineWithDifferentGetOptions { // update the docs (though don't wait for a server response. We're offline; so // that ain't happening!). This allows us to further distinguished cached vs // server responses below. - [[col documentWithPath:@"doc2"] setData:@{@"key2b": @"value2b"} options:FIRSetOptions.merge]; + [[col documentWithPath:@"doc2"] setData:@{@"key2b" : @"value2b"} options:FIRSetOptions.merge]; [[col documentWithPath:@"doc3"] setData:@{@"key3b" : @"value3b"}]; [[col documentWithPath:@"doc4"] setData:@{@"key4" : @"value4"}]; @@ -382,33 +390,32 @@ - (void)testGetCollectionWhileOfflineWithDifferentGetOptions { // get docs (from cache) and ensure they *are* from the cache, and // matches the updated data. - FIRQuerySnapshot *result = [self readDocumentSetForRef:col options:[[FIRGetOptions alloc] initWithSource:FIRCache]]; + FIRQuerySnapshot *result = + [self readDocumentSetForRef:col options:[[FIRGetOptions alloc] initWithSource:FIRCache]]; XCTAssertTrue(result.metadata.fromCache); XCTAssertEqualObjects(FIRQuerySnapshotGetData(result), (@[ - @{@"key1": @"value1"}, - @{@"key2": @"value2", @"key2b": @"value2b"}, - @{@"key3b": @"value3b"}, - @{@"key4": @"value4"} - ])); + @{@"key1" : @"value1"}, @{@"key2" : @"value2", @"key2b" : @"value2b"}, + @{@"key3b" : @"value3b"}, @{@"key4" : @"value4"} + ])); // attempt to get docs (with default get options) - result = [self readDocumentSetForRef:col options:[[FIRGetOptions alloc] initWithSource:FIRDefault]]; + result = + [self readDocumentSetForRef:col options:[[FIRGetOptions alloc] initWithSource:FIRDefault]]; XCTAssertTrue(result.metadata.fromCache); XCTAssertEqualObjects(FIRQuerySnapshotGetData(result), (@[ - @{@"key1": @"value1"}, - @{@"key2": @"value2", @"key2b": @"value2b"}, - @{@"key3b": @"value3b"}, - @{@"key4": @"value4"} - ])); + @{@"key1" : @"value1"}, @{@"key2" : @"value2", @"key2b" : @"value2b"}, + @{@"key3b" : @"value3b"}, @{@"key4" : @"value4"} + ])); // attempt to get docs (from the server) and ensure they cannot be retreived XCTestExpectation *failedGetDocsCompletion = [self expectationWithDescription:@"failedGetDocs"]; - [col getDocumentsWithOptions:[[FIRGetOptions alloc] initWithSource:FIRServer] completion:^(FIRQuerySnapshot *snapshot, NSError *error) { - XCTAssertNotNil(error); - XCTAssertEqualObjects(error.domain, FIRFirestoreErrorDomain); - XCTAssertEqual(error.code, FIRFirestoreErrorCodeUnavailable); - [failedGetDocsCompletion fulfill]; - }]; + [col getDocumentsWithOptions:[[FIRGetOptions alloc] initWithSource:FIRServer] + completion:^(FIRQuerySnapshot *snapshot, NSError *error) { + XCTAssertNotNil(error); + XCTAssertEqualObjects(error.domain, FIRFirestoreErrorDomain); + XCTAssertEqual(error.code, FIRFirestoreErrorCodeUnavailable); + [failedGetDocsCompletion fulfill]; + }]; [self awaitExpectations]; } @@ -416,7 +423,7 @@ - (void)testGetNonExistingDocWhileOnlineWithDefaultGetOptions { FIRDocumentReference *doc = [self documentRef]; // get doc and ensure that it does not exist and is *not* from the cache. - FIRDocumentSnapshot* snapshot = [self readDocumentForRef:doc]; + FIRDocumentSnapshot *snapshot = [self readDocumentForRef:doc]; XCTAssertFalse(snapshot.exists); XCTAssertFalse(snapshot.metadata.fromCache); } @@ -425,7 +432,7 @@ - (void)testGetNonExistingCollectionWhileOnlineWithDefaultGetOptions { FIRCollectionReference *col = [self collectionRef]; // get collection and ensure it's empty and that it's *not* from the cache. - FIRQuerySnapshot* snapshot = [self readDocumentSetForRef:col]; + FIRQuerySnapshot *snapshot = [self readDocumentSetForRef:col]; XCTAssertEqual(snapshot.count, 0); XCTAssertFalse(snapshot.metadata.fromCache); } @@ -439,7 +446,8 @@ - (void)testGetNonExistingDocWhileOfflineWithDefaultGetOptions { // attempt to get doc. Currently, this is expected to fail. In the future, we // might consider adding support for negative cache hits so that we know // certain documents *don't* exist. - XCTestExpectation *getNonExistingDocCompletion = [self expectationWithDescription:@"getNonExistingDoc"]; + XCTestExpectation *getNonExistingDocCompletion = + [self expectationWithDescription:@"getNonExistingDoc"]; [doc getDocumentWithCompletion:^(FIRDocumentSnapshot *snapshot, NSError *error) { XCTAssertNotNil(error); XCTAssertEqualObjects(error.domain, FIRFirestoreErrorDomain); @@ -467,13 +475,15 @@ - (void)testGetNonExistingDocWhileOnlineCacheOnly { // attempt to get doc. Currently, this is expected to fail. In the future, we // might consider adding support for negative cache hits so that we know // certain documents *don't* exist. - XCTestExpectation *getNonExistingDocCompletion = [self expectationWithDescription:@"getNonExistingDoc"]; - [doc getDocumentWithOptions:[[FIRGetOptions alloc] initWithSource:FIRCache] completion:^(FIRDocumentSnapshot *snapshot, NSError *error) { - XCTAssertNotNil(error); - XCTAssertEqualObjects(error.domain, FIRFirestoreErrorDomain); - XCTAssertEqual(error.code, FIRFirestoreErrorCodeUnavailable); - [getNonExistingDocCompletion fulfill]; - }]; + XCTestExpectation *getNonExistingDocCompletion = + [self expectationWithDescription:@"getNonExistingDoc"]; + [doc getDocumentWithOptions:[[FIRGetOptions alloc] initWithSource:FIRCache] + completion:^(FIRDocumentSnapshot *snapshot, NSError *error) { + XCTAssertNotNil(error); + XCTAssertEqualObjects(error.domain, FIRFirestoreErrorDomain); + XCTAssertEqual(error.code, FIRFirestoreErrorCodeUnavailable); + [getNonExistingDocCompletion fulfill]; + }]; [self awaitExpectations]; } @@ -481,7 +491,8 @@ - (void)testGetNonExistingCollectionWhileOnlineCacheOnly { FIRCollectionReference *col = [self collectionRef]; // get collection and ensure it's empty and that it *is* from the cache. - FIRQuerySnapshot *snapshot = [self readDocumentSetForRef:col options:[[FIRGetOptions alloc] initWithSource:FIRCache]]; + FIRQuerySnapshot *snapshot = + [self readDocumentSetForRef:col options:[[FIRGetOptions alloc] initWithSource:FIRCache]]; XCTAssertEqual(snapshot.count, 0); XCTAssertTrue(snapshot.metadata.fromCache); } @@ -495,13 +506,15 @@ - (void)testGetNonExistingDocWhileOfflineCacheOnly { // attempt to get doc. Currently, this is expected to fail. In the future, we // might consider adding support for negative cache hits so that we know // certain documents *don't* exist. - XCTestExpectation *getNonExistingDocCompletion = [self expectationWithDescription:@"getNonExistingDoc"]; - [doc getDocumentWithOptions:[[FIRGetOptions alloc] initWithSource:FIRCache] completion:^(FIRDocumentSnapshot *snapshot, NSError *error) { - XCTAssertNotNil(error); - XCTAssertEqualObjects(error.domain, FIRFirestoreErrorDomain); - XCTAssertEqual(error.code, FIRFirestoreErrorCodeUnavailable); - [getNonExistingDocCompletion fulfill]; - }]; + XCTestExpectation *getNonExistingDocCompletion = + [self expectationWithDescription:@"getNonExistingDoc"]; + [doc getDocumentWithOptions:[[FIRGetOptions alloc] initWithSource:FIRCache] + completion:^(FIRDocumentSnapshot *snapshot, NSError *error) { + XCTAssertNotNil(error); + XCTAssertEqualObjects(error.domain, FIRFirestoreErrorDomain); + XCTAssertEqual(error.code, FIRFirestoreErrorCodeUnavailable); + [getNonExistingDocCompletion fulfill]; + }]; [self awaitExpectations]; } @@ -512,7 +525,8 @@ - (void)testGetNonExistingCollectionWhileOfflineCacheOnly { [self disableNetwork]; // get collection and ensure it's empty and that it *is* from the cache. - FIRQuerySnapshot *snapshot = [self readDocumentSetForRef:col options:[[FIRGetOptions alloc] initWithSource:FIRCache]]; + FIRQuerySnapshot *snapshot = + [self readDocumentSetForRef:col options:[[FIRGetOptions alloc] initWithSource:FIRCache]]; XCTAssertEqual(snapshot.count, 0); XCTAssertTrue(snapshot.metadata.fromCache); } @@ -521,7 +535,8 @@ - (void)testGetNonExistingDocWhileOnlineServerOnly { FIRDocumentReference *doc = [self documentRef]; // get doc and ensure that it does not exist and is *not* from the cache. - FIRDocumentSnapshot* snapshot = [self readDocumentForRef:doc options:[[FIRGetOptions alloc] initWithSource:FIRServer]]; + FIRDocumentSnapshot *snapshot = + [self readDocumentForRef:doc options:[[FIRGetOptions alloc] initWithSource:FIRServer]]; XCTAssertFalse(snapshot.exists); XCTAssertFalse(snapshot.metadata.fromCache); } @@ -530,7 +545,8 @@ - (void)testGetNonExistingCollectionWhileOnlineServerOnly { FIRCollectionReference *col = [self collectionRef]; // get collection and ensure that it's empty and that it's *not* from the cache. - FIRQuerySnapshot* snapshot = [self readDocumentSetForRef:col options:[[FIRGetOptions alloc] initWithSource:FIRServer]]; + FIRQuerySnapshot *snapshot = + [self readDocumentSetForRef:col options:[[FIRGetOptions alloc] initWithSource:FIRServer]]; XCTAssertEqual(snapshot.count, 0); XCTAssertFalse(snapshot.metadata.fromCache); } @@ -544,13 +560,15 @@ - (void)testGetNonExistingDocWhileOfflineServerOnly { // attempt to get doc. Currently, this is expected to fail. In the future, we // might consider adding support for negative cache hits so that we know // certain documents *don't* exist. - XCTestExpectation *getNonExistingDocCompletion = [self expectationWithDescription:@"getNonExistingDoc"]; - [doc getDocumentWithOptions:[[FIRGetOptions alloc] initWithSource:FIRServer] completion:^(FIRDocumentSnapshot *snapshot, NSError *error) { - XCTAssertNotNil(error); - XCTAssertEqualObjects(error.domain, FIRFirestoreErrorDomain); - XCTAssertEqual(error.code, FIRFirestoreErrorCodeUnavailable); - [getNonExistingDocCompletion fulfill]; - }]; + XCTestExpectation *getNonExistingDocCompletion = + [self expectationWithDescription:@"getNonExistingDoc"]; + [doc getDocumentWithOptions:[[FIRGetOptions alloc] initWithSource:FIRServer] + completion:^(FIRDocumentSnapshot *snapshot, NSError *error) { + XCTAssertNotNil(error); + XCTAssertEqualObjects(error.domain, FIRFirestoreErrorDomain); + XCTAssertEqual(error.code, FIRFirestoreErrorCodeUnavailable); + [getNonExistingDocCompletion fulfill]; + }]; [self awaitExpectations]; } @@ -562,12 +580,13 @@ - (void)testGetNonExistingCollectionWhileOfflineServerOnly { // attempt to get collection and ensure that it cannot be retreived XCTestExpectation *failedGetDocsCompletion = [self expectationWithDescription:@"failedGetDocs"]; - [col getDocumentsWithOptions:[[FIRGetOptions alloc] initWithSource:FIRServer] completion:^(FIRQuerySnapshot *snapshot, NSError *error) { - XCTAssertNotNil(error); - XCTAssertEqualObjects(error.domain, FIRFirestoreErrorDomain); - XCTAssertEqual(error.code, FIRFirestoreErrorCodeUnavailable); - [failedGetDocsCompletion fulfill]; - }]; + [col getDocumentsWithOptions:[[FIRGetOptions alloc] initWithSource:FIRServer] + completion:^(FIRQuerySnapshot *snapshot, NSError *error) { + XCTAssertNotNil(error); + XCTAssertEqualObjects(error.domain, FIRFirestoreErrorDomain); + XCTAssertEqual(error.code, FIRFirestoreErrorCodeUnavailable); + [failedGetDocsCompletion fulfill]; + }]; [self awaitExpectations]; } diff --git a/Firestore/Example/Tests/Util/FSTIntegrationTestCase.h b/Firestore/Example/Tests/Util/FSTIntegrationTestCase.h index 1c256a46b64..42e273f3c18 100644 --- a/Firestore/Example/Tests/Util/FSTIntegrationTestCase.h +++ b/Firestore/Example/Tests/Util/FSTIntegrationTestCase.h @@ -73,7 +73,8 @@ extern "C" { - (FIRDocumentSnapshot *)readDocumentForRef:(FIRDocumentReference *)ref; -- (FIRDocumentSnapshot *)readDocumentForRef:(FIRDocumentReference *)ref options:(FIRGetOptions *)options; +- (FIRDocumentSnapshot *)readDocumentForRef:(FIRDocumentReference *)ref + options:(FIRGetOptions *)options; - (FIRQuerySnapshot *)readDocumentSetForRef:(FIRQuery *)query; diff --git a/Firestore/Example/Tests/Util/FSTIntegrationTestCase.mm b/Firestore/Example/Tests/Util/FSTIntegrationTestCase.mm index 36542533f86..1282aabffd5 100644 --- a/Firestore/Example/Tests/Util/FSTIntegrationTestCase.mm +++ b/Firestore/Example/Tests/Util/FSTIntegrationTestCase.mm @@ -212,15 +212,17 @@ - (FIRDocumentSnapshot *)readDocumentForRef:(FIRDocumentReference *)ref { return [self readDocumentForRef:ref options:[FIRGetOptions defaultOptions]]; } -- (FIRDocumentSnapshot *)readDocumentForRef:(FIRDocumentReference *)ref options:(FIRGetOptions *)options { +- (FIRDocumentSnapshot *)readDocumentForRef:(FIRDocumentReference *)ref + options:(FIRGetOptions *)options { __block FIRDocumentSnapshot *result; XCTestExpectation *expectation = [self expectationWithDescription:@"getData"]; - [ref getDocumentWithOptions:options completion:^(FIRDocumentSnapshot *doc, NSError *_Nullable error) { - XCTAssertNil(error); - result = doc; - [expectation fulfill]; - }]; + [ref getDocumentWithOptions:options + completion:^(FIRDocumentSnapshot *doc, NSError *_Nullable error) { + XCTAssertNil(error); + result = doc; + [expectation fulfill]; + }]; [self awaitExpectations]; return result; @@ -234,11 +236,12 @@ - (FIRQuerySnapshot *)readDocumentSetForRef:(FIRQuery *)query options:(FIRGetOpt __block FIRQuerySnapshot *result; XCTestExpectation *expectation = [self expectationWithDescription:@"getData"]; - [query getDocumentsWithOptions:options completion:^(FIRQuerySnapshot *documentSet, NSError *error) { - XCTAssertNil(error); - result = documentSet; - [expectation fulfill]; - }]; + [query getDocumentsWithOptions:options + completion:^(FIRQuerySnapshot *documentSet, NSError *error) { + XCTAssertNil(error); + result = documentSet; + [expectation fulfill]; + }]; [self awaitExpectations]; return result; diff --git a/Firestore/Source/API/FIRDocumentReference.m b/Firestore/Source/API/FIRDocumentReference.m index 2b7f3eb236d..3a20e9ac08b 100644 --- a/Firestore/Source/API/FIRDocumentReference.m +++ b/Firestore/Source/API/FIRDocumentReference.m @@ -213,8 +213,9 @@ - (void)getDocumentWithCompletion:(void (^)(FIRDocumentSnapshot *_Nullable docum return [self getDocumentWithOptions:[FIRGetOptions defaultOptions] completion:completion]; } -- (void)getDocumentWithOptions:(FIRGetOptions *)options completion:(void (^)(FIRDocumentSnapshot *_Nullable document, - NSError *_Nullable error))completion { +- (void)getDocumentWithOptions:(FIRGetOptions *)options + completion:(void (^)(FIRDocumentSnapshot *_Nullable document, + NSError *_Nullable error))completion { if (options.source == FIRCache) { [self.firestore.client getDocumentFromLocalCache:self completion:completion]; return; @@ -255,7 +256,15 @@ - (void)getDocumentWithOptions:(FIRGetOptions *)options completion:(void (^)(FIR @"Failed to get document because the client is offline.", }]); } else if (snapshot.exists && snapshot.metadata.fromCache && options.source == FIRServer) { - completion(nil, [NSError errorWithDomain:FIRFirestoreErrorDomain code:FIRFirestoreErrorCodeUnavailable userInfo:@{NSLocalizedDescriptionKey: @"Failed to get document from server. (However, this document does exist in the local cache. Run again without setting FIRServer in the GetOptions to retrieve the cached document.)"}]); + completion(nil, [NSError errorWithDomain:FIRFirestoreErrorDomain + code:FIRFirestoreErrorCodeUnavailable + userInfo:@{ + NSLocalizedDescriptionKey : + @"Failed to get document from server. (However, this " + @"document does exist in the local cache. Run again " + @"without setting FIRServer in the GetOptions to " + @"retrieve the cached document.)" + }]); } else { completion(snapshot, nil); } diff --git a/Firestore/Source/API/FIRQuery.m b/Firestore/Source/API/FIRQuery.m index 7ea1dafb9af..2e545d3f8f7 100644 --- a/Firestore/Source/API/FIRQuery.m +++ b/Firestore/Source/API/FIRQuery.m @@ -135,15 +135,18 @@ - (void)getDocumentsWithCompletion:(void (^)(FIRQuerySnapshot *_Nullable snapsho [self getDocumentsWithOptions:[FIRGetOptions defaultOptions] completion:completion]; } -- (void)getDocumentsWithOptions:(FIRGetOptions *)options completion:(void (^)(FIRQuerySnapshot *_Nullable snapshot, NSError *_Nullable error))completion { +- (void)getDocumentsWithOptions:(FIRGetOptions *)options + completion:(void (^)(FIRQuerySnapshot *_Nullable snapshot, + NSError *_Nullable error))completion { if (options.source == FIRCache) { [self.firestore.client getDocumentsFromLocalCache:self completion:completion]; return; } - FSTListenOptions *listenOptions = [[FSTListenOptions alloc] initWithIncludeQueryMetadataChanges:YES - includeDocumentMetadataChanges:YES - waitForSyncWhenOnline:YES]; + FSTListenOptions *listenOptions = + [[FSTListenOptions alloc] initWithIncludeQueryMetadataChanges:YES + includeDocumentMetadataChanges:YES + waitForSyncWhenOnline:YES]; dispatch_semaphore_t registered = dispatch_semaphore_create(0); __block id listenerRegistration; @@ -159,13 +162,22 @@ - (void)getDocumentsWithOptions:(FIRGetOptions *)options completion:(void (^)(FI [listenerRegistration remove]; if (snapshot.metadata.fromCache && options.source == FIRServer) { - completion(nil, [NSError errorWithDomain:FIRFirestoreErrorDomain code:FIRFirestoreErrorCodeUnavailable userInfo:@{NSLocalizedDescriptionKey: @"Failed to get documents from server. (However, these documents may exist in the local cache. Run again without setting FIRServer in the GetOptions to retrieve the cached documents.)"}]); + completion(nil, [NSError errorWithDomain:FIRFirestoreErrorDomain + code:FIRFirestoreErrorCodeUnavailable + userInfo:@{ + NSLocalizedDescriptionKey : + @"Failed to get documents from server. (However, these " + @"documents may exist in the local cache. Run again " + @"without setting FIRServer in the GetOptions to " + @"retrieve the cached documents.)" + }]); } else { completion(snapshot, nil); } }; - listenerRegistration = [self addSnapshotListenerInternalWithOptions:listenOptions listener:listener]; + listenerRegistration = + [self addSnapshotListenerInternalWithOptions:listenOptions listener:listener]; dispatch_semaphore_signal(registered); } diff --git a/Firestore/Source/Core/FSTFirestoreClient.h b/Firestore/Source/Core/FSTFirestoreClient.h index 59ba5864893..d7b3304a61c 100644 --- a/Firestore/Source/Core/FSTFirestoreClient.h +++ b/Firestore/Source/Core/FSTFirestoreClient.h @@ -78,13 +78,17 @@ NS_ASSUME_NONNULL_BEGIN * Retrieves a document from the cache via the indicated completion. If the doc * doesn't exist, an error will be sent to the completion. */ -- (void)getDocumentFromLocalCache:(FIRDocumentReference *)doc completion:(void (^)(FIRDocumentSnapshot *_Nullable document, NSError *_Nullable error))completion; +- (void)getDocumentFromLocalCache:(FIRDocumentReference *)doc + completion:(void (^)(FIRDocumentSnapshot *_Nullable document, + NSError *_Nullable error))completion; /** * Retrieves a (possibly empty) set of documents from the cache via the * indicated completion. */ -- (void)getDocumentsFromLocalCache:(FIRQuery *)query completion:(void (^)(FIRQuerySnapshot *_Nullable query, NSError *_Nullable error))completion; +- (void)getDocumentsFromLocalCache:(FIRQuery *)query + completion:(void (^)(FIRQuerySnapshot *_Nullable query, + NSError *_Nullable error))completion; /** Write mutations. completion will be notified when it's written to the backend. */ - (void)writeMutations:(NSArray *)mutations diff --git a/Firestore/Source/Core/FSTFirestoreClient.m b/Firestore/Source/Core/FSTFirestoreClient.m index 8a5bf9d7b53..0d66654b924 100644 --- a/Firestore/Source/Core/FSTFirestoreClient.m +++ b/Firestore/Source/Core/FSTFirestoreClient.m @@ -17,12 +17,17 @@ #import "Firestore/Source/Core/FSTFirestoreClient.h" #import "FIRFirestoreErrors.h" +#import "Firestore/Source/API/FIRDocumentReference+Internal.h" +#import "Firestore/Source/API/FIRDocumentSnapshot+Internal.h" +#import "Firestore/Source/API/FIRQuery+Internal.h" +#import "Firestore/Source/API/FIRQuerySnapshot+Internal.h" +#import "Firestore/Source/API/FIRSnapshotMetadata+Internal.h" #import "Firestore/Source/Auth/FSTCredentialsProvider.h" #import "Firestore/Source/Core/FSTDatabaseInfo.h" #import "Firestore/Source/Core/FSTEventManager.h" +#import "Firestore/Source/Core/FSTQuery.h" #import "Firestore/Source/Core/FSTSyncEngine.h" #import "Firestore/Source/Core/FSTTransaction.h" -#import "Firestore/Source/Core/FSTQuery.h" #import "Firestore/Source/Local/FSTEagerGarbageCollector.h" #import "Firestore/Source/Local/FSTLevelDB.h" #import "Firestore/Source/Local/FSTLocalSerializer.h" @@ -38,12 +43,6 @@ #import "Firestore/Source/Util/FSTClasses.h" #import "Firestore/Source/Util/FSTDispatchQueue.h" #import "Firestore/Source/Util/FSTLogger.h" -#import "Firestore/Source/API/FIRDocumentReference+Internal.h" -#import "Firestore/Source/API/FIRDocumentSnapshot+Internal.h" -#import "Firestore/Source/API/FIRQuery+Internal.h" -#import "Firestore/Source/API/FIRQuerySnapshot+Internal.h" -#import "Firestore/Source/API/FIRSnapshotMetadata+Internal.h" - NS_ASSUME_NONNULL_BEGIN @@ -259,31 +258,59 @@ - (void)removeListener:(FSTQueryListener *)listener { }]; } -- (void)getDocumentFromLocalCache:(FIRDocumentReference *)doc completion:(void (^)(FIRDocumentSnapshot *_Nullable document, NSError *_Nullable error))completion { +- (void)getDocumentFromLocalCache:(FIRDocumentReference *)doc + completion:(void (^)(FIRDocumentSnapshot *_Nullable document, + NSError *_Nullable error))completion { [self.workerDispatchQueue dispatchAsync:^{ FSTMaybeDocument *maybeDoc = [self.localStore readDocument:doc.key]; if (maybeDoc) { - completion([FIRDocumentSnapshot snapshotWithFirestore:doc.firestore documentKey:doc.key document:(FSTDocument *)maybeDoc fromCache:YES], nil); + completion([FIRDocumentSnapshot snapshotWithFirestore:doc.firestore + documentKey:doc.key + document:(FSTDocument *)maybeDoc + fromCache:YES], + nil); } else { - completion(nil, [NSError errorWithDomain:FIRFirestoreErrorDomain code:FIRFirestoreErrorCodeUnavailable userInfo:@{NSLocalizedDescriptionKey: @"Failed to get document from cache. (However, this document may exist on the server. Run again without setting FIRCache in the GetOptions to attempt to retrieve the document from the server.)",}]); + completion(nil, [NSError errorWithDomain:FIRFirestoreErrorDomain + code:FIRFirestoreErrorCodeUnavailable + userInfo:@{ + NSLocalizedDescriptionKey : + @"Failed to get document from cache. (However, this " + @"document may exist on the server. Run again without " + @"setting FIRCache in the GetOptions to attempt to " + @"retrieve the document from the server.)", + }]); } }]; } -- (void)getDocumentsFromLocalCache:(FIRQuery *)query completion:(void (^)(FIRQuerySnapshot *_Nullable query, NSError *_Nullable error))completion { +- (void)getDocumentsFromLocalCache:(FIRQuery *)query + completion:(void (^)(FIRQuerySnapshot *_Nullable query, + NSError *_Nullable error))completion { [self.workerDispatchQueue dispatchAsync:^{ FSTDocumentDictionary *docs = [self.localStore executeQuery:query.query]; - __block FSTDocumentSet *documents = [FSTDocumentSet documentSetWithComparator:query.query.comparator]; + __block FSTDocumentSet *documents = + [FSTDocumentSet documentSetWithComparator:query.query.comparator]; FSTDocumentSet *oldDocuments = documents; [docs enumerateKeysAndObjectsUsingBlock:^(FSTDocumentKey *key, FSTDocument *value, BOOL *stop) { documents = [documents documentSetByAddingDocument:value]; }]; - FSTViewSnapshot *snapshot = [[FSTViewSnapshot alloc] initWithQuery:query.query documents:documents oldDocuments:oldDocuments documentChanges:@[] fromCache:YES hasPendingWrites:NO syncStateChanged:NO]; - FIRSnapshotMetadata *metadata = [FIRSnapshotMetadata snapshotMetadataWithPendingWrites:NO fromCache:YES]; - - completion([FIRQuerySnapshot snapshotWithFirestore:query.firestore originalQuery:query.query snapshot:snapshot metadata:metadata], nil); + FSTViewSnapshot *snapshot = [[FSTViewSnapshot alloc] initWithQuery:query.query + documents:documents + oldDocuments:oldDocuments + documentChanges:@[] + fromCache:YES + hasPendingWrites:NO + syncStateChanged:NO]; + FIRSnapshotMetadata *metadata = + [FIRSnapshotMetadata snapshotMetadataWithPendingWrites:NO fromCache:YES]; + + completion([FIRQuerySnapshot snapshotWithFirestore:query.firestore + originalQuery:query.query + snapshot:snapshot + metadata:metadata], + nil); }]; } diff --git a/Firestore/Source/Public/FIRGetOptions.h b/Firestore/Source/Public/FIRGetOptions.h index 8965506c505..70041655eee 100644 --- a/Firestore/Source/Public/FIRGetOptions.h +++ b/Firestore/Source/Public/FIRGetOptions.h @@ -53,11 +53,7 @@ NS_SWIFT_NAME(GetOptions) * stale with respect to the value on the server.) For a single document, the * get will fail if the document doesn't exist. */ -typedef NS_ENUM(NSUInteger, FIRSource) { - FIRDefault, - FIRServer, - FIRCache -} NS_SWIFT_NAME(Source); +typedef NS_ENUM(NSUInteger, FIRSource) { FIRDefault, FIRServer, FIRCache } NS_SWIFT_NAME(Source); /** * Initializes the get options with the specified source. From ec558824fb326da8eb4a57bbc7e1b5c35a1f0b42 Mon Sep 17 00:00:00 2001 From: Rich Gowman Date: Tue, 16 Jan 2018 18:40:29 -0500 Subject: [PATCH 07/12] Ensure swift bindings are correct --- Firestore/Example/SwiftBuildTest/main.swift | 24 +++++++++ .../Integration/API/FIRGetOptionsTests.m | 54 +++++++++++-------- Firestore/Source/API/FIRDocumentReference.m | 5 +- Firestore/Source/API/FIRGetOptions.m | 2 +- Firestore/Source/API/FIRQuery.m | 4 +- Firestore/Source/Public/FIRGetOptions.h | 6 ++- 6 files changed, 66 insertions(+), 29 deletions(-) diff --git a/Firestore/Example/SwiftBuildTest/main.swift b/Firestore/Example/SwiftBuildTest/main.swift index 260735b1ee1..f102e28c01d 100644 --- a/Firestore/Example/SwiftBuildTest/main.swift +++ b/Firestore/Example/SwiftBuildTest/main.swift @@ -32,8 +32,10 @@ func main() { addDocument(to: collectionRef); readDocument(at: documentRef); + readDocumentWithOptions(at: documentRef); readDocuments(matching: query); + readDocumentsWithOptions(matching: query); listenToDocument(at: documentRef); @@ -223,6 +225,17 @@ func readDocument(at docRef: DocumentReference) { } } +func readDocumentWithOptions(at docRef: DocumentReference) { + docRef.getDocument(options:GetOptions.defaultOptions()) { document, error in + } + docRef.getDocument(options:GetOptions.init(source:Source.default)) { document, error in + } + docRef.getDocument(options:GetOptions.init(source:Source.server)) { document, error in + } + docRef.getDocument(options:GetOptions.init(source:Source.cache)) { document, error in + } +} + func readDocuments(matching query: Query) { query.getDocuments() { querySnapshot, error in // TODO(mikelehen): Figure out how to make "for..in" syntax work @@ -233,6 +246,17 @@ func readDocuments(matching query: Query) { } } +func readDocumentsWithOptions(matching query: Query) { + query.getDocuments(options:GetOptions.defaultOptions()) { querySnapshot, error in + } + query.getDocuments(options:GetOptions.init(source:Source.default)) { querySnapshot, error in + } + query.getDocuments(options:GetOptions.init(source:Source.server)) { querySnapshot, error in + } + query.getDocuments(options:GetOptions.init(source:Source.cache)) { querySnapshot, error in + } +} + func listenToDocument(at docRef: DocumentReference) { let listener = docRef.addSnapshotListener() { document, error in diff --git a/Firestore/Example/Tests/Integration/API/FIRGetOptionsTests.m b/Firestore/Example/Tests/Integration/API/FIRGetOptionsTests.m index 438b9c3c981..e9d17277f12 100644 --- a/Firestore/Example/Tests/Integration/API/FIRGetOptionsTests.m +++ b/Firestore/Example/Tests/Integration/API/FIRGetOptionsTests.m @@ -129,7 +129,7 @@ - (void)testGetDocumentWhileOnlineCacheOnly { // get doc and ensure that it exists, *is* from the cache, and matches // the initialData. FIRDocumentSnapshot *result = - [self readDocumentForRef:doc options:[[FIRGetOptions alloc] initWithSource:FIRCache]]; + [self readDocumentForRef:doc options:[[FIRGetOptions alloc] initWithSource:FIRSourceCache]]; XCTAssertTrue(result.exists); XCTAssertTrue(result.metadata.fromCache); XCTAssertEqualObjects(result.data, initialData); @@ -149,7 +149,8 @@ - (void)testGetCollectionWhileOnlineCacheOnly { // get docs and ensure they *are* from the cache, and matches the // initialDocs. FIRQuerySnapshot *result = - [self readDocumentSetForRef:col options:[[FIRGetOptions alloc] initWithSource:FIRCache]]; + [self readDocumentSetForRef:col + options:[[FIRGetOptions alloc] initWithSource:FIRSourceCache]]; XCTAssertTrue(result.metadata.fromCache); XCTAssertEqualObjects(FIRQuerySnapshotGetData(result), (@[ @{@"key1" : @"value1"}, @@ -180,7 +181,7 @@ - (void)testGetDocumentWhileOfflineCacheOnly { // get doc and ensure it exists, *is* from the cache, and matches the // newData. FIRDocumentSnapshot *result = - [self readDocumentForRef:doc options:[[FIRGetOptions alloc] initWithSource:FIRCache]]; + [self readDocumentForRef:doc options:[[FIRGetOptions alloc] initWithSource:FIRSourceCache]]; XCTAssertTrue(result.exists); XCTAssertTrue(result.metadata.fromCache); XCTAssertEqualObjects(result.data, newData); @@ -210,7 +211,8 @@ - (void)testGetCollectionWhileOfflineCacheOnly { // get docs and ensure they *are* from the cache, and matches the updated // data. FIRQuerySnapshot *result = - [self readDocumentSetForRef:col options:[[FIRGetOptions alloc] initWithSource:FIRCache]]; + [self readDocumentSetForRef:col + options:[[FIRGetOptions alloc] initWithSource:FIRSourceCache]]; XCTAssertTrue(result.metadata.fromCache); XCTAssertEqualObjects(FIRQuerySnapshotGetData(result), (@[ @{@"key1" : @"value1"}, @{@"key2" : @"value2", @"key2b" : @"value2b"}, @@ -228,7 +230,7 @@ - (void)testGetDocumentWhileOnlineServerOnly { // get doc and ensure that it exists, is *not* from the cache, and matches // the initialData. FIRDocumentSnapshot *result = - [self readDocumentForRef:doc options:[[FIRGetOptions alloc] initWithSource:FIRServer]]; + [self readDocumentForRef:doc options:[[FIRGetOptions alloc] initWithSource:FIRSourceServer]]; XCTAssertTrue(result.exists); XCTAssertFalse(result.metadata.fromCache); XCTAssertEqualObjects(result.data, initialData); @@ -248,7 +250,8 @@ - (void)testGetCollectionWhileOnlineServerOnly { // get docs and ensure they are *not* from the cache, and matches the // initialData. FIRQuerySnapshot *result = - [self readDocumentSetForRef:col options:[[FIRGetOptions alloc] initWithSource:FIRServer]]; + [self readDocumentSetForRef:col + options:[[FIRGetOptions alloc] initWithSource:FIRSourceServer]]; XCTAssertFalse(result.metadata.fromCache); XCTAssertEqualObjects(FIRQuerySnapshotGetData(result), (@[ @{@"key1" : @"value1"}, @@ -269,7 +272,7 @@ - (void)testGetDocumentWhileOfflineServerOnly { // attempt to get doc and ensure it cannot be retreived XCTestExpectation *failedGetDocCompletion = [self expectationWithDescription:@"failedGetDoc"]; - [doc getDocumentWithOptions:[[FIRGetOptions alloc] initWithSource:FIRServer] + [doc getDocumentWithOptions:[[FIRGetOptions alloc] initWithSource:FIRSourceServer] completion:^(FIRDocumentSnapshot *snapshot, NSError *error) { XCTAssertNotNil(error); XCTAssertEqualObjects(error.domain, FIRFirestoreErrorDomain); @@ -295,7 +298,7 @@ - (void)testGetCollectionWhileOfflineServerOnly { // attempt to get docs and ensure they cannot be retreived XCTestExpectation *failedGetDocsCompletion = [self expectationWithDescription:@"failedGetDocs"]; - [col getDocumentsWithOptions:[[FIRGetOptions alloc] initWithSource:FIRServer] + [col getDocumentsWithOptions:[[FIRGetOptions alloc] initWithSource:FIRSourceServer] completion:^(FIRQuerySnapshot *snapshot, NSError *error) { XCTAssertNotNil(error); XCTAssertEqualObjects(error.domain, FIRFirestoreErrorDomain); @@ -335,20 +338,21 @@ - (void)testGetDocumentWhileOfflineWithDifferentGetOptions { // get doc (from cache) and ensure it exists, *is* from the cache, and // matches the newData. FIRDocumentSnapshot *result = - [self readDocumentForRef:doc options:[[FIRGetOptions alloc] initWithSource:FIRCache]]; + [self readDocumentForRef:doc options:[[FIRGetOptions alloc] initWithSource:FIRSourceCache]]; XCTAssertTrue(result.exists); XCTAssertTrue(result.metadata.fromCache); XCTAssertEqualObjects(result.data, newData); // attempt to get doc (with default get options) - result = [self readDocumentForRef:doc options:[[FIRGetOptions alloc] initWithSource:FIRDefault]]; + result = + [self readDocumentForRef:doc options:[[FIRGetOptions alloc] initWithSource:FIRSourceDefault]]; XCTAssertTrue(result.exists); XCTAssertTrue(result.metadata.fromCache); XCTAssertEqualObjects(result.data, newData); // attempt to get doc (from the server) and ensure it cannot be retreived XCTestExpectation *failedGetDocCompletion = [self expectationWithDescription:@"failedGetDoc"]; - [doc getDocumentWithOptions:[[FIRGetOptions alloc] initWithSource:FIRServer] + [doc getDocumentWithOptions:[[FIRGetOptions alloc] initWithSource:FIRSourceServer] completion:^(FIRDocumentSnapshot *snapshot, NSError *error) { XCTAssertNotNil(error); XCTAssertEqualObjects(error.domain, FIRFirestoreErrorDomain); @@ -391,7 +395,8 @@ - (void)testGetCollectionWhileOfflineWithDifferentGetOptions { // get docs (from cache) and ensure they *are* from the cache, and // matches the updated data. FIRQuerySnapshot *result = - [self readDocumentSetForRef:col options:[[FIRGetOptions alloc] initWithSource:FIRCache]]; + [self readDocumentSetForRef:col + options:[[FIRGetOptions alloc] initWithSource:FIRSourceCache]]; XCTAssertTrue(result.metadata.fromCache); XCTAssertEqualObjects(FIRQuerySnapshotGetData(result), (@[ @{@"key1" : @"value1"}, @{@"key2" : @"value2", @"key2b" : @"value2b"}, @@ -399,8 +404,8 @@ - (void)testGetCollectionWhileOfflineWithDifferentGetOptions { ])); // attempt to get docs (with default get options) - result = - [self readDocumentSetForRef:col options:[[FIRGetOptions alloc] initWithSource:FIRDefault]]; + result = [self readDocumentSetForRef:col + options:[[FIRGetOptions alloc] initWithSource:FIRSourceDefault]]; XCTAssertTrue(result.metadata.fromCache); XCTAssertEqualObjects(FIRQuerySnapshotGetData(result), (@[ @{@"key1" : @"value1"}, @{@"key2" : @"value2", @"key2b" : @"value2b"}, @@ -409,7 +414,7 @@ - (void)testGetCollectionWhileOfflineWithDifferentGetOptions { // attempt to get docs (from the server) and ensure they cannot be retreived XCTestExpectation *failedGetDocsCompletion = [self expectationWithDescription:@"failedGetDocs"]; - [col getDocumentsWithOptions:[[FIRGetOptions alloc] initWithSource:FIRServer] + [col getDocumentsWithOptions:[[FIRGetOptions alloc] initWithSource:FIRSourceServer] completion:^(FIRQuerySnapshot *snapshot, NSError *error) { XCTAssertNotNil(error); XCTAssertEqualObjects(error.domain, FIRFirestoreErrorDomain); @@ -477,7 +482,7 @@ - (void)testGetNonExistingDocWhileOnlineCacheOnly { // certain documents *don't* exist. XCTestExpectation *getNonExistingDocCompletion = [self expectationWithDescription:@"getNonExistingDoc"]; - [doc getDocumentWithOptions:[[FIRGetOptions alloc] initWithSource:FIRCache] + [doc getDocumentWithOptions:[[FIRGetOptions alloc] initWithSource:FIRSourceCache] completion:^(FIRDocumentSnapshot *snapshot, NSError *error) { XCTAssertNotNil(error); XCTAssertEqualObjects(error.domain, FIRFirestoreErrorDomain); @@ -492,7 +497,8 @@ - (void)testGetNonExistingCollectionWhileOnlineCacheOnly { // get collection and ensure it's empty and that it *is* from the cache. FIRQuerySnapshot *snapshot = - [self readDocumentSetForRef:col options:[[FIRGetOptions alloc] initWithSource:FIRCache]]; + [self readDocumentSetForRef:col + options:[[FIRGetOptions alloc] initWithSource:FIRSourceCache]]; XCTAssertEqual(snapshot.count, 0); XCTAssertTrue(snapshot.metadata.fromCache); } @@ -508,7 +514,7 @@ - (void)testGetNonExistingDocWhileOfflineCacheOnly { // certain documents *don't* exist. XCTestExpectation *getNonExistingDocCompletion = [self expectationWithDescription:@"getNonExistingDoc"]; - [doc getDocumentWithOptions:[[FIRGetOptions alloc] initWithSource:FIRCache] + [doc getDocumentWithOptions:[[FIRGetOptions alloc] initWithSource:FIRSourceCache] completion:^(FIRDocumentSnapshot *snapshot, NSError *error) { XCTAssertNotNil(error); XCTAssertEqualObjects(error.domain, FIRFirestoreErrorDomain); @@ -526,7 +532,8 @@ - (void)testGetNonExistingCollectionWhileOfflineCacheOnly { // get collection and ensure it's empty and that it *is* from the cache. FIRQuerySnapshot *snapshot = - [self readDocumentSetForRef:col options:[[FIRGetOptions alloc] initWithSource:FIRCache]]; + [self readDocumentSetForRef:col + options:[[FIRGetOptions alloc] initWithSource:FIRSourceCache]]; XCTAssertEqual(snapshot.count, 0); XCTAssertTrue(snapshot.metadata.fromCache); } @@ -536,7 +543,7 @@ - (void)testGetNonExistingDocWhileOnlineServerOnly { // get doc and ensure that it does not exist and is *not* from the cache. FIRDocumentSnapshot *snapshot = - [self readDocumentForRef:doc options:[[FIRGetOptions alloc] initWithSource:FIRServer]]; + [self readDocumentForRef:doc options:[[FIRGetOptions alloc] initWithSource:FIRSourceServer]]; XCTAssertFalse(snapshot.exists); XCTAssertFalse(snapshot.metadata.fromCache); } @@ -546,7 +553,8 @@ - (void)testGetNonExistingCollectionWhileOnlineServerOnly { // get collection and ensure that it's empty and that it's *not* from the cache. FIRQuerySnapshot *snapshot = - [self readDocumentSetForRef:col options:[[FIRGetOptions alloc] initWithSource:FIRServer]]; + [self readDocumentSetForRef:col + options:[[FIRGetOptions alloc] initWithSource:FIRSourceServer]]; XCTAssertEqual(snapshot.count, 0); XCTAssertFalse(snapshot.metadata.fromCache); } @@ -562,7 +570,7 @@ - (void)testGetNonExistingDocWhileOfflineServerOnly { // certain documents *don't* exist. XCTestExpectation *getNonExistingDocCompletion = [self expectationWithDescription:@"getNonExistingDoc"]; - [doc getDocumentWithOptions:[[FIRGetOptions alloc] initWithSource:FIRServer] + [doc getDocumentWithOptions:[[FIRGetOptions alloc] initWithSource:FIRSourceServer] completion:^(FIRDocumentSnapshot *snapshot, NSError *error) { XCTAssertNotNil(error); XCTAssertEqualObjects(error.domain, FIRFirestoreErrorDomain); @@ -580,7 +588,7 @@ - (void)testGetNonExistingCollectionWhileOfflineServerOnly { // attempt to get collection and ensure that it cannot be retreived XCTestExpectation *failedGetDocsCompletion = [self expectationWithDescription:@"failedGetDocs"]; - [col getDocumentsWithOptions:[[FIRGetOptions alloc] initWithSource:FIRServer] + [col getDocumentsWithOptions:[[FIRGetOptions alloc] initWithSource:FIRSourceServer] completion:^(FIRQuerySnapshot *snapshot, NSError *error) { XCTAssertNotNil(error); XCTAssertEqualObjects(error.domain, FIRFirestoreErrorDomain); diff --git a/Firestore/Source/API/FIRDocumentReference.m b/Firestore/Source/API/FIRDocumentReference.m index 3a20e9ac08b..c9aebb1d94d 100644 --- a/Firestore/Source/API/FIRDocumentReference.m +++ b/Firestore/Source/API/FIRDocumentReference.m @@ -216,7 +216,7 @@ - (void)getDocumentWithCompletion:(void (^)(FIRDocumentSnapshot *_Nullable docum - (void)getDocumentWithOptions:(FIRGetOptions *)options completion:(void (^)(FIRDocumentSnapshot *_Nullable document, NSError *_Nullable error))completion { - if (options.source == FIRCache) { + if (options.source == FIRSourceCache) { [self.firestore.client getDocumentFromLocalCache:self completion:completion]; return; } @@ -255,7 +255,8 @@ - (void)getDocumentWithOptions:(FIRGetOptions *)options NSLocalizedDescriptionKey : @"Failed to get document because the client is offline.", }]); - } else if (snapshot.exists && snapshot.metadata.fromCache && options.source == FIRServer) { + } else if (snapshot.exists && snapshot.metadata.fromCache && + options.source == FIRSourceServer) { completion(nil, [NSError errorWithDomain:FIRFirestoreErrorDomain code:FIRFirestoreErrorCodeUnavailable userInfo:@{ diff --git a/Firestore/Source/API/FIRGetOptions.m b/Firestore/Source/API/FIRGetOptions.m index c63396206b1..774b0972fc9 100644 --- a/Firestore/Source/API/FIRGetOptions.m +++ b/Firestore/Source/API/FIRGetOptions.m @@ -21,7 +21,7 @@ @implementation FIRGetOptions + (FIRGetOptions *)defaultOptions { - return [[FIRGetOptions alloc] initWithSource:FIRDefault]; + return [[FIRGetOptions alloc] initWithSource:FIRSourceDefault]; } - (instancetype)initWithSource:(FIRSource)source { diff --git a/Firestore/Source/API/FIRQuery.m b/Firestore/Source/API/FIRQuery.m index 2e545d3f8f7..671968882d2 100644 --- a/Firestore/Source/API/FIRQuery.m +++ b/Firestore/Source/API/FIRQuery.m @@ -138,7 +138,7 @@ - (void)getDocumentsWithCompletion:(void (^)(FIRQuerySnapshot *_Nullable snapsho - (void)getDocumentsWithOptions:(FIRGetOptions *)options completion:(void (^)(FIRQuerySnapshot *_Nullable snapshot, NSError *_Nullable error))completion { - if (options.source == FIRCache) { + if (options.source == FIRSourceCache) { [self.firestore.client getDocumentsFromLocalCache:self completion:completion]; return; } @@ -161,7 +161,7 @@ - (void)getDocumentsWithOptions:(FIRGetOptions *)options dispatch_semaphore_wait(registered, DISPATCH_TIME_FOREVER); [listenerRegistration remove]; - if (snapshot.metadata.fromCache && options.source == FIRServer) { + if (snapshot.metadata.fromCache && options.source == FIRSourceServer) { completion(nil, [NSError errorWithDomain:FIRFirestoreErrorDomain code:FIRFirestoreErrorCodeUnavailable userInfo:@{ diff --git a/Firestore/Source/Public/FIRGetOptions.h b/Firestore/Source/Public/FIRGetOptions.h index 70041655eee..d56ef8bf341 100644 --- a/Firestore/Source/Public/FIRGetOptions.h +++ b/Firestore/Source/Public/FIRGetOptions.h @@ -53,7 +53,11 @@ NS_SWIFT_NAME(GetOptions) * stale with respect to the value on the server.) For a single document, the * get will fail if the document doesn't exist. */ -typedef NS_ENUM(NSUInteger, FIRSource) { FIRDefault, FIRServer, FIRCache } NS_SWIFT_NAME(Source); +typedef NS_ENUM(NSUInteger, FIRSource) { + FIRSourceDefault, + FIRSourceServer, + FIRSourceCache +} NS_SWIFT_NAME(Source); /** * Initializes the get options with the specified source. From 61876ad91edb9332c115734e5c4830b1cb2d85f8 Mon Sep 17 00:00:00 2001 From: Rich Gowman Date: Wed, 17 Jan 2018 18:51:09 -0500 Subject: [PATCH 08/12] Alter getDocumentsFromLocalCache to be more like FSTSyncEngine.listenToQuery --- .../Integration/API/FIRGetOptionsTests.m | 68 +++++++++++++++++++ .../Tests/Util/FSTIntegrationTestCase.h | 4 ++ .../Tests/Util/FSTIntegrationTestCase.mm | 12 ++++ Firestore/Source/Core/FSTFirestoreClient.m | 27 ++++---- 4 files changed, 96 insertions(+), 15 deletions(-) diff --git a/Firestore/Example/Tests/Integration/API/FIRGetOptionsTests.m b/Firestore/Example/Tests/Integration/API/FIRGetOptionsTests.m index e9d17277f12..cfcc44548f4 100644 --- a/Firestore/Example/Tests/Integration/API/FIRGetOptionsTests.m +++ b/Firestore/Example/Tests/Integration/API/FIRGetOptionsTests.m @@ -39,6 +39,7 @@ - (void)testGetDocumentWhileOnlineWithDefaultGetOptions { FIRDocumentSnapshot *result = [self readDocumentForRef:doc]; XCTAssertTrue(result.exists); XCTAssertFalse(result.metadata.fromCache); + XCTAssertFalse(result.metadata.hasPendingWrites); XCTAssertEqualObjects(result.data, initialData); } @@ -57,9 +58,15 @@ - (void)testGetCollectionWhileOnlineWithDefaultGetOptions { // initialDocs. FIRQuerySnapshot *result = [self readDocumentSetForRef:col]; XCTAssertFalse(result.metadata.fromCache); + XCTAssertFalse(result.metadata.hasPendingWrites); XCTAssertEqualObjects( FIRQuerySnapshotGetData(result), (@[ @{@"key1" : @"value1"}, @{@"key2" : @"value2"}, @{@"key3" : @"value3"} ])); + XCTAssertEqualObjects(FIRQuerySnapshotGetDocChangesData(result), (@[ + @[ @(FIRDocumentChangeTypeAdded), @"doc1", @{@"key1" : @"value1"} ], + @[ @(FIRDocumentChangeTypeAdded), @"doc2", @{@"key2" : @"value2"} ], + @[ @(FIRDocumentChangeTypeAdded), @"doc3", @{@"key3" : @"value3"} ] + ])); } - (void)testGetDocumentWhileOfflineWithDefaultGetOptions { @@ -86,6 +93,7 @@ - (void)testGetDocumentWhileOfflineWithDefaultGetOptions { FIRDocumentSnapshot *result = [self readDocumentForRef:doc]; XCTAssertTrue(result.exists); XCTAssertTrue(result.metadata.fromCache); + XCTAssertTrue(result.metadata.hasPendingWrites); XCTAssertEqualObjects(result.data, newData); } @@ -113,10 +121,18 @@ - (void)testGetCollectionWhileOfflineWithDefaultGetOptions { // get docs and ensure they *are* from the cache, and matches the updated data. FIRQuerySnapshot *result = [self readDocumentSetForRef:col]; XCTAssertTrue(result.metadata.fromCache); + XCTAssertTrue(result.metadata.hasPendingWrites); XCTAssertEqualObjects(FIRQuerySnapshotGetData(result), (@[ @{@"key1" : @"value1"}, @{@"key2" : @"value2", @"key2b" : @"value2b"}, @{@"key3b" : @"value3b"}, @{@"key4" : @"value4"} ])); + XCTAssertEqualObjects( + FIRQuerySnapshotGetDocChangesData(result), (@[ + @[ @(FIRDocumentChangeTypeAdded), @"doc1", @{@"key1" : @"value1"} ], + @[ @(FIRDocumentChangeTypeAdded), @"doc2", @{@"key2" : @"value2", @"key2b" : @"value2b"} ], + @[ @(FIRDocumentChangeTypeAdded), @"doc3", @{@"key3b" : @"value3b"} ], + @[ @(FIRDocumentChangeTypeAdded), @"doc4", @{@"key4" : @"value4"} ] + ])); } - (void)testGetDocumentWhileOnlineCacheOnly { @@ -132,6 +148,7 @@ - (void)testGetDocumentWhileOnlineCacheOnly { [self readDocumentForRef:doc options:[[FIRGetOptions alloc] initWithSource:FIRSourceCache]]; XCTAssertTrue(result.exists); XCTAssertTrue(result.metadata.fromCache); + XCTAssertFalse(result.metadata.hasPendingWrites); XCTAssertEqualObjects(result.data, initialData); } @@ -152,11 +169,17 @@ - (void)testGetCollectionWhileOnlineCacheOnly { [self readDocumentSetForRef:col options:[[FIRGetOptions alloc] initWithSource:FIRSourceCache]]; XCTAssertTrue(result.metadata.fromCache); + XCTAssertFalse(result.metadata.hasPendingWrites); XCTAssertEqualObjects(FIRQuerySnapshotGetData(result), (@[ @{@"key1" : @"value1"}, @{@"key2" : @"value2"}, @{@"key3" : @"value3"}, ])); + XCTAssertEqualObjects(FIRQuerySnapshotGetDocChangesData(result), (@[ + @[ @(FIRDocumentChangeTypeAdded), @"doc1", @{@"key1" : @"value1"} ], + @[ @(FIRDocumentChangeTypeAdded), @"doc2", @{@"key2" : @"value2"} ], + @[ @(FIRDocumentChangeTypeAdded), @"doc3", @{@"key3" : @"value3"} ] + ])); } - (void)testGetDocumentWhileOfflineCacheOnly { @@ -184,6 +207,7 @@ - (void)testGetDocumentWhileOfflineCacheOnly { [self readDocumentForRef:doc options:[[FIRGetOptions alloc] initWithSource:FIRSourceCache]]; XCTAssertTrue(result.exists); XCTAssertTrue(result.metadata.fromCache); + XCTAssertTrue(result.metadata.hasPendingWrites); XCTAssertEqualObjects(result.data, newData); } @@ -214,10 +238,18 @@ - (void)testGetCollectionWhileOfflineCacheOnly { [self readDocumentSetForRef:col options:[[FIRGetOptions alloc] initWithSource:FIRSourceCache]]; XCTAssertTrue(result.metadata.fromCache); + XCTAssertTrue(result.metadata.hasPendingWrites); XCTAssertEqualObjects(FIRQuerySnapshotGetData(result), (@[ @{@"key1" : @"value1"}, @{@"key2" : @"value2", @"key2b" : @"value2b"}, @{@"key3b" : @"value3b"}, @{@"key4" : @"value4"} ])); + XCTAssertEqualObjects( + FIRQuerySnapshotGetDocChangesData(result), (@[ + @[ @(FIRDocumentChangeTypeAdded), @"doc1", @{@"key1" : @"value1"} ], + @[ @(FIRDocumentChangeTypeAdded), @"doc2", @{@"key2" : @"value2", @"key2b" : @"value2b"} ], + @[ @(FIRDocumentChangeTypeAdded), @"doc3", @{@"key3b" : @"value3b"} ], + @[ @(FIRDocumentChangeTypeAdded), @"doc4", @{@"key4" : @"value4"} ] + ])); } - (void)testGetDocumentWhileOnlineServerOnly { @@ -233,6 +265,7 @@ - (void)testGetDocumentWhileOnlineServerOnly { [self readDocumentForRef:doc options:[[FIRGetOptions alloc] initWithSource:FIRSourceServer]]; XCTAssertTrue(result.exists); XCTAssertFalse(result.metadata.fromCache); + XCTAssertFalse(result.metadata.hasPendingWrites); XCTAssertEqualObjects(result.data, initialData); } @@ -253,11 +286,17 @@ - (void)testGetCollectionWhileOnlineServerOnly { [self readDocumentSetForRef:col options:[[FIRGetOptions alloc] initWithSource:FIRSourceServer]]; XCTAssertFalse(result.metadata.fromCache); + XCTAssertFalse(result.metadata.hasPendingWrites); XCTAssertEqualObjects(FIRQuerySnapshotGetData(result), (@[ @{@"key1" : @"value1"}, @{@"key2" : @"value2"}, @{@"key3" : @"value3"}, ])); + XCTAssertEqualObjects(FIRQuerySnapshotGetDocChangesData(result), (@[ + @[ @(FIRDocumentChangeTypeAdded), @"doc1", @{@"key1" : @"value1"} ], + @[ @(FIRDocumentChangeTypeAdded), @"doc2", @{@"key2" : @"value2"} ], + @[ @(FIRDocumentChangeTypeAdded), @"doc3", @{@"key3" : @"value3"} ] + ])); } - (void)testGetDocumentWhileOfflineServerOnly { @@ -341,6 +380,7 @@ - (void)testGetDocumentWhileOfflineWithDifferentGetOptions { [self readDocumentForRef:doc options:[[FIRGetOptions alloc] initWithSource:FIRSourceCache]]; XCTAssertTrue(result.exists); XCTAssertTrue(result.metadata.fromCache); + XCTAssertTrue(result.metadata.hasPendingWrites); XCTAssertEqualObjects(result.data, newData); // attempt to get doc (with default get options) @@ -348,6 +388,7 @@ - (void)testGetDocumentWhileOfflineWithDifferentGetOptions { [self readDocumentForRef:doc options:[[FIRGetOptions alloc] initWithSource:FIRSourceDefault]]; XCTAssertTrue(result.exists); XCTAssertTrue(result.metadata.fromCache); + XCTAssertTrue(result.metadata.hasPendingWrites); XCTAssertEqualObjects(result.data, newData); // attempt to get doc (from the server) and ensure it cannot be retreived @@ -398,10 +439,18 @@ - (void)testGetCollectionWhileOfflineWithDifferentGetOptions { [self readDocumentSetForRef:col options:[[FIRGetOptions alloc] initWithSource:FIRSourceCache]]; XCTAssertTrue(result.metadata.fromCache); + XCTAssertTrue(result.metadata.hasPendingWrites); XCTAssertEqualObjects(FIRQuerySnapshotGetData(result), (@[ @{@"key1" : @"value1"}, @{@"key2" : @"value2", @"key2b" : @"value2b"}, @{@"key3b" : @"value3b"}, @{@"key4" : @"value4"} ])); + XCTAssertEqualObjects( + FIRQuerySnapshotGetDocChangesData(result), (@[ + @[ @(FIRDocumentChangeTypeAdded), @"doc1", @{@"key1" : @"value1"} ], + @[ @(FIRDocumentChangeTypeAdded), @"doc2", @{@"key2" : @"value2", @"key2b" : @"value2b"} ], + @[ @(FIRDocumentChangeTypeAdded), @"doc3", @{@"key3b" : @"value3b"} ], + @[ @(FIRDocumentChangeTypeAdded), @"doc4", @{@"key4" : @"value4"} ] + ])); // attempt to get docs (with default get options) result = [self readDocumentSetForRef:col @@ -411,6 +460,13 @@ - (void)testGetCollectionWhileOfflineWithDifferentGetOptions { @{@"key1" : @"value1"}, @{@"key2" : @"value2", @"key2b" : @"value2b"}, @{@"key3b" : @"value3b"}, @{@"key4" : @"value4"} ])); + XCTAssertEqualObjects( + FIRQuerySnapshotGetDocChangesData(result), (@[ + @[ @(FIRDocumentChangeTypeAdded), @"doc1", @{@"key1" : @"value1"} ], + @[ @(FIRDocumentChangeTypeAdded), @"doc2", @{@"key2" : @"value2", @"key2b" : @"value2b"} ], + @[ @(FIRDocumentChangeTypeAdded), @"doc3", @{@"key3b" : @"value3b"} ], + @[ @(FIRDocumentChangeTypeAdded), @"doc4", @{@"key4" : @"value4"} ] + ])); // attempt to get docs (from the server) and ensure they cannot be retreived XCTestExpectation *failedGetDocsCompletion = [self expectationWithDescription:@"failedGetDocs"]; @@ -431,6 +487,7 @@ - (void)testGetNonExistingDocWhileOnlineWithDefaultGetOptions { FIRDocumentSnapshot *snapshot = [self readDocumentForRef:doc]; XCTAssertFalse(snapshot.exists); XCTAssertFalse(snapshot.metadata.fromCache); + XCTAssertFalse(snapshot.metadata.hasPendingWrites); } - (void)testGetNonExistingCollectionWhileOnlineWithDefaultGetOptions { @@ -439,7 +496,9 @@ - (void)testGetNonExistingCollectionWhileOnlineWithDefaultGetOptions { // get collection and ensure it's empty and that it's *not* from the cache. FIRQuerySnapshot *snapshot = [self readDocumentSetForRef:col]; XCTAssertEqual(snapshot.count, 0); + XCTAssertEqual(snapshot.documentChanges.count, 0); XCTAssertFalse(snapshot.metadata.fromCache); + XCTAssertFalse(snapshot.metadata.hasPendingWrites); } - (void)testGetNonExistingDocWhileOfflineWithDefaultGetOptions { @@ -471,7 +530,9 @@ - (void)testGetNonExistingCollectionWhileOfflineWithDefaultGetOptions { // get collection and ensure it's empty and that it *is* from the cache. FIRQuerySnapshot *snapshot = [self readDocumentSetForRef:col]; XCTAssertEqual(snapshot.count, 0); + XCTAssertEqual(snapshot.documentChanges.count, 0); XCTAssertTrue(snapshot.metadata.fromCache); + XCTAssertFalse(snapshot.metadata.hasPendingWrites); } - (void)testGetNonExistingDocWhileOnlineCacheOnly { @@ -500,7 +561,9 @@ - (void)testGetNonExistingCollectionWhileOnlineCacheOnly { [self readDocumentSetForRef:col options:[[FIRGetOptions alloc] initWithSource:FIRSourceCache]]; XCTAssertEqual(snapshot.count, 0); + XCTAssertEqual(snapshot.documentChanges.count, 0); XCTAssertTrue(snapshot.metadata.fromCache); + XCTAssertFalse(snapshot.metadata.hasPendingWrites); } - (void)testGetNonExistingDocWhileOfflineCacheOnly { @@ -535,7 +598,9 @@ - (void)testGetNonExistingCollectionWhileOfflineCacheOnly { [self readDocumentSetForRef:col options:[[FIRGetOptions alloc] initWithSource:FIRSourceCache]]; XCTAssertEqual(snapshot.count, 0); + XCTAssertEqual(snapshot.documentChanges.count, 0); XCTAssertTrue(snapshot.metadata.fromCache); + XCTAssertFalse(snapshot.metadata.hasPendingWrites); } - (void)testGetNonExistingDocWhileOnlineServerOnly { @@ -546,6 +611,7 @@ - (void)testGetNonExistingDocWhileOnlineServerOnly { [self readDocumentForRef:doc options:[[FIRGetOptions alloc] initWithSource:FIRSourceServer]]; XCTAssertFalse(snapshot.exists); XCTAssertFalse(snapshot.metadata.fromCache); + XCTAssertFalse(snapshot.metadata.hasPendingWrites); } - (void)testGetNonExistingCollectionWhileOnlineServerOnly { @@ -556,7 +622,9 @@ - (void)testGetNonExistingCollectionWhileOnlineServerOnly { [self readDocumentSetForRef:col options:[[FIRGetOptions alloc] initWithSource:FIRSourceServer]]; XCTAssertEqual(snapshot.count, 0); + XCTAssertEqual(snapshot.documentChanges.count, 0); XCTAssertFalse(snapshot.metadata.fromCache); + XCTAssertFalse(snapshot.metadata.hasPendingWrites); } - (void)testGetNonExistingDocWhileOfflineServerOnly { diff --git a/Firestore/Example/Tests/Util/FSTIntegrationTestCase.h b/Firestore/Example/Tests/Util/FSTIntegrationTestCase.h index 42e273f3c18..fa12d868304 100644 --- a/Firestore/Example/Tests/Util/FSTIntegrationTestCase.h +++ b/Firestore/Example/Tests/Util/FSTIntegrationTestCase.h @@ -111,6 +111,10 @@ NSArray *> *FIRQuerySnapshotGetData(FIRQuerySnapsho /** Converts the FIRQuerySnapshot to an NSArray containing the document IDs in order. */ NSArray *FIRQuerySnapshotGetIDs(FIRQuerySnapshot *docs); +/** Converts the FIRQuerySnapshot to an NSArray containing an NSArray containing the doc change data + * in order of { type, doc title, doc data }. */ +NSArray *> *FIRQuerySnapshotGetDocChangesData(FIRQuerySnapshot *docs); + #if __cplusplus } // extern "C" #endif diff --git a/Firestore/Example/Tests/Util/FSTIntegrationTestCase.mm b/Firestore/Example/Tests/Util/FSTIntegrationTestCase.mm index 1282aabffd5..ac98e877864 100644 --- a/Firestore/Example/Tests/Util/FSTIntegrationTestCase.mm +++ b/Firestore/Example/Tests/Util/FSTIntegrationTestCase.mm @@ -325,6 +325,18 @@ - (void)waitUntil:(BOOL (^)())predicate { return result; } +extern "C" NSArray *> *FIRQuerySnapshotGetDocChangesData(FIRQuerySnapshot *docs) { + NSMutableArray *> *result = [NSMutableArray array]; + for (FIRDocumentChange *docChange in docs.documentChanges) { + NSMutableArray *docChangeData = [NSMutableArray array]; + [docChangeData addObject:@(docChange.type)]; + [docChangeData addObject:docChange.document.documentID]; + [docChangeData addObject:docChange.document.data]; + [result addObject:docChangeData]; + } + return result; +} + @end NS_ASSUME_NONNULL_END diff --git a/Firestore/Source/Core/FSTFirestoreClient.m b/Firestore/Source/Core/FSTFirestoreClient.m index 0d66654b924..5d3a281cd52 100644 --- a/Firestore/Source/Core/FSTFirestoreClient.m +++ b/Firestore/Source/Core/FSTFirestoreClient.m @@ -28,6 +28,7 @@ #import "Firestore/Source/Core/FSTQuery.h" #import "Firestore/Source/Core/FSTSyncEngine.h" #import "Firestore/Source/Core/FSTTransaction.h" +#import "Firestore/Source/Core/FSTView.h" #import "Firestore/Source/Local/FSTEagerGarbageCollector.h" #import "Firestore/Source/Local/FSTLevelDB.h" #import "Firestore/Source/Local/FSTLocalSerializer.h" @@ -287,27 +288,23 @@ - (void)getDocumentsFromLocalCache:(FIRQuery *)query completion:(void (^)(FIRQuerySnapshot *_Nullable query, NSError *_Nullable error))completion { [self.workerDispatchQueue dispatchAsync:^{ + FSTDocumentDictionary *docs = [self.localStore executeQuery:query.query]; + FSTDocumentKeySet *remoteKeys = [FSTDocumentKeySet keySet]; - __block FSTDocumentSet *documents = - [FSTDocumentSet documentSetWithComparator:query.query.comparator]; - FSTDocumentSet *oldDocuments = documents; - [docs enumerateKeysAndObjectsUsingBlock:^(FSTDocumentKey *key, FSTDocument *value, BOOL *stop) { - documents = [documents documentSetByAddingDocument:value]; - }]; + FSTView *view = [[FSTView alloc] initWithQuery:query.query remoteDocuments:remoteKeys]; + FSTViewDocumentChanges *viewDocChanges = [view computeChangesWithDocuments:docs]; + FSTViewChange *viewChange = [view applyChangesToDocuments:viewDocChanges]; + FSTAssert(viewChange.limboChanges.count == 0, + @"View returned limbo docs before target ack from the server."); - FSTViewSnapshot *snapshot = [[FSTViewSnapshot alloc] initWithQuery:query.query - documents:documents - oldDocuments:oldDocuments - documentChanges:@[] - fromCache:YES - hasPendingWrites:NO - syncStateChanged:NO]; + FSTViewSnapshot *snapshot = viewChange.snapshot; FIRSnapshotMetadata *metadata = - [FIRSnapshotMetadata snapshotMetadataWithPendingWrites:NO fromCache:YES]; + [FIRSnapshotMetadata snapshotMetadataWithPendingWrites:snapshot.hasPendingWrites + fromCache:snapshot.fromCache]; completion([FIRQuerySnapshot snapshotWithFirestore:query.firestore - originalQuery:query.query + originalQuery:query snapshot:snapshot metadata:metadata], nil); From f5024fb3a7428d64cacaba3715e8ceae40885764 Mon Sep 17 00:00:00 2001 From: Rich Gowman Date: Wed, 17 Jan 2018 20:10:12 -0500 Subject: [PATCH 09/12] Fix error messages. --- Firestore/Source/API/FIRDocumentReference.m | 19 ++++++++++--------- Firestore/Source/API/FIRQuery.m | 19 ++++++++++--------- Firestore/Source/Core/FSTFirestoreClient.m | 19 ++++++++++--------- 3 files changed, 30 insertions(+), 27 deletions(-) diff --git a/Firestore/Source/API/FIRDocumentReference.m b/Firestore/Source/API/FIRDocumentReference.m index c9aebb1d94d..87db991ba06 100644 --- a/Firestore/Source/API/FIRDocumentReference.m +++ b/Firestore/Source/API/FIRDocumentReference.m @@ -257,15 +257,16 @@ - (void)getDocumentWithOptions:(FIRGetOptions *)options }]); } else if (snapshot.exists && snapshot.metadata.fromCache && options.source == FIRSourceServer) { - completion(nil, [NSError errorWithDomain:FIRFirestoreErrorDomain - code:FIRFirestoreErrorCodeUnavailable - userInfo:@{ - NSLocalizedDescriptionKey : - @"Failed to get document from server. (However, this " - @"document does exist in the local cache. Run again " - @"without setting FIRServer in the GetOptions to " - @"retrieve the cached document.)" - }]); + completion(nil, + [NSError errorWithDomain:FIRFirestoreErrorDomain + code:FIRFirestoreErrorCodeUnavailable + userInfo:@{ + NSLocalizedDescriptionKey : + @"Failed to get document from server. (However, this " + @"document does exist in the local cache. Run again " + @"without setting FIRSourceServer in the FIRGetOptions to " + @"retrieve the cached document.)" + }]); } else { completion(snapshot, nil); } diff --git a/Firestore/Source/API/FIRQuery.m b/Firestore/Source/API/FIRQuery.m index 671968882d2..31624b1257d 100644 --- a/Firestore/Source/API/FIRQuery.m +++ b/Firestore/Source/API/FIRQuery.m @@ -162,15 +162,16 @@ - (void)getDocumentsWithOptions:(FIRGetOptions *)options [listenerRegistration remove]; if (snapshot.metadata.fromCache && options.source == FIRSourceServer) { - completion(nil, [NSError errorWithDomain:FIRFirestoreErrorDomain - code:FIRFirestoreErrorCodeUnavailable - userInfo:@{ - NSLocalizedDescriptionKey : - @"Failed to get documents from server. (However, these " - @"documents may exist in the local cache. Run again " - @"without setting FIRServer in the GetOptions to " - @"retrieve the cached documents.)" - }]); + completion(nil, + [NSError errorWithDomain:FIRFirestoreErrorDomain + code:FIRFirestoreErrorCodeUnavailable + userInfo:@{ + NSLocalizedDescriptionKey : + @"Failed to get documents from server. (However, these " + @"documents may exist in the local cache. Run again " + @"without setting FIRSourceServer in the FIRGetOptions to " + @"retrieve the cached documents.)" + }]); } else { completion(snapshot, nil); } diff --git a/Firestore/Source/Core/FSTFirestoreClient.m b/Firestore/Source/Core/FSTFirestoreClient.m index 5d3a281cd52..6ac0ec3f1e0 100644 --- a/Firestore/Source/Core/FSTFirestoreClient.m +++ b/Firestore/Source/Core/FSTFirestoreClient.m @@ -271,15 +271,16 @@ - (void)getDocumentFromLocalCache:(FIRDocumentReference *)doc fromCache:YES], nil); } else { - completion(nil, [NSError errorWithDomain:FIRFirestoreErrorDomain - code:FIRFirestoreErrorCodeUnavailable - userInfo:@{ - NSLocalizedDescriptionKey : - @"Failed to get document from cache. (However, this " - @"document may exist on the server. Run again without " - @"setting FIRCache in the GetOptions to attempt to " - @"retrieve the document from the server.)", - }]); + completion(nil, + [NSError errorWithDomain:FIRFirestoreErrorDomain + code:FIRFirestoreErrorCodeUnavailable + userInfo:@{ + NSLocalizedDescriptionKey : + @"Failed to get document from cache. (However, this " + @"document may exist on the server. Run again without " + @"setting FIRSourceCache in the FIRGetOptions to attempt to " + @"retrieve the document from the server.)", + }]); } }]; } From 3abd4499305669ab3f8bc4b8634ee4b81b2b481b Mon Sep 17 00:00:00 2001 From: Rich Gowman Date: Wed, 17 Jan 2018 20:12:50 -0500 Subject: [PATCH 10/12] Fix doc comments. --- Firestore/Source/Public/FIRGetOptions.h | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/Firestore/Source/Public/FIRGetOptions.h b/Firestore/Source/Public/FIRGetOptions.h index d56ef8bf341..935345cdbe5 100644 --- a/Firestore/Source/Public/FIRGetOptions.h +++ b/Firestore/Source/Public/FIRGetOptions.h @@ -31,7 +31,7 @@ NS_SWIFT_NAME(GetOptions) /** * Returns the default options. * - * Equiavlent to `[[FIRGetOptions alloc] initWithSource:FIRDefault]` in + * Equiavlent to `[[FIRGetOptions alloc] initWithSource:FIRSourceDefault]` in * objective-c. */ + (FIRGetOptions *)defaultOptions NS_SWIFT_NAME(defaultOptions()); @@ -39,19 +39,19 @@ NS_SWIFT_NAME(GetOptions) /** * Describes whether we should get from server or cache. * - * Setting the GetOption source to FIRDefault, if online, causes Firestore to - * try to give a consistent (server-retrieved) snapshot, or else revert to the - * cache to provide a value. + * Setting the FIRGetOption source to FIRSourceDefault, if online, causes + * Firestore to try to give a consistent (server-retrieved) snapshot, or else + * revert to the cache to provide a value. * - * FIRServer causes Firestore to avoid the cache (generating an error if a - * value cannot be retrieved from the server). The cache will be updated if the - * RPC succeeds. Latency compensation still occurs (implying that if the cache - * is more up to date, then it's values will be merged into the results). + * FIRSourceServer causes Firestore to avoid the cache (generating an error if + * a value cannot be retrieved from the server). The cache will be updated if + * the RPC succeeds. Latency compensation still occurs (implying that if the + * cache is more up to date, then it's values will be merged into the results). * - * FIRCache causes Firestore to immediately return a value from the cache, - * ignoring the server completely (implying that the returned value may be - * stale with respect to the value on the server.) For a single document, the - * get will fail if the document doesn't exist. + * FIRSourceCache causes Firestore to immediately return a value from the + * cache, ignoring the server completely (implying that the returned value may + * be stale with respect to the value on the server.) For a single document, + * the get will fail if the document doesn't exist. */ typedef NS_ENUM(NSUInteger, FIRSource) { FIRSourceDefault, From d7b9e604c6e7573122fec4af4d4f89b1f75a12da Mon Sep 17 00:00:00 2001 From: Rich Gowman Date: Wed, 17 Jan 2018 20:33:33 -0500 Subject: [PATCH 11/12] FIRSource -> FIRGetSource --- Firestore/Example/SwiftBuildTest/main.swift | 12 ++--- .../Integration/API/FIRGetOptionsTests.m | 51 ++++++++++--------- Firestore/Source/API/FIRDocumentReference.m | 24 ++++----- Firestore/Source/API/FIRGetOptions+Internal.h | 2 +- Firestore/Source/API/FIRGetOptions.m | 4 +- Firestore/Source/API/FIRQuery.m | 24 ++++----- Firestore/Source/Core/FSTFirestoreClient.m | 23 +++++---- Firestore/Source/Public/FIRGetOptions.h | 24 ++++----- 8 files changed, 85 insertions(+), 79 deletions(-) diff --git a/Firestore/Example/SwiftBuildTest/main.swift b/Firestore/Example/SwiftBuildTest/main.swift index f102e28c01d..eabca1c4973 100644 --- a/Firestore/Example/SwiftBuildTest/main.swift +++ b/Firestore/Example/SwiftBuildTest/main.swift @@ -228,11 +228,11 @@ func readDocument(at docRef: DocumentReference) { func readDocumentWithOptions(at docRef: DocumentReference) { docRef.getDocument(options:GetOptions.defaultOptions()) { document, error in } - docRef.getDocument(options:GetOptions.init(source:Source.default)) { document, error in + docRef.getDocument(options:GetOptions.init(source:GetSource.default)) { document, error in } - docRef.getDocument(options:GetOptions.init(source:Source.server)) { document, error in + docRef.getDocument(options:GetOptions.init(source:GetSource.server)) { document, error in } - docRef.getDocument(options:GetOptions.init(source:Source.cache)) { document, error in + docRef.getDocument(options:GetOptions.init(source:GetSource.cache)) { document, error in } } @@ -249,11 +249,11 @@ func readDocuments(matching query: Query) { func readDocumentsWithOptions(matching query: Query) { query.getDocuments(options:GetOptions.defaultOptions()) { querySnapshot, error in } - query.getDocuments(options:GetOptions.init(source:Source.default)) { querySnapshot, error in + query.getDocuments(options:GetOptions.init(source:GetSource.default)) { querySnapshot, error in } - query.getDocuments(options:GetOptions.init(source:Source.server)) { querySnapshot, error in + query.getDocuments(options:GetOptions.init(source:GetSource.server)) { querySnapshot, error in } - query.getDocuments(options:GetOptions.init(source:Source.cache)) { querySnapshot, error in + query.getDocuments(options:GetOptions.init(source:GetSource.cache)) { querySnapshot, error in } } diff --git a/Firestore/Example/Tests/Integration/API/FIRGetOptionsTests.m b/Firestore/Example/Tests/Integration/API/FIRGetOptionsTests.m index cfcc44548f4..628a6dcb2d8 100644 --- a/Firestore/Example/Tests/Integration/API/FIRGetOptionsTests.m +++ b/Firestore/Example/Tests/Integration/API/FIRGetOptionsTests.m @@ -145,7 +145,8 @@ - (void)testGetDocumentWhileOnlineCacheOnly { // get doc and ensure that it exists, *is* from the cache, and matches // the initialData. FIRDocumentSnapshot *result = - [self readDocumentForRef:doc options:[[FIRGetOptions alloc] initWithSource:FIRSourceCache]]; + [self readDocumentForRef:doc + options:[[FIRGetOptions alloc] initWithSource:FIRGetSourceCache]]; XCTAssertTrue(result.exists); XCTAssertTrue(result.metadata.fromCache); XCTAssertFalse(result.metadata.hasPendingWrites); @@ -167,7 +168,7 @@ - (void)testGetCollectionWhileOnlineCacheOnly { // initialDocs. FIRQuerySnapshot *result = [self readDocumentSetForRef:col - options:[[FIRGetOptions alloc] initWithSource:FIRSourceCache]]; + options:[[FIRGetOptions alloc] initWithSource:FIRGetSourceCache]]; XCTAssertTrue(result.metadata.fromCache); XCTAssertFalse(result.metadata.hasPendingWrites); XCTAssertEqualObjects(FIRQuerySnapshotGetData(result), (@[ @@ -204,7 +205,8 @@ - (void)testGetDocumentWhileOfflineCacheOnly { // get doc and ensure it exists, *is* from the cache, and matches the // newData. FIRDocumentSnapshot *result = - [self readDocumentForRef:doc options:[[FIRGetOptions alloc] initWithSource:FIRSourceCache]]; + [self readDocumentForRef:doc + options:[[FIRGetOptions alloc] initWithSource:FIRGetSourceCache]]; XCTAssertTrue(result.exists); XCTAssertTrue(result.metadata.fromCache); XCTAssertTrue(result.metadata.hasPendingWrites); @@ -236,7 +238,7 @@ - (void)testGetCollectionWhileOfflineCacheOnly { // data. FIRQuerySnapshot *result = [self readDocumentSetForRef:col - options:[[FIRGetOptions alloc] initWithSource:FIRSourceCache]]; + options:[[FIRGetOptions alloc] initWithSource:FIRGetSourceCache]]; XCTAssertTrue(result.metadata.fromCache); XCTAssertTrue(result.metadata.hasPendingWrites); XCTAssertEqualObjects(FIRQuerySnapshotGetData(result), (@[ @@ -262,7 +264,8 @@ - (void)testGetDocumentWhileOnlineServerOnly { // get doc and ensure that it exists, is *not* from the cache, and matches // the initialData. FIRDocumentSnapshot *result = - [self readDocumentForRef:doc options:[[FIRGetOptions alloc] initWithSource:FIRSourceServer]]; + [self readDocumentForRef:doc + options:[[FIRGetOptions alloc] initWithSource:FIRGetSourceServer]]; XCTAssertTrue(result.exists); XCTAssertFalse(result.metadata.fromCache); XCTAssertFalse(result.metadata.hasPendingWrites); @@ -284,7 +287,7 @@ - (void)testGetCollectionWhileOnlineServerOnly { // initialData. FIRQuerySnapshot *result = [self readDocumentSetForRef:col - options:[[FIRGetOptions alloc] initWithSource:FIRSourceServer]]; + options:[[FIRGetOptions alloc] initWithSource:FIRGetSourceServer]]; XCTAssertFalse(result.metadata.fromCache); XCTAssertFalse(result.metadata.hasPendingWrites); XCTAssertEqualObjects(FIRQuerySnapshotGetData(result), (@[ @@ -311,7 +314,7 @@ - (void)testGetDocumentWhileOfflineServerOnly { // attempt to get doc and ensure it cannot be retreived XCTestExpectation *failedGetDocCompletion = [self expectationWithDescription:@"failedGetDoc"]; - [doc getDocumentWithOptions:[[FIRGetOptions alloc] initWithSource:FIRSourceServer] + [doc getDocumentWithOptions:[[FIRGetOptions alloc] initWithSource:FIRGetSourceServer] completion:^(FIRDocumentSnapshot *snapshot, NSError *error) { XCTAssertNotNil(error); XCTAssertEqualObjects(error.domain, FIRFirestoreErrorDomain); @@ -337,7 +340,7 @@ - (void)testGetCollectionWhileOfflineServerOnly { // attempt to get docs and ensure they cannot be retreived XCTestExpectation *failedGetDocsCompletion = [self expectationWithDescription:@"failedGetDocs"]; - [col getDocumentsWithOptions:[[FIRGetOptions alloc] initWithSource:FIRSourceServer] + [col getDocumentsWithOptions:[[FIRGetOptions alloc] initWithSource:FIRGetSourceServer] completion:^(FIRQuerySnapshot *snapshot, NSError *error) { XCTAssertNotNil(error); XCTAssertEqualObjects(error.domain, FIRFirestoreErrorDomain); @@ -377,15 +380,16 @@ - (void)testGetDocumentWhileOfflineWithDifferentGetOptions { // get doc (from cache) and ensure it exists, *is* from the cache, and // matches the newData. FIRDocumentSnapshot *result = - [self readDocumentForRef:doc options:[[FIRGetOptions alloc] initWithSource:FIRSourceCache]]; + [self readDocumentForRef:doc + options:[[FIRGetOptions alloc] initWithSource:FIRGetSourceCache]]; XCTAssertTrue(result.exists); XCTAssertTrue(result.metadata.fromCache); XCTAssertTrue(result.metadata.hasPendingWrites); XCTAssertEqualObjects(result.data, newData); // attempt to get doc (with default get options) - result = - [self readDocumentForRef:doc options:[[FIRGetOptions alloc] initWithSource:FIRSourceDefault]]; + result = [self readDocumentForRef:doc + options:[[FIRGetOptions alloc] initWithSource:FIRGetSourceDefault]]; XCTAssertTrue(result.exists); XCTAssertTrue(result.metadata.fromCache); XCTAssertTrue(result.metadata.hasPendingWrites); @@ -393,7 +397,7 @@ - (void)testGetDocumentWhileOfflineWithDifferentGetOptions { // attempt to get doc (from the server) and ensure it cannot be retreived XCTestExpectation *failedGetDocCompletion = [self expectationWithDescription:@"failedGetDoc"]; - [doc getDocumentWithOptions:[[FIRGetOptions alloc] initWithSource:FIRSourceServer] + [doc getDocumentWithOptions:[[FIRGetOptions alloc] initWithSource:FIRGetSourceServer] completion:^(FIRDocumentSnapshot *snapshot, NSError *error) { XCTAssertNotNil(error); XCTAssertEqualObjects(error.domain, FIRFirestoreErrorDomain); @@ -437,7 +441,7 @@ - (void)testGetCollectionWhileOfflineWithDifferentGetOptions { // matches the updated data. FIRQuerySnapshot *result = [self readDocumentSetForRef:col - options:[[FIRGetOptions alloc] initWithSource:FIRSourceCache]]; + options:[[FIRGetOptions alloc] initWithSource:FIRGetSourceCache]]; XCTAssertTrue(result.metadata.fromCache); XCTAssertTrue(result.metadata.hasPendingWrites); XCTAssertEqualObjects(FIRQuerySnapshotGetData(result), (@[ @@ -454,7 +458,7 @@ - (void)testGetCollectionWhileOfflineWithDifferentGetOptions { // attempt to get docs (with default get options) result = [self readDocumentSetForRef:col - options:[[FIRGetOptions alloc] initWithSource:FIRSourceDefault]]; + options:[[FIRGetOptions alloc] initWithSource:FIRGetSourceDefault]]; XCTAssertTrue(result.metadata.fromCache); XCTAssertEqualObjects(FIRQuerySnapshotGetData(result), (@[ @{@"key1" : @"value1"}, @{@"key2" : @"value2", @"key2b" : @"value2b"}, @@ -470,7 +474,7 @@ - (void)testGetCollectionWhileOfflineWithDifferentGetOptions { // attempt to get docs (from the server) and ensure they cannot be retreived XCTestExpectation *failedGetDocsCompletion = [self expectationWithDescription:@"failedGetDocs"]; - [col getDocumentsWithOptions:[[FIRGetOptions alloc] initWithSource:FIRSourceServer] + [col getDocumentsWithOptions:[[FIRGetOptions alloc] initWithSource:FIRGetSourceServer] completion:^(FIRQuerySnapshot *snapshot, NSError *error) { XCTAssertNotNil(error); XCTAssertEqualObjects(error.domain, FIRFirestoreErrorDomain); @@ -543,7 +547,7 @@ - (void)testGetNonExistingDocWhileOnlineCacheOnly { // certain documents *don't* exist. XCTestExpectation *getNonExistingDocCompletion = [self expectationWithDescription:@"getNonExistingDoc"]; - [doc getDocumentWithOptions:[[FIRGetOptions alloc] initWithSource:FIRSourceCache] + [doc getDocumentWithOptions:[[FIRGetOptions alloc] initWithSource:FIRGetSourceCache] completion:^(FIRDocumentSnapshot *snapshot, NSError *error) { XCTAssertNotNil(error); XCTAssertEqualObjects(error.domain, FIRFirestoreErrorDomain); @@ -559,7 +563,7 @@ - (void)testGetNonExistingCollectionWhileOnlineCacheOnly { // get collection and ensure it's empty and that it *is* from the cache. FIRQuerySnapshot *snapshot = [self readDocumentSetForRef:col - options:[[FIRGetOptions alloc] initWithSource:FIRSourceCache]]; + options:[[FIRGetOptions alloc] initWithSource:FIRGetSourceCache]]; XCTAssertEqual(snapshot.count, 0); XCTAssertEqual(snapshot.documentChanges.count, 0); XCTAssertTrue(snapshot.metadata.fromCache); @@ -577,7 +581,7 @@ - (void)testGetNonExistingDocWhileOfflineCacheOnly { // certain documents *don't* exist. XCTestExpectation *getNonExistingDocCompletion = [self expectationWithDescription:@"getNonExistingDoc"]; - [doc getDocumentWithOptions:[[FIRGetOptions alloc] initWithSource:FIRSourceCache] + [doc getDocumentWithOptions:[[FIRGetOptions alloc] initWithSource:FIRGetSourceCache] completion:^(FIRDocumentSnapshot *snapshot, NSError *error) { XCTAssertNotNil(error); XCTAssertEqualObjects(error.domain, FIRFirestoreErrorDomain); @@ -596,7 +600,7 @@ - (void)testGetNonExistingCollectionWhileOfflineCacheOnly { // get collection and ensure it's empty and that it *is* from the cache. FIRQuerySnapshot *snapshot = [self readDocumentSetForRef:col - options:[[FIRGetOptions alloc] initWithSource:FIRSourceCache]]; + options:[[FIRGetOptions alloc] initWithSource:FIRGetSourceCache]]; XCTAssertEqual(snapshot.count, 0); XCTAssertEqual(snapshot.documentChanges.count, 0); XCTAssertTrue(snapshot.metadata.fromCache); @@ -608,7 +612,8 @@ - (void)testGetNonExistingDocWhileOnlineServerOnly { // get doc and ensure that it does not exist and is *not* from the cache. FIRDocumentSnapshot *snapshot = - [self readDocumentForRef:doc options:[[FIRGetOptions alloc] initWithSource:FIRSourceServer]]; + [self readDocumentForRef:doc + options:[[FIRGetOptions alloc] initWithSource:FIRGetSourceServer]]; XCTAssertFalse(snapshot.exists); XCTAssertFalse(snapshot.metadata.fromCache); XCTAssertFalse(snapshot.metadata.hasPendingWrites); @@ -620,7 +625,7 @@ - (void)testGetNonExistingCollectionWhileOnlineServerOnly { // get collection and ensure that it's empty and that it's *not* from the cache. FIRQuerySnapshot *snapshot = [self readDocumentSetForRef:col - options:[[FIRGetOptions alloc] initWithSource:FIRSourceServer]]; + options:[[FIRGetOptions alloc] initWithSource:FIRGetSourceServer]]; XCTAssertEqual(snapshot.count, 0); XCTAssertEqual(snapshot.documentChanges.count, 0); XCTAssertFalse(snapshot.metadata.fromCache); @@ -638,7 +643,7 @@ - (void)testGetNonExistingDocWhileOfflineServerOnly { // certain documents *don't* exist. XCTestExpectation *getNonExistingDocCompletion = [self expectationWithDescription:@"getNonExistingDoc"]; - [doc getDocumentWithOptions:[[FIRGetOptions alloc] initWithSource:FIRSourceServer] + [doc getDocumentWithOptions:[[FIRGetOptions alloc] initWithSource:FIRGetSourceServer] completion:^(FIRDocumentSnapshot *snapshot, NSError *error) { XCTAssertNotNil(error); XCTAssertEqualObjects(error.domain, FIRFirestoreErrorDomain); @@ -656,7 +661,7 @@ - (void)testGetNonExistingCollectionWhileOfflineServerOnly { // attempt to get collection and ensure that it cannot be retreived XCTestExpectation *failedGetDocsCompletion = [self expectationWithDescription:@"failedGetDocs"]; - [col getDocumentsWithOptions:[[FIRGetOptions alloc] initWithSource:FIRSourceServer] + [col getDocumentsWithOptions:[[FIRGetOptions alloc] initWithSource:FIRGetSourceServer] completion:^(FIRQuerySnapshot *snapshot, NSError *error) { XCTAssertNotNil(error); XCTAssertEqualObjects(error.domain, FIRFirestoreErrorDomain); diff --git a/Firestore/Source/API/FIRDocumentReference.m b/Firestore/Source/API/FIRDocumentReference.m index 87db991ba06..464217a4fa3 100644 --- a/Firestore/Source/API/FIRDocumentReference.m +++ b/Firestore/Source/API/FIRDocumentReference.m @@ -216,7 +216,7 @@ - (void)getDocumentWithCompletion:(void (^)(FIRDocumentSnapshot *_Nullable docum - (void)getDocumentWithOptions:(FIRGetOptions *)options completion:(void (^)(FIRDocumentSnapshot *_Nullable document, NSError *_Nullable error))completion { - if (options.source == FIRSourceCache) { + if (options.source == FIRGetSourceCache) { [self.firestore.client getDocumentFromLocalCache:self completion:completion]; return; } @@ -256,17 +256,17 @@ - (void)getDocumentWithOptions:(FIRGetOptions *)options @"Failed to get document because the client is offline.", }]); } else if (snapshot.exists && snapshot.metadata.fromCache && - options.source == FIRSourceServer) { - completion(nil, - [NSError errorWithDomain:FIRFirestoreErrorDomain - code:FIRFirestoreErrorCodeUnavailable - userInfo:@{ - NSLocalizedDescriptionKey : - @"Failed to get document from server. (However, this " - @"document does exist in the local cache. Run again " - @"without setting FIRSourceServer in the FIRGetOptions to " - @"retrieve the cached document.)" - }]); + options.source == FIRGetSourceServer) { + completion( + nil, [NSError errorWithDomain:FIRFirestoreErrorDomain + code:FIRFirestoreErrorCodeUnavailable + userInfo:@{ + NSLocalizedDescriptionKey : + @"Failed to get document from server. (However, this " + @"document does exist in the local cache. Run again " + @"without setting FIRGetSourceServer in the FIRGetOptions to " + @"retrieve the cached document.)" + }]); } else { completion(snapshot, nil); } diff --git a/Firestore/Source/API/FIRGetOptions+Internal.h b/Firestore/Source/API/FIRGetOptions+Internal.h index ad5c4b3e9fe..1e8a479c837 100644 --- a/Firestore/Source/API/FIRGetOptions+Internal.h +++ b/Firestore/Source/API/FIRGetOptions+Internal.h @@ -21,7 +21,7 @@ NS_ASSUME_NONNULL_BEGIN @interface FIRGetOptions () /** Where getDocument[s] calls should get their data from. */ -@property(nonatomic, readonly, getter=source) FIRSource source; +@property(nonatomic, readonly, getter=source) FIRGetSource source; @end diff --git a/Firestore/Source/API/FIRGetOptions.m b/Firestore/Source/API/FIRGetOptions.m index 774b0972fc9..b7eb5e2ece9 100644 --- a/Firestore/Source/API/FIRGetOptions.m +++ b/Firestore/Source/API/FIRGetOptions.m @@ -21,10 +21,10 @@ @implementation FIRGetOptions + (FIRGetOptions *)defaultOptions { - return [[FIRGetOptions alloc] initWithSource:FIRSourceDefault]; + return [[FIRGetOptions alloc] initWithSource:FIRGetSourceDefault]; } -- (instancetype)initWithSource:(FIRSource)source { +- (instancetype)initWithSource:(FIRGetSource)source { if (self = [super init]) { _source = source; } diff --git a/Firestore/Source/API/FIRQuery.m b/Firestore/Source/API/FIRQuery.m index 31624b1257d..06fa5e8ae3e 100644 --- a/Firestore/Source/API/FIRQuery.m +++ b/Firestore/Source/API/FIRQuery.m @@ -138,7 +138,7 @@ - (void)getDocumentsWithCompletion:(void (^)(FIRQuerySnapshot *_Nullable snapsho - (void)getDocumentsWithOptions:(FIRGetOptions *)options completion:(void (^)(FIRQuerySnapshot *_Nullable snapshot, NSError *_Nullable error))completion { - if (options.source == FIRSourceCache) { + if (options.source == FIRGetSourceCache) { [self.firestore.client getDocumentsFromLocalCache:self completion:completion]; return; } @@ -161,17 +161,17 @@ - (void)getDocumentsWithOptions:(FIRGetOptions *)options dispatch_semaphore_wait(registered, DISPATCH_TIME_FOREVER); [listenerRegistration remove]; - if (snapshot.metadata.fromCache && options.source == FIRSourceServer) { - completion(nil, - [NSError errorWithDomain:FIRFirestoreErrorDomain - code:FIRFirestoreErrorCodeUnavailable - userInfo:@{ - NSLocalizedDescriptionKey : - @"Failed to get documents from server. (However, these " - @"documents may exist in the local cache. Run again " - @"without setting FIRSourceServer in the FIRGetOptions to " - @"retrieve the cached documents.)" - }]); + if (snapshot.metadata.fromCache && options.source == FIRGetSourceServer) { + completion( + nil, [NSError errorWithDomain:FIRFirestoreErrorDomain + code:FIRFirestoreErrorCodeUnavailable + userInfo:@{ + NSLocalizedDescriptionKey : + @"Failed to get documents from server. (However, these " + @"documents may exist in the local cache. Run again " + @"without setting FIRGetSourceServer in the FIRGetOptions to " + @"retrieve the cached documents.)" + }]); } else { completion(snapshot, nil); } diff --git a/Firestore/Source/Core/FSTFirestoreClient.m b/Firestore/Source/Core/FSTFirestoreClient.m index 6ac0ec3f1e0..8656ea05069 100644 --- a/Firestore/Source/Core/FSTFirestoreClient.m +++ b/Firestore/Source/Core/FSTFirestoreClient.m @@ -271,16 +271,17 @@ - (void)getDocumentFromLocalCache:(FIRDocumentReference *)doc fromCache:YES], nil); } else { - completion(nil, - [NSError errorWithDomain:FIRFirestoreErrorDomain - code:FIRFirestoreErrorCodeUnavailable - userInfo:@{ - NSLocalizedDescriptionKey : - @"Failed to get document from cache. (However, this " - @"document may exist on the server. Run again without " - @"setting FIRSourceCache in the FIRGetOptions to attempt to " - @"retrieve the document from the server.)", - }]); + completion( + nil, + [NSError errorWithDomain:FIRFirestoreErrorDomain + code:FIRFirestoreErrorCodeUnavailable + userInfo:@{ + NSLocalizedDescriptionKey : + @"Failed to get document from cache. (However, this " + @"document may exist on the server. Run again without " + @"setting FIRGetSourceCache in the FIRGetOptions to attempt to " + @"retrieve the document from the server.)", + }]); } }]; } @@ -305,7 +306,7 @@ - (void)getDocumentsFromLocalCache:(FIRQuery *)query fromCache:snapshot.fromCache]; completion([FIRQuerySnapshot snapshotWithFirestore:query.firestore - originalQuery:query + originalQuery:query.query snapshot:snapshot metadata:metadata], nil); diff --git a/Firestore/Source/Public/FIRGetOptions.h b/Firestore/Source/Public/FIRGetOptions.h index 935345cdbe5..0b7412191d9 100644 --- a/Firestore/Source/Public/FIRGetOptions.h +++ b/Firestore/Source/Public/FIRGetOptions.h @@ -31,7 +31,7 @@ NS_SWIFT_NAME(GetOptions) /** * Returns the default options. * - * Equiavlent to `[[FIRGetOptions alloc] initWithSource:FIRSourceDefault]` in + * Equiavlent to `[[FIRGetOptions alloc] initWithSource:FIRGetSourceDefault]` in * objective-c. */ + (FIRGetOptions *)defaultOptions NS_SWIFT_NAME(defaultOptions()); @@ -39,30 +39,30 @@ NS_SWIFT_NAME(GetOptions) /** * Describes whether we should get from server or cache. * - * Setting the FIRGetOption source to FIRSourceDefault, if online, causes + * Setting the FIRGetOption source to FIRGetSourceDefault, if online, causes * Firestore to try to give a consistent (server-retrieved) snapshot, or else * revert to the cache to provide a value. * - * FIRSourceServer causes Firestore to avoid the cache (generating an error if - * a value cannot be retrieved from the server). The cache will be updated if - * the RPC succeeds. Latency compensation still occurs (implying that if the + * FIRGetSourceServer causes Firestore to avoid the cache (generating an error + * if a value cannot be retrieved from the server). The cache will be updated + * if the RPC succeeds. Latency compensation still occurs (implying that if the * cache is more up to date, then it's values will be merged into the results). * - * FIRSourceCache causes Firestore to immediately return a value from the + * FIRGetSourceCache causes Firestore to immediately return a value from the * cache, ignoring the server completely (implying that the returned value may * be stale with respect to the value on the server.) For a single document, * the get will fail if the document doesn't exist. */ -typedef NS_ENUM(NSUInteger, FIRSource) { - FIRSourceDefault, - FIRSourceServer, - FIRSourceCache -} NS_SWIFT_NAME(Source); +typedef NS_ENUM(NSUInteger, FIRGetSource) { + FIRGetSourceDefault, + FIRGetSourceServer, + FIRGetSourceCache +} NS_SWIFT_NAME(GetSource); /** * Initializes the get options with the specified source. */ -- (instancetype)initWithSource:(FIRSource)source NS_SWIFT_NAME(init(source:)); +- (instancetype)initWithSource:(FIRGetSource)source NS_SWIFT_NAME(init(source:)); @end From 893e56ad052d7080ce0f67bac7e441885818b9a3 Mon Sep 17 00:00:00 2001 From: Rich Gowman Date: Thu, 18 Jan 2018 18:14:22 -0500 Subject: [PATCH 12/12] Review feedback Swift api limbo error message --- Firestore/Example/SwiftBuildTest/main.swift | 6 +++--- Firestore/Source/Core/FSTFirestoreClient.m | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Firestore/Example/SwiftBuildTest/main.swift b/Firestore/Example/SwiftBuildTest/main.swift index eabca1c4973..2d77669f265 100644 --- a/Firestore/Example/SwiftBuildTest/main.swift +++ b/Firestore/Example/SwiftBuildTest/main.swift @@ -228,11 +228,11 @@ func readDocument(at docRef: DocumentReference) { func readDocumentWithOptions(at docRef: DocumentReference) { docRef.getDocument(options:GetOptions.defaultOptions()) { document, error in } - docRef.getDocument(options:GetOptions.init(source:GetSource.default)) { document, error in + docRef.getDocument(options:GetOptions(source:GetSource.default)) { document, error in } - docRef.getDocument(options:GetOptions.init(source:GetSource.server)) { document, error in + docRef.getDocument(options:GetOptions(source:.server)) { document, error in } - docRef.getDocument(options:GetOptions.init(source:GetSource.cache)) { document, error in + docRef.getDocument(options:GetOptions(source:GetSource.cache)) { document, error in } } diff --git a/Firestore/Source/Core/FSTFirestoreClient.m b/Firestore/Source/Core/FSTFirestoreClient.m index 8656ea05069..6e076c4ec7f 100644 --- a/Firestore/Source/Core/FSTFirestoreClient.m +++ b/Firestore/Source/Core/FSTFirestoreClient.m @@ -298,7 +298,7 @@ - (void)getDocumentsFromLocalCache:(FIRQuery *)query FSTViewDocumentChanges *viewDocChanges = [view computeChangesWithDocuments:docs]; FSTViewChange *viewChange = [view applyChangesToDocuments:viewDocChanges]; FSTAssert(viewChange.limboChanges.count == 0, - @"View returned limbo docs before target ack from the server."); + @"View returned limbo documents during local-only query execution."); FSTViewSnapshot *snapshot = viewChange.snapshot; FIRSnapshotMetadata *metadata =