From 9e815620e9f7f43b42e03db4e5118d7ad03ddee7 Mon Sep 17 00:00:00 2001 From: zxu Date: Wed, 14 Mar 2018 08:57:31 -0400 Subject: grand PR to port the remaining paths (FieldPath and ResourcePath). (#865) * naively remove FSTPath import and source/test files. * port FieldPath, part I * port FieldPath, part II * port ResourcePath, part I * port ResourcePath, part II * the grand commit to fix build errors * use testutil:: helper instead of those from FSTHelpers * fix test and lint * use c_str in errmsg directly * fix * fix * make code clean * fix integration test I missed * fix to avoid naming collision in preprocessor * address changes * address changes * address changes * fix: fieldMask are actually shared with different context. * address changes * address changes --- .../Example/Firestore.xcodeproj/project.pbxproj | 4 - .../Tests/API/FIRCollectionReferenceTests.mm | 6 +- .../Example/Tests/API/FIRDocumentReferenceTests.mm | 6 +- Firestore/Example/Tests/API/FIRFieldPathTests.mm | 11 +- .../Example/Tests/API/FIRQuerySnapshotTests.mm | 2 - Firestore/Example/Tests/API/FIRQueryTests.mm | 9 +- Firestore/Example/Tests/API/FSTAPIHelpers.h | 4 +- Firestore/Example/Tests/API/FSTAPIHelpers.mm | 34 +- .../Example/Tests/Core/FSTEventManagerTests.mm | 10 +- .../Example/Tests/Core/FSTQueryListenerTests.mm | 24 +- Firestore/Example/Tests/Core/FSTQueryTests.mm | 256 ++++++------- .../Example/Tests/Core/FSTViewSnapshotTest.mm | 3 +- Firestore/Example/Tests/Core/FSTViewTests.mm | 1 - .../Tests/Integration/API/FIRValidationTests.mm | 2 +- .../Example/Tests/Integration/FSTDatastoreTests.mm | 1 - .../Example/Tests/Local/FSTLevelDBKeyTests.mm | 13 +- .../Example/Tests/Local/FSTLocalSerializerTests.mm | 7 +- .../Example/Tests/Local/FSTLocalStoreTests.mm | 37 +- .../Example/Tests/Local/FSTMutationQueueTests.mm | 10 +- .../Example/Tests/Local/FSTQueryCacheTests.mm | 22 +- .../Tests/Local/FSTRemoteDocumentCacheTests.mm | 2 +- .../Example/Tests/Model/FSTDocumentSetTests.mm | 2 +- Firestore/Example/Tests/Model/FSTDocumentTests.mm | 9 +- .../Example/Tests/Model/FSTFieldValueTests.mm | 43 +-- Firestore/Example/Tests/Model/FSTMutationTests.mm | 21 +- Firestore/Example/Tests/Model/FSTPathTests.mm | 224 ------------ .../Example/Tests/Remote/FSTSerializerBetaTests.mm | 33 +- Firestore/Example/Tests/SpecTests/FSTSpecTests.mm | 16 +- Firestore/Example/Tests/Util/FSTHelpers.h | 62 ++-- Firestore/Example/Tests/Util/FSTHelpers.mm | 71 ++-- .../Source/API/FIRCollectionReference+Internal.h | 7 +- Firestore/Source/API/FIRCollectionReference.mm | 20 +- .../Source/API/FIRDocumentReference+Internal.h | 6 +- Firestore/Source/API/FIRDocumentReference.mm | 22 +- Firestore/Source/API/FIRDocumentSnapshot.mm | 12 +- Firestore/Source/API/FIRFieldPath+Internal.h | 8 +- Firestore/Source/API/FIRFieldPath.mm | 40 ++- Firestore/Source/API/FIRFirestore.mm | 11 +- Firestore/Source/API/FIRQuery.mm | 49 ++- Firestore/Source/API/FSTUserDataConverter.mm | 160 +++++---- Firestore/Source/Core/FSTFirestoreClient.mm | 2 +- Firestore/Source/Core/FSTQuery.mm | 28 +- Firestore/Source/Core/FSTSyncEngine.mm | 1 - Firestore/Source/Local/FSTLevelDB.mm | 3 +- Firestore/Source/Local/FSTLevelDBKey.h | 21 +- Firestore/Source/Local/FSTLevelDBKey.mm | 26 +- Firestore/Source/Local/FSTLevelDBMutationQueue.mm | 17 +- Firestore/Source/Local/FSTLevelDBQueryCache.mm | 4 +- .../Source/Local/FSTLevelDBRemoteDocumentCache.mm | 4 +- Firestore/Source/Local/FSTLocalDocumentsView.mm | 13 +- Firestore/Source/Local/FSTMemoryMutationQueue.mm | 1 - .../Source/Local/FSTMemoryRemoteDocumentCache.mm | 1 - Firestore/Source/Model/FSTDocument.h | 5 +- Firestore/Source/Model/FSTDocument.mm | 9 +- Firestore/Source/Model/FSTFieldValue.h | 9 +- Firestore/Source/Model/FSTFieldValue.mm | 31 +- Firestore/Source/Model/FSTMutation.h | 14 +- Firestore/Source/Model/FSTMutation.mm | 45 ++- Firestore/Source/Model/FSTPath.h | 167 --------- Firestore/Source/Model/FSTPath.mm | 399 --------------------- Firestore/Source/Remote/FSTDatastore.mm | 12 +- Firestore/Source/Remote/FSTRemoteStore.mm | 4 +- Firestore/Source/Remote/FSTSerializerBeta.mm | 175 +++++---- .../core/src/firebase/firestore/model/field_path.h | 10 +- .../src/firebase/firestore/model/resource_path.h | 5 - .../src/firebase/firestore/util/string_apple.h | 8 + 66 files changed, 787 insertions(+), 1507 deletions(-) delete mode 100644 Firestore/Example/Tests/Model/FSTPathTests.mm delete mode 100644 Firestore/Source/Model/FSTPath.h delete mode 100644 Firestore/Source/Model/FSTPath.mm diff --git a/Firestore/Example/Firestore.xcodeproj/project.pbxproj b/Firestore/Example/Firestore.xcodeproj/project.pbxproj index 92b4b7b..3b1c328 100644 --- a/Firestore/Example/Firestore.xcodeproj/project.pbxproj +++ b/Firestore/Example/Firestore.xcodeproj/project.pbxproj @@ -98,7 +98,6 @@ 5492E0B12021552D00B64F25 /* FSTRemoteDocumentCacheTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E09C2021552D00B64F25 /* FSTRemoteDocumentCacheTests.mm */; }; 5492E0B92021555100B64F25 /* FSTDocumentKeyTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E0B22021555000B64F25 /* FSTDocumentKeyTests.mm */; }; 5492E0BA2021555100B64F25 /* FSTDocumentSetTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E0B32021555100B64F25 /* FSTDocumentSetTests.mm */; }; - 5492E0BC2021555100B64F25 /* FSTPathTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E0B52021555100B64F25 /* FSTPathTests.mm */; }; 5492E0BD2021555100B64F25 /* FSTDocumentTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E0B62021555100B64F25 /* FSTDocumentTests.mm */; }; 5492E0BE2021555100B64F25 /* FSTMutationTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E0B72021555100B64F25 /* FSTMutationTests.mm */; }; 5492E0BF2021555100B64F25 /* FSTFieldValueTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E0B82021555100B64F25 /* FSTFieldValueTests.mm */; }; @@ -313,7 +312,6 @@ 5492E09C2021552D00B64F25 /* FSTRemoteDocumentCacheTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FSTRemoteDocumentCacheTests.mm; sourceTree = ""; }; 5492E0B22021555000B64F25 /* FSTDocumentKeyTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FSTDocumentKeyTests.mm; sourceTree = ""; }; 5492E0B32021555100B64F25 /* FSTDocumentSetTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FSTDocumentSetTests.mm; sourceTree = ""; }; - 5492E0B52021555100B64F25 /* FSTPathTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FSTPathTests.mm; sourceTree = ""; }; 5492E0B62021555100B64F25 /* FSTDocumentTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FSTDocumentTests.mm; sourceTree = ""; }; 5492E0B72021555100B64F25 /* FSTMutationTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FSTMutationTests.mm; sourceTree = ""; }; 5492E0B82021555100B64F25 /* FSTFieldValueTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FSTFieldValueTests.mm; sourceTree = ""; }; @@ -758,7 +756,6 @@ 5492E0B62021555100B64F25 /* FSTDocumentTests.mm */, 5492E0B82021555100B64F25 /* FSTFieldValueTests.mm */, 5492E0B72021555100B64F25 /* FSTMutationTests.mm */, - 5492E0B52021555100B64F25 /* FSTPathTests.mm */, ); path = Model; sourceTree = ""; @@ -1466,7 +1463,6 @@ B686F2B22025000D0028D6BE /* resource_path_test.cc in Sources */, 5492E0CA2021557E00B64F25 /* FSTWatchChangeTests.mm in Sources */, 5492E063202154B900B64F25 /* FSTViewSnapshotTest.mm in Sources */, - 5492E0BC2021555100B64F25 /* FSTPathTests.mm in Sources */, 5492E0B02021552D00B64F25 /* FSTWriteGroupTests.mm in Sources */, 5492E058202154AB00B64F25 /* FSTAPIHelpers.mm in Sources */, AB380CFB2019388600D97691 /* target_id_generator_test.cc in Sources */, diff --git a/Firestore/Example/Tests/API/FIRCollectionReferenceTests.mm b/Firestore/Example/Tests/API/FIRCollectionReferenceTests.mm index 547078f..cb99d24 100644 --- a/Firestore/Example/Tests/API/FIRCollectionReferenceTests.mm +++ b/Firestore/Example/Tests/API/FIRCollectionReferenceTests.mm @@ -28,9 +28,9 @@ NS_ASSUME_NONNULL_BEGIN @implementation FIRCollectionReferenceTests - (void)testEquals { - FIRCollectionReference *referenceFoo = FSTTestCollectionRef(@"foo"); - FIRCollectionReference *referenceFooDup = FSTTestCollectionRef(@"foo"); - FIRCollectionReference *referenceBar = FSTTestCollectionRef(@"bar"); + FIRCollectionReference *referenceFoo = FSTTestCollectionRef("foo"); + FIRCollectionReference *referenceFooDup = FSTTestCollectionRef("foo"); + FIRCollectionReference *referenceBar = FSTTestCollectionRef("bar"); XCTAssertEqualObjects(referenceFoo, referenceFooDup); XCTAssertNotEqualObjects(referenceFoo, referenceBar); diff --git a/Firestore/Example/Tests/API/FIRDocumentReferenceTests.mm b/Firestore/Example/Tests/API/FIRDocumentReferenceTests.mm index cc2b431..4124cd0 100644 --- a/Firestore/Example/Tests/API/FIRDocumentReferenceTests.mm +++ b/Firestore/Example/Tests/API/FIRDocumentReferenceTests.mm @@ -28,9 +28,9 @@ NS_ASSUME_NONNULL_BEGIN @implementation FIRDocumentReferenceTests - (void)testEquals { - FIRDocumentReference *referenceFoo = FSTTestDocRef(@"rooms/foo"); - FIRDocumentReference *referenceFooDup = FSTTestDocRef(@"rooms/foo"); - FIRDocumentReference *referenceBar = FSTTestDocRef(@"rooms/bar"); + FIRDocumentReference *referenceFoo = FSTTestDocRef("rooms/foo"); + FIRDocumentReference *referenceFooDup = FSTTestDocRef("rooms/foo"); + FIRDocumentReference *referenceBar = FSTTestDocRef("rooms/bar"); XCTAssertEqualObjects(referenceFoo, referenceFooDup); XCTAssertNotEqualObjects(referenceFoo, referenceBar); diff --git a/Firestore/Example/Tests/API/FIRFieldPathTests.mm b/Firestore/Example/Tests/API/FIRFieldPathTests.mm index 679ea89..50d37c1 100644 --- a/Firestore/Example/Tests/API/FIRFieldPathTests.mm +++ b/Firestore/Example/Tests/API/FIRFieldPathTests.mm @@ -19,10 +19,13 @@ #import #import "Firestore/Source/API/FIRFieldPath+Internal.h" -#import "Firestore/Source/Model/FSTPath.h" #import "Firestore/Example/Tests/Util/FSTHelpers.h" +#include "Firestore/core/test/firebase/firestore/testutil/testutil.h" + +namespace testutil = firebase::firestore::testutil; + NS_ASSUME_NONNULL_BEGIN @interface FIRFieldPathTests : XCTestCase @@ -31,9 +34,9 @@ NS_ASSUME_NONNULL_BEGIN @implementation FIRFieldPathTests - (void)testEquals { - FIRFieldPath *foo = [[FIRFieldPath alloc] initPrivate:FSTTestFieldPath(@"foo.ooo.oooo")]; - FIRFieldPath *fooDup = [[FIRFieldPath alloc] initPrivate:FSTTestFieldPath(@"foo.ooo.oooo")]; - FIRFieldPath *bar = [[FIRFieldPath alloc] initPrivate:FSTTestFieldPath(@"baa.aaa.aaar")]; + FIRFieldPath *foo = [[FIRFieldPath alloc] initPrivate:testutil::Field("foo.ooo.oooo")]; + FIRFieldPath *fooDup = [[FIRFieldPath alloc] initPrivate:testutil::Field("foo.ooo.oooo")]; + FIRFieldPath *bar = [[FIRFieldPath alloc] initPrivate:testutil::Field("baa.aaa.aaar")]; XCTAssertEqualObjects(foo, fooDup); XCTAssertNotEqualObjects(foo, bar); diff --git a/Firestore/Example/Tests/API/FIRQuerySnapshotTests.mm b/Firestore/Example/Tests/API/FIRQuerySnapshotTests.mm index 067425a..bb8110b 100644 --- a/Firestore/Example/Tests/API/FIRQuerySnapshotTests.mm +++ b/Firestore/Example/Tests/API/FIRQuerySnapshotTests.mm @@ -18,8 +18,6 @@ #import -#import "Firestore/Source/Model/FSTPath.h" - #import "Firestore/Example/Tests/API/FSTAPIHelpers.h" NS_ASSUME_NONNULL_BEGIN diff --git a/Firestore/Example/Tests/API/FIRQueryTests.mm b/Firestore/Example/Tests/API/FIRQueryTests.mm index 83f90be..c02c92c 100644 --- a/Firestore/Example/Tests/API/FIRQueryTests.mm +++ b/Firestore/Example/Tests/API/FIRQueryTests.mm @@ -20,7 +20,6 @@ #import "Firestore/Source/API/FIRQuery+Internal.h" #import "Firestore/Source/Core/FSTQuery.h" -#import "Firestore/Source/Model/FSTPath.h" #import "Firestore/Example/Tests/API/FSTAPIHelpers.h" @@ -33,9 +32,9 @@ NS_ASSUME_NONNULL_BEGIN - (void)testEquals { FIRFirestore *firestore = FSTTestFirestore(); - FIRQuery *queryFoo = [FIRQuery referenceWithQuery:FSTTestQuery(@"foo") firestore:firestore]; - FIRQuery *queryFooDup = [FIRQuery referenceWithQuery:FSTTestQuery(@"foo") firestore:firestore]; - FIRQuery *queryBar = [FIRQuery referenceWithQuery:FSTTestQuery(@"bar") firestore:firestore]; + FIRQuery *queryFoo = [FIRQuery referenceWithQuery:FSTTestQuery("foo") firestore:firestore]; + FIRQuery *queryFooDup = [FIRQuery referenceWithQuery:FSTTestQuery("foo") firestore:firestore]; + FIRQuery *queryBar = [FIRQuery referenceWithQuery:FSTTestQuery("bar") firestore:firestore]; XCTAssertEqualObjects(queryFoo, queryFooDup); XCTAssertNotEqualObjects(queryFoo, queryBar); XCTAssertEqualObjects([queryFoo queryWhereField:@"f" isEqualTo:@1], @@ -53,7 +52,7 @@ NS_ASSUME_NONNULL_BEGIN - (void)testFilteringWithPredicate { FIRFirestore *firestore = FSTTestFirestore(); - FIRQuery *query = [FIRQuery referenceWithQuery:FSTTestQuery(@"foo") firestore:firestore]; + FIRQuery *query = [FIRQuery referenceWithQuery:FSTTestQuery("foo") firestore:firestore]; FIRQuery *query1 = [query queryWhereField:@"f" isLessThanOrEqualTo:@1]; FIRQuery *query2 = [query queryFilteredUsingPredicate:[NSPredicate predicateWithFormat:@"f<=1"]]; FIRQuery *query3 = diff --git a/Firestore/Example/Tests/API/FSTAPIHelpers.h b/Firestore/Example/Tests/API/FSTAPIHelpers.h index 0729af0..4edd7d5 100644 --- a/Firestore/Example/Tests/API/FSTAPIHelpers.h +++ b/Firestore/Example/Tests/API/FSTAPIHelpers.h @@ -41,10 +41,10 @@ FIRDocumentSnapshot *FSTTestDocSnapshot(NSString *path, BOOL fromCache); /** A convenience method for creating a collection reference from a path string. */ -FIRCollectionReference *FSTTestCollectionRef(NSString *path); +FIRCollectionReference *FSTTestCollectionRef(const absl::string_view path); /** A convenience method for creating a document reference from a path string. */ -FIRDocumentReference *FSTTestDocRef(NSString *path); +FIRDocumentReference *FSTTestDocRef(const absl::string_view path); /** * A convenience method for creating a particular query snapshot for tests. diff --git a/Firestore/Example/Tests/API/FSTAPIHelpers.mm b/Firestore/Example/Tests/API/FSTAPIHelpers.mm index d091842..c180dc4 100644 --- a/Firestore/Example/Tests/API/FSTAPIHelpers.mm +++ b/Firestore/Example/Tests/API/FSTAPIHelpers.mm @@ -31,7 +31,12 @@ #import "Firestore/Source/Model/FSTDocument.h" #import "Firestore/Source/Model/FSTDocumentKey.h" #import "Firestore/Source/Model/FSTDocumentSet.h" -#import "Firestore/Source/Model/FSTPath.h" + +#include "Firestore/core/src/firebase/firestore/util/string_apple.h" +#include "Firestore/core/test/firebase/firestore/testutil/testutil.h" + +namespace testutil = firebase::firestore::testutil; +namespace util = firebase::firestore::util; NS_ASSUME_NONNULL_BEGIN @@ -65,12 +70,14 @@ FIRDocumentSnapshot *FSTTestDocSnapshot(NSString *path, fromCache:fromCache]; } -FIRCollectionReference *FSTTestCollectionRef(NSString *path) { - return [FIRCollectionReference referenceWithPath:FSTTestPath(path) firestore:FSTTestFirestore()]; +FIRCollectionReference *FSTTestCollectionRef(const absl::string_view path) { + return [FIRCollectionReference referenceWithPath:testutil::Resource(path) + firestore:FSTTestFirestore()]; } -FIRDocumentReference *FSTTestDocRef(NSString *path) { - return [FIRDocumentReference referenceWithPath:FSTTestPath(path) firestore:FSTTestFirestore()]; +FIRDocumentReference *FSTTestDocRef(const absl::string_view path) { + return [FIRDocumentReference referenceWithPath:testutil::Resource(path) + firestore:FSTTestFirestore()]; } /** A convenience method for creating a query snapshots for tests. */ @@ -99,15 +106,16 @@ FIRQuerySnapshot *FSTTestQuerySnapshot( changeWithDocument:docToAdd type:FSTDocumentViewChangeTypeAdded]]; } - FSTViewSnapshot *viewSnapshot = [[FSTViewSnapshot alloc] initWithQuery:FSTTestQuery(path) - documents:newDocuments - oldDocuments:oldDocuments - documentChanges:documentChanges - fromCache:fromCache - hasPendingWrites:hasPendingWrites - syncStateChanged:YES]; + FSTViewSnapshot *viewSnapshot = + [[FSTViewSnapshot alloc] initWithQuery:FSTTestQuery(util::MakeStringView(path)) + documents:newDocuments + oldDocuments:oldDocuments + documentChanges:documentChanges + fromCache:fromCache + hasPendingWrites:hasPendingWrites + syncStateChanged:YES]; return [FIRQuerySnapshot snapshotWithFirestore:FSTTestFirestore() - originalQuery:FSTTestQuery(path) + originalQuery:FSTTestQuery(util::MakeStringView(path)) snapshot:viewSnapshot metadata:metadata]; } diff --git a/Firestore/Example/Tests/Core/FSTEventManagerTests.mm b/Firestore/Example/Tests/Core/FSTEventManagerTests.mm index f5f7b5b..952d01f 100644 --- a/Firestore/Example/Tests/Core/FSTEventManagerTests.mm +++ b/Firestore/Example/Tests/Core/FSTEventManagerTests.mm @@ -52,7 +52,7 @@ NS_ASSUME_NONNULL_BEGIN } - (void)testHandlesManyListenersPerQuery { - FSTQuery *query = FSTTestQuery(@"foo/bar"); + FSTQuery *query = FSTTestQuery("foo/bar"); FSTQueryListener *listener1 = [self noopListenerForQuery:query]; FSTQueryListener *listener2 = [self noopListenerForQuery:query]; @@ -73,7 +73,7 @@ NS_ASSUME_NONNULL_BEGIN } - (void)testHandlesUnlistenOnUnknownListenerGracefully { - FSTQuery *query = FSTTestQuery(@"foo/bar"); + FSTQuery *query = FSTTestQuery("foo/bar"); FSTQueryListener *listener = [self noopListenerForQuery:query]; FSTSyncEngine *syncEngineMock = OCMStrictClassMock([FSTSyncEngine class]); @@ -95,8 +95,8 @@ NS_ASSUME_NONNULL_BEGIN } - (void)testNotifiesListenersInTheRightOrder { - FSTQuery *query1 = FSTTestQuery(@"foo/bar"); - FSTQuery *query2 = FSTTestQuery(@"bar/baz"); + FSTQuery *query1 = FSTTestQuery("foo/bar"); + FSTQuery *query2 = FSTTestQuery("bar/baz"); NSMutableArray *eventOrder = [NSMutableArray array]; FSTQueryListener *listener1 = [self makeMockListenerForQuery:query1 @@ -135,7 +135,7 @@ NS_ASSUME_NONNULL_BEGIN } - (void)testWillForwardOnlineStateChanges { - FSTQuery *query = FSTTestQuery(@"foo/bar"); + FSTQuery *query = FSTTestQuery("foo/bar"); FSTQueryListener *fakeListener = OCMClassMock([FSTQueryListener class]); NSMutableArray *events = [NSMutableArray array]; OCMStub([fakeListener query]).andReturn(query); diff --git a/Firestore/Example/Tests/Core/FSTQueryListenerTests.mm b/Firestore/Example/Tests/Core/FSTQueryListenerTests.mm index 1b26360..55c4219 100644 --- a/Firestore/Example/Tests/Core/FSTQueryListenerTests.mm +++ b/Firestore/Example/Tests/Core/FSTQueryListenerTests.mm @@ -45,7 +45,7 @@ NS_ASSUME_NONNULL_BEGIN NSMutableArray *accum = [NSMutableArray array]; NSMutableArray *otherAccum = [NSMutableArray array]; - FSTQuery *query = FSTTestQuery(@"rooms"); + FSTQuery *query = FSTTestQuery("rooms"); FSTDocument *doc1 = FSTTestDoc(@"rooms/Eros", 1, @{@"name" : @"Eros"}, NO); FSTDocument *doc2 = FSTTestDoc(@"rooms/Hades", 2, @{@"name" : @"Hades"}, NO); FSTDocument *doc2prime = @@ -88,7 +88,7 @@ NS_ASSUME_NONNULL_BEGIN - (void)testRaisesErrorEvent { NSMutableArray *accum = [NSMutableArray array]; - FSTQuery *query = FSTTestQuery(@"rooms/Eros"); + FSTQuery *query = FSTTestQuery("rooms/Eros"); FSTQueryListener *listener = [self listenToQuery:query handler:^(FSTViewSnapshot *snapshot, NSError *error) { @@ -104,7 +104,7 @@ NS_ASSUME_NONNULL_BEGIN - (void)testRaisesEventForEmptyCollectionAfterSync { NSMutableArray *accum = [NSMutableArray array]; - FSTQuery *query = FSTTestQuery(@"rooms"); + FSTQuery *query = FSTTestQuery("rooms"); FSTQueryListener *listener = [self listenToQuery:query accumulatingSnapshots:accum]; @@ -126,7 +126,7 @@ NS_ASSUME_NONNULL_BEGIN - (void)testMutingAsyncListenerPreventsAllSubsequentEvents { NSMutableArray *accum = [NSMutableArray array]; - FSTQuery *query = FSTTestQuery(@"rooms/Eros"); + FSTQuery *query = FSTTestQuery("rooms/Eros"); FSTDocument *doc1 = FSTTestDoc(@"rooms/Eros", 3, @{@"name" : @"Eros"}, NO); FSTDocument *doc2 = FSTTestDoc(@"rooms/Eros", 4, @{@"name" : @"Eros2"}, NO); @@ -166,7 +166,7 @@ NS_ASSUME_NONNULL_BEGIN NSMutableArray *filteredAccum = [NSMutableArray array]; NSMutableArray *fullAccum = [NSMutableArray array]; - FSTQuery *query = FSTTestQuery(@"rooms"); + FSTQuery *query = FSTTestQuery("rooms"); FSTDocument *doc1 = FSTTestDoc(@"rooms/Eros", 1, @{@"name" : @"Eros"}, NO); FSTDocument *doc2 = FSTTestDoc(@"rooms/Hades", 2, @{@"name" : @"Hades"}, NO); @@ -204,7 +204,7 @@ NS_ASSUME_NONNULL_BEGIN NSMutableArray *filteredAccum = [NSMutableArray array]; NSMutableArray *fullAccum = [NSMutableArray array]; - FSTQuery *query = FSTTestQuery(@"rooms"); + FSTQuery *query = FSTTestQuery("rooms"); FSTDocument *doc1 = FSTTestDoc(@"rooms/Eros", 1, @{@"name" : @"Eros"}, YES); FSTDocument *doc2 = FSTTestDoc(@"rooms/Hades", 2, @{@"name" : @"Hades"}, NO); FSTDocument *doc1Prime = FSTTestDoc(@"rooms/Eros", 1, @{@"name" : @"Eros"}, NO); @@ -253,7 +253,7 @@ NS_ASSUME_NONNULL_BEGIN - (void)testRaisesQueryMetadataEventsOnlyWhenHasPendingWritesOnTheQueryChanges { NSMutableArray *fullAccum = [NSMutableArray array]; - FSTQuery *query = FSTTestQuery(@"rooms"); + FSTQuery *query = FSTTestQuery("rooms"); FSTDocument *doc1 = FSTTestDoc(@"rooms/Eros", 1, @{@"name" : @"Eros"}, YES); FSTDocument *doc2 = FSTTestDoc(@"rooms/Hades", 2, @{@"name" : @"Hades"}, YES); FSTDocument *doc1Prime = FSTTestDoc(@"rooms/Eros", 1, @{@"name" : @"Eros"}, NO); @@ -290,7 +290,7 @@ NS_ASSUME_NONNULL_BEGIN - (void)testMetadataOnlyDocumentChangesAreFilteredOutWhenIncludeDocumentMetadataChangesIsFalse { NSMutableArray *filteredAccum = [NSMutableArray array]; - FSTQuery *query = FSTTestQuery(@"rooms"); + FSTQuery *query = FSTTestQuery("rooms"); FSTDocument *doc1 = FSTTestDoc(@"rooms/Eros", 1, @{@"name" : @"Eros"}, YES); FSTDocument *doc2 = FSTTestDoc(@"rooms/Hades", 2, @{@"name" : @"Hades"}, NO); FSTDocument *doc1Prime = FSTTestDoc(@"rooms/Eros", 1, @{@"name" : @"Eros"}, NO); @@ -322,7 +322,7 @@ NS_ASSUME_NONNULL_BEGIN - (void)testWillWaitForSyncIfOnline { NSMutableArray *events = [NSMutableArray array]; - FSTQuery *query = FSTTestQuery(@"rooms"); + FSTQuery *query = FSTTestQuery("rooms"); FSTDocument *doc1 = FSTTestDoc(@"rooms/Eros", 1, @{@"name" : @"Eros"}, NO); FSTDocument *doc2 = FSTTestDoc(@"rooms/Hades", 2, @{@"name" : @"Hades"}, NO); FSTQueryListener *listener = @@ -365,7 +365,7 @@ NS_ASSUME_NONNULL_BEGIN - (void)testWillRaiseInitialEventWhenGoingOffline { NSMutableArray *events = [NSMutableArray array]; - FSTQuery *query = FSTTestQuery(@"rooms"); + FSTQuery *query = FSTTestQuery("rooms"); FSTDocument *doc1 = FSTTestDoc(@"rooms/Eros", 1, @{@"name" : @"Eros"}, NO); FSTDocument *doc2 = FSTTestDoc(@"rooms/Hades", 2, @{@"name" : @"Hades"}, NO); FSTQueryListener *listener = @@ -411,7 +411,7 @@ NS_ASSUME_NONNULL_BEGIN - (void)testWillRaiseInitialEventWhenGoingOfflineAndThereAreNoDocs { NSMutableArray *events = [NSMutableArray array]; - FSTQuery *query = FSTTestQuery(@"rooms"); + FSTQuery *query = FSTTestQuery("rooms"); FSTQueryListener *listener = [self listenToQuery:query options:[FSTListenOptions defaultOptions] accumulatingSnapshots:events]; @@ -437,7 +437,7 @@ NS_ASSUME_NONNULL_BEGIN - (void)testWillRaiseInitialEventWhenStartingOfflineAndThereAreNoDocs { NSMutableArray *events = [NSMutableArray array]; - FSTQuery *query = FSTTestQuery(@"rooms"); + FSTQuery *query = FSTTestQuery("rooms"); FSTQueryListener *listener = [self listenToQuery:query options:[FSTListenOptions defaultOptions] accumulatingSnapshots:events]; diff --git a/Firestore/Example/Tests/Core/FSTQueryTests.mm b/Firestore/Example/Tests/Core/FSTQueryTests.mm index 5f6d279..8b5b524 100644 --- a/Firestore/Example/Tests/Core/FSTQueryTests.mm +++ b/Firestore/Example/Tests/Core/FSTQueryTests.mm @@ -21,7 +21,6 @@ #import "Firestore/Source/API/FIRFirestore+Internal.h" #import "Firestore/Source/Model/FSTDocument.h" #import "Firestore/Source/Model/FSTDocumentKey.h" -#import "Firestore/Source/Model/FSTPath.h" #import "Firestore/Example/Tests/Util/FSTHelpers.h" @@ -30,6 +29,7 @@ #include "Firestore/core/src/firebase/firestore/model/resource_path.h" #include "Firestore/core/src/firebase/firestore/util/string_apple.h" #include "Firestore/core/test/firebase/firestore/testutil/testutil.h" +#include "absl/strings/string_view.h" namespace testutil = firebase::firestore::testutil; namespace util = firebase::firestore::util; @@ -41,16 +41,14 @@ NS_ASSUME_NONNULL_BEGIN /** Convenience methods for building test queries. */ @interface FSTQuery (Tests) -- (FSTQuery *)queryByAddingSortBy:(NSString *)key ascending:(BOOL)ascending; +- (FSTQuery *)queryByAddingSortBy:(const absl::string_view)key ascending:(BOOL)ascending; @end @implementation FSTQuery (Tests) -- (FSTQuery *)queryByAddingSortBy:(NSString *)key ascending:(BOOL)ascending { - return [self - queryByAddingSortOrder:[FSTSortOrder - sortOrderWithFieldPath:testutil::Field(util::MakeStringView(key)) - ascending:ascending]]; +- (FSTQuery *)queryByAddingSortBy:(const absl::string_view)key ascending:(BOOL)ascending { + return [self queryByAddingSortOrder:[FSTSortOrder sortOrderWithFieldPath:testutil::Field(key) + ascending:ascending]]; } @end @@ -61,9 +59,8 @@ NS_ASSUME_NONNULL_BEGIN @implementation FSTQueryTests - (void)testConstructor { - FSTResourcePath *path = - [FSTResourcePath pathWithSegments:@[ @"rooms", @"Firestore", @"messages", @"0001" ]]; - FSTQuery *query = [FSTQuery queryWithPath:[path toCPPResourcePath]]; + const ResourcePath path{"rooms", "Firestore", "messages", "0001"}; + FSTQuery *query = [FSTQuery queryWithPath:path]; XCTAssertNotNil(query); XCTAssertEqual(query.sortOrders.count, 1); @@ -74,7 +71,7 @@ NS_ASSUME_NONNULL_BEGIN } - (void)testOrderBy { - FSTQuery *query = FSTTestQuery(@"rooms/Firestore/messages"); + FSTQuery *query = FSTTestQuery("rooms/Firestore/messages"); query = [query queryByAddingSortOrder:[FSTSortOrder sortOrderWithFieldPath:testutil::Field("length") ascending:NO]]; @@ -96,7 +93,7 @@ NS_ASSUME_NONNULL_BEGIN FSTDocument *doc3 = FSTTestDoc(@"rooms/other/messages/1", 0, @{@"text" : @"msg3"}, NO); // document query - FSTQuery *query = FSTTestQuery(@"rooms/eros/messages/1"); + FSTQuery *query = FSTTestQuery("rooms/eros/messages/1"); XCTAssertTrue([query matchesDocument:doc1]); XCTAssertFalse([query matchesDocument:doc2]); XCTAssertFalse([query matchesDocument:doc3]); @@ -109,7 +106,7 @@ NS_ASSUME_NONNULL_BEGIN FSTDocument *doc3 = FSTTestDoc(@"rooms/other/messages/1", 0, @{@"text" : @"msg3"}, NO); // shallow ancestor query - FSTQuery *query = FSTTestQuery(@"rooms/eros/messages"); + FSTQuery *query = FSTTestQuery("rooms/eros/messages"); XCTAssertTrue([query matchesDocument:doc1]); XCTAssertFalse([query matchesDocument:doc1Meta]); XCTAssertTrue([query matchesDocument:doc2]); @@ -120,17 +117,17 @@ NS_ASSUME_NONNULL_BEGIN FSTDocument *doc1 = FSTTestDoc(@"rooms/eros/messages/1", 0, @{@"text" : @"msg1"}, NO); FSTDocument *doc2 = FSTTestDoc(@"rooms/eros/messages/2", 0, @{}, NO); - FSTQuery *query = [FSTTestQuery(@"rooms/eros/messages") - queryByAddingFilter:FSTTestFilter(@"text", @"==", @"msg1")]; + FSTQuery *query = [FSTTestQuery("rooms/eros/messages") + queryByAddingFilter:FSTTestFilter("text", @"==", @"msg1")]; XCTAssertTrue([query matchesDocument:doc1]); XCTAssertFalse([query matchesDocument:doc2]); } - (void)testMatchesPrimitiveValuesForFilters { FSTQuery *query1 = - [FSTTestQuery(@"collection") queryByAddingFilter:FSTTestFilter(@"sort", @">=", @(2))]; + [FSTTestQuery("collection") queryByAddingFilter:FSTTestFilter("sort", @">=", @(2))]; FSTQuery *query2 = - [FSTTestQuery(@"collection") queryByAddingFilter:FSTTestFilter(@"sort", @"<=", @(2))]; + [FSTTestQuery("collection") queryByAddingFilter:FSTTestFilter("sort", @"<=", @(2))]; FSTDocument *doc1 = FSTTestDoc(@"collection/1", 0, @{ @"sort" : @1 }, NO); FSTDocument *doc2 = FSTTestDoc(@"collection/2", 0, @{ @"sort" : @2 }, NO); @@ -155,8 +152,8 @@ NS_ASSUME_NONNULL_BEGIN } - (void)testNullFilter { - FSTQuery *query = [FSTTestQuery(@"collection") - queryByAddingFilter:FSTTestFilter(@"sort", @"==", [NSNull null])]; + FSTQuery *query = + [FSTTestQuery("collection") queryByAddingFilter:FSTTestFilter("sort", @"==", [NSNull null])]; FSTDocument *doc1 = FSTTestDoc(@"collection/1", 0, @{@"sort" : [NSNull null]}, NO); FSTDocument *doc2 = FSTTestDoc(@"collection/2", 0, @{ @"sort" : @2 }, NO); FSTDocument *doc3 = FSTTestDoc(@"collection/2", 0, @{ @"sort" : @3.1 }, NO); @@ -172,7 +169,7 @@ NS_ASSUME_NONNULL_BEGIN - (void)testNanFilter { FSTQuery *query = - [FSTTestQuery(@"collection") queryByAddingFilter:FSTTestFilter(@"sort", @"==", @(NAN))]; + [FSTTestQuery("collection") queryByAddingFilter:FSTTestFilter("sort", @"==", @(NAN))]; FSTDocument *doc1 = FSTTestDoc(@"collection/1", 0, @{ @"sort" : @(NAN) }, NO); FSTDocument *doc2 = FSTTestDoc(@"collection/2", 0, @{ @"sort" : @2 }, NO); FSTDocument *doc3 = FSTTestDoc(@"collection/2", 0, @{ @"sort" : @3.1 }, NO); @@ -188,9 +185,9 @@ NS_ASSUME_NONNULL_BEGIN - (void)testDoesNotMatchComplexObjectsForFilters { FSTQuery *query1 = - [FSTTestQuery(@"collection") queryByAddingFilter:FSTTestFilter(@"sort", @"<=", @(2))]; + [FSTTestQuery("collection") queryByAddingFilter:FSTTestFilter("sort", @"<=", @(2))]; FSTQuery *query2 = - [FSTTestQuery(@"collection") queryByAddingFilter:FSTTestFilter(@"sort", @">=", @(2))]; + [FSTTestQuery("collection") queryByAddingFilter:FSTTestFilter("sort", @">=", @(2))]; FSTDocument *doc1 = FSTTestDoc(@"collection/1", 0, @{ @"sort" : @2 }, NO); FSTDocument *doc2 = FSTTestDoc(@"collection/2", 0, @{ @"sort" : @[] }, NO); @@ -218,7 +215,7 @@ NS_ASSUME_NONNULL_BEGIN } - (void)testDoesntRemoveComplexObjectsWithOrderBy { - FSTQuery *query1 = [FSTTestQuery(@"collection") + FSTQuery *query1 = [FSTTestQuery("collection") queryByAddingSortOrder:[FSTSortOrder sortOrderWithFieldPath:testutil::Field("sort") ascending:YES]]; @@ -238,16 +235,16 @@ NS_ASSUME_NONNULL_BEGIN } - (void)testFiltersBasedOnArrayValue { - FSTQuery *baseQuery = FSTTestQuery(@"collection"); + FSTQuery *baseQuery = FSTTestQuery("collection"); FSTDocument *doc1 = FSTTestDoc(@"collection/doc", 0, @{ @"tags" : @[ @"foo", @1, @YES ] }, NO); NSArray> *matchingFilters = - @[ FSTTestFilter(@"tags", @"==", @[ @"foo", @1, @YES ]) ]; + @[ FSTTestFilter("tags", @"==", @[ @"foo", @1, @YES ]) ]; NSArray> *nonMatchingFilters = @[ - FSTTestFilter(@"tags", @"==", @"foo"), - FSTTestFilter(@"tags", @"==", @[ @"foo", @1 ]), - FSTTestFilter(@"tags", @"==", @[ @"foo", @YES, @1 ]), + FSTTestFilter("tags", @"==", @"foo"), + FSTTestFilter("tags", @"==", @[ @"foo", @1 ]), + FSTTestFilter("tags", @"==", @[ @"foo", @YES, @1 ]), ]; for (id filter in matchingFilters) { @@ -260,27 +257,27 @@ NS_ASSUME_NONNULL_BEGIN } - (void)testFiltersBasedOnObjectValue { - FSTQuery *baseQuery = FSTTestQuery(@"collection"); + FSTQuery *baseQuery = FSTTestQuery("collection"); FSTDocument *doc1 = FSTTestDoc(@"collection/doc", 0, @{ @"tags" : @{@"foo" : @"foo", @"a" : @0, @"b" : @YES, @"c" : @(NAN)} }, NO); NSArray> *matchingFilters = @[ - FSTTestFilter(@"tags", @"==", + FSTTestFilter("tags", @"==", @{ @"foo" : @"foo", @"a" : @0, @"b" : @YES, @"c" : @(NAN) }), - FSTTestFilter(@"tags", @"==", + FSTTestFilter("tags", @"==", @{ @"b" : @YES, @"a" : @0, @"foo" : @"foo", @"c" : @(NAN) }), - FSTTestFilter(@"tags.foo", @"==", @"foo") + FSTTestFilter("tags.foo", @"==", @"foo") ]; NSArray> *nonMatchingFilters = @[ - FSTTestFilter(@"tags", @"==", @"foo"), FSTTestFilter(@"tags", @"==", @{ + FSTTestFilter("tags", @"==", @"foo"), FSTTestFilter("tags", @"==", @{ @"foo" : @"foo", @"a" : @0, @"b" : @YES, @@ -312,7 +309,7 @@ NS_ASSUME_NONNULL_BEGIN } - (void)testSortsDocumentsInTheCorrectOrder { - FSTQuery *query = FSTTestQuery(@"collection"); + FSTQuery *query = FSTTestQuery("collection"); query = [query queryByAddingSortOrder:[FSTSortOrder sortOrderWithFieldPath:testutil::Field("sort") ascending:YES]]; @@ -340,7 +337,7 @@ NS_ASSUME_NONNULL_BEGIN } - (void)testSortsDocumentsUsingMultipleFields { - FSTQuery *query = FSTTestQuery(@"collection"); + FSTQuery *query = FSTTestQuery("collection"); query = [query queryByAddingSortOrder:[FSTSortOrder sortOrderWithFieldPath:testutil::Field("sort1") ascending:YES]]; @@ -367,7 +364,7 @@ NS_ASSUME_NONNULL_BEGIN } - (void)testSortsDocumentsWithDescendingToo { - FSTQuery *query = FSTTestQuery(@"collection"); + FSTQuery *query = FSTTestQuery("collection"); query = [query queryByAddingSortOrder:[FSTSortOrder sortOrderWithFieldPath:testutil::Field("sort1") ascending:NO]]; @@ -394,40 +391,40 @@ NS_ASSUME_NONNULL_BEGIN } - (void)testEquality { - FSTQuery *q11 = FSTTestQuery(@"foo"); - q11 = [q11 queryByAddingFilter:FSTTestFilter(@"i1", @"<", @(2))]; - q11 = [q11 queryByAddingFilter:FSTTestFilter(@"i2", @"==", @(3))]; - FSTQuery *q12 = FSTTestQuery(@"foo"); - q12 = [q12 queryByAddingFilter:FSTTestFilter(@"i2", @"==", @(3))]; - q12 = [q12 queryByAddingFilter:FSTTestFilter(@"i1", @"<", @(2))]; - - FSTQuery *q21 = FSTTestQuery(@"foo"); - FSTQuery *q22 = FSTTestQuery(@"foo"); - - FSTQuery *q31 = FSTTestQuery(@"foo/bar"); - FSTQuery *q32 = FSTTestQuery(@"foo/bar"); - - FSTQuery *q41 = FSTTestQuery(@"foo"); - q41 = [q41 queryByAddingSortBy:@"foo" ascending:YES]; - q41 = [q41 queryByAddingSortBy:@"bar" ascending:YES]; - FSTQuery *q42 = FSTTestQuery(@"foo"); - q42 = [q42 queryByAddingSortBy:@"foo" ascending:YES]; - q42 = [q42 queryByAddingSortBy:@"bar" ascending:YES]; - FSTQuery *q43Diff = FSTTestQuery(@"foo"); - q43Diff = [q43Diff queryByAddingSortBy:@"bar" ascending:YES]; - q43Diff = [q43Diff queryByAddingSortBy:@"foo" ascending:YES]; - - FSTQuery *q51 = FSTTestQuery(@"foo"); - q51 = [q51 queryByAddingSortBy:@"foo" ascending:YES]; - q51 = [q51 queryByAddingFilter:FSTTestFilter(@"foo", @">", @(2))]; - FSTQuery *q52 = FSTTestQuery(@"foo"); - q52 = [q52 queryByAddingFilter:FSTTestFilter(@"foo", @">", @(2))]; - q52 = [q52 queryByAddingSortBy:@"foo" ascending:YES]; - FSTQuery *q53Diff = FSTTestQuery(@"foo"); - q53Diff = [q53Diff queryByAddingFilter:FSTTestFilter(@"bar", @">", @(2))]; - q53Diff = [q53Diff queryByAddingSortBy:@"bar" ascending:YES]; - - FSTQuery *q61 = FSTTestQuery(@"foo"); + FSTQuery *q11 = FSTTestQuery("foo"); + q11 = [q11 queryByAddingFilter:FSTTestFilter("i1", @"<", @(2))]; + q11 = [q11 queryByAddingFilter:FSTTestFilter("i2", @"==", @(3))]; + FSTQuery *q12 = FSTTestQuery("foo"); + q12 = [q12 queryByAddingFilter:FSTTestFilter("i2", @"==", @(3))]; + q12 = [q12 queryByAddingFilter:FSTTestFilter("i1", @"<", @(2))]; + + FSTQuery *q21 = FSTTestQuery("foo"); + FSTQuery *q22 = FSTTestQuery("foo"); + + FSTQuery *q31 = FSTTestQuery("foo/bar"); + FSTQuery *q32 = FSTTestQuery("foo/bar"); + + FSTQuery *q41 = FSTTestQuery("foo"); + q41 = [q41 queryByAddingSortBy:"foo" ascending:YES]; + q41 = [q41 queryByAddingSortBy:"bar" ascending:YES]; + FSTQuery *q42 = FSTTestQuery("foo"); + q42 = [q42 queryByAddingSortBy:"foo" ascending:YES]; + q42 = [q42 queryByAddingSortBy:"bar" ascending:YES]; + FSTQuery *q43Diff = FSTTestQuery("foo"); + q43Diff = [q43Diff queryByAddingSortBy:"bar" ascending:YES]; + q43Diff = [q43Diff queryByAddingSortBy:"foo" ascending:YES]; + + FSTQuery *q51 = FSTTestQuery("foo"); + q51 = [q51 queryByAddingSortBy:"foo" ascending:YES]; + q51 = [q51 queryByAddingFilter:FSTTestFilter("foo", @">", @(2))]; + FSTQuery *q52 = FSTTestQuery("foo"); + q52 = [q52 queryByAddingFilter:FSTTestFilter("foo", @">", @(2))]; + q52 = [q52 queryByAddingSortBy:"foo" ascending:YES]; + FSTQuery *q53Diff = FSTTestQuery("foo"); + q53Diff = [q53Diff queryByAddingFilter:FSTTestFilter("bar", @">", @(2))]; + q53Diff = [q53Diff queryByAddingSortBy:"bar" ascending:YES]; + + FSTQuery *q61 = FSTTestQuery("foo"); q61 = [q61 queryBySettingLimit:10]; // XCTAssertEqualObjects(q11, q12); // TODO(klimt): not canonical yet @@ -459,40 +456,40 @@ NS_ASSUME_NONNULL_BEGIN } - (void)testUniqueIds { - FSTQuery *q11 = FSTTestQuery(@"foo"); - q11 = [q11 queryByAddingFilter:FSTTestFilter(@"i1", @"<", @(2))]; - q11 = [q11 queryByAddingFilter:FSTTestFilter(@"i2", @"==", @(3))]; - FSTQuery *q12 = FSTTestQuery(@"foo"); - q12 = [q12 queryByAddingFilter:FSTTestFilter(@"i2", @"==", @(3))]; - q12 = [q12 queryByAddingFilter:FSTTestFilter(@"i1", @"<", @(2))]; - - FSTQuery *q21 = FSTTestQuery(@"foo"); - FSTQuery *q22 = FSTTestQuery(@"foo"); - - FSTQuery *q31 = FSTTestQuery(@"foo/bar"); - FSTQuery *q32 = FSTTestQuery(@"foo/bar"); - - FSTQuery *q41 = FSTTestQuery(@"foo"); - q41 = [q41 queryByAddingSortBy:@"foo" ascending:YES]; - q41 = [q41 queryByAddingSortBy:@"bar" ascending:YES]; - FSTQuery *q42 = FSTTestQuery(@"foo"); - q42 = [q42 queryByAddingSortBy:@"foo" ascending:YES]; - q42 = [q42 queryByAddingSortBy:@"bar" ascending:YES]; - FSTQuery *q43Diff = FSTTestQuery(@"foo"); - q43Diff = [q43Diff queryByAddingSortBy:@"bar" ascending:YES]; - q43Diff = [q43Diff queryByAddingSortBy:@"foo" ascending:YES]; - - FSTQuery *q51 = FSTTestQuery(@"foo"); - q51 = [q51 queryByAddingSortBy:@"foo" ascending:YES]; - q51 = [q51 queryByAddingFilter:FSTTestFilter(@"foo", @">", @(2))]; - FSTQuery *q52 = FSTTestQuery(@"foo"); - q52 = [q52 queryByAddingFilter:FSTTestFilter(@"foo", @">", @(2))]; - q52 = [q52 queryByAddingSortBy:@"foo" ascending:YES]; - FSTQuery *q53Diff = FSTTestQuery(@"foo"); - q53Diff = [q53Diff queryByAddingFilter:FSTTestFilter(@"bar", @">", @(2))]; - q53Diff = [q53Diff queryByAddingSortBy:@"bar" ascending:YES]; - - FSTQuery *q61 = FSTTestQuery(@"foo"); + FSTQuery *q11 = FSTTestQuery("foo"); + q11 = [q11 queryByAddingFilter:FSTTestFilter("i1", @"<", @(2))]; + q11 = [q11 queryByAddingFilter:FSTTestFilter("i2", @"==", @(3))]; + FSTQuery *q12 = FSTTestQuery("foo"); + q12 = [q12 queryByAddingFilter:FSTTestFilter("i2", @"==", @(3))]; + q12 = [q12 queryByAddingFilter:FSTTestFilter("i1", @"<", @(2))]; + + FSTQuery *q21 = FSTTestQuery("foo"); + FSTQuery *q22 = FSTTestQuery("foo"); + + FSTQuery *q31 = FSTTestQuery("foo/bar"); + FSTQuery *q32 = FSTTestQuery("foo/bar"); + + FSTQuery *q41 = FSTTestQuery("foo"); + q41 = [q41 queryByAddingSortBy:"foo" ascending:YES]; + q41 = [q41 queryByAddingSortBy:"bar" ascending:YES]; + FSTQuery *q42 = FSTTestQuery("foo"); + q42 = [q42 queryByAddingSortBy:"foo" ascending:YES]; + q42 = [q42 queryByAddingSortBy:"bar" ascending:YES]; + FSTQuery *q43Diff = FSTTestQuery("foo"); + q43Diff = [q43Diff queryByAddingSortBy:"bar" ascending:YES]; + q43Diff = [q43Diff queryByAddingSortBy:"foo" ascending:YES]; + + FSTQuery *q51 = FSTTestQuery("foo"); + q51 = [q51 queryByAddingSortBy:"foo" ascending:YES]; + q51 = [q51 queryByAddingFilter:FSTTestFilter("foo", @">", @(2))]; + FSTQuery *q52 = FSTTestQuery("foo"); + q52 = [q52 queryByAddingFilter:FSTTestFilter("foo", @">", @(2))]; + q52 = [q52 queryByAddingSortBy:"foo" ascending:YES]; + FSTQuery *q53Diff = FSTTestQuery("foo"); + q53Diff = [q53Diff queryByAddingFilter:FSTTestFilter("bar", @">", @(2))]; + q53Diff = [q53Diff queryByAddingSortBy:"bar" ascending:YES]; + + FSTQuery *q61 = FSTTestQuery("foo"); q61 = [q61 queryBySettingLimit:10]; // XCTAssertEqual(q11.hash, q12.hash); // TODO(klimt): not canonical yet @@ -524,52 +521,55 @@ NS_ASSUME_NONNULL_BEGIN } - (void)testImplicitOrderBy { - FSTQuery *baseQuery = FSTTestQuery(@"foo"); + FSTQuery *baseQuery = FSTTestQuery("foo"); // Default is ascending - XCTAssertEqualObjects(baseQuery.sortOrders, @[ FSTTestOrderBy(kDocumentKeyPath, @"asc") ]); + XCTAssertEqualObjects(baseQuery.sortOrders, + @[ FSTTestOrderBy(FieldPath::kDocumentKeyPath, @"asc") ]); // Explicit key ordering is respected XCTAssertEqualObjects( - [baseQuery queryByAddingSortOrder:FSTTestOrderBy(kDocumentKeyPath, @"asc")].sortOrders, - @[ FSTTestOrderBy(kDocumentKeyPath, @"asc") ]); + [baseQuery queryByAddingSortOrder:FSTTestOrderBy(FieldPath::kDocumentKeyPath, @"asc")] + .sortOrders, + @[ FSTTestOrderBy(FieldPath::kDocumentKeyPath, @"asc") ]); XCTAssertEqualObjects( - [baseQuery queryByAddingSortOrder:FSTTestOrderBy(kDocumentKeyPath, @"desc")].sortOrders, - @[ FSTTestOrderBy(kDocumentKeyPath, @"desc") ]); + [baseQuery queryByAddingSortOrder:FSTTestOrderBy(FieldPath::kDocumentKeyPath, @"desc")] + .sortOrders, + @[ FSTTestOrderBy(FieldPath::kDocumentKeyPath, @"desc") ]); XCTAssertEqualObjects( - [[baseQuery queryByAddingSortOrder:FSTTestOrderBy(@"foo", @"asc")] - queryByAddingSortOrder:FSTTestOrderBy(kDocumentKeyPath, @"asc")] + [[baseQuery queryByAddingSortOrder:FSTTestOrderBy("foo", @"asc")] + queryByAddingSortOrder:FSTTestOrderBy(FieldPath::kDocumentKeyPath, @"asc")] .sortOrders, - (@[ FSTTestOrderBy(@"foo", @"asc"), FSTTestOrderBy(kDocumentKeyPath, @"asc") ])); + (@[ FSTTestOrderBy("foo", @"asc"), FSTTestOrderBy(FieldPath::kDocumentKeyPath, @"asc") ])); XCTAssertEqualObjects( - [[baseQuery queryByAddingSortOrder:FSTTestOrderBy(@"foo", @"asc")] - queryByAddingSortOrder:FSTTestOrderBy(kDocumentKeyPath, @"desc")] + [[baseQuery queryByAddingSortOrder:FSTTestOrderBy("foo", @"asc")] + queryByAddingSortOrder:FSTTestOrderBy(FieldPath::kDocumentKeyPath, @"desc")] .sortOrders, - (@[ FSTTestOrderBy(@"foo", @"asc"), FSTTestOrderBy(kDocumentKeyPath, @"desc") ])); + (@[ FSTTestOrderBy("foo", @"asc"), FSTTestOrderBy(FieldPath::kDocumentKeyPath, @"desc") ])); // Inequality filters add order bys XCTAssertEqualObjects( - [baseQuery queryByAddingFilter:FSTTestFilter(@"foo", @"<", @5)].sortOrders, - (@[ FSTTestOrderBy(@"foo", @"asc"), FSTTestOrderBy(kDocumentKeyPath, @"asc") ])); + [baseQuery queryByAddingFilter:FSTTestFilter("foo", @"<", @5)].sortOrders, + (@[ FSTTestOrderBy("foo", @"asc"), FSTTestOrderBy(FieldPath::kDocumentKeyPath, @"asc") ])); // Descending order by applies to implicit key ordering XCTAssertEqualObjects( - [baseQuery queryByAddingSortOrder:FSTTestOrderBy(@"foo", @"desc")].sortOrders, - (@[ FSTTestOrderBy(@"foo", @"desc"), FSTTestOrderBy(kDocumentKeyPath, @"desc") ])); - XCTAssertEqualObjects([[baseQuery queryByAddingSortOrder:FSTTestOrderBy(@"foo", @"asc")] - queryByAddingSortOrder:FSTTestOrderBy(@"bar", @"desc")] + [baseQuery queryByAddingSortOrder:FSTTestOrderBy("foo", @"desc")].sortOrders, + (@[ FSTTestOrderBy("foo", @"desc"), FSTTestOrderBy(FieldPath::kDocumentKeyPath, @"desc") ])); + XCTAssertEqualObjects([[baseQuery queryByAddingSortOrder:FSTTestOrderBy("foo", @"asc")] + queryByAddingSortOrder:FSTTestOrderBy("bar", @"desc")] .sortOrders, (@[ - FSTTestOrderBy(@"foo", @"asc"), FSTTestOrderBy(@"bar", @"desc"), - FSTTestOrderBy(kDocumentKeyPath, @"desc") + FSTTestOrderBy("foo", @"asc"), FSTTestOrderBy("bar", @"desc"), + FSTTestOrderBy(FieldPath::kDocumentKeyPath, @"desc") ])); - XCTAssertEqualObjects([[baseQuery queryByAddingSortOrder:FSTTestOrderBy(@"foo", @"desc")] - queryByAddingSortOrder:FSTTestOrderBy(@"bar", @"asc")] + XCTAssertEqualObjects([[baseQuery queryByAddingSortOrder:FSTTestOrderBy("foo", @"desc")] + queryByAddingSortOrder:FSTTestOrderBy("bar", @"asc")] .sortOrders, (@[ - FSTTestOrderBy(@"foo", @"desc"), FSTTestOrderBy(@"bar", @"asc"), - FSTTestOrderBy(kDocumentKeyPath, @"asc") + FSTTestOrderBy("foo", @"desc"), FSTTestOrderBy("bar", @"asc"), + FSTTestOrderBy(FieldPath::kDocumentKeyPath, @"asc") ])); } diff --git a/Firestore/Example/Tests/Core/FSTViewSnapshotTest.mm b/Firestore/Example/Tests/Core/FSTViewSnapshotTest.mm index fe3e42d..c503684 100644 --- a/Firestore/Example/Tests/Core/FSTViewSnapshotTest.mm +++ b/Firestore/Example/Tests/Core/FSTViewSnapshotTest.mm @@ -21,7 +21,6 @@ #import "Firestore/Source/Core/FSTQuery.h" #import "Firestore/Source/Model/FSTDocument.h" #import "Firestore/Source/Model/FSTDocumentSet.h" -#import "Firestore/Source/Model/FSTPath.h" #import "Firestore/Example/Tests/Util/FSTHelpers.h" @@ -107,7 +106,7 @@ NS_ASSUME_NONNULL_BEGIN } - (void)testViewSnapshotConstructor { - FSTQuery *query = FSTTestQuery(@"a"); + FSTQuery *query = FSTTestQuery("a"); FSTDocumentSet *documents = [FSTDocumentSet documentSetWithComparator:FSTDocumentComparatorByKey]; FSTDocumentSet *oldDocuments = documents; documents = [documents documentSetByAddingDocument:FSTTestDoc(@"c/a", 1, @{}, NO)]; diff --git a/Firestore/Example/Tests/Core/FSTViewTests.mm b/Firestore/Example/Tests/Core/FSTViewTests.mm index 7df8195..1e3ec1a 100644 --- a/Firestore/Example/Tests/Core/FSTViewTests.mm +++ b/Firestore/Example/Tests/Core/FSTViewTests.mm @@ -25,7 +25,6 @@ #import "Firestore/Source/Model/FSTDocumentKey.h" #import "Firestore/Source/Model/FSTDocumentSet.h" #import "Firestore/Source/Model/FSTFieldValue.h" -#import "Firestore/Source/Model/FSTPath.h" #import "Firestore/Source/Remote/FSTRemoteEvent.h" #import "Firestore/Example/Tests/Util/FSTHelpers.h" diff --git a/Firestore/Example/Tests/Integration/API/FIRValidationTests.mm b/Firestore/Example/Tests/Integration/API/FIRValidationTests.mm index 49e572a..0ad30fd 100644 --- a/Firestore/Example/Tests/Integration/API/FIRValidationTests.mm +++ b/Firestore/Example/Tests/Integration/API/FIRValidationTests.mm @@ -132,7 +132,7 @@ } - (void)testPathsWithEmptySegmentsFail { - // We're only testing using collectionWithPath since the validation happens in FSTPath which is + // We're only testing using collectionWithPath since the validation happens in BasePath which is // shared by all methods that accept paths. // leading / trailing slashes are okay. diff --git a/Firestore/Example/Tests/Integration/FSTDatastoreTests.mm b/Firestore/Example/Tests/Integration/FSTDatastoreTests.mm index 77581d4..9ce3d30 100644 --- a/Firestore/Example/Tests/Integration/FSTDatastoreTests.mm +++ b/Firestore/Example/Tests/Integration/FSTDatastoreTests.mm @@ -31,7 +31,6 @@ #import "Firestore/Source/Model/FSTFieldValue.h" #import "Firestore/Source/Model/FSTMutation.h" #import "Firestore/Source/Model/FSTMutationBatch.h" -#import "Firestore/Source/Model/FSTPath.h" #import "Firestore/Source/Remote/FSTDatastore.h" #import "Firestore/Source/Remote/FSTRemoteEvent.h" #import "Firestore/Source/Remote/FSTRemoteStore.h" diff --git a/Firestore/Example/Tests/Local/FSTLevelDBKeyTests.mm b/Firestore/Example/Tests/Local/FSTLevelDBKeyTests.mm index 998d23d..f23b7c5 100644 --- a/Firestore/Example/Tests/Local/FSTLevelDBKeyTests.mm +++ b/Firestore/Example/Tests/Local/FSTLevelDBKeyTests.mm @@ -18,10 +18,14 @@ #import -#import "Firestore/Source/Model/FSTPath.h" - #import "Firestore/Example/Tests/Util/FSTHelpers.h" +#include "Firestore/core/src/firebase/firestore/util/string_apple.h" +#include "Firestore/core/test/firebase/firestore/testutil/testutil.h" + +namespace util = firebase::firestore::util; +namespace testutil = firebase::firestore::testutil; + NS_ASSUME_NONNULL_BEGIN @interface FSTLevelDBKeyTests : XCTestCase @@ -37,7 +41,8 @@ static std::string RemoteDocKey(NSString *pathString) { } static std::string RemoteDocKeyPrefix(NSString *pathString) { - return [FSTLevelDBRemoteDocumentKey keyPrefixWithResourcePath:FSTTestPath(pathString)]; + return [FSTLevelDBRemoteDocumentKey + keyPrefixWithResourcePath:testutil::Resource(util::MakeStringView(pathString))]; } static std::string DocMutationKey(NSString *userID, NSString *key, FSTBatchID batchID) { @@ -199,7 +204,7 @@ static std::string DocTargetKey(NSString *key, FSTTargetID targetID) { @"[document_mutation: userID=user1 incomplete key]"); auto key = [FSTLevelDBDocumentMutationKey keyPrefixWithUserID:@"user1" - resourcePath:FSTTestPath(@"foo/bar")]; + resourcePath:testutil::Resource("foo/bar")]; FSTAssertExpectedKeyDescription(key, @"[document_mutation: userID=user1 key=foo/bar incomplete key]"); diff --git a/Firestore/Example/Tests/Local/FSTLocalSerializerTests.mm b/Firestore/Example/Tests/Local/FSTLocalSerializerTests.mm index 1793b23..87242fa 100644 --- a/Firestore/Example/Tests/Local/FSTLocalSerializerTests.mm +++ b/Firestore/Example/Tests/Local/FSTLocalSerializerTests.mm @@ -36,14 +36,15 @@ #import "Firestore/Source/Model/FSTFieldValue.h" #import "Firestore/Source/Model/FSTMutation.h" #import "Firestore/Source/Model/FSTMutationBatch.h" -#import "Firestore/Source/Model/FSTPath.h" #import "Firestore/Source/Remote/FSTSerializerBeta.h" #import "Firestore/Example/Tests/Util/FSTHelpers.h" #include "Firestore/core/src/firebase/firestore/model/database_id.h" #include "Firestore/core/src/firebase/firestore/util/string_apple.h" +#include "Firestore/core/test/firebase/firestore/testutil/testutil.h" +namespace testutil = firebase::firestore::testutil; using firebase::firestore::model::DatabaseId; NS_ASSUME_NONNULL_BEGIN @@ -77,7 +78,7 @@ NS_ASSUME_NONNULL_BEGIN FSTMutation *set = FSTTestSetMutation(@"foo/bar", @{ @"a" : @"b", @"num" : @1 }); FSTMutation *patch = [[FSTPatchMutation alloc] initWithKey:FSTTestDocKey(@"bar/baz") - fieldMask:[[FSTFieldMask alloc] initWithFields:@[ FSTTestFieldPath(@"a") ]] + fieldMask:[[FSTFieldMask alloc] initWithFields:{testutil::Field("a")}] value:FSTTestObjectValue( @{ @"a" : @"b", @"num" : @1 }) @@ -156,7 +157,7 @@ NS_ASSUME_NONNULL_BEGIN } - (void)testEncodesQueryData { - FSTQuery *query = FSTTestQuery(@"room"); + FSTQuery *query = FSTTestQuery("room"); FSTTargetID targetID = 42; FSTSnapshotVersion *version = FSTTestVersion(1039); NSData *resumeToken = FSTTestResumeTokenFromSnapshotVersion(1039); diff --git a/Firestore/Example/Tests/Local/FSTLocalStoreTests.mm b/Firestore/Example/Tests/Local/FSTLocalStoreTests.mm index 393f77b..5a386b6 100644 --- a/Firestore/Example/Tests/Local/FSTLocalStoreTests.mm +++ b/Firestore/Example/Tests/Local/FSTLocalStoreTests.mm @@ -30,7 +30,6 @@ #import "Firestore/Source/Model/FSTDocumentSet.h" #import "Firestore/Source/Model/FSTMutation.h" #import "Firestore/Source/Model/FSTMutationBatch.h" -#import "Firestore/Source/Model/FSTPath.h" #import "Firestore/Source/Remote/FSTRemoteEvent.h" #import "Firestore/Source/Remote/FSTWatchChange.h" #import "Firestore/Source/Util/FSTClasses.h" @@ -263,7 +262,7 @@ FSTDocumentVersionDictionary *FSTVersionDictionary(FSTMutation *mutation, if ([self isTestBaseClass]) return; // Start a query that requires acks to be held. - FSTQuery *query = FSTTestQuery(@"foo"); + FSTQuery *query = FSTTestQuery("foo"); [self allocateQuery:query]; [self writeMutation:FSTTestSetMutation(@"foo/bar", @{@"foo" : @"bar"})]; @@ -342,7 +341,7 @@ FSTDocumentVersionDictionary *FSTVersionDictionary(FSTMutation *mutation, - (void)testHandlesPatchWithoutPriorDocument { if ([self isTestBaseClass]) return; - [self writeMutation:FSTTestPatchMutation(@"foo/bar", @{@"foo" : @"bar"}, nil)]; + [self writeMutation:FSTTestPatchMutation("foo/bar", @{@"foo" : @"bar"}, {})]; FSTAssertRemoved(@[ @"foo/bar" ]); FSTAssertNotContains(@"foo/bar"); @@ -354,7 +353,7 @@ FSTDocumentVersionDictionary *FSTVersionDictionary(FSTMutation *mutation, - (void)testHandlesPatchMutationThenDocumentThenAck { if ([self isTestBaseClass]) return; - [self writeMutation:FSTTestPatchMutation(@"foo/bar", @{@"foo" : @"bar"}, nil)]; + [self writeMutation:FSTTestPatchMutation("foo/bar", @{@"foo" : @"bar"}, {})]; FSTAssertRemoved(@[ @"foo/bar" ]); FSTAssertNotContains(@"foo/bar"); @@ -371,7 +370,7 @@ FSTDocumentVersionDictionary *FSTVersionDictionary(FSTMutation *mutation, - (void)testHandlesPatchMutationThenAckThenDocument { if ([self isTestBaseClass]) return; - [self writeMutation:FSTTestPatchMutation(@"foo/bar", @{@"foo" : @"bar"}, nil)]; + [self writeMutation:FSTTestPatchMutation("foo/bar", @{@"foo" : @"bar"}, {})]; FSTAssertRemoved(@[ @"foo/bar" ]); FSTAssertNotContains(@"foo/bar"); @@ -456,7 +455,7 @@ FSTDocumentVersionDictionary *FSTVersionDictionary(FSTMutation *mutation, FSTAssertChanged(@[ FSTTestDoc(@"foo/bar", 0, @{@"foo" : @"old"}, YES) ]); FSTAssertContains(FSTTestDoc(@"foo/bar", 0, @{@"foo" : @"old"}, YES)); - [self writeMutation:FSTTestPatchMutation(@"foo/bar", @{@"foo" : @"bar"}, nil)]; + [self writeMutation:FSTTestPatchMutation("foo/bar", @{@"foo" : @"bar"}, {})]; FSTAssertChanged(@[ FSTTestDoc(@"foo/bar", 0, @{@"foo" : @"bar"}, YES) ]); FSTAssertContains(FSTTestDoc(@"foo/bar", 0, @{@"foo" : @"bar"}, YES)); @@ -479,7 +478,7 @@ FSTDocumentVersionDictionary *FSTVersionDictionary(FSTMutation *mutation, [self writeMutations:@[ FSTTestSetMutation(@"foo/bar", @{@"foo" : @"old"}), - FSTTestPatchMutation(@"foo/bar", @{@"foo" : @"bar"}, nil) + FSTTestPatchMutation("foo/bar", @{@"foo" : @"bar"}, {}) ]]; FSTAssertChanged(@[ FSTTestDoc(@"foo/bar", 0, @{@"foo" : @"bar"}, YES) ]); @@ -493,7 +492,7 @@ FSTDocumentVersionDictionary *FSTVersionDictionary(FSTMutation *mutation, [self acknowledgeMutationWithVersion:1]; FSTAssertContains(FSTTestDoc(@"foo/bar", 0, @{@"foo" : @"old"}, NO)); - [self writeMutation:FSTTestPatchMutation(@"foo/bar", @{@"foo" : @"bar"}, nil)]; + [self writeMutation:FSTTestPatchMutation("foo/bar", @{@"foo" : @"bar"}, {})]; FSTAssertContains(FSTTestDoc(@"foo/bar", 0, @{@"foo" : @"bar"}, YES)); [self rejectMutation]; @@ -507,7 +506,7 @@ FSTDocumentVersionDictionary *FSTVersionDictionary(FSTMutation *mutation, [self writeMutations:@[ FSTTestSetMutation(@"foo/bar", @{@"foo" : @"old"}), FSTTestSetMutation(@"bar/baz", @{@"bar" : @"baz"}), - FSTTestPatchMutation(@"foo/bar", @{@"foo" : @"bar"}, nil) + FSTTestPatchMutation("foo/bar", @{@"foo" : @"bar"}, {}) ]]; FSTAssertChanged((@[ @@ -525,7 +524,7 @@ FSTDocumentVersionDictionary *FSTVersionDictionary(FSTMutation *mutation, FSTAssertRemoved(@[ @"foo/bar" ]); FSTAssertContains(FSTTestDeletedDoc(@"foo/bar", 0)); - [self writeMutation:FSTTestPatchMutation(@"foo/bar", @{@"foo" : @"bar"}, nil)]; + [self writeMutation:FSTTestPatchMutation("foo/bar", @{@"foo" : @"bar"}, {})]; FSTAssertRemoved(@[ @"foo/bar" ]); FSTAssertContains(FSTTestDeletedDoc(@"foo/bar", 0)); @@ -556,7 +555,7 @@ FSTDocumentVersionDictionary *FSTVersionDictionary(FSTMutation *mutation, - (void)testCollectsGarbageAfterChangeBatch { if ([self isTestBaseClass]) return; - FSTQuery *query = FSTTestQuery(@"foo"); + FSTQuery *query = FSTTestQuery("foo"); [self allocateQuery:query]; FSTAssertTargetID(2); @@ -577,7 +576,7 @@ FSTDocumentVersionDictionary *FSTVersionDictionary(FSTMutation *mutation, [self applyRemoteEvent:FSTTestUpdateRemoteEvent(FSTTestDoc(@"foo/bar", 0, @{@"foo" : @"old"}, NO), @[ @1 ], @[])]; - [self writeMutation:FSTTestPatchMutation(@"foo/bar", @{@"foo" : @"bar"}, nil)]; + [self writeMutation:FSTTestPatchMutation("foo/bar", @{@"foo" : @"bar"}, {})]; [self writeMutation:FSTTestSetMutation(@"foo/bah", @{@"foo" : @"bah"})]; [self writeMutation:FSTTestDeleteMutation(@"foo/baz")]; [self collectGarbage]; @@ -609,7 +608,7 @@ FSTDocumentVersionDictionary *FSTVersionDictionary(FSTMutation *mutation, [self applyRemoteEvent:FSTTestUpdateRemoteEvent(FSTTestDoc(@"foo/bar", 0, @{@"foo" : @"old"}, NO), @[ @1 ], @[])]; - [self writeMutation:FSTTestPatchMutation(@"foo/bar", @{@"foo" : @"bar"}, nil)]; + [self writeMutation:FSTTestPatchMutation("foo/bar", @{@"foo" : @"bar"}, {})]; [self writeMutation:FSTTestSetMutation(@"foo/bah", @{@"foo" : @"bah"})]; [self writeMutation:FSTTestDeleteMutation(@"foo/baz")]; [self collectGarbage]; @@ -639,7 +638,7 @@ FSTDocumentVersionDictionary *FSTVersionDictionary(FSTMutation *mutation, - (void)testPinsDocumentsInTheLocalView { if ([self isTestBaseClass]) return; - FSTQuery *query = FSTTestQuery(@"foo"); + FSTQuery *query = FSTTestQuery("foo"); [self allocateQuery:query]; FSTAssertTargetID(2); @@ -687,7 +686,7 @@ FSTDocumentVersionDictionary *FSTVersionDictionary(FSTMutation *mutation, FSTTestSetMutation(@"foo/baz", @{@"foo" : @"baz"}), FSTTestSetMutation(@"foo/bar/Foo/Bar", @{@"Foo" : @"Bar"}) ]]; - FSTQuery *query = FSTTestQuery(@"foo/bar"); + FSTQuery *query = FSTTestQuery("foo/bar"); FSTDocumentDictionary *docs = [self.localStore executeQuery:query]; XCTAssertEqualObjects([docs values], @[ FSTTestDoc(@"foo/bar", 0, @{@"foo" : @"bar"}, YES) ]); } @@ -702,7 +701,7 @@ FSTDocumentVersionDictionary *FSTVersionDictionary(FSTMutation *mutation, FSTTestSetMutation(@"foo/bar/Foo/Bar", @{@"Foo" : @"Bar"}), FSTTestSetMutation(@"fooo/blah", @{@"fooo" : @"blah"}) ]]; - FSTQuery *query = FSTTestQuery(@"foo"); + FSTQuery *query = FSTTestQuery("foo"); FSTDocumentDictionary *docs = [self.localStore executeQuery:query]; XCTAssertEqualObjects([docs values], (@[ FSTTestDoc(@"foo/bar", 0, @{@"foo" : @"bar"}, YES), @@ -713,7 +712,7 @@ FSTDocumentVersionDictionary *FSTVersionDictionary(FSTMutation *mutation, - (void)testCanExecuteMixedCollectionQueries { if ([self isTestBaseClass]) return; - FSTQuery *query = FSTTestQuery(@"foo"); + FSTQuery *query = FSTTestQuery("foo"); [self allocateQuery:query]; FSTAssertTargetID(2); @@ -738,7 +737,7 @@ FSTDocumentVersionDictionary *FSTVersionDictionary(FSTMutation *mutation, // This test only works in the absence of the FSTEagerGarbageCollector. [self restartWithNoopGarbageCollector]; - FSTQuery *query = FSTTestQuery(@"foo/bar"); + FSTQuery *query = FSTTestQuery("foo/bar"); FSTQueryData *queryData = [self.localStore allocateQuery:query]; FSTBoxedTargetID *targetID = @(queryData.targetID); NSData *resumeToken = FSTTestResumeTokenFromSnapshotVersion(1000); @@ -772,7 +771,7 @@ FSTDocumentVersionDictionary *FSTVersionDictionary(FSTMutation *mutation, if ([self isTestBaseClass]) return; [self restartWithNoopGarbageCollector]; - FSTQuery *query = FSTTestQuery(@"foo"); + FSTQuery *query = FSTTestQuery("foo"); [self allocateQuery:query]; FSTAssertTargetID(2); diff --git a/Firestore/Example/Tests/Local/FSTMutationQueueTests.mm b/Firestore/Example/Tests/Local/FSTMutationQueueTests.mm index f5294d5..57572ec 100644 --- a/Firestore/Example/Tests/Local/FSTMutationQueueTests.mm +++ b/Firestore/Example/Tests/Local/FSTMutationQueueTests.mm @@ -259,8 +259,8 @@ NS_ASSUME_NONNULL_BEGIN @{ @"a" : @1 }), FSTTestSetMutation(@"foo/bar", @{ @"a" : @1 }), - FSTTestPatchMutation(@"foo/bar", - @{ @"b" : @1 }, nil), + FSTTestPatchMutation("foo/bar", + @{ @"b" : @1 }, {}), FSTTestSetMutation(@"foo/bar/suffix/key", @{ @"a" : @1 }), FSTTestSetMutation(@"foo/baz", @@ -296,8 +296,8 @@ NS_ASSUME_NONNULL_BEGIN @{ @"a" : @1 }), FSTTestSetMutation(@"foo/bar", @{ @"a" : @1 }), - FSTTestPatchMutation(@"foo/bar", - @{ @"b" : @1 }, nil), + FSTTestPatchMutation("foo/bar", + @{ @"b" : @1 }, {}), FSTTestSetMutation(@"foo/bar/suffix/key", @{ @"a" : @1 }), FSTTestSetMutation(@"foo/baz", @@ -319,7 +319,7 @@ NS_ASSUME_NONNULL_BEGIN [self.persistence commitGroup:group]; NSArray *expected = @[ batches[1], batches[2], batches[4] ]; - FSTQuery *query = FSTTestQuery(@"foo"); + FSTQuery *query = FSTTestQuery("foo"); NSArray *matches = [self.mutationQueue allMutationBatchesAffectingQuery:query]; diff --git a/Firestore/Example/Tests/Local/FSTQueryCacheTests.mm b/Firestore/Example/Tests/Local/FSTQueryCacheTests.mm index 5cdfd66..0618e9c 100644 --- a/Firestore/Example/Tests/Local/FSTQueryCacheTests.mm +++ b/Firestore/Example/Tests/Local/FSTQueryCacheTests.mm @@ -39,7 +39,7 @@ NS_ASSUME_NONNULL_BEGIN - (void)setUp { [super setUp]; - _queryRooms = FSTTestQuery(@"rooms"); + _queryRooms = FSTTestQuery("rooms"); _previousSequenceNumber = 1000; _previousTargetID = 500; _previousSnapshotVersion = 100; @@ -76,8 +76,8 @@ NS_ASSUME_NONNULL_BEGIN // Type information is currently lost in our canonicalID implementations so this currently an // easy way to force colliding canonicalIDs - FSTQuery *q1 = [FSTTestQuery(@"a") queryByAddingFilter:FSTTestFilter(@"foo", @"==", @(1))]; - FSTQuery *q2 = [FSTTestQuery(@"a") queryByAddingFilter:FSTTestFilter(@"foo", @"==", @"1")]; + FSTQuery *q1 = [FSTTestQuery("a") queryByAddingFilter:FSTTestFilter("foo", @"==", @(1))]; + FSTQuery *q2 = [FSTTestQuery("a") queryByAddingFilter:FSTTestFilter("foo", @"==", @"1")]; XCTAssertEqualObjects(q1.canonicalID, q2.canonicalID); FSTQueryData *data1 = [self queryDataWithQuery:q1]; @@ -215,14 +215,14 @@ NS_ASSUME_NONNULL_BEGIN [garbageCollector addGarbageSource:self.queryCache]; FSTAssertEqualSets([garbageCollector collectGarbage], @[]); - FSTQueryData *rooms = [self queryDataWithQuery:FSTTestQuery(@"rooms")]; + FSTQueryData *rooms = [self queryDataWithQuery:FSTTestQuery("rooms")]; FSTDocumentKey *room1 = FSTTestDocKey(@"rooms/bar"); FSTDocumentKey *room2 = FSTTestDocKey(@"rooms/foo"); [self addQueryData:rooms]; [self addMatchingKey:room1 forTargetID:rooms.targetID]; [self addMatchingKey:room2 forTargetID:rooms.targetID]; - FSTQueryData *halls = [self queryDataWithQuery:FSTTestQuery(@"halls")]; + FSTQueryData *halls = [self queryDataWithQuery:FSTTestQuery("halls")]; FSTDocumentKey *hall1 = FSTTestDocKey(@"halls/bar"); FSTDocumentKey *hall2 = FSTTestDocKey(@"halls/foo"); [self addQueryData:halls]; @@ -263,12 +263,12 @@ NS_ASSUME_NONNULL_BEGIN - (void)testHighestListenSequenceNumber { if ([self isTestBaseClass]) return; - FSTQueryData *query1 = [[FSTQueryData alloc] initWithQuery:FSTTestQuery(@"rooms") + FSTQueryData *query1 = [[FSTQueryData alloc] initWithQuery:FSTTestQuery("rooms") targetID:1 listenSequenceNumber:10 purpose:FSTQueryPurposeListen]; [self addQueryData:query1]; - FSTQueryData *query2 = [[FSTQueryData alloc] initWithQuery:FSTTestQuery(@"halls") + FSTQueryData *query2 = [[FSTQueryData alloc] initWithQuery:FSTTestQuery("halls") targetID:2 listenSequenceNumber:20 purpose:FSTQueryPurposeListen]; @@ -280,7 +280,7 @@ NS_ASSUME_NONNULL_BEGIN XCTAssertEqual([self.queryCache highestListenSequenceNumber], 20); // A query with an empty result set still counts. - FSTQueryData *query3 = [[FSTQueryData alloc] initWithQuery:FSTTestQuery(@"garages") + FSTQueryData *query3 = [[FSTQueryData alloc] initWithQuery:FSTTestQuery("garages") targetID:42 listenSequenceNumber:100 purpose:FSTQueryPurposeListen]; @@ -305,7 +305,7 @@ NS_ASSUME_NONNULL_BEGIN XCTAssertEqual([self.queryCache highestTargetID], 0); - FSTQueryData *query1 = [[FSTQueryData alloc] initWithQuery:FSTTestQuery(@"rooms") + FSTQueryData *query1 = [[FSTQueryData alloc] initWithQuery:FSTTestQuery("rooms") targetID:1 listenSequenceNumber:10 purpose:FSTQueryPurposeListen]; @@ -315,7 +315,7 @@ NS_ASSUME_NONNULL_BEGIN [self addMatchingKey:key1 forTargetID:1]; [self addMatchingKey:key2 forTargetID:1]; - FSTQueryData *query2 = [[FSTQueryData alloc] initWithQuery:FSTTestQuery(@"halls") + FSTQueryData *query2 = [[FSTQueryData alloc] initWithQuery:FSTTestQuery("halls") targetID:2 listenSequenceNumber:20 purpose:FSTQueryPurposeListen]; @@ -329,7 +329,7 @@ NS_ASSUME_NONNULL_BEGIN XCTAssertEqual([self.queryCache highestTargetID], 2); // A query with an empty result set still counts. - FSTQueryData *query3 = [[FSTQueryData alloc] initWithQuery:FSTTestQuery(@"garages") + FSTQueryData *query3 = [[FSTQueryData alloc] initWithQuery:FSTTestQuery("garages") targetID:42 listenSequenceNumber:100 purpose:FSTQueryPurposeListen]; diff --git a/Firestore/Example/Tests/Local/FSTRemoteDocumentCacheTests.mm b/Firestore/Example/Tests/Local/FSTRemoteDocumentCacheTests.mm index d240604..d056488 100644 --- a/Firestore/Example/Tests/Local/FSTRemoteDocumentCacheTests.mm +++ b/Firestore/Example/Tests/Local/FSTRemoteDocumentCacheTests.mm @@ -112,7 +112,7 @@ static const int kVersion = 42; [self setTestDocumentAtPath:@"b/2"]; [self setTestDocumentAtPath:@"c/1"]; - FSTQuery *query = FSTTestQuery(@"b"); + FSTQuery *query = FSTTestQuery("b"); FSTDocumentDictionary *results = [self.remoteDocumentCache documentsMatchingQuery:query]; NSArray *expected = @[ FSTTestDoc(@"b/1", kVersion, _kDocData, NO), FSTTestDoc(@"b/2", kVersion, _kDocData, NO) ]; diff --git a/Firestore/Example/Tests/Model/FSTDocumentSetTests.mm b/Firestore/Example/Tests/Model/FSTDocumentSetTests.mm index fbaa5d6..d70c44d 100644 --- a/Firestore/Example/Tests/Model/FSTDocumentSetTests.mm +++ b/Firestore/Example/Tests/Model/FSTDocumentSetTests.mm @@ -37,7 +37,7 @@ NS_ASSUME_NONNULL_BEGIN - (void)setUp { [super setUp]; - _comp = FSTTestDocComparator(@"sort"); + _comp = FSTTestDocComparator("sort"); _doc1 = FSTTestDoc(@"docs/1", 0, @{ @"sort" : @2 }, NO); _doc2 = FSTTestDoc(@"docs/2", 0, @{ @"sort" : @3 }, NO); _doc3 = FSTTestDoc(@"docs/3", 0, @{ @"sort" : @1 }, NO); diff --git a/Firestore/Example/Tests/Model/FSTDocumentTests.mm b/Firestore/Example/Tests/Model/FSTDocumentTests.mm index 59f526d..0527852 100644 --- a/Firestore/Example/Tests/Model/FSTDocumentTests.mm +++ b/Firestore/Example/Tests/Model/FSTDocumentTests.mm @@ -21,10 +21,13 @@ #import "Firestore/Source/Core/FSTSnapshotVersion.h" #import "Firestore/Source/Model/FSTDocumentKey.h" #import "Firestore/Source/Model/FSTFieldValue.h" -#import "Firestore/Source/Model/FSTPath.h" #import "Firestore/Example/Tests/Util/FSTHelpers.h" +#include "Firestore/core/test/firebase/firestore/testutil/testutil.h" + +namespace testutil = firebase::firestore::testutil; + NS_ASSUME_NONNULL_BEGIN @interface FSTDocumentTests : XCTestCase @@ -55,9 +58,9 @@ NS_ASSUME_NONNULL_BEGIN FSTDocument *doc = [FSTDocument documentWithData:data key:key version:version hasLocalMutations:NO]; - XCTAssertEqualObjects([doc fieldForPath:FSTTestFieldPath(@"desc")], + XCTAssertEqualObjects([doc fieldForPath:testutil::Field("desc")], [FSTStringValue stringValue:@"Discuss all the project related stuff"]); - XCTAssertEqualObjects([doc fieldForPath:FSTTestFieldPath(@"owner.title")], + XCTAssertEqualObjects([doc fieldForPath:testutil::Field("owner.title")], [FSTStringValue stringValue:@"scallywag"]); } diff --git a/Firestore/Example/Tests/Model/FSTFieldValueTests.mm b/Firestore/Example/Tests/Model/FSTFieldValueTests.mm index 03dfa66..1a207f4 100644 --- a/Firestore/Example/Tests/Model/FSTFieldValueTests.mm +++ b/Firestore/Example/Tests/Model/FSTFieldValueTests.mm @@ -23,14 +23,15 @@ #import "Firestore/Source/API/FIRFirestore+Internal.h" #import "Firestore/Source/API/FSTUserDataConverter.h" #import "Firestore/Source/Model/FSTFieldValue.h" -#import "Firestore/Source/Model/FSTPath.h" #import "Firestore/Example/Tests/API/FSTAPIHelpers.h" #import "Firestore/Example/Tests/Util/FSTHelpers.h" #include "Firestore/core/src/firebase/firestore/model/database_id.h" #include "Firestore/core/src/firebase/firestore/util/string_apple.h" +#include "Firestore/core/test/firebase/firestore/testutil/testutil.h" +namespace testutil = firebase::firestore::testutil; namespace util = firebase::firestore::util; using firebase::firestore::model::DatabaseId; @@ -301,20 +302,20 @@ union DoubleBits { FSTObjectValue *obj = FSTTestObjectValue(@{ @"foo" : @{@"a" : @YES, @"b" : @"string"} }); FSTAssertIsKindOfClass(obj, FSTObjectValue); - FSTAssertIsKindOfClass([obj valueForPath:FSTTestFieldPath(@"foo")], FSTObjectValue); - XCTAssertEqualObjects([obj valueForPath:FSTTestFieldPath(@"foo.a")], [FSTBooleanValue trueValue]); - XCTAssertEqualObjects([obj valueForPath:FSTTestFieldPath(@"foo.b")], + FSTAssertIsKindOfClass([obj valueForPath:testutil::Field("foo")], FSTObjectValue); + XCTAssertEqualObjects([obj valueForPath:testutil::Field("foo.a")], [FSTBooleanValue trueValue]); + XCTAssertEqualObjects([obj valueForPath:testutil::Field("foo.b")], [FSTStringValue stringValue:@"string"]); - XCTAssertNil([obj valueForPath:FSTTestFieldPath(@"foo.a.b")]); - XCTAssertNil([obj valueForPath:FSTTestFieldPath(@"bar")]); - XCTAssertNil([obj valueForPath:FSTTestFieldPath(@"bar.a")]); + XCTAssertNil([obj valueForPath:testutil::Field("foo.a.b")]); + XCTAssertNil([obj valueForPath:testutil::Field("bar")]); + XCTAssertNil([obj valueForPath:testutil::Field("bar.a")]); } - (void)testOverwritesExistingFields { FSTObjectValue *old = FSTTestObjectValue(@{@"a" : @"old"}); FSTObjectValue *mod = - [old objectBySettingValue:FSTTestFieldValue(@"mod") forPath:FSTTestFieldPath(@"a")]; + [old objectBySettingValue:FSTTestFieldValue(@"mod") forPath:testutil::Field("a")]; // Should return a new object, leaving the old one unmodified. XCTAssertNotEqual(old, mod); @@ -325,13 +326,13 @@ union DoubleBits { - (void)testAddsNewFields { FSTObjectValue *empty = [FSTObjectValue objectValue]; FSTObjectValue *mod = - [empty objectBySettingValue:FSTTestFieldValue(@"mod") forPath:FSTTestFieldPath(@"a")]; + [empty objectBySettingValue:FSTTestFieldValue(@"mod") forPath:testutil::Field("a")]; XCTAssertNotEqual(empty, mod); XCTAssertEqualObjects(empty, FSTTestFieldValue(@{})); XCTAssertEqualObjects(mod, FSTTestFieldValue(@{@"a" : @"mod"})); FSTObjectValue *old = mod; - mod = [old objectBySettingValue:FSTTestFieldValue(@1) forPath:FSTTestFieldPath(@"b")]; + mod = [old objectBySettingValue:FSTTestFieldValue(@1) forPath:testutil::Field("b")]; XCTAssertNotEqual(old, mod); XCTAssertEqualObjects(old, FSTTestFieldValue(@{@"a" : @"mod"})); XCTAssertEqualObjects(mod, FSTTestFieldValue(@{ @"a" : @"mod", @"b" : @1 })); @@ -340,7 +341,7 @@ union DoubleBits { - (void)testImplicitlyCreatesObjects { FSTObjectValue *old = FSTTestObjectValue(@{@"a" : @"old"}); FSTObjectValue *mod = - [old objectBySettingValue:FSTTestFieldValue(@"mod") forPath:FSTTestFieldPath(@"b.c.d")]; + [old objectBySettingValue:FSTTestFieldValue(@"mod") forPath:testutil::Field("b.c.d")]; XCTAssertNotEqual(old, mod); XCTAssertEqualObjects(old, FSTTestFieldValue(@{@"a" : @"old"})); XCTAssertEqualObjects(mod, FSTTestFieldValue( @@ -351,7 +352,7 @@ union DoubleBits { - (void)testCanOverwritePrimitivesWithObjects { FSTObjectValue *old = FSTTestObjectValue(@{ @"a" : @{@"b" : @"old"} }); FSTObjectValue *mod = - [old objectBySettingValue:FSTTestFieldValue(@{@"b" : @"mod"}) forPath:FSTTestFieldPath(@"a")]; + [old objectBySettingValue:FSTTestFieldValue(@{@"b" : @"mod"}) forPath:testutil::Field("a")]; XCTAssertNotEqual(old, mod); XCTAssertEqualObjects(old, FSTTestFieldValue(@{ @"a" : @{@"b" : @"old"} })); XCTAssertEqualObjects(mod, FSTTestFieldValue(@{ @"a" : @{@"b" : @"mod"} })); @@ -360,7 +361,7 @@ union DoubleBits { - (void)testAddsToNestedObjects { FSTObjectValue *old = FSTTestObjectValue(@{ @"a" : @{@"b" : @"old"} }); FSTObjectValue *mod = - [old objectBySettingValue:FSTTestFieldValue(@"mod") forPath:FSTTestFieldPath(@"a.c")]; + [old objectBySettingValue:FSTTestFieldValue(@"mod") forPath:testutil::Field("a.c")]; XCTAssertNotEqual(old, mod); XCTAssertEqualObjects(old, FSTTestFieldValue(@{ @"a" : @{@"b" : @"old"} })); XCTAssertEqualObjects(mod, FSTTestFieldValue(@{ @"a" : @{@"b" : @"old", @"c" : @"mod"} })); @@ -368,12 +369,12 @@ union DoubleBits { - (void)testDeletesKeys { FSTObjectValue *old = FSTTestObjectValue(@{ @"a" : @1, @"b" : @2 }); - FSTObjectValue *mod = [old objectByDeletingPath:FSTTestFieldPath(@"a")]; + FSTObjectValue *mod = [old objectByDeletingPath:testutil::Field("a")]; XCTAssertNotEqual(old, mod); XCTAssertEqualObjects(old, FSTTestFieldValue(@{ @"a" : @1, @"b" : @2 })); XCTAssertEqualObjects(mod, FSTTestFieldValue(@{ @"b" : @2 })); - FSTObjectValue *empty = [mod objectByDeletingPath:FSTTestFieldPath(@"b")]; + FSTObjectValue *empty = [mod objectByDeletingPath:testutil::Field("b")]; XCTAssertNotEqual(mod, empty); XCTAssertEqualObjects(mod, FSTTestFieldValue(@{ @"b" : @2 })); XCTAssertEqualObjects(empty, FSTTestFieldValue(@{})); @@ -381,15 +382,15 @@ union DoubleBits { - (void)testDeletesHandleMissingKeys { FSTObjectValue *old = FSTTestObjectValue(@{ @"a" : @{@"b" : @1, @"c" : @2} }); - FSTObjectValue *mod = [old objectByDeletingPath:FSTTestFieldPath(@"b")]; + FSTObjectValue *mod = [old objectByDeletingPath:testutil::Field("b")]; XCTAssertEqualObjects(old, mod); XCTAssertEqualObjects(mod, FSTTestFieldValue(@{ @"a" : @{@"b" : @1, @"c" : @2} })); - mod = [old objectByDeletingPath:FSTTestFieldPath(@"a.d")]; + mod = [old objectByDeletingPath:testutil::Field("a.d")]; XCTAssertEqualObjects(old, mod); XCTAssertEqualObjects(mod, FSTTestFieldValue(@{ @"a" : @{@"b" : @1, @"c" : @2} })); - mod = [old objectByDeletingPath:FSTTestFieldPath(@"a.b.c")]; + mod = [old objectByDeletingPath:testutil::Field("a.b.c")]; XCTAssertEqualObjects(old, mod); XCTAssertEqualObjects(mod, FSTTestFieldValue(@{ @"a" : @{@"b" : @1, @"c" : @2} })); } @@ -397,19 +398,19 @@ union DoubleBits { - (void)testDeletesNestedKeys { FSTObjectValue *old = FSTTestObjectValue( @{ @"a" : @{@"b" : @1, @"c" : @{@"d" : @2, @"e" : @3}} }); - FSTObjectValue *mod = [old objectByDeletingPath:FSTTestFieldPath(@"a.c.d")]; + FSTObjectValue *mod = [old objectByDeletingPath:testutil::Field("a.c.d")]; XCTAssertNotEqual(old, mod); XCTAssertEqualObjects(old, FSTTestFieldValue( @{ @"a" : @{@"b" : @1, @"c" : @{@"d" : @2, @"e" : @3}} })); XCTAssertEqualObjects(mod, FSTTestFieldValue(@{ @"a" : @{@"b" : @1, @"c" : @{@"e" : @3}} })); old = mod; - mod = [old objectByDeletingPath:FSTTestFieldPath(@"a.c")]; + mod = [old objectByDeletingPath:testutil::Field("a.c")]; XCTAssertEqualObjects(old, FSTTestFieldValue(@{ @"a" : @{@"b" : @1, @"c" : @{@"e" : @3}} })); XCTAssertEqualObjects(mod, FSTTestFieldValue(@{ @"a" : @{@"b" : @1} })); old = mod; - mod = [old objectByDeletingPath:FSTTestFieldPath(@"a")]; + mod = [old objectByDeletingPath:testutil::Field("a")]; XCTAssertEqualObjects(old, FSTTestFieldValue(@{ @"a" : @{@"b" : @1} })); XCTAssertEqualObjects(mod, FSTTestFieldValue(@{})); } diff --git a/Firestore/Example/Tests/Model/FSTMutationTests.mm b/Firestore/Example/Tests/Model/FSTMutationTests.mm index 1c1375c..5b056fb 100644 --- a/Firestore/Example/Tests/Model/FSTMutationTests.mm +++ b/Firestore/Example/Tests/Model/FSTMutationTests.mm @@ -22,10 +22,13 @@ #import "Firestore/Source/Model/FSTDocument.h" #import "Firestore/Source/Model/FSTDocumentKey.h" #import "Firestore/Source/Model/FSTFieldValue.h" -#import "Firestore/Source/Model/FSTPath.h" #import "Firestore/Example/Tests/Util/FSTHelpers.h" +#include "Firestore/core/test/firebase/firestore/testutil/testutil.h" + +namespace testutil = firebase::firestore::testutil; + @interface FSTMutationTests : XCTestCase @end @@ -52,8 +55,7 @@ NSDictionary *docData = @{ @"foo" : @{@"bar" : @"bar-value"}, @"baz" : @"baz-value" }; FSTDocument *baseDoc = FSTTestDoc(@"collection/key", 0, docData, NO); - FSTMutation *patch = - FSTTestPatchMutation(@"collection/key", @{@"foo.bar" : @"new-bar-value"}, nil); + FSTMutation *patch = FSTTestPatchMutation("collection/key", @{@"foo.bar" : @"new-bar-value"}, {}); FSTMaybeDocument *patchedDoc = [patch applyTo:baseDoc baseDocument:baseDoc localWriteTime:_timestamp]; @@ -66,7 +68,7 @@ FSTDocument *baseDoc = FSTTestDoc(@"collection/key", 0, docData, NO); FSTDocumentKey *key = FSTTestDocKey(@"collection/key"); - FSTFieldMask *mask = [[FSTFieldMask alloc] initWithFields:@[ FSTTestFieldPath(@"foo.bar") ]]; + FSTFieldMask *mask = [[FSTFieldMask alloc] initWithFields:{testutil::Field("foo.bar")}]; FSTMutation *patch = [[FSTPatchMutation alloc] initWithKey:key fieldMask:mask value:[FSTObjectValue objectValue] @@ -82,8 +84,7 @@ NSDictionary *docData = @{@"foo" : @"foo-value", @"baz" : @"baz-value"}; FSTDocument *baseDoc = FSTTestDoc(@"collection/key", 0, docData, NO); - FSTMutation *patch = - FSTTestPatchMutation(@"collection/key", @{@"foo.bar" : @"new-bar-value"}, nil); + FSTMutation *patch = FSTTestPatchMutation("collection/key", @{@"foo.bar" : @"new-bar-value"}, {}); FSTMaybeDocument *patchedDoc = [patch applyTo:baseDoc baseDocument:baseDoc localWriteTime:_timestamp]; @@ -93,7 +94,7 @@ - (void)testPatchingDeletedDocumentsDoesNothing { FSTMaybeDocument *baseDoc = FSTTestDeletedDoc(@"collection/key", 0); - FSTMutation *patch = FSTTestPatchMutation(@"collection/key", @{@"foo" : @"bar"}, nil); + FSTMutation *patch = FSTTestPatchMutation("collection/key", @{@"foo" : @"bar"}, {}); FSTMaybeDocument *patchedDoc = [patch applyTo:baseDoc baseDocument:baseDoc localWriteTime:_timestamp]; XCTAssertEqualObjects(patchedDoc, baseDoc); @@ -115,7 +116,7 @@ [expectedData objectBySettingValue:[FSTServerTimestampValue serverTimestampValueWithLocalWriteTime:_timestamp previousValue:nil] - forPath:FSTTestFieldPath(@"foo.bar")]; + forPath:testutil::Field("foo.bar")]; FSTDocument *expectedDoc = [FSTDocument documentWithData:expectedData key:FSTTestDocKey(@"collection/key") @@ -176,7 +177,7 @@ NSDictionary *docData = @{@"foo" : @"bar"}; FSTDocument *baseDoc = FSTTestDoc(@"collection/key", 0, docData, NO); - FSTMutation *patch = FSTTestPatchMutation(@"collection/key", @{@"foo" : @"new-bar"}, nil); + FSTMutation *patch = FSTTestPatchMutation("collection/key", @{@"foo" : @"new-bar"}, {}); FSTMutationResult *mutationResult = [[FSTMutationResult alloc] initWithVersion:FSTTestVersion(4) transformResults:nil]; FSTMaybeDocument *patchedDoc = [patch applyTo:baseDoc @@ -210,7 +211,7 @@ FSTDeletedDocument *deletedV3 = FSTTestDeletedDoc(@"collection/key", 3); FSTMutation *setMutation = FSTTestSetMutation(@"collection/key", @{}); - FSTMutation *patchMutation = FSTTestPatchMutation(@"collection/key", @{}, nil); + FSTMutation *patchMutation = FSTTestPatchMutation("collection/key", {}, {}); FSTMutation *deleteMutation = FSTTestDeleteMutation(@"collection/key"); ASSERT_VERSION_TRANSITION(setMutation, docV3, docV3); diff --git a/Firestore/Example/Tests/Model/FSTPathTests.mm b/Firestore/Example/Tests/Model/FSTPathTests.mm deleted file mode 100644 index 388c5c3..0000000 --- a/Firestore/Example/Tests/Model/FSTPathTests.mm +++ /dev/null @@ -1,224 +0,0 @@ -/* - * Copyright 2017 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/Example/Tests/Util/FSTHelpers.h" -#import "Firestore/Source/Model/FSTPath.h" - -#import - -NS_ASSUME_NONNULL_BEGIN - -@interface FSTFieldPathTests : XCTestCase -@end - -@implementation FSTFieldPathTests - -- (void)testConstructor { - FSTFieldPath *path = [FSTFieldPath pathWithSegments:@[ @"rooms", @"Eros", @"messages" ]]; - XCTAssertEqual(3, path.length); -} - -- (void)testIndexing { - FSTFieldPath *path = [FSTFieldPath pathWithSegments:@[ @"rooms", @"Eros", @"messages" ]]; - XCTAssertEqualObjects(@"rooms", path.firstSegment); - XCTAssertEqualObjects(@"rooms", [path segmentAtIndex:0]); - XCTAssertEqualObjects(@"rooms", path[0]); - - XCTAssertEqualObjects(@"Eros", [path segmentAtIndex:1]); - XCTAssertEqualObjects(@"Eros", path[1]); - - XCTAssertEqualObjects(@"messages", [path segmentAtIndex:2]); - XCTAssertEqualObjects(@"messages", path[2]); - XCTAssertEqualObjects(@"messages", path.lastSegment); -} - -- (void)testPathByRemovingFirstSegment { - FSTFieldPath *path = [FSTFieldPath pathWithSegments:@[ @"rooms", @"Eros", @"messages" ]]; - FSTFieldPath *same = [FSTFieldPath pathWithSegments:@[ @"rooms", @"Eros", @"messages" ]]; - FSTFieldPath *second = [FSTFieldPath pathWithSegments:@[ @"Eros", @"messages" ]]; - FSTFieldPath *third = [FSTFieldPath pathWithSegments:@[ @"messages" ]]; - FSTFieldPath *empty = [FSTFieldPath pathWithSegments:@[]]; - - XCTAssertEqualObjects(second, path.pathByRemovingFirstSegment); - XCTAssertEqualObjects(third, path.pathByRemovingFirstSegment.pathByRemovingFirstSegment); - XCTAssertEqualObjects( - empty, path.pathByRemovingFirstSegment.pathByRemovingFirstSegment.pathByRemovingFirstSegment); - // unmodified original - XCTAssertEqualObjects(same, path); -} - -- (void)testPathByRemovingLastSegment { - FSTFieldPath *path = [FSTFieldPath pathWithSegments:@[ @"rooms", @"Eros", @"messages" ]]; - FSTFieldPath *same = [FSTFieldPath pathWithSegments:@[ @"rooms", @"Eros", @"messages" ]]; - FSTFieldPath *second = [FSTFieldPath pathWithSegments:@[ @"rooms", @"Eros" ]]; - FSTFieldPath *third = [FSTFieldPath pathWithSegments:@[ @"rooms" ]]; - FSTFieldPath *empty = [FSTFieldPath pathWithSegments:@[]]; - - XCTAssertEqualObjects(second, path.pathByRemovingLastSegment); - XCTAssertEqualObjects(third, path.pathByRemovingLastSegment.pathByRemovingLastSegment); - XCTAssertEqualObjects( - empty, path.pathByRemovingLastSegment.pathByRemovingLastSegment.pathByRemovingLastSegment); - // unmodified original - XCTAssertEqualObjects(same, path); -} - -- (void)testPathByAppendingSegment { - FSTFieldPath *path = [FSTFieldPath pathWithSegments:@[ @"rooms" ]]; - FSTFieldPath *rooms = [FSTFieldPath pathWithSegments:@[ @"rooms" ]]; - FSTFieldPath *roomsEros = [FSTFieldPath pathWithSegments:@[ @"rooms", @"eros" ]]; - FSTFieldPath *roomsEros1 = [FSTFieldPath pathWithSegments:@[ @"rooms", @"eros", @"1" ]]; - - XCTAssertEqualObjects(roomsEros, [path pathByAppendingSegment:@"eros"]); - XCTAssertEqualObjects(roomsEros1, - [[path pathByAppendingSegment:@"eros"] pathByAppendingSegment:@"1"]); - // unmodified original - XCTAssertEqualObjects(rooms, path); - - FSTFieldPath *sub = [FSTTestFieldPath(@"rooms.eros.1") pathByRemovingFirstSegment]; - FSTFieldPath *appended = [sub pathByAppendingSegment:@"2"]; - XCTAssertEqualObjects(appended, FSTTestFieldPath(@"eros.1.2")); -} - -- (void)testPathComparison { - FSTFieldPath *path1 = [FSTFieldPath pathWithSegments:@[ @"a", @"b", @"c" ]]; - FSTFieldPath *path2 = [FSTFieldPath pathWithSegments:@[ @"a", @"b", @"c" ]]; - FSTFieldPath *path3 = [FSTFieldPath pathWithSegments:@[ @"x", @"y", @"z" ]]; - XCTAssertTrue([path1 isEqual:path2]); - XCTAssertFalse([path1 isEqual:path3]); - - FSTFieldPath *empty = [FSTFieldPath pathWithSegments:@[]]; - FSTFieldPath *a = [FSTFieldPath pathWithSegments:@[ @"a" ]]; - FSTFieldPath *b = [FSTFieldPath pathWithSegments:@[ @"b" ]]; - FSTFieldPath *ab = [FSTFieldPath pathWithSegments:@[ @"a", @"b" ]]; - - XCTAssertEqual(NSOrderedAscending, [empty compare:a]); - XCTAssertEqual(NSOrderedAscending, [a compare:b]); - XCTAssertEqual(NSOrderedAscending, [a compare:ab]); - - XCTAssertEqual(NSOrderedDescending, [a compare:empty]); - XCTAssertEqual(NSOrderedDescending, [b compare:a]); - XCTAssertEqual(NSOrderedDescending, [ab compare:a]); -} - -- (void)testIsPrefixOfPath { - FSTFieldPath *empty = [FSTFieldPath pathWithSegments:@[]]; - FSTFieldPath *a = [FSTFieldPath pathWithSegments:@[ @"a" ]]; - FSTFieldPath *ab = [FSTFieldPath pathWithSegments:@[ @"a", @"b" ]]; - FSTFieldPath *abc = [FSTFieldPath pathWithSegments:@[ @"a", @"b", @"c" ]]; - FSTFieldPath *b = [FSTFieldPath pathWithSegments:@[ @"b" ]]; - FSTFieldPath *ba = [FSTFieldPath pathWithSegments:@[ @"b", @"a" ]]; - - XCTAssertTrue([empty isPrefixOfPath:a]); - XCTAssertTrue([empty isPrefixOfPath:ab]); - XCTAssertTrue([empty isPrefixOfPath:abc]); - XCTAssertTrue([empty isPrefixOfPath:empty]); - XCTAssertTrue([empty isPrefixOfPath:b]); - XCTAssertTrue([empty isPrefixOfPath:ba]); - - XCTAssertTrue([a isPrefixOfPath:a]); - XCTAssertTrue([a isPrefixOfPath:ab]); - XCTAssertTrue([a isPrefixOfPath:abc]); - XCTAssertFalse([a isPrefixOfPath:empty]); - XCTAssertFalse([a isPrefixOfPath:b]); - XCTAssertFalse([a isPrefixOfPath:ba]); - - XCTAssertFalse([ab isPrefixOfPath:a]); - XCTAssertTrue([ab isPrefixOfPath:ab]); - XCTAssertTrue([ab isPrefixOfPath:abc]); - XCTAssertFalse([ab isPrefixOfPath:empty]); - XCTAssertFalse([ab isPrefixOfPath:b]); - XCTAssertFalse([ab isPrefixOfPath:ba]); - - XCTAssertFalse([abc isPrefixOfPath:a]); - XCTAssertFalse([abc isPrefixOfPath:ab]); - XCTAssertTrue([abc isPrefixOfPath:abc]); - XCTAssertFalse([abc isPrefixOfPath:empty]); - XCTAssertFalse([abc isPrefixOfPath:b]); - XCTAssertFalse([abc isPrefixOfPath:ba]); -} - -- (void)testInvalidPaths { - XCTAssertThrows(FSTTestFieldPath(@"")); - XCTAssertThrows(FSTTestFieldPath(@".")); - XCTAssertThrows(FSTTestFieldPath(@".foo")); - XCTAssertThrows(FSTTestFieldPath(@"foo.")); - XCTAssertThrows(FSTTestFieldPath(@"foo..bar")); -} - -#define ASSERT_ROUND_TRIP(str, segments) \ - do { \ - FSTFieldPath *path = [FSTFieldPath pathWithServerFormat:str]; \ - XCTAssertEqual([path length], segments); \ - NSString *canonical = [path canonicalString]; \ - XCTAssertEqualObjects(canonical, str); \ - } while (0); - -- (void)testCanonicalString { - ASSERT_ROUND_TRIP(@"foo", 1); - ASSERT_ROUND_TRIP(@"foo.bar", 2); - ASSERT_ROUND_TRIP(@"foo.bar.baz", 3); - ASSERT_ROUND_TRIP(@"`.foo\\\\`", 1); - ASSERT_ROUND_TRIP(@"`.foo\\\\`.`.foo`", 2); - ASSERT_ROUND_TRIP(@"foo.`\\``.bar", 3); - - FSTFieldPath *path = [FSTFieldPath pathWithServerFormat:@"foo\\.bar"]; - XCTAssertEqualObjects([path canonicalString], @"`foo.bar`"); - XCTAssertEqual(path.length, 1); -} - -#undef ASSERT_ROUND_TRIP - -- (void)testCanonicalStringOfSubstring { - FSTFieldPath *path = [FSTFieldPath pathWithServerFormat:@"foo.bar.baz"]; - XCTAssertEqualObjects([path canonicalString], @"foo.bar.baz"); - - FSTFieldPath *pathTail = [path pathByRemovingFirstSegment]; - XCTAssertEqualObjects([pathTail canonicalString], @"bar.baz"); - - FSTFieldPath *pathHead = [path pathByRemovingLastSegment]; - XCTAssertEqualObjects([pathHead canonicalString], @"foo.bar"); - - XCTAssertEqualObjects([[pathTail pathByRemovingLastSegment] canonicalString], @"bar"); - XCTAssertEqualObjects([[pathHead pathByRemovingFirstSegment] canonicalString], @"bar"); -} - -- (void)testRoundTrip { - FSTFieldPath *path = [FSTFieldPath pathWithSegments:@[ @"rooms", @"Eros", @"messages" ]]; - XCTAssertEqualObjects(path, [FSTFieldPath fieldPathWithCPPFieldPath:[path toCPPFieldPath]]); - - const firebase::firestore::model::FieldPath cppPath{"rooms", "Eros", "messages"}; - XCTAssertEqual(cppPath, [[FSTFieldPath fieldPathWithCPPFieldPath:cppPath] toCPPFieldPath]); -} - -@end - -@interface FSTResourcePathTests : XCTestCase -@end - -@implementation FSTResourcePathTests - -- (void)testRoundTrip { - FSTResourcePath *path = [FSTResourcePath pathWithSegments:@[ @"rooms", @"Eros", @"messages" ]]; - XCTAssertEqualObjects(path, - [FSTResourcePath resourcePathWithCPPResourcePath:[path toCPPResourcePath]]); - - const firebase::firestore::model::ResourcePath cppPath{"rooms", "Eros", "messages"}; - XCTAssertEqual(cppPath, - [[FSTResourcePath resourcePathWithCPPResourcePath:cppPath] toCPPResourcePath]); -} - -@end -NS_ASSUME_NONNULL_END diff --git a/Firestore/Example/Tests/Remote/FSTSerializerBetaTests.mm b/Firestore/Example/Tests/Remote/FSTSerializerBetaTests.mm index 5cd816f..4c3682f 100644 --- a/Firestore/Example/Tests/Remote/FSTSerializerBetaTests.mm +++ b/Firestore/Example/Tests/Remote/FSTSerializerBetaTests.mm @@ -40,7 +40,6 @@ #import "Firestore/Source/Model/FSTFieldValue.h" #import "Firestore/Source/Model/FSTMutation.h" #import "Firestore/Source/Model/FSTMutationBatch.h" -#import "Firestore/Source/Model/FSTPath.h" #import "Firestore/Source/Remote/FSTWatchChange.h" #import "Firestore/Example/Tests/API/FSTAPIHelpers.h" @@ -338,11 +337,11 @@ NS_ASSUME_NONNULL_BEGIN - (void)testEncodesPatchMutation { FSTPatchMutation *mutation = - FSTTestPatchMutation(@"docs/1", + FSTTestPatchMutation("docs/1", @{ @"a" : @"b", @"num" : @1, @"some.de\\\\ep.th\\ing'" : @2 }, - nil); + {}); GCFSWrite *proto = [GCFSWrite message]; proto.update = [self.serializer encodedDocumentWithFields:mutation.value key:mutation.key]; proto.updateMask = [self.serializer encodedFieldMask:mutation.fieldMask]; @@ -406,7 +405,7 @@ NS_ASSUME_NONNULL_BEGIN } - (void)testEncodesListenRequestLabels { - FSTQuery *query = FSTTestQuery(@"collection/key"); + FSTQuery *query = FSTTestQuery("collection/key"); FSTQueryData *queryData = [[FSTQueryData alloc] initWithQuery:query targetID:2 listenSequenceNumber:3 @@ -432,7 +431,7 @@ NS_ASSUME_NONNULL_BEGIN } - (void)testEncodesRelationFilter { - FSTRelationFilter *input = FSTTestFilter(@"item.part.top", @"==", @"food"); + FSTRelationFilter *input = FSTTestFilter("item.part.top", @"==", @"food"); GCFSStructuredQuery_Filter *actual = [self.serializer encodedRelationFilter:input]; GCFSStructuredQuery_Filter *expected = [GCFSStructuredQuery_Filter message]; @@ -446,7 +445,7 @@ NS_ASSUME_NONNULL_BEGIN #pragma mark - encodedQuery - (void)testEncodesFirstLevelKeyQueries { - FSTQuery *q = FSTTestQuery(@"docs/1"); + FSTQuery *q = FSTTestQuery("docs/1"); FSTQueryData *model = [self queryDataForQuery:q]; GCFSTarget *expected = [GCFSTarget message]; @@ -457,7 +456,7 @@ NS_ASSUME_NONNULL_BEGIN } - (void)testEncodesFirstLevelAncestorQueries { - FSTQuery *q = FSTTestQuery(@"messages"); + FSTQuery *q = FSTTestQuery("messages"); FSTQueryData *model = [self queryDataForQuery:q]; GCFSTarget *expected = [GCFSTarget message]; @@ -473,7 +472,7 @@ NS_ASSUME_NONNULL_BEGIN } - (void)testEncodesNestedAncestorQueries { - FSTQuery *q = FSTTestQuery(@"rooms/1/messages/10/attachments"); + FSTQuery *q = FSTTestQuery("rooms/1/messages/10/attachments"); FSTQueryData *model = [self queryDataForQuery:q]; GCFSTarget *expected = [GCFSTarget message]; @@ -489,7 +488,7 @@ NS_ASSUME_NONNULL_BEGIN } - (void)testEncodesSingleFiltersAtFirstLevelCollections { - FSTQuery *q = [FSTTestQuery(@"docs") queryByAddingFilter:FSTTestFilter(@"prop", @"<", @(42))]; + FSTQuery *q = [FSTTestQuery("docs") queryByAddingFilter:FSTTestFilter("prop", @"<", @(42))]; FSTQueryData *model = [self queryDataForQuery:q]; GCFSTarget *expected = [GCFSTarget message]; @@ -512,9 +511,9 @@ NS_ASSUME_NONNULL_BEGIN } - (void)testEncodesMultipleFiltersOnDeeperCollections { - FSTQuery *q = [[FSTTestQuery(@"rooms/1/messages/10/attachments") - queryByAddingFilter:FSTTestFilter(@"prop", @">=", @(42))] - queryByAddingFilter:FSTTestFilter(@"author", @"==", @"dimond")]; + FSTQuery *q = [[FSTTestQuery("rooms/1/messages/10/attachments") + queryByAddingFilter:FSTTestFilter("prop", @">=", @(42))] + queryByAddingFilter:FSTTestFilter("author", @"==", @"dimond")]; FSTQueryData *model = [self queryDataForQuery:q]; GCFSTarget *expected = [GCFSTarget message]; @@ -562,7 +561,7 @@ NS_ASSUME_NONNULL_BEGIN - (void)unaryFilterTestWithValue:(id)value expectedUnaryOperator:(GCFSStructuredQuery_UnaryFilter_Operator)op { - FSTQuery *q = [FSTTestQuery(@"docs") queryByAddingFilter:FSTTestFilter(@"prop", @"==", value)]; + FSTQuery *q = [FSTTestQuery("docs") queryByAddingFilter:FSTTestFilter("prop", @"==", value)]; FSTQueryData *model = [self queryDataForQuery:q]; GCFSTarget *expected = [GCFSTarget message]; @@ -582,7 +581,7 @@ NS_ASSUME_NONNULL_BEGIN } - (void)testEncodesSortOrders { - FSTQuery *q = [FSTTestQuery(@"docs") + FSTQuery *q = [FSTTestQuery("docs") queryByAddingSortOrder:[FSTSortOrder sortOrderWithFieldPath:testutil::Field("prop") ascending:YES]]; FSTQueryData *model = [self queryDataForQuery:q]; @@ -602,7 +601,7 @@ NS_ASSUME_NONNULL_BEGIN } - (void)testEncodesSortOrdersDescending { - FSTQuery *q = [FSTTestQuery(@"rooms/1/messages/10/attachments") + FSTQuery *q = [FSTTestQuery("rooms/1/messages/10/attachments") queryByAddingSortOrder:[FSTSortOrder sortOrderWithFieldPath:testutil::Field("prop") ascending:NO]]; FSTQueryData *model = [self queryDataForQuery:q]; @@ -622,7 +621,7 @@ NS_ASSUME_NONNULL_BEGIN } - (void)testEncodesLimits { - FSTQuery *q = [FSTTestQuery(@"docs") queryBySettingLimit:26]; + FSTQuery *q = [FSTTestQuery("docs") queryBySettingLimit:26]; FSTQueryData *model = [self queryDataForQuery:q]; GCFSTarget *expected = [GCFSTarget message]; @@ -639,7 +638,7 @@ NS_ASSUME_NONNULL_BEGIN } - (void)testEncodesResumeTokens { - FSTQuery *q = FSTTestQuery(@"docs"); + FSTQuery *q = FSTTestQuery("docs"); FSTQueryData *model = [[FSTQueryData alloc] initWithQuery:q targetID:1 listenSequenceNumber:0 diff --git a/Firestore/Example/Tests/SpecTests/FSTSpecTests.mm b/Firestore/Example/Tests/SpecTests/FSTSpecTests.mm index b00ea07..0f57b81 100644 --- a/Firestore/Example/Tests/SpecTests/FSTSpecTests.mm +++ b/Firestore/Example/Tests/SpecTests/FSTSpecTests.mm @@ -16,6 +16,8 @@ #import "Firestore/Example/Tests/SpecTests/FSTSpecTests.h" +#include + #import #import @@ -30,7 +32,6 @@ #import "Firestore/Source/Model/FSTDocumentKey.h" #import "Firestore/Source/Model/FSTFieldValue.h" #import "Firestore/Source/Model/FSTMutation.h" -#import "Firestore/Source/Model/FSTPath.h" #import "Firestore/Source/Remote/FSTExistenceFilter.h" #import "Firestore/Source/Remote/FSTWatchChange.h" #import "Firestore/Source/Util/FSTAssert.h" @@ -108,11 +109,11 @@ static NSString *const kNoIOSTag = @"no-ios"; - (nullable FSTQuery *)parseQuery:(id)querySpec { if ([querySpec isKindOfClass:[NSString class]]) { - return FSTTestQuery(querySpec); + return FSTTestQuery(util::MakeStringView((NSString *)querySpec)); } else if ([querySpec isKindOfClass:[NSDictionary class]]) { NSDictionary *queryDict = (NSDictionary *)querySpec; NSString *path = queryDict[@"path"]; - __block FSTQuery *query = FSTTestQuery(path); + __block FSTQuery *query = FSTTestQuery(util::MakeStringView(path)); if (queryDict[@"limit"]) { NSNumber *limit = queryDict[@"limit"]; query = [query queryBySettingLimit:limit.integerValue]; @@ -121,14 +122,16 @@ static NSString *const kNoIOSTag = @"no-ios"; NSArray *filters = queryDict[@"filters"]; [filters enumerateObjectsUsingBlock:^(NSArray *_Nonnull filter, NSUInteger idx, BOOL *_Nonnull stop) { - query = [query queryByAddingFilter:FSTTestFilter(filter[0], filter[1], filter[2])]; + query = [query queryByAddingFilter:FSTTestFilter(util::MakeStringView(filter[0]), filter[1], + filter[2])]; }]; } if (queryDict[@"orderBys"]) { NSArray *orderBys = queryDict[@"orderBys"]; [orderBys enumerateObjectsUsingBlock:^(NSArray *_Nonnull orderBy, NSUInteger idx, BOOL *_Nonnull stop) { - query = [query queryByAddingSortOrder:FSTTestOrderBy(orderBy[0], orderBy[1])]; + query = [query + queryByAddingSortOrder:FSTTestOrderBy(util::MakeStringView(orderBy[0]), orderBy[1])]; }]; } return query; @@ -174,7 +177,8 @@ static NSString *const kNoIOSTag = @"no-ios"; } - (void)doPatch:(NSArray *)patchSpec { - [self.driver writeUserMutation:FSTTestPatchMutation(patchSpec[0], patchSpec[1], nil)]; + [self.driver + writeUserMutation:FSTTestPatchMutation(util::MakeStringView(patchSpec[0]), patchSpec[1], {})]; } - (void)doDelete:(NSString *)key { diff --git a/Firestore/Example/Tests/Util/FSTHelpers.h b/Firestore/Example/Tests/Util/FSTHelpers.h index cc9f2ec..d86201b 100644 --- a/Firestore/Example/Tests/Util/FSTHelpers.h +++ b/Firestore/Example/Tests/Util/FSTHelpers.h @@ -16,10 +16,16 @@ #import +#include +#include + #import "Firestore/Source/Core/FSTTypes.h" #import "Firestore/Source/Model/FSTDocumentDictionary.h" #import "Firestore/Source/Model/FSTDocumentKeySet.h" +#include "Firestore/core/src/firebase/firestore/model/field_path.h" +#include "Firestore/core/src/firebase/firestore/model/field_value.h" +#include "Firestore/core/src/firebase/firestore/model/resource_path.h" #include "absl/strings/string_view.h" @class FIRGeoPoint; @@ -28,13 +34,11 @@ @class FSTDocument; @class FSTDocumentKeyReference; @class FSTDocumentSet; -@class FSTFieldPath; @class FSTFieldValue; @class FSTLocalViewChanges; @class FSTPatchMutation; @class FSTQuery; @class FSTRemoteEvent; -@class FSTResourcePath; @class FSTSetMutation; @class FSTSnapshotVersion; @class FSTSortOrder; @@ -121,18 +125,30 @@ extern "C" { } \ } while (0) +static NSString *kExceptionPrefix = @"FIRESTORE INTERNAL ASSERTION FAILED: "; + +// Remove possible exception-prefix. +inline NSString *FSTRemoveExceptionPrefix(NSString *exception) { + if ([exception hasPrefix:kExceptionPrefix]) { + return [exception substringFromIndex:kExceptionPrefix.length]; + } else { + return exception; + } +} + // Helper for validating API exceptions. -#define FSTAssertThrows(expression, exceptionReason, ...) \ - ({ \ - BOOL __didThrow = NO; \ - @try { \ - (void)(expression); \ - } @catch (NSException * exception) { \ - __didThrow = YES; \ - XCTAssertEqualObjects(exception.reason, exceptionReason); \ - } \ - XCTAssertTrue(__didThrow, ##__VA_ARGS__); \ - }) +#define FSTAssertThrows(expression, exceptionReason, ...) \ + do { \ + BOOL didThrow = NO; \ + @try { \ + (void)(expression); \ + } @catch (NSException * exception) { \ + didThrow = YES; \ + XCTAssertEqualObjects(FSTRemoveExceptionPrefix(exception.reason), \ + FSTRemoveExceptionPrefix(exceptionReason)); \ + } \ + XCTAssertTrue(didThrow, ##__VA_ARGS__); \ + } while (0) /** Creates a new FIRTimestamp from components. Note that year, month, and day are all one-based. */ FIRTimestamp *FSTTestTimestamp(int year, int month, int day, int hour, int minute, int second); @@ -157,8 +173,6 @@ FIRGeoPoint *FSTTestGeoPoint(double latitude, double longitude); NSDateComponents *FSTTestDateComponents( int year, int month, int day, int hour, int minute, int second); -FSTFieldPath *FSTTestFieldPath(NSString *field); - /** Wraps a plain value into an FSTFieldValue instance. */ FSTFieldValue *FSTTestFieldValue(id _Nullable value); @@ -186,9 +200,6 @@ FSTDocument *FSTTestDoc(NSString *path, /** A convenience method for creating deleted docs for tests. */ FSTDeletedDocument *FSTTestDeletedDoc(NSString *path, FSTTestSnapshotVersion version); -/** A convenience method for creating resource paths from a path string. */ -FSTResourcePath *FSTTestPath(NSString *path); - /** * A convenience method for creating a document reference from a path string. */ @@ -197,22 +208,22 @@ FSTDocumentKeyReference *FSTTestRef(const absl::string_view projectID, NSString *path); /** A convenience method for creating a query for the given path (without any other filters). */ -FSTQuery *FSTTestQuery(NSString *path); +FSTQuery *FSTTestQuery(const absl::string_view path); /** * A convenience method to create a FSTFilter using a string representation for both field * and operator (<, <=, ==, >=, >). */ -id FSTTestFilter(NSString *field, NSString *op, id value); +id FSTTestFilter(const absl::string_view field, NSString *op, id value); /** A convenience method for creating sort orders. */ -FSTSortOrder *FSTTestOrderBy(NSString *field, NSString *direction); +FSTSortOrder *FSTTestOrderBy(const absl::string_view field, NSString *direction); /** * Creates an NSComparator that will compare FSTDocuments by the given fieldPath string then by * key. */ -NSComparator FSTTestDocComparator(NSString *fieldPath); +NSComparator FSTTestDocComparator(const absl::string_view fieldPath); /** * Creates a FSTDocumentSet based on the given comparator, initially containing the given @@ -229,9 +240,10 @@ FSTViewSnapshot *_Nullable FSTTestApplyChanges(FSTView *view, FSTSetMutation *FSTTestSetMutation(NSString *path, NSDictionary *values); /** Creates a patch mutation for the document key at the given path. */ -FSTPatchMutation *FSTTestPatchMutation(NSString *path, - NSDictionary *values, - NSArray *_Nullable updateMask); +FSTPatchMutation *FSTTestPatchMutation( + const absl::string_view path, + NSDictionary *values, + const std::vector &updateMask); FSTTransformMutation *FSTTestTransformMutation(NSString *path, NSArray *serverTimestampFields); diff --git a/Firestore/Example/Tests/Util/FSTHelpers.mm b/Firestore/Example/Tests/Util/FSTHelpers.mm index 00464bc..be02002 100644 --- a/Firestore/Example/Tests/Util/FSTHelpers.mm +++ b/Firestore/Example/Tests/Util/FSTHelpers.mm @@ -18,6 +18,8 @@ #include #include +#include +#include #import #import @@ -36,18 +38,22 @@ #import "Firestore/Source/Model/FSTDocumentSet.h" #import "Firestore/Source/Model/FSTFieldValue.h" #import "Firestore/Source/Model/FSTMutation.h" -#import "Firestore/Source/Model/FSTPath.h" #import "Firestore/Source/Remote/FSTRemoteEvent.h" #import "Firestore/Source/Remote/FSTWatchChange.h" #import "Firestore/Source/Util/FSTAssert.h" #include "Firestore/core/src/firebase/firestore/model/database_id.h" +#include "Firestore/core/src/firebase/firestore/model/field_value.h" +#include "Firestore/core/src/firebase/firestore/model/resource_path.h" #include "Firestore/core/src/firebase/firestore/util/string_apple.h" #include "Firestore/core/test/firebase/firestore/testutil/testutil.h" namespace util = firebase::firestore::util; namespace testutil = firebase::firestore::testutil; using firebase::firestore::model::DatabaseId; +using firebase::firestore::model::FieldPath; +using firebase::firestore::model::FieldValue; +using firebase::firestore::model::ResourcePath; NS_ASSUME_NONNULL_BEGIN @@ -103,10 +109,6 @@ NSDateComponents *FSTTestDateComponents( return comps; } -FSTFieldPath *FSTTestFieldPath(NSString *field) { - return [FIRFieldPath pathWithDotSeparatedString:field].internalValue; -} - FSTFieldValue *FSTTestFieldValue(id _Nullable value) { // This owns the DatabaseIds since we do not have FirestoreClient instance to own them. static DatabaseId database_id{"project", DatabaseId::kDefault}; @@ -162,18 +164,6 @@ FSTDeletedDocument *FSTTestDeletedDoc(NSString *path, FSTTestSnapshotVersion ver return [FSTDeletedDocument documentWithKey:key version:FSTTestVersion(version)]; } -static NSArray *FSTTestSplitPath(NSString *path) { - if ([path isEqualToString:@""]) { - return @[]; - } else { - return [path componentsSeparatedByString:@"/"]; - } -} - -FSTResourcePath *FSTTestPath(NSString *path) { - return [FSTResourcePath pathWithSegments:FSTTestSplitPath(path)]; -} - FSTDocumentKeyReference *FSTTestRef(const absl::string_view projectID, const absl::string_view database, NSString *path) { @@ -184,12 +174,12 @@ FSTDocumentKeyReference *FSTTestRef(const absl::string_view projectID, databaseID:&database_ids.back()]; } -FSTQuery *FSTTestQuery(NSString *path) { - return [FSTQuery queryWithPath:[FSTTestPath(path) toCPPResourcePath]]; +FSTQuery *FSTTestQuery(const absl::string_view path) { + return [FSTQuery queryWithPath:testutil::Resource(path)]; } -id FSTTestFilter(NSString *field, NSString *opString, id value) { - FSTFieldPath *path = FSTTestFieldPath(field); +id FSTTestFilter(const absl::string_view field, NSString *opString, id value) { + const FieldPath path = testutil::Field(field); FSTRelationFilterOperator op; if ([opString isEqualToString:@"<"]) { op = FSTRelationFilterOperatorLessThan; @@ -208,17 +198,17 @@ id FSTTestFilter(NSString *field, NSString *opString, id value) { FSTFieldValue *data = FSTTestFieldValue(value); if ([data isEqual:[FSTDoubleValue nanValue]]) { FSTCAssert(op == FSTRelationFilterOperatorEqual, @"Must use == with NAN."); - return [[FSTNanFilter alloc] initWithField:[path toCPPFieldPath]]; + return [[FSTNanFilter alloc] initWithField:path]; } else if ([data isEqual:[FSTNullValue nullValue]]) { FSTCAssert(op == FSTRelationFilterOperatorEqual, @"Must use == with Null."); - return [[FSTNullFilter alloc] initWithField:[path toCPPFieldPath]]; + return [[FSTNullFilter alloc] initWithField:path]; } else { - return [FSTRelationFilter filterWithField:[path toCPPFieldPath] filterOperator:op value:data]; + return [FSTRelationFilter filterWithField:path filterOperator:op value:data]; } } -FSTSortOrder *FSTTestOrderBy(NSString *field, NSString *direction) { - FSTFieldPath *path = FSTTestFieldPath(field); +FSTSortOrder *FSTTestOrderBy(const absl::string_view field, NSString *direction) { + const FieldPath path = testutil::Field(field); BOOL ascending; if ([direction isEqualToString:@"asc"]) { ascending = YES; @@ -227,14 +217,13 @@ FSTSortOrder *FSTTestOrderBy(NSString *field, NSString *direction) { } else { FSTCFail(@"Unsupported direction: %@", direction); } - return [FSTSortOrder sortOrderWithFieldPath:[path toCPPFieldPath] ascending:ascending]; + return [FSTSortOrder sortOrderWithFieldPath:path ascending:ascending]; } -NSComparator FSTTestDocComparator(NSString *fieldPath) { - FSTQuery *query = [FSTTestQuery(@"docs") - queryByAddingSortOrder:[FSTSortOrder - sortOrderWithFieldPath:[FSTTestFieldPath(fieldPath) toCPPFieldPath] - ascending:YES]]; +NSComparator FSTTestDocComparator(const absl::string_view fieldPath) { + FSTQuery *query = [FSTTestQuery("docs") + queryByAddingSortOrder:[FSTSortOrder sortOrderWithFieldPath:testutil::Field(fieldPath) + ascending:YES]]; return [query comparator]; } @@ -252,23 +241,23 @@ FSTSetMutation *FSTTestSetMutation(NSString *path, NSDictionary precondition:[FSTPrecondition none]]; } -FSTPatchMutation *FSTTestPatchMutation(NSString *path, +FSTPatchMutation *FSTTestPatchMutation(const absl::string_view path, NSDictionary *values, - NSArray *_Nullable updateMask) { - BOOL merge = updateMask != nil; + const std::vector &updateMask) { + BOOL merge = !updateMask.empty(); __block FSTObjectValue *objectValue = [FSTObjectValue objectValue]; - NSMutableArray *fieldMaskPaths = [NSMutableArray array]; + __block std::vector fieldMaskPaths{}; [values enumerateKeysAndObjectsUsingBlock:^(NSString *key, id value, BOOL *stop) { - FSTFieldPath *path = FSTTestFieldPath(key); - [fieldMaskPaths addObject:path]; + const FieldPath path = testutil::Field(util::MakeStringView(key)); + fieldMaskPaths.push_back(path); if (![value isEqual:kDeleteSentinel]) { FSTFieldValue *parsedValue = FSTTestFieldValue(value); objectValue = [objectValue objectBySettingValue:parsedValue forPath:path]; } }]; - FSTDocumentKey *key = [FSTDocumentKey keyWithPath:testutil::Resource([path UTF8String])]; + FSTDocumentKey *key = [FSTDocumentKey keyWithPath:testutil::Resource(path)]; FSTFieldMask *mask = [[FSTFieldMask alloc] initWithFields:merge ? updateMask : fieldMaskPaths]; return [[FSTPatchMutation alloc] initWithKey:key fieldMask:mask @@ -279,10 +268,10 @@ FSTPatchMutation *FSTTestPatchMutation(NSString *path, // For now this only creates TransformMutations with server timestamps. FSTTransformMutation *FSTTestTransformMutation(NSString *path, NSArray *serverTimestampFields) { - FSTDocumentKey *key = [FSTDocumentKey keyWithPath:testutil::Resource([path UTF8String])]; + FSTDocumentKey *key = [FSTDocumentKey keyWithPath:testutil::Resource(util::MakeStringView(path))]; NSMutableArray *fieldTransforms = [NSMutableArray array]; for (NSString *field in serverTimestampFields) { - FSTFieldPath *fieldPath = FSTTestFieldPath(field); + const FieldPath fieldPath = testutil::Field(util::MakeStringView(field)); id transformOp = [FSTServerTimestampTransform serverTimestampTransform]; FSTFieldTransform *transform = [[FSTFieldTransform alloc] initWithPath:fieldPath transform:transformOp]; diff --git a/Firestore/Source/API/FIRCollectionReference+Internal.h b/Firestore/Source/API/FIRCollectionReference+Internal.h index 1d00cbb..9d36ede 100644 --- a/Firestore/Source/API/FIRCollectionReference+Internal.h +++ b/Firestore/Source/API/FIRCollectionReference+Internal.h @@ -16,13 +16,14 @@ #import "FIRCollectionReference.h" -NS_ASSUME_NONNULL_BEGIN +#include "Firestore/core/src/firebase/firestore/model/resource_path.h" -@class FSTResourcePath; +NS_ASSUME_NONNULL_BEGIN /** Internal FIRCollectionReference API we don't want exposed in our public header files. */ @interface FIRCollectionReference (Internal) -+ (instancetype)referenceWithPath:(FSTResourcePath *)path firestore:(FIRFirestore *)firestore; ++ (instancetype)referenceWithPath:(const firebase::firestore::model::ResourcePath &)path + firestore:(FIRFirestore *)firestore; @end NS_ASSUME_NONNULL_END diff --git a/Firestore/Source/API/FIRCollectionReference.mm b/Firestore/Source/API/FIRCollectionReference.mm index 9560d13..dfd06c9 100644 --- a/Firestore/Source/API/FIRCollectionReference.mm +++ b/Firestore/Source/API/FIRCollectionReference.mm @@ -24,7 +24,6 @@ #import "Firestore/Source/API/FIRQuery_Init.h" #import "Firestore/Source/Core/FSTQuery.h" #import "Firestore/Source/Model/FSTDocumentKey.h" -#import "Firestore/Source/Model/FSTPath.h" #import "Firestore/Source/Util/FSTAssert.h" #import "Firestore/Source/Util/FSTUsageValidation.h" @@ -38,7 +37,7 @@ using firebase::firestore::util::CreateAutoId; NS_ASSUME_NONNULL_BEGIN @interface FIRCollectionReference () -- (instancetype)initWithPath:(FSTResourcePath *)path +- (instancetype)initWithPath:(const ResourcePath &)path firestore:(FIRFirestore *)firestore NS_DESIGNATED_INITIALIZER; // Mark the super class designated initializer unavailable. @@ -48,22 +47,21 @@ NS_ASSUME_NONNULL_BEGIN @end @implementation FIRCollectionReference (Internal) -+ (instancetype)referenceWithPath:(FSTResourcePath *)path firestore:(FIRFirestore *)firestore { ++ (instancetype)referenceWithPath:(const ResourcePath &)path firestore:(FIRFirestore *)firestore { return [[FIRCollectionReference alloc] initWithPath:path firestore:firestore]; } @end @implementation FIRCollectionReference -- (instancetype)initWithPath:(FSTResourcePath *)path firestore:(FIRFirestore *)firestore { - if (path.length % 2 != 1) { +- (instancetype)initWithPath:(const ResourcePath &)path firestore:(FIRFirestore *)firestore { + if (path.size() % 2 != 1) { FSTThrowInvalidArgument( @"Invalid collection reference. Collection references must have an odd " - "number of segments, but %@ has %d", - path.canonicalString, path.length); + "number of segments, but %s has %zu", + path.CanonicalString().c_str(), path.size()); } - self = - [super initWithQuery:[FSTQuery queryWithPath:[path toCPPResourcePath]] firestore:firestore]; + self = [super initWithQuery:[FSTQuery queryWithPath:path] firestore:firestore]; return self; } @@ -116,9 +114,7 @@ NS_ASSUME_NONNULL_BEGIN } const ResourcePath subPath = ResourcePath::FromString(util::MakeStringView(documentPath)); const ResourcePath path = self.query.path.Append(subPath); - return - [FIRDocumentReference referenceWithPath:[FSTResourcePath resourcePathWithCPPResourcePath:path] - firestore:self.firestore]; + return [FIRDocumentReference referenceWithPath:path firestore:self.firestore]; } - (FIRDocumentReference *)addDocumentWithData:(NSDictionary *)data { diff --git a/Firestore/Source/API/FIRDocumentReference+Internal.h b/Firestore/Source/API/FIRDocumentReference+Internal.h index 5e12ddc..706e8db 100644 --- a/Firestore/Source/API/FIRDocumentReference+Internal.h +++ b/Firestore/Source/API/FIRDocumentReference+Internal.h @@ -16,15 +16,17 @@ #import "FIRDocumentReference.h" +#include "Firestore/core/src/firebase/firestore/model/resource_path.h" + NS_ASSUME_NONNULL_BEGIN @class FSTDocumentKey; -@class FSTResourcePath; /** Internal FIRDocumentReference API we don't want exposed in our public header files. */ @interface FIRDocumentReference (Internal) -+ (instancetype)referenceWithPath:(FSTResourcePath *)path firestore:(FIRFirestore *)firestore; ++ (instancetype)referenceWithPath:(const firebase::firestore::model::ResourcePath &)path + firestore:(FIRFirestore *)firestore; + (instancetype)referenceWithKey:(FSTDocumentKey *)key firestore:(FIRFirestore *)firestore; @property(nonatomic, strong, readonly) FSTDocumentKey *key; diff --git a/Firestore/Source/API/FIRDocumentReference.mm b/Firestore/Source/API/FIRDocumentReference.mm index cc14af5..5968fb2 100644 --- a/Firestore/Source/API/FIRDocumentReference.mm +++ b/Firestore/Source/API/FIRDocumentReference.mm @@ -34,7 +34,6 @@ #import "Firestore/Source/Model/FSTDocumentSet.h" #import "Firestore/Source/Model/FSTFieldValue.h" #import "Firestore/Source/Model/FSTMutation.h" -#import "Firestore/Source/Model/FSTPath.h" #import "Firestore/Source/Util/FSTAssert.h" #import "Firestore/Source/Util/FSTAsyncQueryListener.h" #import "Firestore/Source/Util/FSTUsageValidation.h" @@ -91,16 +90,15 @@ NS_ASSUME_NONNULL_BEGIN @implementation FIRDocumentReference (Internal) -+ (instancetype)referenceWithPath:(FSTResourcePath *)path firestore:(FIRFirestore *)firestore { - if (path.length % 2 != 0) { ++ (instancetype)referenceWithPath:(const ResourcePath &)path firestore:(FIRFirestore *)firestore { + if (path.size() % 2 != 0) { FSTThrowInvalidArgument( @"Invalid document reference. Document references must have an even " - "number of segments, but %@ has %d", - path.canonicalString, path.length); + "number of segments, but %s has %zu", + path.CanonicalString().c_str(), path.size()); } return - [FIRDocumentReference referenceWithKey:[FSTDocumentKey keyWithPath:[path toCPPResourcePath]] - firestore:firestore]; + [FIRDocumentReference referenceWithKey:[FSTDocumentKey keyWithPath:path] firestore:firestore]; } + (instancetype)referenceWithKey:(FSTDocumentKey *)key firestore:(FIRFirestore *)firestore { @@ -147,9 +145,8 @@ NS_ASSUME_NONNULL_BEGIN } - (FIRCollectionReference *)parent { - return [FIRCollectionReference - referenceWithPath:[FSTResourcePath resourcePathWithCPPResourcePath:self.key.path.PopLast()] - firestore:self.firestore]; + return + [FIRCollectionReference referenceWithPath:self.key.path.PopLast() firestore:self.firestore]; } - (NSString *)path { @@ -160,9 +157,8 @@ NS_ASSUME_NONNULL_BEGIN if (!collectionPath) { FSTThrowInvalidArgument(@"Collection path cannot be nil."); } - FSTResourcePath *subPath = [FSTResourcePath pathWithString:collectionPath]; - FSTResourcePath *path = [FSTResourcePath - resourcePathWithCPPResourcePath:self.key.path.Append([subPath toCPPResourcePath])]; + const ResourcePath subPath = ResourcePath::FromString(util::MakeStringView(collectionPath)); + const ResourcePath path = self.key.path.Append(subPath); return [FIRCollectionReference referenceWithPath:path firestore:self.firestore]; } diff --git a/Firestore/Source/API/FIRDocumentSnapshot.mm b/Firestore/Source/API/FIRDocumentSnapshot.mm index 8e731da..4d82986 100644 --- a/Firestore/Source/API/FIRDocumentSnapshot.mm +++ b/Firestore/Source/API/FIRDocumentSnapshot.mm @@ -24,7 +24,6 @@ #import "Firestore/Source/Model/FSTDocument.h" #import "Firestore/Source/Model/FSTDocumentKey.h" #import "Firestore/Source/Model/FSTFieldValue.h" -#import "Firestore/Source/Model/FSTPath.h" #import "Firestore/Source/Util/FSTAssert.h" #import "Firestore/Source/Util/FSTUsageValidation.h" @@ -184,12 +183,11 @@ NS_ASSUME_NONNULL_BEGIN // TODO(b/32073923): Log this as a proper warning. NSLog( @"WARNING: Document %@ contains a document reference within a different database " - "(%@/%@) which is not supported. It will be treated as a reference within the " - "current database (%@/%@) instead.", - self.reference.path, util::WrapNSStringNoCopy(refDatabase->project_id()), - util::WrapNSStringNoCopy(refDatabase->database_id()), - util::WrapNSStringNoCopy(database->project_id()), - util::WrapNSStringNoCopy(database->database_id())); + "(%s/%s) which is not supported. It will be treated as a reference within the " + "current database (%s/%s) instead.", + self.reference.path, refDatabase->project_id().c_str(), + refDatabase->database_id().c_str(), database->project_id().c_str(), + database->database_id().c_str()); } return [FIRDocumentReference referenceWithKey:[ref valueWithOptions:options] firestore:self.firestore]; diff --git a/Firestore/Source/API/FIRFieldPath+Internal.h b/Firestore/Source/API/FIRFieldPath+Internal.h index 227cdad..6fb6add 100644 --- a/Firestore/Source/API/FIRFieldPath+Internal.h +++ b/Firestore/Source/API/FIRFieldPath+Internal.h @@ -16,16 +16,16 @@ #import "FIRFieldPath.h" -@class FSTFieldPath; +#include "Firestore/core/src/firebase/firestore/model/field_path.h" NS_ASSUME_NONNULL_BEGIN @interface FIRFieldPath () -- (instancetype)initPrivate:(FSTFieldPath *)path NS_DESIGNATED_INITIALIZER; - /** Internal field path representation */ -@property(nonatomic, strong, readonly) FSTFieldPath *internalValue; +- (const firebase::firestore::model::FieldPath &)internalValue; + +- (instancetype)initPrivate:(firebase::firestore::model::FieldPath)path NS_DESIGNATED_INITIALIZER; @end diff --git a/Firestore/Source/API/FIRFieldPath.mm b/Firestore/Source/API/FIRFieldPath.mm index f4e532f..c651160 100644 --- a/Firestore/Source/API/FIRFieldPath.mm +++ b/Firestore/Source/API/FIRFieldPath.mm @@ -16,11 +16,28 @@ #import "Firestore/Source/API/FIRFieldPath+Internal.h" -#import "Firestore/Source/Model/FSTPath.h" +#include +#include +#include +#include + #import "Firestore/Source/Util/FSTUsageValidation.h" +#include "Firestore/core/src/firebase/firestore/model/field_path.h" +#include "Firestore/core/src/firebase/firestore/util/string_apple.h" + +namespace util = firebase::firestore::util; +using firebase::firestore::model::FieldPath; + NS_ASSUME_NONNULL_BEGIN +@interface FIRFieldPath () { + /** Internal field path representation */ + firebase::firestore::model::FieldPath _internalValue; +} + +@end + @implementation FIRFieldPath - (instancetype)initWithFields:(NSArray *)fieldNames { @@ -28,22 +45,25 @@ NS_ASSUME_NONNULL_BEGIN FSTThrowInvalidArgument(@"Invalid field path. Provided names must not be empty."); } + std::vector field_names{}; + field_names.reserve(fieldNames.count); for (int i = 0; i < fieldNames.count; ++i) { if (fieldNames[i].length == 0) { FSTThrowInvalidArgument(@"Invalid field name at index %d. Field names must not be empty.", i); } + field_names.emplace_back(util::MakeString(fieldNames[i])); } - return [self initPrivate:[FSTFieldPath pathWithSegments:fieldNames]]; + return [self initPrivate:FieldPath(std::move(field_names))]; } + (instancetype)documentID { - return [[FIRFieldPath alloc] initPrivate:FSTFieldPath.keyFieldPath]; + return [[FIRFieldPath alloc] initPrivate:FieldPath::KeyFieldPath()]; } -- (instancetype)initPrivate:(FSTFieldPath *)fieldPath { +- (instancetype)initPrivate:(FieldPath)fieldPath { if (self = [super init]) { - _internalValue = fieldPath; + _internalValue = std::move(fieldPath); } return self; } @@ -77,7 +97,7 @@ NS_ASSUME_NONNULL_BEGIN } - (id)copyWithZone:(NSZone *__nullable)zone { - return [[[self class] alloc] initPrivate:self.internalValue]; + return [[[self class] alloc] initPrivate:_internalValue]; } - (BOOL)isEqual:(nullable id)object { @@ -89,11 +109,15 @@ NS_ASSUME_NONNULL_BEGIN return NO; } - return [self.internalValue isEqual:((FIRFieldPath *)object).internalValue]; + return _internalValue == ((FIRFieldPath *)object)->_internalValue; } - (NSUInteger)hash { - return [self.internalValue hash]; + return _internalValue.Hash(); +} + +- (const firebase::firestore::model::FieldPath &)internalValue { + return _internalValue; } @end diff --git a/Firestore/Source/API/FIRFirestore.mm b/Firestore/Source/API/FIRFirestore.mm index eff0605..f3769ed 100644 --- a/Firestore/Source/API/FIRFirestore.mm +++ b/Firestore/Source/API/FIRFirestore.mm @@ -34,7 +34,6 @@ #import "Firestore/Source/Core/FSTFirestoreClient.h" #import "Firestore/Source/Model/FSTDocumentKey.h" -#import "Firestore/Source/Model/FSTPath.h" #import "Firestore/Source/Util/FSTAssert.h" #import "Firestore/Source/Util/FSTDispatchQueue.h" #import "Firestore/Source/Util/FSTLogger.h" @@ -44,6 +43,7 @@ #include "Firestore/core/src/firebase/firestore/auth/firebase_credentials_provider_apple.h" #include "Firestore/core/src/firebase/firestore/core/database_info.h" #include "Firestore/core/src/firebase/firestore/model/database_id.h" +#include "Firestore/core/src/firebase/firestore/model/resource_path.h" #include "Firestore/core/src/firebase/firestore/util/string_apple.h" #include "absl/memory/memory.h" @@ -52,6 +52,7 @@ using firebase::firestore::auth::CredentialsProvider; using firebase::firestore::auth::FirebaseCredentialsProvider; using firebase::firestore::core::DatabaseInfo; using firebase::firestore::model::DatabaseId; +using firebase::firestore::model::ResourcePath; NS_ASSUME_NONNULL_BEGIN @@ -141,9 +142,9 @@ extern "C" NSString *const FIRFirestoreErrorDomain = @"FIRFirestoreErrorDomain"; } if (!database) { FSTThrowInvalidArgument( - @"database identifier may not be nil. Use '%@' if you want the default " + @"database identifier may not be nil. Use '%s' if you want the default " "database", - util::WrapNSStringNoCopy(DatabaseId::kDefault)); + DatabaseId::kDefault); } // Note: If the key format changes, please change the code that detects FIRApps being deleted @@ -261,7 +262,7 @@ extern "C" NSString *const FIRFirestoreErrorDomain = @"FIRFirestoreErrorDomain"; FSTThrowInvalidArgument(@"Collection path cannot be nil."); } [self ensureClientConfigured]; - FSTResourcePath *path = [FSTResourcePath pathWithString:collectionPath]; + const ResourcePath path = ResourcePath::FromString(util::MakeStringView(collectionPath)); return [FIRCollectionReference referenceWithPath:path firestore:self]; } @@ -270,7 +271,7 @@ extern "C" NSString *const FIRFirestoreErrorDomain = @"FIRFirestoreErrorDomain"; FSTThrowInvalidArgument(@"Document path cannot be nil."); } [self ensureClientConfigured]; - FSTResourcePath *path = [FSTResourcePath pathWithString:documentPath]; + const ResourcePath path = ResourcePath::FromString(util::MakeStringView(documentPath)); return [FIRDocumentReference referenceWithPath:path firestore:self]; } diff --git a/Firestore/Source/API/FIRQuery.mm b/Firestore/Source/API/FIRQuery.mm index c277561..07dac39 100644 --- a/Firestore/Source/API/FIRQuery.mm +++ b/Firestore/Source/API/FIRQuery.mm @@ -33,7 +33,6 @@ #import "Firestore/Source/Model/FSTDocument.h" #import "Firestore/Source/Model/FSTDocumentKey.h" #import "Firestore/Source/Model/FSTFieldValue.h" -#import "Firestore/Source/Model/FSTPath.h" #import "Firestore/Source/Util/FSTAssert.h" #import "Firestore/Source/Util/FSTAsyncQueryListener.h" #import "Firestore/Source/Util/FSTUsageValidation.h" @@ -379,8 +378,7 @@ addSnapshotListenerInternalWithOptions:(FSTListenOptions *)internalOptions @"Invalid query. You must not specify an ending point before specifying the order by."); } FSTSortOrder *sortOrder = - [FSTSortOrder sortOrderWithFieldPath:[fieldPath.internalValue toCPPFieldPath] - ascending:!descending]; + [FSTSortOrder sortOrderWithFieldPath:fieldPath.internalValue ascending:!descending]; return [FIRQuery referenceWithQuery:[self.query queryByAddingSortOrder:sortOrder] firestore:self.firestore]; } @@ -453,10 +451,10 @@ addSnapshotListenerInternalWithOptions:(FSTListenOptions *)internalOptions } - (FIRQuery *)queryWithFilterOperator:(FSTRelationFilterOperator)filterOperator - path:(FSTFieldPath *)fieldPath + path:(const FieldPath &)fieldPath value:(id)value { FSTFieldValue *fieldValue; - if ([fieldPath isKeyFieldPath]) { + if (fieldPath.IsKeyFieldPath()) { if ([value isKindOfClass:[NSString class]]) { NSString *documentKey = (NSString *)value; if ([documentKey containsString:@"/"]) { @@ -492,15 +490,15 @@ addSnapshotListenerInternalWithOptions:(FSTListenOptions *)internalOptions @"Invalid Query. You can only perform equality comparisons on nil / " "NSNull."); } - filter = [[FSTNullFilter alloc] initWithField:[fieldPath toCPPFieldPath]]; + filter = [[FSTNullFilter alloc] initWithField:fieldPath]; } else if ([fieldValue isEqual:[FSTDoubleValue nanValue]]) { if (filterOperator != FSTRelationFilterOperatorEqual) { FSTThrowInvalidUsage(@"InvalidQueryException", @"Invalid Query. You can only perform equality comparisons on NaN."); } - filter = [[FSTNanFilter alloc] initWithField:[fieldPath toCPPFieldPath]]; + filter = [[FSTNanFilter alloc] initWithField:fieldPath]; } else { - filter = [FSTRelationFilter filterWithField:[fieldPath toCPPFieldPath] + filter = [FSTRelationFilter filterWithField:fieldPath filterOperator:filterOperator value:fieldValue]; [self validateNewRelationFilter:filter]; @@ -517,40 +515,38 @@ addSnapshotListenerInternalWithOptions:(FSTListenOptions *)internalOptions @"InvalidQueryException", @"Invalid Query. All where filters with an inequality " "(lessThan, lessThanOrEqual, greaterThan, or greaterThanOrEqual) must be on the same " - "field. But you have inequality filters on '%@' and '%@'", - util::WrapNSStringNoCopy(existingField->CanonicalString()), - util::WrapNSStringNoCopy(filter.field.CanonicalString())); + "field. But you have inequality filters on '%s' and '%s'", + existingField->CanonicalString().c_str(), filter.field.CanonicalString().c_str()); } const FieldPath *firstOrderByField = [self.query firstSortOrderField]; if (firstOrderByField) { - [self validateOrderByField:[FSTFieldPath fieldPathWithCPPFieldPath:*firstOrderByField] - matchesInequalityField:[FSTFieldPath fieldPathWithCPPFieldPath:filter.field]]; + [self validateOrderByField:*firstOrderByField matchesInequalityField:filter.field]; } } } -- (void)validateNewOrderByPath:(FSTFieldPath *)fieldPath { +- (void)validateNewOrderByPath:(const FieldPath &)fieldPath { if (![self.query firstSortOrderField]) { // This is the first order by. It must match any inequality. const FieldPath *inequalityField = [self.query inequalityFilterField]; if (inequalityField) { - [self validateOrderByField:fieldPath - matchesInequalityField:[FSTFieldPath fieldPathWithCPPFieldPath:*inequalityField]]; + [self validateOrderByField:fieldPath matchesInequalityField:*inequalityField]; } } } -- (void)validateOrderByField:(FSTFieldPath *)orderByField - matchesInequalityField:(FSTFieldPath *)inequalityField { - if (!([orderByField isEqual:inequalityField])) { +- (void)validateOrderByField:(const FieldPath &)orderByField + matchesInequalityField:(const FieldPath &)inequalityField { + if (orderByField != inequalityField) { FSTThrowInvalidUsage( @"InvalidQueryException", @"Invalid query. You have a where filter with an " - "inequality (lessThan, lessThanOrEqual, greaterThan, or greaterThanOrEqual) on field '%@' " - "and so you must also use '%@' as your first queryOrderedBy field, but your first " - "queryOrderedBy is currently on field '%@' instead.", - inequalityField, inequalityField, orderByField); + "inequality (lessThan, lessThanOrEqual, greaterThan, or greaterThanOrEqual) on field '%s' " + "and so you must also use '%s' as your first queryOrderedBy field, but your first " + "queryOrderedBy is currently on field '%s' instead.", + inequalityField.CanonicalString().c_str(), inequalityField.CanonicalString().c_str(), + orderByField.CanonicalString().c_str()); } } @@ -581,16 +577,15 @@ addSnapshotListenerInternalWithOptions:(FSTListenOptions *)internalOptions [components addObject:[FSTReferenceValue referenceValue:document.key databaseID:self.firestore.databaseID]]; } else { - FSTFieldValue *value = - [document fieldForPath:[FSTFieldPath fieldPathWithCPPFieldPath:sortOrder.field]]; + FSTFieldValue *value = [document fieldForPath:sortOrder.field]; if (value != nil) { [components addObject:value]; } else { FSTThrowInvalidUsage(@"InvalidQueryException", @"Invalid query. You are trying to start or end a query using a " - "document for which the field '%@' (used as the order by) " + "document for which the field '%s' (used as the order by) " "does not exist.", - util::WrapNSStringNoCopy(sortOrder.field.CanonicalString())); + sortOrder.field.CanonicalString().c_str()); } } } diff --git a/Firestore/Source/API/FSTUserDataConverter.mm b/Firestore/Source/API/FSTUserDataConverter.mm index 5f89b8e..e418996 100644 --- a/Firestore/Source/API/FSTUserDataConverter.mm +++ b/Firestore/Source/API/FSTUserDataConverter.mm @@ -16,6 +16,10 @@ #import "Firestore/Source/API/FSTUserDataConverter.h" +#include +#include +#include + #import "FIRTimestamp.h" #import "FIRGeoPoint.h" @@ -27,15 +31,17 @@ #import "Firestore/Source/Model/FSTDocumentKey.h" #import "Firestore/Source/Model/FSTFieldValue.h" #import "Firestore/Source/Model/FSTMutation.h" -#import "Firestore/Source/Model/FSTPath.h" #import "Firestore/Source/Util/FSTAssert.h" #import "Firestore/Source/Util/FSTUsageValidation.h" #include "Firestore/core/src/firebase/firestore/model/database_id.h" +#include "Firestore/core/src/firebase/firestore/model/field_path.h" #include "Firestore/core/src/firebase/firestore/util/string_apple.h" +#include "absl/memory/memory.h" namespace util = firebase::firestore::util; using firebase::firestore::model::DatabaseId; +using firebase::firestore::model::FieldPath; NS_ASSUME_NONNULL_BEGIN @@ -126,9 +132,6 @@ typedef NS_ENUM(NSInteger, FSTUserDataSource) { * A "context" object passed around while parsing user data. */ @interface FSTParseContext : NSObject -/** The current path being parsed. */ -// TODO(b/34871131): path should never be nil, but we don't support array paths right now. -@property(nonatomic, strong, readonly, nullable) FSTFieldPath *path; /** Whether or not this context corresponds to an element of an array. */ @property(nonatomic, assign, readonly, getter=isArrayElement) BOOL arrayElement; @@ -139,7 +142,6 @@ typedef NS_ENUM(NSInteger, FSTUserDataSource) { */ @property(nonatomic, assign) FSTUserDataSource dataSource; @property(nonatomic, strong, readonly) NSMutableArray *fieldTransforms; -@property(nonatomic, strong, readonly) NSMutableArray *fieldMask; - (instancetype)init NS_UNAVAILABLE; /** @@ -150,71 +152,94 @@ typedef NS_ENUM(NSInteger, FSTUserDataSource) { * the context represents the root of the data being parsed), or a nonempty path (indicating the * context represents a nested location within the data). * - * TODO(b/34871131): We don't support array paths right now, so path can be nil to indicate + * TODO(b/34871131): We don't support array paths right now, so path can be nullptr to indicate * the context represents any location within an array (in which case certain features will not work * and errors will be somewhat compromised). */ - (instancetype)initWithSource:(FSTUserDataSource)dataSource - path:(nullable FSTFieldPath *)path + path:(std::unique_ptr)path arrayElement:(BOOL)arrayElement fieldTransforms:(NSMutableArray *)fieldTransforms - fieldMask:(NSMutableArray *)fieldMask + fieldMask:(std::shared_ptr>)fieldMask NS_DESIGNATED_INITIALIZER; // Helpers to get a FSTParseContext for a child field. - (instancetype)contextForField:(NSString *)fieldName; -- (instancetype)contextForFieldPath:(FSTFieldPath *)fieldPath; +- (instancetype)contextForFieldPath:(const FieldPath &)fieldPath; - (instancetype)contextForArrayIndex:(NSUInteger)index; /** Returns true for the non-query parse contexts (Set, MergeSet and Update) */ - (BOOL)isWrite; + +- (const FieldPath *)path; + +- (const std::vector *)fieldMask; + +- (void)appendToFieldMaskWithFieldPath:(FieldPath)fieldPath; + @end -@implementation FSTParseContext +@implementation FSTParseContext { + /** The current path being parsed. */ + // TODO(b/34871131): path should never be nullptr, but we don't support array paths right now. + std::unique_ptr _path; + // _fieldMask is shared across all active context objects to accumulate the result. For example, + // the result of calling any of contextForField, contextForFieldPath and contextForArrayIndex + // shares the ownership of _fieldMask. + std::shared_ptr> _fieldMask; +} -+ (instancetype)contextWithSource:(FSTUserDataSource)dataSource path:(nullable FSTFieldPath *)path { - FSTParseContext *context = [[FSTParseContext alloc] initWithSource:dataSource - path:path - arrayElement:NO - fieldTransforms:[NSMutableArray array] - fieldMask:[NSMutableArray array]]; ++ (instancetype)contextWithSource:(FSTUserDataSource)dataSource + path:(std::unique_ptr)path { + FSTParseContext *context = + [[FSTParseContext alloc] initWithSource:dataSource + path:std::move(path) + arrayElement:NO + fieldTransforms:[NSMutableArray array] + fieldMask:std::make_shared>()]; [context validatePath]; return context; } - (instancetype)initWithSource:(FSTUserDataSource)dataSource - path:(nullable FSTFieldPath *)path + path:(std::unique_ptr)path arrayElement:(BOOL)arrayElement fieldTransforms:(NSMutableArray *)fieldTransforms - fieldMask:(NSMutableArray *)fieldMask { + fieldMask:(std::shared_ptr>)fieldMask { if (self = [super init]) { _dataSource = dataSource; - _path = path; + _path = std::move(path); _arrayElement = arrayElement; _fieldTransforms = fieldTransforms; - _fieldMask = fieldMask; + _fieldMask = std::move(fieldMask); } return self; } - (instancetype)contextForField:(NSString *)fieldName { - FSTParseContext *context = - [[FSTParseContext alloc] initWithSource:self.dataSource - path:[self.path pathByAppendingSegment:fieldName] - arrayElement:NO - fieldTransforms:self.fieldTransforms - fieldMask:self.fieldMask]; + std::unique_ptr path{}; + if (_path) { + path = absl::make_unique(_path->Append(util::MakeString(fieldName))); + } + FSTParseContext *context = [[FSTParseContext alloc] initWithSource:self.dataSource + path:std::move(path) + arrayElement:NO + fieldTransforms:self.fieldTransforms + fieldMask:_fieldMask]; [context validatePathSegment:fieldName]; return context; } -- (instancetype)contextForFieldPath:(FSTFieldPath *)fieldPath { - FSTParseContext *context = - [[FSTParseContext alloc] initWithSource:self.dataSource - path:[self.path pathByAppendingPath:fieldPath] - arrayElement:NO - fieldTransforms:self.fieldTransforms - fieldMask:self.fieldMask]; +- (instancetype)contextForFieldPath:(const FieldPath &)fieldPath { + std::unique_ptr path{}; + if (_path) { + path = absl::make_unique(_path->Append(fieldPath)); + } + FSTParseContext *context = [[FSTParseContext alloc] initWithSource:self.dataSource + path:std::move(path) + arrayElement:NO + fieldTransforms:self.fieldTransforms + fieldMask:_fieldMask]; [context validatePath]; return context; } @@ -225,7 +250,7 @@ typedef NS_ENUM(NSInteger, FSTUserDataSource) { path:nil arrayElement:YES fieldTransforms:self.fieldTransforms - fieldMask:self.fieldMask]; + fieldMask:_fieldMask]; } /** @@ -233,10 +258,10 @@ typedef NS_ENUM(NSInteger, FSTUserDataSource) { */ - (NSString *)fieldDescription { // TODO(b/34871131): Remove nil check once we have proper paths for fields within arrays. - if (!self.path || self.path.empty) { + if (!_path || _path->empty()) { return @""; } else { - return [NSString stringWithFormat:@" (found in field %@)", self.path]; + return [NSString stringWithFormat:@" (found in field %s)", _path->CanonicalString().c_str()]; } } @@ -255,11 +280,11 @@ typedef NS_ENUM(NSInteger, FSTUserDataSource) { - (void)validatePath { // TODO(b/34871131): Remove nil check once we have proper paths for fields within arrays. - if (self.path == nil) { + if (_path == nullptr) { return; } - for (int i = 0; i < self.path.length; i++) { - [self validatePathSegment:[self.path segmentAtIndex:i]]; + for (const auto &segment : *_path) { + [self validatePathSegment:util::WrapNSStringNoCopy(segment)]; } } @@ -271,6 +296,18 @@ typedef NS_ENUM(NSInteger, FSTUserDataSource) { } } +- (const FieldPath *)path { + return _path.get(); +} + +- (const std::vector *)fieldMask { + return _fieldMask.get(); +} + +- (void)appendToFieldMaskWithFieldPath:(FieldPath)fieldPath { + _fieldMask->push_back(std::move(fieldPath)); +} + @end #pragma mark - FSTDocumentKeyReference @@ -316,13 +353,14 @@ typedef NS_ENUM(NSInteger, FSTUserDataSource) { } FSTParseContext *context = - [FSTParseContext contextWithSource:FSTUserDataSourceMergeSet path:[FSTFieldPath emptyPath]]; + [FSTParseContext contextWithSource:FSTUserDataSourceMergeSet + path:absl::make_unique(FieldPath::EmptyPath())]; FSTObjectValue *updateData = (FSTObjectValue *)[self parseData:input context:context]; - return - [[FSTParsedSetData alloc] initWithData:updateData - fieldMask:[[FSTFieldMask alloc] initWithFields:context.fieldMask] - fieldTransforms:context.fieldTransforms]; + return [[FSTParsedSetData alloc] + initWithData:updateData + fieldMask:[[FSTFieldMask alloc] initWithFields:*context.fieldMask] + fieldTransforms:context.fieldTransforms]; } - (FSTParsedSetData *)parsedSetData:(id)input { @@ -333,7 +371,8 @@ typedef NS_ENUM(NSInteger, FSTUserDataSource) { } FSTParseContext *context = - [FSTParseContext contextWithSource:FSTUserDataSourceSet path:[FSTFieldPath emptyPath]]; + [FSTParseContext contextWithSource:FSTUserDataSourceSet + path:absl::make_unique(FieldPath::EmptyPath())]; FSTObjectValue *updateData = (FSTObjectValue *)[self parseData:input context:context]; return [[FSTParsedSetData alloc] initWithData:updateData @@ -350,13 +389,14 @@ typedef NS_ENUM(NSInteger, FSTUserDataSource) { NSDictionary *dict = input; - NSMutableArray *fieldMaskPaths = [NSMutableArray array]; + __block std::vector fieldMaskPaths{}; __block FSTObjectValue *updateData = [FSTObjectValue objectValue]; FSTParseContext *context = - [FSTParseContext contextWithSource:FSTUserDataSourceUpdate path:[FSTFieldPath emptyPath]]; + [FSTParseContext contextWithSource:FSTUserDataSourceUpdate + path:absl::make_unique(FieldPath::EmptyPath())]; [dict enumerateKeysAndObjectsUsingBlock:^(id key, id value, BOOL *stop) { - FSTFieldPath *path; + FieldPath path{}; if ([key isKindOfClass:[NSString class]]) { path = [FIRFieldPath pathWithDotSeparatedString:key].internalValue; @@ -370,12 +410,12 @@ typedef NS_ENUM(NSInteger, FSTUserDataSource) { value = self.preConverter(value); if ([value isKindOfClass:[FSTDeleteFieldValue class]]) { // Add it to the field mask, but don't add anything to updateData. - [fieldMaskPaths addObject:path]; + fieldMaskPaths.push_back(path); } else { FSTFieldValue *_Nullable parsedValue = [self parseData:value context:[context contextForFieldPath:path]]; if (parsedValue) { - [fieldMaskPaths addObject:path]; + fieldMaskPaths.push_back(path); updateData = [updateData objectBySettingValue:parsedValue forPath:path]; } } @@ -389,7 +429,8 @@ typedef NS_ENUM(NSInteger, FSTUserDataSource) { - (FSTFieldValue *)parsedQueryValue:(id)input { FSTParseContext *context = - [FSTParseContext contextWithSource:FSTUserDataSourceQueryValue path:[FSTFieldPath emptyPath]]; + [FSTParseContext contextWithSource:FSTUserDataSourceQueryValue + path:absl::make_unique(FieldPath::EmptyPath())]; FSTFieldValue *_Nullable parsed = [self parseData:input context:context]; FSTAssert(parsed, @"Parsed data should not be nil."); FSTAssert(context.fieldTransforms.count == 0, @"Field transforms should have been disallowed."); @@ -427,7 +468,7 @@ typedef NS_ENUM(NSInteger, FSTUserDataSource) { // If context.path is nil we are already inside an array and we don't support field mask paths // more granular than the top-level array. if (context.path) { - [context.fieldMask addObject:context.path]; + [context appendToFieldMaskWithFieldPath:*context.path]; } return [[FSTArrayValue alloc] initWithValueNoCopy:result]; @@ -448,7 +489,7 @@ typedef NS_ENUM(NSInteger, FSTUserDataSource) { // If context.path is null, we are inside an array and we should have already added the root of // the array to the field mask. if (context.path) { - [context.fieldMask addObject:context.path]; + [context appendToFieldMaskWithFieldPath:*context.path]; } return [self parseScalarValue:input context:context]; } @@ -557,11 +598,10 @@ typedef NS_ENUM(NSInteger, FSTUserDataSource) { if (*reference.databaseID != *self.databaseID) { const DatabaseId *other = reference.databaseID; FSTThrowInvalidArgument( - @"Document Reference is for database %@/%@ but should be for database %@/%@%@", - util::WrapNSStringNoCopy(other->project_id()), - util::WrapNSStringNoCopy(other->database_id()), - util::WrapNSStringNoCopy(self.databaseID->project_id()), - util::WrapNSStringNoCopy(self.databaseID->database_id()), [context fieldDescription]); + @"Document Reference is for database %s/%s but should be for database %s/%s%@", + other->project_id().c_str(), other->database_id().c_str(), + self.databaseID->project_id().c_str(), self.databaseID->database_id().c_str(), + [context fieldDescription]); } return [FSTReferenceValue referenceValue:reference.key databaseID:self.databaseID]; @@ -570,7 +610,7 @@ typedef NS_ENUM(NSInteger, FSTUserDataSource) { if (context.dataSource == FSTUserDataSourceMergeSet) { return nil; } else if (context.dataSource == FSTUserDataSourceUpdate) { - FSTAssert(context.path.length > 0, + FSTAssert(context.path->size() > 0, @"FieldValue.delete() at the top level should have already been handled."); FSTThrowInvalidArgument( @"FieldValue.delete() can only appear at the top level of your " @@ -594,7 +634,7 @@ typedef NS_ENUM(NSInteger, FSTUserDataSource) { } [context.fieldTransforms addObject:[[FSTFieldTransform alloc] - initWithPath:context.path + initWithPath:*context.path transform:[FSTServerTimestampTransform serverTimestampTransform]]]; // Return nil so this value is omitted from the parsed result. diff --git a/Firestore/Source/Core/FSTFirestoreClient.mm b/Firestore/Source/Core/FSTFirestoreClient.mm index 288cbe2..9f0779a 100644 --- a/Firestore/Source/Core/FSTFirestoreClient.mm +++ b/Firestore/Source/Core/FSTFirestoreClient.mm @@ -205,7 +205,7 @@ NS_ASSUME_NONNULL_BEGIN - (void)userDidChange:(const User &)user { [self.workerDispatchQueue verifyIsCurrentQueue]; - FSTLog(@"User Changed: %@", util::WrapNSStringNoCopy(user.uid())); + FSTLog(@"User Changed: %s", user.uid().c_str()); [self.syncEngine userDidChange:user]; } diff --git a/Firestore/Source/Core/FSTQuery.mm b/Firestore/Source/Core/FSTQuery.mm index c10b94d..43b6356 100644 --- a/Firestore/Source/Core/FSTQuery.mm +++ b/Firestore/Source/Core/FSTQuery.mm @@ -23,7 +23,6 @@ #import "Firestore/Source/Model/FSTDocument.h" #import "Firestore/Source/Model/FSTDocumentKey.h" #import "Firestore/Source/Model/FSTFieldValue.h" -#import "Firestore/Source/Model/FSTPath.h" #import "Firestore/Source/Util/FSTAssert.h" #include "Firestore/core/src/firebase/firestore/model/field_path.h" @@ -153,8 +152,7 @@ NSString *FSTStringFromQueryRelationOperator(FSTRelationFilterOperator filterOpe NSComparisonResult comparison = FSTDocumentKeyComparator(document.key, refValue.value); return [self matchesComparison:comparison]; } else { - return [self - matchesValue:[document fieldForPath:[FSTFieldPath fieldPathWithCPPFieldPath:self.field]]]; + return [self matchesValue:[document fieldForPath:self.field]]; } } @@ -220,8 +218,7 @@ NSString *FSTStringFromQueryRelationOperator(FSTRelationFilterOperator filterOpe } - (BOOL)matchesDocument:(FSTDocument *)document { - FSTFieldValue *fieldValue = - [document fieldForPath:[FSTFieldPath fieldPathWithCPPFieldPath:self.field]]; + FSTFieldValue *fieldValue = [document fieldForPath:self.field]; return fieldValue != nil && [fieldValue isEqual:[FSTNullValue nullValue]]; } @@ -267,8 +264,7 @@ NSString *FSTStringFromQueryRelationOperator(FSTRelationFilterOperator filterOpe } - (BOOL)matchesDocument:(FSTDocument *)document { - FSTFieldValue *fieldValue = - [document fieldForPath:[FSTFieldPath fieldPathWithCPPFieldPath:self.field]]; + FSTFieldValue *fieldValue = [document fieldForPath:self.field]; return fieldValue != nil && [fieldValue isEqual:[FSTDoubleValue nanValue]]; } @@ -338,10 +334,8 @@ NSString *FSTStringFromQueryRelationOperator(FSTRelationFilterOperator filterOpe if (_field == FieldPath::KeyFieldPath()) { result = FSTDocumentKeyComparator(document1.key, document2.key); } else { - FSTFieldValue *value1 = - [document1 fieldForPath:[FSTFieldPath fieldPathWithCPPFieldPath:self.field]]; - FSTFieldValue *value2 = - [document2 fieldForPath:[FSTFieldPath fieldPathWithCPPFieldPath:self.field]]; + FSTFieldValue *value1 = [document1 fieldForPath:self.field]; + FSTFieldValue *value2 = [document2 fieldForPath:self.field]; FSTAssert(value1 != nil && value2 != nil, @"Trying to compare documents on fields that don't exist."); result = [value1 compare:value2]; @@ -434,8 +428,7 @@ NSString *FSTStringFromQueryRelationOperator(FSTRelationFilterOperator filterOpe FSTReferenceValue *refValue = (FSTReferenceValue *)fieldValue; comparison = [refValue.value compare:document.key]; } else { - FSTFieldValue *docValue = - [document fieldForPath:[FSTFieldPath fieldPathWithCPPFieldPath:sortOrderComponent.field]]; + FSTFieldValue *docValue = [document fieldForPath:sortOrderComponent.field]; FSTAssert(docValue != nil, @"Field should exist since document matched the orderBy already."); comparison = [fieldValue compare:docValue]; } @@ -590,9 +583,9 @@ NSString *FSTStringFromQueryRelationOperator(FSTRelationFilterOperator filterOpe } } else { FSTAssert(!inequalityField || *inequalityField == *firstSortOrderField, - @"First orderBy %@ should match inequality field %@.", - util::WrapNSStringNoCopy(firstSortOrderField->CanonicalString()), - util::WrapNSStringNoCopy(inequalityField->CanonicalString())); + @"First orderBy %s should match inequality field %s.", + firstSortOrderField->CanonicalString().c_str(), + inequalityField->CanonicalString().c_str()); __block BOOL foundKeyOrder = NO; @@ -791,8 +784,7 @@ NSString *FSTStringFromQueryRelationOperator(FSTRelationFilterOperator filterOpe for (FSTSortOrder *orderBy in self.explicitSortOrders) { const FieldPath &fieldPath = orderBy.field; // order by key always matches - if (fieldPath != FieldPath::KeyFieldPath() && - [document fieldForPath:[FSTFieldPath fieldPathWithCPPFieldPath:fieldPath]] == nil) { + if (fieldPath != FieldPath::KeyFieldPath() && [document fieldForPath:fieldPath] == nil) { return NO; } } diff --git a/Firestore/Source/Core/FSTSyncEngine.mm b/Firestore/Source/Core/FSTSyncEngine.mm index a857f5a..61fac7d 100644 --- a/Firestore/Source/Core/FSTSyncEngine.mm +++ b/Firestore/Source/Core/FSTSyncEngine.mm @@ -36,7 +36,6 @@ #import "Firestore/Source/Model/FSTDocumentKey.h" #import "Firestore/Source/Model/FSTDocumentSet.h" #import "Firestore/Source/Model/FSTMutationBatch.h" -#import "Firestore/Source/Model/FSTPath.h" #import "Firestore/Source/Remote/FSTRemoteEvent.h" #import "Firestore/Source/Util/FSTAssert.h" #import "Firestore/Source/Util/FSTDispatchQueue.h" diff --git a/Firestore/Source/Local/FSTLevelDB.mm b/Firestore/Source/Local/FSTLevelDB.mm index 9d3c35e..ac29304 100644 --- a/Firestore/Source/Local/FSTLevelDB.mm +++ b/Firestore/Source/Local/FSTLevelDB.mm @@ -113,8 +113,7 @@ using leveldb::WriteOptions; NSString *segment = util::WrapNSStringNoCopy(databaseInfo.database_id().project_id()); if (!databaseInfo.database_id().IsDefaultDatabase()) { segment = [NSString - stringWithFormat:@"%@.%@", segment, - util::WrapNSStringNoCopy(databaseInfo.database_id().database_id())]; + stringWithFormat:@"%@.%s", segment, databaseInfo.database_id().database_id().c_str()]; } directory = [directory stringByAppendingPathComponent:segment]; diff --git a/Firestore/Source/Local/FSTLevelDBKey.h b/Firestore/Source/Local/FSTLevelDBKey.h index f3f4bcf..c7a64ee 100644 --- a/Firestore/Source/Local/FSTLevelDBKey.h +++ b/Firestore/Source/Local/FSTLevelDBKey.h @@ -19,8 +19,9 @@ #import "Firestore/Source/Core/FSTTypes.h" #import "Firestore/Source/Local/StringView.h" +#include "Firestore/core/src/firebase/firestore/model/resource_path.h" + @class FSTDocumentKey; -@class FSTResourcePath; NS_ASSUME_NONNULL_BEGIN @@ -34,7 +35,7 @@ NS_ASSUME_NONNULL_BEGIN // document_mutations: // - tableName: string = "document_mutation" // - userID: string -// - path: FSTResourcePath +// - path: ResourcePath // - batchID: FSTBatchID // // mutation_queues: @@ -56,16 +57,16 @@ NS_ASSUME_NONNULL_BEGIN // target_documents: // - tableName: string = "target_document" // - targetID: FSTTargetID -// - path: FSTResourcePath +// - path: ResourcePath // // document_targets: // - tableName: string = "document_target" -// - path: FSTResourcePath +// - path: ResourcePath // - targetID: FSTTargetID // // remote_documents: // - tableName: string = "remote_document" -// - path: FSTResourcePath +// - path: ResourcePath /** Helpers for any LevelDB key. */ @interface FSTLevelDBKey : NSObject @@ -128,12 +129,12 @@ NS_ASSUME_NONNULL_BEGIN /** * Creates a key prefix that points just before the first key for the userID and resource path. * - * Note that this uses an FSTResourcePath rather than an FSTDocumentKey in order to allow prefix + * Note that this uses a ResourcePath rather than an FSTDocumentKey in order to allow prefix * scans over a collection. However a naive scan over those results isn't useful since it would * match both immediate children of the collection and any subcollections. */ + (std::string)keyPrefixWithUserID:(Firestore::StringView)userID - resourcePath:(FSTResourcePath *)resourcePath; + resourcePath:(const firebase::firestore::model::ResourcePath &)resourcePath; /** Creates a complete key that points to a specific userID, document key, and batchID. */ + (std::string)keyWithUserID:(Firestore::StringView)userID @@ -291,7 +292,8 @@ NS_ASSUME_NONNULL_BEGIN + (std::string)keyPrefix; /** Creates a key that points to the first document-target association for document. */ -+ (std::string)keyPrefixWithResourcePath:(FSTResourcePath *)resourcePath; ++ (std::string)keyPrefixWithResourcePath: + (const firebase::firestore::model::ResourcePath &)resourcePath; /** Creates a key that points to a specific document-target entry. */ + (std::string)keyWithDocumentKey:(FSTDocumentKey *)documentKey targetID:(FSTTargetID)targetID; @@ -328,7 +330,8 @@ NS_ASSUME_NONNULL_BEGIN * a document key prefix will match the document itself and any documents that exist in its * subcollections. */ -+ (std::string)keyPrefixWithResourcePath:(FSTResourcePath *)resourcePath; ++ (std::string)keyPrefixWithResourcePath: + (const firebase::firestore::model::ResourcePath &)resourcePath; /** * Decodes the contents of a remote document key into properties on this instance. This can only diff --git a/Firestore/Source/Local/FSTLevelDBKey.mm b/Firestore/Source/Local/FSTLevelDBKey.mm index bd7b44a..e23f5b7 100644 --- a/Firestore/Source/Local/FSTLevelDBKey.mm +++ b/Firestore/Source/Local/FSTLevelDBKey.mm @@ -21,16 +21,19 @@ #include #import "Firestore/Source/Model/FSTDocumentKey.h" -#import "Firestore/Source/Model/FSTPath.h" #include "Firestore/core/src/firebase/firestore/model/resource_path.h" #include "Firestore/core/src/firebase/firestore/util/ordered_code.h" +#include "Firestore/core/src/firebase/firestore/util/string_apple.h" + +namespace util = firebase::firestore::util; namespace util = firebase::firestore::util; using firebase::firestore::model::ResourcePath; NS_ASSUME_NONNULL_BEGIN +using firebase::firestore::model::ResourcePath; using firebase::firestore::util::OrderedCode; using Firestore::StringView; using leveldb::Slice; @@ -255,10 +258,10 @@ BOOL ReadLabeledStringMatching(Slice *contents, * For each segment in the given resource path writes an FSTComponentLabelPathSegment component * label and a string containing the path segment. */ -void WriteResourcePath(std::string *dest, FSTResourcePath *path) { - for (int i = 0; i < path.length; i++) { +void WriteResourcePath(std::string *dest, const ResourcePath &path) { + for (const auto &segment : path) { WriteComponentLabel(dest, FSTComponentLabelPathSegment); - OrderedCode::WriteString(dest, StringView([path segmentAtIndex:i])); + OrderedCode::WriteString(dest, segment); } } @@ -522,7 +525,8 @@ NSString *InvalidKey(const Slice &key) { return result; } -+ (std::string)keyPrefixWithUserID:(StringView)userID resourcePath:(FSTResourcePath *)resourcePath { ++ (std::string)keyPrefixWithUserID:(StringView)userID + resourcePath:(const ResourcePath &)resourcePath { std::string result; WriteTableName(&result, kDocumentMutationsTable); WriteUserID(&result, userID); @@ -536,7 +540,7 @@ NSString *InvalidKey(const Slice &key) { std::string result; WriteTableName(&result, kDocumentMutationsTable); WriteUserID(&result, userID); - WriteResourcePath(&result, [FSTResourcePath resourcePathWithCPPResourcePath:documentKey.path]); + WriteResourcePath(&result, documentKey.path); WriteBatchID(&result, batchID); WriteTerminator(&result); return result; @@ -690,7 +694,7 @@ NSString *InvalidKey(const Slice &key) { std::string result; WriteTableName(&result, kTargetDocumentsTable); WriteTargetID(&result, targetID); - WriteResourcePath(&result, [FSTResourcePath resourcePathWithCPPResourcePath:documentKey.path]); + WriteResourcePath(&result, documentKey.path); WriteTerminator(&result); return result; } @@ -714,7 +718,7 @@ NSString *InvalidKey(const Slice &key) { return result; } -+ (std::string)keyPrefixWithResourcePath:(FSTResourcePath *)resourcePath { ++ (std::string)keyPrefixWithResourcePath:(const ResourcePath &)resourcePath { std::string result; WriteTableName(&result, kDocumentTargetsTable); WriteResourcePath(&result, resourcePath); @@ -724,7 +728,7 @@ NSString *InvalidKey(const Slice &key) { + (std::string)keyWithDocumentKey:(FSTDocumentKey *)documentKey targetID:(FSTTargetID)targetID { std::string result; WriteTableName(&result, kDocumentTargetsTable); - WriteResourcePath(&result, [FSTResourcePath resourcePathWithCPPResourcePath:documentKey.path]); + WriteResourcePath(&result, documentKey.path); WriteTargetID(&result, targetID); WriteTerminator(&result); return result; @@ -749,7 +753,7 @@ NSString *InvalidKey(const Slice &key) { return result; } -+ (std::string)keyPrefixWithResourcePath:(FSTResourcePath *)path { ++ (std::string)keyPrefixWithResourcePath:(const ResourcePath &)path { std::string result; WriteTableName(&result, kRemoteDocumentsTable); WriteResourcePath(&result, path); @@ -759,7 +763,7 @@ NSString *InvalidKey(const Slice &key) { + (std::string)keyWithDocumentKey:(FSTDocumentKey *)key { std::string result; WriteTableName(&result, kRemoteDocumentsTable); - WriteResourcePath(&result, [FSTResourcePath resourcePathWithCPPResourcePath:key.path]); + WriteResourcePath(&result, key.path); WriteTerminator(&result); return result; } diff --git a/Firestore/Source/Local/FSTLevelDBMutationQueue.mm b/Firestore/Source/Local/FSTLevelDBMutationQueue.mm index d7b5eca..ac93ab1 100644 --- a/Firestore/Source/Local/FSTLevelDBMutationQueue.mm +++ b/Firestore/Source/Local/FSTLevelDBMutationQueue.mm @@ -30,10 +30,10 @@ #import "Firestore/Source/Model/FSTDocumentKey.h" #import "Firestore/Source/Model/FSTMutation.h" #import "Firestore/Source/Model/FSTMutationBatch.h" -#import "Firestore/Source/Model/FSTPath.h" #import "Firestore/Source/Util/FSTAssert.h" #include "Firestore/core/src/firebase/firestore/auth/user.h" +#include "Firestore/core/src/firebase/firestore/model/resource_path.h" #include "Firestore/core/src/firebase/firestore/util/string_apple.h" #include "Firestore/core/src/firebase/firestore/util/string_util.h" @@ -42,6 +42,7 @@ NS_ASSUME_NONNULL_BEGIN namespace util = firebase::firestore::util; using Firestore::StringView; using firebase::firestore::auth::User; +using firebase::firestore::model::ResourcePath; using leveldb::DB; using leveldb::Iterator; using leveldb::ReadOptions; @@ -380,9 +381,8 @@ static ReadOptions StandardReadOptions() { NSString *userID = self.userID; // Scan the document-mutation index starting with a prefix starting with the given documentKey. - std::string indexPrefix = [FSTLevelDBDocumentMutationKey - keyPrefixWithUserID:self.userID - resourcePath:[FSTResourcePath resourcePathWithCPPResourcePath:documentKey.path]]; + std::string indexPrefix = + [FSTLevelDBDocumentMutationKey keyPrefixWithUserID:self.userID resourcePath:documentKey.path]; std::unique_ptr indexIterator(_db->NewIterator(StandardReadOptions())); indexIterator->Seek(indexPrefix); @@ -432,8 +432,8 @@ static ReadOptions StandardReadOptions() { FSTAssert(![query isDocumentQuery], @"Document queries shouldn't go down this path"); NSString *userID = self.userID; - FSTResourcePath *queryPath = [FSTResourcePath resourcePathWithCPPResourcePath:query.path]; - int immediateChildrenPathLength = queryPath.length + 1; + const ResourcePath &queryPath = query.path; + size_t immediateChildrenPathLength = queryPath.size() + 1; // TODO(mcg): Actually implement a single-collection query // @@ -620,9 +620,8 @@ static ReadOptions StandardReadOptions() { #pragma mark - FSTGarbageSource implementation - (BOOL)containsKey:(FSTDocumentKey *)documentKey { - std::string indexPrefix = [FSTLevelDBDocumentMutationKey - keyPrefixWithUserID:self.userID - resourcePath:[FSTResourcePath resourcePathWithCPPResourcePath:documentKey.path]]; + std::string indexPrefix = + [FSTLevelDBDocumentMutationKey keyPrefixWithUserID:self.userID resourcePath:documentKey.path]; std::unique_ptr indexIterator(_db->NewIterator(StandardReadOptions())); indexIterator->Seek(indexPrefix); diff --git a/Firestore/Source/Local/FSTLevelDBQueryCache.mm b/Firestore/Source/Local/FSTLevelDBQueryCache.mm index dcbcee1..fe1bf19 100644 --- a/Firestore/Source/Local/FSTLevelDBQueryCache.mm +++ b/Firestore/Source/Local/FSTLevelDBQueryCache.mm @@ -27,7 +27,6 @@ #import "Firestore/Source/Local/FSTQueryData.h" #import "Firestore/Source/Local/FSTWriteGroup.h" #import "Firestore/Source/Model/FSTDocumentKey.h" -#import "Firestore/Source/Model/FSTPath.h" #import "Firestore/Source/Util/FSTAssert.h" NS_ASSUME_NONNULL_BEGIN @@ -340,8 +339,7 @@ using leveldb::WriteOptions; #pragma mark - FSTGarbageSource implementation - (BOOL)containsKey:(FSTDocumentKey *)key { - std::string indexPrefix = [FSTLevelDBDocumentTargetKey - keyPrefixWithResourcePath:[FSTResourcePath resourcePathWithCPPResourcePath:key.path]]; + std::string indexPrefix = [FSTLevelDBDocumentTargetKey keyPrefixWithResourcePath:key.path]; std::unique_ptr indexIterator(_db->NewIterator([FSTLevelDB standardReadOptions])); indexIterator->Seek(indexPrefix); diff --git a/Firestore/Source/Local/FSTLevelDBRemoteDocumentCache.mm b/Firestore/Source/Local/FSTLevelDBRemoteDocumentCache.mm index 423912f..c86318d 100644 --- a/Firestore/Source/Local/FSTLevelDBRemoteDocumentCache.mm +++ b/Firestore/Source/Local/FSTLevelDBRemoteDocumentCache.mm @@ -29,7 +29,6 @@ #import "Firestore/Source/Model/FSTDocumentDictionary.h" #import "Firestore/Source/Model/FSTDocumentKey.h" #import "Firestore/Source/Model/FSTDocumentSet.h" -#import "Firestore/Source/Model/FSTPath.h" #import "Firestore/Source/Util/FSTAssert.h" NS_ASSUME_NONNULL_BEGIN @@ -104,8 +103,7 @@ static ReadOptions StandardReadOptions() { // Documents are ordered by key, so we can use a prefix scan to narrow down // the documents we need to match the query against. - std::string startKey = [FSTLevelDBRemoteDocumentKey - keyPrefixWithResourcePath:[FSTResourcePath resourcePathWithCPPResourcePath:query.path]]; + std::string startKey = [FSTLevelDBRemoteDocumentKey keyPrefixWithResourcePath:query.path]; std::unique_ptr it(_db->NewIterator(StandardReadOptions())); it->Seek(startKey); diff --git a/Firestore/Source/Local/FSTLocalDocumentsView.mm b/Firestore/Source/Local/FSTLocalDocumentsView.mm index 0059e28..c059146 100644 --- a/Firestore/Source/Local/FSTLocalDocumentsView.mm +++ b/Firestore/Source/Local/FSTLocalDocumentsView.mm @@ -25,9 +25,12 @@ #import "Firestore/Source/Model/FSTDocumentKey.h" #import "Firestore/Source/Model/FSTMutation.h" #import "Firestore/Source/Model/FSTMutationBatch.h" -#import "Firestore/Source/Model/FSTPath.h" #import "Firestore/Source/Util/FSTAssert.h" +#include "Firestore/core/src/firebase/firestore/model/resource_path.h" + +using firebase::firestore::model::ResourcePath; + NS_ASSUME_NONNULL_BEGIN @interface FSTLocalDocumentsView () @@ -76,18 +79,16 @@ NS_ASSUME_NONNULL_BEGIN - (FSTDocumentDictionary *)documentsMatchingQuery:(FSTQuery *)query { if ([FSTDocumentKey isDocumentKey:query.path]) { - return [self documentsMatchingDocumentQuery:[FSTResourcePath - resourcePathWithCPPResourcePath:query.path]]; + return [self documentsMatchingDocumentQuery:query.path]; } else { return [self documentsMatchingCollectionQuery:query]; } } -- (FSTDocumentDictionary *)documentsMatchingDocumentQuery:(FSTResourcePath *)docPath { +- (FSTDocumentDictionary *)documentsMatchingDocumentQuery:(const ResourcePath &)docPath { FSTDocumentDictionary *result = [FSTDocumentDictionary documentDictionary]; // Just do a simple document lookup. - FSTMaybeDocument *doc = - [self documentForKey:[FSTDocumentKey keyWithPath:[docPath toCPPResourcePath]]]; + FSTMaybeDocument *doc = [self documentForKey:[FSTDocumentKey keyWithPath:docPath]]; if ([doc isKindOfClass:[FSTDocument class]]) { result = [result dictionaryBySettingObject:(FSTDocument *)doc forKey:doc.key]; } diff --git a/Firestore/Source/Local/FSTMemoryMutationQueue.mm b/Firestore/Source/Local/FSTMemoryMutationQueue.mm index 7e5cc02..8375efd 100644 --- a/Firestore/Source/Local/FSTMemoryMutationQueue.mm +++ b/Firestore/Source/Local/FSTMemoryMutationQueue.mm @@ -21,7 +21,6 @@ #import "Firestore/Source/Model/FSTDocumentKey.h" #import "Firestore/Source/Model/FSTMutation.h" #import "Firestore/Source/Model/FSTMutationBatch.h" -#import "Firestore/Source/Model/FSTPath.h" #import "Firestore/Source/Util/FSTAssert.h" #include "Firestore/core/src/firebase/firestore/model/resource_path.h" diff --git a/Firestore/Source/Local/FSTMemoryRemoteDocumentCache.mm b/Firestore/Source/Local/FSTMemoryRemoteDocumentCache.mm index b0d6807..fed608c 100644 --- a/Firestore/Source/Local/FSTMemoryRemoteDocumentCache.mm +++ b/Firestore/Source/Local/FSTMemoryRemoteDocumentCache.mm @@ -20,7 +20,6 @@ #import "Firestore/Source/Model/FSTDocument.h" #import "Firestore/Source/Model/FSTDocumentDictionary.h" #import "Firestore/Source/Model/FSTDocumentKey.h" -#import "Firestore/Source/Model/FSTPath.h" NS_ASSUME_NONNULL_BEGIN diff --git a/Firestore/Source/Model/FSTDocument.h b/Firestore/Source/Model/FSTDocument.h index 100f553..36237fd 100644 --- a/Firestore/Source/Model/FSTDocument.h +++ b/Firestore/Source/Model/FSTDocument.h @@ -16,8 +16,9 @@ #import +#include "Firestore/core/src/firebase/firestore/model/field_path.h" + @class FSTDocumentKey; -@class FSTFieldPath; @class FSTFieldValue; @class FSTObjectValue; @class FSTSnapshotVersion; @@ -41,7 +42,7 @@ NS_ASSUME_NONNULL_BEGIN version:(FSTSnapshotVersion *)version hasLocalMutations:(BOOL)mutations; -- (nullable FSTFieldValue *)fieldForPath:(FSTFieldPath *)path; +- (nullable FSTFieldValue *)fieldForPath:(const firebase::firestore::model::FieldPath &)path; @property(nonatomic, strong, readonly) FSTObjectValue *data; @property(nonatomic, readonly, getter=hasLocalMutations) BOOL localMutations; diff --git a/Firestore/Source/Model/FSTDocument.mm b/Firestore/Source/Model/FSTDocument.mm index 58d3629..ca66da1 100644 --- a/Firestore/Source/Model/FSTDocument.mm +++ b/Firestore/Source/Model/FSTDocument.mm @@ -19,9 +19,14 @@ #import "Firestore/Source/Core/FSTSnapshotVersion.h" #import "Firestore/Source/Model/FSTDocumentKey.h" #import "Firestore/Source/Model/FSTFieldValue.h" -#import "Firestore/Source/Model/FSTPath.h" #import "Firestore/Source/Util/FSTAssert.h" +#include "Firestore/core/src/firebase/firestore/model/field_path.h" +#include "Firestore/core/src/firebase/firestore/util/string_apple.h" + +namespace util = firebase::firestore::util; +using firebase::firestore::model::FieldPath; + NS_ASSUME_NONNULL_BEGIN @interface FSTMaybeDocument () @@ -99,7 +104,7 @@ NS_ASSUME_NONNULL_BEGIN self.localMutations ? @"YES" : @"NO", self.data]; } -- (nullable FSTFieldValue *)fieldForPath:(FSTFieldPath *)path { +- (nullable FSTFieldValue *)fieldForPath:(const FieldPath &)path { return [_data valueForPath:path]; } diff --git a/Firestore/Source/Model/FSTFieldValue.h b/Firestore/Source/Model/FSTFieldValue.h index be8ba45..7d72138 100644 --- a/Firestore/Source/Model/FSTFieldValue.h +++ b/Firestore/Source/Model/FSTFieldValue.h @@ -19,9 +19,9 @@ #import "Firestore/third_party/Immutable/FSTImmutableSortedDictionary.h" #include "Firestore/core/src/firebase/firestore/model/database_id.h" +#include "Firestore/core/src/firebase/firestore/model/field_path.h" @class FSTDocumentKey; -@class FSTFieldPath; @class FIRTimestamp; @class FSTFieldValueOptions; @class FIRGeoPoint; @@ -243,19 +243,20 @@ typedef NS_ENUM(NSInteger, FSTServerTimestampBehavior) { - (FSTImmutableSortedDictionary *)internalValue; /** Returns the value at the given path if it exists. Returns nil otherwise. */ -- (nullable FSTFieldValue *)valueForPath:(FSTFieldPath *)fieldPath; +- (nullable FSTFieldValue *)valueForPath:(const firebase::firestore::model::FieldPath &)fieldPath; /** * Returns a new object where the field at the named path has its value set to the given value. * This object remains unmodified. */ -- (FSTObjectValue *)objectBySettingValue:(FSTFieldValue *)value forPath:(FSTFieldPath *)fieldPath; +- (FSTObjectValue *)objectBySettingValue:(FSTFieldValue *)value + forPath:(const firebase::firestore::model::FieldPath &)fieldPath; /** * Returns a new object where the field at the named path has been removed. If any segment of the * path does not exist within this object's structure, no change is performed. */ -- (FSTObjectValue *)objectByDeletingPath:(FSTFieldPath *)fieldPath; +- (FSTObjectValue *)objectByDeletingPath:(const firebase::firestore::model::FieldPath &)fieldPath; @end /** diff --git a/Firestore/Source/Model/FSTFieldValue.mm b/Firestore/Source/Model/FSTFieldValue.mm index 5ef64e1..2f013c3 100644 --- a/Firestore/Source/Model/FSTFieldValue.mm +++ b/Firestore/Source/Model/FSTFieldValue.mm @@ -24,15 +24,16 @@ #import "Firestore/Source/API/FIRGeoPoint+Internal.h" #import "Firestore/Source/API/FIRSnapshotOptions+Internal.h" #import "Firestore/Source/Model/FSTDocumentKey.h" -#import "Firestore/Source/Model/FSTPath.h" #import "Firestore/Source/Util/FSTAssert.h" #import "Firestore/Source/Util/FSTClasses.h" #include "Firestore/core/src/firebase/firestore/model/database_id.h" +#include "Firestore/core/src/firebase/firestore/model/field_path.h" #include "Firestore/core/src/firebase/firestore/util/string_apple.h" namespace util = firebase::firestore::util; using firebase::firestore::model::DatabaseId; +using firebase::firestore::model::FieldPath; using firebase::firestore::util::Comparator; using firebase::firestore::util::CompareMixedNumber; using firebase::firestore::util::DoubleBitwiseEquals; @@ -808,25 +809,26 @@ static const NSComparator StringComparator = ^NSComparisonResult(NSString *left, } } -- (nullable FSTFieldValue *)valueForPath:(FSTFieldPath *)fieldPath { +- (nullable FSTFieldValue *)valueForPath:(const FieldPath &)fieldPath { FSTFieldValue *value = self; - for (int i = 0, max = fieldPath.length; value && i < max; i++) { + for (size_t i = 0, max = fieldPath.size(); value && i < max; i++) { if (![value isMemberOfClass:[FSTObjectValue class]]) { return nil; } - NSString *fieldName = fieldPath[i]; + NSString *fieldName = util::WrapNSStringNoCopy(fieldPath[i]); value = ((FSTObjectValue *)value).internalValue[fieldName]; } return value; } -- (FSTObjectValue *)objectBySettingValue:(FSTFieldValue *)value forPath:(FSTFieldPath *)fieldPath { - FSTAssert([fieldPath length] > 0, @"Cannot set value with an empty path"); +- (FSTObjectValue *)objectBySettingValue:(FSTFieldValue *)value + forPath:(const FieldPath &)fieldPath { + FSTAssert(fieldPath.size() > 0, @"Cannot set value with an empty path"); - NSString *childName = [fieldPath firstSegment]; - if ([fieldPath length] == 1) { + NSString *childName = util::WrapNSString(fieldPath.first_segment()); + if (fieldPath.size() == 1) { // Recursive base case: return [self objectBySettingValue:value forField:childName]; } else { @@ -841,23 +843,22 @@ static const NSComparator StringComparator = ^NSComparisonResult(NSString *left, // there. childObject = [FSTObjectValue objectValue]; } - FSTFieldValue *newChild = - [childObject objectBySettingValue:value forPath:[fieldPath pathByRemovingFirstSegment]]; + FSTFieldValue *newChild = [childObject objectBySettingValue:value forPath:fieldPath.PopFirst()]; return [self objectBySettingValue:newChild forField:childName]; } } -- (FSTObjectValue *)objectByDeletingPath:(FSTFieldPath *)fieldPath { - FSTAssert([fieldPath length] > 0, @"Cannot delete an empty path"); - NSString *childName = [fieldPath firstSegment]; - if ([fieldPath length] == 1) { +- (FSTObjectValue *)objectByDeletingPath:(const FieldPath &)fieldPath { + FSTAssert(fieldPath.size() > 0, @"Cannot delete an empty path"); + NSString *childName = util::WrapNSString(fieldPath.first_segment()); + if (fieldPath.size() == 1) { return [[FSTObjectValue alloc] initWithImmutableDictionary:[_internalValue dictionaryByRemovingObjectForKey:childName]]; } else { FSTFieldValue *child = _internalValue[childName]; if ([child isKindOfClass:[FSTObjectValue class]]) { FSTObjectValue *newChild = - [((FSTObjectValue *)child) objectByDeletingPath:[fieldPath pathByRemovingFirstSegment]]; + [((FSTObjectValue *)child) objectByDeletingPath:fieldPath.PopFirst()]; return [self objectBySettingValue:newChild forField:childName]; } else { // If the child is not found or is a primitive type, make no modifications diff --git a/Firestore/Source/Model/FSTMutation.h b/Firestore/Source/Model/FSTMutation.h index 72f6a25..2d29dc9 100644 --- a/Firestore/Source/Model/FSTMutation.h +++ b/Firestore/Source/Model/FSTMutation.h @@ -16,9 +16,12 @@ #import +#include + +#include "Firestore/core/src/firebase/firestore/model/field_path.h" + @class FSTDocument; @class FSTDocumentKey; -@class FSTFieldPath; @class FSTFieldValue; @class FSTMaybeDocument; @class FSTObjectValue; @@ -46,9 +49,10 @@ NS_ASSUME_NONNULL_BEGIN * Initializes the field mask with the given field paths. Caller is expected to either copy or * or release the array of fields. */ -- (instancetype)initWithFields:(NSArray *)fields NS_DESIGNATED_INITIALIZER; +- (instancetype)initWithFields:(std::vector)fields + NS_DESIGNATED_INITIALIZER; -@property(nonatomic, strong, readonly) NSArray *fields; +- (const std::vector &)fields; @end #pragma mark - FSTFieldTransform @@ -65,9 +69,9 @@ NS_ASSUME_NONNULL_BEGIN /** A field path and the FSTTransformOperation to perform upon it. */ @interface FSTFieldTransform : NSObject - (instancetype)init NS_UNAVAILABLE; -- (instancetype)initWithPath:(FSTFieldPath *)path +- (instancetype)initWithPath:(firebase::firestore::model::FieldPath)path transform:(id)transform NS_DESIGNATED_INITIALIZER; -@property(nonatomic, strong, readonly) FSTFieldPath *path; +- (const firebase::firestore::model::FieldPath &)path; @property(nonatomic, strong, readonly) id transform; @end diff --git a/Firestore/Source/Model/FSTMutation.mm b/Firestore/Source/Model/FSTMutation.mm index e702644..a61ee84 100644 --- a/Firestore/Source/Model/FSTMutation.mm +++ b/Firestore/Source/Model/FSTMutation.mm @@ -22,19 +22,24 @@ #import "Firestore/Source/Model/FSTDocument.h" #import "Firestore/Source/Model/FSTDocumentKey.h" #import "Firestore/Source/Model/FSTFieldValue.h" -#import "Firestore/Source/Model/FSTPath.h" #import "Firestore/Source/Util/FSTAssert.h" #import "Firestore/Source/Util/FSTClasses.h" +#include "Firestore/core/src/firebase/firestore/model/field_path.h" + +using firebase::firestore::model::FieldPath; + NS_ASSUME_NONNULL_BEGIN #pragma mark - FSTFieldMask -@implementation FSTFieldMask +@implementation FSTFieldMask { + std::vector _fields; +} -- (instancetype)initWithFields:(NSArray *)fields { +- (instancetype)initWithFields:(std::vector)fields { if (self = [super init]) { - _fields = fields; + _fields = std::move(fields); } return self; } @@ -48,11 +53,19 @@ NS_ASSUME_NONNULL_BEGIN } FSTFieldMask *otherMask = (FSTFieldMask *)other; - return [self.fields isEqual:otherMask.fields]; + return _fields == otherMask->_fields; } - (NSUInteger)hash { - return self.fields.hash; + NSUInteger hashResult = 0; + for (const FieldPath &field : _fields) { + hashResult = hashResult * 31u + field.Hash(); + } + return hashResult; +} + +- (const std::vector &)fields { + return _fields; } @end @@ -85,12 +98,14 @@ NS_ASSUME_NONNULL_BEGIN #pragma mark - FSTFieldTransform -@implementation FSTFieldTransform +@implementation FSTFieldTransform { + FieldPath _path; +} -- (instancetype)initWithPath:(FSTFieldPath *)path transform:(id)transform { +- (instancetype)initWithPath:(FieldPath)path transform:(id)transform { self = [super init]; if (self) { - _path = path; + _path = std::move(path); _transform = transform; } return self; @@ -100,16 +115,20 @@ NS_ASSUME_NONNULL_BEGIN if (other == self) return YES; if (![[other class] isEqual:[self class]]) return NO; FSTFieldTransform *otherFieldTransform = other; - return [self.path isEqual:otherFieldTransform.path] && + return self.path == otherFieldTransform.path && [self.transform isEqual:otherFieldTransform.transform]; } - (NSUInteger)hash { - NSUInteger hash = [self.path hash]; + NSUInteger hash = self.path.Hash(); hash = hash * 31 + [self.transform hash]; return hash; } +- (const firebase::firestore::model::FieldPath &)path { + return _path; +} + @end #pragma mark - FSTPrecondition @@ -405,7 +424,7 @@ NS_ASSUME_NONNULL_BEGIN - (FSTObjectValue *)patchObjectValue:(FSTObjectValue *)objectValue { FSTObjectValue *result = objectValue; - for (FSTFieldPath *fieldPath in self.fieldMask.fields) { + for (const FieldPath &fieldPath : self.fieldMask.fields) { FSTFieldValue *newValue = [self.value valueForPath:fieldPath]; if (newValue) { result = [result objectBySettingValue:newValue forPath:fieldPath]; @@ -529,7 +548,7 @@ NS_ASSUME_NONNULL_BEGIN for (NSUInteger i = 0; i < self.fieldTransforms.count; i++) { FSTFieldTransform *fieldTransform = self.fieldTransforms[i]; id transform = fieldTransform.transform; - FSTFieldPath *fieldPath = fieldTransform.path; + FieldPath fieldPath = fieldTransform.path; if ([transform isKindOfClass:[FSTServerTimestampTransform class]]) { objectValue = [objectValue objectBySettingValue:transformResults[i] forPath:fieldPath]; } else { diff --git a/Firestore/Source/Model/FSTPath.h b/Firestore/Source/Model/FSTPath.h deleted file mode 100644 index f127156..0000000 --- a/Firestore/Source/Model/FSTPath.h +++ /dev/null @@ -1,167 +0,0 @@ -/* - * Copyright 2017 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 - -#include "Firestore/core/src/firebase/firestore/model/field_path.h" -#include "Firestore/core/src/firebase/firestore/model/resource_path.h" - -NS_ASSUME_NONNULL_BEGIN - -/** - * FSTPath represents a path sequence in the Firestore database. It is composed of an ordered - * sequence of string segments. - * - * ## Subclassing Notes - * - * FSTPath itself is an abstract class that must be specialized by subclasses. Subclasses should - * implement constructors for common string-based representations of the path and also override - * -canonicalString which converts back to the canonical string-based representation of the path. - */ -@interface FSTPath : NSObject - -/** Returns the path segment of the given index. */ -- (NSString *)segmentAtIndex:(int)index; -- (id)objectAtIndexedSubscript:(int)index; - -- (BOOL)isEqual:(id)path; -- (NSComparisonResult)compare:(SelfType)other; - -/** - * Returns a new path whose segments are the current path's plus one more. - * - * @param segment The new segment to concatenate to the path. - * @return A new path with this path's segment plus the new one. - */ -- (instancetype)pathByAppendingSegment:(NSString *)segment; - -/** - * Returns a new path whose segments are the current path's plus another's. - * - * @param path The new path whose segments should be concatenated to the path. - * @return A new path with this path's segment plus the new ones. - */ -- (instancetype)pathByAppendingPath:(SelfType)path; - -/** Returns a new path whose segments are the same as this one's minus the first one. */ -- (instancetype)pathByRemovingFirstSegment; - -/** Returns a new path whose segments are the same as this one's minus the first `count`. */ -- (instancetype)pathByRemovingFirstSegments:(int)count; - -/** Returns a new path whose segments are the same as this one's minus the last one. */ -- (instancetype)pathByRemovingLastSegment; - -/** Convenience method for getting the first segment of this path. */ -- (NSString *)firstSegment; - -/** Convenience method for getting the last segment of this path. */ -- (NSString *)lastSegment; - -/** Returns true if this path is a prefix of the given path. */ -- (BOOL)isPrefixOfPath:(SelfType)other; - -/** Returns a standardized string representation of this path. */ -- (NSString *)canonicalString; - -/** The number of segments in the path. */ -@property(nonatomic, readonly) int length; - -/** True if the path is empty. */ -@property(nonatomic, readonly, getter=isEmpty) BOOL empty; - -@end - -/** A dot-separated path for navigating sub-objects within a document. */ -@class FSTFieldPath; - -@interface FSTFieldPath : FSTPath - -/** - * Creates and returns a new path with the given segments. The array of segments is not copied, so - * one should not mutate the array once it is passed in here. - * - * @param segments The underlying array of segments for the path. - * @return A new instance of FSTPath. - */ -+ (instancetype)pathWithSegments:(NSArray *)segments; - -/** - * Creates and returns a new path from the server formatted field-path string, where path segments - * are separated by a dot "." and optionally encoded using backticks. - * - * @param fieldPath A dot-separated string representing the path. - */ -+ (instancetype)pathWithServerFormat:(NSString *)fieldPath; - -/** Returns a field path that represents a document key. */ -+ (instancetype)keyFieldPath; - -/** Returns a field path that represents an empty path. */ -+ (instancetype)emptyPath; - -/** Returns YES if this is the `FSTFieldPath.keyFieldPath` field path. */ -- (BOOL)isKeyFieldPath; - -/** Creates and returns a new path from C++ FieldPath. - * - * @param fieldPath A C++ FieldPath. - */ -+ (instancetype)fieldPathWithCPPFieldPath:(const firebase::firestore::model::FieldPath &)fieldPath; - -/** - * Creates and returns a new C++ FieldPath. - */ -- (firebase::firestore::model::FieldPath)toCPPFieldPath; - -@end - -/** A slash-separated path for navigating resources (documents and collections) within Firestore. */ -@class FSTResourcePath; - -@interface FSTResourcePath : FSTPath - -/** - * Creates and returns a new path with the given segments. The array of segments is not copied, so - * one should not mutate the array once it is passed in here. - * - * @param segments The underlying array of segments for the path. - * @return A new instance of FSTPath. - */ -+ (instancetype)pathWithSegments:(NSArray *)segments; - -/** - * Creates and returns a new path from the given resource-path string, where the path segments are - * separated by a slash "/". - * - * @param resourcePath A slash-separated string representing the path. - */ -+ (instancetype)pathWithString:(NSString *)resourcePath; - -/** Creates and returns a new path from C++ ResourcePath. - * - * @param resourcePath A C++ ResourcePath. - */ -+ (instancetype)resourcePathWithCPPResourcePath: - (const firebase::firestore::model::ResourcePath &)resourcePath; - -/** - * Creates and returns a new C++ ResourcePath. - */ -- (firebase::firestore::model::ResourcePath)toCPPResourcePath; -@end - -NS_ASSUME_NONNULL_END diff --git a/Firestore/Source/Model/FSTPath.mm b/Firestore/Source/Model/FSTPath.mm deleted file mode 100644 index b91e428..0000000 --- a/Firestore/Source/Model/FSTPath.mm +++ /dev/null @@ -1,399 +0,0 @@ -/* - * Copyright 2017 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/Model/FSTPath.h" - -#include - -#import "Firestore/Source/Model/FSTDocumentKey.h" -#import "Firestore/Source/Util/FSTAssert.h" -#import "Firestore/Source/Util/FSTClasses.h" -#import "Firestore/Source/Util/FSTUsageValidation.h" - -#include "Firestore/core/src/firebase/firestore/model/field_path.h" -#include "Firestore/core/src/firebase/firestore/model/resource_path.h" -#include "Firestore/core/src/firebase/firestore/util/string_apple.h" - -namespace util = firebase::firestore::util; -using firebase::firestore::model::FieldPath; -using firebase::firestore::model::ResourcePath; - -NS_ASSUME_NONNULL_BEGIN - -@interface FSTPath () -/** An underlying array of which a subset of elements are the segments of the path. */ -@property(strong, nonatomic) NSArray *segments; -/** The index into the segments array of the first segment in this path. */ -@property int offset; -@end - -@implementation FSTPath - -/** - * Designated initializer. - * - * @param segments The underlying array of segments for the path. - * @param offset The starting index in the underlying array for the subarray to use. - * @param length The length of the subarray to use. - */ -- (instancetype)initWithSegments:(NSArray *)segments - offset:(int)offset - length:(int)length { - FSTAssert(offset <= segments.count, @"offset %d out of range %d", offset, (int)segments.count); - FSTAssert(length <= segments.count - offset, @"offset %d out of range %d", offset, - (int)segments.count - offset); - - if (self = [super init]) { - _segments = segments; - _offset = offset; - _length = length; - } - return self; -} - -- (BOOL)isEqual:(id)object { - if (self == object) { - return YES; - } - if (![object isKindOfClass:[FSTPath class]]) { - return NO; - } - FSTPath *path = object; - return [self compare:path] == NSOrderedSame; -} - -- (NSUInteger)hash { - NSUInteger hash = 0; - for (int i = 0; i < self.length; ++i) { - hash += [self segmentAtIndex:i].hash; - } - return hash; -} - -- (NSString *)description { - return [self canonicalString]; -} - -- (id)objectAtIndexedSubscript:(int)index { - return [self segmentAtIndex:index]; -} - -- (NSString *)segmentAtIndex:(int)index { - FSTAssert(index < self.length, @"index %d out of range", index); - return self.segments[self.offset + index]; -} - -- (NSString *)firstSegment { - FSTAssert(!self.isEmpty, @"Cannot call firstSegment on empty path"); - return [self segmentAtIndex:0]; -} - -- (NSString *)lastSegment { - FSTAssert(!self.isEmpty, @"Cannot call lastSegment on empty path"); - return [self segmentAtIndex:self.length - 1]; -} - -- (NSComparisonResult)compare:(FSTPath *)other { - int length = MIN(self.length, other.length); - for (int i = 0; i < length; ++i) { - NSString *left = [self segmentAtIndex:i]; - NSString *right = [other segmentAtIndex:i]; - NSComparisonResult result = [left compare:right]; - if (result != NSOrderedSame) { - return result; - } - } - if (self.length < other.length) { - return NSOrderedAscending; - } - if (self.length > other.length) { - return NSOrderedDescending; - } - return NSOrderedSame; -} - -- (instancetype)pathWithSegments:(NSArray *)segments - offset:(int)offset - length:(int)length { - return [[[self class] alloc] initWithSegments:segments offset:offset length:length]; -} - -- (instancetype)pathByAppendingSegment:(NSString *)segment { - int newLength = self.length + 1; - NSMutableArray *segments = [NSMutableArray arrayWithCapacity:newLength]; - for (int i = 0; i < self.length; ++i) { - [segments addObject:self[i]]; - } - [segments addObject:segment]; - return [self pathWithSegments:segments offset:0 length:newLength]; -} - -- (instancetype)pathByAppendingPath:(FSTPath *)path { - int newLength = self.length + path.length; - NSMutableArray *segments = [NSMutableArray arrayWithCapacity:newLength]; - for (int i = 0; i < self.length; ++i) { - [segments addObject:self[i]]; - } - for (int i = 0; i < path.length; ++i) { - [segments addObject:path[i]]; - } - return [self pathWithSegments:segments offset:0 length:newLength]; -} - -- (BOOL)isEmpty { - return self.length == 0; -} - -- (instancetype)pathByRemovingFirstSegment { - FSTAssert(!self.isEmpty, @"Cannot call pathByRemovingFirstSegment on empty path"); - return [self pathWithSegments:self.segments offset:self.offset + 1 length:self.length - 1]; -} - -- (instancetype)pathByRemovingFirstSegments:(int)count { - FSTAssert(self.length >= count, @"pathByRemovingFirstSegments:%d on path of length %d", count, - self.length); - return - [self pathWithSegments:self.segments offset:self.offset + count length:self.length - count]; -} - -- (instancetype)pathByRemovingLastSegment { - FSTAssert(!self.isEmpty, @"Cannot call pathByRemovingLastSegment on empty path"); - return [self pathWithSegments:self.segments offset:self.offset length:self.length - 1]; -} - -- (BOOL)isPrefixOfPath:(FSTPath *)other { - if (other.length < self.length) { - return NO; - } - for (int i = 0; i < self.length; ++i) { - if (![self[i] isEqual:other[i]]) { - return NO; - } - } - return YES; -} - -/** Returns a standardized string representation of this path. */ -- (NSString *)canonicalString { - @throw FSTAbstractMethodException(); // NOLINT -} -@end - -@implementation FSTFieldPath -+ (instancetype)pathWithSegments:(NSArray *)segments { - return [[FSTFieldPath alloc] initWithSegments:segments offset:0 length:(int)segments.count]; -} - -+ (instancetype)pathWithServerFormat:(NSString *)fieldPath { - NSMutableArray *segments = [NSMutableArray array]; - - // TODO(b/37244157): Once we move to v1beta1, we should make this more strict. Right now, it - // allows non-identifier path components, even if they aren't escaped. Technically, this will - // mangle paths with backticks in them used in v1alpha1, but that's fine. - - const char *source = [fieldPath UTF8String]; - char *segment = (char *)malloc(strlen(source) + 1); - char *segmentEnd = segment; - - // If we're inside '`' backticks, then we should ignore '.' dots. - BOOL inBackticks = NO; - - char c; - do { - // Examine current character. This is legit even on zero-length strings because there's always - // a null terminator. - c = *source++; - switch (c) { - case '\0': // Falls through - case '.': - if (!inBackticks) { - // Segment is complete - *segmentEnd = '\0'; - if (segment == segmentEnd) { - FSTThrowInvalidArgument( - @"Invalid field path (%@). Paths must not be empty, begin with " - @"'.', end with '.', or contain '..'", - fieldPath); - } - - [segments addObject:[NSString stringWithUTF8String:segment]]; - segmentEnd = segment; - } else { - // copy into the current segment - *segmentEnd++ = c; - } - break; - - case '`': - if (inBackticks) { - inBackticks = NO; - } else { - inBackticks = YES; - } - break; - - case '\\': - // advance to escaped character - c = *source++; - // TODO(b/37244157): Make this a user-facing exception once we finalize field escaping. - FSTAssert(c != '\0', @"Trailing escape characters not allowed in %@", fieldPath); - // Fall through - - default: - // copy into the current segment - *segmentEnd++ = c; - break; - } - } while (c); - - FSTAssert(!inBackticks, @"Unterminated ` in path %@", fieldPath); - - free(segment); - return [FSTFieldPath pathWithSegments:segments]; -} - -+ (instancetype)keyFieldPath { - static FSTFieldPath *keyFieldPath; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - keyFieldPath = [FSTFieldPath pathWithSegments:@[ kDocumentKeyPath ]]; - }); - return keyFieldPath; -} - -+ (instancetype)emptyPath { - static FSTFieldPath *emptyPath; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - emptyPath = [FSTFieldPath pathWithSegments:@[]]; - }); - return emptyPath; -} - -/** Return YES if the string could be used as a segment in a field path without escaping. */ -+ (BOOL)isValidIdentifier:(NSString *)segment { - if (segment.length == 0) { - return NO; - } - unichar first = [segment characterAtIndex:0]; - if (first != '_' && (first < 'a' || first > 'z') && (first < 'A' || first > 'Z')) { - return NO; - } - for (int i = 1; i < segment.length; i++) { - unichar c = [segment characterAtIndex:i]; - if (c != '_' && (c < 'a' || c > 'z') && (c < 'A' || c > 'Z') && (c < '0' || c > '9')) { - return NO; - } - } - return YES; -} - -- (BOOL)isKeyFieldPath { - return [self isEqual:FSTFieldPath.keyFieldPath]; -} - -- (NSString *)canonicalString { - NSMutableString *result = [NSMutableString string]; - for (int i = 0; i < self.length; i++) { - if (i > 0) { - [result appendString:@"."]; - } - - NSString *escaped = [self[i] stringByReplacingOccurrencesOfString:@"\\" withString:@"\\\\"]; - escaped = [escaped stringByReplacingOccurrencesOfString:@"`" withString:@"\\`"]; - if (![FSTFieldPath isValidIdentifier:escaped]) { - escaped = [NSString stringWithFormat:@"`%@`", escaped]; - } - - [result appendString:escaped]; - } - return result; -} - -+ (instancetype)fieldPathWithCPPFieldPath:(const FieldPath &)fieldPath { - NSMutableArray *segments = [NSMutableArray arrayWithCapacity:fieldPath.size()]; - for (int i = 0; i < fieldPath.size(); i++) { - segments[i] = util::WrapNSString(fieldPath[i]); - } - return [FSTFieldPath pathWithSegments:segments]; -} - -- (FieldPath)toCPPFieldPath { - std::vector segments(self.length); - for (int i = 0; i < self.length; i++) { - segments[i] = [[self segmentAtIndex:i] UTF8String]; - } - return FieldPath(segments.begin(), segments.end()); -} - -@end - -@implementation FSTResourcePath -+ (instancetype)pathWithSegments:(NSArray *)segments { - return [[FSTResourcePath alloc] initWithSegments:segments offset:0 length:(int)segments.count]; -} - -+ (instancetype)pathWithString:(NSString *)resourcePath { - // NOTE: The client is ignorant of any path segments containing escape sequences (e.g. __id123__) - // and just passes them through raw (they exist for legacy reasons and should not be used - // frequently). - - if ([resourcePath rangeOfString:@"//"].location != NSNotFound) { - FSTThrowInvalidArgument(@"Invalid path (%@). Paths must not contain // in them.", resourcePath); - } - - NSMutableArray *segments = [[resourcePath componentsSeparatedByString:@"/"] mutableCopy]; - // We may still have an empty segment at the beginning or end if they had a leading or trailing - // slash (which we allow). - [segments removeObject:@""]; - - return [self pathWithSegments:segments]; -} - -- (NSString *)canonicalString { - // NOTE: The client is ignorant of any path segments containing escape sequences (e.g. __id123__) - // and just passes them through raw (they exist for legacy reasons and should not be used - // frequently). - - NSMutableString *result = [NSMutableString string]; - for (int i = 0; i < self.length; i++) { - if (i > 0) { - [result appendString:@"/"]; - } - [result appendString:self[i]]; - } - return result; -} - -+ (instancetype)resourcePathWithCPPResourcePath:(const ResourcePath &)resourcePath { - NSMutableArray *segments = [NSMutableArray arrayWithCapacity:resourcePath.size()]; - for (int i = 0; i < resourcePath.size(); i++) { - segments[i] = util::WrapNSString(resourcePath[i]); - } - return [FSTResourcePath pathWithSegments:segments]; -} - -- (ResourcePath)toCPPResourcePath { - std::vector segments(self.length); - for (int i = 0; i < self.length; i++) { - segments[i] = [[self segmentAtIndex:i] UTF8String]; - } - return ResourcePath(segments.begin(), segments.end()); -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/Firestore/Source/Remote/FSTDatastore.mm b/Firestore/Source/Remote/FSTDatastore.mm index 3b536ab..e63017a 100644 --- a/Firestore/Source/Remote/FSTDatastore.mm +++ b/Firestore/Source/Remote/FSTDatastore.mm @@ -111,10 +111,9 @@ typedef GRPCProtoCall * (^RPCFactory)(void); } - (NSString *)description { - return [NSString - stringWithFormat:@">", - util::WrapNSStringNoCopy(self.databaseInfo->database_id().database_id()), - util::WrapNSStringNoCopy(self.databaseInfo->host())]; + return [NSString stringWithFormat:@">", + self.databaseInfo->database_id().database_id().c_str(), + self.databaseInfo->host().c_str()]; } /** @@ -186,9 +185,8 @@ typedef GRPCProtoCall * (^RPCFactory)(void); /** Returns the string to be used as google-cloud-resource-prefix header value. */ + (NSString *)googleCloudResourcePrefixForDatabaseID:(const DatabaseId *)databaseID { - return [NSString stringWithFormat:@"projects/%@/databases/%@", - util::WrapNSStringNoCopy(databaseID->project_id()), - util::WrapNSStringNoCopy(databaseID->database_id())]; + return [NSString stringWithFormat:@"projects/%s/databases/%s", databaseID->project_id().c_str(), + databaseID->database_id().c_str()]; } /** * Takes a dictionary of (HTTP) response headers and returns the set of whitelisted headers diff --git a/Firestore/Source/Remote/FSTRemoteStore.mm b/Firestore/Source/Remote/FSTRemoteStore.mm index 2c8e84a..f484278 100644 --- a/Firestore/Source/Remote/FSTRemoteStore.mm +++ b/Firestore/Source/Remote/FSTRemoteStore.mm @@ -27,7 +27,6 @@ #import "Firestore/Source/Model/FSTDocumentKey.h" #import "Firestore/Source/Model/FSTMutation.h" #import "Firestore/Source/Model/FSTMutationBatch.h" -#import "Firestore/Source/Model/FSTPath.h" #import "Firestore/Source/Remote/FSTDatastore.h" #import "Firestore/Source/Remote/FSTExistenceFilter.h" #import "Firestore/Source/Remote/FSTOnlineStateTracker.h" @@ -211,8 +210,7 @@ static const int kMaxPendingWrites = 10; } - (void)userDidChange:(const User &)user { - FSTLog(@"FSTRemoteStore %p changing users: %@", (__bridge void *)self, - util::WrapNSStringNoCopy(user.uid())); + FSTLog(@"FSTRemoteStore %p changing users: %s", (__bridge void *)self, user.uid().c_str()); if ([self isNetworkEnabled]) { // Tear down and re-create our network streams. This will ensure we get a fresh auth token // for the new user and re-fill the write pipeline with new mutations from the LocalStore diff --git a/Firestore/Source/Remote/FSTSerializerBeta.mm b/Firestore/Source/Remote/FSTSerializerBeta.mm index 00391ec..77d2ec7 100644 --- a/Firestore/Source/Remote/FSTSerializerBeta.mm +++ b/Firestore/Source/Remote/FSTSerializerBeta.mm @@ -39,16 +39,19 @@ #import "Firestore/Source/Model/FSTFieldValue.h" #import "Firestore/Source/Model/FSTMutation.h" #import "Firestore/Source/Model/FSTMutationBatch.h" -#import "Firestore/Source/Model/FSTPath.h" #import "Firestore/Source/Remote/FSTExistenceFilter.h" #import "Firestore/Source/Remote/FSTWatchChange.h" #import "Firestore/Source/Util/FSTAssert.h" #include "Firestore/core/src/firebase/firestore/model/database_id.h" +#include "Firestore/core/src/firebase/firestore/model/field_path.h" +#include "Firestore/core/src/firebase/firestore/model/resource_path.h" #include "Firestore/core/src/firebase/firestore/util/string_apple.h" namespace util = firebase::firestore::util; using firebase::firestore::model::DatabaseId; +using firebase::firestore::model::FieldPath; +using firebase::firestore::model::ResourcePath; NS_ASSUME_NONNULL_BEGIN @@ -104,73 +107,67 @@ NS_ASSUME_NONNULL_BEGIN #pragma mark - FSTDocumentKey <=> Key proto - (NSString *)encodedDocumentKey:(FSTDocumentKey *)key { - return [self - encodedResourcePathForDatabaseID:self.databaseID - path:[FSTResourcePath resourcePathWithCPPResourcePath:key.path]]; + return [self encodedResourcePathForDatabaseID:self.databaseID path:key.path]; } - (FSTDocumentKey *)decodedDocumentKey:(NSString *)name { - FSTResourcePath *path = [self decodedResourcePathWithDatabaseID:name]; - FSTAssert([[path segmentAtIndex:1] - isEqualToString:util::WrapNSStringNoCopy(self.databaseID->project_id())], + const ResourcePath path = [self decodedResourcePathWithDatabaseID:name]; + FSTAssert(path[1] == self.databaseID->project_id(), @"Tried to deserialize key from different project."); - FSTAssert([[path segmentAtIndex:3] - isEqualToString:util::WrapNSStringNoCopy(self.databaseID->database_id())], + FSTAssert(path[3] == self.databaseID->database_id(), @"Tried to deserialize key from different datbase."); - return [FSTDocumentKey - keyWithPath:[[self localResourcePathForQualifiedResourcePath:path] toCPPResourcePath]]; + return [FSTDocumentKey keyWithPath:[self localResourcePathForQualifiedResourcePath:path]]; } - (NSString *)encodedResourcePathForDatabaseID:(const DatabaseId *)databaseID - path:(FSTResourcePath *)path { - return [[[[self encodedResourcePathForDatabaseID:databaseID] pathByAppendingSegment:@"documents"] - pathByAppendingPath:path] canonicalString]; + path:(const ResourcePath &)path { + return util::WrapNSString([self encodedResourcePathForDatabaseID:databaseID] + .Append("documents") + .Append(path) + .CanonicalString()); } -- (FSTResourcePath *)decodedResourcePathWithDatabaseID:(NSString *)name { - FSTResourcePath *path = [FSTResourcePath pathWithString:name]; - FSTAssert([self validQualifiedResourcePath:path], @"Tried to deserialize invalid key %@", path); +- (ResourcePath)decodedResourcePathWithDatabaseID:(NSString *)name { + const ResourcePath path = ResourcePath::FromString(util::MakeStringView(name)); + FSTAssert([self validQualifiedResourcePath:path], @"Tried to deserialize invalid key %s", + path.CanonicalString().c_str()); return path; } -- (NSString *)encodedQueryPath:(FSTResourcePath *)path { - if (path.length == 0) { +- (NSString *)encodedQueryPath:(const ResourcePath &)path { + if (path.size() == 0) { // If the path is empty, the backend requires we leave off the /documents at the end. return [self encodedDatabaseID]; } return [self encodedResourcePathForDatabaseID:self.databaseID path:path]; } -- (FSTResourcePath *)decodedQueryPath:(NSString *)name { - FSTResourcePath *resource = [self decodedResourcePathWithDatabaseID:name]; - if (resource.length == 4) { - return [FSTResourcePath pathWithSegments:@[]]; +- (ResourcePath)decodedQueryPath:(NSString *)name { + const ResourcePath resource = [self decodedResourcePathWithDatabaseID:name]; + if (resource.size() == 4) { + return ResourcePath{}; } else { return [self localResourcePathForQualifiedResourcePath:resource]; } } -- (FSTResourcePath *)encodedResourcePathForDatabaseID:(const DatabaseId *)databaseID { - return [FSTResourcePath pathWithSegments:@[ - @"projects", util::WrapNSString(databaseID->project_id()), @"databases", - util::WrapNSString(databaseID->database_id()) - ]]; +- (ResourcePath)encodedResourcePathForDatabaseID:(const DatabaseId *)databaseID { + return ResourcePath{"projects", databaseID->project_id(), "databases", databaseID->database_id()}; } -- (FSTResourcePath *)localResourcePathForQualifiedResourcePath:(FSTResourcePath *)resourceName { - FSTAssert( - resourceName.length > 4 && [[resourceName segmentAtIndex:4] isEqualToString:@"documents"], - @"Tried to deserialize invalid key %@", resourceName); - return [resourceName pathByRemovingFirstSegments:5]; +- (ResourcePath)localResourcePathForQualifiedResourcePath:(const ResourcePath &)resourceName { + FSTAssert(resourceName.size() > 4 && resourceName[4] == "documents", + @"Tried to deserialize invalid key %s", resourceName.CanonicalString().c_str()); + return resourceName.PopFirst(5); } -- (BOOL)validQualifiedResourcePath:(FSTResourcePath *)path { - return path.length >= 4 && [[path segmentAtIndex:0] isEqualToString:@"projects"] && - [[path segmentAtIndex:2] isEqualToString:@"databases"]; +- (BOOL)validQualifiedResourcePath:(const ResourcePath &)path { + return path.size() >= 4 && path[0] == "projects" && path[2] == "databases"; } - (NSString *)encodedDatabaseID { - return [[self encodedResourcePathForDatabaseID:self.databaseID] canonicalString]; + return util::WrapNSString( + [self encodedResourcePathForDatabaseID:self.databaseID].CanonicalString()); } #pragma mark - FSTFieldValue <=> Value proto @@ -310,31 +307,25 @@ NS_ASSUME_NONNULL_BEGIN - (GCFSValue *)encodedReferenceValueForDatabaseID:(const DatabaseId *)databaseID key:(FSTDocumentKey *)key { - FSTAssert(*databaseID == *self.databaseID, @"Database %@:%@ cannot encode reference from %@:%@", - util::WrapNSStringNoCopy(self.databaseID->project_id()), - util::WrapNSStringNoCopy(self.databaseID->database_id()), - util::WrapNSStringNoCopy(databaseID->project_id()), - util::WrapNSStringNoCopy(databaseID->database_id())); + FSTAssert(*databaseID == *self.databaseID, @"Database %s:%s cannot encode reference from %s:%s", + self.databaseID->project_id().c_str(), self.databaseID->database_id().c_str(), + databaseID->project_id().c_str(), databaseID->database_id().c_str()); GCFSValue *result = [GCFSValue message]; - result.referenceValue = [self - encodedResourcePathForDatabaseID:databaseID - path:[FSTResourcePath resourcePathWithCPPResourcePath:key.path]]; + result.referenceValue = [self encodedResourcePathForDatabaseID:databaseID path:key.path]; return result; } - (FSTReferenceValue *)decodedReferenceValue:(NSString *)resourceName { - FSTResourcePath *path = [self decodedResourcePathWithDatabaseID:resourceName]; - NSString *project = [path segmentAtIndex:1]; - NSString *database = [path segmentAtIndex:3]; - FSTDocumentKey *key = [FSTDocumentKey - keyWithPath:[[self localResourcePathForQualifiedResourcePath:path] toCPPResourcePath]]; - - const DatabaseId database_id(util::MakeStringView(project), util::MakeStringView(database)); - FSTAssert(database_id == *self.databaseID, @"Database %@:%@ cannot encode reference from %@:%@", - util::WrapNSStringNoCopy(self.databaseID->project_id()), - util::WrapNSStringNoCopy(self.databaseID->database_id()), - util::WrapNSStringNoCopy(database_id.project_id()), - util::WrapNSStringNoCopy(database_id.database_id())); + const ResourcePath path = [self decodedResourcePathWithDatabaseID:resourceName]; + const std::string &project = path[1]; + const std::string &database = path[3]; + FSTDocumentKey *key = + [FSTDocumentKey keyWithPath:[self localResourcePathForQualifiedResourcePath:path]]; + + const DatabaseId database_id(project, database); + FSTAssert(database_id == *self.databaseID, @"Database %s:%s cannot encode reference from %s:%s", + self.databaseID->project_id().c_str(), self.databaseID->database_id().c_str(), + database_id.project_id().c_str(), database_id.database_id().c_str()); return [FSTReferenceValue referenceValue:key databaseID:self.databaseID]; } @@ -389,7 +380,7 @@ NS_ASSUME_NONNULL_BEGIN __block FSTObjectValue *result = [FSTObjectValue objectValue]; [fields enumerateKeysAndObjectsUsingBlock:^(NSString *_Nonnull key, GCFSValue *_Nonnull obj, BOOL *_Nonnull stop) { - FSTFieldPath *path = [FSTFieldPath pathWithSegments:@[ key ]]; + FieldPath path{util::MakeString(key)}; FSTFieldValue *value = [self decodedFieldValue:obj]; result = [result objectBySettingValue:value forPath:path]; }]; @@ -550,19 +541,19 @@ NS_ASSUME_NONNULL_BEGIN - (GCFSDocumentMask *)encodedFieldMask:(FSTFieldMask *)fieldMask { GCFSDocumentMask *mask = [GCFSDocumentMask message]; - for (FSTFieldPath *field in fieldMask.fields) { - [mask.fieldPathsArray addObject:field.canonicalString]; + for (const FieldPath &field : fieldMask.fields) { + [mask.fieldPathsArray addObject:util::WrapNSString(field.CanonicalString())]; } return mask; } - (FSTFieldMask *)decodedFieldMask:(GCFSDocumentMask *)fieldMask { - NSMutableArray *fields = - [NSMutableArray arrayWithCapacity:fieldMask.fieldPathsArray_Count]; + std::vector fields{}; + fields.reserve(fieldMask.fieldPathsArray_Count); for (NSString *path in fieldMask.fieldPathsArray) { - [fields addObject:[FSTFieldPath pathWithServerFormat:path]]; + fields.push_back(FieldPath::FromServerFormat(util::MakeStringView(path))); } - return [[FSTFieldMask alloc] initWithFields:fields]; + return [[FSTFieldMask alloc] initWithFields:std::move(fields)]; } - (NSMutableArray *)encodedFieldTransforms: @@ -572,7 +563,7 @@ NS_ASSUME_NONNULL_BEGIN FSTAssert([fieldTransform.transform isKindOfClass:[FSTServerTimestampTransform class]], @"Unknown transform: %@", fieldTransform.transform); GCFSDocumentTransform_FieldTransform *proto = [GCFSDocumentTransform_FieldTransform message]; - proto.fieldPath = fieldTransform.path.canonicalString; + proto.fieldPath = util::WrapNSString(fieldTransform.path.CanonicalString()); proto.setToServerValue = GCFSDocumentTransform_FieldTransform_ServerValue_RequestTime; [protos addObject:proto]; } @@ -588,7 +579,8 @@ NS_ASSUME_NONNULL_BEGIN @"Unknown transform setToServerValue: %d", proto.setToServerValue); [fieldTransforms addObject:[[FSTFieldTransform alloc] - initWithPath:[FSTFieldPath pathWithServerFormat:proto.fieldPath] + initWithPath:FieldPath::FromServerFormat( + util::MakeStringView(proto.fieldPath)) transform:[FSTServerTimestampTransform serverTimestampTransform]]]; } return fieldTransforms; @@ -659,8 +651,7 @@ NS_ASSUME_NONNULL_BEGIN - (GCFSTarget_DocumentsTarget *)encodedDocumentsTarget:(FSTQuery *)query { GCFSTarget_DocumentsTarget *result = [GCFSTarget_DocumentsTarget message]; NSMutableArray *docs = result.documentsArray; - [docs addObject:[self encodedQueryPath:[FSTResourcePath - resourcePathWithCPPResourcePath:query.path]]]; + [docs addObject:[self encodedQueryPath:query.path]]; return result; } @@ -670,21 +661,20 @@ NS_ASSUME_NONNULL_BEGIN (unsigned long)documents.count); NSString *name = documents[0]; - return [FSTQuery queryWithPath:[[self decodedQueryPath:name] toCPPResourcePath]]; + return [FSTQuery queryWithPath:[self decodedQueryPath:name]]; } - (GCFSTarget_QueryTarget *)encodedQueryTarget:(FSTQuery *)query { // Dissect the path into parent, collectionId, and optional key filter. GCFSTarget_QueryTarget *queryTarget = [GCFSTarget_QueryTarget message]; - if (query.path.empty()) { - queryTarget.parent = - [self encodedQueryPath:[FSTResourcePath resourcePathWithCPPResourcePath:query.path]]; + if (query.path.size() == 0) { + queryTarget.parent = [self encodedQueryPath:query.path]; } else { - FSTResourcePath *path = [FSTResourcePath resourcePathWithCPPResourcePath:query.path]; - FSTAssert(path.length % 2 != 0, @"Document queries with filters are not supported."); - queryTarget.parent = [self encodedQueryPath:[path pathByRemovingLastSegment]]; + const ResourcePath &path = query.path; + FSTAssert(path.size() % 2 != 0, @"Document queries with filters are not supported."); + queryTarget.parent = [self encodedQueryPath:path.PopLast()]; GCFSStructuredQuery_CollectionSelector *from = [GCFSStructuredQuery_CollectionSelector message]; - from.collectionId = path.lastSegment; + from.collectionId = util::WrapNSString(path.last_segment()); [queryTarget.structuredQuery.fromArray addObject:from]; } @@ -715,7 +705,7 @@ NS_ASSUME_NONNULL_BEGIN } - (FSTQuery *)decodedQueryFromQueryTarget:(GCFSTarget_QueryTarget *)target { - FSTResourcePath *path = [self decodedQueryPath:target.parent]; + ResourcePath path = [self decodedQueryPath:target.parent]; GCFSStructuredQuery *query = target.structuredQuery; NSUInteger fromCount = query.fromArray_Count; @@ -724,7 +714,7 @@ NS_ASSUME_NONNULL_BEGIN @"StructuredQuery.from with more than one collection is not supported."); GCFSStructuredQuery_CollectionSelector *from = query.fromArray[0]; - path = [path pathByAppendingSegment:from.collectionId]; + path = path.Append(util::MakeString(from.collectionId)); } NSArray> *filterBy; @@ -756,7 +746,7 @@ NS_ASSUME_NONNULL_BEGIN endAt = [self decodedBound:query.endAt]; } - return [[FSTQuery alloc] initWithPath:[path toCPPResourcePath] + return [[FSTQuery alloc] initWithPath:path filterBy:filterBy orderBy:orderBy limit:limit @@ -825,25 +815,22 @@ NS_ASSUME_NONNULL_BEGIN - (GCFSStructuredQuery_Filter *)encodedRelationFilter:(FSTRelationFilter *)filter { GCFSStructuredQuery_Filter *proto = [GCFSStructuredQuery_Filter message]; GCFSStructuredQuery_FieldFilter *fieldFilter = proto.fieldFilter; - fieldFilter.field = [self encodedFieldPath:[FSTFieldPath fieldPathWithCPPFieldPath:filter.field]]; + fieldFilter.field = [self encodedFieldPath:filter.field]; fieldFilter.op = [self encodedRelationFilterOperator:filter.filterOperator]; fieldFilter.value = [self encodedFieldValue:filter.value]; return proto; } - (FSTRelationFilter *)decodedRelationFilter:(GCFSStructuredQuery_FieldFilter *)proto { - FSTFieldPath *fieldPath = [FSTFieldPath pathWithServerFormat:proto.field.fieldPath]; + FieldPath fieldPath = FieldPath::FromServerFormat(util::MakeString(proto.field.fieldPath)); FSTRelationFilterOperator filterOperator = [self decodedRelationFilterOperator:proto.op]; FSTFieldValue *value = [self decodedFieldValue:proto.value]; - return [FSTRelationFilter filterWithField:[fieldPath toCPPFieldPath] - filterOperator:filterOperator - value:value]; + return [FSTRelationFilter filterWithField:fieldPath filterOperator:filterOperator value:value]; } - (GCFSStructuredQuery_Filter *)encodedUnaryFilter:(id)filter { GCFSStructuredQuery_Filter *proto = [GCFSStructuredQuery_Filter message]; - proto.unaryFilter.field = - [self encodedFieldPath:[FSTFieldPath fieldPathWithCPPFieldPath:filter.field]]; + proto.unaryFilter.field = [self encodedFieldPath:filter.field]; if ([filter isKindOfClass:[FSTNanFilter class]]) { proto.unaryFilter.op = GCFSStructuredQuery_UnaryFilter_Operator_IsNan; } else if ([filter isKindOfClass:[FSTNullFilter class]]) { @@ -855,22 +842,22 @@ NS_ASSUME_NONNULL_BEGIN } - (id)decodedUnaryFilter:(GCFSStructuredQuery_UnaryFilter *)proto { - FSTFieldPath *field = [FSTFieldPath pathWithServerFormat:proto.field.fieldPath]; + FieldPath field = FieldPath::FromServerFormat(util::MakeString(proto.field.fieldPath)); switch (proto.op) { case GCFSStructuredQuery_UnaryFilter_Operator_IsNan: - return [[FSTNanFilter alloc] initWithField:[field toCPPFieldPath]]; + return [[FSTNanFilter alloc] initWithField:field]; case GCFSStructuredQuery_UnaryFilter_Operator_IsNull: - return [[FSTNullFilter alloc] initWithField:[field toCPPFieldPath]]; + return [[FSTNullFilter alloc] initWithField:field]; default: FSTFail(@"Unrecognized UnaryFilter.operator %d", proto.op); } } -- (GCFSStructuredQuery_FieldReference *)encodedFieldPath:(FSTFieldPath *)fieldPath { +- (GCFSStructuredQuery_FieldReference *)encodedFieldPath:(const FieldPath &)fieldPath { GCFSStructuredQuery_FieldReference *ref = [GCFSStructuredQuery_FieldReference message]; - ref.fieldPath = fieldPath.canonicalString; + ref.fieldPath = util::WrapNSString(fieldPath.CanonicalString()); return ref; } @@ -930,7 +917,7 @@ NS_ASSUME_NONNULL_BEGIN - (GCFSStructuredQuery_Order *)encodedSortOrder:(FSTSortOrder *)sortOrder { GCFSStructuredQuery_Order *proto = [GCFSStructuredQuery_Order message]; - proto.field = [self encodedFieldPath:[FSTFieldPath fieldPathWithCPPFieldPath:sortOrder.field]]; + proto.field = [self encodedFieldPath:sortOrder.field]; if (sortOrder.ascending) { proto.direction = GCFSStructuredQuery_Direction_Ascending; } else { @@ -940,7 +927,7 @@ NS_ASSUME_NONNULL_BEGIN } - (FSTSortOrder *)decodedSortOrder:(GCFSStructuredQuery_Order *)proto { - FSTFieldPath *fieldPath = [FSTFieldPath pathWithServerFormat:proto.field.fieldPath]; + FieldPath fieldPath = FieldPath::FromServerFormat(util::MakeString(proto.field.fieldPath)); BOOL ascending; switch (proto.direction) { case GCFSStructuredQuery_Direction_Ascending: @@ -952,7 +939,7 @@ NS_ASSUME_NONNULL_BEGIN default: FSTFail(@"Unrecognized GCFSStructuredQuery_Direction %d", proto.direction); } - return [FSTSortOrder sortOrderWithFieldPath:[fieldPath toCPPFieldPath] ascending:ascending]; + return [FSTSortOrder sortOrderWithFieldPath:fieldPath ascending:ascending]; } #pragma mark - Bounds/Cursors diff --git a/Firestore/core/src/firebase/firestore/model/field_path.h b/Firestore/core/src/firebase/firestore/model/field_path.h index fdf4918..ce3527d 100644 --- a/Firestore/core/src/firebase/firestore/model/field_path.h +++ b/Firestore/core/src/firebase/firestore/model/field_path.h @@ -48,6 +48,8 @@ class FieldPath : public impl::BasePath { } FieldPath(std::initializer_list list) : BasePath{list} { } + explicit FieldPath(SegmentsT&& segments) : BasePath{std::move(segments)} { + } /** * Creates and returns a new path from the server formatted field-path string, @@ -83,14 +85,6 @@ class FieldPath : public impl::BasePath { bool operator>=(const FieldPath& rhs) const { return BasePath::operator>=(rhs); } - - private: - explicit FieldPath(SegmentsT&& segments) : BasePath{std::move(segments)} { - } - - // So that methods of base can construct FieldPath using the private - // constructor. - friend class BasePath; }; } // namespace model diff --git a/Firestore/core/src/firebase/firestore/model/resource_path.h b/Firestore/core/src/firebase/firestore/model/resource_path.h index 6ff1b68..acdf1e2 100644 --- a/Firestore/core/src/firebase/firestore/model/resource_path.h +++ b/Firestore/core/src/firebase/firestore/model/resource_path.h @@ -70,11 +70,6 @@ class ResourcePath : public impl::BasePath { bool operator>=(const ResourcePath& rhs) const { return BasePath::operator>=(rhs); } - - private: - // So that methods of base can construct ResourcePath using the private - // constructor. - friend class BasePath; }; } // namespace model diff --git a/Firestore/core/src/firebase/firestore/util/string_apple.h b/Firestore/core/src/firebase/firestore/util/string_apple.h index 3f6b814..73388be 100644 --- a/Firestore/core/src/firebase/firestore/util/string_apple.h +++ b/Firestore/core/src/firebase/firestore/util/string_apple.h @@ -22,6 +22,8 @@ #import +#include + #include "absl/strings/string_view.h" namespace firebase { @@ -57,6 +59,12 @@ inline absl::string_view MakeStringView(NSString* str) { [str UTF8String], [str lengthOfBytesUsingEncoding:NSUTF8StringEncoding]); } +// Creates a std::string wrapper for the contents of the given NSString. +inline std::string MakeString(NSString* str) { + return std::string([str UTF8String], + [str lengthOfBytesUsingEncoding:NSUTF8StringEncoding]); +} + } // namespace util } // namespace firestore } // namespace firebase -- cgit v1.2.3