From 2ac778f312301a8dd10c3c6498a59ce536abd738 Mon Sep 17 00:00:00 2001 From: zxu Date: Tue, 10 Apr 2018 16:28:22 -0400 Subject: Port FieldTransform to C++ (#1033) * port FieldMask to C++ * address changes * address changes * fix test * address change * Port transform operations (FSTTransformOperation, FSTServerTimestampTransform) to C++ * address changes * address changes * address changes * implement `FieldTransform` in C++ * port `FieldTransform` * make `fieldTransforms` shared inside `context` * address changes * fix lint * address changes --- .../Example/Tests/Remote/FSTSerializerBetaTests.mm | 6 +- Firestore/Example/Tests/Util/FSTHelpers.mm | 12 +-- Firestore/Source/API/FSTUserDataConverter.h | 18 +++-- Firestore/Source/API/FSTUserDataConverter.mm | 83 ++++++++++++------- Firestore/Source/Core/FSTTransaction.h | 1 - Firestore/Source/Model/FSTMutation.h | 22 ++--- Firestore/Source/Model/FSTMutation.mm | 93 ++++++++-------------- Firestore/Source/Remote/FSTSerializerBeta.mm | 27 ++++--- .../src/firebase/firestore/model/CMakeLists.txt | 1 + .../src/firebase/firestore/model/field_transform.h | 70 ++++++++++++++++ .../test/firebase/firestore/model/CMakeLists.txt | 1 + .../firestore/model/field_transform_test.cc | 39 +++++++++ 12 files changed, 243 insertions(+), 130 deletions(-) create mode 100644 Firestore/core/src/firebase/firestore/model/field_transform.h create mode 100644 Firestore/core/test/firebase/firestore/model/field_transform_test.cc (limited to 'Firestore') diff --git a/Firestore/Example/Tests/Remote/FSTSerializerBetaTests.mm b/Firestore/Example/Tests/Remote/FSTSerializerBetaTests.mm index 17191f8..c0e9cad 100644 --- a/Firestore/Example/Tests/Remote/FSTSerializerBetaTests.mm +++ b/Firestore/Example/Tests/Remote/FSTSerializerBetaTests.mm @@ -23,6 +23,8 @@ #import #import +#include + #import "Firestore/Protos/objc/firestore/local/MaybeDocument.pbobjc.h" #import "Firestore/Protos/objc/firestore/local/Mutation.pbobjc.h" #import "Firestore/Protos/objc/google/firestore/v1beta1/Common.pbobjc.h" @@ -47,6 +49,7 @@ #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/model/field_transform.h" #include "Firestore/core/src/firebase/firestore/util/string_apple.h" #include "Firestore/core/test/firebase/firestore/testutil/testutil.h" @@ -54,6 +57,7 @@ namespace testutil = firebase::firestore::testutil; namespace util = firebase::firestore::util; using firebase::firestore::model::DatabaseId; using firebase::firestore::model::FieldMask; +using firebase::firestore::model::FieldTransform; NS_ASSUME_NONNULL_BEGIN @@ -67,7 +71,7 @@ NS_ASSUME_NONNULL_BEGIN - (GCFSDocumentMask *)encodedFieldMask:(const FieldMask &)fieldMask; - (NSMutableArray *)encodedFieldTransforms: - (NSArray *)fieldTransforms; + (const std::vector &)fieldTransforms; - (GCFSStructuredQuery_Filter *)encodedRelationFilter:(FSTRelationFilter *)filter; @end diff --git a/Firestore/Example/Tests/Util/FSTHelpers.mm b/Firestore/Example/Tests/Util/FSTHelpers.mm index 8f170e6..2e1082e 100644 --- a/Firestore/Example/Tests/Util/FSTHelpers.mm +++ b/Firestore/Example/Tests/Util/FSTHelpers.mm @@ -46,6 +46,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_transform.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/model/transform_operations.h" @@ -59,6 +60,7 @@ using firebase::firestore::model::DatabaseId; using firebase::firestore::model::DocumentKey; using firebase::firestore::model::FieldMask; using firebase::firestore::model::FieldPath; +using firebase::firestore::model::FieldTransform; using firebase::firestore::model::FieldValue; using firebase::firestore::model::ResourcePath; using firebase::firestore::model::ServerTimestampTransform; @@ -279,15 +281,13 @@ FSTPatchMutation *FSTTestPatchMutation(const absl::string_view path, FSTTransformMutation *FSTTestTransformMutation(NSString *path, NSArray *serverTimestampFields) { FSTDocumentKey *key = [FSTDocumentKey keyWithPath:testutil::Resource(util::MakeStringView(path))]; - NSMutableArray *fieldTransforms = [NSMutableArray array]; + std::vector fieldTransforms; for (NSString *field in serverTimestampFields) { - const FieldPath fieldPath = testutil::Field(util::MakeStringView(field)); + FieldPath fieldPath = testutil::Field(util::MakeStringView(field)); auto transformOp = absl::make_unique(ServerTimestampTransform::Get()); - FSTFieldTransform *transform = - [[FSTFieldTransform alloc] initWithPath:fieldPath transform:std::move(transformOp)]; - [fieldTransforms addObject:transform]; + fieldTransforms.emplace_back(std::move(fieldPath), std::move(transformOp)); } - return [[FSTTransformMutation alloc] initWithKey:key fieldTransforms:fieldTransforms]; + return [[FSTTransformMutation alloc] initWithKey:key fieldTransforms:std::move(fieldTransforms)]; } FSTDeleteMutation *FSTTestDeleteMutation(NSString *path) { diff --git a/Firestore/Source/API/FSTUserDataConverter.h b/Firestore/Source/API/FSTUserDataConverter.h index 2b4b340..a2f947a 100644 --- a/Firestore/Source/API/FSTUserDataConverter.h +++ b/Firestore/Source/API/FSTUserDataConverter.h @@ -16,14 +16,16 @@ #import +#include + #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_transform.h" @class FIRSetOptions; @class FSTObjectValue; @class FSTFieldValue; -@class FSTFieldTransform; @class FSTMutation; @class FSTPrecondition; @class FSTSnapshotVersion; @@ -36,16 +38,19 @@ NS_ASSUME_NONNULL_BEGIN - (instancetype)init NS_UNAVAILABLE; - (instancetype)initWithData:(FSTObjectValue *)data - fieldTransforms:(NSArray *)fieldTransforms + fieldTransforms: + (std::vector)fieldTransforms NS_DESIGNATED_INITIALIZER; - (instancetype)initWithData:(FSTObjectValue *)data fieldMask:(firebase::firestore::model::FieldMask)fieldMask - fieldTransforms:(NSArray *)fieldTransforms + fieldTransforms: + (std::vector)fieldTransforms NS_DESIGNATED_INITIALIZER; +- (const std::vector &)fieldTransforms; + @property(nonatomic, strong, readonly) FSTObjectValue *data; -@property(nonatomic, strong, readonly) NSArray *fieldTransforms; @property(nonatomic, assign, readonly) BOOL isPatch; /** @@ -64,13 +69,14 @@ NS_ASSUME_NONNULL_BEGIN - (instancetype)initWithData:(FSTObjectValue *)data fieldMask:(firebase::firestore::model::FieldMask)fieldMask - fieldTransforms:(NSArray *)fieldTransforms + fieldTransforms: + (std::vector)fieldTransforms NS_DESIGNATED_INITIALIZER; - (const firebase::firestore::model::FieldMask &)fieldMask; +- (const std::vector &)fieldTransforms; @property(nonatomic, strong, readonly) FSTObjectValue *data; -@property(nonatomic, strong, readonly) NSArray *fieldTransforms; /** * Converts the parsed update data into 1 or 2 mutations (depending on whether there are any diff --git a/Firestore/Source/API/FSTUserDataConverter.mm b/Firestore/Source/API/FSTUserDataConverter.mm index c6a6e34..2eee878 100644 --- a/Firestore/Source/API/FSTUserDataConverter.mm +++ b/Firestore/Source/API/FSTUserDataConverter.mm @@ -37,6 +37,7 @@ #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/field_transform.h" #include "Firestore/core/src/firebase/firestore/model/transform_operations.h" #include "Firestore/core/src/firebase/firestore/util/string_apple.h" #include "absl/memory/memory.h" @@ -46,7 +47,9 @@ using firebase::firestore::model::DatabaseId; using firebase::firestore::model::DocumentKey; using firebase::firestore::model::FieldMask; using firebase::firestore::model::FieldPath; +using firebase::firestore::model::FieldTransform; using firebase::firestore::model::ServerTimestampTransform; +using firebase::firestore::model::TransformOperation; NS_ASSUME_NONNULL_BEGIN @@ -56,14 +59,15 @@ static NSString *const RESERVED_FIELD_DESIGNATOR = @"__"; @implementation FSTParsedSetData { FieldMask _fieldMask; + std::vector _fieldTransforms; } - (instancetype)initWithData:(FSTObjectValue *)data - fieldTransforms:(NSArray *)fieldTransforms { + fieldTransforms:(std::vector)fieldTransforms { self = [super init]; if (self) { _data = data; - _fieldTransforms = fieldTransforms; + _fieldTransforms = std::move(fieldTransforms); _isPatch = NO; } return self; @@ -71,17 +75,21 @@ static NSString *const RESERVED_FIELD_DESIGNATOR = @"__"; - (instancetype)initWithData:(FSTObjectValue *)data fieldMask:(FieldMask)fieldMask - fieldTransforms:(NSArray *)fieldTransforms { + fieldTransforms:(std::vector)fieldTransforms { self = [super init]; if (self) { _data = data; _fieldMask = std::move(fieldMask); - _fieldTransforms = fieldTransforms; + _fieldTransforms = std::move(fieldTransforms); _isPatch = YES; } return self; } +- (const std::vector &)fieldTransforms { + return _fieldTransforms; +} + - (NSArray *)mutationsWithKey:(const DocumentKey &)key precondition:(FSTPrecondition *)precondition { NSMutableArray *mutations = [NSMutableArray array]; @@ -95,7 +103,7 @@ static NSString *const RESERVED_FIELD_DESIGNATOR = @"__"; value:self.data precondition:precondition]]; } - if (self.fieldTransforms.count > 0) { + if (!self.fieldTransforms.empty()) { [mutations addObject:[[FSTTransformMutation alloc] initWithKey:key fieldTransforms:self.fieldTransforms]]; } @@ -108,16 +116,17 @@ static NSString *const RESERVED_FIELD_DESIGNATOR = @"__"; @implementation FSTParsedUpdateData { FieldMask _fieldMask; + std::vector _fieldTransforms; } - (instancetype)initWithData:(FSTObjectValue *)data fieldMask:(FieldMask)fieldMask - fieldTransforms:(NSArray *)fieldTransforms { + fieldTransforms:(std::vector)fieldTransforms { self = [super init]; if (self) { _data = data; _fieldMask = std::move(fieldMask); - _fieldTransforms = fieldTransforms; + _fieldTransforms = std::move(fieldTransforms); } return self; } @@ -129,7 +138,7 @@ static NSString *const RESERVED_FIELD_DESIGNATOR = @"__"; fieldMask:self.fieldMask value:self.data precondition:precondition]]; - if (self.fieldTransforms.count > 0) { + if (!self.fieldTransforms.empty()) { [mutations addObject:[[FSTTransformMutation alloc] initWithKey:key fieldTransforms:self.fieldTransforms]]; } @@ -140,6 +149,10 @@ static NSString *const RESERVED_FIELD_DESIGNATOR = @"__"; return _fieldMask; } +- (const std::vector &)fieldTransforms { + return _fieldTransforms; +} + @end /** @@ -168,7 +181,6 @@ typedef NS_ENUM(NSInteger, FSTUserDataSource) { * conditions apply during parsing and providing better error messages. */ @property(nonatomic, assign) FSTUserDataSource dataSource; -@property(nonatomic, strong, readonly) NSMutableArray *fieldTransforms; - (instancetype)init NS_UNAVAILABLE; /** @@ -186,7 +198,7 @@ typedef NS_ENUM(NSInteger, FSTUserDataSource) { - (instancetype)initWithSource:(FSTUserDataSource)dataSource path:(std::unique_ptr)path arrayElement:(BOOL)arrayElement - fieldTransforms:(NSMutableArray *)fieldTransforms + fieldTransforms:(std::shared_ptr>)fieldTransforms fieldMask:(std::shared_ptr>)fieldMask NS_DESIGNATED_INITIALIZER; @@ -204,16 +216,22 @@ typedef NS_ENUM(NSInteger, FSTUserDataSource) { - (void)appendToFieldMaskWithFieldPath:(FieldPath)fieldPath; +- (const std::vector *)fieldTransforms; + +- (void)appendToFieldTransformsWithFieldPath:(FieldPath)fieldPath + transformOperation: + (std::unique_ptr)transformOperation; @end @implementation FSTParseContext { /** The current path being parsed. */ // TODO(b/34871131): path should never be nullptr, but we don't support array paths right now. std::unique_ptr _path; - // _fieldMask is shared across all active context objects to accumulate the result. For example, - // the result of calling any of contextForField, contextForFieldPath and contextForArrayIndex - // shares the ownership of _fieldMask. + // _fieldMask and _fieldTransforms are 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 and _fieldTransforms. std::shared_ptr> _fieldMask; + std::shared_ptr> _fieldTransforms; } + (instancetype)contextWithSource:(FSTUserDataSource)dataSource @@ -222,7 +240,7 @@ typedef NS_ENUM(NSInteger, FSTUserDataSource) { [[FSTParseContext alloc] initWithSource:dataSource path:std::move(path) arrayElement:NO - fieldTransforms:[NSMutableArray array] + fieldTransforms:std::make_shared>() fieldMask:std::make_shared>()]; [context validatePath]; return context; @@ -231,13 +249,13 @@ typedef NS_ENUM(NSInteger, FSTUserDataSource) { - (instancetype)initWithSource:(FSTUserDataSource)dataSource path:(std::unique_ptr)path arrayElement:(BOOL)arrayElement - fieldTransforms:(NSMutableArray *)fieldTransforms + fieldTransforms:(std::shared_ptr>)fieldTransforms fieldMask:(std::shared_ptr>)fieldMask { if (self = [super init]) { _dataSource = dataSource; _path = std::move(path); _arrayElement = arrayElement; - _fieldTransforms = fieldTransforms; + _fieldTransforms = std::move(fieldTransforms); _fieldMask = std::move(fieldMask); } return self; @@ -251,7 +269,7 @@ typedef NS_ENUM(NSInteger, FSTUserDataSource) { FSTParseContext *context = [[FSTParseContext alloc] initWithSource:self.dataSource path:std::move(path) arrayElement:NO - fieldTransforms:self.fieldTransforms + fieldTransforms:_fieldTransforms fieldMask:_fieldMask]; [context validatePathSegment:fieldName]; return context; @@ -265,7 +283,7 @@ typedef NS_ENUM(NSInteger, FSTUserDataSource) { FSTParseContext *context = [[FSTParseContext alloc] initWithSource:self.dataSource path:std::move(path) arrayElement:NO - fieldTransforms:self.fieldTransforms + fieldTransforms:_fieldTransforms fieldMask:_fieldMask]; [context validatePath]; return context; @@ -276,7 +294,7 @@ typedef NS_ENUM(NSInteger, FSTUserDataSource) { return [[FSTParseContext alloc] initWithSource:self.dataSource path:nil arrayElement:YES - fieldTransforms:self.fieldTransforms + fieldTransforms:_fieldTransforms fieldMask:_fieldMask]; } @@ -335,6 +353,16 @@ typedef NS_ENUM(NSInteger, FSTUserDataSource) { _fieldMask->push_back(std::move(fieldPath)); } +- (const std::vector *)fieldTransforms { + return _fieldTransforms.get(); +} + +- (void)appendToFieldTransformsWithFieldPath:(FieldPath)fieldPath + transformOperation: + (std::unique_ptr)transformOperation { + _fieldTransforms->emplace_back(std::move(fieldPath), std::move(transformOperation)); +} + @end #pragma mark - FSTDocumentKeyReference @@ -392,7 +420,7 @@ typedef NS_ENUM(NSInteger, FSTUserDataSource) { return [[FSTParsedSetData alloc] initWithData:updateData fieldMask:FieldMask{*context.fieldMask} - fieldTransforms:context.fieldTransforms]; + fieldTransforms:*context.fieldTransforms]; } - (FSTParsedSetData *)parsedSetData:(id)input { @@ -407,7 +435,8 @@ typedef NS_ENUM(NSInteger, FSTUserDataSource) { path:absl::make_unique(FieldPath::EmptyPath())]; FSTObjectValue *updateData = (FSTObjectValue *)[self parseData:input context:context]; - return [[FSTParsedSetData alloc] initWithData:updateData fieldTransforms:context.fieldTransforms]; + return + [[FSTParsedSetData alloc] initWithData:updateData fieldTransforms:*context.fieldTransforms]; } - (FSTParsedUpdateData *)parsedUpdateData:(id)input { @@ -453,7 +482,7 @@ typedef NS_ENUM(NSInteger, FSTUserDataSource) { return [[FSTParsedUpdateData alloc] initWithData:updateData fieldMask:FieldMask{fieldMaskPaths} - fieldTransforms:context.fieldTransforms]; + fieldTransforms:*context.fieldTransforms]; } - (FSTFieldValue *)parsedQueryValue:(id)input { @@ -462,7 +491,7 @@ typedef NS_ENUM(NSInteger, FSTUserDataSource) { path:absl::make_unique(FieldPath::EmptyPath())]; FSTFieldValue *_Nullable parsed = [self parseData:input context:context]; FSTAssert(parsed, @"Parsed data should not be nil."); - FSTAssert(context.fieldTransforms.count == 0, @"Field transforms should have been disallowed."); + FSTAssert(context.fieldTransforms->empty(), @"Field transforms should have been disallowed."); return parsed; } @@ -661,11 +690,9 @@ typedef NS_ENUM(NSInteger, FSTUserDataSource) { @"FieldValue.serverTimestamp() is not currently supported inside arrays%@", [context fieldDescription]); } - [context.fieldTransforms - addObject:[[FSTFieldTransform alloc] - initWithPath:*context.path - transform:absl::make_unique( - ServerTimestampTransform::Get())]]; + [context appendToFieldTransformsWithFieldPath:*context.path + transformOperation:absl::make_unique( + ServerTimestampTransform::Get())]; // Return nil so this value is omitted from the parsed result. return nil; diff --git a/Firestore/Source/Core/FSTTransaction.h b/Firestore/Source/Core/FSTTransaction.h index 01c2e20..581a5fa 100644 --- a/Firestore/Source/Core/FSTTransaction.h +++ b/Firestore/Source/Core/FSTTransaction.h @@ -24,7 +24,6 @@ @class FIRSetOptions; @class FSTDatastore; -@class FSTFieldTransform; @class FSTMaybeDocument; @class FSTObjectValue; @class FSTParsedSetData; diff --git a/Firestore/Source/Model/FSTMutation.h b/Firestore/Source/Model/FSTMutation.h index 2fa8806..38c35bf 100644 --- a/Firestore/Source/Model/FSTMutation.h +++ b/Firestore/Source/Model/FSTMutation.h @@ -22,6 +22,7 @@ #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/field_transform.h" #include "Firestore/core/src/firebase/firestore/model/transform_operations.h" @class FSTDocument; @@ -33,19 +34,6 @@ NS_ASSUME_NONNULL_BEGIN -#pragma mark - FSTFieldTransform - -/** A field path and the TransformOperation to perform upon it. */ -@interface FSTFieldTransform : NSObject -- (instancetype)init NS_UNAVAILABLE; -- (instancetype)initWithPath:(firebase::firestore::model::FieldPath)path - transform: - (std::unique_ptr)transform - NS_DESIGNATED_INITIALIZER; -- (const firebase::firestore::model::FieldPath &)path; -- (const firebase::firestore::model::TransformOperation *)transform; -@end - #pragma mark - FSTPrecondition typedef NS_ENUM(NSUInteger, FSTPreconditionExists) { @@ -103,7 +91,7 @@ typedef NS_ENUM(NSUInteger, FSTPreconditionExists) { /** * The resulting fields returned from the backend after a FSTTransformMutation has been committed. - * Contains one FieldValue for each FSTFieldTransform that was in the mutation. + * Contains one FieldValue for each FieldTransform that was in the mutation. * * Will be nil if the mutation was not a FSTTransformMutation. */ @@ -284,14 +272,14 @@ typedef NS_ENUM(NSUInteger, FSTPreconditionExists) { * Initializes a new transform mutation with the specified field transforms. * * @param key Identifies the location of the document to mutate. - * @param fieldTransforms A list of FSTFieldTransform objects to perform to the document. + * @param fieldTransforms A list of FieldTransform objects to perform to the document. */ - (instancetype)initWithKey:(firebase::firestore::model::DocumentKey)key - fieldTransforms:(NSArray *)fieldTransforms + fieldTransforms:(std::vector)fieldTransforms NS_DESIGNATED_INITIALIZER; /** The field transforms to use when transforming the document. */ -@property(nonatomic, strong, readonly) NSArray *fieldTransforms; +- (const std::vector &)fieldTransforms; @end diff --git a/Firestore/Source/Model/FSTMutation.mm b/Firestore/Source/Model/FSTMutation.mm index a18053c..dd649a0 100644 --- a/Firestore/Source/Model/FSTMutation.mm +++ b/Firestore/Source/Model/FSTMutation.mm @@ -17,7 +17,9 @@ #import "Firestore/Source/Model/FSTMutation.h" #include +#include #include +#include #import "FIRTimestamp.h" @@ -30,56 +32,18 @@ #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/field_transform.h" #include "Firestore/core/src/firebase/firestore/model/transform_operations.h" using firebase::firestore::model::DocumentKey; using firebase::firestore::model::FieldMask; using firebase::firestore::model::FieldPath; +using firebase::firestore::model::FieldTransform; using firebase::firestore::model::ServerTimestampTransform; using firebase::firestore::model::TransformOperation; NS_ASSUME_NONNULL_BEGIN -#pragma mark - FSTFieldTransform - -@implementation FSTFieldTransform { - FieldPath _path; - std::unique_ptr _transform; -} - -- (instancetype)initWithPath:(FieldPath)path - transform:(std::unique_ptr)transform { - self = [super init]; - if (self) { - _path = std::move(path); - _transform = std::move(transform); - } - return self; -} - -- (BOOL)isEqual:(id)other { - if (other == self) return YES; - if (![[other class] isEqual:[self class]]) return NO; - FSTFieldTransform *otherFieldTransform = other; - return self.path == otherFieldTransform.path && *self.transform == *otherFieldTransform.transform; -} - -- (NSUInteger)hash { - NSUInteger hash = self.path.Hash(); - hash = hash * 31 + self.transform->Hash(); - return hash; -} - -- (const firebase::firestore::model::FieldPath &)path { - return _path; -} - -- (const firebase::firestore::model::TransformOperation *)transform { - return _transform.get(); -} - -@end - #pragma mark - FSTPrecondition @implementation FSTPrecondition @@ -399,20 +363,27 @@ NS_ASSUME_NONNULL_BEGIN @end -@implementation FSTTransformMutation +@implementation FSTTransformMutation { + /** The field transforms to use when transforming the document. */ + std::vector _fieldTransforms; +} - (instancetype)initWithKey:(DocumentKey)key - fieldTransforms:(NSArray *)fieldTransforms { + fieldTransforms:(std::vector)fieldTransforms { // NOTE: We set a precondition of exists: true as a safety-check, since we always combine // FSTTransformMutations with a FSTSetMutation or FSTPatchMutation which (if successful) should // end up with an existing document. if (self = [super initWithKey:std::move(key) precondition:[FSTPrecondition preconditionWithExists:YES]]) { - _fieldTransforms = fieldTransforms; + _fieldTransforms = std::move(fieldTransforms); } return self; } +- (const std::vector &)fieldTransforms { + return _fieldTransforms; +} + - (BOOL)isEqual:(id)other { if (other == self) { return YES; @@ -423,20 +394,26 @@ NS_ASSUME_NONNULL_BEGIN FSTTransformMutation *otherMutation = (FSTTransformMutation *)other; return [self.key isEqual:otherMutation.key] && - [self.fieldTransforms isEqual:otherMutation.fieldTransforms] && + self.fieldTransforms == otherMutation.fieldTransforms && [self.precondition isEqual:otherMutation.precondition]; } - (NSUInteger)hash { NSUInteger result = [self.key hash]; result = 31 * result + [self.precondition hash]; - result = 31 * result + [self.fieldTransforms hash]; + for (const auto &transform : self.fieldTransforms) { + result = 31 * result + transform.Hash(); + } return result; } - (NSString *)description { - return [NSString stringWithFormat:@"", - self.key.ToString().c_str(), self.fieldTransforms, + std::string fieldTransforms; + for (const auto &transform : self.fieldTransforms) { + fieldTransforms += " " + transform.path().CanonicalString(); + } + return [NSString stringWithFormat:@"", + self.key.ToString().c_str(), fieldTransforms.c_str(), self.precondition]; } @@ -486,19 +463,19 @@ NS_ASSUME_NONNULL_BEGIN (FSTMaybeDocument *_Nullable)baseDocument writeTime:(FIRTimestamp *)localWriteTime { NSMutableArray *transformResults = [NSMutableArray array]; - for (FSTFieldTransform *fieldTransform in self.fieldTransforms) { - if (fieldTransform.transform->type() == TransformOperation::Type::ServerTimestamp) { + for (const FieldTransform &fieldTransform : self.fieldTransforms) { + if (fieldTransform.transformation().type() == TransformOperation::Type::ServerTimestamp) { FSTFieldValue *previousValue = nil; if ([baseDocument isMemberOfClass:[FSTDocument class]]) { - previousValue = [((FSTDocument *)baseDocument) fieldForPath:fieldTransform.path]; + previousValue = [((FSTDocument *)baseDocument) fieldForPath:fieldTransform.path()]; } [transformResults addObject:[FSTServerTimestampValue serverTimestampValueWithLocalWriteTime:localWriteTime previousValue:previousValue]]; } else { - FSTFail(@"Encountered unknown transform: %@", fieldTransform); + FSTFail(@"Encountered unknown transform: %d type", fieldTransform.transformation().type()); } } return transformResults; @@ -506,17 +483,17 @@ NS_ASSUME_NONNULL_BEGIN - (FSTObjectValue *)transformObject:(FSTObjectValue *)objectValue transformResults:(NSArray *)transformResults { - FSTAssert(transformResults.count == self.fieldTransforms.count, + FSTAssert(transformResults.count == self.fieldTransforms.size(), @"Transform results length mismatch."); - for (NSUInteger i = 0; i < self.fieldTransforms.count; i++) { - FSTFieldTransform *fieldTransform = self.fieldTransforms[i]; - const TransformOperation *transform = fieldTransform.transform; - FieldPath fieldPath = fieldTransform.path; - if (transform->type() == TransformOperation::Type::ServerTimestamp) { + for (size_t i = 0; i < self.fieldTransforms.size(); i++) { + const FieldTransform &fieldTransform = self.fieldTransforms[i]; + const TransformOperation &transform = fieldTransform.transformation(); + const FieldPath &fieldPath = fieldTransform.path(); + if (transform.type() == TransformOperation::Type::ServerTimestamp) { objectValue = [objectValue objectBySettingValue:transformResults[i] forPath:fieldPath]; } else { - FSTFail(@"Encountered unknown transform: %d type", transform->type()); + FSTFail(@"Encountered unknown transform: %d type", transform.type()); } } return objectValue; diff --git a/Firestore/Source/Remote/FSTSerializerBeta.mm b/Firestore/Source/Remote/FSTSerializerBeta.mm index 095d731..1d9ad30 100644 --- a/Firestore/Source/Remote/FSTSerializerBeta.mm +++ b/Firestore/Source/Remote/FSTSerializerBeta.mm @@ -49,6 +49,7 @@ #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/field_transform.h" #include "Firestore/core/src/firebase/firestore/model/resource_path.h" #include "Firestore/core/src/firebase/firestore/model/transform_operations.h" #include "Firestore/core/src/firebase/firestore/util/string_apple.h" @@ -59,6 +60,7 @@ using firebase::firestore::model::DatabaseId; using firebase::firestore::model::DocumentKey; using firebase::firestore::model::FieldMask; using firebase::firestore::model::FieldPath; +using firebase::firestore::model::FieldTransform; using firebase::firestore::model::ResourcePath; using firebase::firestore::model::ServerTimestampTransform; using firebase::firestore::model::TransformOperation; @@ -557,7 +559,7 @@ NS_ASSUME_NONNULL_BEGIN } - (FieldMask)decodedFieldMask:(GCFSDocumentMask *)fieldMask { - std::vector fields{}; + std::vector fields; fields.reserve(fieldMask.fieldPathsArray_Count); for (NSString *path in fieldMask.fieldPathsArray) { fields.push_back(FieldPath::FromServerFormat(util::MakeStringView(path))); @@ -566,31 +568,30 @@ NS_ASSUME_NONNULL_BEGIN } - (NSMutableArray *)encodedFieldTransforms: - (NSArray *)fieldTransforms { + (const std::vector &)fieldTransforms { NSMutableArray *protos = [NSMutableArray array]; - for (FSTFieldTransform *fieldTransform in fieldTransforms) { - FSTAssert(fieldTransform.transform->type() == TransformOperation::Type::ServerTimestamp, - @"Unknown transform: %d type", fieldTransform.transform->type()); + for (const FieldTransform &fieldTransform : fieldTransforms) { + FSTAssert(fieldTransform.transformation().type() == TransformOperation::Type::ServerTimestamp, + @"Unknown transform: %d type", fieldTransform.transformation().type()); GCFSDocumentTransform_FieldTransform *proto = [GCFSDocumentTransform_FieldTransform message]; - proto.fieldPath = util::WrapNSString(fieldTransform.path.CanonicalString()); + proto.fieldPath = util::WrapNSString(fieldTransform.path().CanonicalString()); proto.setToServerValue = GCFSDocumentTransform_FieldTransform_ServerValue_RequestTime; [protos addObject:proto]; } return protos; } -- (NSArray *)decodedFieldTransforms: +- (std::vector)decodedFieldTransforms: (NSArray *)protos { - NSMutableArray *fieldTransforms = [NSMutableArray array]; + std::vector fieldTransforms; + fieldTransforms.reserve(protos.count); for (GCFSDocumentTransform_FieldTransform *proto in protos) { FSTAssert( proto.setToServerValue == GCFSDocumentTransform_FieldTransform_ServerValue_RequestTime, @"Unknown transform setToServerValue: %d", proto.setToServerValue); - [fieldTransforms addObject:[[FSTFieldTransform alloc] - initWithPath:FieldPath::FromServerFormat( - util::MakeStringView(proto.fieldPath)) - transform:absl::make_unique( - ServerTimestampTransform::Get())]]; + fieldTransforms.emplace_back( + FieldPath::FromServerFormat(util::MakeStringView(proto.fieldPath)), + absl::make_unique(ServerTimestampTransform::Get())); } return fieldTransforms; } diff --git a/Firestore/core/src/firebase/firestore/model/CMakeLists.txt b/Firestore/core/src/firebase/firestore/model/CMakeLists.txt index d83c0aa..de783ad 100644 --- a/Firestore/core/src/firebase/firestore/model/CMakeLists.txt +++ b/Firestore/core/src/firebase/firestore/model/CMakeLists.txt @@ -25,6 +25,7 @@ cc_library( field_mask.h field_path.cc field_path.h + field_transform.h field_value.cc field_value.h maybe_document.cc diff --git a/Firestore/core/src/firebase/firestore/model/field_transform.h b/Firestore/core/src/firebase/firestore/model/field_transform.h new file mode 100644 index 0000000..a1dd96c --- /dev/null +++ b/Firestore/core/src/firebase/firestore/model/field_transform.h @@ -0,0 +1,70 @@ +/* + * 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_TRANSFORM_H_ +#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_MODEL_FIELD_TRANSFORM_H_ + +#include +#include + +#include "Firestore/core/src/firebase/firestore/model/field_path.h" +#include "Firestore/core/src/firebase/firestore/model/transform_operations.h" + +namespace firebase { +namespace firestore { +namespace model { + +/** A field path and the TransformOperation to perform upon it. */ +class FieldTransform { + public: + FieldTransform(FieldPath path, + std::unique_ptr transformation) noexcept + : path_{std::move(path)}, transformation_{std::move(transformation)} { + } + + const FieldPath& path() const { + return path_; + } + + const TransformOperation& transformation() const { + return *transformation_.get(); + } + + bool operator==(const FieldTransform& other) const { + return path_ == other.path_ && *transformation_ == *other.transformation_; + } + +#if defined(__OBJC__) + // For Objective-C++ hash; to be removed after migration. + // Do NOT use in C++ code. + NSUInteger Hash() const { + NSUInteger hash = path_.Hash(); + hash = hash * 31 + transformation_->Hash(); + return hash; + } +#endif // defined(__OBJC__) + + private: + FieldPath path_; + // Shared by copies of the same FieldTransform. + std::shared_ptr transformation_; +}; + +} // namespace model +} // namespace firestore +} // namespace firebase + +#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_MODEL_FIELD_TRANSFORM_H_ diff --git a/Firestore/core/test/firebase/firestore/model/CMakeLists.txt b/Firestore/core/test/firebase/firestore/model/CMakeLists.txt index 5e494f1..3bac89d 100644 --- a/Firestore/core/test/firebase/firestore/model/CMakeLists.txt +++ b/Firestore/core/test/firebase/firestore/model/CMakeLists.txt @@ -20,6 +20,7 @@ cc_test( document_test.cc field_mask_test.cc field_path_test.cc + field_transform_test.cc field_value_test.cc maybe_document_test.cc no_document_test.cc diff --git a/Firestore/core/test/firebase/firestore/model/field_transform_test.cc b/Firestore/core/test/firebase/firestore/model/field_transform_test.cc new file mode 100644 index 0000000..b66aeef --- /dev/null +++ b/Firestore/core/test/firebase/firestore/model/field_transform_test.cc @@ -0,0 +1,39 @@ +/* + * 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_transform.h" +#include "Firestore/core/src/firebase/firestore/model/transform_operations.h" +#include "Firestore/core/test/firebase/firestore/testutil/testutil.h" + +#include "absl/memory/memory.h" +#include "gtest/gtest.h" + +namespace firebase { +namespace firestore { +namespace model { + +TEST(FieldTransform, Getter) { + FieldTransform transform(testutil::Field("foo"), + absl::make_unique( + ServerTimestampTransform::Get())); + + EXPECT_EQ(testutil::Field("foo"), transform.path()); + EXPECT_EQ(ServerTimestampTransform::Get(), transform.transformation()); +} + +} // namespace model +} // namespace firestore +} // namespace firebase -- cgit v1.2.3