aboutsummaryrefslogtreecommitdiffhomepage
path: root/Firestore
diff options
context:
space:
mode:
authorGravatar zxu <zxu@google.com>2018-03-05 11:30:59 -0500
committerGravatar GitHub <noreply@github.com>2018-03-05 11:30:59 -0500
commit1c40e7aada6b32bbc621f06fb5f380149606a58d (patch)
tree6dee81f74f8a33d1beae915d9227caf28b8e2598 /Firestore
parent9b5b4d876eb77e65b3246614855088be101eebf3 (diff)
add converters and port paths to FSTQuery (#869)
* add converters and fix FSTQuery.{h,m} only * address changes * a change forget to address * add a dummy function to make inline-only-library buildable
Diffstat (limited to 'Firestore')
-rw-r--r--Firestore/Example/Tests/Core/FSTQueryTests.mm39
-rw-r--r--Firestore/Example/Tests/Core/FSTViewTests.mm24
-rw-r--r--Firestore/Example/Tests/Model/FSTPathTests.mm24
-rw-r--r--Firestore/Example/Tests/Remote/FSTSerializerBetaTests.mm6
-rw-r--r--Firestore/Example/Tests/Util/FSTHelpers.mm15
-rw-r--r--Firestore/Source/API/FIRCollectionReference.mm31
-rw-r--r--Firestore/Source/API/FIRDocumentReference.mm2
-rw-r--r--Firestore/Source/API/FIRQuery.mm52
-rw-r--r--Firestore/Source/Core/FSTQuery.h41
-rw-r--r--Firestore/Source/Core/FSTQuery.mm221
-rw-r--r--Firestore/Source/Core/FSTSyncEngine.mm3
-rw-r--r--Firestore/Source/Local/FSTLevelDBMutationQueue.mm2
-rw-r--r--Firestore/Source/Local/FSTLevelDBRemoteDocumentCache.mm5
-rw-r--r--Firestore/Source/Local/FSTLocalDocumentsView.mm6
-rw-r--r--Firestore/Source/Local/FSTMemoryMutationQueue.mm4
-rw-r--r--Firestore/Source/Local/FSTMemoryRemoteDocumentCache.mm5
-rw-r--r--Firestore/Source/Model/FSTPath.h26
-rw-r--r--Firestore/Source/Model/FSTPath.mm43
-rw-r--r--Firestore/Source/Remote/FSTRemoteStore.mm4
-rw-r--r--Firestore/Source/Remote/FSTSerializerBeta.mm31
-rw-r--r--Firestore/core/src/firebase/firestore/model/base_path.h13
-rw-r--r--Firestore/core/test/firebase/firestore/testutil/CMakeLists.txt14
-rw-r--r--Firestore/core/test/firebase/firestore/testutil/testutil.cc28
-rw-r--r--Firestore/core/test/firebase/firestore/testutil/testutil.h41
24 files changed, 485 insertions, 195 deletions
diff --git a/Firestore/Example/Tests/Core/FSTQueryTests.mm b/Firestore/Example/Tests/Core/FSTQueryTests.mm
index c0b2cd9..5f6d279 100644
--- a/Firestore/Example/Tests/Core/FSTQueryTests.mm
+++ b/Firestore/Example/Tests/Core/FSTQueryTests.mm
@@ -26,10 +26,16 @@
#import "Firestore/Example/Tests/Util/FSTHelpers.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"
+#include "Firestore/core/test/firebase/firestore/testutil/testutil.h"
+namespace testutil = firebase::firestore::testutil;
namespace util = firebase::firestore::util;
using firebase::firestore::model::DatabaseId;
+using firebase::firestore::model::FieldPath;
+using firebase::firestore::model::ResourcePath;
NS_ASSUME_NONNULL_BEGIN
@@ -41,8 +47,10 @@ NS_ASSUME_NONNULL_BEGIN
@implementation FSTQuery (Tests)
- (FSTQuery *)queryByAddingSortBy:(NSString *)key ascending:(BOOL)ascending {
- return [self queryByAddingSortOrder:[FSTSortOrder sortOrderWithFieldPath:FSTTestFieldPath(key)
- ascending:ascending]];
+ return [self
+ queryByAddingSortOrder:[FSTSortOrder
+ sortOrderWithFieldPath:testutil::Field(util::MakeStringView(key))
+ ascending:ascending]];
}
@end
@@ -55,11 +63,11 @@ NS_ASSUME_NONNULL_BEGIN
- (void)testConstructor {
FSTResourcePath *path =
[FSTResourcePath pathWithSegments:@[ @"rooms", @"Firestore", @"messages", @"0001" ]];
- FSTQuery *query = [FSTQuery queryWithPath:path];
+ FSTQuery *query = [FSTQuery queryWithPath:[path toCPPResourcePath]];
XCTAssertNotNil(query);
XCTAssertEqual(query.sortOrders.count, 1);
- XCTAssertEqualObjects(query.sortOrders[0].field.canonicalString, kDocumentKeyPath);
+ XCTAssertEqual(query.sortOrders[0].field.CanonicalString(), FieldPath::kDocumentKeyPath);
XCTAssertEqual(query.sortOrders[0].ascending, YES);
XCTAssertEqual(query.explicitSortOrders.count, 0);
@@ -68,17 +76,17 @@ NS_ASSUME_NONNULL_BEGIN
- (void)testOrderBy {
FSTQuery *query = FSTTestQuery(@"rooms/Firestore/messages");
query =
- [query queryByAddingSortOrder:[FSTSortOrder sortOrderWithFieldPath:FSTTestFieldPath(@"length")
+ [query queryByAddingSortOrder:[FSTSortOrder sortOrderWithFieldPath:testutil::Field("length")
ascending:NO]];
XCTAssertEqual(query.sortOrders.count, 2);
- XCTAssertEqualObjects(query.sortOrders[0].field.canonicalString, @"length");
+ XCTAssertEqual(query.sortOrders[0].field.CanonicalString(), "length");
XCTAssertEqual(query.sortOrders[0].ascending, NO);
- XCTAssertEqualObjects(query.sortOrders[1].field.canonicalString, kDocumentKeyPath);
+ XCTAssertEqual(query.sortOrders[1].field.CanonicalString(), FieldPath::kDocumentKeyPath);
XCTAssertEqual(query.sortOrders[1].ascending, NO);
XCTAssertEqual(query.explicitSortOrders.count, 1);
- XCTAssertEqualObjects(query.explicitSortOrders[0].field.canonicalString, @"length");
+ XCTAssertEqual(query.explicitSortOrders[0].field.CanonicalString(), "length");
XCTAssertEqual(query.explicitSortOrders[0].ascending, NO);
}
@@ -211,7 +219,7 @@ NS_ASSUME_NONNULL_BEGIN
- (void)testDoesntRemoveComplexObjectsWithOrderBy {
FSTQuery *query1 = [FSTTestQuery(@"collection")
- queryByAddingSortOrder:[FSTSortOrder sortOrderWithFieldPath:FSTTestFieldPath(@"sort")
+ queryByAddingSortOrder:[FSTSortOrder sortOrderWithFieldPath:testutil::Field("sort")
ascending:YES]];
FSTDocument *doc1 = FSTTestDoc(@"collection/1", 0, @{ @"sort" : @2 }, NO);
@@ -305,9 +313,8 @@ NS_ASSUME_NONNULL_BEGIN
- (void)testSortsDocumentsInTheCorrectOrder {
FSTQuery *query = FSTTestQuery(@"collection");
- query =
- [query queryByAddingSortOrder:[FSTSortOrder sortOrderWithFieldPath:FSTTestFieldPath(@"sort")
- ascending:YES]];
+ query = [query queryByAddingSortOrder:[FSTSortOrder sortOrderWithFieldPath:testutil::Field("sort")
+ ascending:YES]];
// clang-format off
NSArray<FSTDocument *> *docs = @[
@@ -335,10 +342,10 @@ NS_ASSUME_NONNULL_BEGIN
- (void)testSortsDocumentsUsingMultipleFields {
FSTQuery *query = FSTTestQuery(@"collection");
query =
- [query queryByAddingSortOrder:[FSTSortOrder sortOrderWithFieldPath:FSTTestFieldPath(@"sort1")
+ [query queryByAddingSortOrder:[FSTSortOrder sortOrderWithFieldPath:testutil::Field("sort1")
ascending:YES]];
query =
- [query queryByAddingSortOrder:[FSTSortOrder sortOrderWithFieldPath:FSTTestFieldPath(@"sort2")
+ [query queryByAddingSortOrder:[FSTSortOrder sortOrderWithFieldPath:testutil::Field("sort2")
ascending:YES]];
// clang-format off
@@ -362,10 +369,10 @@ NS_ASSUME_NONNULL_BEGIN
- (void)testSortsDocumentsWithDescendingToo {
FSTQuery *query = FSTTestQuery(@"collection");
query =
- [query queryByAddingSortOrder:[FSTSortOrder sortOrderWithFieldPath:FSTTestFieldPath(@"sort1")
+ [query queryByAddingSortOrder:[FSTSortOrder sortOrderWithFieldPath:testutil::Field("sort1")
ascending:NO]];
query =
- [query queryByAddingSortOrder:[FSTSortOrder sortOrderWithFieldPath:FSTTestFieldPath(@"sort2")
+ [query queryByAddingSortOrder:[FSTSortOrder sortOrderWithFieldPath:testutil::Field("sort2")
ascending:NO]];
// clang-format off
diff --git a/Firestore/Example/Tests/Core/FSTViewTests.mm b/Firestore/Example/Tests/Core/FSTViewTests.mm
index e6c4510..7df8195 100644
--- a/Firestore/Example/Tests/Core/FSTViewTests.mm
+++ b/Firestore/Example/Tests/Core/FSTViewTests.mm
@@ -30,6 +30,12 @@
#import "Firestore/Example/Tests/Util/FSTHelpers.h"
+#include "Firestore/core/src/firebase/firestore/model/resource_path.h"
+#include "Firestore/core/test/firebase/firestore/testutil/testutil.h"
+
+namespace testutil = firebase::firestore::testutil;
+using firebase::firestore::model::ResourcePath;
+
NS_ASSUME_NONNULL_BEGIN
@interface FSTViewTests : XCTestCase
@@ -39,8 +45,7 @@ NS_ASSUME_NONNULL_BEGIN
/** Returns a new empty query to use for testing. */
- (FSTQuery *)queryForMessages {
- return [FSTQuery
- queryWithPath:[FSTResourcePath pathWithSegments:@[ @"rooms", @"eros", @"messages" ]]];
+ return [FSTQuery queryWithPath:ResourcePath{"rooms", "eros", "messages"}];
}
- (void)testAddsDocumentsBasedOnQuery {
@@ -128,7 +133,7 @@ NS_ASSUME_NONNULL_BEGIN
- (void)testFiltersDocumentsBasedOnQueryWithFilter {
FSTQuery *query = [self queryForMessages];
FSTRelationFilter *filter =
- [FSTRelationFilter filterWithField:FSTTestFieldPath(@"sort")
+ [FSTRelationFilter filterWithField:testutil::Field("sort")
filterOperator:FSTRelationFilterOperatorLessThanOrEqual
value:[FSTDoubleValue doubleValue:2]];
query = [query queryByAddingFilter:filter];
@@ -160,7 +165,7 @@ NS_ASSUME_NONNULL_BEGIN
- (void)testUpdatesDocumentsBasedOnQueryWithFilter {
FSTQuery *query = [self queryForMessages];
FSTRelationFilter *filter =
- [FSTRelationFilter filterWithField:FSTTestFieldPath(@"sort")
+ [FSTRelationFilter filterWithField:testutil::Field("sort")
filterOperator:FSTRelationFilterOperatorLessThanOrEqual
value:[FSTDoubleValue doubleValue:2]];
query = [query queryByAddingFilter:filter];
@@ -232,9 +237,8 @@ NS_ASSUME_NONNULL_BEGIN
- (void)testDoesntReportChangesForDocumentBeyondLimitOfQuery {
FSTQuery *query = [self queryForMessages];
- query =
- [query queryByAddingSortOrder:[FSTSortOrder sortOrderWithFieldPath:FSTTestFieldPath(@"num")
- ascending:YES]];
+ query = [query queryByAddingSortOrder:[FSTSortOrder sortOrderWithFieldPath:testutil::Field("num")
+ ascending:YES]];
query = [query queryBySettingLimit:2];
FSTView *view = [[FSTView alloc] initWithQuery:query remoteDocuments:[FSTDocumentKeySet keySet]];
@@ -385,7 +389,7 @@ NS_ASSUME_NONNULL_BEGIN
- (void)testReturnsNeedsRefillOnReorderInLimitQuery {
FSTQuery *query = [self queryForMessages];
query =
- [query queryByAddingSortOrder:[FSTSortOrder sortOrderWithFieldPath:FSTTestFieldPath(@"order")
+ [query queryByAddingSortOrder:[FSTSortOrder sortOrderWithFieldPath:testutil::Field("order")
ascending:YES]];
query = [query queryBySettingLimit:2];
FSTDocument *doc1 = FSTTestDoc(@"rooms/eros/messages/0", 0, @{ @"order" : @1 }, NO);
@@ -419,7 +423,7 @@ NS_ASSUME_NONNULL_BEGIN
- (void)testDoesntNeedRefillOnReorderWithinLimit {
FSTQuery *query = [self queryForMessages];
query =
- [query queryByAddingSortOrder:[FSTSortOrder sortOrderWithFieldPath:FSTTestFieldPath(@"order")
+ [query queryByAddingSortOrder:[FSTSortOrder sortOrderWithFieldPath:testutil::Field("order")
ascending:YES]];
query = [query queryBySettingLimit:3];
FSTDocument *doc1 = FSTTestDoc(@"rooms/eros/messages/0", 0, @{ @"order" : @1 }, NO);
@@ -449,7 +453,7 @@ NS_ASSUME_NONNULL_BEGIN
- (void)testDoesntNeedRefillOnReorderAfterLimitQuery {
FSTQuery *query = [self queryForMessages];
query =
- [query queryByAddingSortOrder:[FSTSortOrder sortOrderWithFieldPath:FSTTestFieldPath(@"order")
+ [query queryByAddingSortOrder:[FSTSortOrder sortOrderWithFieldPath:testutil::Field("order")
ascending:YES]];
query = [query queryBySettingLimit:3];
FSTDocument *doc1 = FSTTestDoc(@"rooms/eros/messages/0", 0, @{ @"order" : @1 }, NO);
diff --git a/Firestore/Example/Tests/Model/FSTPathTests.mm b/Firestore/Example/Tests/Model/FSTPathTests.mm
index 68bcc44..388c5c3 100644
--- a/Firestore/Example/Tests/Model/FSTPathTests.mm
+++ b/Firestore/Example/Tests/Model/FSTPathTests.mm
@@ -195,6 +195,30 @@ NS_ASSUME_NONNULL_BEGIN
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 fc4060b..5cd816f 100644
--- a/Firestore/Example/Tests/Remote/FSTSerializerBetaTests.mm
+++ b/Firestore/Example/Tests/Remote/FSTSerializerBetaTests.mm
@@ -48,7 +48,9 @@
#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;
@@ -581,7 +583,7 @@ NS_ASSUME_NONNULL_BEGIN
- (void)testEncodesSortOrders {
FSTQuery *q = [FSTTestQuery(@"docs")
- queryByAddingSortOrder:[FSTSortOrder sortOrderWithFieldPath:FSTTestFieldPath(@"prop")
+ queryByAddingSortOrder:[FSTSortOrder sortOrderWithFieldPath:testutil::Field("prop")
ascending:YES]];
FSTQueryData *model = [self queryDataForQuery:q];
@@ -601,7 +603,7 @@ NS_ASSUME_NONNULL_BEGIN
- (void)testEncodesSortOrdersDescending {
FSTQuery *q = [FSTTestQuery(@"rooms/1/messages/10/attachments")
- queryByAddingSortOrder:[FSTSortOrder sortOrderWithFieldPath:FSTTestFieldPath(@"prop")
+ queryByAddingSortOrder:[FSTSortOrder sortOrderWithFieldPath:testutil::Field("prop")
ascending:NO]];
FSTQueryData *model = [self queryDataForQuery:q];
diff --git a/Firestore/Example/Tests/Util/FSTHelpers.mm b/Firestore/Example/Tests/Util/FSTHelpers.mm
index 649486a..9b05604 100644
--- a/Firestore/Example/Tests/Util/FSTHelpers.mm
+++ b/Firestore/Example/Tests/Util/FSTHelpers.mm
@@ -183,7 +183,7 @@ FSTDocumentKeyReference *FSTTestRef(const absl::string_view projectID,
}
FSTQuery *FSTTestQuery(NSString *path) {
- return [FSTQuery queryWithPath:FSTTestPath(path)];
+ return [FSTQuery queryWithPath:[FSTTestPath(path) toCPPResourcePath]];
}
id<FSTFilter> FSTTestFilter(NSString *field, NSString *opString, id value) {
@@ -206,12 +206,12 @@ id<FSTFilter> 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];
+ return [[FSTNanFilter alloc] initWithField:[path toCPPFieldPath]];
} else if ([data isEqual:[FSTNullValue nullValue]]) {
FSTCAssert(op == FSTRelationFilterOperatorEqual, @"Must use == with Null.");
- return [[FSTNullFilter alloc] initWithField:path];
+ return [[FSTNullFilter alloc] initWithField:[path toCPPFieldPath]];
} else {
- return [FSTRelationFilter filterWithField:path filterOperator:op value:data];
+ return [FSTRelationFilter filterWithField:[path toCPPFieldPath] filterOperator:op value:data];
}
}
@@ -225,13 +225,14 @@ FSTSortOrder *FSTTestOrderBy(NSString *field, NSString *direction) {
} else {
FSTCFail(@"Unsupported direction: %@", direction);
}
- return [FSTSortOrder sortOrderWithFieldPath:path ascending:ascending];
+ return [FSTSortOrder sortOrderWithFieldPath:[path toCPPFieldPath] ascending:ascending];
}
NSComparator FSTTestDocComparator(NSString *fieldPath) {
FSTQuery *query = [FSTTestQuery(@"docs")
- queryByAddingSortOrder:[FSTSortOrder sortOrderWithFieldPath:FSTTestFieldPath(fieldPath)
- ascending:YES]];
+ queryByAddingSortOrder:[FSTSortOrder
+ sortOrderWithFieldPath:[FSTTestFieldPath(fieldPath) toCPPFieldPath]
+ ascending:YES]];
return [query comparator];
}
diff --git a/Firestore/Source/API/FIRCollectionReference.mm b/Firestore/Source/API/FIRCollectionReference.mm
index a8de29b..cb7b61a 100644
--- a/Firestore/Source/API/FIRCollectionReference.mm
+++ b/Firestore/Source/API/FIRCollectionReference.mm
@@ -28,6 +28,11 @@
#import "Firestore/Source/Util/FSTAssert.h"
#import "Firestore/Source/Util/FSTUsageValidation.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::ResourcePath;
using firebase::firestore::util::CreateAutoId;
NS_ASSUME_NONNULL_BEGIN
@@ -57,7 +62,8 @@ NS_ASSUME_NONNULL_BEGIN
"number of segments, but %@ has %d",
path.canonicalString, path.length);
}
- self = [super initWithQuery:[FSTQuery queryWithPath:path] firestore:firestore];
+ self =
+ [super initWithQuery:[FSTQuery queryWithPath:[path toCPPResourcePath]] firestore:firestore];
return self;
}
@@ -87,30 +93,33 @@ NS_ASSUME_NONNULL_BEGIN
}
- (NSString *)collectionID {
- return [self.query.path lastSegment];
+ return util::WrapNSString(self.query.path.last_segment());
}
- (FIRDocumentReference *_Nullable)parent {
- FSTResourcePath *parentPath = [self.query.path pathByRemovingLastSegment];
- if (parentPath.isEmpty) {
+ const ResourcePath parentPath = self.query.path.PopLast();
+ if (parentPath.empty()) {
return nil;
} else {
- FSTDocumentKey *key = [FSTDocumentKey keyWithPath:parentPath];
+ FSTDocumentKey *key =
+ [FSTDocumentKey keyWithPath:[FSTResourcePath resourcePathWithCPPResourcePath:parentPath]];
return [FIRDocumentReference referenceWithKey:key firestore:self.firestore];
}
}
- (NSString *)path {
- return [self.query.path canonicalString];
+ return util::WrapNSString(self.query.path.CanonicalString());
}
- (FIRDocumentReference *)documentWithPath:(NSString *)documentPath {
if (!documentPath) {
FSTThrowInvalidArgument(@"Document path cannot be nil.");
}
- FSTResourcePath *subPath = [FSTResourcePath pathWithString:documentPath];
- FSTResourcePath *path = [self.query.path pathByAppendingPath:subPath];
- return [FIRDocumentReference referenceWithPath:path firestore:self.firestore];
+ 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];
}
- (FIRDocumentReference *)addDocumentWithData:(NSDictionary<NSString *, id> *)data {
@@ -126,9 +135,9 @@ NS_ASSUME_NONNULL_BEGIN
}
- (FIRDocumentReference *)documentWithAutoID {
- NSString *autoID = [NSString stringWithUTF8String:CreateAutoId().c_str()];
+ const ResourcePath path = self.query.path.Append(CreateAutoId());
FSTDocumentKey *key =
- [FSTDocumentKey keyWithPath:[self.query.path pathByAppendingSegment:autoID]];
+ [FSTDocumentKey keyWithPath:[FSTResourcePath resourcePathWithCPPResourcePath:path]];
return [FIRDocumentReference referenceWithKey:key firestore:self.firestore];
}
diff --git a/Firestore/Source/API/FIRDocumentReference.mm b/Firestore/Source/API/FIRDocumentReference.mm
index 05253f7..b1a5d49 100644
--- a/Firestore/Source/API/FIRDocumentReference.mm
+++ b/Firestore/Source/API/FIRDocumentReference.mm
@@ -266,7 +266,7 @@ NS_ASSUME_NONNULL_BEGIN
addSnapshotListenerInternalWithOptions:(FSTListenOptions *)internalOptions
listener:(FIRDocumentSnapshotBlock)listener {
FIRFirestore *firestore = self.firestore;
- FSTQuery *query = [FSTQuery queryWithPath:self.key.path];
+ FSTQuery *query = [FSTQuery queryWithPath:[self.key.path toCPPResourcePath]];
FSTDocumentKey *key = self.key;
FSTViewSnapshotHandler snapshotHandler = ^(FSTViewSnapshot *snapshot, NSError *error) {
diff --git a/Firestore/Source/API/FIRQuery.mm b/Firestore/Source/API/FIRQuery.mm
index 1bbf91e..45ee482 100644
--- a/Firestore/Source/API/FIRQuery.mm
+++ b/Firestore/Source/API/FIRQuery.mm
@@ -38,6 +38,14 @@
#import "Firestore/Source/Util/FSTAsyncQueryListener.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 FIRQueryListenOptions ()
@@ -371,7 +379,8 @@ addSnapshotListenerInternalWithOptions:(FSTListenOptions *)internalOptions
@"Invalid query. You must not specify an ending point before specifying the order by.");
}
FSTSortOrder *sortOrder =
- [FSTSortOrder sortOrderWithFieldPath:fieldPath.internalValue ascending:!descending];
+ [FSTSortOrder sortOrderWithFieldPath:[fieldPath.internalValue toCPPFieldPath]
+ ascending:!descending];
return [FIRQuery referenceWithQuery:[self.query queryByAddingSortOrder:sortOrder]
firestore:self.firestore];
}
@@ -460,7 +469,8 @@ addSnapshotListenerInternalWithOptions:(FSTListenOptions *)internalOptions
@"Invalid query. When querying by document ID you must provide "
"a valid document ID, but it was an empty string.");
}
- FSTResourcePath *path = [self.query.path pathByAppendingSegment:documentKey];
+ FSTResourcePath *path = [[FSTResourcePath resourcePathWithCPPResourcePath:self.query.path]
+ pathByAppendingSegment:documentKey];
fieldValue = [FSTReferenceValue referenceValue:[FSTDocumentKey keyWithPath:path]
databaseID:self.firestore.databaseID];
} else if ([value isKindOfClass:[FIRDocumentReference class]]) {
@@ -483,15 +493,15 @@ addSnapshotListenerInternalWithOptions:(FSTListenOptions *)internalOptions
@"Invalid Query. You can only perform equality comparisons on nil / "
"NSNull.");
}
- filter = [[FSTNullFilter alloc] initWithField:fieldPath];
+ filter = [[FSTNullFilter alloc] initWithField:[fieldPath toCPPFieldPath]];
} 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];
+ filter = [[FSTNanFilter alloc] initWithField:[fieldPath toCPPFieldPath]];
} else {
- filter = [FSTRelationFilter filterWithField:fieldPath
+ filter = [FSTRelationFilter filterWithField:[fieldPath toCPPFieldPath]
filterOperator:filterOperator
value:fieldValue];
[self validateNewRelationFilter:filter];
@@ -502,19 +512,21 @@ addSnapshotListenerInternalWithOptions:(FSTListenOptions *)internalOptions
- (void)validateNewRelationFilter:(FSTRelationFilter *)filter {
if ([filter isInequality]) {
- FSTFieldPath *existingField = [self.query inequalityFilterField];
- if (existingField && ![existingField isEqual:filter.field]) {
+ const FieldPath *existingField = [self.query inequalityFilterField];
+ if (existingField && *existingField != filter.field) {
FSTThrowInvalidUsage(
@"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 '%@'",
- existingField, filter.field);
+ util::WrapNSStringNoCopy(existingField->CanonicalString()),
+ util::WrapNSStringNoCopy(filter.field.CanonicalString()));
}
- FSTFieldPath *firstOrderByField = [self.query firstSortOrderField];
+ const FieldPath *firstOrderByField = [self.query firstSortOrderField];
if (firstOrderByField) {
- [self validateOrderByField:firstOrderByField matchesInequalityField:filter.field];
+ [self validateOrderByField:[FSTFieldPath fieldPathWithCPPFieldPath:*firstOrderByField]
+ matchesInequalityField:[FSTFieldPath fieldPathWithCPPFieldPath:filter.field]];
}
}
}
@@ -522,9 +534,10 @@ addSnapshotListenerInternalWithOptions:(FSTListenOptions *)internalOptions
- (void)validateNewOrderByPath:(FSTFieldPath *)fieldPath {
if (![self.query firstSortOrderField]) {
// This is the first order by. It must match any inequality.
- FSTFieldPath *inequalityField = [self.query inequalityFilterField];
+ const FieldPath *inequalityField = [self.query inequalityFilterField];
if (inequalityField) {
- [self validateOrderByField:fieldPath matchesInequalityField:inequalityField];
+ [self validateOrderByField:fieldPath
+ matchesInequalityField:[FSTFieldPath fieldPathWithCPPFieldPath:*inequalityField]];
}
}
}
@@ -565,11 +578,12 @@ addSnapshotListenerInternalWithOptions:(FSTListenOptions *)internalOptions
// continues/ends exactly at the provided document. Without the key (by using the explicit sort
// orders), multiple documents could match the position, yielding duplicate results.
for (FSTSortOrder *sortOrder in self.query.sortOrders) {
- if ([sortOrder.field isEqual:[FSTFieldPath keyFieldPath]]) {
+ if (sortOrder.field == FieldPath::KeyFieldPath()) {
[components addObject:[FSTReferenceValue referenceValue:document.key
databaseID:self.firestore.databaseID]];
} else {
- FSTFieldValue *value = [document fieldForPath:sortOrder.field];
+ FSTFieldValue *value =
+ [document fieldForPath:[FSTFieldPath fieldPathWithCPPFieldPath:sortOrder.field]];
if (value != nil) {
[components addObject:value];
} else {
@@ -577,7 +591,7 @@ addSnapshotListenerInternalWithOptions:(FSTListenOptions *)internalOptions
@"Invalid query. You are trying to start or end a query using a "
"document for which the field '%@' (used as the order by) "
"does not exist.",
- sortOrder.field.canonicalString);
+ util::WrapNSStringNoCopy(sortOrder.field.CanonicalString()));
}
}
}
@@ -597,7 +611,7 @@ addSnapshotListenerInternalWithOptions:(FSTListenOptions *)internalOptions
NSMutableArray<FSTFieldValue *> *components = [NSMutableArray array];
[fieldValues enumerateObjectsUsingBlock:^(id rawValue, NSUInteger idx, BOOL *stop) {
FSTSortOrder *sortOrder = explicitSortOrders[idx];
- if ([sortOrder.field isEqual:[FSTFieldPath keyFieldPath]]) {
+ if (sortOrder.field == FieldPath::KeyFieldPath()) {
if (![rawValue isKindOfClass:[NSString class]]) {
FSTThrowInvalidUsage(@"InvalidQueryException",
@"Invalid query. Expected a string for the document ID.");
@@ -607,8 +621,10 @@ addSnapshotListenerInternalWithOptions:(FSTListenOptions *)internalOptions
FSTThrowInvalidUsage(@"InvalidQueryException",
@"Invalid query. Document ID '%@' contains a slash.", documentID);
}
- FSTDocumentKey *key =
- [FSTDocumentKey keyWithPath:[self.query.path pathByAppendingSegment:documentID]];
+ FSTDocumentKey *key = [FSTDocumentKey
+ keyWithPath:[FSTResourcePath
+ resourcePathWithCPPResourcePath:self.query.path.Append(
+ [documentID UTF8String])]];
[components
addObject:[FSTReferenceValue referenceValue:key databaseID:self.firestore.databaseID]];
} else {
diff --git a/Firestore/Source/Core/FSTQuery.h b/Firestore/Source/Core/FSTQuery.h
index 0562ae4..8da0878 100644
--- a/Firestore/Source/Core/FSTQuery.h
+++ b/Firestore/Source/Core/FSTQuery.h
@@ -16,11 +16,12 @@
#import <Foundation/Foundation.h>
+#include "Firestore/core/src/firebase/firestore/model/field_path.h"
+#include "Firestore/core/src/firebase/firestore/model/resource_path.h"
+
@class FSTDocument;
@class FSTDocumentKey;
-@class FSTFieldPath;
@class FSTFieldValue;
-@class FSTResourcePath;
NS_ASSUME_NONNULL_BEGIN
@@ -40,7 +41,7 @@ typedef NS_ENUM(NSInteger, FSTRelationFilterOperator) {
@protocol FSTFilter <NSObject>
/** Returns the field the Filter operates over. */
-- (FSTFieldPath *)field;
+- (const firebase::firestore::model::FieldPath &)field;
/** Returns true if a document matches the filter. */
- (BOOL)matchesDocument:(FSTDocument *)document;
@@ -64,7 +65,7 @@ typedef NS_ENUM(NSInteger, FSTRelationFilterOperator) {
* @param value A constant value to compare @a field to. The RHS of the expression.
* @return A new instance of FSTRelationFilter.
*/
-+ (instancetype)filterWithField:(FSTFieldPath *)field
++ (instancetype)filterWithField:(firebase::firestore::model::FieldPath)field
filterOperator:(FSTRelationFilterOperator)filterOperator
value:(FSTFieldValue *)value;
@@ -74,7 +75,7 @@ typedef NS_ENUM(NSInteger, FSTRelationFilterOperator) {
- (BOOL)isInequality;
/** The left hand side of the relation. A path into a document field. */
-@property(nonatomic, strong, readonly) FSTFieldPath *field;
+- (const firebase::firestore::model::FieldPath &)field;
/** The type of equality/inequality operator to use in the relation. */
@property(nonatomic, assign, readonly) FSTRelationFilterOperator filterOperator;
@@ -87,32 +88,35 @@ typedef NS_ENUM(NSInteger, FSTRelationFilterOperator) {
/** Filter that matches NULL values. */
@interface FSTNullFilter : NSObject <FSTFilter>
- (instancetype)init NS_UNAVAILABLE;
-- (instancetype)initWithField:(FSTFieldPath *)field NS_DESIGNATED_INITIALIZER;
+- (instancetype)initWithField:(firebase::firestore::model::FieldPath)field
+ NS_DESIGNATED_INITIALIZER;
@end
/** Filter that matches NAN values. */
@interface FSTNanFilter : NSObject <FSTFilter>
- (instancetype)init NS_UNAVAILABLE;
-- (instancetype)initWithField:(FSTFieldPath *)field NS_DESIGNATED_INITIALIZER;
+- (instancetype)initWithField:(firebase::firestore::model::FieldPath)field
+ NS_DESIGNATED_INITIALIZER;
@end
/** FSTSortOrder is a field and direction to order query results by. */
@interface FSTSortOrder : NSObject <NSCopying>
/** Creates a new sort order with the given field and direction. */
-+ (instancetype)sortOrderWithFieldPath:(FSTFieldPath *)fieldPath ascending:(BOOL)ascending;
++ (instancetype)sortOrderWithFieldPath:(firebase::firestore::model::FieldPath)fieldPath
+ ascending:(BOOL)ascending;
- (instancetype)init NS_UNAVAILABLE;
/** Compares two documents based on the field and direction of this sort order. */
- (NSComparisonResult)compareDocument:(FSTDocument *)document1 toDocument:(FSTDocument *)document2;
+/** The field to sort by. */
+- (const firebase::firestore::model::FieldPath &)field;
+
/** The direction of the sort. */
@property(nonatomic, assign, readonly, getter=isAscending) BOOL ascending;
-/** The field to sort by. */
-@property(nonatomic, strong, readonly) FSTFieldPath *field;
-
@end
/**
@@ -157,7 +161,7 @@ typedef NS_ENUM(NSInteger, FSTRelationFilterOperator) {
/**
* Initializes a query with all of its components directly.
*/
-- (instancetype)initWithPath:(FSTResourcePath *)path
+- (instancetype)initWithPath:(firebase::firestore::model::ResourcePath)path
filterBy:(NSArray<id<FSTFilter>> *)filters
orderBy:(NSArray<FSTSortOrder *> *)sortOrders
limit:(NSInteger)limit
@@ -170,7 +174,7 @@ typedef NS_ENUM(NSInteger, FSTRelationFilterOperator) {
* @param path The path to the collection to be queried over.
* @return A new instance of FSTQuery.
*/
-+ (instancetype)queryWithPath:(FSTResourcePath *)path;
++ (instancetype)queryWithPath:(firebase::firestore::model::ResourcePath)path;
/**
* Returns the list of ordering constraints that were explicitly requested on the query by the
@@ -237,14 +241,15 @@ typedef NS_ENUM(NSInteger, FSTRelationFilterOperator) {
/** Returns a comparator that will sort documents according to the receiver's sort order. */
- (NSComparator)comparator;
-/** Returns the field of the first filter on the receiver that's an inequality, or nil if none. */
-- (FSTFieldPath *_Nullable)inequalityFilterField;
+/** Returns the field of the first filter on the receiver that's an inequality, or nullptr if none.
+ */
+- (const firebase::firestore::model::FieldPath *)inequalityFilterField;
-/** Returns the first field in an order-by constraint, or nil if none. */
-- (FSTFieldPath *_Nullable)firstSortOrderField;
+/** Returns the first field in an order-by constraint, or nullptr if none. */
+- (const firebase::firestore::model::FieldPath *)firstSortOrderField;
/** The base path of the query. */
-@property(nonatomic, strong, readonly) FSTResourcePath *path;
+- (const firebase::firestore::model::ResourcePath &)path;
/** The filters on the documents returned by the query. */
@property(nonatomic, strong, readonly) NSArray<id<FSTFilter>> *filters;
diff --git a/Firestore/Source/Core/FSTQuery.mm b/Firestore/Source/Core/FSTQuery.mm
index 8c98687..7314ce9 100644
--- a/Firestore/Source/Core/FSTQuery.mm
+++ b/Firestore/Source/Core/FSTQuery.mm
@@ -16,6 +16,9 @@
#import "Firestore/Source/Core/FSTQuery.h"
+#include <memory>
+#include <utility>
+
#import "Firestore/Source/API/FIRFirestore+Internal.h"
#import "Firestore/Source/Model/FSTDocument.h"
#import "Firestore/Source/Model/FSTDocumentKey.h"
@@ -23,6 +26,14 @@
#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/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
#pragma mark - FSTRelationFilterOperator functions
@@ -53,7 +64,10 @@ NSString *FSTStringFromQueryRelationOperator(FSTRelationFilterOperator filterOpe
#pragma mark - FSTRelationFilter
-@interface FSTRelationFilter ()
+@interface FSTRelationFilter () {
+ /** The left hand side of the relation. A path into a document field. */
+ firebase::firestore::model::FieldPath _field;
+}
/**
* Initializes the receiver relation filter.
@@ -62,7 +76,7 @@ NSString *FSTStringFromQueryRelationOperator(FSTRelationFilterOperator filterOpe
* @param filterOperator The binary operator to apply.
* @param value A constant value to compare @a field to. The RHS of the expression.
*/
-- (instancetype)initWithField:(FSTFieldPath *)field
+- (instancetype)initWithField:(FieldPath)field
filterOperator:(FSTRelationFilterOperator)filterOperator
value:(FSTFieldValue *)value NS_DESIGNATED_INITIALIZER;
@@ -81,18 +95,20 @@ NSString *FSTStringFromQueryRelationOperator(FSTRelationFilterOperator filterOpe
#pragma mark - Constructor methods
-+ (instancetype)filterWithField:(FSTFieldPath *)field
++ (instancetype)filterWithField:(FieldPath)field
filterOperator:(FSTRelationFilterOperator)filterOperator
value:(FSTFieldValue *)value {
- return [[FSTRelationFilter alloc] initWithField:field filterOperator:filterOperator value:value];
+ return [[FSTRelationFilter alloc] initWithField:std::move(field)
+ filterOperator:filterOperator
+ value:value];
}
-- (instancetype)initWithField:(FSTFieldPath *)field
+- (instancetype)initWithField:(FieldPath)field
filterOperator:(FSTRelationFilterOperator)filterOperator
value:(FSTFieldValue *)value {
self = [super init];
if (self) {
- _field = field;
+ _field = std::move(field);
_filterOperator = filterOperator;
_value = value;
}
@@ -105,10 +121,14 @@ NSString *FSTStringFromQueryRelationOperator(FSTRelationFilterOperator filterOpe
return self.filterOperator != FSTRelationFilterOperatorEqual;
}
+- (const firebase::firestore::model::FieldPath &)field {
+ return _field;
+}
+
#pragma mark - NSObject methods
- (NSString *)description {
- return [NSString stringWithFormat:@"%@ %@ %@", [self.field canonicalString],
+ return [NSString stringWithFormat:@"%s %@ %@", _field.CanonicalString().c_str(),
FSTStringFromQueryRelationOperator(self.filterOperator),
self.value];
}
@@ -126,20 +146,21 @@ NSString *FSTStringFromQueryRelationOperator(FSTRelationFilterOperator filterOpe
#pragma mark - Private methods
- (BOOL)matchesDocument:(FSTDocument *)document {
- if ([self.field isKeyFieldPath]) {
+ if (_field.IsKeyFieldPath()) {
FSTAssert([self.value isKindOfClass:[FSTReferenceValue class]],
@"Comparing on key, but filter value not a FSTReferenceValue.");
FSTReferenceValue *refValue = (FSTReferenceValue *)self.value;
NSComparisonResult comparison = FSTDocumentKeyComparator(document.key, refValue.value);
return [self matchesComparison:comparison];
} else {
- return [self matchesValue:[document fieldForPath:self.field]];
+ return [self
+ matchesValue:[document fieldForPath:[FSTFieldPath fieldPathWithCPPFieldPath:self.field]]];
}
}
- (NSString *)canonicalID {
// TODO(b/37283291): This should be collision robust and avoid relying on |description| methods.
- return [NSString stringWithFormat:@"%@%@%@", [self.field canonicalString],
+ return [NSString stringWithFormat:@"%s%@%@", _field.CanonicalString().c_str(),
FSTStringFromQueryRelationOperator(self.filterOperator),
[self.value value]];
}
@@ -148,7 +169,7 @@ NSString *FSTStringFromQueryRelationOperator(FSTRelationFilterOperator filterOpe
if (self.filterOperator != other.filterOperator) {
return NO;
}
- if (![self.field isEqual:other.field]) {
+ if (_field != other.field) {
return NO;
}
if (![self.value isEqual:other.value]) {
@@ -185,25 +206,31 @@ NSString *FSTStringFromQueryRelationOperator(FSTRelationFilterOperator filterOpe
#pragma mark - FSTNullFilter
-@interface FSTNullFilter ()
-@property(nonatomic, strong, readonly) FSTFieldPath *field;
+@interface FSTNullFilter () {
+ FieldPath _field;
+}
@end
@implementation FSTNullFilter
-- (instancetype)initWithField:(FSTFieldPath *)field {
+- (instancetype)initWithField:(FieldPath)field {
if (self = [super init]) {
- _field = field;
+ _field = std::move(field);
}
return self;
}
- (BOOL)matchesDocument:(FSTDocument *)document {
- FSTFieldValue *fieldValue = [document fieldForPath:self.field];
+ FSTFieldValue *fieldValue =
+ [document fieldForPath:[FSTFieldPath fieldPathWithCPPFieldPath:self.field]];
return fieldValue != nil && [fieldValue isEqual:[FSTNullValue nullValue]];
}
- (NSString *)canonicalID {
- return [NSString stringWithFormat:@"%@ IS NULL", [self.field canonicalString]];
+ return [NSString stringWithFormat:@"%s IS NULL", _field.CanonicalString().c_str()];
+}
+
+- (const firebase::firestore::model::FieldPath &)field {
+ return _field;
}
- (NSString *)description {
@@ -214,37 +241,43 @@ NSString *FSTStringFromQueryRelationOperator(FSTRelationFilterOperator filterOpe
if (other == self) return YES;
if (![[other class] isEqual:[self class]]) return NO;
- return [self.field isEqual:((FSTNullFilter *)other).field];
+ return _field == ((FSTNullFilter *)other)->_field;
}
- (NSUInteger)hash {
- return [self.field hash];
+ return _field.Hash();
}
@end
#pragma mark - FSTNanFilter
-@interface FSTNanFilter ()
-@property(nonatomic, strong, readonly) FSTFieldPath *field;
+@interface FSTNanFilter () {
+ FieldPath _field;
+}
@end
@implementation FSTNanFilter
-- (instancetype)initWithField:(FSTFieldPath *)field {
+- (instancetype)initWithField:(FieldPath)field {
if (self = [super init]) {
- _field = field;
+ _field = std::move(field);
}
return self;
}
- (BOOL)matchesDocument:(FSTDocument *)document {
- FSTFieldValue *fieldValue = [document fieldForPath:self.field];
+ FSTFieldValue *fieldValue =
+ [document fieldForPath:[FSTFieldPath fieldPathWithCPPFieldPath:self.field]];
return fieldValue != nil && [fieldValue isEqual:[FSTDoubleValue nanValue]];
}
- (NSString *)canonicalID {
- return [NSString stringWithFormat:@"%@ IS NaN", [self.field canonicalString]];
+ return [NSString stringWithFormat:@"%s IS NaN", _field.CanonicalString().c_str()];
+}
+
+- (const firebase::firestore::model::FieldPath &)field {
+ return _field;
}
- (NSString *)description {
@@ -255,20 +288,23 @@ NSString *FSTStringFromQueryRelationOperator(FSTRelationFilterOperator filterOpe
if (other == self) return YES;
if (![[other class] isEqual:[self class]]) return NO;
- return [self.field isEqual:((FSTNanFilter *)other).field];
+ return _field == ((FSTNanFilter *)other)->_field;
}
- (NSUInteger)hash {
- return [self.field hash];
+ return _field.Hash();
}
@end
#pragma mark - FSTSortOrder
-@interface FSTSortOrder ()
+@interface FSTSortOrder () {
+ /** The field to sort by. */
+ firebase::firestore::model::FieldPath _field;
+}
/** Creates a new sort order with the given field and direction. */
-- (instancetype)initWithFieldPath:(FSTFieldPath *)fieldPath ascending:(BOOL)ascending;
+- (instancetype)initWithFieldPath:(FieldPath)fieldPath ascending:(BOOL)ascending;
- (NSString *)canonicalID;
@@ -278,28 +314,34 @@ NSString *FSTStringFromQueryRelationOperator(FSTRelationFilterOperator filterOpe
#pragma mark - Constructor methods
-+ (instancetype)sortOrderWithFieldPath:(FSTFieldPath *)fieldPath ascending:(BOOL)ascending {
- return [[FSTSortOrder alloc] initWithFieldPath:fieldPath ascending:ascending];
++ (instancetype)sortOrderWithFieldPath:(FieldPath)fieldPath ascending:(BOOL)ascending {
+ return [[FSTSortOrder alloc] initWithFieldPath:std::move(fieldPath) ascending:ascending];
}
-- (instancetype)initWithFieldPath:(FSTFieldPath *)fieldPath ascending:(BOOL)ascending {
+- (instancetype)initWithFieldPath:(FieldPath)fieldPath ascending:(BOOL)ascending {
self = [super init];
if (self) {
- _field = fieldPath;
+ _field = std::move(fieldPath);
_ascending = ascending;
}
return self;
}
+- (const firebase::firestore::model::FieldPath &)field {
+ return _field;
+}
+
#pragma mark - Public methods
- (NSComparisonResult)compareDocument:(FSTDocument *)document1 toDocument:(FSTDocument *)document2 {
NSComparisonResult result;
- if ([self.field isEqual:[FSTFieldPath keyFieldPath]]) {
+ if (_field == FieldPath::KeyFieldPath()) {
result = FSTDocumentKeyComparator(document1.key, document2.key);
} else {
- FSTFieldValue *value1 = [document1 fieldForPath:self.field];
- FSTFieldValue *value2 = [document2 fieldForPath:self.field];
+ FSTFieldValue *value1 =
+ [document1 fieldForPath:[FSTFieldPath fieldPathWithCPPFieldPath:self.field]];
+ FSTFieldValue *value2 =
+ [document2 fieldForPath:[FSTFieldPath fieldPathWithCPPFieldPath:self.field]];
FSTAssert(value1 != nil && value2 != nil,
@"Trying to compare documents on fields that don't exist.");
result = [value1 compare:value2];
@@ -311,18 +353,19 @@ NSString *FSTStringFromQueryRelationOperator(FSTRelationFilterOperator filterOpe
}
- (NSString *)canonicalID {
- return [NSString
- stringWithFormat:@"%@%@", self.field.canonicalString, self.isAscending ? @"asc" : @"desc"];
+ return [NSString stringWithFormat:@"%s%@", _field.CanonicalString().c_str(),
+ self.isAscending ? @"asc" : @"desc"];
}
- (BOOL)isEqualToSortOrder:(FSTSortOrder *)other {
- return [self.field isEqual:other.field] && self.isAscending == other.isAscending;
+ return _field == other->_field && self.isAscending == other.isAscending;
}
#pragma mark - NSObject methods
- (NSString *)description {
- return [NSString stringWithFormat:@"<FSTSortOrder: path:%@ dir:%@>", self.field,
+ return [NSString stringWithFormat:@"<FSTSortOrder: path:%s dir:%@>",
+ _field.CanonicalString().c_str(),
self.ascending ? @"asc" : @"desc"];
}
@@ -385,13 +428,14 @@ NSString *FSTStringFromQueryRelationOperator(FSTRelationFilterOperator filterOpe
BOOL *stop) {
FSTSortOrder *sortOrderComponent = sortOrder[idx];
NSComparisonResult comparison;
- if ([sortOrderComponent.field isEqual:[FSTFieldPath keyFieldPath]]) {
+ if (sortOrderComponent.field == FieldPath::KeyFieldPath()) {
FSTAssert([fieldValue isKindOfClass:[FSTReferenceValue class]],
@"FSTBound has a non-key value where the key path is being used %@", fieldValue);
FSTReferenceValue *refValue = (FSTReferenceValue *)fieldValue;
comparison = [refValue.value compare:document.key];
} else {
- FSTFieldValue *docValue = [document fieldForPath:sortOrderComponent.field];
+ FSTFieldValue *docValue =
+ [document fieldForPath:[FSTFieldPath fieldPathWithCPPFieldPath:sortOrderComponent.field]];
FSTAssert(docValue != nil, @"Field should exist since document matched the orderBy already.");
comparison = [fieldValue compare:docValue];
}
@@ -444,6 +488,8 @@ NSString *FSTStringFromQueryRelationOperator(FSTRelationFilterOperator filterOpe
@interface FSTQuery () {
// Cached value of the canonicalID property.
NSString *_canonicalID;
+ /** The base path of the query. */
+ ResourcePath _path;
}
/**
@@ -454,7 +500,7 @@ NSString *FSTStringFromQueryRelationOperator(FSTRelationFilterOperator filterOpe
* @param sortOrders The fields and directions to sort the results.
* @param limit If not NSNotFound, only this many results will be returned.
*/
-- (instancetype)initWithPath:(FSTResourcePath *)path
+- (instancetype)initWithPath:(ResourcePath)path
filterBy:(NSArray<id<FSTFilter>> *)filters
orderBy:(NSArray<FSTSortOrder *> *)sortOrders
limit:(NSInteger)limit
@@ -473,8 +519,8 @@ NSString *FSTStringFromQueryRelationOperator(FSTRelationFilterOperator filterOpe
#pragma mark - Constructors
-+ (instancetype)queryWithPath:(FSTResourcePath *)path {
- return [[FSTQuery alloc] initWithPath:path
++ (instancetype)queryWithPath:(ResourcePath)path {
+ return [[FSTQuery alloc] initWithPath:std::move(path)
filterBy:@[]
orderBy:@[]
limit:NSNotFound
@@ -482,14 +528,14 @@ NSString *FSTStringFromQueryRelationOperator(FSTRelationFilterOperator filterOpe
endAt:nil];
}
-- (instancetype)initWithPath:(FSTResourcePath *)path
+- (instancetype)initWithPath:(ResourcePath)path
filterBy:(NSArray<id<FSTFilter>> *)filters
orderBy:(NSArray<FSTSortOrder *> *)sortOrders
limit:(NSInteger)limit
startAt:(nullable FSTBound *)startAtBound
endAt:(nullable FSTBound *)endAtBound {
if (self = [super init]) {
- _path = path;
+ _path = std::move(path);
_filters = filters;
_explicitSortOrders = sortOrders;
_limit = limit;
@@ -527,32 +573,33 @@ NSString *FSTStringFromQueryRelationOperator(FSTRelationFilterOperator filterOpe
- (NSArray *)sortOrders {
if (self.memoizedSortOrders == nil) {
- FSTFieldPath *_Nullable inequalityField = [self inequalityFilterField];
- FSTFieldPath *_Nullable firstSortOrderField = [self firstSortOrderField];
+ const FieldPath *inequalityField = [self inequalityFilterField];
+ const FieldPath *firstSortOrderField = [self firstSortOrderField];
if (inequalityField && !firstSortOrderField) {
// In order to implicitly add key ordering, we must also add the inequality filter field for
// it to be a valid query. Note that the default inequality field and key ordering is
// ascending.
- if ([inequalityField isKeyFieldPath]) {
+ if (inequalityField->IsKeyFieldPath()) {
self.memoizedSortOrders =
- @[ [FSTSortOrder sortOrderWithFieldPath:[FSTFieldPath keyFieldPath] ascending:YES] ];
+ @[ [FSTSortOrder sortOrderWithFieldPath:FieldPath::KeyFieldPath() ascending:YES] ];
} else {
self.memoizedSortOrders = @[
- [FSTSortOrder sortOrderWithFieldPath:inequalityField ascending:YES],
- [FSTSortOrder sortOrderWithFieldPath:[FSTFieldPath keyFieldPath] ascending:YES]
+ [FSTSortOrder sortOrderWithFieldPath:*inequalityField ascending:YES],
+ [FSTSortOrder sortOrderWithFieldPath:FieldPath::KeyFieldPath() ascending:YES]
];
}
} else {
- FSTAssert(!inequalityField || [inequalityField isEqual:firstSortOrderField],
- @"First orderBy %@ should match inequality field %@.", firstSortOrderField,
- inequalityField);
+ FSTAssert(!inequalityField || *inequalityField == *firstSortOrderField,
+ @"First orderBy %@ should match inequality field %@.",
+ util::WrapNSStringNoCopy(firstSortOrderField->CanonicalString()),
+ util::WrapNSStringNoCopy(inequalityField->CanonicalString()));
__block BOOL foundKeyOrder = NO;
NSMutableArray *result = [NSMutableArray array];
for (FSTSortOrder *sortOrder in self.explicitSortOrders) {
[result addObject:sortOrder];
- if ([sortOrder.field isEqual:[FSTFieldPath keyFieldPath]]) {
+ if (sortOrder.field == FieldPath::KeyFieldPath()) {
foundKeyOrder = YES;
}
}
@@ -562,7 +609,7 @@ NSString *FSTStringFromQueryRelationOperator(FSTRelationFilterOperator filterOpe
// explicit sort order
BOOL lastIsAscending =
self.explicitSortOrders.count > 0 ? self.explicitSortOrders.lastObject.ascending : YES;
- [result addObject:[FSTSortOrder sortOrderWithFieldPath:[FSTFieldPath keyFieldPath]
+ [result addObject:[FSTSortOrder sortOrderWithFieldPath:FieldPath::KeyFieldPath()
ascending:lastIsAscending]];
}
@@ -573,17 +620,18 @@ NSString *FSTStringFromQueryRelationOperator(FSTRelationFilterOperator filterOpe
}
- (instancetype)queryByAddingFilter:(id<FSTFilter>)filter {
- FSTAssert(![FSTDocumentKey isDocumentKey:self.path], @"No filtering allowed for document query");
+ FSTAssert(![FSTDocumentKey isDocumentKey:[FSTResourcePath resourcePathWithCPPResourcePath:_path]],
+ @"No filtering allowed for document query");
- FSTFieldPath *_Nullable newInequalityField = nil;
+ const FieldPath *newInequalityField = nullptr;
if ([filter isKindOfClass:[FSTRelationFilter class]] &&
[((FSTRelationFilter *)filter)isInequality]) {
- newInequalityField = filter.field;
+ newInequalityField = &filter.field;
}
- FSTFieldPath *_Nullable queryInequalityField = [self inequalityFilterField];
- FSTAssert(!queryInequalityField || !newInequalityField ||
- [queryInequalityField isEqual:newInequalityField],
- @"Query must only have one inequality field.");
+ const FieldPath *queryInequalityField = [self inequalityFilterField];
+ FSTAssert(
+ !queryInequalityField || !newInequalityField || *queryInequalityField == *newInequalityField,
+ @"Query must only have one inequality field.");
return [[FSTQuery alloc] initWithPath:self.path
filterBy:[self.filters arrayByAddingObject:filter]
@@ -594,7 +642,7 @@ NSString *FSTStringFromQueryRelationOperator(FSTRelationFilterOperator filterOpe
}
- (instancetype)queryByAddingSortOrder:(FSTSortOrder *)sortOrder {
- FSTAssert(![FSTDocumentKey isDocumentKey:self.path],
+ FSTAssert(![FSTDocumentKey isDocumentKey:[FSTResourcePath resourcePathWithCPPResourcePath:_path]],
@"No ordering is allowed for a document query.");
// TODO(klimt): Validate that the same key isn't added twice.
@@ -634,7 +682,8 @@ NSString *FSTStringFromQueryRelationOperator(FSTRelationFilterOperator filterOpe
}
- (BOOL)isDocumentQuery {
- return [FSTDocumentKey isDocumentKey:self.path] && self.filters.count == 0;
+ return [FSTDocumentKey isDocumentKey:[FSTResourcePath resourcePathWithCPPResourcePath:_path]] &&
+ self.filters.count == 0;
}
- (BOOL)matchesDocument:(FSTDocument *)document {
@@ -650,26 +699,33 @@ NSString *FSTStringFromQueryRelationOperator(FSTRelationFilterOperator filterOpe
if (comp != NSOrderedSame) {
return comp;
}
- didCompareOnKeyField =
- didCompareOnKeyField || [orderBy.field isEqual:[FSTFieldPath keyFieldPath]];
+ didCompareOnKeyField = didCompareOnKeyField || orderBy.field == FieldPath::KeyFieldPath();
}
FSTAssert(didCompareOnKeyField, @"sortOrder of query did not include key ordering");
return NSOrderedSame;
};
}
-- (FSTFieldPath *_Nullable)inequalityFilterField {
+- (const FieldPath *)inequalityFilterField {
for (id<FSTFilter> filter in self.filters) {
if ([filter isKindOfClass:[FSTRelationFilter class]] &&
((FSTRelationFilter *)filter).filterOperator != FSTRelationFilterOperatorEqual) {
- return filter.field;
+ return &filter.field;
}
}
- return nil;
+ return nullptr;
+}
+
+- (const FieldPath *)firstSortOrderField {
+ if (self.explicitSortOrders.count > 0) {
+ return &self.explicitSortOrders.firstObject.field;
+ }
+ return nullptr;
}
-- (FSTFieldPath *_Nullable)firstSortOrderField {
- return self.explicitSortOrders.firstObject.field;
+/** The base path of the query. */
+- (const firebase::firestore::model::ResourcePath &)path {
+ return _path;
}
#pragma mark - Private properties
@@ -679,7 +735,7 @@ NSString *FSTStringFromQueryRelationOperator(FSTRelationFilterOperator filterOpe
return _canonicalID;
}
- NSMutableString *canonicalID = [[self.path canonicalString] mutableCopy];
+ NSMutableString *canonicalID = [util::WrapNSStringNoCopy(_path.CanonicalString()) mutableCopy];
// Add filters.
[canonicalID appendString:@"|f:"];
@@ -713,7 +769,7 @@ NSString *FSTStringFromQueryRelationOperator(FSTRelationFilterOperator filterOpe
#pragma mark - Private methods
- (BOOL)isEqualToQuery:(FSTQuery *)other {
- return [self.path isEqual:other.path] && self.limit == other.limit &&
+ return self.path == other.path && self.limit == other.limit &&
[self.filters isEqual:other.filters] && [self.sortOrders isEqual:other.sortOrders] &&
(self.startAt == other.startAt || [self.startAt isEqual:other.startAt]) &&
(self.endAt == other.endAt || [self.endAt isEqual:other.endAt]);
@@ -722,12 +778,13 @@ NSString *FSTStringFromQueryRelationOperator(FSTRelationFilterOperator filterOpe
/* Returns YES if the document matches the path for the receiver. */
- (BOOL)pathMatchesDocument:(FSTDocument *)document {
FSTResourcePath *documentPath = document.key.path;
- if ([FSTDocumentKey isDocumentKey:self.path]) {
+ if ([FSTDocumentKey isDocumentKey:[FSTResourcePath resourcePathWithCPPResourcePath:_path]]) {
// Exact match for document queries.
- return [self.path isEqual:documentPath];
+ return self.path == [documentPath toCPPResourcePath];
} else {
// Shallow ancestor queries by default.
- return [self.path isPrefixOfPath:documentPath] && self.path.length == documentPath.length - 1;
+ return self.path.IsPrefixOf([documentPath toCPPResourcePath]) &&
+ _path.size() == documentPath.length - 1;
}
}
@@ -736,10 +793,10 @@ NSString *FSTStringFromQueryRelationOperator(FSTRelationFilterOperator filterOpe
*/
- (BOOL)orderByMatchesDocument:(FSTDocument *)document {
for (FSTSortOrder *orderBy in self.explicitSortOrders) {
- FSTFieldPath *fieldPath = orderBy.field;
+ const FieldPath &fieldPath = orderBy.field;
// order by key always matches
- if (![fieldPath isEqual:[FSTFieldPath keyFieldPath]] &&
- [document fieldForPath:fieldPath] == nil) {
+ if (fieldPath != FieldPath::KeyFieldPath() &&
+ [document fieldForPath:[FSTFieldPath fieldPathWithCPPFieldPath:fieldPath]] == nil) {
return NO;
}
}
diff --git a/Firestore/Source/Core/FSTSyncEngine.mm b/Firestore/Source/Core/FSTSyncEngine.mm
index 61fac7d..88be23c 100644
--- a/Firestore/Source/Core/FSTSyncEngine.mm
+++ b/Firestore/Source/Core/FSTSyncEngine.mm
@@ -36,6 +36,7 @@
#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"
@@ -496,7 +497,7 @@ static const FSTListenSequenceNumber kIrrelevantSequenceNumber = -1;
if (!self.limboTargetsByKey[key]) {
FSTLog(@"New document in limbo: %@", key);
FSTTargetID limboTargetID = _targetIdGenerator.NextId();
- FSTQuery *query = [FSTQuery queryWithPath:key.path];
+ FSTQuery *query = [FSTQuery queryWithPath:[key.path toCPPResourcePath]];
FSTQueryData *queryData = [[FSTQueryData alloc] initWithQuery:query
targetID:limboTargetID
listenSequenceNumber:kIrrelevantSequenceNumber
diff --git a/Firestore/Source/Local/FSTLevelDBMutationQueue.mm b/Firestore/Source/Local/FSTLevelDBMutationQueue.mm
index 248ef9a..9041ddc 100644
--- a/Firestore/Source/Local/FSTLevelDBMutationQueue.mm
+++ b/Firestore/Source/Local/FSTLevelDBMutationQueue.mm
@@ -426,7 +426,7 @@ static ReadOptions StandardReadOptions() {
FSTAssert(![query isDocumentQuery], @"Document queries shouldn't go down this path");
NSString *userID = self.userID;
- FSTResourcePath *queryPath = query.path;
+ FSTResourcePath *queryPath = [FSTResourcePath resourcePathWithCPPResourcePath:query.path];
int immediateChildrenPathLength = queryPath.length + 1;
// TODO(mcg): Actually implement a single-collection query
diff --git a/Firestore/Source/Local/FSTLevelDBRemoteDocumentCache.mm b/Firestore/Source/Local/FSTLevelDBRemoteDocumentCache.mm
index b842cb5..17ecb53 100644
--- a/Firestore/Source/Local/FSTLevelDBRemoteDocumentCache.mm
+++ b/Firestore/Source/Local/FSTLevelDBRemoteDocumentCache.mm
@@ -104,7 +104,8 @@ 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:query.path];
+ std::string startKey = [FSTLevelDBRemoteDocumentKey
+ keyPrefixWithResourcePath:[FSTResourcePath resourcePathWithCPPResourcePath:query.path]];
std::unique_ptr<Iterator> it(_db->NewIterator(StandardReadOptions()));
it->Seek(startKey);
@@ -112,7 +113,7 @@ static ReadOptions StandardReadOptions() {
for (; it->Valid() && [currentKey decodeKey:it->key()]; it->Next()) {
FSTMaybeDocument *maybeDoc =
[self decodedMaybeDocument:it->value() withKey:currentKey.documentKey];
- if (![query.path isPrefixOfPath:maybeDoc.key.path]) {
+ if (!query.path.IsPrefixOf([maybeDoc.key.path toCPPResourcePath])) {
break;
} else if ([maybeDoc isKindOfClass:[FSTDocument class]]) {
results = [results dictionaryBySettingObject:(FSTDocument *)maybeDoc forKey:maybeDoc.key];
diff --git a/Firestore/Source/Local/FSTLocalDocumentsView.mm b/Firestore/Source/Local/FSTLocalDocumentsView.mm
index 0e88958..4bcdf47 100644
--- a/Firestore/Source/Local/FSTLocalDocumentsView.mm
+++ b/Firestore/Source/Local/FSTLocalDocumentsView.mm
@@ -25,6 +25,7 @@
#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"
NS_ASSUME_NONNULL_BEGIN
@@ -74,8 +75,9 @@ NS_ASSUME_NONNULL_BEGIN
}
- (FSTDocumentDictionary *)documentsMatchingQuery:(FSTQuery *)query {
- if ([FSTDocumentKey isDocumentKey:query.path]) {
- return [self documentsMatchingDocumentQuery:query.path];
+ if ([FSTDocumentKey isDocumentKey:[FSTResourcePath resourcePathWithCPPResourcePath:query.path]]) {
+ return [self documentsMatchingDocumentQuery:[FSTResourcePath
+ resourcePathWithCPPResourcePath:query.path]];
} else {
return [self documentsMatchingCollectionQuery:query];
}
diff --git a/Firestore/Source/Local/FSTMemoryMutationQueue.mm b/Firestore/Source/Local/FSTMemoryMutationQueue.mm
index 2a6a1cc..bf4f600 100644
--- a/Firestore/Source/Local/FSTMemoryMutationQueue.mm
+++ b/Firestore/Source/Local/FSTMemoryMutationQueue.mm
@@ -248,13 +248,13 @@ static const NSComparator NumberComparator = ^NSComparisonResult(NSNumber *left,
- (NSArray<FSTMutationBatch *> *)allMutationBatchesAffectingQuery:(FSTQuery *)query {
// Use the query path as a prefix for testing if a document matches the query.
- FSTResourcePath *prefix = query.path;
+ FSTResourcePath *prefix = [FSTResourcePath resourcePathWithCPPResourcePath:query.path];
int immediateChildrenPathLength = prefix.length + 1;
// Construct a document reference for actually scanning the index. Unlike the prefix, the document
// key in this reference must have an even number of segments. The empty segment can be used as
// a suffix of the query path because it precedes all other segments in an ordered traversal.
- FSTResourcePath *startPath = query.path;
+ FSTResourcePath *startPath = [FSTResourcePath resourcePathWithCPPResourcePath:query.path];
if (![FSTDocumentKey isDocumentKey:startPath]) {
startPath = [startPath pathByAppendingSegment:@""];
}
diff --git a/Firestore/Source/Local/FSTMemoryRemoteDocumentCache.mm b/Firestore/Source/Local/FSTMemoryRemoteDocumentCache.mm
index 9bbc047..7d5e1e2 100644
--- a/Firestore/Source/Local/FSTMemoryRemoteDocumentCache.mm
+++ b/Firestore/Source/Local/FSTMemoryRemoteDocumentCache.mm
@@ -60,10 +60,11 @@ NS_ASSUME_NONNULL_BEGIN
// Documents are ordered by key, so we can use a prefix scan to narrow down the documents
// we need to match the query against.
- FSTDocumentKey *prefix = [FSTDocumentKey keyWithPath:[query.path pathByAppendingSegment:@""]];
+ FSTDocumentKey *prefix = [FSTDocumentKey
+ keyWithPath:[FSTResourcePath resourcePathWithCPPResourcePath:query.path.Append("")]];
NSEnumerator<FSTDocumentKey *> *enumerator = [self.docs keyEnumeratorFrom:prefix];
for (FSTDocumentKey *key in enumerator) {
- if (![query.path isPrefixOfPath:key.path]) {
+ if (!query.path.IsPrefixOf([key.path toCPPResourcePath])) {
break;
}
FSTMaybeDocument *maybeDoc = self.docs[key];
diff --git a/Firestore/Source/Model/FSTPath.h b/Firestore/Source/Model/FSTPath.h
index 1f63f17..f127156 100644
--- a/Firestore/Source/Model/FSTPath.h
+++ b/Firestore/Source/Model/FSTPath.h
@@ -16,6 +16,9 @@
#import <Foundation/Foundation.h>
+#include "Firestore/core/src/firebase/firestore/model/field_path.h"
+#include "Firestore/core/src/firebase/firestore/model/resource_path.h"
+
NS_ASSUME_NONNULL_BEGIN
/**
@@ -113,6 +116,17 @@ NS_ASSUME_NONNULL_BEGIN
/** 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. */
@@ -136,6 +150,18 @@ NS_ASSUME_NONNULL_BEGIN
* @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
index 636c322..b91e428 100644
--- a/Firestore/Source/Model/FSTPath.mm
+++ b/Firestore/Source/Model/FSTPath.mm
@@ -16,11 +16,21 @@
#import "Firestore/Source/Model/FSTPath.h"
+#include <string>
+
#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 ()
@@ -313,6 +323,22 @@ NS_ASSUME_NONNULL_BEGIN
return result;
}
++ (instancetype)fieldPathWithCPPFieldPath:(const FieldPath &)fieldPath {
+ NSMutableArray<NSString *> *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<std::string> 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
@@ -351,6 +377,23 @@ NS_ASSUME_NONNULL_BEGIN
}
return result;
}
+
++ (instancetype)resourcePathWithCPPResourcePath:(const ResourcePath &)resourcePath {
+ NSMutableArray<NSString *> *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<std::string> 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/FSTRemoteStore.mm b/Firestore/Source/Remote/FSTRemoteStore.mm
index b2e4013..b762722 100644
--- a/Firestore/Source/Remote/FSTRemoteStore.mm
+++ b/Firestore/Source/Remote/FSTRemoteStore.mm
@@ -27,6 +27,7 @@
#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/FSTRemoteEvent.h"
@@ -446,7 +447,8 @@ static const int kOnlineAttemptsBeforeFailure = 2;
// updates. Without applying a deleted document there might be another query that will
// raise this document as part of a snapshot until it is resolved, essentially exposing
// inconsistency between queries
- FSTDocumentKey *key = [FSTDocumentKey keyWithPath:query.path];
+ FSTDocumentKey *key = [FSTDocumentKey
+ keyWithPath:[FSTResourcePath resourcePathWithCPPResourcePath:query.path]];
FSTDeletedDocument *deletedDoc =
[FSTDeletedDocument documentWithKey:key version:snapshotVersion];
[remoteEvent addDocumentUpdate:deletedDoc];
diff --git a/Firestore/Source/Remote/FSTSerializerBeta.mm b/Firestore/Source/Remote/FSTSerializerBeta.mm
index ceb0501..1dc7c79 100644
--- a/Firestore/Source/Remote/FSTSerializerBeta.mm
+++ b/Firestore/Source/Remote/FSTSerializerBeta.mm
@@ -654,7 +654,8 @@ NS_ASSUME_NONNULL_BEGIN
- (GCFSTarget_DocumentsTarget *)encodedDocumentsTarget:(FSTQuery *)query {
GCFSTarget_DocumentsTarget *result = [GCFSTarget_DocumentsTarget message];
NSMutableArray<NSString *> *docs = result.documentsArray;
- [docs addObject:[self encodedQueryPath:query.path]];
+ [docs addObject:[self encodedQueryPath:[FSTResourcePath
+ resourcePathWithCPPResourcePath:query.path]]];
return result;
}
@@ -664,16 +665,17 @@ NS_ASSUME_NONNULL_BEGIN
(unsigned long)documents.count);
NSString *name = documents[0];
- return [FSTQuery queryWithPath:[self decodedQueryPath:name]];
+ return [FSTQuery queryWithPath:[[self decodedQueryPath:name] toCPPResourcePath]];
}
- (GCFSTarget_QueryTarget *)encodedQueryTarget:(FSTQuery *)query {
// Dissect the path into parent, collectionId, and optional key filter.
GCFSTarget_QueryTarget *queryTarget = [GCFSTarget_QueryTarget message];
- if (query.path.length == 0) {
- queryTarget.parent = [self encodedQueryPath:query.path];
+ if (query.path.empty()) {
+ queryTarget.parent =
+ [self encodedQueryPath:[FSTResourcePath resourcePathWithCPPResourcePath:query.path]];
} else {
- FSTResourcePath *path = query.path;
+ FSTResourcePath *path = [FSTResourcePath resourcePathWithCPPResourcePath:query.path];
FSTAssert(path.length % 2 != 0, @"Document queries with filters are not supported.");
queryTarget.parent = [self encodedQueryPath:[path pathByRemovingLastSegment]];
GCFSStructuredQuery_CollectionSelector *from = [GCFSStructuredQuery_CollectionSelector message];
@@ -749,7 +751,7 @@ NS_ASSUME_NONNULL_BEGIN
endAt = [self decodedBound:query.endAt];
}
- return [[FSTQuery alloc] initWithPath:path
+ return [[FSTQuery alloc] initWithPath:[path toCPPResourcePath]
filterBy:filterBy
orderBy:orderBy
limit:limit
@@ -818,7 +820,7 @@ NS_ASSUME_NONNULL_BEGIN
- (GCFSStructuredQuery_Filter *)encodedRelationFilter:(FSTRelationFilter *)filter {
GCFSStructuredQuery_Filter *proto = [GCFSStructuredQuery_Filter message];
GCFSStructuredQuery_FieldFilter *fieldFilter = proto.fieldFilter;
- fieldFilter.field = [self encodedFieldPath:filter.field];
+ fieldFilter.field = [self encodedFieldPath:[FSTFieldPath fieldPathWithCPPFieldPath:filter.field]];
fieldFilter.op = [self encodedRelationFilterOperator:filter.filterOperator];
fieldFilter.value = [self encodedFieldValue:filter.value];
return proto;
@@ -828,12 +830,15 @@ NS_ASSUME_NONNULL_BEGIN
FSTFieldPath *fieldPath = [FSTFieldPath pathWithServerFormat:proto.field.fieldPath];
FSTRelationFilterOperator filterOperator = [self decodedRelationFilterOperator:proto.op];
FSTFieldValue *value = [self decodedFieldValue:proto.value];
- return [FSTRelationFilter filterWithField:fieldPath filterOperator:filterOperator value:value];
+ return [FSTRelationFilter filterWithField:[fieldPath toCPPFieldPath]
+ filterOperator:filterOperator
+ value:value];
}
- (GCFSStructuredQuery_Filter *)encodedUnaryFilter:(id<FSTFilter>)filter {
GCFSStructuredQuery_Filter *proto = [GCFSStructuredQuery_Filter message];
- proto.unaryFilter.field = [self encodedFieldPath:filter.field];
+ proto.unaryFilter.field =
+ [self encodedFieldPath:[FSTFieldPath fieldPathWithCPPFieldPath:filter.field]];
if ([filter isKindOfClass:[FSTNanFilter class]]) {
proto.unaryFilter.op = GCFSStructuredQuery_UnaryFilter_Operator_IsNan;
} else if ([filter isKindOfClass:[FSTNullFilter class]]) {
@@ -848,10 +853,10 @@ NS_ASSUME_NONNULL_BEGIN
FSTFieldPath *field = [FSTFieldPath pathWithServerFormat:proto.field.fieldPath];
switch (proto.op) {
case GCFSStructuredQuery_UnaryFilter_Operator_IsNan:
- return [[FSTNanFilter alloc] initWithField:field];
+ return [[FSTNanFilter alloc] initWithField:[field toCPPFieldPath]];
case GCFSStructuredQuery_UnaryFilter_Operator_IsNull:
- return [[FSTNullFilter alloc] initWithField:field];
+ return [[FSTNullFilter alloc] initWithField:[field toCPPFieldPath]];
default:
FSTFail(@"Unrecognized UnaryFilter.operator %d", proto.op);
@@ -920,7 +925,7 @@ NS_ASSUME_NONNULL_BEGIN
- (GCFSStructuredQuery_Order *)encodedSortOrder:(FSTSortOrder *)sortOrder {
GCFSStructuredQuery_Order *proto = [GCFSStructuredQuery_Order message];
- proto.field = [self encodedFieldPath:sortOrder.field];
+ proto.field = [self encodedFieldPath:[FSTFieldPath fieldPathWithCPPFieldPath:sortOrder.field]];
if (sortOrder.ascending) {
proto.direction = GCFSStructuredQuery_Direction_Ascending;
} else {
@@ -942,7 +947,7 @@ NS_ASSUME_NONNULL_BEGIN
default:
FSTFail(@"Unrecognized GCFSStructuredQuery_Direction %d", proto.direction);
}
- return [FSTSortOrder sortOrderWithFieldPath:fieldPath ascending:ascending];
+ return [FSTSortOrder sortOrderWithFieldPath:[fieldPath toCPPFieldPath] ascending:ascending];
}
#pragma mark - Bounds/Cursors
diff --git a/Firestore/core/src/firebase/firestore/model/base_path.h b/Firestore/core/src/firebase/firestore/model/base_path.h
index accce27..73ac611 100644
--- a/Firestore/core/src/firebase/firestore/model/base_path.h
+++ b/Firestore/core/src/firebase/firestore/model/base_path.h
@@ -159,6 +159,19 @@ class BasePath {
return segments_ >= rhs.segments_;
}
+#if defined(__OBJC__)
+ // For Objective-C++ hash; to be removed after migration.
+ // Do NOT use in C++ code.
+ uint64_t Hash() const {
+ std::hash<std::string> hash_fn;
+ uint64_t hash_result = 0;
+ for (const std::string& segment : segments_) {
+ hash_result = hash_result * 31u + hash_fn(segment);
+ }
+ return hash_result;
+ }
+#endif // defined(__OBJC__)
+
protected:
BasePath() = default;
template <typename IterT>
diff --git a/Firestore/core/test/firebase/firestore/testutil/CMakeLists.txt b/Firestore/core/test/firebase/firestore/testutil/CMakeLists.txt
index 14308a5..636acb0 100644
--- a/Firestore/core/test/firebase/firestore/testutil/CMakeLists.txt
+++ b/Firestore/core/test/firebase/firestore/testutil/CMakeLists.txt
@@ -27,10 +27,12 @@ if(APPLE)
list(APPEND TESTUTIL_DEPENDS firebase_firestore_testutil_apple)
endif()
-add_library(
- firebase_firestore_testutil INTERFACE
-)
-target_link_libraries(
- firebase_firestore_testutil INTERFACE
- ${TESTUTIL_DEPENDS}
+cc_library(
+ firebase_firestore_testutil
+ SOURCES
+ testutil.cc
+ testutil.h
+ DEPENDS
+ ${TESTUTIL_DEPENDS}
+ firebase_firestore_model
)
diff --git a/Firestore/core/test/firebase/firestore/testutil/testutil.cc b/Firestore/core/test/firebase/firestore/testutil/testutil.cc
new file mode 100644
index 0000000..9b9228d
--- /dev/null
+++ b/Firestore/core/test/firebase/firestore/testutil/testutil.cc
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2018 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Firestore/core/test/firebase/firestore/testutil/testutil.h"
+
+namespace firebase {
+namespace firestore {
+namespace testutil {
+
+void dummy() {
+}
+
+} // namespace testutil
+} // namespace firestore
+} // namespace firebase
diff --git a/Firestore/core/test/firebase/firestore/testutil/testutil.h b/Firestore/core/test/firebase/firestore/testutil/testutil.h
new file mode 100644
index 0000000..7e4f313
--- /dev/null
+++ b/Firestore/core/test/firebase/firestore/testutil/testutil.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2018 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef FIRESTORE_CORE_TEST_FIREBASE_FIRESTORE_TESTUTIL_TESTUTIL_H_
+#define FIRESTORE_CORE_TEST_FIREBASE_FIRESTORE_TESTUTIL_TESTUTIL_H_
+
+#include "Firestore/core/src/firebase/firestore/model/field_path.h"
+#include "absl/strings/string_view.h"
+
+namespace firebase {
+namespace firestore {
+namespace testutil {
+
+// Below are convenience methods for creating instances for tests.
+
+inline model::FieldPath Field(absl::string_view field) {
+ return model::FieldPath::FromServerFormat(field);
+}
+
+// Add a non-inline function to make this library buildable.
+// TODO(zxu123): remove once there is non-inline function.
+void dummy();
+
+} // namespace testutil
+} // namespace firestore
+} // namespace firebase
+
+#endif // FIRESTORE_CORE_TEST_FIREBASE_FIRESTORE_TESTUTIL_TESTUTIL_H_