From 5fa10a914334562564a26298f128bc852269077f Mon Sep 17 00:00:00 2001 From: zxu Date: Wed, 4 Apr 2018 12:40:46 -0400 Subject: port FieldMask to C++ (#998) * port FieldMask to C++ * address changes * address changes * fix test * address change * fix lint * address changes * Revert "address changes" This reverts commit c75bb42851b785ab0838bb23679f87dfad9df4bb. --- .../Example/Tests/Local/FSTLocalSerializerTests.mm | 16 ++-- Firestore/Example/Tests/Model/FSTMutationTests.mm | 5 +- .../Example/Tests/Remote/FSTSerializerBetaTests.mm | 4 +- Firestore/Example/Tests/Util/FSTHelpers.mm | 6 +- Firestore/Source/API/FSTUserDataConverter.h | 15 ++-- Firestore/Source/API/FSTUserDataConverter.mm | 54 ++++++++---- Firestore/Source/Core/FSTTransaction.h | 1 - Firestore/Source/Model/FSTMutation.h | 38 ++------- Firestore/Source/Model/FSTMutation.mm | 64 ++++---------- Firestore/Source/Remote/FSTSerializerBeta.mm | 10 ++- .../src/firebase/firestore/model/CMakeLists.txt | 1 + .../core/src/firebase/firestore/model/field_mask.h | 97 ++++++++++++++++++++++ .../test/firebase/firestore/model/CMakeLists.txt | 1 + .../firebase/firestore/model/field_mask_test.cc | 56 +++++++++++++ 14 files changed, 251 insertions(+), 117 deletions(-) create mode 100644 Firestore/core/src/firebase/firestore/model/field_mask.h create mode 100644 Firestore/core/test/firebase/firestore/model/field_mask_test.cc diff --git a/Firestore/Example/Tests/Local/FSTLocalSerializerTests.mm b/Firestore/Example/Tests/Local/FSTLocalSerializerTests.mm index d94925d..d810aa6 100644 --- a/Firestore/Example/Tests/Local/FSTLocalSerializerTests.mm +++ b/Firestore/Example/Tests/Local/FSTLocalSerializerTests.mm @@ -41,11 +41,13 @@ #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_mask.h" #include "Firestore/core/src/firebase/firestore/util/string_apple.h" #include "Firestore/core/test/firebase/firestore/testutil/testutil.h" namespace testutil = firebase::firestore::testutil; using firebase::firestore::model::DatabaseId; +using firebase::firestore::model::FieldMask; NS_ASSUME_NONNULL_BEGIN @@ -76,13 +78,13 @@ NS_ASSUME_NONNULL_BEGIN - (void)testEncodesMutationBatch { FSTMutation *set = FSTTestSetMutation(@"foo/bar", @{ @"a" : @"b", @"num" : @1 }); - FSTMutation *patch = [[FSTPatchMutation alloc] - initWithKey:FSTTestDocKey(@"bar/baz") - fieldMask:[[FSTFieldMask alloc] initWithFields:{testutil::Field("a")}] - value:FSTTestObjectValue( - @{ @"a" : @"b", - @"num" : @1 }) - precondition:[FSTPrecondition preconditionWithExists:YES]]; + FSTMutation *patch = + [[FSTPatchMutation alloc] initWithKey:FSTTestDocKey(@"bar/baz") + fieldMask:FieldMask{testutil::Field("a")} + value:FSTTestObjectValue( + @{ @"a" : @"b", + @"num" : @1 }) + precondition:[FSTPrecondition preconditionWithExists:YES]]; FSTMutation *del = FSTTestDeleteMutation(@"baz/quux"); FIRTimestamp *writeTime = [FIRTimestamp timestamp]; FSTMutationBatch *model = [[FSTMutationBatch alloc] initWithBatchID:42 diff --git a/Firestore/Example/Tests/Model/FSTMutationTests.mm b/Firestore/Example/Tests/Model/FSTMutationTests.mm index 1f9193e..9024b22 100644 --- a/Firestore/Example/Tests/Model/FSTMutationTests.mm +++ b/Firestore/Example/Tests/Model/FSTMutationTests.mm @@ -25,10 +25,12 @@ #import "Firestore/Example/Tests/Util/FSTHelpers.h" #include "Firestore/core/src/firebase/firestore/model/document_key.h" +#include "Firestore/core/src/firebase/firestore/model/field_mask.h" #include "Firestore/core/test/firebase/firestore/testutil/testutil.h" namespace testutil = firebase::firestore::testutil; using firebase::firestore::model::DocumentKey; +using firebase::firestore::model::FieldMask; @interface FSTMutationTests : XCTestCase @end @@ -69,9 +71,8 @@ using firebase::firestore::model::DocumentKey; FSTDocument *baseDoc = FSTTestDoc("collection/key", 0, docData, NO); DocumentKey key = testutil::Key("collection/key"); - FSTFieldMask *mask = [[FSTFieldMask alloc] initWithFields:{testutil::Field("foo.bar")}]; FSTMutation *patch = [[FSTPatchMutation alloc] initWithKey:key - fieldMask:mask + fieldMask:{testutil::Field("foo.bar")} value:[FSTObjectValue objectValue] precondition:[FSTPrecondition none]]; FSTMaybeDocument *patchedDoc = diff --git a/Firestore/Example/Tests/Remote/FSTSerializerBetaTests.mm b/Firestore/Example/Tests/Remote/FSTSerializerBetaTests.mm index 64f4777..17191f8 100644 --- a/Firestore/Example/Tests/Remote/FSTSerializerBetaTests.mm +++ b/Firestore/Example/Tests/Remote/FSTSerializerBetaTests.mm @@ -46,12 +46,14 @@ #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_mask.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::FieldMask; NS_ASSUME_NONNULL_BEGIN @@ -63,7 +65,7 @@ NS_ASSUME_NONNULL_BEGIN - (GCFSValue *)encodedString:(NSString *)value; - (GCFSValue *)encodedDate:(NSDate *)value; -- (GCFSDocumentMask *)encodedFieldMask:(FSTFieldMask *)fieldMask; +- (GCFSDocumentMask *)encodedFieldMask:(const FieldMask &)fieldMask; - (NSMutableArray *)encodedFieldTransforms: (NSArray *)fieldTransforms; diff --git a/Firestore/Example/Tests/Util/FSTHelpers.mm b/Firestore/Example/Tests/Util/FSTHelpers.mm index 5751739..8a7306c 100644 --- a/Firestore/Example/Tests/Util/FSTHelpers.mm +++ b/Firestore/Example/Tests/Util/FSTHelpers.mm @@ -44,6 +44,7 @@ #include "Firestore/core/src/firebase/firestore/model/database_id.h" #include "Firestore/core/src/firebase/firestore/model/document_key.h" +#include "Firestore/core/src/firebase/firestore/model/field_mask.h" #include "Firestore/core/src/firebase/firestore/model/field_value.h" #include "Firestore/core/src/firebase/firestore/model/resource_path.h" #include "Firestore/core/src/firebase/firestore/util/string_apple.h" @@ -53,6 +54,7 @@ namespace util = firebase::firestore::util; namespace testutil = firebase::firestore::testutil; using firebase::firestore::model::DatabaseId; using firebase::firestore::model::DocumentKey; +using firebase::firestore::model::FieldMask; using firebase::firestore::model::FieldPath; using firebase::firestore::model::FieldValue; using firebase::firestore::model::ResourcePath; @@ -260,8 +262,8 @@ FSTPatchMutation *FSTTestPatchMutation(const absl::string_view path, } }]; - FSTDocumentKey *key = [FSTDocumentKey keyWithPath:testutil::Resource(path)]; - FSTFieldMask *mask = [[FSTFieldMask alloc] initWithFields:merge ? updateMask : fieldMaskPaths]; + DocumentKey key = testutil::Key(path); + FieldMask mask(merge ? updateMask : fieldMaskPaths); return [[FSTPatchMutation alloc] initWithKey:key fieldMask:mask value:objectValue diff --git a/Firestore/Source/API/FSTUserDataConverter.h b/Firestore/Source/API/FSTUserDataConverter.h index 3b178be..2b4b340 100644 --- a/Firestore/Source/API/FSTUserDataConverter.h +++ b/Firestore/Source/API/FSTUserDataConverter.h @@ -18,10 +18,10 @@ #include "Firestore/core/src/firebase/firestore/model/database_id.h" #include "Firestore/core/src/firebase/firestore/model/document_key.h" +#include "Firestore/core/src/firebase/firestore/model/field_mask.h" @class FIRSetOptions; @class FSTObjectValue; -@class FSTFieldMask; @class FSTFieldValue; @class FSTFieldTransform; @class FSTMutation; @@ -36,13 +36,17 @@ NS_ASSUME_NONNULL_BEGIN - (instancetype)init NS_UNAVAILABLE; - (instancetype)initWithData:(FSTObjectValue *)data - fieldMask:(nullable FSTFieldMask *)fieldMask + fieldTransforms:(NSArray *)fieldTransforms + NS_DESIGNATED_INITIALIZER; + +- (instancetype)initWithData:(FSTObjectValue *)data + fieldMask:(firebase::firestore::model::FieldMask)fieldMask fieldTransforms:(NSArray *)fieldTransforms NS_DESIGNATED_INITIALIZER; @property(nonatomic, strong, readonly) FSTObjectValue *data; -@property(nonatomic, strong, readonly, nullable) FSTFieldMask *fieldMask; @property(nonatomic, strong, readonly) NSArray *fieldTransforms; +@property(nonatomic, assign, readonly) BOOL isPatch; /** * Converts the parsed document data into 1 or 2 mutations (depending on whether there are any @@ -59,12 +63,13 @@ NS_ASSUME_NONNULL_BEGIN - (instancetype)init NS_UNAVAILABLE; - (instancetype)initWithData:(FSTObjectValue *)data - fieldMask:(FSTFieldMask *)fieldMask + fieldMask:(firebase::firestore::model::FieldMask)fieldMask fieldTransforms:(NSArray *)fieldTransforms NS_DESIGNATED_INITIALIZER; +- (const firebase::firestore::model::FieldMask &)fieldMask; + @property(nonatomic, strong, readonly) FSTObjectValue *data; -@property(nonatomic, strong, readonly) FSTFieldMask *fieldMask; @property(nonatomic, strong, readonly) NSArray *fieldTransforms; /** diff --git a/Firestore/Source/API/FSTUserDataConverter.mm b/Firestore/Source/API/FSTUserDataConverter.mm index 7ee16de..34f1015 100644 --- a/Firestore/Source/API/FSTUserDataConverter.mm +++ b/Firestore/Source/API/FSTUserDataConverter.mm @@ -35,6 +35,7 @@ #include "Firestore/core/src/firebase/firestore/model/database_id.h" #include "Firestore/core/src/firebase/firestore/model/document_key.h" +#include "Firestore/core/src/firebase/firestore/model/field_mask.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" @@ -42,6 +43,7 @@ namespace util = firebase::firestore::util; using firebase::firestore::model::DatabaseId; using firebase::firestore::model::DocumentKey; +using firebase::firestore::model::FieldMask; using firebase::firestore::model::FieldPath; NS_ASSUME_NONNULL_BEGIN @@ -50,15 +52,30 @@ static NSString *const RESERVED_FIELD_DESIGNATOR = @"__"; #pragma mark - FSTParsedSetData -@implementation FSTParsedSetData +@implementation FSTParsedSetData { + FieldMask _fieldMask; +} + +- (instancetype)initWithData:(FSTObjectValue *)data + fieldTransforms:(NSArray *)fieldTransforms { + self = [super init]; + if (self) { + _data = data; + _fieldTransforms = fieldTransforms; + _isPatch = NO; + } + return self; +} + - (instancetype)initWithData:(FSTObjectValue *)data - fieldMask:(nullable FSTFieldMask *)fieldMask + fieldMask:(FieldMask)fieldMask fieldTransforms:(NSArray *)fieldTransforms { self = [super init]; if (self) { _data = data; - _fieldMask = fieldMask; + _fieldMask = std::move(fieldMask); _fieldTransforms = fieldTransforms; + _isPatch = YES; } return self; } @@ -66,9 +83,9 @@ static NSString *const RESERVED_FIELD_DESIGNATOR = @"__"; - (NSArray *)mutationsWithKey:(const DocumentKey &)key precondition:(FSTPrecondition *)precondition { NSMutableArray *mutations = [NSMutableArray array]; - if (self.fieldMask) { + if (self.isPatch) { [mutations addObject:[[FSTPatchMutation alloc] initWithKey:key - fieldMask:self.fieldMask + fieldMask:_fieldMask value:self.data precondition:precondition]]; } else { @@ -87,14 +104,17 @@ static NSString *const RESERVED_FIELD_DESIGNATOR = @"__"; #pragma mark - FSTParsedUpdateData -@implementation FSTParsedUpdateData +@implementation FSTParsedUpdateData { + FieldMask _fieldMask; +} + - (instancetype)initWithData:(FSTObjectValue *)data - fieldMask:(FSTFieldMask *)fieldMask + fieldMask:(FieldMask)fieldMask fieldTransforms:(NSArray *)fieldTransforms { self = [super init]; if (self) { _data = data; - _fieldMask = fieldMask; + _fieldMask = std::move(fieldMask); _fieldTransforms = fieldTransforms; } return self; @@ -114,6 +134,10 @@ static NSString *const RESERVED_FIELD_DESIGNATOR = @"__"; return mutations; } +- (const firebase::firestore::model::FieldMask &)fieldMask { + return _fieldMask; +} + @end /** @@ -364,10 +388,9 @@ typedef NS_ENUM(NSInteger, FSTUserDataSource) { path:absl::make_unique(FieldPath::EmptyPath())]; FSTObjectValue *updateData = (FSTObjectValue *)[self parseData:input context:context]; - return [[FSTParsedSetData alloc] - initWithData:updateData - fieldMask:[[FSTFieldMask alloc] initWithFields:*context.fieldMask] - fieldTransforms:context.fieldTransforms]; + return [[FSTParsedSetData alloc] initWithData:updateData + fieldMask:FieldMask{*context.fieldMask} + fieldTransforms:context.fieldTransforms]; } - (FSTParsedSetData *)parsedSetData:(id)input { @@ -382,9 +405,7 @@ typedef NS_ENUM(NSInteger, FSTUserDataSource) { path:absl::make_unique(FieldPath::EmptyPath())]; FSTObjectValue *updateData = (FSTObjectValue *)[self parseData:input context:context]; - return [[FSTParsedSetData alloc] initWithData:updateData - fieldMask:nil - fieldTransforms:context.fieldTransforms]; + return [[FSTParsedSetData alloc] initWithData:updateData fieldTransforms:context.fieldTransforms]; } - (FSTParsedUpdateData *)parsedUpdateData:(id)input { @@ -428,9 +449,8 @@ typedef NS_ENUM(NSInteger, FSTUserDataSource) { } }]; - FSTFieldMask *mask = [[FSTFieldMask alloc] initWithFields:fieldMaskPaths]; return [[FSTParsedUpdateData alloc] initWithData:updateData - fieldMask:mask + fieldMask:FieldMask{fieldMaskPaths} fieldTransforms:context.fieldTransforms]; } diff --git a/Firestore/Source/Core/FSTTransaction.h b/Firestore/Source/Core/FSTTransaction.h index 676ada9..01c2e20 100644 --- a/Firestore/Source/Core/FSTTransaction.h +++ b/Firestore/Source/Core/FSTTransaction.h @@ -24,7 +24,6 @@ @class FIRSetOptions; @class FSTDatastore; -@class FSTFieldMask; @class FSTFieldTransform; @class FSTMaybeDocument; @class FSTObjectValue; diff --git a/Firestore/Source/Model/FSTMutation.h b/Firestore/Source/Model/FSTMutation.h index 4e4357d..2b81af6 100644 --- a/Firestore/Source/Model/FSTMutation.h +++ b/Firestore/Source/Model/FSTMutation.h @@ -19,6 +19,7 @@ #include #include "Firestore/core/src/firebase/firestore/model/document_key.h" +#include "Firestore/core/src/firebase/firestore/model/field_mask.h" #include "Firestore/core/src/firebase/firestore/model/field_path.h" @class FSTDocument; @@ -30,31 +31,6 @@ NS_ASSUME_NONNULL_BEGIN -#pragma mark - FSTFieldMask - -/** - * Provides a set of fields that can be used to partially patch a document. FieldMask is used in - * conjunction with ObjectValue. - * - * Examples: - * foo - Overwrites foo entirely with the provided value. If foo is not present in the companion - * ObjectValue, the field is deleted. - * foo.bar - Overwrites only the field bar of the object foo. If foo is not an object, foo is - * replaced with an object containing bar. - */ -@interface FSTFieldMask : NSObject -- (id)init __attribute__((unavailable("Use initWithFields:"))); - -/** - * Initializes the field mask with the given field paths. Caller is expected to either copy or - * or release the array of fields. - */ -- (instancetype)initWithFields:(std::vector)fields - NS_DESIGNATED_INITIALIZER; - -- (const std::vector &)fields; -@end - #pragma mark - FSTFieldTransform /** Represents a transform within a TransformMutation. */ @@ -267,7 +243,7 @@ typedef NS_ENUM(NSUInteger, FSTPreconditionExists) { precondition:(FSTPrecondition *)precondition NS_UNAVAILABLE; /** - * Initializes a new patch mutation with an explicit FSTFieldMask and FSTObjectValue representing + * Initializes a new patch mutation with an explicit FieldMask and FSTObjectValue representing * the updates to perform * * @param key Identifies the location of the document to mutate. @@ -278,18 +254,18 @@ typedef NS_ENUM(NSUInteger, FSTPreconditionExists) { * @param precondition The precondition for this mutation. */ - (instancetype)initWithKey:(firebase::firestore::model::DocumentKey)key - fieldMask:(FSTFieldMask *)fieldMask + fieldMask:(firebase::firestore::model::FieldMask)fieldMask value:(FSTObjectValue *)value precondition:(FSTPrecondition *)precondition NS_DESIGNATED_INITIALIZER; -/** The fields and associated values to use when patching the document. */ -@property(nonatomic, strong, readonly) FSTObjectValue *value; - /** * A mask to apply to |value|, where only fields that are in both the fieldMask and the value * will be updated. */ -@property(nonatomic, strong, readonly) FSTFieldMask *fieldMask; +- (const firebase::firestore::model::FieldMask &)fieldMask; + +/** The fields and associated values to use when patching the document. */ +@property(nonatomic, strong, readonly) FSTObjectValue *value; @end diff --git a/Firestore/Source/Model/FSTMutation.mm b/Firestore/Source/Model/FSTMutation.mm index 253a853..df95155 100644 --- a/Firestore/Source/Model/FSTMutation.mm +++ b/Firestore/Source/Model/FSTMutation.mm @@ -27,51 +27,15 @@ #import "Firestore/Source/Util/FSTClasses.h" #include "Firestore/core/src/firebase/firestore/model/document_key.h" +#include "Firestore/core/src/firebase/firestore/model/field_mask.h" #include "Firestore/core/src/firebase/firestore/model/field_path.h" using firebase::firestore::model::DocumentKey; +using firebase::firestore::model::FieldMask; using firebase::firestore::model::FieldPath; NS_ASSUME_NONNULL_BEGIN -#pragma mark - FSTFieldMask - -@implementation FSTFieldMask { - std::vector _fields; -} - -- (instancetype)initWithFields:(std::vector)fields { - if (self = [super init]) { - _fields = std::move(fields); - } - return self; -} - -- (BOOL)isEqual:(id)other { - if (other == self) { - return YES; - } - if (![other isKindOfClass:[FSTFieldMask class]]) { - return NO; - } - - FSTFieldMask *otherMask = (FSTFieldMask *)other; - return _fields == otherMask->_fields; -} - -- (NSUInteger)hash { - NSUInteger hashResult = 0; - for (const FieldPath &field : _fields) { - hashResult = hashResult * 31u + field.Hash(); - } - return hashResult; -} - -- (const std::vector &)fields { - return _fields; -} -@end - #pragma mark - FSTServerTimestampTransform @implementation FSTServerTimestampTransform @@ -354,20 +318,26 @@ NS_ASSUME_NONNULL_BEGIN #pragma mark - FSTPatchMutation -@implementation FSTPatchMutation +@implementation FSTPatchMutation { + FieldMask _fieldMask; +} - (instancetype)initWithKey:(DocumentKey)key - fieldMask:(FSTFieldMask *)fieldMask + fieldMask:(FieldMask)fieldMask value:(FSTObjectValue *)value precondition:(FSTPrecondition *)precondition { self = [super initWithKey:std::move(key) precondition:precondition]; if (self) { - _fieldMask = fieldMask; + _fieldMask = std::move(fieldMask); _value = value; } return self; } +- (const firebase::firestore::model::FieldMask &)fieldMask { + return _fieldMask; +} + - (BOOL)isEqual:(id)other { if (other == self) { return YES; @@ -377,7 +347,7 @@ NS_ASSUME_NONNULL_BEGIN } FSTPatchMutation *otherMutation = (FSTPatchMutation *)other; - return [self.key isEqual:otherMutation.key] && [self.fieldMask isEqual:otherMutation.fieldMask] && + return [self.key isEqual:otherMutation.key] && self.fieldMask == otherMutation.fieldMask && [self.value isEqual:otherMutation.value] && [self.precondition isEqual:otherMutation.precondition]; } @@ -385,15 +355,15 @@ NS_ASSUME_NONNULL_BEGIN - (NSUInteger)hash { NSUInteger result = [self.key hash]; result = 31 * result + [self.precondition hash]; - result = 31 * result + [self.fieldMask hash]; + result = 31 * result + self.fieldMask.Hash(); result = 31 * result + [self.value hash]; return result; } - (NSString *)description { - return [NSString stringWithFormat:@"", - self.key.ToString().c_str(), self.fieldMask, self.value, - self.precondition]; + return [NSString stringWithFormat:@"", + self.key.ToString().c_str(), self.fieldMask.ToString().c_str(), + self.value, self.precondition]; } - (nullable FSTMaybeDocument *)applyTo:(nullable FSTMaybeDocument *)maybeDoc @@ -434,7 +404,7 @@ NS_ASSUME_NONNULL_BEGIN - (FSTObjectValue *)patchObjectValue:(FSTObjectValue *)objectValue { FSTObjectValue *result = objectValue; - for (const FieldPath &fieldPath : self.fieldMask.fields) { + for (const FieldPath &fieldPath : self.fieldMask) { FSTFieldValue *newValue = [self.value valueForPath:fieldPath]; if (newValue) { result = [result objectBySettingValue:newValue forPath:fieldPath]; diff --git a/Firestore/Source/Remote/FSTSerializerBeta.mm b/Firestore/Source/Remote/FSTSerializerBeta.mm index 3a22a3f..3b6f052 100644 --- a/Firestore/Source/Remote/FSTSerializerBeta.mm +++ b/Firestore/Source/Remote/FSTSerializerBeta.mm @@ -44,6 +44,7 @@ #include "Firestore/core/src/firebase/firestore/model/database_id.h" #include "Firestore/core/src/firebase/firestore/model/document_key.h" +#include "Firestore/core/src/firebase/firestore/model/field_mask.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" @@ -51,6 +52,7 @@ namespace util = firebase::firestore::util; using firebase::firestore::model::DatabaseId; using firebase::firestore::model::DocumentKey; +using firebase::firestore::model::FieldMask; using firebase::firestore::model::FieldPath; using firebase::firestore::model::ResourcePath; @@ -539,21 +541,21 @@ NS_ASSUME_NONNULL_BEGIN } } -- (GCFSDocumentMask *)encodedFieldMask:(FSTFieldMask *)fieldMask { +- (GCFSDocumentMask *)encodedFieldMask:(const FieldMask &)fieldMask { GCFSDocumentMask *mask = [GCFSDocumentMask message]; - for (const FieldPath &field : fieldMask.fields) { + for (const FieldPath &field : fieldMask) { [mask.fieldPathsArray addObject:util::WrapNSString(field.CanonicalString())]; } return mask; } -- (FSTFieldMask *)decodedFieldMask:(GCFSDocumentMask *)fieldMask { +- (FieldMask)decodedFieldMask:(GCFSDocumentMask *)fieldMask { std::vector fields{}; fields.reserve(fieldMask.fieldPathsArray_Count); for (NSString *path in fieldMask.fieldPathsArray) { fields.push_back(FieldPath::FromServerFormat(util::MakeStringView(path))); } - return [[FSTFieldMask alloc] initWithFields:std::move(fields)]; + return FieldMask(std::move(fields)); } - (NSMutableArray *)encodedFieldTransforms: diff --git a/Firestore/core/src/firebase/firestore/model/CMakeLists.txt b/Firestore/core/src/firebase/firestore/model/CMakeLists.txt index 78f5cd6..f6c5efe 100644 --- a/Firestore/core/src/firebase/firestore/model/CMakeLists.txt +++ b/Firestore/core/src/firebase/firestore/model/CMakeLists.txt @@ -22,6 +22,7 @@ cc_library( document.h document_key.cc document_key.h + field_mask.h field_path.cc field_path.h field_value.cc diff --git a/Firestore/core/src/firebase/firestore/model/field_mask.h b/Firestore/core/src/firebase/firestore/model/field_mask.h new file mode 100644 index 0000000..a9f509a --- /dev/null +++ b/Firestore/core/src/firebase/firestore/model/field_mask.h @@ -0,0 +1,97 @@ +/* + * 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_SRC_FIREBASE_FIRESTORE_MODEL_FIELD_MASK_H_ +#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_MODEL_FIELD_MASK_H_ + +#include +#include +#include +#include + +#include "Firestore/core/src/firebase/firestore/model/field_path.h" + +namespace firebase { +namespace firestore { +namespace model { + +/** + * Provides a set of fields that can be used to partially patch a document. + * FieldMask is used in conjunction with FieldValue of Object type. + * + * Examples: + * foo - Overwrites foo entirely with the provided value. If foo is not + * present in the companion FieldValue, the field is deleted. + * foo.bar - Overwrites only the field bar of the object foo. If foo is not an + * object, foo is replaced with an object containing bar. + */ +class FieldMask { + public: + using const_iterator = std::vector::const_iterator; + + FieldMask(std::initializer_list list) : fields_{list} { + } + explicit FieldMask(const std::vector& fields) : fields_{fields} { + } + explicit FieldMask(std::vector&& fields) + : fields_{std::move(fields)} { + } + + const_iterator begin() const { + return fields_.begin(); + } + const_iterator end() const { + return fields_.end(); + } + + std::string ToString() const { + // Ideally, one should use a string builder. Since this is only non-critical + // code for logging and debugging, the logic is kept simple here. + std::string result("{ "); + for (const FieldPath& field : fields_) { + result += field.CanonicalString() + " "; + } + return result + "}"; + } + +#if defined(__OBJC__) + FieldMask() { + } + + NSUInteger Hash() const { + NSUInteger hashResult = 0; + for (const FieldPath& field : fields_) { + hashResult = hashResult * 31u + field.Hash(); + } + return hashResult; + } +#endif + + friend bool operator==(const FieldMask& lhs, const FieldMask& rhs); + + private: + std::vector fields_; +}; + +inline bool operator==(const FieldMask& lhs, const FieldMask& rhs) { + return lhs.fields_ == rhs.fields_; +} + +} // namespace model +} // namespace firestore +} // namespace firebase + +#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_MODEL_FIELD_MASK_H_ diff --git a/Firestore/core/test/firebase/firestore/model/CMakeLists.txt b/Firestore/core/test/firebase/firestore/model/CMakeLists.txt index 2c2281f..59a1f03 100644 --- a/Firestore/core/test/firebase/firestore/model/CMakeLists.txt +++ b/Firestore/core/test/firebase/firestore/model/CMakeLists.txt @@ -18,6 +18,7 @@ cc_test( database_id_test.cc document_key_test.cc document_test.cc + field_mask_test.cc field_path_test.cc field_value_test.cc maybe_document_test.cc diff --git a/Firestore/core/test/firebase/firestore/model/field_mask_test.cc b/Firestore/core/test/firebase/firestore/model/field_mask_test.cc new file mode 100644 index 0000000..52d5951 --- /dev/null +++ b/Firestore/core/test/firebase/firestore/model/field_mask_test.cc @@ -0,0 +1,56 @@ +/* + * 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/src/firebase/firestore/model/field_mask.h" + +#include + +#include "Firestore/core/src/firebase/firestore/model/field_path.h" +#include "gtest/gtest.h" + +namespace firebase { +namespace firestore { +namespace model { + +TEST(FieldMask, ConstructorAndEqual) { + FieldMask mask_a{FieldPath::FromServerFormat("foo"), + FieldPath::FromServerFormat("bar")}; + std::vector field_path_vector{FieldPath::FromServerFormat("foo"), + FieldPath::FromServerFormat("bar")}; + FieldMask mask_b{field_path_vector}; + FieldMask mask_c{std::vector{FieldPath::FromServerFormat("foo"), + FieldPath::FromServerFormat("bar")}}; + EXPECT_EQ(mask_a, mask_b); + EXPECT_EQ(mask_b, mask_c); +} + +TEST(FieldMask, Getter) { + FieldMask mask{FieldPath::FromServerFormat("foo"), + FieldPath::FromServerFormat("bar")}; + EXPECT_EQ(std::vector({FieldPath::FromServerFormat("foo"), + FieldPath::FromServerFormat("bar")}), + std::vector(mask.begin(), mask.end())); +} + +TEST(FieldMask, ToString) { + FieldMask mask{FieldPath::FromServerFormat("foo"), + FieldPath::FromServerFormat("bar")}; + EXPECT_EQ("{ foo bar }", mask.ToString()); +} + +} // namespace model +} // namespace firestore +} // namespace firebase -- cgit v1.2.3