aboutsummaryrefslogtreecommitdiffhomepage
path: root/Firestore/Source/API
diff options
context:
space:
mode:
authorGravatar zxu <zxu@google.com>2018-03-14 08:57:31 -0400
committerGravatar GitHub <noreply@github.com>2018-03-14 08:57:31 -0400
commit9e815620e9f7f43b42e03db4e5118d7ad03ddee7 (patch)
tree86f362bad99281325fca7ee3ae116b6a0f36d511 /Firestore/Source/API
parentd4d73ea53ecdf1e8ade3d00921419645dd5d66f7 (diff)
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
Diffstat (limited to 'Firestore/Source/API')
-rw-r--r--Firestore/Source/API/FIRCollectionReference+Internal.h7
-rw-r--r--Firestore/Source/API/FIRCollectionReference.mm20
-rw-r--r--Firestore/Source/API/FIRDocumentReference+Internal.h6
-rw-r--r--Firestore/Source/API/FIRDocumentReference.mm22
-rw-r--r--Firestore/Source/API/FIRDocumentSnapshot.mm12
-rw-r--r--Firestore/Source/API/FIRFieldPath+Internal.h8
-rw-r--r--Firestore/Source/API/FIRFieldPath.mm40
-rw-r--r--Firestore/Source/API/FIRFirestore.mm11
-rw-r--r--Firestore/Source/API/FIRQuery.mm49
-rw-r--r--Firestore/Source/API/FSTUserDataConverter.mm160
10 files changed, 194 insertions, 141 deletions
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<NSString *, id> *)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 <functional>
+#include <string>
+#include <utility>
+#include <vector>
+
#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<NSString *> *)fieldNames {
@@ -28,22 +45,25 @@ NS_ASSUME_NONNULL_BEGIN
FSTThrowInvalidArgument(@"Invalid field path. Provided names must not be empty.");
}
+ std::vector<std::string> 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 <memory>
+#include <utility>
+#include <vector>
+
#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<FSTFieldTransform *> *fieldTransforms;
-@property(nonatomic, strong, readonly) NSMutableArray<FSTFieldPath *> *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<FieldPath>)path
arrayElement:(BOOL)arrayElement
fieldTransforms:(NSMutableArray<FSTFieldTransform *> *)fieldTransforms
- fieldMask:(NSMutableArray<FSTFieldPath *> *)fieldMask
+ fieldMask:(std::shared_ptr<std::vector<FieldPath>>)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<FieldPath> *)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<FieldPath> _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<std::vector<FieldPath>> _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<FieldPath>)path {
+ FSTParseContext *context =
+ [[FSTParseContext alloc] initWithSource:dataSource
+ path:std::move(path)
+ arrayElement:NO
+ fieldTransforms:[NSMutableArray array]
+ fieldMask:std::make_shared<std::vector<FieldPath>>()];
[context validatePath];
return context;
}
- (instancetype)initWithSource:(FSTUserDataSource)dataSource
- path:(nullable FSTFieldPath *)path
+ path:(std::unique_ptr<FieldPath>)path
arrayElement:(BOOL)arrayElement
fieldTransforms:(NSMutableArray<FSTFieldTransform *> *)fieldTransforms
- fieldMask:(NSMutableArray<FSTFieldPath *> *)fieldMask {
+ fieldMask:(std::shared_ptr<std::vector<FieldPath>>)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<FieldPath> path{};
+ if (_path) {
+ path = absl::make_unique<FieldPath>(_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<FieldPath> path{};
+ if (_path) {
+ path = absl::make_unique<FieldPath>(_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<FieldPath> *)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>(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>(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<FSTFieldPath *> *fieldMaskPaths = [NSMutableArray array];
+ __block std::vector<FieldPath> fieldMaskPaths{};
__block FSTObjectValue *updateData = [FSTObjectValue objectValue];
FSTParseContext *context =
- [FSTParseContext contextWithSource:FSTUserDataSourceUpdate path:[FSTFieldPath emptyPath]];
+ [FSTParseContext contextWithSource:FSTUserDataSourceUpdate
+ path:absl::make_unique<FieldPath>(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>(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.