diff --git a/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore.podspec b/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore.podspec index 5f6046a9d0df..53886b85e07e 100755 --- a/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore.podspec +++ b/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore.podspec @@ -24,10 +24,10 @@ Pod::Spec.new do |s| s.license = { :file => '../LICENSE' } s.authors = 'The Chromium Authors' s.source = { :path => '.' } - s.source_files = 'cloud_firestore/Sources/cloud_firestore/**/*.{h,m,mm}' - s.public_header_files = 'cloud_firestore/Sources/cloud_firestore/include/Public/**/*.h' - s.private_header_files = 'cloud_firestore/Sources/cloud_firestore/include/Private/**/*.h' + s.source_files = 'cloud_firestore/Sources/**/*.{swift,h,m,mm}' + s.public_header_files = 'cloud_firestore/Sources/cloud_firestore_objc/include/*.h' + s.swift_version = '5.0' s.ios.deployment_target = '15.0' s.dependency 'Flutter' @@ -36,7 +36,6 @@ Pod::Spec.new do |s| s.static_framework = true s.pod_target_xcconfig = { - 'GCC_PREPROCESSOR_DEFINITIONS' => "LIBRARY_VERSION=\\\"#{library_version}\\\" LIBRARY_NAME=\\\"flutter-fire-fst\\\"", 'DEFINES_MODULE' => 'YES' } end diff --git a/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Package.swift b/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Package.swift index d3d29b817809..e116eff10233 100644 --- a/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Package.swift +++ b/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Package.swift @@ -24,22 +24,30 @@ let package = Package( .package(name: "FlutterFramework", path: "../FlutterFramework"), ], targets: [ + // SPM does not allow mixing Swift and ObjC in a single target. + .target( + name: "cloud_firestore_objc", + dependencies: [ + .product(name: "FirebaseFirestore", package: "firebase-ios-sdk") + ], + path: "Sources/cloud_firestore_objc", + publicHeadersPath: "include", + cSettings: [ + .headerSearchPath("include") + ] + ), .target( name: "cloud_firestore", dependencies: [ + "cloud_firestore_objc", .product(name: "FirebaseFirestore", package: "firebase-ios-sdk"), .product(name: "firebase-core", package: "firebase_core"), .product(name: "FlutterFramework", package: "FlutterFramework"), ], + path: "Sources/cloud_firestore", resources: [ .process("Resources") - ], - cSettings: [ - .headerSearchPath("include/cloud_firestore/Private"), - .headerSearchPath("include/cloud_firestore/Public"), - .define("LIBRARY_VERSION", to: "\"\(libraryVersion)\""), - .define("LIBRARY_NAME", to: "\"flutter-fire-fst\""), ] - ) + ), ] ) diff --git a/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/Constants.swift b/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/Constants.swift new file mode 100644 index 000000000000..23cc892df8a9 --- /dev/null +++ b/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/Constants.swift @@ -0,0 +1,19 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/// Auto-generated file. Do not edit. +public let versionNumber = "6.8.0" + +let kFLTFirebaseFirestoreChannelName = "plugins.flutter.io/firebase_firestore" +let kFLTFirebaseFirestoreQuerySnapshotEventChannelName = + "plugins.flutter.io/firebase_firestore/query" +let kFLTFirebaseFirestoreDocumentSnapshotEventChannelName = + "plugins.flutter.io/firebase_firestore/document" +let kFLTFirebaseFirestoreSnapshotsInSyncEventChannelName = + "plugins.flutter.io/firebase_firestore/snapshotsInSync" +let kFLTFirebaseFirestoreTransactionChannelName = + "plugins.flutter.io/firebase_firestore/transaction" +let kFLTFirebaseFirestoreLoadBundleChannelName = + "plugins.flutter.io/firebase_firestore/loadBundle" +let kFirebaseFirestoreLibraryName = "flutter-fire-fst" diff --git a/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/DocumentSnapshotStreamHandler.swift b/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/DocumentSnapshotStreamHandler.swift new file mode 100644 index 000000000000..98a1da4a8fd2 --- /dev/null +++ b/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/DocumentSnapshotStreamHandler.swift @@ -0,0 +1,81 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import FirebaseFirestore +import Foundation + +#if canImport(firebase_core) + import firebase_core +#else + import firebase_core_shared +#endif + +#if os(iOS) + import Flutter +#elseif os(macOS) + import FlutterMacOS +#endif + +final class DocumentSnapshotStreamHandler: NSObject, FlutterStreamHandler { + private let firestore: Firestore + private let reference: DocumentReference + private let includeMetadataChanges: Bool + private let serverTimestampBehavior: FirebaseFirestore.ServerTimestampBehavior + private let source: FirebaseFirestore.ListenSource + private var listenerRegistration: ListenerRegistration? + + init( + firestore: Firestore, + reference: DocumentReference, + includeMetadataChanges: Bool, + serverTimestampBehavior: FirebaseFirestore.ServerTimestampBehavior, + source: FirebaseFirestore.ListenSource + ) { + self.firestore = firestore + self.reference = reference + self.includeMetadataChanges = includeMetadataChanges + self.serverTimestampBehavior = serverTimestampBehavior + self.source = source + } + + func onListen(withArguments arguments: Any?, eventSink events: @escaping FlutterEventSink) + -> FlutterError? + { + let options = SnapshotListenOptions() + .withIncludeMetadataChanges(includeMetadataChanges) + .withSource(source) + + listenerRegistration = reference.addSnapshotListener(options: options) { + [serverTimestampBehavior] snapshot, error in + if let error { + let (code, message) = FirebaseFirestoreUtils.errorCodeAndMessage(from: error) + DispatchQueue.main.async { + events( + FLTFirebasePlugin.createFlutterError( + fromCode: code, + message: message, + optionalDetails: ["code": code, "message": message], + andOptionalNSError: error as NSError + ) + ) + } + } else if let snapshot { + DispatchQueue.main.async { + events( + PigeonParser.toPigeonDocumentSnapshot( + snapshot, serverTimestampBehavior: serverTimestampBehavior + ) + ) + } + } + } + return nil + } + + func onCancel(withArguments arguments: Any?) -> FlutterError? { + listenerRegistration?.remove() + listenerRegistration = nil + return nil + } +} diff --git a/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/FLTDocumentSnapshotStreamHandler.m b/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/FLTDocumentSnapshotStreamHandler.m deleted file mode 100644 index e8119c70d761..000000000000 --- a/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/FLTDocumentSnapshotStreamHandler.m +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright 2021 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -@import FirebaseFirestore; -#if __has_include() -#import -#else -#import -#endif - -#import "include/cloud_firestore/Private/FLTDocumentSnapshotStreamHandler.h" -#import "include/cloud_firestore/Private/FLTFirebaseFirestoreUtils.h" -#import "include/cloud_firestore/Private/FirestorePigeonParser.h" -#import "include/cloud_firestore/Public/CustomPigeonHeaderFirestore.h" - -@interface FLTDocumentSnapshotStreamHandler () -@property(readwrite, strong) id listenerRegistration; -@end - -@implementation FLTDocumentSnapshotStreamHandler - -- (nonnull instancetype)initWithFirestore:(nonnull FIRFirestore *)firestore - reference:(nonnull FIRDocumentReference *)reference - includeMetadataChanges:(BOOL)includeMetadataChanges - serverTimestampBehavior:(FIRServerTimestampBehavior)serverTimestampBehavior - source:(FIRListenSource)source { - self = [super init]; - if (self) { - self.firestore = firestore; - self.reference = reference; - self.includeMetadataChanges = includeMetadataChanges; - self.serverTimestampBehavior = serverTimestampBehavior; - self.source = source; - } - return self; -} - -- (FlutterError *_Nullable)onListenWithArguments:(id _Nullable)arguments - eventSink:(nonnull FlutterEventSink)events { - id listener = ^(FIRDocumentSnapshot *snapshot, NSError *_Nullable error) { - if (error) { - NSArray *codeAndMessage = [FLTFirebaseFirestoreUtils ErrorCodeAndMessageFromNSError:error]; - NSString *code = codeAndMessage[0]; - NSString *message = codeAndMessage[1]; - NSDictionary *details = @{ - @"code" : code, - @"message" : message, - }; - dispatch_async(dispatch_get_main_queue(), ^{ - events([FLTFirebasePlugin createFlutterErrorFromCode:code - message:message - optionalDetails:details - andOptionalNSError:error]); - }); - } else { - dispatch_async(dispatch_get_main_queue(), ^{ - // Emit the Pigeon object directly; the Pigeon-aware codec on the - // MessageChannel serializes it end-to-end. Pigeon 26 no longer flattens - // nested types via `toList`. - events([FirestorePigeonParser toPigeonDocumentSnapshot:snapshot - serverTimestampBehavior:self.serverTimestampBehavior]); - }); - } - }; - - FIRSnapshotListenOptions *options = [[FIRSnapshotListenOptions alloc] init]; - FIRSnapshotListenOptions *optionsWithSourceAndMetadata = [[options - optionsWithIncludeMetadataChanges:_includeMetadataChanges] optionsWithSource:_source]; - - self.listenerRegistration = - [_reference addSnapshotListenerWithOptions:optionsWithSourceAndMetadata listener:listener]; - - return nil; -} - -- (FlutterError *_Nullable)onCancelWithArguments:(id _Nullable)arguments { - [self.listenerRegistration remove]; - self.listenerRegistration = nil; - - return nil; -} - -@end diff --git a/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/FLTFirebaseFirestoreExtension.m b/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/FLTFirebaseFirestoreExtension.m deleted file mode 100644 index 33fd92271fc4..000000000000 --- a/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/FLTFirebaseFirestoreExtension.m +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2023 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -@import FirebaseFirestore; - -#import "include/cloud_firestore/Private/FLTFirebaseFirestoreExtension.h" - -@interface FLTFirebaseFirestoreExtension () - -@property(nonatomic, strong, readwrite) FIRFirestore *instance; -@property(nonatomic, strong, readwrite) NSString *databaseURL; - -@end - -@implementation FLTFirebaseFirestoreExtension - -- (instancetype)initWithFirestoreInstance:(FIRFirestore *)firestore - databaseURL:(NSString *)databaseURL { - self = [super init]; - if (self) { - _instance = firestore; - _databaseURL = [databaseURL copy]; - } - return self; -} - -@end diff --git a/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/FLTFirebaseFirestorePlugin.m b/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/FLTFirebaseFirestorePlugin.m deleted file mode 100644 index 667ce9c43ba0..000000000000 --- a/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/FLTFirebaseFirestorePlugin.m +++ /dev/null @@ -1,984 +0,0 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -@import FirebaseFirestore; -#if __has_include() -#import -#else -#import -#endif - -#import -#import "FirebaseFirestoreInternal/FIRPersistentCacheIndexManager.h" -#import "include/cloud_firestore/Private/FLTDocumentSnapshotStreamHandler.h" -#import "include/cloud_firestore/Private/FLTFirebaseFirestoreReader.h" -#import "include/cloud_firestore/Private/FLTFirebaseFirestoreUtils.h" -#import "include/cloud_firestore/Private/FLTLoadBundleStreamHandler.h" -#import "include/cloud_firestore/Private/FLTPipelineParser.h" -#import "include/cloud_firestore/Private/FLTQuerySnapshotStreamHandler.h" -#import "include/cloud_firestore/Private/FLTSnapshotsInSyncStreamHandler.h" -#import "include/cloud_firestore/Private/FLTTransactionStreamHandler.h" -#import "include/cloud_firestore/Private/FirestorePigeonParser.h" -#import "include/cloud_firestore/Public/FLTFirebaseFirestorePlugin.h" -#import "include/cloud_firestore/Public/FirestoreMessages.g.h" - -// Forward-declare the Pigeon-generated reader/writer defined in -// `FirestoreMessages.g.m`. It bundles `FLTFirebaseFirestoreReader/Writer` with -// Pigeon type serialization, so it's safe to use on the plugin's method/event -// channels. -@interface FirebaseFirestoreHostApiCodecReaderWriter : FlutterStandardReaderWriter -@end - -NSString *const kFLTFirebaseFirestoreChannelName = @"plugins.flutter.io/firebase_firestore"; -NSString *const kFLTFirebaseFirestoreQuerySnapshotEventChannelName = - @"plugins.flutter.io/firebase_firestore/query"; -NSString *const kFLTFirebaseFirestoreDocumentSnapshotEventChannelName = - @"plugins.flutter.io/firebase_firestore/document"; -NSString *const kFLTFirebaseFirestoreSnapshotsInSyncEventChannelName = - @"plugins.flutter.io/firebase_firestore/snapshotsInSync"; -NSString *const kFLTFirebaseFirestoreTransactionChannelName = - @"plugins.flutter.io/firebase_firestore/transaction"; -NSString *const kFLTFirebaseFirestoreLoadBundleChannelName = - @"plugins.flutter.io/firebase_firestore/loadBundle"; - -@interface FLTFirestoreClientLanguage : NSObject -+ (void)setClientLanguage:(NSString *)language; -@end - -@interface FLTFirebaseFirestorePlugin () -@property(nonatomic, retain) NSMutableDictionary *transactions; - -/// Registers a unique event channel based on a channel prefix. -/// -/// Once registered, the plugin will take care of removing the stream handler and cleaning up, -/// if the engine is detached. -/// -/// This function generates a random ID. -/// -/// @param prefix Channel prefix onto which the unique ID will be appended on. The convention is -/// "namespace/component" whereas the last / is added internally. -/// @param handler The handler object for responding to channel events and submitting data. -/// @return The generated identifier. -/// @see #registerEventChannel(String, String, StreamHandler) -- (NSString *)registerEventChannelWithPrefix:(NSString *)prefix - streamHandler:(NSObject *)handler; - -/// Registers a unique event channel based on a channel prefix. -/// -/// Once registered, the plugin will take care of removing the stream handler and cleaning up, -/// if the engine is detached. -/// -/// @param prefix Channel prefix onto which the unique ID will be appended on. The convention is -/// "namespace/component" whereas the last / is added internally. -/// @param identifier A identifier which will be appended to the prefix. -/// @param handler The handler object for responding to channel events and submitting data. -/// @return The passed identifier. -/// @see #registerEventChannel(String, String, StreamHandler) -- (NSString *)registerEventChannelWithPrefix:(NSString *)prefix - identifier:(NSString *)identifier - streamHandler:(NSObject *)handler; -@end - -static NSCache *_serverTimestampMap; - -static id _Nullable FLTPipelineNullSafe(id value) { - return (value == nil || [value isKindOfClass:[NSNull class]]) ? nil : value; -} - -static NSNumber *_Nullable FLTPipelineTimestampToMs(id value) { - if (!value) return nil; - if ([value isKindOfClass:[NSNumber class]]) return value; - if ([value isKindOfClass:[FIRTimestamp class]]) { - FIRTimestamp *ts = value; - return @((int64_t)ts.seconds * 1000 + (int64_t)ts.nanoseconds / 1000000); - } - return nil; -} - -@implementation FLTFirebaseFirestorePlugin { - NSMutableDictionary *_eventChannels; - NSMutableDictionary *> *_streamHandlers; - NSMutableDictionary *_transactionHandlers; - NSObject *_binaryMessenger; -} - -FlutterStandardMethodCodec *_codec; - -+ (NSCache *)serverTimestampMap { - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - _serverTimestampMap = [NSCache new]; - }); - return _serverTimestampMap; -} - -+ (void)initialize { - // Use the Pigeon-generated reader/writer for MethodChannel/EventChannels so - // Pigeon types emitted by stream handlers (e.g. `InternalDocumentSnapshot`, - // `InternalSnapshotMetadata`) serialize correctly. The reader/writer extend - // `FLTFirebaseFirestoreReader/Writer`, so Firestore-specific types - // (Timestamp, GeoPoint, FieldValue, ...) still round-trip. - _codec = [FlutterStandardMethodCodec - codecWithReaderWriter:[[FirebaseFirestoreHostApiCodecReaderWriter alloc] init]]; -} - -#pragma mark - FlutterPlugin - -// Returns a singleton instance of the Firebase Firestore plugin. -//+ (instancetype)sharedInstance { -// static dispatch_once_t onceToken; -// static FLTFirebaseFirestorePlugin *instance; -// -// dispatch_once(&onceToken, ^{ -// instance = [[FLTFirebaseFirestorePlugin alloc] init]; -// // Register with the Flutter Firebase plugin registry. -// [[FLTFirebasePluginRegistry sharedInstance] registerFirebasePlugin:instance]; -// }); -// -// return instance; -//} - -- (instancetype)init:(NSObject *)messenger { - self = [super init]; - if (self) { - _binaryMessenger = messenger; - _transactions = [NSMutableDictionary dictionary]; - _eventChannels = [NSMutableDictionary dictionary]; - _streamHandlers = [NSMutableDictionary dictionary]; - _transactionHandlers = [NSMutableDictionary dictionary]; - } - return self; -} - -+ (void)registerWithRegistrar:(NSObject *)registrar { - FLTFirebaseFirestorePlugin *instance = - [[FLTFirebaseFirestorePlugin alloc] init:[registrar messenger]]; -#if TARGET_OS_IPHONE - [FLTFirestoreClientLanguage - setClientLanguage:[NSString stringWithFormat:@"gl-dart/%@", @LIBRARY_VERSION]]; -#endif - -#if TARGET_OS_OSX -// TODO(Salakar): Publish does not exist on MacOS version of FlutterPluginRegistrar. -#else - [registrar publish:instance]; -#endif - SetUpFirebaseFirestoreHostApi(registrar.messenger, instance); -} - -- (void)cleanupEventListeners { - for (FlutterEventChannel *channel in self->_eventChannels.allValues) { - [channel setStreamHandler:nil]; - } - [self->_eventChannels removeAllObjects]; - for (NSObject *handler in self->_streamHandlers.allValues) { - [handler onCancelWithArguments:nil]; - } - [self->_streamHandlers removeAllObjects]; - - @synchronized(self->_transactions) { - [self->_transactions removeAllObjects]; - } -} - -- (void)cleanupFirestoreInstances:(void (^)(void))completion { - if ([FLTFirebaseFirestoreUtils count] > 0) { - [FLTFirebaseFirestoreUtils cleanupFirestoreInstances:completion]; - } else { - if (completion != nil) completion(); - } -} - -- (void)detachFromEngineForRegistrar:(NSObject *)registrar { - [self cleanupEventListeners]; -} - -#pragma mark - FLTFirebasePlugin - -- (void)didReinitializeFirebaseCore:(void (^)(void))completion { - [self cleanupEventListeners]; - [self cleanupFirestoreInstances:completion]; -} - -- (NSDictionary *_Nonnull)pluginConstantsForFIRApp:(FIRApp *)firebase_app { - return @{}; -} - -- (NSString *_Nonnull)firebaseLibraryName { - return @LIBRARY_NAME; -} - -- (NSString *_Nonnull)firebaseLibraryVersion { - return @LIBRARY_VERSION; -} - -- (NSString *_Nonnull)flutterChannelName { - return kFLTFirebaseFirestoreChannelName; -} - -#pragma mark - Firestore API - -- (NSString *)registerEventChannelWithPrefix:(NSString *)prefix - streamHandler:(NSObject *)handler { - return [self registerEventChannelWithPrefix:prefix - identifier:[[[NSUUID UUID] UUIDString] lowercaseString] - streamHandler:handler]; -} - -- (NSString *)registerEventChannelWithPrefix:(NSString *)prefix - identifier:(NSString *)identifier - streamHandler:(NSObject *)handler { - NSString *channelName = [NSString stringWithFormat:@"%@/%@", prefix, identifier]; - - FlutterEventChannel *channel = [[FlutterEventChannel alloc] initWithName:channelName - binaryMessenger:_binaryMessenger - codec:_codec]; - - [channel setStreamHandler:handler]; - [_eventChannels setObject:channel forKey:identifier]; - [_streamHandlers setObject:handler forKey:identifier]; - - return identifier; -} - -- (FIRFirestore *_Nullable)getFIRFirestoreFromAppNameFromPigeon: - (FirestorePigeonFirebaseApp *)pigeonApp { - @synchronized(self) { - NSString *appNameDart = pigeonApp.appName; - NSString *databaseUrl = pigeonApp.databaseURL; - - FIRApp *app = [FLTFirebasePlugin firebaseAppNamed:appNameDart]; - - if ([FLTFirebaseFirestoreUtils getFirestoreInstanceByName:app.name - databaseURL:databaseUrl] != nil) { - return [FLTFirebaseFirestoreUtils getFirestoreInstanceByName:app.name - databaseURL:databaseUrl]; - } - - FIRFirestoreSettings *settings = [[FIRFirestoreSettings alloc] init]; - if (pigeonApp.settings.persistenceEnabled != nil) { - bool persistEnabled = [pigeonApp.settings.persistenceEnabled boolValue]; - - // We default to the maximum amount of cache allowed. - NSNumber *size = @(kFIRFirestoreCacheSizeUnlimited); - - if (pigeonApp.settings.cacheSizeBytes) { - NSNumber *cacheSizeBytes = pigeonApp.settings.cacheSizeBytes; - if ([cacheSizeBytes intValue] != -1) { - size = cacheSizeBytes; - } - } - - if (persistEnabled) { - settings.cacheSettings = [[FIRPersistentCacheSettings alloc] initWithSizeBytes:size]; - } else { - settings.cacheSettings = [[FIRMemoryCacheSettings alloc] - initWithGarbageCollectorSettings:[[FIRMemoryLRUGCSettings alloc] init]]; - } - } - - if (pigeonApp.settings.host != nil) { - settings.host = pigeonApp.settings.host; - // Only allow changing ssl if host is also specified. - if (pigeonApp.settings.sslEnabled != nil) { - settings.sslEnabled = [pigeonApp.settings.sslEnabled boolValue]; - } - } - - settings.dispatchQueue = [FLTFirebaseFirestoreReader getFirestoreQueue]; - - FIRFirestore *firestore = [FIRFirestore firestoreForApp:app database:databaseUrl]; - firestore.settings = settings; - - [FLTFirebaseFirestoreUtils setCachedFIRFirestoreInstance:firestore - forAppName:app.name - databaseURL:databaseUrl]; - return firestore; - } -} - -- (FlutterError *)convertToFlutterError:(NSError *)error { - NSArray *codeAndMessage = [FLTFirebaseFirestoreUtils ErrorCodeAndMessageFromNSError:error]; - NSString *_Nullable code = codeAndMessage[0]; - NSString *_Nullable message = codeAndMessage[1]; - NSDictionary *_Nullable details = @{ - @"code" : code, - @"message" : message, - }; - - return [FlutterError errorWithCode:code message:message details:details]; -} - -- (void)clearPersistenceApp:(nonnull FirestorePigeonFirebaseApp *)app - completion:(nonnull void (^)(FlutterError *_Nullable))completion { - FIRFirestore *firestore = [self getFIRFirestoreFromAppNameFromPigeon:app]; - [firestore clearPersistenceWithCompletion:^(NSError *error) { - if (error != nil) { - completion([self convertToFlutterError:error]); - } else { - completion(nil); - } - }]; -} - -- (void)disableNetworkApp:(nonnull FirestorePigeonFirebaseApp *)app - completion:(nonnull void (^)(FlutterError *_Nullable))completion { - FIRFirestore *firestore = [self getFIRFirestoreFromAppNameFromPigeon:app]; - [firestore disableNetworkWithCompletion:^(NSError *error) { - if (error != nil) { - completion([self convertToFlutterError:error]); - } else { - completion(nil); - } - }]; -} - -- (void)documentReferenceDeleteApp:(nonnull FirestorePigeonFirebaseApp *)app - request:(nonnull DocumentReferenceRequest *)request - completion:(nonnull void (^)(FlutterError *_Nullable))completion { - FIRFirestore *firestore = [self getFIRFirestoreFromAppNameFromPigeon:app]; - FIRDocumentReference *document = [firestore documentWithPath:request.path]; - - [document deleteDocumentWithCompletion:^(NSError *error) { - if (error != nil) { - completion([self convertToFlutterError:error]); - } else { - completion(nil); - } - }]; -} - -- (void)terminate:(id)arguments withMethodCallResult:(FLTFirebaseMethodCallResult *)result { - FIRFirestore *firestore = arguments[@"firestore"]; - [firestore terminateWithCompletion:^(NSError *error) { - if (error != nil) { - result.error(nil, nil, nil, error); - } else { - FLTFirebaseFirestoreExtension *firestoreExtension = - [FLTFirebaseFirestoreUtils getCachedInstanceForFirestore:firestore]; - [FLTFirebaseFirestoreUtils destroyCachedInstanceForFirestore:firestore.app.name - databaseURL:firestoreExtension.databaseURL]; - result.success(nil); - } - }]; -} - -- (void)documentReferenceGetApp:(nonnull FirestorePigeonFirebaseApp *)app - request:(nonnull DocumentReferenceRequest *)request - completion:(nonnull void (^)(InternalDocumentSnapshot *_Nullable, - FlutterError *_Nullable))completion { - FIRFirestore *firestore = [self getFIRFirestoreFromAppNameFromPigeon:app]; - FIRDocumentReference *document = [firestore documentWithPath:request.path]; - FIRFirestoreSource source = [FirestorePigeonParser parseSource:request.source.value]; - FIRServerTimestampBehavior serverTimestampBehavior = - [FirestorePigeonParser parseServerTimestampBehavior:request.serverTimestampBehavior.value]; - - id completionGet = ^(FIRDocumentSnapshot *_Nullable snapshot, NSError *_Nullable error) { - if (error != nil) { - completion(nil, [self convertToFlutterError:error]); - } else { - completion([FirestorePigeonParser toPigeonDocumentSnapshot:snapshot - serverTimestampBehavior:serverTimestampBehavior], - nil); - } - }; - - [document getDocumentWithSource:source completion:completionGet]; -} - -- (void)documentReferenceSetApp:(nonnull FirestorePigeonFirebaseApp *)app - request:(nonnull DocumentReferenceRequest *)request - completion:(nonnull void (^)(FlutterError *_Nullable))completion { - id data = request.data; - FIRFirestore *firestore = [self getFIRFirestoreFromAppNameFromPigeon:app]; - FIRDocumentReference *document = [firestore documentWithPath:request.path]; - - void (^completionBlock)(NSError *) = ^(NSError *error) { - if (error != nil) { - completion([self convertToFlutterError:error]); - } else { - completion(nil); - } - }; - - if ([request.option.merge isEqual:@YES]) { - [document setData:data merge:YES completion:completionBlock]; - } else if (request.option.mergeFields) { - [document setData:data - mergeFields:[FirestorePigeonParser parseFieldPath:request.option.mergeFields] - completion:completionBlock]; - } else { - [document setData:data completion:completionBlock]; - } -} - -- (void)documentReferenceSnapshotApp:(nonnull FirestorePigeonFirebaseApp *)app - parameters:(nonnull DocumentReferenceRequest *)parameters - includeMetadataChanges:(BOOL)includeMetadataChanges - source:(ListenSource)source - completion:(nonnull void (^)(NSString *_Nullable, - FlutterError *_Nullable))completion { - FIRFirestore *firestore = [self getFIRFirestoreFromAppNameFromPigeon:app]; - FIRDocumentReference *document = [firestore documentWithPath:parameters.path]; - FIRServerTimestampBehavior serverTimestampBehavior = - [FirestorePigeonParser parseServerTimestampBehavior:parameters.serverTimestampBehavior.value]; - FIRListenSource listenSource = [FirestorePigeonParser parseListenSource:source]; - - completion( - [self registerEventChannelWithPrefix:kFLTFirebaseFirestoreDocumentSnapshotEventChannelName - streamHandler:[[FLTDocumentSnapshotStreamHandler alloc] - initWithFirestore:firestore - reference:document - includeMetadataChanges:includeMetadataChanges - serverTimestampBehavior:serverTimestampBehavior - source:listenSource]], - nil); -} - -- (void)documentReferenceUpdateApp:(nonnull FirestorePigeonFirebaseApp *)app - request:(nonnull DocumentReferenceRequest *)request - completion:(nonnull void (^)(FlutterError *_Nullable))completion { - id data = request.data; - FIRFirestore *firestore = [self getFIRFirestoreFromAppNameFromPigeon:app]; - FIRDocumentReference *document = [firestore documentWithPath:request.path]; - - [document updateData:data - completion:^(NSError *error) { - if (error != nil) { - completion([self convertToFlutterError:error]); - } else { - completion(nil); - } - }]; -} - -- (void)enableNetworkApp:(nonnull FirestorePigeonFirebaseApp *)app - completion:(nonnull void (^)(FlutterError *_Nullable))completion { - FIRFirestore *firestore = [self getFIRFirestoreFromAppNameFromPigeon:app]; - [firestore enableNetworkWithCompletion:^(NSError *error) { - if (error != nil) { - completion([self convertToFlutterError:error]); - } else { - completion(nil); - } - }]; -} - -- (void)loadBundleApp:(nonnull FirestorePigeonFirebaseApp *)app - bundle:(nonnull FlutterStandardTypedData *)bundle - completion:(nonnull void (^)(NSString *_Nullable, FlutterError *_Nullable))completion { - FIRFirestore *firestore = [self getFIRFirestoreFromAppNameFromPigeon:app]; - - completion([self registerEventChannelWithPrefix:kFLTFirebaseFirestoreLoadBundleChannelName - streamHandler:[[FLTLoadBundleStreamHandler alloc] - initWithFirestore:firestore - bundle:bundle]], - nil); -} - -- (void)namedQueryGetApp:(nonnull FirestorePigeonFirebaseApp *)app - name:(nonnull NSString *)name - options:(nonnull InternalGetOptions *)options - completion:(nonnull void (^)(InternalQuerySnapshot *_Nullable, - FlutterError *_Nullable))completion { - FIRFirestore *firestore = [self getFIRFirestoreFromAppNameFromPigeon:app]; - - FIRFirestoreSource source = [FirestorePigeonParser parseSource:options.source]; - FIRServerTimestampBehavior serverTimestampBehavior = - [FirestorePigeonParser parseServerTimestampBehavior:options.serverTimestampBehavior]; - - [firestore - getQueryNamed:name - completion:^(FIRQuery *_Nullable query) { - if (query == nil) { - completion(nil, - [FlutterError errorWithCode:@"non-existent-named-query" - message:@"Named query has not been found. Please check " - @"it has been loaded properly via loadBundle()." - details:nil]); - - return; - } - [query getDocumentsWithSource:source - completion:^(FIRQuerySnapshot *_Nullable snapshot, - NSError *_Nullable error) { - if (error != nil) { - completion(nil, [self convertToFlutterError:error]); - } else { - completion([FirestorePigeonParser - toPigeonQuerySnapshot:snapshot - serverTimestampBehavior:serverTimestampBehavior], - nil); - } - }]; - }]; -} - -- (void)queryGetApp:(nonnull FirestorePigeonFirebaseApp *)app - path:(nonnull NSString *)path - isCollectionGroup:(BOOL)isCollectionGroup - parameters:(nonnull InternalQueryParameters *)parameters - options:(nonnull InternalGetOptions *)options - completion:(nonnull void (^)(InternalQuerySnapshot *_Nullable, - FlutterError *_Nullable))completion { - FIRFirestore *firestore = [self getFIRFirestoreFromAppNameFromPigeon:app]; - FIRQuery *query = [FirestorePigeonParser parseQueryWithParameters:parameters - firestore:firestore - path:path - isCollectionGroup:isCollectionGroup]; - if (query == nil) { - completion(nil, [FlutterError errorWithCode:@"error-parsing" - message:@"An error occurred while parsing query arguments, " - @"this is most likely an error with this SDK." - details:nil]); - return; - } - - FIRFirestoreSource source = [FirestorePigeonParser parseSource:options.source]; - FIRServerTimestampBehavior serverTimestampBehavior = - [FirestorePigeonParser parseServerTimestampBehavior:options.serverTimestampBehavior]; - - [query getDocumentsWithSource:source - completion:^(FIRQuerySnapshot *_Nullable snapshot, NSError *_Nullable error) { - if (error != nil) { - completion(nil, [self convertToFlutterError:error]); - } else { - completion( - [FirestorePigeonParser toPigeonQuerySnapshot:snapshot - serverTimestampBehavior:serverTimestampBehavior], - nil); - } - }]; -} - -- (void)querySnapshotApp:(nonnull FirestorePigeonFirebaseApp *)app - path:(nonnull NSString *)path - isCollectionGroup:(BOOL)isCollectionGroup - parameters:(nonnull InternalQueryParameters *)parameters - options:(nonnull InternalGetOptions *)options - includeMetadataChanges:(BOOL)includeMetadataChanges - source:(ListenSource)source - completion: - (nonnull void (^)(NSString *_Nullable, FlutterError *_Nullable))completion { - FIRFirestore *firestore = [self getFIRFirestoreFromAppNameFromPigeon:app]; - FIRQuery *query = [FirestorePigeonParser parseQueryWithParameters:parameters - firestore:firestore - path:path - isCollectionGroup:isCollectionGroup]; - if (query == nil) { - completion(nil, [FlutterError errorWithCode:@"error-parsing" - message:@"An error occurred while parsing query arguments, " - @"this is most likely an error with this SDK." - details:nil]); - return; - } - - FIRServerTimestampBehavior serverTimestampBehavior = - [FirestorePigeonParser parseServerTimestampBehavior:options.serverTimestampBehavior]; - FIRListenSource listenSource = [FirestorePigeonParser parseListenSource:source]; - - completion( - [self registerEventChannelWithPrefix:kFLTFirebaseFirestoreQuerySnapshotEventChannelName - streamHandler:[[FLTQuerySnapshotStreamHandler alloc] - initWithFirestore:firestore - query:query - includeMetadataChanges:includeMetadataChanges - serverTimestampBehavior:serverTimestampBehavior - source:listenSource]], - nil); -} - -- (void)setIndexConfigurationApp:(nonnull FirestorePigeonFirebaseApp *)app - indexConfiguration:(nonnull NSString *)indexConfiguration - completion:(nonnull void (^)(FlutterError *_Nullable))completion { - FIRFirestore *firestore = [self getFIRFirestoreFromAppNameFromPigeon:app]; - - [firestore setIndexConfigurationFromJSON:indexConfiguration - completion:^(NSError *_Nullable error) { - if (error != nil) { - completion([self convertToFlutterError:error]); - } else { - completion(nil); - } - }]; -} - -- (void)persistenceCacheIndexManagerRequestApp:(FirestorePigeonFirebaseApp *)app - request:(PersistenceCacheIndexManagerRequest)request - completion:(void (^)(FlutterError *_Nullable))completion { - FIRPersistentCacheIndexManager *persistentCacheIndexManager = - [self getFIRFirestoreFromAppNameFromPigeon:app].persistentCacheIndexManager; - - if (persistentCacheIndexManager) { - switch (request) { - case PersistenceCacheIndexManagerRequestEnableIndexAutoCreation: - [persistentCacheIndexManager enableIndexAutoCreation]; - break; - case PersistenceCacheIndexManagerRequestDisableIndexAutoCreation: - [persistentCacheIndexManager disableIndexAutoCreation]; - break; - case PersistenceCacheIndexManagerRequestDeleteAllIndexes: - [persistentCacheIndexManager deleteAllIndexes]; - break; - } - } else { - // Put because `persistentCacheIndexManager` is a nullable property - NSLog(@"FLTFirebaseFirestore: `PersistentCacheIndexManager` is not available."); - } - completion(nil); -} - -- (void)setLoggingEnabledLoggingEnabled:(BOOL)loggingEnabled - completion:(nonnull void (^)(FlutterError *_Nullable))completion { - [FIRFirestore enableLogging:loggingEnabled]; - completion(nil); -} - -- (void)terminateApp:(nonnull FirestorePigeonFirebaseApp *)app - completion:(nonnull void (^)(FlutterError *_Nullable))completion { - FIRFirestore *firestore = [self getFIRFirestoreFromAppNameFromPigeon:app]; - [firestore terminateWithCompletion:^(NSError *error) { - if (error != nil) { - completion([self convertToFlutterError:error]); - } else { - FLTFirebaseFirestoreExtension *firestoreExtension = - [FLTFirebaseFirestoreUtils getCachedInstanceForFirestore:firestore]; - [FLTFirebaseFirestoreUtils destroyCachedInstanceForFirestore:firestore.app.name - databaseURL:firestoreExtension.databaseURL]; - completion(nil); - } - }]; -} - -- (void)transactionGetApp:(nonnull FirestorePigeonFirebaseApp *)app - transactionId:(nonnull NSString *)transactionId - path:(nonnull NSString *)path - completion:(nonnull void (^)(InternalDocumentSnapshot *_Nullable, - FlutterError *_Nullable))completion { - // Dispatching to main thread allow us to ensure that the auth token are fetched in time - // for the transaction - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - FIRFirestore *firestore = [self getFIRFirestoreFromAppNameFromPigeon:app]; - FIRDocumentReference *document = [firestore documentWithPath:path]; - - FIRTransaction *transaction; - @synchronized(self->_transactions) { - transaction = self->_transactions[transactionId]; - } - - if (transaction == nil) { - completion( - nil, - [FlutterError - errorWithCode:@"missing-transaction" - message:@"An error occurred while getting the native transaction. " - @"It could be caused by a timeout in a preceding transaction operation." - details:nil]); - return; - } - - NSError *error = nil; - FIRDocumentSnapshot *snapshot = [transaction getDocument:document error:&error]; - - if (error != nil) { - completion(nil, [self convertToFlutterError:error]); - } else if (snapshot != nil) { - completion([FirestorePigeonParser toPigeonDocumentSnapshot:snapshot - serverTimestampBehavior:FIRServerTimestampBehaviorNone], - nil); - } else { - completion(nil, nil); - } - }); -} - -- (void)transactionStoreResultTransactionId:(nonnull NSString *)transactionId - resultType:(InternalTransactionResult)resultType - commands: - (nullable NSArray *)commands - completion:(nonnull void (^)(FlutterError *_Nullable))completion { - [_transactionHandlers[transactionId] receiveTransactionResponse:resultType commands:commands]; - - completion(nil); -} - -- (void)waitForPendingWritesApp:(nonnull FirestorePigeonFirebaseApp *)app - completion:(nonnull void (^)(FlutterError *_Nullable))completion { - FIRFirestore *firestore = [self getFIRFirestoreFromAppNameFromPigeon:app]; - [firestore waitForPendingWritesWithCompletion:^(NSError *error) { - if (error != nil) { - completion([self convertToFlutterError:error]); - } else { - completion(nil); - } - }]; -} - -- (void)writeBatchCommitApp:(nonnull FirestorePigeonFirebaseApp *)app - writes:(nonnull NSArray *)writes - completion:(nonnull void (^)(FlutterError *_Nullable))completion { - FIRFirestore *firestore = [self getFIRFirestoreFromAppNameFromPigeon:app]; - FIRWriteBatch *batch = [firestore batch]; - - for (InternalTransactionCommand *write in writes) { - InternalTransactionType type = write.type; - NSString *path = write.path; - FIRDocumentReference *reference = [firestore documentWithPath:path]; - - switch (type) { - case InternalTransactionTypeGet: - break; - case InternalTransactionTypeDeleteType: - [batch deleteDocument:reference]; - break; - case InternalTransactionTypeUpdate: - [batch updateData:write.data forDocument:reference]; - break; - case InternalTransactionTypeSet: - if ([write.option.merge isEqual:@YES]) { - [batch setData:write.data forDocument:reference merge:YES]; - } else if (write.option.mergeFields) { - [batch setData:write.data - forDocument:reference - mergeFields:[FirestorePigeonParser parseFieldPath:write.option.mergeFields]]; - } else { - [batch setData:write.data forDocument:reference]; - } - break; - } - } - - [batch commitWithCompletion:^(NSError *error) { - if (error != nil) { - completion([self convertToFlutterError:error]); - } else { - completion(nil); - } - }]; -} - -- (void)snapshotsInSyncSetupApp:(nonnull FirestorePigeonFirebaseApp *)app - completion:(nonnull void (^)(NSString *_Nullable, - FlutterError *_Nullable))completion { - FIRFirestore *firestore = [self getFIRFirestoreFromAppNameFromPigeon:app]; - - completion( - [self registerEventChannelWithPrefix:kFLTFirebaseFirestoreSnapshotsInSyncEventChannelName - streamHandler:[[FLTSnapshotsInSyncStreamHandler alloc] - initWithFirestore:firestore]], - nil); -} - -- (void)transactionCreateApp:(nonnull FirestorePigeonFirebaseApp *)app - timeout:(NSInteger)timeout - maxAttempts:(NSInteger)maxAttempts - completion: - (nonnull void (^)(NSString *_Nullable, FlutterError *_Nullable))completion { - FIRFirestore *firestore = [self getFIRFirestoreFromAppNameFromPigeon:app]; - - NSString *transactionId = [[[NSUUID UUID] UUIDString] lowercaseString]; - - FLTTransactionStreamHandler *handler = - [[FLTTransactionStreamHandler alloc] initWithId:transactionId - firestore:firestore - timeout:timeout - maxAttempts:maxAttempts - started:^(FIRTransaction *_Nonnull transaction) { - // Called from Firestore's transaction worker queue; multiple - // in-flight transactions may hit this concurrently. - @synchronized(self->_transactions) { - self->_transactions[transactionId] = transaction; - } - } - ended:^{ - @synchronized(self->_transactions) { - [self->_transactions removeObjectForKey:transactionId]; - } - }]; - - _transactionHandlers[transactionId] = handler; - - completion([self registerEventChannelWithPrefix:kFLTFirebaseFirestoreTransactionChannelName - identifier:transactionId - streamHandler:handler], - nil); -} - -- (void)aggregateQueryApp:(nonnull FirestorePigeonFirebaseApp *)app - path:(nonnull NSString *)path - parameters:(nonnull InternalQueryParameters *)parameters - source:(AggregateSource)source - queries:(nonnull NSArray *)queries - isCollectionGroup:(BOOL)isCollectionGroup - completion:(nonnull void (^)(NSArray *_Nullable, - FlutterError *_Nullable))completion { - FIRFirestore *firestore = [self getFIRFirestoreFromAppNameFromPigeon:app]; - - FIRQuery *query = [FirestorePigeonParser parseQueryWithParameters:parameters - firestore:firestore - path:path - isCollectionGroup:isCollectionGroup]; - if (query == nil) { - completion(nil, [FlutterError errorWithCode:@"error-parsing" - message:@"An error occurred while parsing query arguments, " - @"this is most likely an error with this SDK." - details:nil]); - return; - } - - NSMutableArray *aggregateFields = - [[NSMutableArray alloc] init]; - - for (AggregateQuery *queryRequest in queries) { - switch ([queryRequest type]) { - case AggregateTypeCount: - [aggregateFields addObject:[FIRAggregateField aggregateFieldForCount]]; - break; - case AggregateTypeSum: - [aggregateFields - addObject:[FIRAggregateField aggregateFieldForSumOfField:[queryRequest field]]]; - break; - case AggregateTypeAverage: - [aggregateFields - addObject:[FIRAggregateField aggregateFieldForAverageOfField:[queryRequest field]]]; - break; - default: - // Handle the default case - break; - } - } - - FIRAggregateQuery *aggregateQuery = [query aggregate:aggregateFields]; - - [aggregateQuery - aggregationWithSource:FIRAggregateSourceServer - completion:^(FIRAggregateQuerySnapshot *_Nullable snapshot, - NSError *_Nullable error) { - if (error != nil) { - completion(nil, [self convertToFlutterError:error]); - return; - } - NSMutableArray *aggregateResponses = - [[NSMutableArray alloc] init]; - - for (AggregateQuery *queryRequest in queries) { - switch (queryRequest.type) { - case AggregateTypeCount: { - double doubleValue = [snapshot.count doubleValue]; - - [aggregateResponses - addObject:[AggregateQueryResponse - makeWithType:AggregateTypeCount - field:nil - value:[NSNumber numberWithDouble:doubleValue]]]; - break; - } - case AggregateTypeSum: { - NSNumber *value = [snapshot - valueForAggregateField:[FIRAggregateField - aggregateFieldForSumOfField:[queryRequest - field]]]; - - [aggregateResponses - addObject:[AggregateQueryResponse - makeWithType:AggregateTypeSum - field:queryRequest.field - // This passes either a double (wrapped in - // NSNumber) or null value - value:value != ((id)[NSNull null]) - ? [NSNumber - numberWithDouble:[value - doubleValue]] - : value]]; - break; - } - case AggregateTypeAverage: { - NSNumber *value = [snapshot - valueForAggregateField: - [FIRAggregateField - aggregateFieldForAverageOfField:[queryRequest field]]]; - - [aggregateResponses - addObject:[AggregateQueryResponse - makeWithType:AggregateTypeAverage - field:queryRequest.field - // This passes either a double (wrapped in - // NSNumber) or null value - value:value != ((id)[NSNull null]) - ? [NSNumber - numberWithDouble:[value - doubleValue]] - : value]]; - break; - } - } - } - - completion(aggregateResponses, nil); - }]; -} - -- (void)executePipelineApp:(nonnull FirestorePigeonFirebaseApp *)app - stages:(nonnull NSArray *> *)stages - options:(nullable NSDictionary *)options - completion:(nonnull void (^)(InternalPipelineSnapshot *_Nullable, - FlutterError *_Nullable))completion { - FIRFirestore *firestore = [self getFIRFirestoreFromAppNameFromPigeon:app]; - - [FLTPipelineParser - executePipelineWithFirestore:firestore - stages:stages - options:options - completion:^(id _Nullable snapshot, NSError *_Nullable error) { - if (error) { - completion(nil, [self convertToFlutterError:error]); - return; - } - if (snapshot == nil) { - completion( - nil, - [FlutterError errorWithCode:@"error" - message:@"Pipeline execution returned no result" - details:nil]); - return; - } - - NSMutableArray *pigeonResults = - [NSMutableArray array]; - NSArray *results = [snapshot results]; - if ([results isKindOfClass:[NSArray class]]) { - for (id result in results) { - id ref = [result reference]; - NSString *path = (ref && [ref respondsToSelector:@selector(path)]) - ? [ref path] - : FLTPipelineNullSafe([result documentID]); - NSNumber *createTime = - FLTPipelineTimestampToMs([result valueForKey:@"create_time"]); - NSNumber *updateTime = - FLTPipelineTimestampToMs([result valueForKey:@"update_time"]); - NSDictionary *data = FLTPipelineNullSafe([result data]); - InternalPipelineResult *pigeonResult = - [InternalPipelineResult makeWithDocumentPath:path - createTime:createTime - updateTime:updateTime - data:data]; - [pigeonResults addObject:pigeonResult]; - } - } - - NSNumber *executionTime = - FLTPipelineTimestampToMs([snapshot execution_time]); - if (executionTime == nil) { - executionTime = - @((int64_t)([[NSDate date] timeIntervalSince1970] * 1000)); - } - - InternalPipelineSnapshot *pigeonSnapshot = [InternalPipelineSnapshot - makeWithResults:pigeonResults - executionTime:[executionTime longLongValue]]; - completion(pigeonSnapshot, nil); - }]; -} - -@end diff --git a/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/FLTFirebaseFirestorePlugin.swift b/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/FLTFirebaseFirestorePlugin.swift new file mode 100644 index 000000000000..97dd6de56037 --- /dev/null +++ b/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/FLTFirebaseFirestorePlugin.swift @@ -0,0 +1,886 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import FirebaseCore +import FirebaseFirestore +import Foundation + +#if canImport(firebase_core) + import firebase_core +#else + import firebase_core_shared +#endif + +#if canImport(cloud_firestore_objc) + import cloud_firestore_objc +#endif + +#if os(iOS) + import Flutter + import UIKit +#elseif os(macOS) + import AppKit + import FlutterMacOS +#endif + +@objc(FLTFirebaseFirestorePlugin) +public class FLTFirebaseFirestorePlugin: NSObject, FlutterPlugin, FLTFirebasePluginProtocol, + FirebaseFirestoreHostApi +{ + private var messenger: FlutterBinaryMessenger + private var transactions: [String: Transaction] = [:] + private var eventChannels: [String: FlutterEventChannel] = [:] + private var streamHandlers: [String: NSObject & FlutterStreamHandler] = [:] + private var transactionHandlers: [String: TransactionStreamHandler] = [:] + private let transactionLock = NSLock() + private let listenersLock = NSLock() + + static let serverTimestampMap = NSCache() + + private static let codec = FlutterStandardMethodCodec( + readerWriter: FirestoreMessagesPigeonCodecReaderWriter() + ) + + init(messenger: FlutterBinaryMessenger) { + self.messenger = messenger + super.init() + FLTFirebasePluginRegistry.sharedInstance().register(self) + } + + @objc + public static func register(with registrar: FlutterPluginRegistrar) { + #if os(macOS) + let binaryMessenger = registrar.messenger + #else + let binaryMessenger = registrar.messenger() + #endif + + let instance = FLTFirebaseFirestorePlugin(messenger: binaryMessenger) + #if os(iOS) + registrar.publish(instance) + FLTFirestoreClientLanguage.setClientLanguage("gl-dart/\(versionNumber)") + #endif + + FirebaseFirestoreHostApiSetup.setUp(binaryMessenger: binaryMessenger, api: instance) + } + + public func detachFromEngine(for registrar: FlutterPluginRegistrar) { + cleanupEventListeners() + } + + public func didReinitializeFirebaseCore(_ completion: @escaping () -> Void) { + cleanupEventListeners() + cleanupFirestoreInstances(completion) + } + + public func pluginConstants(for firebaseApp: FirebaseApp) -> [AnyHashable: Any] { + [:] + } + + @objc public func firebaseLibraryName() -> String { + kFirebaseFirestoreLibraryName + } + + @objc public func firebaseLibraryVersion() -> String { + versionNumber + } + + @objc public func flutterChannelName() -> String { + kFLTFirebaseFirestoreChannelName + } + + private func cleanupEventListeners() { + listenersLock.lock() + let channels = Array(eventChannels.values) + let handlers = Array(streamHandlers.values) + eventChannels.removeAll() + streamHandlers.removeAll() + transactionHandlers.removeAll() + listenersLock.unlock() + + for channel in channels { + channel.setStreamHandler(nil) + } + for handler in handlers { + _ = handler.onCancel(withArguments: nil) + } + transactionLock.lock() + transactions.removeAll() + transactionLock.unlock() + } + + private func unregisterEventChannel(_ identifier: String) { + listenersLock.lock() + eventChannels.removeValue(forKey: identifier) + streamHandlers.removeValue(forKey: identifier) + transactionHandlers.removeValue(forKey: identifier) + listenersLock.unlock() + } + + private func cleanupFirestoreInstances(_ completion: (() -> Void)?) { + if FirebaseFirestoreUtils.count > 0 { + FirebaseFirestoreUtils.cleanupFirestoreInstances(completion) + } else { + completion?() + } + } + + @discardableResult + private func registerEventChannel( + prefix: String, + identifier: String = UUID().uuidString.lowercased(), + streamHandler: NSObject & FlutterStreamHandler + ) -> String { + let channelName = "\(prefix)/\(identifier)" + let channel = FlutterEventChannel( + name: channelName, + binaryMessenger: messenger, + codec: Self.codec + ) + let wrapped = EventChannelCleanupHandler(inner: streamHandler) { [weak self] in + self?.unregisterEventChannel(identifier) + } + channel.setStreamHandler(wrapped) + listenersLock.lock() + eventChannels[identifier] = channel + streamHandlers[identifier] = wrapped + listenersLock.unlock() + return identifier + } + + private func firestore(from pigeonApp: FirestorePigeonFirebaseApp) -> Firestore { + objc_sync_enter(self) + defer { objc_sync_exit(self) } + + let app = FLTFirebasePlugin.firebaseAppNamed(pigeonApp.appName)! + if let cached = FirebaseFirestoreUtils.firestoreInstance( + appName: app.name, databaseURL: pigeonApp.databaseURL + ) { + return cached + } + + let settings = FirestoreSettings() + if let persistenceEnabled = pigeonApp.settings.persistenceEnabled { + var size = NSNumber(value: FirestoreCacheSizeUnlimited) + if let cacheSizeBytes = pigeonApp.settings.cacheSizeBytes, cacheSizeBytes != -1 { + size = NSNumber(value: cacheSizeBytes) + } + if persistenceEnabled { + settings.cacheSettings = PersistentCacheSettings(sizeBytes: size) + } else { + settings.cacheSettings = MemoryCacheSettings( + garbageCollectorSettings: MemoryLRUGCSettings() + ) + } + } + + if let host = pigeonApp.settings.host { + settings.host = host + if let sslEnabled = pigeonApp.settings.sslEnabled { + settings.isSSLEnabled = sslEnabled + } + } + + settings.dispatchQueue = FirebaseFirestoreReader.firestoreQueue + + let firestore = Firestore.firestore(app: app, database: pigeonApp.databaseURL) + firestore.settings = settings + FirebaseFirestoreUtils.setCachedInstance( + firestore, appName: app.name, databaseURL: pigeonApp.databaseURL + ) + return firestore + } + + private func completeOnError( + _ error: Error, + _ completion: @escaping (Result) -> Void + ) { + completion(.failure(FirebaseFirestoreUtils.flutterError(from: error))) + } + + func loadBundle( + app: FirestorePigeonFirebaseApp, bundle: FlutterStandardTypedData, + completion: @escaping (Result) -> Void + ) { + let firestore = firestore(from: app) + let identifier = registerEventChannel( + prefix: kFLTFirebaseFirestoreLoadBundleChannelName, + streamHandler: LoadBundleStreamHandler(firestore: firestore, bundle: bundle) + ) + completion(.success(identifier)) + } + + func namedQueryGet( + app: FirestorePigeonFirebaseApp, name: String, options: InternalGetOptions, + completion: @escaping (Result) -> Void + ) { + let firestore = firestore(from: app) + let source = PigeonParser.parseSource(options.source) + let serverTimestampBehavior = PigeonParser.parseServerTimestampBehavior( + options.serverTimestampBehavior + ) + + firestore.getQuery(named: name) { query in + guard let query else { + completion( + .failure( + FlutterError( + code: "non-existent-named-query", + message: + "Named query has not been found. Please check it has been loaded properly via loadBundle().", + details: nil + ) + ) + ) + return + } + query.getDocuments(source: source) { snapshot, error in + if let error { + self.completeOnError(error, completion) + } else if let snapshot { + completion( + .success( + PigeonParser.toPigeonQuerySnapshot( + snapshot, serverTimestampBehavior: serverTimestampBehavior + ) + ) + ) + } + } + } + } + + func clearPersistence( + app: FirestorePigeonFirebaseApp, + completion: @escaping (Result) -> Void + ) { + firestore(from: app).clearPersistence { error in + if let error { + self.completeOnError(error, completion) + } else { + completion(.success(())) + } + } + } + + func disableNetwork( + app: FirestorePigeonFirebaseApp, + completion: @escaping (Result) -> Void + ) { + firestore(from: app).disableNetwork { error in + if let error { + self.completeOnError(error, completion) + } else { + completion(.success(())) + } + } + } + + func enableNetwork( + app: FirestorePigeonFirebaseApp, + completion: @escaping (Result) -> Void + ) { + firestore(from: app).enableNetwork { error in + if let error { + self.completeOnError(error, completion) + } else { + completion(.success(())) + } + } + } + + func terminate( + app: FirestorePigeonFirebaseApp, + completion: @escaping (Result) -> Void + ) { + let firestore = firestore(from: app) + firestore.terminate { error in + if let error { + self.completeOnError(error, completion) + } else { + let extensionInstance = FirebaseFirestoreUtils.cachedInstance(for: firestore) + FirebaseFirestoreUtils.destroyCachedInstance( + appName: firestore.app.name, databaseURL: extensionInstance.databaseURL + ) + completion(.success(())) + } + } + } + + func waitForPendingWrites( + app: FirestorePigeonFirebaseApp, + completion: @escaping (Result) -> Void + ) { + firestore(from: app).waitForPendingWrites { error in + if let error { + self.completeOnError(error, completion) + } else { + completion(.success(())) + } + } + } + + func setIndexConfiguration( + app: FirestorePigeonFirebaseApp, indexConfiguration: String, + completion: @escaping (Result) -> Void + ) { + firestore(from: app).setIndexConfiguration(indexConfiguration) { error in + if let error { + self.completeOnError(error, completion) + } else { + completion(.success(())) + } + } + } + + func setLoggingEnabled( + loggingEnabled: Bool, + completion: @escaping (Result) -> Void + ) { + Firestore.enableLogging(loggingEnabled) + completion(.success(())) + } + + func snapshotsInSyncSetup( + app: FirestorePigeonFirebaseApp, + completion: @escaping (Result) -> Void + ) { + let firestore = firestore(from: app) + let identifier = registerEventChannel( + prefix: kFLTFirebaseFirestoreSnapshotsInSyncEventChannelName, + streamHandler: SnapshotsInSyncStreamHandler(firestore: firestore) + ) + completion(.success(identifier)) + } + + func transactionCreate( + app: FirestorePigeonFirebaseApp, timeout: Int64, maxAttempts: Int64, + completion: @escaping (Result) -> Void + ) { + let firestore = firestore(from: app) + let transactionId = UUID().uuidString.lowercased() + let handler = TransactionStreamHandler( + id: transactionId, + firestore: firestore, + timeout: Int(timeout), + maxAttempts: Int(maxAttempts), + started: { [weak self] transaction in + guard let self else { return } + self.transactionLock.lock() + self.transactions[transactionId] = transaction + self.transactionLock.unlock() + }, + ended: { [weak self] in + guard let self else { return } + self.transactionLock.lock() + self.transactions.removeValue(forKey: transactionId) + self.transactionLock.unlock() + self.unregisterEventChannel(transactionId) + } + ) + listenersLock.lock() + transactionHandlers[transactionId] = handler + listenersLock.unlock() + let identifier = registerEventChannel( + prefix: kFLTFirebaseFirestoreTransactionChannelName, + identifier: transactionId, + streamHandler: handler + ) + completion(.success(identifier)) + } + + func transactionStoreResult( + transactionId: String, resultType: InternalTransactionResult, + commands: [InternalTransactionCommand?]?, + completion: @escaping (Result) -> Void + ) { + listenersLock.lock() + let handler = transactionHandlers[transactionId] + listenersLock.unlock() + handler?.receiveTransactionResponse(resultType, commands: commands) + completion(.success(())) + } + + func transactionGet( + app: FirestorePigeonFirebaseApp, transactionId: String, path: String, + completion: @escaping (Result) -> Void + ) { + DispatchQueue.global(qos: .default).async { + let firestore = self.firestore(from: app) + let document = firestore.document(path) + + self.transactionLock.lock() + let transaction = self.transactions[transactionId] + self.transactionLock.unlock() + + guard let transaction else { + completion( + .failure( + FlutterError( + code: "missing-transaction", + message: + "An error occurred while getting the native transaction. It could be caused by a timeout in a preceding transaction operation.", + details: nil + ) + ) + ) + return + } + + do { + let snapshot = try transaction.getDocument(document) + completion( + .success( + PigeonParser.toPigeonDocumentSnapshot( + snapshot, serverTimestampBehavior: .none + ) + ) + ) + } catch { + self.completeOnError(error, completion) + } + } + } + + func documentReferenceSet( + app: FirestorePigeonFirebaseApp, request: DocumentReferenceRequest, + completion: @escaping (Result) -> Void + ) { + let document = firestore(from: app).document(request.path) + let data = request.data as? [String: Any] ?? [:] + let finish: (Error?) -> Void = { error in + if let error { + self.completeOnError(error, completion) + } else { + completion(.success(())) + } + } + + if request.option?.merge == true { + document.setData(data, merge: true, completion: finish) + } else if let mergeFields = request.option?.mergeFields { + document.setData( + data, mergeFields: PigeonParser.parseFieldPath(mergeFields), completion: finish + ) + } else { + document.setData(data, completion: finish) + } + } + + func documentReferenceUpdate( + app: FirestorePigeonFirebaseApp, request: DocumentReferenceRequest, + completion: @escaping (Result) -> Void + ) { + let document = firestore(from: app).document(request.path) + let data = request.data as? [AnyHashable: Any] ?? [:] + document.updateData(data) { error in + if let error { + self.completeOnError(error, completion) + } else { + completion(.success(())) + } + } + } + + func documentReferenceGet( + app: FirestorePigeonFirebaseApp, request: DocumentReferenceRequest, + completion: + @escaping (Result) + -> Void + ) { + let document = firestore(from: app).document(request.path) + let source = PigeonParser.parseSource(request.source ?? .serverAndCache) + let serverTimestampBehavior = PigeonParser.parseServerTimestampBehavior( + request.serverTimestampBehavior ?? .none + ) + document.getDocument(source: source) { snapshot, error in + if let error { + self.completeOnError(error, completion) + } else if let snapshot { + completion( + .success( + PigeonParser.toPigeonDocumentSnapshot( + snapshot, serverTimestampBehavior: serverTimestampBehavior + ) + ) + ) + } + } + } + + func documentReferenceDelete( + app: FirestorePigeonFirebaseApp, request: DocumentReferenceRequest, + completion: @escaping (Result) -> Void + ) { + firestore(from: app).document(request.path).delete { error in + if let error { + self.completeOnError(error, completion) + } else { + completion(.success(())) + } + } + } + + func queryGet( + app: FirestorePigeonFirebaseApp, path: String, isCollectionGroup: Bool, + parameters: InternalQueryParameters, options: InternalGetOptions, + completion: @escaping (Result) -> Void + ) { + let firestore = firestore(from: app) + guard + let query = PigeonParser.parseQuery( + parameters: parameters, firestore: firestore, path: path, + isCollectionGroup: isCollectionGroup + ) + else { + completion( + .failure( + FlutterError( + code: "error-parsing", + message: + "An error occurred while parsing query arguments, this is most likely an error with this SDK.", + details: nil + ) + ) + ) + return + } + + let source = PigeonParser.parseSource(options.source) + let serverTimestampBehavior = PigeonParser.parseServerTimestampBehavior( + options.serverTimestampBehavior + ) + query.getDocuments(source: source) { snapshot, error in + if let error { + self.completeOnError(error, completion) + } else if let snapshot { + completion( + .success( + PigeonParser.toPigeonQuerySnapshot( + snapshot, serverTimestampBehavior: serverTimestampBehavior + ) + ) + ) + } + } + } + + func aggregateQuery( + app: FirestorePigeonFirebaseApp, path: String, + parameters: InternalQueryParameters, + source: AggregateSource, queries: [AggregateQuery?], isCollectionGroup: Bool, + completion: @escaping (Result<[AggregateQueryResponse?], Error>) -> Void + ) { + let firestore = firestore(from: app) + guard + let query = PigeonParser.parseQuery( + parameters: parameters, firestore: firestore, path: path, + isCollectionGroup: isCollectionGroup + ) + else { + completion( + .failure( + FlutterError( + code: "error-parsing", + message: + "An error occurred while parsing query arguments, this is most likely an error with this SDK.", + details: nil + ) + ) + ) + return + } + + var aggregateFields: [AggregateField] = [] + for queryRequest in queries.compactMap({ $0 }) { + switch queryRequest.type { + case .count: + aggregateFields.append(AggregateField.count()) + case .sum: + if let field = queryRequest.field { + aggregateFields.append(AggregateField.sum(field)) + } + case .average: + if let field = queryRequest.field { + aggregateFields.append(AggregateField.average(field)) + } + } + } + + let firebaseAggregateQuery: FirebaseFirestore.AggregateQuery = query.aggregate( + aggregateFields + ) + firebaseAggregateQuery.getAggregation(source: .server) { snapshot, error in + if let error { + self.completeOnError(error, completion) + return + } + guard let snapshot else { + completion(.success([])) + return + } + + var responses: [AggregateQueryResponse?] = [] + for queryRequest in queries.compactMap({ $0 }) { + switch queryRequest.type { + case .count: + responses.append( + AggregateQueryResponse( + type: .count, field: nil, value: snapshot.count.doubleValue + ) + ) + case .sum: + let value = + snapshot.get(AggregateField.sum(queryRequest.field ?? "")) as? NSNumber + responses.append( + AggregateQueryResponse( + type: .sum, field: queryRequest.field, value: value?.doubleValue + ) + ) + case .average: + let value = + snapshot.get(AggregateField.average(queryRequest.field ?? "")) as? NSNumber + responses.append( + AggregateQueryResponse( + type: .average, field: queryRequest.field, value: value?.doubleValue + ) + ) + } + } + completion(.success(responses)) + } + } + + func writeBatchCommit( + app: FirestorePigeonFirebaseApp, writes: [InternalTransactionCommand?], + completion: @escaping (Result) -> Void + ) { + let firestore = firestore(from: app) + let batch = firestore.batch() + for write in writes.compactMap({ $0 }) { + let reference = firestore.document(write.path) + switch write.type { + case .get: + break + case .deleteType: + batch.deleteDocument(reference) + case .update: + if let data = write.data as? [AnyHashable: Any] { + batch.updateData(data, forDocument: reference) + } + case .set: + let data = write.data as? [String: Any] ?? [:] + if write.option?.merge == true { + batch.setData(data, forDocument: reference, merge: true) + } else if let mergeFields = write.option?.mergeFields { + batch.setData( + data, forDocument: reference, mergeFields: PigeonParser.parseFieldPath(mergeFields) + ) + } else { + batch.setData(data, forDocument: reference) + } + } + } + batch.commit { error in + if let error { + self.completeOnError(error, completion) + } else { + completion(.success(())) + } + } + } + + func querySnapshot( + app: FirestorePigeonFirebaseApp, path: String, isCollectionGroup: Bool, + parameters: InternalQueryParameters, options: InternalGetOptions, + includeMetadataChanges: Bool, source: ListenSource, + completion: @escaping (Result) -> Void + ) { + let firestore = firestore(from: app) + let query = PigeonParser.parseQuery( + parameters: parameters, firestore: firestore, path: path, isCollectionGroup: isCollectionGroup + ) + if query == nil { + completion( + .failure( + FlutterError( + code: "error-parsing", + message: + "An error occurred while parsing query arguments, this is most likely an error with this SDK.", + details: nil + ) + ) + ) + return + } + + let identifier = registerEventChannel( + prefix: kFLTFirebaseFirestoreQuerySnapshotEventChannelName, + streamHandler: QuerySnapshotStreamHandler( + firestore: firestore, + query: query, + includeMetadataChanges: includeMetadataChanges, + serverTimestampBehavior: PigeonParser.parseServerTimestampBehavior( + options.serverTimestampBehavior + ), + source: PigeonParser.parseListenSource(source) + ) + ) + completion(.success(identifier)) + } + + func documentReferenceSnapshot( + app: FirestorePigeonFirebaseApp, + parameters: DocumentReferenceRequest, + includeMetadataChanges: Bool, source: ListenSource, + completion: @escaping (Result) -> Void + ) { + let firestore = firestore(from: app) + let document = firestore.document(parameters.path) + let identifier = registerEventChannel( + prefix: kFLTFirebaseFirestoreDocumentSnapshotEventChannelName, + streamHandler: DocumentSnapshotStreamHandler( + firestore: firestore, + reference: document, + includeMetadataChanges: includeMetadataChanges, + serverTimestampBehavior: PigeonParser.parseServerTimestampBehavior( + parameters.serverTimestampBehavior ?? .none + ), + source: PigeonParser.parseListenSource(source) + ) + ) + completion(.success(identifier)) + } + + func persistenceCacheIndexManagerRequest( + app: FirestorePigeonFirebaseApp, + request: PersistenceCacheIndexManagerRequest, + completion: @escaping (Result) -> Void + ) { + if let manager = firestore(from: app).persistentCacheIndexManager { + switch request { + case .enableIndexAutoCreation: + manager.enableIndexAutoCreation() + case .disableIndexAutoCreation: + manager.disableIndexAutoCreation() + case .deleteAllIndexes: + manager.deleteAllIndexes() + } + } else { + NSLog("FLTFirebaseFirestore: `PersistentCacheIndexManager` is not available.") + } + completion(.success(())) + } + + func executePipeline( + app: FirestorePigeonFirebaseApp, stages: [[String?: Any?]?], + options: [String?: Any?]?, + completion: @escaping (Result) -> Void + ) { + let firestore = firestore(from: app) + let mappedStages: [[String: Any?]] = stages.compactMap { stage in + guard let stage else { return nil } + var mapped: [String: Any?] = [:] + for (key, value) in stage { + if let key { + mapped[key] = value + } + } + return mapped + } + var mappedOptions: [String: Any?]? + if let options { + var mapped: [String: Any?] = [:] + for (key, value) in options { + if let key { + mapped[key] = value + } + } + mappedOptions = mapped + } + + PipelineParser.executePipeline( + firestore: firestore, stages: mappedStages, options: mappedOptions + ) { snapshot, error in + if let error { + self.completeOnError(error, completion) + return + } + guard let snapshot else { + completion( + .failure( + FlutterError( + code: "error", + message: "Pipeline execution returned no result", + details: nil + ) + ) + ) + return + } + + func timestampToMs(_ value: Any?) -> Int64? { + if value == nil || value is NSNull { return nil } + if let number = value as? NSNumber { return number.int64Value } + if let timestamp = value as? Timestamp { + return timestamp.seconds * 1000 + Int64(timestamp.nanoseconds) / 1_000_000 + } + return nil + } + + var pigeonResults: [InternalPipelineResult?] = [] + if let results = (snapshot as AnyObject).value(forKey: "results") as? [Any] { + for result in results { + let object = result as AnyObject + let ref = object.value(forKey: "reference") as AnyObject? + let path = + (ref?.value(forKey: "path") as? String) + ?? (object.value(forKey: "documentID") as? String) + let data = object.value(forKey: "data") as? [String: Any] + let mappedData = PigeonParser.toPigeonMap(data) + pigeonResults.append( + InternalPipelineResult( + documentPath: path, + createTime: timestampToMs(object.value(forKey: "create_time")), + updateTime: timestampToMs(object.value(forKey: "update_time")), + data: mappedData + ) + ) + } + } + + var executionTime = timestampToMs((snapshot as AnyObject).value(forKey: "execution_time")) + if executionTime == nil { + executionTime = Int64(Date().timeIntervalSince1970 * 1000) + } + completion( + .success( + InternalPipelineSnapshot(results: pigeonResults, executionTime: executionTime ?? 0) + ) + ) + } + } +} + +private final class EventChannelCleanupHandler: NSObject, FlutterStreamHandler { + private let inner: NSObject & FlutterStreamHandler + private let onDisposed: () -> Void + + init(inner: NSObject & FlutterStreamHandler, onDisposed: @escaping () -> Void) { + self.inner = inner + self.onDisposed = onDisposed + } + + func onListen(withArguments arguments: Any?, eventSink events: @escaping FlutterEventSink) + -> FlutterError? + { + inner.onListen(withArguments: arguments, eventSink: events) + } + + func onCancel(withArguments arguments: Any?) -> FlutterError? { + let error = inner.onCancel(withArguments: arguments) + onDisposed() + return error + } +} diff --git a/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/FLTFirebaseFirestoreReader.m b/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/FLTFirebaseFirestoreReader.m deleted file mode 100644 index edfa4cba17ae..000000000000 --- a/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/FLTFirebaseFirestoreReader.m +++ /dev/null @@ -1,318 +0,0 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -@import FirebaseFirestore; -@import FirebaseCore; - -#if __has_include() -#import -#else -#import -#endif -#import "include/cloud_firestore/Private/FLTFirebaseFirestoreReader.h" -#import "include/cloud_firestore/Private/FLTFirebaseFirestoreUtils.h" - -@implementation FLTFirebaseFirestoreReader - -- (id)readValueOfType:(UInt8)type { - switch (type) { - case FirestoreDataTypeDateTime: { - SInt64 value; - [self readBytes:&value length:8]; - return [NSDate dateWithTimeIntervalSince1970:(value / 1000.0)]; - } - case FirestoreDataTypeTimestamp: { - SInt64 seconds; - int nanoseconds; - [self readBytes:&seconds length:8]; - [self readBytes:&nanoseconds length:4]; - return [[FIRTimestamp alloc] initWithSeconds:seconds nanoseconds:nanoseconds]; - } - case FirestoreDataTypeGeoPoint: { - Float64 latitude; - Float64 longitude; - [self readAlignment:8]; - [self readBytes:&latitude length:8]; - [self readBytes:&longitude length:8]; - return [[FIRGeoPoint alloc] initWithLatitude:latitude longitude:longitude]; - } - case FirestoreDataTypeVectorValue: { - return [[FIRVectorValue alloc] initWithArray:[self readValue]]; - } - case FirestoreDataTypeDocumentReference: { - FIRFirestore *firestore = [self readValue]; - NSString *documentPath = [self readValue]; - return [firestore documentWithPath:documentPath]; - } - case FirestoreDataTypeFieldPath: { - UInt32 length = [self readSize]; - NSMutableArray *array = [NSMutableArray arrayWithCapacity:length]; - for (UInt32 i = 0; i < length; i++) { - id value = [self readValue]; - [array addObject:(value == nil ? [NSNull null] : value)]; - } - return [[FIRFieldPath alloc] initWithFields:array]; - } - case FirestoreDataTypeBlob: - return [self readData:[self readSize]]; - case FirestoreDataTypeArrayUnion: - return [FIRFieldValue fieldValueForArrayUnion:[self readValue]]; - case FirestoreDataTypeArrayRemove: - return [FIRFieldValue fieldValueForArrayRemove:[self readValue]]; - case FirestoreDataTypeDelete: - return [FIRFieldValue fieldValueForDelete]; - case FirestoreDataTypeServerTimestamp: - return [FIRFieldValue fieldValueForServerTimestamp]; - case FirestoreDataTypeIncrementDouble: - return - [FIRFieldValue fieldValueForDoubleIncrement:((NSNumber *)[self readValue]).doubleValue]; - case FirestoreDataTypeIncrementInteger: - return [FIRFieldValue fieldValueForIntegerIncrement:((NSNumber *)[self readValue]).intValue]; - case FirestoreDataTypeDocumentId: - return [FIRFieldPath documentID]; - case FirestoreDataTypeFirestoreInstance: - return [self FIRFirestore]; - case FirestoreDataTypeFirestoreQuery: - return [self FIRQuery]; - case FirestoreDataTypeFirestoreSettings: - return [self FIRFirestoreSettings]; - case FirestoreDataTypeNaN: - return @(NAN); - case FirestoreDataTypeInfinity: - return @(INFINITY); - case FirestoreDataTypeNegativeInfinity: - return @(-INFINITY); - default: - return [super readValueOfType:type]; - } -} - -+ (dispatch_queue_t)getFirestoreQueue { - static dispatch_queue_t firestoreQueue; - static dispatch_once_t once; - dispatch_once(&once, ^{ - firestoreQueue = dispatch_queue_create("dev.flutter.firebase.firestore", DISPATCH_QUEUE_SERIAL); - }); - return firestoreQueue; -} - -- (FIRFirestoreSettings *)FIRFirestoreSettings { - NSDictionary *values = [self readValue]; - FIRFirestoreSettings *settings = [[FIRFirestoreSettings alloc] init]; - - if (![values[@"persistenceEnabled"] isEqual:[NSNull null]]) { - bool persistEnabled = [((NSNumber *)values[@"persistenceEnabled"]) boolValue]; - - // We default to the maximum amount of cache allowed. - NSNumber *size = @(kFIRFirestoreCacheSizeUnlimited); - - if (![values[@"cacheSizeBytes"] isEqual:[NSNull null]]) { - NSNumber *cacheSizeBytes = ((NSNumber *)values[@"cacheSizeBytes"]); - if ([cacheSizeBytes intValue] != -1) { - size = cacheSizeBytes; - } - } - - if (persistEnabled) { - settings.cacheSettings = [[FIRPersistentCacheSettings alloc] initWithSizeBytes:size]; - } else { - settings.cacheSettings = [[FIRMemoryCacheSettings alloc] - initWithGarbageCollectorSettings:[[FIRMemoryLRUGCSettings alloc] init]]; - } - } - - if (![values[@"host"] isEqual:[NSNull null]]) { - settings.host = (NSString *)values[@"host"]; - // Only allow changing ssl if host is also specified. - if (![values[@"sslEnabled"] isEqual:[NSNull null]]) { - settings.sslEnabled = [((NSNumber *)values[@"sslEnabled"]) boolValue]; - } - } - - settings.dispatchQueue = [FLTFirebaseFirestoreReader getFirestoreQueue]; - - return settings; -} - -- (FIRFilter *)filterFromJson:(NSDictionary *)map { - if (map[@"fieldPath"]) { - // Deserialize a FilterQuery - NSString *op = map[@"op"]; - FIRFieldPath *fieldPath = map[@"fieldPath"]; - id value = map[@"value"]; - - // All the operators from Firebase - if ([op isEqualToString:@"=="]) { - return [FIRFilter filterWhereFieldPath:fieldPath isEqualTo:value]; - } else if ([op isEqualToString:@"!="]) { - return [FIRFilter filterWhereFieldPath:fieldPath isNotEqualTo:value]; - } else if ([op isEqualToString:@"<"]) { - return [FIRFilter filterWhereFieldPath:fieldPath isLessThan:value]; - } else if ([op isEqualToString:@"<="]) { - return [FIRFilter filterWhereFieldPath:fieldPath isLessThanOrEqualTo:value]; - } else if ([op isEqualToString:@">"]) { - return [FIRFilter filterWhereFieldPath:fieldPath isGreaterThan:value]; - } else if ([op isEqualToString:@">="]) { - return [FIRFilter filterWhereFieldPath:fieldPath isGreaterThanOrEqualTo:value]; - } else if ([op isEqualToString:@"array-contains"]) { - return [FIRFilter filterWhereFieldPath:fieldPath arrayContains:value]; - } else if ([op isEqualToString:@"array-contains-any"]) { - return [FIRFilter filterWhereFieldPath:fieldPath arrayContainsAny:value]; - } else if ([op isEqualToString:@"in"]) { - return [FIRFilter filterWhereFieldPath:fieldPath in:value]; - } else if ([op isEqualToString:@"not-in"]) { - return [FIRFilter filterWhereFieldPath:fieldPath notIn:value]; - } else { - @throw [NSException exceptionWithName:@"InvalidOperator" - reason:@"Invalid operator" - userInfo:nil]; - } - } - // Deserialize a FilterOperator - NSString *op = map[@"op"]; - NSArray *> *queries = map[@"queries"]; - - // Map queries recursively - NSMutableArray *parsedFilters = [NSMutableArray array]; - for (NSDictionary *query in queries) { - [parsedFilters addObject:[self filterFromJson:query]]; - } - - if ([op isEqualToString:@"OR"]) { - return [FIRFilter orFilterWithFilters:parsedFilters]; - } else if ([op isEqualToString:@"AND"]) { - return [FIRFilter andFilterWithFilters:parsedFilters]; - } - - @throw [NSException exceptionWithName:@"InvalidOperator" reason:@"Invalid operator" userInfo:nil]; -} - -- (FIRQuery *)FIRQuery { - @try { - FIRQuery *query; - NSDictionary *values = [self readValue]; - FIRFirestore *firestore = values[@"firestore"]; - - NSDictionary *parameters = values[@"parameters"]; - NSArray *whereConditions = parameters[@"where"]; - BOOL isCollectionGroup = ((NSNumber *)values[@"isCollectionGroup"]).boolValue; - - if (isCollectionGroup) { - query = [firestore collectionGroupWithID:values[@"path"]]; - } else { - query = (FIRQuery *)[firestore collectionWithPath:values[@"path"]]; - } - - BOOL isFilterQuery = [parameters objectForKey:@"filters"] != nil; - if (isFilterQuery) { - FIRFilter *filter = - [self filterFromJson:(NSDictionary *)parameters[@"filters"]]; - query = [query queryWhereFilter:filter]; - } - - // Filters - for (id item in whereConditions) { - NSArray *condition = item; - FIRFieldPath *fieldPath = (FIRFieldPath *)condition[0]; - NSString *operator= condition[1]; - id value = condition[2]; - if ([operator isEqualToString:@"=="]) { - query = [query queryWhereFieldPath:fieldPath isEqualTo:value]; - } else if ([operator isEqualToString:@"!="]) { - query = [query queryWhereFieldPath:fieldPath isNotEqualTo:value]; - } else if ([operator isEqualToString:@"<"]) { - query = [query queryWhereFieldPath:fieldPath isLessThan:value]; - } else if ([operator isEqualToString:@"<="]) { - query = [query queryWhereFieldPath:fieldPath isLessThanOrEqualTo:value]; - } else if ([operator isEqualToString:@">"]) { - query = [query queryWhereFieldPath:fieldPath isGreaterThan:value]; - } else if ([operator isEqualToString:@">="]) { - query = [query queryWhereFieldPath:fieldPath isGreaterThanOrEqualTo:value]; - } else if ([operator isEqualToString:@"array-contains"]) { - query = [query queryWhereFieldPath:fieldPath arrayContains:value]; - } else if ([operator isEqualToString:@"array-contains-any"]) { - query = [query queryWhereFieldPath:fieldPath arrayContainsAny:value]; - } else if ([operator isEqualToString:@"in"]) { - query = [query queryWhereFieldPath:fieldPath in:value]; - } else if ([operator isEqualToString:@"not-in"]) { - query = [query queryWhereFieldPath:fieldPath notIn:value]; - } else { - NSLog(@"FLTFirebaseFirestore: An invalid query operator %@ was received but not handled.", - operator); - } - } - - // Limit - id limit = parameters[@"limit"]; - if (![limit isEqual:[NSNull null]]) { - query = [query queryLimitedTo:((NSNumber *)limit).intValue]; - } - - // Limit To Last - id limitToLast = parameters[@"limitToLast"]; - if (![limitToLast isEqual:[NSNull null]]) { - query = [query queryLimitedToLast:((NSNumber *)limitToLast).intValue]; - } - - // Ordering - NSArray *orderBy = parameters[@"orderBy"]; - if ([orderBy isEqual:[NSNull null]]) { - // We return early if no ordering set as cursor queries below require at least one orderBy set - return query; - } - - for (NSArray *orderByParameters in orderBy) { - FIRFieldPath *fieldPath = (FIRFieldPath *)orderByParameters[0]; - NSNumber *descending = orderByParameters[1]; - query = [query queryOrderedByFieldPath:fieldPath descending:[descending boolValue]]; - } - - // Start At - id startAt = parameters[@"startAt"]; - if (![startAt isEqual:[NSNull null]]) query = [query queryStartingAtValues:(NSArray *)startAt]; - // Start After - id startAfter = parameters[@"startAfter"]; - if (![startAfter isEqual:[NSNull null]]) - query = [query queryStartingAfterValues:(NSArray *)startAfter]; - // End At - id endAt = parameters[@"endAt"]; - if (![endAt isEqual:[NSNull null]]) query = [query queryEndingAtValues:(NSArray *)endAt]; - // End Before - id endBefore = parameters[@"endBefore"]; - if (![endBefore isEqual:[NSNull null]]) - query = [query queryEndingBeforeValues:(NSArray *)endBefore]; - - return query; - } @catch (NSException *exception) { - NSLog(@"An error occurred while parsing query arguments, this is most likely an error with " - @"this SDK. %@", - [exception callStackSymbols]); - return nil; - } -} - -- (FIRFirestore *)FIRFirestore { - @synchronized(self) { - NSString *appNameDart = [self readValue]; - NSString *databaseUrl = [self readValue]; - FIRFirestoreSettings *settings = [self readValue]; - FIRApp *app = [FLTFirebasePlugin firebaseAppNamed:appNameDart]; - - if ([FLTFirebaseFirestoreUtils getFirestoreInstanceByName:app.name - databaseURL:databaseUrl] != nil) { - return [FLTFirebaseFirestoreUtils getFirestoreInstanceByName:app.name - databaseURL:databaseUrl]; - } - - FIRFirestore *firestore = [FIRFirestore firestoreForApp:app database:databaseUrl]; - firestore.settings = settings; - - [FLTFirebaseFirestoreUtils setCachedFIRFirestoreInstance:firestore - forAppName:app.name - databaseURL:databaseUrl]; - return firestore; - } -} - -@end diff --git a/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/FLTFirebaseFirestoreUtils.m b/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/FLTFirebaseFirestoreUtils.m deleted file mode 100644 index c1e557790706..000000000000 --- a/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/FLTFirebaseFirestoreUtils.m +++ /dev/null @@ -1,263 +0,0 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -@import FirebaseFirestore; -@import FirebaseCore; - -#import "include/cloud_firestore/Private/FLTFirebaseFirestoreUtils.h" -#import "include/cloud_firestore/Private/FLTFirebaseFirestoreExtension.h" -#import "include/cloud_firestore/Private/FLTFirebaseFirestoreReader.h" -#import "include/cloud_firestore/Private/FLTFirebaseFirestoreWriter.h" - -@implementation FLTFirebaseFirestoreReaderWriter -- (FlutterStandardWriter *_Nonnull)writerWithData:(NSMutableData *)data { - return [[FLTFirebaseFirestoreWriter alloc] initWithData:data]; -} -- (FlutterStandardReader *_Nonnull)readerWithData:(NSData *)data { - return [[FLTFirebaseFirestoreReader alloc] initWithData:data]; -} -@end - -NSMutableDictionary *firestoreInstanceCache; - -const NSInteger FLTFirebaseFirestoreErrorCodePipelineParse = -1; - -@implementation FLTFirebaseFirestoreUtils - -+ (NSString *)generateKeyForAppName:(NSString *)appName andDatabaseURL:(NSString *)databaseURL { - return [NSString stringWithFormat:@"%@|%@", appName, databaseURL]; -} - -+ (FLTFirebaseFirestoreExtension *_Nullable) - getCachedFIRFirestoreInstanceForAppName:(NSString *_Nonnull)appName - databaseURL:(NSString *_Nonnull)url { - @synchronized(firestoreInstanceCache) { - if (firestoreInstanceCache == nil) { - firestoreInstanceCache = [NSMutableDictionary dictionary]; - return nil; - } else { - NSString *key = [self generateKeyForAppName:appName andDatabaseURL:url]; - return firestoreInstanceCache[key]; - } - } -} - -+ (void)setCachedFIRFirestoreInstance:(FIRFirestore *_Nonnull)firestore - forAppName:(NSString *_Nonnull)appName - databaseURL:(NSString *_Nonnull)url { - @synchronized(firestoreInstanceCache) { - if (firestoreInstanceCache == nil) { - firestoreInstanceCache = [NSMutableDictionary dictionary]; - } - NSString *key = [self generateKeyForAppName:appName andDatabaseURL:url]; - firestoreInstanceCache[key] = - [[FLTFirebaseFirestoreExtension alloc] initWithFirestoreInstance:firestore databaseURL:url]; - } -} - -+ (void)destroyCachedInstanceForFirestore:(NSString *_Nonnull)appName - databaseURL:(NSString *_Nonnull)databaseURL { - @synchronized(firestoreInstanceCache) { - if (firestoreInstanceCache != nil) { - NSString *key = [self generateKeyForAppName:appName andDatabaseURL:databaseURL]; - FLTFirebaseFirestoreExtension *extension = firestoreInstanceCache[key]; - - if (extension != nil) { - [firestoreInstanceCache removeObjectForKey:key]; - } - } - } -} - -+ (FIRFirestore *)getFirestoreInstanceByName:(NSString *)appName - databaseURL:(NSString *)databaseURL { - @synchronized(firestoreInstanceCache) { - if (firestoreInstanceCache == nil) { - firestoreInstanceCache = [NSMutableDictionary dictionary]; - } - NSString *key = [self generateKeyForAppName:appName andDatabaseURL:databaseURL]; - FLTFirebaseFirestoreExtension *extension = firestoreInstanceCache[key]; - - if (extension != nil) { - return extension.instance; - } - - return nil; - } -} - -+ (NSUInteger)count { - return [firestoreInstanceCache count]; -} - -// Require this method when we don't have access to the "databaseURL" -+ (FLTFirebaseFirestoreExtension *_Nullable)getCachedInstanceForFirestore: - (FIRFirestore *_Nonnull)firestore { - @synchronized(firestoreInstanceCache) { - if (firestoreInstanceCache != nil) { - NSEnumerator *enumerator = [firestoreInstanceCache keyEnumerator]; - NSString *key; - - while ((key = [enumerator nextObject])) { - FLTFirebaseFirestoreExtension *value = firestoreInstanceCache[key]; - - if (value.instance == firestore) { - return value; - } - } - } - @throw [NSException exceptionWithName:@"NoCachedInstance" - reason:@"No cached instance of Firestore" - userInfo:nil]; - } -} - -+ (void)cleanupFirestoreInstances:(void (^)(void))completion { - __block int instancesTerminated = 0; - NSUInteger numberOfInstances = [firestoreInstanceCache count]; - void (^firestoreTerminateInstanceCompletion)(NSError *) = ^void(NSError *error) { - instancesTerminated++; - if (instancesTerminated == numberOfInstances && completion != nil) { - completion(); - } - }; - - if (numberOfInstances > 0) { - for (NSString *key in firestoreInstanceCache) { - FLTFirebaseFirestoreExtension *firestoreExtension = firestoreInstanceCache[key]; - FIRFirestore *firestore = firestoreExtension.instance; - - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ - [firestore terminateWithCompletion:^(NSError *error) { - [FLTFirebaseFirestoreUtils - destroyCachedInstanceForFirestore:firestore.app.name - databaseURL:firestoreExtension.databaseURL]; - firestoreTerminateInstanceCompletion(error); - }]; - }); - } - } -} - -+ (FIRFirestoreSource)FIRFirestoreSourceFromArguments:(NSDictionary *)arguments { - NSString *source = arguments[@"source"]; - if ([@"server" isEqualToString:source]) { - return FIRFirestoreSourceServer; - } - - if ([@"cache" isEqualToString:source]) { - return FIRFirestoreSourceCache; - } - - return FIRFirestoreSourceDefault; -} - -+ (NSArray *)ErrorCodeAndMessageFromNSError:(NSError *)error { - NSString *code = @"unknown"; - - if (error == nil) { - return @[ code, @"An unknown error has occurred." ]; - } - - NSString *message; - - switch (error.code) { - case FIRFirestoreErrorCodeAborted: - code = @"aborted"; - message = @"The operation was aborted, typically due to a concurrency issue like transaction " - @"aborts, etc."; - break; - case FIRFirestoreErrorCodeAlreadyExists: - code = @"already-exists"; - message = @"Some document that we attempted to create already exists."; - break; - case FIRFirestoreErrorCodeCancelled: - code = @"cancelled"; - message = @"The operation was cancelled (typically by the caller)."; - break; - case FIRFirestoreErrorCodeDataLoss: - code = @"data-loss"; - message = @"Unrecoverable data loss or corruption."; - break; - case FIRFirestoreErrorCodeDeadlineExceeded: - code = @"deadline-exceeded"; - message = @"Deadline expired before operation could complete. For operations that change the " - @"state of the system, this error may be returned even if the operation has " - @"completed successfully. For example, a successful response from a server could " - @"have been delayed long enough for the deadline to expire."; - break; - case FIRFirestoreErrorCodeFailedPrecondition: - code = @"failed-precondition"; - if ([error.localizedDescription containsString:@"index"]) { - message = error.localizedDescription; - } else { - message = @"Operation was rejected because the system is not in a state required for the " - @"operation's execution. If performing a query, ensure it has been indexed via " - @"the Firebase console."; - } - break; - case FIRFirestoreErrorCodeInternal: - code = @"internal"; - message = @"Internal errors. Means some invariants expected by underlying system has been " - @"broken. If you see one of these errors, something is very broken."; - break; - case FIRFirestoreErrorCodeInvalidArgument: - code = @"invalid-argument"; - message = @"Client specified an invalid argument. Note that this differs from " - @"failed-precondition. invalid-argument indicates arguments that are problematic " - @"regardless of the state of the system (e.g., an invalid field name)."; - break; - case FIRFirestoreErrorCodeNotFound: - code = @"not-found"; - message = @"Some requested document was not found."; - break; - case FIRFirestoreErrorCodeOutOfRange: - code = @"out-of-range"; - message = @"Operation was attempted past the valid range."; - break; - case FIRFirestoreErrorCodePermissionDenied: - code = @"permission-denied"; - message = @"The caller does not have permission to execute the specified operation."; - break; - case FIRFirestoreErrorCodeResourceExhausted: - code = @"resource-exhausted"; - message = @"Some resource has been exhausted, perhaps a per-user quota, or perhaps the " - @"entire file system is out of space."; - break; - case FIRFirestoreErrorCodeUnauthenticated: - code = @"unauthenticated"; - message = @"The request does not have valid authentication credentials for the operation."; - break; - case FIRFirestoreErrorCodeUnavailable: - code = @"unavailable"; - message = @"The service is currently unavailable. This is a most likely a transient " - @"condition and may be corrected by retrying with a backoff."; - break; - case FIRFirestoreErrorCodeUnimplemented: - code = @"unimplemented"; - message = @"Operation is not implemented or not supported/enabled."; - break; - case FIRFirestoreErrorCodeUnknown: - code = @"unknown"; - message = @"Unknown error or an error from a different error domain."; - break; - case FLTFirebaseFirestoreErrorCodePipelineParse: - code = @"parse-error"; - message = (error.localizedDescription.length > 0) ? error.localizedDescription - : @"An unknown error occurred."; - break; - default: - code = @"unknown"; - message = @"An unknown error occurred."; - break; - } - - if (error.localizedDescription.length > 0) { - message = error.localizedDescription; - } - - return @[ code, message ]; -} - -@end diff --git a/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/FLTFirebaseFirestoreWriter.m b/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/FLTFirebaseFirestoreWriter.m deleted file mode 100644 index cdcd84ae3b78..000000000000 --- a/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/FLTFirebaseFirestoreWriter.m +++ /dev/null @@ -1,259 +0,0 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -@import FirebaseFirestore; -@import FirebaseCore; - -#import "include/cloud_firestore/Private/FLTFirebaseFirestoreWriter.h" -#import "include/cloud_firestore/Private/FLTFirebaseFirestoreUtils.h" -#import "include/cloud_firestore/Public/FLTFirebaseFirestorePlugin.h" - -static const UInt8 FLTStandardFieldList = 12; -static const UInt8 FLTStandardFieldMap = 13; - -@implementation FLTFirebaseFirestoreWriter : FlutterStandardWriter -- (void)writeValue:(id)value { - if ([value isKindOfClass:[NSDate class]]) { - [self writeByte:FirestoreDataTypeDateTime]; - NSDate *date = value; - NSTimeInterval time = date.timeIntervalSince1970; - SInt64 ms = (SInt64)(time * 1000.0); - [self writeBytes:&ms length:8]; - } else if ([value isKindOfClass:[FIRTimestamp class]]) { - FIRTimestamp *timestamp = value; - SInt64 seconds = timestamp.seconds; - int nanoseconds = timestamp.nanoseconds; - [self writeByte:FirestoreDataTypeTimestamp]; - [self writeBytes:(UInt8 *)&seconds length:8]; - [self writeBytes:(UInt8 *)&nanoseconds length:4]; - } else if ([value isKindOfClass:[FIRGeoPoint class]]) { - FIRGeoPoint *geoPoint = value; - Float64 latitude = geoPoint.latitude; - Float64 longitude = geoPoint.longitude; - [self writeByte:FirestoreDataTypeGeoPoint]; - [self writeAlignment:8]; - [self writeBytes:(UInt8 *)&latitude length:8]; - [self writeBytes:(UInt8 *)&longitude length:8]; - } else if ([value isKindOfClass:[FIRVectorValue class]]) { - FIRVectorValue *vector = value; - [self writeByte:FirestoreDataTypeVectorValue]; - [self writeValue:vector.array]; - } else if ([value isKindOfClass:[FIRDocumentReference class]]) { - FIRDocumentReference *document = value; - NSString *documentPath = [document path]; - NSString *appName = [FLTFirebasePlugin firebaseAppNameFromIosName:document.firestore.app.name]; - [self writeByte:FirestoreDataTypeDocumentReference]; - [self writeValue:appName]; - [self writeValue:documentPath]; - - FIRFirestore *firestore = document.firestore; - - FLTFirebaseFirestoreExtension *extension = - [FLTFirebaseFirestoreUtils getCachedInstanceForFirestore:firestore]; - [self writeValue:extension.databaseURL]; - - } else if ([value isKindOfClass:[FIRDocumentSnapshot class]]) { - [self writeValue:[self FIRDocumentSnapshot:value]]; - } else if ([value isKindOfClass:[FIRLoadBundleTaskProgress class]]) { - [self writeValue:[self FIRLoadBundleTaskProgress:value]]; - } else if ([value isKindOfClass:[FIRQuerySnapshot class]]) { - [self writeValue:[self FIRQuerySnapshot:value]]; - } else if ([value isKindOfClass:[FIRDocumentChange class]]) { - [self writeValue:[self FIRDocumentChange:value]]; - } else if ([value isKindOfClass:[FIRSnapshotMetadata class]]) { - [self writeValue:[self FIRSnapshotMetadata:value]]; - } else if ([value isKindOfClass:[NSArray class]]) { - NSArray *list = value; - [self writeByte:FLTStandardFieldList]; - [self writeSize:(UInt32)list.count]; - for (id item in list) { - [self writeValue:item]; - } - } else if ([value isKindOfClass:[NSDictionary class]]) { - NSDictionary *map = value; - [self writeByte:FLTStandardFieldMap]; - [self writeSize:(UInt32)map.count]; - for (id key in map) { - [self writeValue:key]; - [self writeValue:map[key]]; - } - } else if ([value isKindOfClass:[NSNumber class]]) { - NSNumber *number = (NSNumber *)value; - - // Infinity - if ([number isEqual:@(INFINITY)]) { - [self writeByte:FirestoreDataTypeInfinity]; - return; - } - - // -Infinity - if ([number isEqual:@(-INFINITY)]) { - [self writeByte:FirestoreDataTypeNegativeInfinity]; - return; - } - - // NaN - if ([[value description].lowercaseString isEqual:@"nan"]) { - [self writeByte:FirestoreDataTypeNaN]; - return; - } - - [super writeValue:value]; - } else if ([value isKindOfClass:[NSData class]]) { - NSData *blob = value; - [self writeByte:FirestoreDataTypeBlob]; - [self writeSize:(UInt32)blob.length]; - [self writeData:blob]; - } else { - [super writeValue:value]; - } -} - -- (NSDictionary *)FIRSnapshotMetadata:(FIRSnapshotMetadata *)snapshotMetadata { - return @{ - @"hasPendingWrites" : @(snapshotMetadata.hasPendingWrites), - @"isFromCache" : @(snapshotMetadata.isFromCache), - }; -} - -- (NSDictionary *)FIRDocumentChange:(FIRDocumentChange *)documentChange { - NSString *type; - - switch (documentChange.type) { - case FIRDocumentChangeTypeAdded: - type = @"DocumentChangeType.added"; - break; - case FIRDocumentChangeTypeModified: - type = @"DocumentChangeType.modified"; - break; - case FIRDocumentChangeTypeRemoved: - type = @"DocumentChangeType.removed"; - break; - } - - NSNumber *oldIndex; - NSNumber *newIndex; - - // Note the Firestore C++ SDK here returns a maxed UInt that is != NSUIntegerMax, so we make one - // ourselves so we can convert to -1 for Dart. - NSUInteger MAX_VAL = (NSUInteger)[@(-1) integerValue]; - - if (documentChange.newIndex == NSNotFound || documentChange.newIndex == 4294967295 || - documentChange.newIndex == MAX_VAL) { - newIndex = @([@(-1) intValue]); - } else { - newIndex = @([@(documentChange.newIndex) intValue]); - } - - if (documentChange.oldIndex == NSNotFound || documentChange.oldIndex == 4294967295 || - documentChange.oldIndex == MAX_VAL) { - oldIndex = @([@(-1) intValue]); - } else { - oldIndex = @([@(documentChange.oldIndex) intValue]); - } - - return @{ - @"type" : type, - @"data" : documentChange.document.data, - @"path" : documentChange.document.reference.path, - @"oldIndex" : oldIndex, - @"newIndex" : newIndex, - @"metadata" : documentChange.document.metadata, - }; -} - -- (FIRServerTimestampBehavior)toServerTimestampBehavior:(NSString *)serverTimestampBehavior { - if (serverTimestampBehavior == nil) { - return FIRServerTimestampBehaviorNone; - } - - if ([serverTimestampBehavior isEqualToString:@"estimate"]) { - return FIRServerTimestampBehaviorEstimate; - } else if ([serverTimestampBehavior isEqualToString:@"previous"]) { - return FIRServerTimestampBehaviorPrevious; - } else { - return FIRServerTimestampBehaviorNone; - } -} - -- (NSDictionary *)FIRDocumentSnapshot:(FIRDocumentSnapshot *)documentSnapshot { - if (documentSnapshot == nil) { - NSLog(@"Error: documentSnapshot is nil"); - return nil; - } - - NSNumber *documentSnapshotHash = @([documentSnapshot hash]); - NSString *timestampBehaviorString = - [FLTFirebaseFirestorePlugin.serverTimestampMap objectForKey:documentSnapshotHash]; - - FIRServerTimestampBehavior serverTimestampBehavior = - [self toServerTimestampBehavior:timestampBehaviorString]; - - [FLTFirebaseFirestorePlugin.serverTimestampMap removeObjectForKey:documentSnapshotHash]; - - return @{ - @"path" : documentSnapshot.reference.path, - @"data" : documentSnapshot.exists - ? (id)[documentSnapshot dataWithServerTimestampBehavior:serverTimestampBehavior] - : [NSNull null], - @"metadata" : documentSnapshot.metadata, - }; -} -- (NSDictionary *)FIRLoadBundleTaskProgress:(FIRLoadBundleTaskProgress *)progress { - NSString *state; - - switch (progress.state) { - case FIRLoadBundleTaskStateError: - state = @"error"; - break; - case FIRLoadBundleTaskStateSuccess: - state = @"success"; - break; - case FIRLoadBundleTaskStateInProgress: - state = @"running"; - break; - } - return @{ - @"bytesLoaded" : @(progress.bytesLoaded), - @"documentsLoaded" : @(progress.documentsLoaded), - @"totalBytes" : @(progress.totalBytes), - @"totalDocuments" : @(progress.totalDocuments), - @"taskState" : state, - }; -} - -- (NSDictionary *)FIRQuerySnapshot:(FIRQuerySnapshot *)querySnapshot { - if (querySnapshot == nil) { - NSLog(@"Error: querySnapshot is nil"); - return nil; - } - - NSNumber *querySnapshotHash = @([querySnapshot hash]); - - NSMutableArray *paths = [NSMutableArray array]; - NSMutableArray *documents = [NSMutableArray array]; - NSMutableArray *metadatas = [NSMutableArray array]; - NSString *timestampBehaviorString = - [FLTFirebaseFirestorePlugin.serverTimestampMap objectForKey:querySnapshotHash]; - - FIRServerTimestampBehavior serverTimestampBehavior = - [self toServerTimestampBehavior:timestampBehaviorString]; - - [FLTFirebaseFirestorePlugin.serverTimestampMap removeObjectForKey:querySnapshotHash]; - - for (FIRDocumentSnapshot *document in querySnapshot.documents) { - [paths addObject:document.reference.path]; - [documents addObject:[document dataWithServerTimestampBehavior:serverTimestampBehavior]]; - [metadatas addObject:document.metadata]; - } - - return @{ - @"paths" : paths, - @"documentChanges" : querySnapshot.documentChanges, - @"documents" : documents, - @"metadatas" : metadatas, - @"metadata" : querySnapshot.metadata, - }; -} -@end diff --git a/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/FLTLoadBundleStreamHandler.m b/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/FLTLoadBundleStreamHandler.m deleted file mode 100644 index cc8bd9be9ae2..000000000000 --- a/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/FLTLoadBundleStreamHandler.m +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright 2022, the Chromium project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -// -// FLTLoadBundleStreamHandler.m -// cloud_firestore -// -// Created by Russell Wheatley on 05/05/2021. -// - -@import FirebaseFirestore; -#if __has_include() -#import -#else -#import -#endif - -#import "include/cloud_firestore/Private/FLTFirebaseFirestoreUtils.h" -#import "include/cloud_firestore/Private/FLTLoadBundleStreamHandler.h" - -@interface FLTLoadBundleStreamHandler () -@property(readwrite, strong) FIRLoadBundleTask *task; -@end - -@implementation FLTLoadBundleStreamHandler - -- (nonnull instancetype)initWithFirestore:(nonnull FIRFirestore *)firestore - bundle:(FlutterStandardTypedData *)bundle { - self = [super init]; - if (self) { - _firestore = firestore; - _bundle = bundle; - } - return self; -} - -- (FlutterError *_Nullable)onListenWithArguments:(id _Nullable)arguments - eventSink:(nonnull FlutterEventSink)events { - // use completion handler to inform user of platform error. - self.task = [_firestore - loadBundle:_bundle.data - completion:^(FIRLoadBundleTaskProgress *_Nullable snapshot, NSError *_Nullable error) { - if (error != nil) { - NSArray *codeAndMessage = - [FLTFirebaseFirestoreUtils ErrorCodeAndMessageFromNSError:error]; - NSString *code = codeAndMessage[0]; - NSString *message = codeAndMessage[1]; - NSDictionary *details = @{ - @"code" : code, - @"message" : message, - }; - - dispatch_async(dispatch_get_main_queue(), ^{ - events([FLTFirebasePlugin createFlutterErrorFromCode:code - message:message - optionalDetails:details - andOptionalNSError:error]); - }); - } - }]; - // use addObserver to update user with snapshot progress - [self.task addObserver:^(FIRLoadBundleTaskProgress *_Nullable progress) { - dispatch_async(dispatch_get_main_queue(), ^{ - if (progress.state != FIRLoadBundleTaskStateError) { - events(progress); - } - }); - }]; - - return nil; -} - -- (FlutterError *_Nullable)onCancelWithArguments:(id _Nullable)arguments { - [self.task removeAllObservers]; - self.task = nil; - - return nil; -} -@end diff --git a/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/FLTPipelineParser.m b/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/FLTPipelineParser.m deleted file mode 100644 index ed2838214342..000000000000 --- a/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/FLTPipelineParser.m +++ /dev/null @@ -1,1772 +0,0 @@ -/* - * Copyright 2026, the Chromium project authors. Please see the AUTHORS file - * for details. All rights reserved. Use of this source code is governed by a - * BSD-style license that can be found in the LICENSE file. - */ - -#import "include/cloud_firestore/Private/FLTPipelineParser.h" -#import "include/cloud_firestore/Private/FLTFirebaseFirestoreUtils.h" - -#if TARGET_OS_OSX -#import -#import "FirebaseFirestoreInternal/FIRPipelineBridge.h" -#else -@import FirebaseFirestore; -#if __has_include("FirebaseFirestoreInternal/FIRPipelineBridge.h") -#import "FirebaseFirestoreInternal/FIRPipelineBridge.h" -#elif __has_include("FIRPipelineBridge.h") -#import "FIRPipelineBridge.h" -#endif -#endif - -#if __has_include("FirebaseFirestoreInternal/FIRVectorValue.h") -#import "FirebaseFirestoreInternal/FIRVectorValue.h" -#elif __has_include() -#import -#endif - -#import - -static NSString *const kPipelineNotAvailable = - @"Pipeline API is not available. Firestore Pipelines require Firebase iOS SDK with pipeline " - "support."; - -static NSError *pipelineUnavailableError(void) { - return [NSError errorWithDomain:@"FLTFirebaseFirestore" - code:FLTFirebaseFirestoreErrorCodePipelineParse - userInfo:@{NSLocalizedDescriptionKey : kPipelineNotAvailable}]; -} - -#if TARGET_OS_OSX -#if __has_include("FirebaseFirestoreInternal/FIRPipelineBridge.h") -#define FLT_PIPELINE_AVAILABLE 1 -#endif -#else -#if __has_include("FirebaseFirestoreInternal/FIRPipelineBridge.h") || \ - __has_include("FIRPipelineBridge.h") -#define FLT_PIPELINE_AVAILABLE 1 -#endif -#endif - -#if FLT_PIPELINE_AVAILABLE - -// Firebase iOS SDK versions differ: some expose initWithName:Args:Options:, others -// initWithName:Args:. -@interface FIRFunctionExprBridge (FLTSDKCompat) -- (instancetype)initWithName:(NSString *)name - Args:(NSArray *)args - Options:(NSDictionary *)options; -- (instancetype)initWithName:(NSString *)name Args:(NSArray *)args; -@end - -static FIRFunctionExprBridge *FLTNewFunctionExprBridge(NSString *name, - NSArray *args) { - FIRFunctionExprBridge *obj = [FIRFunctionExprBridge alloc]; - if ([obj respondsToSelector:@selector(initWithName:Args:Options:)]) { - return [obj initWithName:name Args:args Options:nil]; - } - return [obj initWithName:name Args:args]; -} - -static NSError *parseError(NSString *message) { - return [NSError errorWithDomain:@"FLTFirebaseFirestore" - code:FLTFirebaseFirestoreErrorCodePipelineParse - userInfo:@{NSLocalizedDescriptionKey : message}]; -} - -@interface FLTPipelineExpressionParser : NSObject -@property(nonatomic, strong) FIRFirestore *firestore; -- (instancetype)initWithFirestore:(FIRFirestore *)firestore; -- (FIRExprBridge *)parseExpression:(NSDictionary *)map error:(NSError **)error; -- (FIRExprBridge *)parseBooleanExpression:(NSDictionary *)map - error:(NSError **)error; -- (FIRExprBridge *)rightExprFromValue:(id)value error:(NSError **)error; -@end - -@implementation FLTPipelineExpressionParser - -- (instancetype)initWithFirestore:(FIRFirestore *)firestore { - self = [super init]; - if (self) { - _firestore = firestore; - } - return self; -} - -- (FIRExprBridge *)parseExpression:(NSDictionary *)map error:(NSError **)error { - NSString *name = map[@"name"]; - if (!name) { - NSDictionary *args = map[@"args"]; - if ([args isKindOfClass:[NSDictionary class]] && args[@"field"]) { - return [[FIRFieldBridge alloc] initWithName:args[@"field"]]; - } - if (error) *error = parseError(@"Expression must have a 'name' field"); - return nil; - } - - NSDictionary *args = map[@"args"]; - if (![args isKindOfClass:[NSDictionary class]]) args = @{}; - - if ([name isEqualToString:@"field"]) { - NSString *field = args[@"field"]; - if (!field) { - if (error) *error = parseError(@"Field expression requires 'field' argument"); - return nil; - } - return [[FIRFieldBridge alloc] initWithName:field]; - } - - if ([name isEqualToString:@"constant"]) { - id value = args[@"value"]; - if (value == nil) { - if (error) *error = parseError(@"Constant requires 'value' argument"); - return nil; - } - if ([value isKindOfClass:[NSDictionary class]]) { - NSString *path = ((NSDictionary *)value)[@"path"]; - if ([path isKindOfClass:[NSString class]] && self.firestore) { - FIRDocumentReference *docRef = [self.firestore documentWithPath:path]; - return [[FIRConstantBridge alloc] init:docRef]; - } - } - return [[FIRConstantBridge alloc] init:value]; - } - - if ([name isEqualToString:@"alias"]) { - id exprMap = args[@"expression"]; - if (![exprMap isKindOfClass:[NSDictionary class]]) { - if (error) *error = parseError(@"Alias requires 'expression'"); - return nil; - } - // No explicit AliasedExpression type in ObjC; aliases are dict keys when building stages. - // Parse and return the inner expression; the caller uses args[@"alias"] as the dict key. - return [self parseExpression:exprMap error:error]; - } - - if ([name isEqualToString:@"null"]) { - return [[FIRConstantBridge alloc] init:[NSNull null]]; - } - - if ([name isEqualToString:@"document_id_from_ref"]) { - NSString *path = args[@"doc_ref"]; - if (![path isKindOfClass:[NSString class]] || path.length == 0) { - if (error) *error = parseError(@"document_id_from_ref requires doc_ref path"); - return nil; - } - if (!self.firestore) { - if (error) *error = parseError(@"document_id_from_ref requires firestore"); - return nil; - } - FIRDocumentReference *docRef = [self.firestore documentWithPath:path]; - FIRExprBridge *refExpr = [[FIRConstantBridge alloc] init:docRef]; - return FLTNewFunctionExprBridge(@"document_id", @[ refExpr ]); - } - - // Swift asBoolean() is a type coercion, not a pipeline function named "as_boolean". - // Dart still sends as_boolean + expression; unwrap to the inner FIRExprBridge. - if ([name isEqualToString:@"as_boolean"]) { - id exprMap = args[@"expression"]; - if (![exprMap isKindOfClass:[NSDictionary class]]) { - if (error) *error = parseError(@"as_boolean requires expression"); - return nil; - } - return [self parseExpression:(NSDictionary *)exprMap error:error]; - } - - if ([name isEqualToString:@"document_matches"]) { - NSString *query = args[@"query"]; - if (![query isKindOfClass:[NSString class]]) { - if (error) *error = parseError(@"document_matches requires query"); - return nil; - } - FIRExprBridge *queryExpr = [[FIRConstantBridge alloc] init:query]; - return FLTNewFunctionExprBridge(@"document_matches", @[ queryExpr ]); - } - - // Map Dart names to iOS SDK names where they differ - NSString *sdkName = name; - if ([name isEqualToString:@"bit_xor"]) sdkName = @"xor"; - if ([name isEqualToString:@"modulo"]) sdkName = @"mod"; - - // ------------------------------------------------------------------------- - // Binary expressions (left + right): comparisons, arithmetic, bitwise - // ------------------------------------------------------------------------- - static NSArray *binaryNames = nil; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - binaryNames = @[ - @"equal", @"not_equal", @"greater_than", @"greater_than_or_equal", @"less_than", - @"less_than_or_equal", @"add", @"subtract", @"multiply", @"divide", @"mod", @"bit_and", - @"bit_or", @"bit_left_shift", @"bit_right_shift" - ]; - }); - if ([binaryNames containsObject:sdkName] || [name isEqualToString:@"bit_xor"]) { - id leftMap = args[@"left"]; - id rightMap = args[@"right"]; - if (![leftMap isKindOfClass:[NSDictionary class]] || - ![rightMap isKindOfClass:[NSDictionary class]]) { - if (error) - *error = - parseError([NSString stringWithFormat:@"%@ requires left and right expressions", name]); - return nil; - } - FIRExprBridge *left = [self parseExpression:leftMap error:error]; - FIRExprBridge *right = [self parseExpression:rightMap error:error]; - if (!left || !right) return nil; - return FLTNewFunctionExprBridge(sdkName, @[ left, right ]); - } - - // ------------------------------------------------------------------------- - // Unary expressions (single expression): exists, is_error, is_absent, not - // (as_boolean is handled above — unwrap only, not a pipeline function.) - // ------------------------------------------------------------------------- - NSArray *unaryNames = @[ @"exists", @"is_error", @"is_absent", @"not" ]; - if ([unaryNames containsObject:name]) { - id exprMap = args[@"expression"]; - if (![exprMap isKindOfClass:[NSDictionary class]]) { - if (error) *error = parseError([NSString stringWithFormat:@"%@ requires expression", name]); - return nil; - } - FIRExprBridge *expr = [name isEqualToString:@"not"] - ? [self parseBooleanExpression:exprMap error:error] - : [self parseExpression:exprMap error:error]; - if (!expr) return nil; - return FLTNewFunctionExprBridge(name, @[ expr ]); - } - - // ------------------------------------------------------------------------- - // Unary with optional SDK name mapping: length, to_lower, to_upper, trim, - // abs, array_length, array_reverse, bit_not, document_id, collection_id - // ------------------------------------------------------------------------- - NSArray *unaryWithSdkName = @[ - @"length", @"to_lower_case", @"to_upper_case", @"trim", @"abs", @"array_length", - @"array_reverse", @"bit_not", @"document_id", @"collection_id" - ]; - if ([unaryWithSdkName containsObject:name]) { - id exprMap = args[@"expression"]; - if (![exprMap isKindOfClass:[NSDictionary class]]) { - if (error) *error = parseError([NSString stringWithFormat:@"%@ requires expression", name]); - return nil; - } - FIRExprBridge *expr = [self parseExpression:exprMap error:error]; - if (!expr) return nil; - NSString *unarySdkName = name; - if ([name isEqualToString:@"to_lower_case"]) unarySdkName = @"to_lower"; - if ([name isEqualToString:@"to_upper_case"]) unarySdkName = @"to_upper"; - return FLTNewFunctionExprBridge(unarySdkName, @[ expr ]); - } - - // ------------------------------------------------------------------------- - // N-ary logical (expressions array): and, or, xor, nor - // ------------------------------------------------------------------------- - if ([name isEqualToString:@"and"] || [name isEqualToString:@"or"] || - [name isEqualToString:@"xor"] || [name isEqualToString:@"nor"]) { - NSArray *exprMaps = args[@"expressions"]; - if (![exprMaps isKindOfClass:[NSArray class]] || exprMaps.count == 0) { - if (error) - *error = - parseError([NSString stringWithFormat:@"%@ requires at least one expression", name]); - return nil; - } - NSMutableArray *all = [NSMutableArray array]; - for (id em in exprMaps) { - if (![em isKindOfClass:[NSDictionary class]]) continue; - FIRExprBridge *e = [self parseBooleanExpression:em error:error]; - if (!e) return nil; - [all addObject:e]; - } - if (all.count == 0) { - if (error) - *error = - parseError([NSString stringWithFormat:@"%@ requires at least one expression", name]); - return nil; - } - return FLTNewFunctionExprBridge(name, all); - } - - // ------------------------------------------------------------------------- - // ------------------------------------------------------------------------- - if ([name isEqualToString:@"equal_any"] || [name isEqualToString:@"not_equal_any"]) { - id valueMap = args[@"value"]; - NSArray *valuesMaps = args[@"values"]; - if (![valueMap isKindOfClass:[NSDictionary class]] || - ![valuesMaps isKindOfClass:[NSArray class]] || valuesMaps.count == 0) { - if (error) - *error = - parseError([NSString stringWithFormat:@"%@ requires value and non-empty values", name]); - return nil; - } - FIRExprBridge *valueExpr = [self parseExpression:valueMap error:error]; - if (!valueExpr) return nil; - NSMutableArray *valueExprs = [NSMutableArray array]; - for (id vm in valuesMaps) { - if (![vm isKindOfClass:[NSDictionary class]]) continue; - FIRExprBridge *ve = [self parseExpression:vm error:error]; - if (!ve) return nil; - [valueExprs addObject:ve]; - } - if (valueExprs.count == 0) { - if (error) - *error = parseError([NSString stringWithFormat:@"%@ requires at least one value", name]); - return nil; - } - FIRExprBridge *valuesArrayExpr = FLTNewFunctionExprBridge(@"array", valueExprs); - return FLTNewFunctionExprBridge(name, @[ valueExpr, valuesArrayExpr ]); - } - - // ------------------------------------------------------------------------- - // array + element: array_contains - // ------------------------------------------------------------------------- - if ([name isEqualToString:@"array_contains"]) { - id arrayMap = args[@"array"]; - id elementMap = args[@"element"]; - if (![arrayMap isKindOfClass:[NSDictionary class]] || - ![elementMap isKindOfClass:[NSDictionary class]]) { - if (error) *error = parseError(@"array_contains requires array and element"); - return nil; - } - FIRExprBridge *arrayExpr = [self parseExpression:arrayMap error:error]; - FIRExprBridge *elementExpr = [self parseExpression:elementMap error:error]; - if (!arrayExpr || !elementExpr) return nil; - return FLTNewFunctionExprBridge(name, @[ arrayExpr, elementExpr ]); - } - - // ------------------------------------------------------------------------- - // array + values[]: array_contains_all, array_contains_any - // SDK expects: array_contains_any(field, array(val1, val2, ...)) — two args. - // Reuse the "array" expression parser to build the values array. - // ------------------------------------------------------------------------- - if ([name isEqualToString:@"array_contains_all"] || - [name isEqualToString:@"array_contains_any"]) { - id arrayMap = args[@"array"]; - if (![arrayMap isKindOfClass:[NSDictionary class]]) { - if (error) *error = parseError([NSString stringWithFormat:@"%@ requires array", name]); - return nil; - } - FIRExprBridge *arrayExpr = [self parseExpression:arrayMap error:error]; - if (!arrayExpr) return nil; - - NSArray *valuesMaps = args[@"values"]; - if (![valuesMaps isKindOfClass:[NSArray class]]) valuesMaps = args[@"elements"]; - BOOL hasValues = [valuesMaps isKindOfClass:[NSArray class]] && valuesMaps.count > 0; - - if (hasValues) { - NSDictionary *arrayExprMap = @{@"name" : @"array", @"args" : @{@"elements" : valuesMaps}}; - FIRExprBridge *valuesArrayExpr = [self parseExpression:arrayExprMap error:error]; - if (!valuesArrayExpr) return nil; - return FLTNewFunctionExprBridge(name, @[ arrayExpr, valuesArrayExpr ]); - } - - if ([name isEqualToString:@"array_contains_all"]) { - id arrayExpressionMap = args[@"array_expression"]; - if ([arrayExpressionMap isKindOfClass:[NSDictionary class]]) { - FIRExprBridge *requiredArrayExpr = [self parseExpression:arrayExpressionMap error:error]; - if (!requiredArrayExpr) return nil; - return FLTNewFunctionExprBridge(name, @[ arrayExpr, requiredArrayExpr ]); - } - } - - if (error) - *error = parseError([NSString - stringWithFormat: - @"%@ requires array and values/elements, or array_contains_all with array_expression", - name]); - return nil; - } - - // ------------------------------------------------------------------------- - // expressions[]: concat (SDK: concat) - // ------------------------------------------------------------------------- - if ([name isEqualToString:@"concat"]) { - NSArray *exprMaps = args[@"expressions"]; - if (![exprMaps isKindOfClass:[NSArray class]] || exprMaps.count == 0) { - if (error) *error = parseError(@"concat requires non-empty expressions"); - return nil; - } - NSMutableArray *all = [NSMutableArray array]; - for (id em in exprMaps) { - if (![em isKindOfClass:[NSDictionary class]]) continue; - FIRExprBridge *e = [self parseExpression:em error:error]; - if (!e) return nil; - [all addObject:e]; - } - if (all.count == 0) { - if (error) *error = parseError(@"concat requires at least one expression"); - return nil; - } - return FLTNewFunctionExprBridge(@"concat", all); - } - - // ------------------------------------------------------------------------- - // expression + start + end: substring (SDK: substring) - // ------------------------------------------------------------------------- - if ([name isEqualToString:@"substring"]) { - id exprMap = args[@"expression"]; - id startMap = args[@"start"]; - id endMap = args[@"end"]; - if (![exprMap isKindOfClass:[NSDictionary class]] || - ![startMap isKindOfClass:[NSDictionary class]] || - ![endMap isKindOfClass:[NSDictionary class]]) { - if (error) *error = parseError(@"substring requires expression, start, and end"); - return nil; - } - FIRExprBridge *expr = [self parseExpression:exprMap error:error]; - FIRExprBridge *start = [self parseExpression:startMap error:error]; - FIRExprBridge *end = [self parseExpression:endMap error:error]; - if (!expr || !start || !end) return nil; - return FLTNewFunctionExprBridge(@"substring", @[ expr, start, end ]); - } - - // ------------------------------------------------------------------------- - // expression + find + replacement: replace (SDK: string_replace) - // ------------------------------------------------------------------------- - if ([name isEqualToString:@"replace"]) { - id exprMap = args[@"expression"]; - id findMap = args[@"find"]; - id replacementMap = args[@"replacement"]; - if (![exprMap isKindOfClass:[NSDictionary class]] || - ![findMap isKindOfClass:[NSDictionary class]] || - ![replacementMap isKindOfClass:[NSDictionary class]]) { - if (error) *error = parseError(@"replace requires expression, find, and replacement"); - return nil; - } - FIRExprBridge *expr = [self parseExpression:exprMap error:error]; - FIRExprBridge *find = [self parseExpression:findMap error:error]; - FIRExprBridge *replacement = [self parseExpression:replacementMap error:error]; - if (!expr || !find || !replacement) return nil; - return FLTNewFunctionExprBridge(@"string_replace", @[ expr, find, replacement ]); - } - - // ------------------------------------------------------------------------- - // expression + find + replacement: string_replace_one / string_replace_all - // ------------------------------------------------------------------------- - if ([name isEqualToString:@"string_replace_one"] || - [name isEqualToString:@"string_replace_all"]) { - id exprMap = args[@"expression"]; - id findMap = args[@"find"]; - id replacementMap = args[@"replacement"]; - if (![exprMap isKindOfClass:[NSDictionary class]] || - ![findMap isKindOfClass:[NSDictionary class]] || - ![replacementMap isKindOfClass:[NSDictionary class]]) { - if (error) - *error = parseError( - [NSString stringWithFormat:@"%@ requires expression, find, and replacement", name]); - return nil; - } - FIRExprBridge *expr = [self parseExpression:exprMap error:error]; - FIRExprBridge *find = [self parseExpression:findMap error:error]; - FIRExprBridge *replacement = [self parseExpression:replacementMap error:error]; - if (!expr || !find || !replacement) return nil; - return FLTNewFunctionExprBridge(name, @[ expr, find, replacement ]); - } - - // ------------------------------------------------------------------------- - // expression + search/repetitions: string_index_of / string_repeat - // ------------------------------------------------------------------------- - if ([name isEqualToString:@"string_index_of"] || [name isEqualToString:@"string_repeat"]) { - id exprMap = args[@"expression"]; - NSString *argumentName = [name isEqualToString:@"string_index_of"] ? @"search" : @"repetitions"; - id argumentMap = args[argumentName]; - if (![exprMap isKindOfClass:[NSDictionary class]] || - ![argumentMap isKindOfClass:[NSDictionary class]]) { - if (error) - *error = parseError( - [NSString stringWithFormat:@"%@ requires expression and %@", name, argumentName]); - return nil; - } - FIRExprBridge *expr = [self parseExpression:exprMap error:error]; - FIRExprBridge *argument = [self parseExpression:argumentMap error:error]; - if (!expr || !argument) return nil; - return FLTNewFunctionExprBridge(name, @[ expr, argument ]); - } - - // ------------------------------------------------------------------------- - // expression + optional value: ltrim / rtrim - // ------------------------------------------------------------------------- - if ([name isEqualToString:@"ltrim"] || [name isEqualToString:@"rtrim"]) { - id exprMap = args[@"expression"]; - if (![exprMap isKindOfClass:[NSDictionary class]]) { - if (error) *error = parseError([NSString stringWithFormat:@"%@ requires expression", name]); - return nil; - } - FIRExprBridge *expr = [self parseExpression:exprMap error:error]; - if (!expr) return nil; - - id valueMap = args[@"value"]; - if (![valueMap isKindOfClass:[NSDictionary class]]) { - return FLTNewFunctionExprBridge(name, @[ expr ]); - } - FIRExprBridge *value = [self parseExpression:valueMap error:error]; - if (!value) return nil; - return FLTNewFunctionExprBridge(name, @[ expr, value ]); - } - - // ------------------------------------------------------------------------- - // expression + delimiter: split, join (SDK: split, join) - // ------------------------------------------------------------------------- - if ([name isEqualToString:@"split"] || [name isEqualToString:@"join"]) { - id exprMap = args[@"expression"]; - id delimiterMap = args[@"delimiter"]; - if (![exprMap isKindOfClass:[NSDictionary class]] || - ![delimiterMap isKindOfClass:[NSDictionary class]]) { - if (error) - *error = - parseError([NSString stringWithFormat:@"%@ requires expression and delimiter", name]); - return nil; - } - FIRExprBridge *expr = [self parseExpression:exprMap error:error]; - FIRExprBridge *delimiter = [self parseExpression:delimiterMap error:error]; - if (!expr || !delimiter) return nil; - return FLTNewFunctionExprBridge(name, @[ expr, delimiter ]); - } - - // ------------------------------------------------------------------------- - // first + second: array_concat (SDK: array_concat) - // ------------------------------------------------------------------------- - if ([name isEqualToString:@"array_concat"]) { - id firstMap = args[@"first"]; - id secondMap = args[@"second"]; - if (![firstMap isKindOfClass:[NSDictionary class]] || - ![secondMap isKindOfClass:[NSDictionary class]]) { - if (error) *error = parseError(@"array_concat requires first and second"); - return nil; - } - FIRExprBridge *first = [self parseExpression:firstMap error:error]; - FIRExprBridge *second = [self parseExpression:secondMap error:error]; - if (!first || !second) return nil; - return FLTNewFunctionExprBridge(@"array_concat", @[ first, second ]); - } - - // ------------------------------------------------------------------------- - // arrays[]: array_concat_multiple (SDK: array_concat) - // ------------------------------------------------------------------------- - if ([name isEqualToString:@"array_concat_multiple"]) { - NSArray *arraysMaps = args[@"arrays"]; - if (![arraysMaps isKindOfClass:[NSArray class]] || arraysMaps.count == 0) { - if (error) *error = parseError(@"array_concat_multiple requires non-empty arrays"); - return nil; - } - NSMutableArray *all = [NSMutableArray array]; - for (id am in arraysMaps) { - if (![am isKindOfClass:[NSDictionary class]]) continue; - FIRExprBridge *e = [self parseExpression:am error:error]; - if (!e) return nil; - [all addObject:e]; - } - if (all.count == 0) { - if (error) *error = parseError(@"array_concat_multiple requires at least one array"); - return nil; - } - return FLTNewFunctionExprBridge(@"array_concat", all); - } - - // ------------------------------------------------------------------------- - // expression + offset (+ optional length): array_slice - // ------------------------------------------------------------------------- - if ([name isEqualToString:@"array_slice"]) { - id exprMap = args[@"expression"]; - id offsetMap = args[@"offset"]; - id lengthMap = args[@"length"]; - if (![exprMap isKindOfClass:[NSDictionary class]] || - ![offsetMap isKindOfClass:[NSDictionary class]]) { - if (error) *error = parseError(@"array_slice requires expression and offset"); - return nil; - } - FIRExprBridge *expr = [self parseExpression:exprMap error:error]; - FIRExprBridge *offset = [self parseExpression:offsetMap error:error]; - if (!expr || !offset) return nil; - NSMutableArray *sliceArgs = - [NSMutableArray arrayWithObjects:expr, offset, nil]; - if ([lengthMap isKindOfClass:[NSDictionary class]]) { - FIRExprBridge *length = [self parseExpression:lengthMap error:error]; - if (!length) return nil; - [sliceArgs addObject:length]; - } - return FLTNewFunctionExprBridge(@"array_slice", sliceArgs); - } - - // ------------------------------------------------------------------------- - // expression + alias + filter: array_filter - // ------------------------------------------------------------------------- - if ([name isEqualToString:@"array_filter"]) { - id exprMap = args[@"expression"]; - NSString *alias = args[@"alias"]; - id filterMap = args[@"filter"]; - if (![exprMap isKindOfClass:[NSDictionary class]] || ![alias isKindOfClass:[NSString class]] || - ![filterMap isKindOfClass:[NSDictionary class]]) { - if (error) *error = parseError(@"array_filter requires expression, alias, and filter"); - return nil; - } - FIRExprBridge *expr = [self parseExpression:exprMap error:error]; - FIRExprBridge *filter = [self parseBooleanExpression:filterMap error:error]; - if (!expr || !filter) return nil; - return FLTNewFunctionExprBridge(@"array_filter", - @[ expr, [[FIRConstantBridge alloc] init:alias], filter ]); - } - - // ------------------------------------------------------------------------- - // expression + aliases + transform: array_transform / array_transform_with_index - // ------------------------------------------------------------------------- - if ([name isEqualToString:@"array_transform"] || - [name isEqualToString:@"array_transform_with_index"]) { - id exprMap = args[@"expression"]; - NSString *elementAlias = args[@"element_alias"]; - NSString *indexAlias = args[@"index_alias"]; - id transformMap = args[@"transform"]; - BOOL withIndex = [name isEqualToString:@"array_transform_with_index"]; - if (![exprMap isKindOfClass:[NSDictionary class]] || - ![elementAlias isKindOfClass:[NSString class]] || - (withIndex && ![indexAlias isKindOfClass:[NSString class]]) || - ![transformMap isKindOfClass:[NSDictionary class]]) { - if (error) { - NSString *message = - withIndex - ? @"array_transform_with_index requires expression, element_alias, index_alias, " - @"and transform" - : @"array_transform requires expression, element_alias, and transform"; - *error = parseError(message); - } - return nil; - } - FIRExprBridge *expr = [self parseExpression:exprMap error:error]; - FIRExprBridge *transform = [self parseExpression:transformMap error:error]; - if (!expr || !transform) return nil; - NSMutableArray *transformArgs = - [NSMutableArray arrayWithObjects:expr, [[FIRConstantBridge alloc] init:elementAlias], nil]; - if (withIndex) { - [transformArgs addObject:[[FIRConstantBridge alloc] init:indexAlias]]; - } - [transformArgs addObject:transform]; - return FLTNewFunctionExprBridge(name, transformArgs); - } - - // ------------------------------------------------------------------------- - // elements[]: array (construct) — Expression.array([...]) from Dart - // ------------------------------------------------------------------------- - if ([name isEqualToString:@"array"]) { - NSArray *elementsMaps = args[@"elements"]; - if (![elementsMaps isKindOfClass:[NSArray class]] || elementsMaps.count == 0) { - if (error) *error = parseError(@"array requires non-empty elements"); - return nil; - } - NSMutableArray *elementExprs = [NSMutableArray array]; - for (id em in elementsMaps) { - if (![em isKindOfClass:[NSDictionary class]]) continue; - FIRExprBridge *e = [self parseExpression:em error:error]; - if (!e) return nil; - [elementExprs addObject:e]; - } - if (elementExprs.count == 0) { - if (error) *error = parseError(@"array requires at least one element"); - return nil; - } - return FLTNewFunctionExprBridge(@"array", elementExprs); - } - - // ------------------------------------------------------------------------- - // data: map (construct) — Expression.map({ "k": expr, ... }) from Dart - // SDK expects Args as alternating key (constant), value (expression). - // ------------------------------------------------------------------------- - if ([name isEqualToString:@"map"]) { - NSDictionary *dataMap = args[@"data"]; - if (![dataMap isKindOfClass:[NSDictionary class]] || dataMap.count == 0) { - if (error) *error = parseError(@"map requires non-empty data"); - return nil; - } - NSMutableArray *mapArgs = [NSMutableArray array]; - for (NSString *key in dataMap) { - id valueMap = dataMap[key]; - if (![valueMap isKindOfClass:[NSDictionary class]]) continue; - FIRExprBridge *keyExpr = [[FIRConstantBridge alloc] init:key]; - FIRExprBridge *valueExpr = [self parseExpression:valueMap error:error]; - if (!valueExpr) return nil; - [mapArgs addObject:keyExpr]; - [mapArgs addObject:valueExpr]; - } - if (mapArgs.count == 0) { - if (error) *error = parseError(@"map requires at least one key-value pair"); - return nil; - } - return FLTNewFunctionExprBridge(@"map", mapArgs); - } - - // ------------------------------------------------------------------------- - // map + key: map_get (SDK: map_get) - // ------------------------------------------------------------------------- - if ([name isEqualToString:@"map_get"]) { - id mapMap = args[@"map"]; - id keyMap = args[@"key"]; - if (![mapMap isKindOfClass:[NSDictionary class]] || - ![keyMap isKindOfClass:[NSDictionary class]]) { - if (error) *error = parseError(@"map_get requires map and key"); - return nil; - } - FIRExprBridge *mapExpr = [self parseExpression:mapMap error:error]; - FIRExprBridge *keyExpr = [self parseExpression:keyMap error:error]; - if (!mapExpr || !keyExpr) return nil; - return FLTNewFunctionExprBridge(@"map_get", @[ mapExpr, keyExpr ]); - } - - // ------------------------------------------------------------------------- - // expression + else: if_absent (SDK: if_absent) - // ------------------------------------------------------------------------- - if ([name isEqualToString:@"if_absent"]) { - id exprMap = args[@"expression"]; - id elseMap = args[@"else"]; - if (![exprMap isKindOfClass:[NSDictionary class]] || - ![elseMap isKindOfClass:[NSDictionary class]]) { - if (error) *error = parseError(@"if_absent requires expression and else"); - return nil; - } - FIRExprBridge *expr = [self parseExpression:exprMap error:error]; - FIRExprBridge *elseExpr = [self parseExpression:elseMap error:error]; - if (!expr || !elseExpr) return nil; - return FLTNewFunctionExprBridge(@"if_absent", @[ expr, elseExpr ]); - } - - // ------------------------------------------------------------------------- - // expression + catch: if_error (SDK: if_error) - // ------------------------------------------------------------------------- - if ([name isEqualToString:@"if_error"]) { - id exprMap = args[@"expression"]; - id catchMap = args[@"catch"]; - if (![exprMap isKindOfClass:[NSDictionary class]] || - ![catchMap isKindOfClass:[NSDictionary class]]) { - if (error) *error = parseError(@"if_error requires expression and catch"); - return nil; - } - FIRExprBridge *expr = [self parseExpression:exprMap error:error]; - FIRExprBridge *catchExpr = [self parseExpression:catchMap error:error]; - if (!expr || !catchExpr) return nil; - return FLTNewFunctionExprBridge(@"if_error", @[ expr, catchExpr ]); - } - - // ------------------------------------------------------------------------- - // condition + then + else: conditional (SDK: conditional) - // ------------------------------------------------------------------------- - if ([name isEqualToString:@"conditional"]) { - id conditionMap = args[@"condition"]; - id thenMap = args[@"then"]; - id elseMap = args[@"else"]; - if (![conditionMap isKindOfClass:[NSDictionary class]] || - ![thenMap isKindOfClass:[NSDictionary class]] || - ![elseMap isKindOfClass:[NSDictionary class]]) { - if (error) *error = parseError(@"conditional requires condition, then, and else"); - return nil; - } - FIRExprBridge *condition = [self parseBooleanExpression:conditionMap error:error]; - FIRExprBridge *thenExpr = [self parseExpression:thenMap error:error]; - FIRExprBridge *elseExpr = [self parseExpression:elseMap error:error]; - if (!condition || !thenExpr || !elseExpr) return nil; - return FLTNewFunctionExprBridge(@"conditional", @[ condition, thenExpr, elseExpr ]); - } - - // ------------------------------------------------------------------------- - // timestamp + amount + unit: timestamp_add, timestamp_subtract (SDK: Args ts, amount, unit) - // ------------------------------------------------------------------------- - if ([name isEqualToString:@"timestamp_add"] || [name isEqualToString:@"timestamp_subtract"]) { - id timestampMap = args[@"timestamp"]; - id unitVal = args[@"unit"]; - id amountMap = args[@"amount"]; - if (![timestampMap isKindOfClass:[NSDictionary class]] || !unitVal || - ![amountMap isKindOfClass:[NSDictionary class]]) { - if (error) - *error = parseError( - [NSString stringWithFormat:@"%@ requires timestamp, unit, and amount", name]); - return nil; - } - FIRExprBridge *timestampExpr = [self parseExpression:timestampMap error:error]; - FIRExprBridge *amountExpr = [self parseExpression:amountMap error:error]; - if (!timestampExpr || !amountExpr) return nil; - FIRExprBridge *unitExpr = [[FIRConstantBridge alloc] init:unitVal]; - return FLTNewFunctionExprBridge(name, @[ timestampExpr, unitExpr, amountExpr ]); - } - - // ------------------------------------------------------------------------- - // No args: current_timestamp (SDK: current_timestamp with empty Args) - // ------------------------------------------------------------------------- - if ([name isEqualToString:@"current_timestamp"]) { - return FLTNewFunctionExprBridge(@"current_timestamp", @[]); - } - - // ------------------------------------------------------------------------- - // timestamp + unit: timestamp_truncate (SDK: timestamp_trunc) - // ------------------------------------------------------------------------- - if ([name isEqualToString:@"timestamp_truncate"]) { - id timestampMap = args[@"timestamp"]; - id unitVal = args[@"unit"]; - if (![timestampMap isKindOfClass:[NSDictionary class]] || !unitVal) { - if (error) *error = parseError(@"timestamp_truncate requires timestamp and unit"); - return nil; - } - FIRExprBridge *timestampExpr = [self parseExpression:timestampMap error:error]; - if (!timestampExpr) return nil; - FIRExprBridge *unitExpr = [[FIRConstantBridge alloc] init:unitVal]; - return FLTNewFunctionExprBridge(@"timestamp_trunc", @[ timestampExpr, unitExpr ]); - } - - // ------------------------------------------------------------------------- - // map_keys, map_values (unary on map expression) - // ------------------------------------------------------------------------- - if ([name isEqualToString:@"map_keys"] || [name isEqualToString:@"map_values"]) { - id exprMap = args[@"expression"]; - if (![exprMap isKindOfClass:[NSDictionary class]]) { - if (error) *error = parseError([NSString stringWithFormat:@"%@ requires expression", name]); - return nil; - } - FIRExprBridge *expr = [self parseExpression:(NSDictionary *)exprMap error:error]; - if (!expr) return nil; - return FLTNewFunctionExprBridge(name, @[ expr ]); - } - - // ------------------------------------------------------------------------- - // parent: doc_ref path or expression - // ------------------------------------------------------------------------- - if ([name isEqualToString:@"parent"]) { - NSString *docPath = args[@"doc_ref"]; - if ([docPath isKindOfClass:[NSString class]] && docPath.length > 0) { - FIRDocumentReference *ref = [self.firestore documentWithPath:docPath]; - FIRExprBridge *refExpr = [[FIRConstantBridge alloc] init:ref]; - return FLTNewFunctionExprBridge(@"parent", @[ refExpr ]); - } - id exprMap = args[@"expression"]; - if (![exprMap isKindOfClass:[NSDictionary class]]) { - if (error) *error = parseError(@"parent requires expression or doc_ref"); - return nil; - } - FIRExprBridge *expr = [self parseExpression:(NSDictionary *)exprMap error:error]; - if (!expr) return nil; - return FLTNewFunctionExprBridge(@"parent", @[ expr ]); - } - - // ------------------------------------------------------------------------- - // timestamp_diff: end, start, unit (unit = string or expression map) - // ------------------------------------------------------------------------- - if ([name isEqualToString:@"timestamp_diff"]) { - id endMap = args[@"end"]; - id startMap = args[@"start"]; - id unitObj = args[@"unit"]; - if (![endMap isKindOfClass:[NSDictionary class]] || - ![startMap isKindOfClass:[NSDictionary class]] || !unitObj) { - if (error) *error = parseError(@"timestamp_diff requires end, start, and unit"); - return nil; - } - FIRExprBridge *endExpr = [self parseExpression:(NSDictionary *)endMap error:error]; - FIRExprBridge *startExpr = [self parseExpression:(NSDictionary *)startMap error:error]; - if (!endExpr || !startExpr) return nil; - FIRExprBridge *unitExpr = nil; - if ([unitObj isKindOfClass:[NSString class]]) { - unitExpr = [[FIRConstantBridge alloc] init:unitObj]; - } else if ([unitObj isKindOfClass:[NSDictionary class]]) { - unitExpr = [self parseExpression:(NSDictionary *)unitObj error:error]; - } else { - if (error) *error = parseError(@"timestamp_diff unit must be string or expression"); - return nil; - } - if (!unitExpr) return nil; - return FLTNewFunctionExprBridge(@"timestamp_diff", @[ endExpr, startExpr, unitExpr ]); - } - - // ------------------------------------------------------------------------- - // timestamp_extract: timestamp, part; optional timezone (string or expression) - // ------------------------------------------------------------------------- - if ([name isEqualToString:@"timestamp_extract"]) { - id timestampMap = args[@"timestamp"]; - id partMap = args[@"part"]; - if (![timestampMap isKindOfClass:[NSDictionary class]] || - ![partMap isKindOfClass:[NSDictionary class]]) { - if (error) *error = parseError(@"timestamp_extract requires timestamp and part"); - return nil; - } - FIRExprBridge *tsExpr = [self parseExpression:(NSDictionary *)timestampMap error:error]; - FIRExprBridge *partExpr = [self parseExpression:(NSDictionary *)partMap error:error]; - if (!tsExpr || !partExpr) return nil; - id tzRaw = args[@"timezone"]; - if (tzRaw == nil) { - return FLTNewFunctionExprBridge(@"timestamp_extract", @[ tsExpr, partExpr ]); - } - FIRExprBridge *tzExpr = nil; - if ([tzRaw isKindOfClass:[NSString class]]) { - tzExpr = [[FIRConstantBridge alloc] init:tzRaw]; - } else if ([tzRaw isKindOfClass:[NSDictionary class]]) { - tzExpr = [self parseExpression:(NSDictionary *)tzRaw error:error]; - } else { - if (error) *error = parseError(@"timestamp_extract timezone must be string or expression"); - return nil; - } - if (!tzExpr) return nil; - return FLTNewFunctionExprBridge(@"timestamp_extract", @[ tsExpr, partExpr, tzExpr ]); - } - - // ------------------------------------------------------------------------- - // if_null: expression + replacement - // ------------------------------------------------------------------------- - if ([name isEqualToString:@"if_null"]) { - id exprMap = args[@"expression"]; - id replMap = args[@"replacement"]; - if (![exprMap isKindOfClass:[NSDictionary class]] || - ![replMap isKindOfClass:[NSDictionary class]]) { - if (error) *error = parseError(@"if_null requires expression and replacement"); - return nil; - } - FIRExprBridge *ifExpr = [self parseExpression:(NSDictionary *)exprMap error:error]; - FIRExprBridge *replExpr = [self parseExpression:(NSDictionary *)replMap error:error]; - if (!ifExpr || !replExpr) return nil; - return FLTNewFunctionExprBridge(@"if_null", @[ ifExpr, replExpr ]); - } - - // ------------------------------------------------------------------------- - // coalesce: expressions[] (>= 2) - // ------------------------------------------------------------------------- - if ([name isEqualToString:@"coalesce"]) { - NSArray *exprMaps = args[@"expressions"]; - if (![exprMaps isKindOfClass:[NSArray class]] || exprMaps.count < 2) { - if (error) *error = parseError(@"coalesce requires at least two expressions"); - return nil; - } - NSMutableArray *exprs = [NSMutableArray array]; - for (id em in exprMaps) { - if (![em isKindOfClass:[NSDictionary class]]) continue; - FIRExprBridge *e = [self parseExpression:(NSDictionary *)em error:error]; - if (!e) return nil; - [exprs addObject:e]; - } - if (exprs.count < 2) { - if (error) *error = parseError(@"coalesce requires at least two expressions"); - return nil; - } - return FLTNewFunctionExprBridge(@"coalesce", exprs); - } - - // ------------------------------------------------------------------------- - // switch_on: alternating condition (bool), result (expr), optional default - // ------------------------------------------------------------------------- - if ([name isEqualToString:@"switch_on"]) { - NSArray *exprMaps = args[@"expressions"]; - if (![exprMaps isKindOfClass:[NSArray class]] || exprMaps.count < 2) { - if (error) *error = parseError(@"switch_on requires at least two expressions"); - return nil; - } - NSUInteger n = exprMaps.count; - FIRExprBridge *first = [self parseBooleanExpression:exprMaps[0] error:error]; - FIRExprBridge *second = [self parseExpression:exprMaps[1] error:error]; - if (!first || !second) return nil; - if (n == 2) { - return FLTNewFunctionExprBridge(@"switch_on", @[ first, second ]); - } - NSMutableArray *rest = [NSMutableArray array]; - for (NSUInteger i = 2; i < n; i++) { - FIRExprBridge *e = nil; - if ((n % 2 == 1) && (i == n - 1)) { - e = [self parseExpression:exprMaps[i] error:error]; - } else if (i % 2 == 0) { - e = [self parseBooleanExpression:exprMaps[i] error:error]; - } else { - e = [self parseExpression:exprMaps[i] error:error]; - } - if (!e) return nil; - [rest addObject:e]; - } - NSMutableArray *all = [NSMutableArray arrayWithObjects:first, second, nil]; - [all addObjectsFromArray:rest]; - return FLTNewFunctionExprBridge(@"switch_on", all); - } - - // ------------------------------------------------------------------------- - // PipelineFilter (name "filter"): operator-based (and/or) or field-based - // ------------------------------------------------------------------------- - if ([name isEqualToString:@"filter"]) { - return [self parseFilterExpressionWithArgs:args error:error]; - } - - if (error) *error = parseError([NSString stringWithFormat:@"Unsupported expression: %@", name]); - return nil; -} - -- (FIRExprBridge *)rightExprFromValue:(id)value error:(NSError **)error { - if ([value isKindOfClass:[NSDictionary class]]) { - return [self parseExpression:(NSDictionary *)value error:error]; - } - return [[FIRConstantBridge alloc] init:value]; -} - -- (FIRExprBridge *)parseFilterExpressionWithArgs:(NSDictionary *)args error:(NSError **)error { - // Operator-based: and/or with expressions array (from PipelineFilter.and / .or) - NSString *operator= args[@"operator"]; - NSArray *exprMaps = args[@"expressions"]; - if ([operator isKindOfClass:[NSString class]] && [exprMaps isKindOfClass:[NSArray class]]) { - if (exprMaps.count == 0) { - if (error) *error = parseError(@"filter with operator requires at least one expression"); - return nil; - } - if (exprMaps.count == 1) { - id em = exprMaps[0]; - if (![em isKindOfClass:[NSDictionary class]]) { - if (error) *error = parseError(@"filter expressions must be maps"); - return nil; - } - return [self parseBooleanExpression:(NSDictionary *)em error:error]; - } - NSMutableArray *all = [NSMutableArray array]; - for (id em in exprMaps) { - if (![em isKindOfClass:[NSDictionary class]]) continue; - FIRExprBridge *e = [self parseBooleanExpression:(NSDictionary *)em error:error]; - if (!e) return nil; - [all addObject:e]; - } - if (all.count == 0) return nil; - return FLTNewFunctionExprBridge(operator, all); - } - - // Field-based: field + isEqualTo, isGreaterThan, etc. - NSString *fieldName = args[@"field"]; - if (![fieldName isKindOfClass:[NSString class]]) { - if (error) *error = parseError(@"filter requires operator+expressions or field"); - return nil; - } - FIRExprBridge *fieldExpr = [[FIRFieldBridge alloc] initWithName:fieldName]; - - static NSArray *filterComparisonKeys = nil; - static dispatch_once_t filterOnce; - dispatch_once(&filterOnce, ^{ - filterComparisonKeys = @[ - @"isEqualTo", @"isNotEqualTo", @"isGreaterThan", @"isGreaterThanOrEqualTo", @"isLessThan", - @"isLessThanOrEqualTo", @"arrayContains", @"arrayContainsAny", @"whereIn", @"whereNotIn", - @"isNull", @"isNotNull" - ]; - }); - for (NSString *key in filterComparisonKeys) { - id value = args[key]; - if (value == nil) continue; - - if ([key isEqualToString:@"isEqualTo"]) { - FIRExprBridge *right = [self rightExprFromValue:value error:error]; - if (!right) return nil; - return FLTNewFunctionExprBridge(@"equal", @[ fieldExpr, right ]); - } - if ([key isEqualToString:@"isNotEqualTo"]) { - FIRExprBridge *right = [self rightExprFromValue:value error:error]; - if (!right) return nil; - return FLTNewFunctionExprBridge(@"not_equal", @[ fieldExpr, right ]); - } - if ([key isEqualToString:@"isGreaterThan"]) { - FIRExprBridge *right = [self rightExprFromValue:value error:error]; - if (!right) return nil; - return FLTNewFunctionExprBridge(@"greater_than", @[ fieldExpr, right ]); - } - if ([key isEqualToString:@"isGreaterThanOrEqualTo"]) { - FIRExprBridge *right = [self rightExprFromValue:value error:error]; - if (!right) return nil; - return FLTNewFunctionExprBridge(@"greater_than_or_equal", @[ fieldExpr, right ]); - } - if ([key isEqualToString:@"isLessThan"]) { - FIRExprBridge *right = [self rightExprFromValue:value error:error]; - if (!right) return nil; - return FLTNewFunctionExprBridge(@"less_than", @[ fieldExpr, right ]); - } - if ([key isEqualToString:@"isLessThanOrEqualTo"]) { - FIRExprBridge *right = [self rightExprFromValue:value error:error]; - if (!right) return nil; - return FLTNewFunctionExprBridge(@"less_than_or_equal", @[ fieldExpr, right ]); - } - if ([key isEqualToString:@"arrayContains"]) { - FIRExprBridge *right = [self rightExprFromValue:value error:error]; - if (!right) return nil; - return FLTNewFunctionExprBridge(@"array_contains", @[ fieldExpr, right ]); - } - if ([key isEqualToString:@"arrayContainsAny"] || [key isEqualToString:@"whereIn"]) { - NSArray *valuesList = [value isKindOfClass:[NSArray class]] ? value : @[]; - NSMutableArray *valueExprs = [NSMutableArray array]; - for (id v in valuesList) { - FIRExprBridge *ve = [self rightExprFromValue:v error:error]; - if (!ve) return nil; - [valueExprs addObject:ve]; - } - if (valueExprs.count == 0) { - if (error) *error = parseError(@"arrayContainsAny/whereIn requires non-empty list"); - return nil; - } - // SDK expects (value, array) not (value, v1, v2, ...); wrap in "array" expr. - FIRExprBridge *valuesArrayExpr = FLTNewFunctionExprBridge(@"array", valueExprs); - return FLTNewFunctionExprBridge(@"equal_any", @[ fieldExpr, valuesArrayExpr ]); - } - if ([key isEqualToString:@"whereNotIn"]) { - NSArray *valuesList = [value isKindOfClass:[NSArray class]] ? value : @[]; - NSMutableArray *valueExprs = [NSMutableArray array]; - for (id v in valuesList) { - FIRExprBridge *ve = [self rightExprFromValue:v error:error]; - if (!ve) return nil; - [valueExprs addObject:ve]; - } - if (valueExprs.count == 0) { - if (error) *error = parseError(@"whereNotIn requires non-empty list"); - return nil; - } - // SDK expects (value, array) not (value, v1, v2, ...); wrap in "array" expr. - FIRExprBridge *valuesArrayExpr = FLTNewFunctionExprBridge(@"array", valueExprs); - return FLTNewFunctionExprBridge(@"not_equal_any", @[ fieldExpr, valuesArrayExpr ]); - } - if ([key isEqualToString:@"isNull"]) { - FIRExprBridge *right = [[FIRConstantBridge alloc] init:[NSNull null]]; - return FLTNewFunctionExprBridge(@"equal", @[ fieldExpr, right ]); - } - if ([key isEqualToString:@"isNotNull"]) { - FIRExprBridge *right = [[FIRConstantBridge alloc] init:[NSNull null]]; - return FLTNewFunctionExprBridge(@"not_equal", @[ fieldExpr, right ]); - } - } - - if (error) - *error = - parseError(@"filter requires at least one comparison (isEqualTo, isGreaterThan, etc.)"); - return nil; -} - -- (FIRExprBridge *)parseBooleanExpression:(NSDictionary *)map - error:(NSError **)error { - return [self parseExpression:map error:error]; -} - -@end - -@implementation FLTPipelineParser - -/// Returns the key (alias or field name) for an expression map in select/distinct stages. -/// Uses args.alias if present; otherwise for "field" expressions uses args.field. Returns nil if -/// no key can be determined (caller should error). -+ (NSString *)keyForExpressionMap:(NSDictionary *)em error:(NSError **)error { - NSString *alias = [em valueForKeyPath:@"args.alias"]; - if ([alias isKindOfClass:[NSString class]] && alias.length > 0) { - return alias; - } - if ([em[@"name"] isEqualToString:@"field"]) { - NSString *field = [em valueForKeyPath:@"args.field"]; - if ([field isKindOfClass:[NSString class]]) return field; - if (error) *error = parseError(@"field expression must have args.field"); - return nil; - } - if (error) *error = parseError(@"expression must have alias or be a field reference"); - return nil; -} - -+ (NSDictionary *) - parseSearchFieldsWithExpressionMaps:(NSArray *> *)exprMaps - exprParser:(FLTPipelineExpressionParser *)exprParser - error:(NSError **)error { - NSMutableDictionary *fields = [NSMutableDictionary dictionary]; - NSError *parseErr = nil; - - for (id em in exprMaps) { - if (![em isKindOfClass:[NSDictionary class]]) continue; - - FIRExprBridge *expr = [exprParser parseExpression:em error:&parseErr]; - if (!expr) { - if (error) *error = parseErr; - return nil; - } - - NSString *key = [self keyForExpressionMap:em error:error]; - if (![key isKindOfClass:[NSString class]] || key.length == 0) return nil; - fields[key] = expr; - } - - return fields; -} - -+ (FIRStageBridge *)parseSearchStageWithArgs:(NSDictionary *)args - exprParser:(FLTPipelineExpressionParser *)exprParser - error:(NSError **)error { - NSString *queryType = args[@"query_type"]; - id query = args[@"query"]; - NSMutableDictionary *options = [NSMutableDictionary dictionary]; - NSError *parseErr = nil; - - if ([queryType isEqualToString:@"string"]) { - if (![query isKindOfClass:[NSString class]]) { - if (error) *error = parseError(@"search query_type 'string' requires string query"); - return nil; - } - FIRExprBridge *queryExpr = [[FIRConstantBridge alloc] init:query]; - options[@"query"] = FLTNewFunctionExprBridge(@"document_matches", @[ queryExpr ]); - } else if ([queryType isEqualToString:@"expression"]) { - if (![query isKindOfClass:[NSDictionary class]]) { - if (error) *error = parseError(@"search query_type 'expression' requires expression query"); - return nil; - } - FIRExprBridge *queryExpr = [exprParser parseBooleanExpression:query error:&parseErr]; - if (!queryExpr) { - if (error) *error = parseErr; - return nil; - } - options[@"query"] = queryExpr; - } else { - if (error) *error = parseError(@"search requires query_type to be 'string' or 'expression'"); - return nil; - } - - NSNumber *limit = [args[@"limit"] isKindOfClass:[NSNumber class]] ? args[@"limit"] : nil; - if (limit) options[@"limit"] = [[FIRConstantBridge alloc] init:limit]; - - NSNumber *offset = [args[@"offset"] isKindOfClass:[NSNumber class]] ? args[@"offset"] : nil; - if (offset) options[@"offset"] = [[FIRConstantBridge alloc] init:offset]; - - NSNumber *retrievalDepth = - [args[@"retrieval_depth"] isKindOfClass:[NSNumber class]] ? args[@"retrieval_depth"] : nil; - if (retrievalDepth) { - options[@"retrieval_depth"] = [[FIRConstantBridge alloc] init:retrievalDepth]; - } - - NSString *languageCode = - [args[@"language_code"] isKindOfClass:[NSString class]] ? args[@"language_code"] : nil; - if (languageCode) { - options[@"language_code"] = [[FIRConstantBridge alloc] init:languageCode]; - } - - NSMutableArray *sort = [NSMutableArray array]; - NSArray *orderingMaps = args[@"sort"]; - if ([orderingMaps isKindOfClass:[NSArray class]]) { - for (id om in orderingMaps) { - if (![om isKindOfClass:[NSDictionary class]]) continue; - id exprMap = ((NSDictionary *)om)[@"expression"]; - NSString *dir = ((NSDictionary *)om)[@"order_direction"]; - if (![exprMap isKindOfClass:[NSDictionary class]]) continue; - FIRExprBridge *expr = [exprParser parseExpression:exprMap error:&parseErr]; - if (!expr) { - if (error) *error = parseErr; - return nil; - } - NSString *direction = [dir isEqualToString:@"asc"] ? @"ascending" : @"descending"; - [sort addObject:[[FIROrderingBridge alloc] initWithExpr:expr Direction:direction]]; - } - } - - NSDictionary *addFields = @{}; - NSArray *addFieldMaps = args[@"add_fields"]; - if ([addFieldMaps isKindOfClass:[NSArray class]] && addFieldMaps.count > 0) { - addFields = [self parseSearchFieldsWithExpressionMaps:addFieldMaps - exprParser:exprParser - error:error]; - if (!addFields) return nil; - } - - return [[FIRSearchStageBridge alloc] initWithOptions:options - addFields:addFields - select:@{} - sort:sort]; -} - -+ (NSArray *) - parseStagesWithFirestore:(FIRFirestore *)firestore - stages:(NSArray *> *)stages - error:(NSError **)error { - FLTPipelineExpressionParser *exprParser = - [[FLTPipelineExpressionParser alloc] initWithFirestore:firestore]; - NSMutableArray *stageBridges = [NSMutableArray array]; - NSError *parseErr = nil; - - for (NSUInteger i = 0; i < stages.count; i++) { - NSDictionary *stageMap = stages[i]; - if (![stageMap isKindOfClass:[NSDictionary class]]) { - if (error) *error = parseError(@"Stage must be a map"); - return nil; - } - NSString *stageName = stageMap[@"stage"]; - if (![stageName isKindOfClass:[NSString class]]) { - if (error) *error = parseError(@"Stage must have a 'stage' field"); - return nil; - } - id argsObj = stageMap[@"args"]; - NSDictionary *args = [argsObj isKindOfClass:[NSDictionary class]] ? argsObj : @{}; - NSArray *argsArray = [argsObj isKindOfClass:[NSArray class]] ? argsObj : nil; - - FIRStageBridge *stage = nil; - - if (i == 0) { - if ([stageName isEqualToString:@"collection"]) { - NSString *path = args[@"path"]; - if (!path) { - if (error) *error = parseError(@"collection requires 'path'"); - return nil; - } - FIRCollectionReference *ref = [firestore collectionWithPath:path]; - stage = [[FIRCollectionSourceStageBridge alloc] initWithRef:ref - firestore:firestore - forceIndex:nil]; - } else if ([stageName isEqualToString:@"collection_group"]) { - NSString *path = args[@"path"]; - if (!path) { - if (error) *error = parseError(@"collection_group requires 'path'"); - return nil; - } - stage = [[FIRCollectionGroupSourceStageBridge alloc] initWithCollectionId:path - forceIndex:nil]; - } else if ([stageName isEqualToString:@"database"]) { - stage = [[FIRDatabaseSourceStageBridge alloc] init]; - } else if ([stageName isEqualToString:@"documents"]) { - NSArray *docMaps = argsArray; - if (!docMaps || docMaps.count == 0) { - if (error) *error = parseError(@"documents requires array of document refs"); - return nil; - } - NSMutableArray *refs = [NSMutableArray array]; - for (id docMap in docMaps) { - if (![docMap isKindOfClass:[NSDictionary class]]) continue; - NSString *path = ((NSDictionary *)docMap)[@"path"]; - if (path) [refs addObject:[firestore documentWithPath:path]]; - } - stage = [[FIRDocumentsSourceStageBridge alloc] initWithDocuments:refs firestore:firestore]; - } else { - if (error) - *error = parseError( - [NSString stringWithFormat:@"First stage must be collection, collection_group, " - @"documents, or database. Got: %@", - stageName]); - return nil; - } - } else { - if ([stageName isEqualToString:@"where"]) { - id exprMap = args[@"expression"]; - if (![exprMap isKindOfClass:[NSDictionary class]]) { - if (error) *error = parseError(@"where requires expression"); - return nil; - } - FIRExprBridge *expr = [exprParser parseBooleanExpression:exprMap error:&parseErr]; - if (!expr) { - if (error) *error = parseErr; - return nil; - } - stage = [[FIRWhereStageBridge alloc] initWithExpr:expr]; - } else if ([stageName isEqualToString:@"search"]) { - stage = [self parseSearchStageWithArgs:args exprParser:exprParser error:error]; - if (!stage) return nil; - } else if ([stageName isEqualToString:@"limit"]) { - NSNumber *limit = args[@"limit"]; - if (![limit isKindOfClass:[NSNumber class]]) { - if (error) *error = parseError(@"limit requires numeric limit"); - return nil; - } - stage = [[FIRLimitStageBridge alloc] initWithLimit:limit.intValue]; - } else if ([stageName isEqualToString:@"offset"]) { - NSNumber *offset = args[@"offset"]; - if (![offset isKindOfClass:[NSNumber class]]) { - if (error) *error = parseError(@"offset requires numeric offset"); - return nil; - } - stage = [[FIROffsetStageBridge alloc] initWithOffset:offset.intValue]; - } else if ([stageName isEqualToString:@"sort"]) { - NSArray *orderingMaps = args[@"orderings"]; - if (![orderingMaps isKindOfClass:[NSArray class]] || orderingMaps.count == 0) { - if (error) *error = parseError(@"sort requires at least one ordering"); - return nil; - } - NSMutableArray *orderings = [NSMutableArray array]; - for (id om in orderingMaps) { - if (![om isKindOfClass:[NSDictionary class]]) continue; - id exprMap = ((NSDictionary *)om)[@"expression"]; - NSString *dir = ((NSDictionary *)om)[@"order_direction"]; - if (![exprMap isKindOfClass:[NSDictionary class]]) continue; - FIRExprBridge *expr = [exprParser parseExpression:exprMap error:&parseErr]; - if (!expr) { - if (error) *error = parseErr; - return nil; - } - NSString *direction = [dir isEqualToString:@"asc"] ? @"ascending" : @"descending"; - FIROrderingBridge *ordering = [[FIROrderingBridge alloc] initWithExpr:expr - Direction:direction]; - [orderings addObject:ordering]; - } - if (orderings.count == 0) { - if (error) *error = parseError(@"sort requires at least one ordering"); - return nil; - } - stage = [[FIRSorStageBridge alloc] initWithOrderings:orderings]; - } else if ([stageName isEqualToString:@"select"]) { - NSArray *exprMaps = args[@"expressions"]; - if (![exprMaps isKindOfClass:[NSArray class]] || exprMaps.count == 0) { - if (error) *error = parseError(@"select requires at least one expression"); - return nil; - } - NSMutableDictionary *fields = [NSMutableDictionary dictionary]; - for (id em in exprMaps) { - if (![em isKindOfClass:[NSDictionary class]]) continue; - FIRExprBridge *expr = [exprParser parseExpression:em error:&parseErr]; - if (!expr) { - if (error) *error = parseErr; - return nil; - } - NSString *key = [self keyForExpressionMap:em error:error]; - if (!key) return nil; - fields[key] = expr; - } - stage = [[FIRSelectStageBridge alloc] initWithSelections:fields]; - } else if ([stageName isEqualToString:@"add_fields"]) { - NSArray *exprMaps = args[@"expressions"]; - if (![exprMaps isKindOfClass:[NSArray class]] || exprMaps.count == 0) { - if (error) *error = parseError(@"add_fields requires at least one expression"); - return nil; - } - NSMutableDictionary *fields = [NSMutableDictionary dictionary]; - for (id em in exprMaps) { - if (![em isKindOfClass:[NSDictionary class]]) continue; - FIRExprBridge *expr = [exprParser parseExpression:em error:&parseErr]; - if (!expr) { - if (error) *error = parseErr; - return nil; - } - NSString *alias = [em valueForKeyPath:@"args.alias"]; - if (!alias) { - if (error) *error = parseError(@"add_fields expressions must have alias"); - return nil; - } - fields[alias] = expr; - } - stage = [[FIRAddFieldsStageBridge alloc] initWithFields:fields]; - } else if ([stageName isEqualToString:@"remove_fields"]) { - NSArray *paths = args[@"field_paths"]; - if (![paths isKindOfClass:[NSArray class]] || paths.count == 0) { - if (error) *error = parseError(@"remove_fields requires field_paths"); - return nil; - } - stage = [[FIRRemoveFieldsStageBridge alloc] initWithFields:paths]; - } else if ([stageName isEqualToString:@"distinct"]) { - NSArray *exprMaps = args[@"expressions"]; - if (![exprMaps isKindOfClass:[NSArray class]] || exprMaps.count == 0) { - if (error) *error = parseError(@"distinct requires at least one expression"); - return nil; - } - NSMutableDictionary *fields = [NSMutableDictionary dictionary]; - for (id em in exprMaps) { - if (![em isKindOfClass:[NSDictionary class]]) continue; - FIRExprBridge *expr = [exprParser parseExpression:em error:&parseErr]; - if (!expr) { - if (error) *error = parseErr; - return nil; - } - NSString *key = [self keyForExpressionMap:em error:error]; - if (!key) return nil; - fields[key] = expr; - } - stage = [[FIRDistinctStageBridge alloc] initWithGroups:fields]; - } else if ([stageName isEqualToString:@"replace_with"]) { - id exprMap = args[@"expression"]; - if (![exprMap isKindOfClass:[NSDictionary class]]) { - if (error) *error = parseError(@"replace_with requires expression"); - return nil; - } - FIRExprBridge *expr = [exprParser parseExpression:exprMap error:&parseErr]; - if (!expr) { - if (error) *error = parseErr; - return nil; - } - stage = [[FIRReplaceWithStageBridge alloc] initWithExpr:expr]; - } else if ([stageName isEqualToString:@"union"]) { - NSArray *nestedStages = args[@"pipeline"]; - if (![nestedStages isKindOfClass:[NSArray class]] || nestedStages.count == 0) { - if (error) *error = parseError(@"union requires non-empty pipeline"); - return nil; - } - id otherPipeline = [self buildPipelineWithFirestore:firestore - stages:nestedStages - error:&parseErr]; - if (!otherPipeline) { - if (error) *error = parseErr; - return nil; - } - stage = [[FIRUnionStageBridge alloc] initWithOther:otherPipeline]; - } else if ([stageName isEqualToString:@"sample"]) { - NSString *type = args[@"type"]; - id val = args[@"value"]; - if ([type isEqualToString:@"percentage"]) { - double v = [val isKindOfClass:[NSNumber class]] ? [(NSNumber *)val doubleValue] : 0; - stage = [[FIRSampleStageBridge alloc] initWithPercentage:v]; - } else { - int v = [val isKindOfClass:[NSNumber class]] ? [(NSNumber *)val intValue] : 0; - stage = [[FIRSampleStageBridge alloc] initWithCount:v]; - } - } else if ([stageName isEqualToString:@"aggregate"]) { - stage = [self parseAggregateStageWithArgs:args exprParser:exprParser error:error]; - } else if ([stageName isEqualToString:@"aggregate_with_options"]) { - stage = [self parseAggregateStageWithOptionsArgs:args exprParser:exprParser error:error]; - } else if ([stageName isEqualToString:@"unnest"]) { - id exprMap = args[@"expression"]; - if (![exprMap isKindOfClass:[NSDictionary class]]) { - if (error) *error = parseError(@"unnest requires expression"); - return nil; - } - FIRExprBridge *fieldExpr = nil; - FIRExprBridge *aliasExpr = nil; - NSDictionary *exprDict = (NSDictionary *)exprMap; - NSString *aliasStr = nil; - if ([exprDict[@"name"] isEqualToString:@"alias"]) { - NSDictionary *aliasArgs = exprDict[@"args"]; - if ([aliasArgs isKindOfClass:[NSDictionary class]] && aliasArgs[@"expression"]) { - fieldExpr = [exprParser parseExpression:aliasArgs[@"expression"] error:&parseErr]; - if (!fieldExpr) { - if (error) *error = parseErr; - return nil; - } - aliasStr = - [aliasArgs[@"alias"] isKindOfClass:[NSString class]] ? aliasArgs[@"alias"] : nil; - } - } - if (!fieldExpr) { - fieldExpr = [exprParser parseExpression:exprMap error:&parseErr]; - if (!fieldExpr) { - if (error) *error = parseErr; - return nil; - } - if (!aliasStr && [exprDict[@"name"] isEqualToString:@"field"]) { - NSDictionary *fieldArgs = exprDict[@"args"]; - aliasStr = - [fieldArgs[@"field"] isKindOfClass:[NSString class]] ? fieldArgs[@"field"] : @"_"; - } - } - if (!aliasStr) aliasStr = @"_"; - aliasExpr = [[FIRFieldBridge alloc] initWithName:aliasStr]; - NSString *indexFieldStr = - [args[@"index_field"] isKindOfClass:[NSString class]] ? args[@"index_field"] : nil; - FIRExprBridge *indexFieldExpr = - (indexFieldStr.length > 0) ? [[FIRFieldBridge alloc] initWithName:indexFieldStr] : nil; - stage = [[FIRUnnestStageBridge alloc] initWithField:fieldExpr - alias:aliasExpr - indexField:indexFieldExpr]; - } else if ([stageName isEqualToString:@"find_nearest"]) { - NSString *vectorFieldName = args[@"vector_field"]; - NSArray *vectorValueArray = args[@"vector_value"]; - NSString *distanceMeasure = args[@"distance_measure"]; - NSNumber *limit = [args[@"limit"] isKindOfClass:[NSNumber class]] ? args[@"limit"] : nil; - NSString *distanceField = [args[@"distance_field"] isKindOfClass:[NSString class]] - ? args[@"distance_field"] - : nil; - if (![vectorFieldName isKindOfClass:[NSString class]] || vectorFieldName.length == 0) { - if (error) *error = parseError(@"find_nearest requires 'vector_field'"); - return nil; - } - if (![vectorValueArray isKindOfClass:[NSArray class]] || vectorValueArray.count == 0) { - if (error) *error = parseError(@"find_nearest requires non-empty 'vector_value'"); - return nil; - } - if (![distanceMeasure isKindOfClass:[NSString class]] || distanceMeasure.length == 0) { - if (error) *error = parseError(@"find_nearest requires 'distance_measure'"); - return nil; - } - FIRFieldBridge *embeddingField = [[FIRFieldBridge alloc] initWithName:vectorFieldName]; - NSMutableArray *numbers = - [NSMutableArray arrayWithCapacity:vectorValueArray.count]; - for (id v in vectorValueArray) { - if ([v isKindOfClass:[NSNumber class]]) { - [numbers addObject:(NSNumber *)v]; - } - } - if (numbers.count != (NSUInteger)vectorValueArray.count) { - if (error) *error = parseError(@"find_nearest vector_value must be an array of numbers"); - return nil; - } - FIRVectorValue *queryVector = [[FIRVectorValue alloc] initWithArray:numbers]; - stage = [[FIRFindNearestStageBridge alloc] initWithField:embeddingField - vectorValue:queryVector - distanceMeasure:distanceMeasure - limit:limit - distanceField:distanceField]; - } else { - if (error) - *error = parseError([NSString stringWithFormat:@"Unknown pipeline stage: %@", stageName]); - return nil; - } - } - - if (stage) [stageBridges addObject:stage]; - } - - if (stageBridges.count == 0) { - if (error && !*error) *error = parseError(@"No valid stages"); - return nil; - } - - return stageBridges; -} - -+ (FIRAggregateFunctionBridge *)aggregateFunctionFromMap:(NSDictionary *)funcMap - exprParser:(FLTPipelineExpressionParser *)exprParser - error:(NSError **)error { - NSString *name = funcMap[@"name"]; - if (![name isKindOfClass:[NSString class]]) { - if (error) *error = parseError(@"Aggregate function must have a 'name'"); - return nil; - } - // Map Dart aggregate function names to iOS SDK names (count_all -> count with no args; minimum -> - // min; maximum -> max) - NSString *iosName = name; - if ([name isEqualToString:@"count_all"]) { - iosName = @"count"; - } else if ([name isEqualToString:@"minimum"]) { - iosName = @"min"; - } else if ([name isEqualToString:@"maximum"]) { - iosName = @"max"; - } - NSDictionary *argsDict = funcMap[@"args"]; - NSMutableArray *argsArray = [NSMutableArray array]; - if ([argsDict isKindOfClass:[NSDictionary class]]) { - id exprMap = argsDict[@"expression"]; - if ([exprMap isKindOfClass:[NSDictionary class]]) { - FIRExprBridge *expr = [exprParser parseExpression:exprMap error:error]; - if (!expr) return nil; - [argsArray addObject:expr]; - } - } - return [[FIRAggregateFunctionBridge alloc] initWithName:iosName Args:argsArray]; -} - -+ (FIRStageBridge *)parseAggregateStageWithArgs:(NSDictionary *)args - exprParser:(FLTPipelineExpressionParser *)exprParser - error:(NSError **)error { - NSArray *accumulatorMaps = args[@"aggregate_functions"]; - if (![accumulatorMaps isKindOfClass:[NSArray class]] || accumulatorMaps.count == 0) { - if (error) *error = parseError(@"aggregate requires aggregate_functions"); - return nil; - } - return [self parseAggregateStageWithAccumulatorMaps:accumulatorMaps - groupMaps:nil - exprParser:exprParser - error:error]; -} - -+ (FIRStageBridge *)parseAggregateStageWithOptionsArgs:(NSDictionary *)args - exprParser:(FLTPipelineExpressionParser *)exprParser - error:(NSError **)error { - NSDictionary *stageMap = args[@"aggregate_stage"]; - if (![stageMap isKindOfClass:[NSDictionary class]]) { - if (error) *error = parseError(@"aggregate_with_options requires aggregate_stage"); - return nil; - } - NSArray *accumulatorMaps = stageMap[@"accumulators"]; - if (![accumulatorMaps isKindOfClass:[NSArray class]] || accumulatorMaps.count == 0) { - accumulatorMaps = stageMap[@"aggregate_functions"]; - } - if (![accumulatorMaps isKindOfClass:[NSArray class]] || accumulatorMaps.count == 0) { - if (error) *error = parseError(@"aggregate_stage requires accumulators or aggregate_functions"); - return nil; - } - NSArray *groupMaps = stageMap[@"groups"]; - return [self parseAggregateStageWithAccumulatorMaps:accumulatorMaps - groupMaps:groupMaps - exprParser:exprParser - error:error]; -} - -+ (FIRStageBridge *)parseAggregateStageWithAccumulatorMaps:(NSArray *)accumulatorMaps - groupMaps:(nullable NSArray *)groupMaps - exprParser:(FLTPipelineExpressionParser *)exprParser - error:(NSError **)error { - NSError *parseErr = nil; - NSMutableDictionary *accumulators = - [NSMutableDictionary dictionary]; - for (id accMap in accumulatorMaps) { - if (![accMap isKindOfClass:[NSDictionary class]]) continue; - NSString *alias = nil; - NSDictionary *funcMap = nil; - if ([accMap[@"name"] isEqualToString:@"alias"]) { - NSDictionary *accArgs = accMap[@"args"]; - if (![accArgs isKindOfClass:[NSDictionary class]]) continue; - alias = accArgs[@"alias"]; - funcMap = accArgs[@"aggregate_function"]; - } - if (![alias isKindOfClass:[NSString class]] || ![funcMap isKindOfClass:[NSDictionary class]]) { - if (error) *error = parseError(@"Each accumulator must have alias and aggregate_function"); - return nil; - } - FIRAggregateFunctionBridge *func = [self aggregateFunctionFromMap:funcMap - exprParser:exprParser - error:&parseErr]; - if (!func) { - if (error) *error = parseErr; - return nil; - } - accumulators[alias] = func; - } - if (accumulators.count == 0) { - if (error) *error = parseError(@"aggregate requires at least one valid accumulator"); - return nil; - } - - NSMutableDictionary *groups = [NSMutableDictionary dictionary]; - if ([groupMaps isKindOfClass:[NSArray class]] && groupMaps.count > 0) { - for (NSUInteger g = 0; g < groupMaps.count; g++) { - id gm = groupMaps[g]; - if (![gm isKindOfClass:[NSDictionary class]]) continue; - FIRExprBridge *expr = [exprParser parseExpression:gm error:&parseErr]; - if (!expr) continue; - NSError *groupKeyError = nil; - NSString *groupKey = [self keyForExpressionMap:gm error:&groupKeyError]; - if (![groupKey isKindOfClass:[NSString class]] || groupKey.length == 0) { - if (error) - *error = - groupKeyError - ?: parseError( - @"aggregate group expression must be a field reference or have an alias"); - return nil; - } - groups[groupKey] = expr; - } - } - - return [[FIRAggregateStageBridge alloc] initWithAccumulators:accumulators groups:groups]; -} - -+ (void)executePipelineWithFirestore:(FIRFirestore *)firestore - stages:(NSArray *> *)stages - options:(nullable NSDictionary *)options - completion:(void (^)(id _Nullable snapshot, - NSError *_Nullable error))completion { - if (!stages || stages.count == 0) { - completion(nil, parseError(@"Pipeline requires at least one stage")); - return; - } - - NSError *parseErr = nil; - NSArray *stageBridges = [self parseStagesWithFirestore:firestore - stages:stages - error:&parseErr]; - if (!stageBridges) { - completion(nil, parseErr); - return; - } - - FIRPipelineBridge *pipeline = [[FIRPipelineBridge alloc] initWithStages:stageBridges - db:firestore]; - [pipeline executeWithCompletion:^(id snapshot, NSError *execError) { - if (execError) { - completion(nil, execError); - return; - } - completion(snapshot, nil); - }]; -} - -+ (id)buildPipelineWithFirestore:(FIRFirestore *)firestore - stages:(NSArray *> *)stages - error:(NSError **)error { - NSArray *stageBridges = [self parseStagesWithFirestore:firestore - stages:stages - error:error]; - if (!stageBridges) return nil; - return [[FIRPipelineBridge alloc] initWithStages:stageBridges db:firestore]; -} - -@end - -#else - -@implementation FLTPipelineParser - -+ (void)executePipelineWithFirestore:(FIRFirestore *)firestore - stages:(NSArray *> *)stages - options:(nullable NSDictionary *)options - completion:(void (^)(id _Nullable snapshot, - NSError *_Nullable error))completion { - completion(nil, pipelineUnavailableError()); -} - -@end - -#endif diff --git a/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/FLTQuerySnapshotStreamHandler.m b/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/FLTQuerySnapshotStreamHandler.m deleted file mode 100644 index a821cc35e94f..000000000000 --- a/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/FLTQuerySnapshotStreamHandler.m +++ /dev/null @@ -1,102 +0,0 @@ -// Copyright 2021 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -@import FirebaseFirestore; -#if __has_include() -#import -#else -#import -#endif - -#import "include/cloud_firestore/Private/FLTFirebaseFirestoreUtils.h" -#import "include/cloud_firestore/Private/FLTQuerySnapshotStreamHandler.h" -#import "include/cloud_firestore/Private/FirestorePigeonParser.h" -#import "include/cloud_firestore/Public/CustomPigeonHeaderFirestore.h" - -@interface FLTQuerySnapshotStreamHandler () -@property(readwrite, strong) id listenerRegistration; -@property(nonatomic) dispatch_queue_t snapshotQueue; -@end - -@implementation FLTQuerySnapshotStreamHandler - -- (instancetype)initWithFirestore:(FIRFirestore *)firestore - query:(FIRQuery *)query - includeMetadataChanges:(BOOL)includeMetadataChanges - serverTimestampBehavior:(FIRServerTimestampBehavior)serverTimestampBehavior - source:(FIRListenSource)source { - self = [super init]; - if (self) { - _firestore = firestore; - _query = query; - _includeMetadataChanges = includeMetadataChanges; - _serverTimestampBehavior = serverTimestampBehavior; - _source = source; - _snapshotQueue = dispatch_queue_create("io.flutter.plugins.firebase.firestore.query_snapshot", - DISPATCH_QUEUE_SERIAL); - } - return self; -} - -- (FlutterError *_Nullable)onListenWithArguments:(id _Nullable)arguments - eventSink:(nonnull FlutterEventSink)events { - FIRQuery *query = self.query; - - if (query == nil) { - return [FlutterError - errorWithCode:@"sdk-error" - message:@"An error occurred while parsing query arguments, see native logs for more " - @"information. Please report this issue." - details:nil]; - } - - id listener = ^(FIRQuerySnapshot *_Nullable snapshot, NSError *_Nullable error) { - if (error) { - NSArray *codeAndMessage = [FLTFirebaseFirestoreUtils ErrorCodeAndMessageFromNSError:error]; - NSString *code = codeAndMessage[0]; - NSString *message = codeAndMessage[1]; - NSDictionary *details = @{ - @"code" : code, - @"message" : message, - }; - dispatch_async(dispatch_get_main_queue(), ^{ - events([FLTFirebasePlugin createFlutterErrorFromCode:code - message:message - optionalDetails:details - andOptionalNSError:error]); - }); - } else { - dispatch_async(self.snapshotQueue, ^{ - // Emit the Pigeon object directly; the Pigeon-aware codec serializes nested - // `InternalDocumentSnapshot` / `InternalDocumentChange` / `InternalSnapshotMetadata` - // with their proper type codes. Pigeon 26 no longer flattens nested types - // via `toList`. - InternalQuerySnapshot *pigeonSnapshot = - [FirestorePigeonParser toPigeonQuerySnapshot:snapshot - serverTimestampBehavior:self.serverTimestampBehavior]; - dispatch_async(dispatch_get_main_queue(), ^{ - events(pigeonSnapshot); - }); - }); - } - }; - - FIRSnapshotListenOptions *options = [[FIRSnapshotListenOptions alloc] init]; - FIRSnapshotListenOptions *optionsWithSourceAndMetadata = [[options - optionsWithIncludeMetadataChanges:_includeMetadataChanges] optionsWithSource:_source]; - - self.listenerRegistration = [query addSnapshotListenerWithOptions:optionsWithSourceAndMetadata - listener:listener]; - - return nil; -} - -- (FlutterError *_Nullable)onCancelWithArguments:(id _Nullable)arguments { - [self.listenerRegistration remove]; - self.listenerRegistration = nil; - - return nil; -} - -@end diff --git a/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/FLTSnapshotsInSyncStreamHandler.m b/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/FLTSnapshotsInSyncStreamHandler.m deleted file mode 100644 index 1003be610006..000000000000 --- a/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/FLTSnapshotsInSyncStreamHandler.m +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2021 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -@import FirebaseFirestore; - -#import "include/cloud_firestore/Private/FLTSnapshotsInSyncStreamHandler.h" -#import "include/cloud_firestore/Private/FLTFirebaseFirestoreUtils.h" - -@interface FLTSnapshotsInSyncStreamHandler () -@property(readwrite, strong) id listenerRegistration; -@end - -@implementation FLTSnapshotsInSyncStreamHandler - -- (nonnull instancetype)initWithFirestore:(nonnull FIRFirestore *)firestore { - self = [super init]; - if (self) { - _firestore = firestore; - } - return self; -} - -- (FlutterError *_Nullable)onListenWithArguments:(id _Nullable)arguments - eventSink:(nonnull FlutterEventSink)events { - id listener = ^() { - dispatch_async(dispatch_get_main_queue(), ^{ - events(nil); - }); - }; - - self.listenerRegistration = [_firestore addSnapshotsInSyncListener:listener]; - - return nil; -} - -- (FlutterError *_Nullable)onCancelWithArguments:(id _Nullable)arguments { - [self.listenerRegistration remove]; - self.listenerRegistration = nil; - - return nil; -} - -@end diff --git a/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/FLTTransactionStreamHandler.m b/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/FLTTransactionStreamHandler.m deleted file mode 100644 index 8cd347b0b269..000000000000 --- a/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/FLTTransactionStreamHandler.m +++ /dev/null @@ -1,167 +0,0 @@ -// Copyright 2021 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -@import FirebaseFirestore; -#if __has_include() -#import -#else -#import -#endif - -#import "include/cloud_firestore/Private/FLTFirebaseFirestoreUtils.h" -#import "include/cloud_firestore/Private/FLTTransactionStreamHandler.h" -#import "include/cloud_firestore/Private/FirestorePigeonParser.h" - -@interface FLTTransactionStreamHandler () -@property(nonatomic, copy, nonnull) void (^started)(FIRTransaction *); -@property(nonatomic, copy, nonnull) void (^ended)(void); -@property(strong) dispatch_semaphore_t semaphore; -@property InternalTransactionResult resultType; -@property NSArray *commands; - -@end - -@implementation FLTTransactionStreamHandler { - NSString *_transactionId; -} - -- (instancetype)initWithId:(NSString *)transactionId - firestore:(FIRFirestore *)firestore - timeout:(NSInteger)timeout - maxAttempts:(NSInteger)maxAttempts - started:(void (^)(FIRTransaction *))startedListener - ended:(void (^)(void))endedListener { - self = [super init]; - if (self) { - _transactionId = transactionId; - self.firestore = firestore; - self.maxAttempts = maxAttempts; - self.timeout = timeout; - self.started = startedListener; - self.ended = endedListener; - self.semaphore = dispatch_semaphore_create(0); - } - return self; -} - -- (FlutterError *_Nullable)onListenWithArguments:(id _Nullable)arguments - eventSink:(nonnull FlutterEventSink)events { - __weak FLTTransactionStreamHandler *weakSelf = self; - - id transactionRunBlock = ^id(FIRTransaction *transaction, NSError **pError) { - FLTTransactionStreamHandler *strongSelf = weakSelf; - - strongSelf.started(transaction); - - dispatch_async(dispatch_get_main_queue(), ^{ - events( - @{@"appName" : [FLTFirebasePlugin firebaseAppNameFromIosName:self.firestore.app.name]}); - }); - - long timedOut = dispatch_semaphore_wait( - strongSelf.semaphore, dispatch_time(DISPATCH_TIME_NOW, self.timeout * NSEC_PER_MSEC)); - - if (timedOut) { - NSArray *codeAndMessage = [FLTFirebaseFirestoreUtils - ErrorCodeAndMessageFromNSError:[NSError - errorWithDomain:FIRFirestoreErrorDomain - code:FIRFirestoreErrorCodeDeadlineExceeded - userInfo:@{}]]; - - dispatch_async(dispatch_get_main_queue(), ^{ - events(@{ - @"error" : @{ - @"code" : codeAndMessage[0], - @"message" : codeAndMessage[1], - } - }); - }); - } - - if (self.resultType == InternalTransactionResultFailure) { - // Do nothing - already handled in Dart land. - return nil; - } - - for (InternalTransactionCommand *command in self.commands) { - InternalTransactionType commandType = command.type; - NSString *documentPath = command.path; - FIRDocumentReference *reference = [self.firestore documentWithPath:documentPath]; - - switch (commandType) { - case InternalTransactionTypeDeleteType: - [transaction deleteDocument:reference]; - break; - case InternalTransactionTypeUpdate: - [transaction updateData:command.data forDocument:reference]; - break; - case InternalTransactionTypeSet: - if ([command.option.merge isEqual:@YES]) { - [transaction setData:command.data forDocument:reference merge:YES]; - } else if (command.option.mergeFields) { - [transaction setData:command.data - forDocument:reference - mergeFields:[FirestorePigeonParser parseFieldPath:command.option.mergeFields]]; - } else { - [transaction setData:command.data forDocument:reference]; - } - break; - default: - break; - } - } - - return nil; - }; - - id transactionCompleteBlock = ^(id transactionResult, NSError *error) { - FLTTransactionStreamHandler *strongSelf = weakSelf; - if (error) { - NSArray *details = [FLTFirebaseFirestoreUtils ErrorCodeAndMessageFromNSError:error]; - - dispatch_async(dispatch_get_main_queue(), ^{ - events(@{ - @"error" : @{ - @"code" : details[0], - @"message" : details[1], - } - }); - }); - } else { - dispatch_async(dispatch_get_main_queue(), ^{ - events(@{@"complete" : [NSNumber numberWithBool:YES]}); - }); - } - - dispatch_async(dispatch_get_main_queue(), ^{ - events(FlutterEndOfEventStream); - }); - - strongSelf.ended(); - }; - FIRTransactionOptions *options = [[FIRTransactionOptions alloc] init]; - options.maxAttempts = _maxAttempts; - - [_firestore runTransactionWithOptions:options - block:transactionRunBlock - completion:transactionCompleteBlock]; - - return nil; -} - -- (FlutterError *_Nullable)onCancelWithArguments:(id _Nullable)arguments { - dispatch_semaphore_signal(self.semaphore); - - return nil; -} - -- (void)receiveTransactionResponse:(InternalTransactionResult)resultType - commands:(NSArray *)commands { - self.resultType = resultType; - self.commands = commands; - - dispatch_semaphore_signal(self.semaphore); -} - -@end diff --git a/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/FirebaseFirestoreExtension.swift b/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/FirebaseFirestoreExtension.swift new file mode 100644 index 000000000000..28820e1a2973 --- /dev/null +++ b/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/FirebaseFirestoreExtension.swift @@ -0,0 +1,16 @@ +// Copyright 2023 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import FirebaseFirestore +import Foundation + +final class FirebaseFirestoreExtension { + let instance: Firestore + let databaseURL: String + + init(firestoreInstance firestore: Firestore, databaseURL: String) { + instance = firestore + self.databaseURL = databaseURL + } +} diff --git a/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/FirebaseFirestoreReader.swift b/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/FirebaseFirestoreReader.swift new file mode 100644 index 000000000000..c27d0bee4e0e --- /dev/null +++ b/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/FirebaseFirestoreReader.swift @@ -0,0 +1,312 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import FirebaseCore +import FirebaseFirestore +import Foundation + +#if canImport(firebase_core) + import firebase_core +#else + import firebase_core_shared +#endif + +#if os(iOS) + import Flutter +#elseif os(macOS) + import FlutterMacOS +#endif + +class FirebaseFirestoreReader: FlutterStandardReader { + static let firestoreQueue = DispatchQueue(label: "dev.flutter.firebase.firestore") + + override func readValue(ofType type: UInt8) -> Any? { + switch type { + case FirestoreDataType.dateTime.rawValue: + var value: Int64 = 0 + readBytes(&value, length: 8) + return Date(timeIntervalSince1970: Double(value) / 1000.0) + case FirestoreDataType.timestamp.rawValue: + var seconds: Int64 = 0 + var nanoseconds: Int32 = 0 + readBytes(&seconds, length: 8) + readBytes(&nanoseconds, length: 4) + return Timestamp(seconds: seconds, nanoseconds: nanoseconds) + case FirestoreDataType.geoPoint.rawValue: + var latitude: Double = 0 + var longitude: Double = 0 + readAlignment(8) + readBytes(&latitude, length: 8) + readBytes(&longitude, length: 8) + return GeoPoint(latitude: latitude, longitude: longitude) + case FirestoreDataType.vectorValue.rawValue: + return VectorValue((readValue() as? [NSNumber] ?? []).map(\.doubleValue)) + case FirestoreDataType.documentReference.rawValue: + let firestore = readValue() as! Firestore + let documentPath = readValue() as! String + return firestore.document(documentPath) + case FirestoreDataType.fieldPath.rawValue: + let length = readSize() + var array: [Any] = [] + array.reserveCapacity(Int(length)) + for _ in 0.. FirestoreSettings { + let values = readValue() as! [String: Any] + let settings = FirestoreSettings() + + if let persistenceEnabled = values["persistenceEnabled"], !(persistenceEnabled is NSNull) { + let persistEnabled = (persistenceEnabled as! NSNumber).boolValue + var size = NSNumber(value: FirestoreCacheSizeUnlimited) + if let cacheSizeBytes = values["cacheSizeBytes"], !(cacheSizeBytes is NSNull) { + let cacheSize = cacheSizeBytes as! NSNumber + if cacheSize.intValue != -1 { + size = cacheSize + } + } + if persistEnabled { + settings.cacheSettings = PersistentCacheSettings(sizeBytes: size) + } else { + settings.cacheSettings = MemoryCacheSettings( + garbageCollectorSettings: MemoryLRUGCSettings() + ) + } + } + + if let host = values["host"] as? String { + settings.host = host + if let sslEnabled = values["sslEnabled"], !(sslEnabled is NSNull) { + settings.isSSLEnabled = (sslEnabled as! NSNumber).boolValue + } + } + + settings.dispatchQueue = FirebaseFirestoreReader.firestoreQueue + return settings + } + + private func filterFromJson(_ map: [String: Any]?) throws -> Filter { + guard let map else { + throw PigeonParser.queryParseError("Invalid operator") + } + + if map["fieldPath"] != nil { + guard let op = map["op"] as? String else { + throw PigeonParser.queryParseError("Filter is missing an operator") + } + guard let fieldPath = map["fieldPath"] as? FieldPath else { + throw PigeonParser.queryParseError("Filter is missing a field path") + } + let value = map["value"] as Any + switch op { + case "==": + return Filter.whereField(fieldPath, isEqualTo: value) + case "!=": + return Filter.whereField(fieldPath, isNotEqualTo: value) + case "<": + return Filter.whereField(fieldPath, isLessThan: value) + case "<=": + return Filter.whereField(fieldPath, isLessThanOrEqualTo: value) + case ">": + return Filter.whereField(fieldPath, isGreaterThan: value) + case ">=": + return Filter.whereField(fieldPath, isGreaterOrEqualTo: value) + case "array-contains": + return Filter.whereField(fieldPath, arrayContains: value) + case "array-contains-any": + return Filter.whereField(fieldPath, arrayContainsAny: value as? [Any] ?? []) + case "in": + return Filter.whereField(fieldPath, in: value as? [Any] ?? []) + case "not-in": + return Filter.whereField(fieldPath, notIn: value as? [Any] ?? []) + default: + throw PigeonParser.queryParseError("Invalid operator") + } + } + + guard let op = map["op"] as? String else { + throw PigeonParser.queryParseError("Compound filter is missing an operator") + } + guard let queries = map["queries"] as? [[String: Any]] else { + throw PigeonParser.queryParseError("Compound filter is missing queries") + } + let parsedFilters = try queries.map { try filterFromJson($0) } + + if op == "OR" { + return Filter.orFilter(parsedFilters) + } + if op == "AND" { + return Filter.andFilter(parsedFilters) + } + + throw PigeonParser.queryParseError("Invalid operator") + } + + private func readQuery() -> Query? { + do { + let values = readValue() as! [String: Any] + let firestore = values["firestore"] as! Firestore + let parameters = values["parameters"] as! [String: Any] + let whereConditions = parameters["where"] as? [Any] ?? [] + let isCollectionGroup = (values["isCollectionGroup"] as! NSNumber).boolValue + let path = values["path"] as! String + + var query: Query + if isCollectionGroup { + query = firestore.collectionGroup(path) + } else { + query = firestore.collection(path) + } + + if let filters = parameters["filters"] as? [String: Any] { + query = try query.whereFilter(filterFromJson(filters)) + } + + for item in whereConditions { + guard let condition = item as? [Any], condition.count >= 3, + let fieldPath = condition[0] as? FieldPath, + let op = condition[1] as? String + else { + throw PigeonParser.queryParseError("Invalid query condition") + } + let value = condition[2] + switch op { + case "==": + query = query.whereField(fieldPath, isEqualTo: value as Any) + case "!=": + query = query.whereField(fieldPath, isNotEqualTo: value as Any) + case "<": + query = query.whereField(fieldPath, isLessThan: value as Any) + case "<=": + query = query.whereField(fieldPath, isLessThanOrEqualTo: value as Any) + case ">": + query = query.whereField(fieldPath, isGreaterThan: value as Any) + case ">=": + query = query.whereField(fieldPath, isGreaterThanOrEqualTo: value as Any) + case "array-contains": + query = query.whereField(fieldPath, arrayContains: value as Any) + case "array-contains-any": + query = query.whereField(fieldPath, arrayContainsAny: value as? [Any] ?? []) + case "in": + query = query.whereField(fieldPath, in: value as? [Any] ?? []) + case "not-in": + query = query.whereField(fieldPath, notIn: value as? [Any] ?? []) + default: + NSLog( + "FLTFirebaseFirestore: An invalid query operator %@ was received but not handled.", op + ) + } + } + + if let limit = parameters["limit"], !(limit is NSNull) { + query = query.limit(to: (limit as! NSNumber).intValue) + } + if let limitToLast = parameters["limitToLast"], !(limitToLast is NSNull) { + query = query.limit(toLast: (limitToLast as! NSNumber).intValue) + } + + let orderBy = parameters["orderBy"] + if orderBy is NSNull || orderBy == nil { + return query + } + + guard let orderByEntries = orderBy as? [[Any]] else { + throw PigeonParser.queryParseError("Invalid orderBy parameters") + } + for orderByEntry in orderByEntries { + guard orderByEntry.count >= 2, let fieldPath = orderByEntry[0] as? FieldPath else { + throw PigeonParser.queryParseError("Invalid orderBy field path") + } + let descending: Bool + if let number = orderByEntry[1] as? NSNumber { + descending = number.boolValue + } else if let boolValue = orderByEntry[1] as? Bool { + descending = boolValue + } else { + throw PigeonParser.queryParseError("Invalid orderBy direction") + } + query = query.order(by: fieldPath, descending: descending) + } + + if let startAt = parameters["startAt"], !(startAt is NSNull) { + query = query.start(at: startAt as! [Any]) + } + if let startAfter = parameters["startAfter"], !(startAfter is NSNull) { + query = query.start(after: startAfter as! [Any]) + } + if let endAt = parameters["endAt"], !(endAt is NSNull) { + query = query.end(at: endAt as! [Any]) + } + if let endBefore = parameters["endBefore"], !(endBefore is NSNull) { + query = query.end(before: endBefore as! [Any]) + } + + return query + } catch { + NSLog( + "An error occurred while parsing query arguments, this is most likely an error with this SDK. %@", + error.localizedDescription + ) + return nil + } + } + + private func readFirestore() -> Firestore { + objc_sync_enter(self) + defer { objc_sync_exit(self) } + + let appNameDart = readValue() as! String + let databaseUrl = readValue() as! String + let settings = readValue() as! FirestoreSettings + let app = FLTFirebasePlugin.firebaseAppNamed(appNameDart)! + + if let cached = FirebaseFirestoreUtils.firestoreInstance( + appName: app.name, databaseURL: databaseUrl + ) { + return cached + } + + let firestore = Firestore.firestore(app: app, database: databaseUrl) + firestore.settings = settings + FirebaseFirestoreUtils.setCachedInstance( + firestore, appName: app.name, databaseURL: databaseUrl + ) + return firestore + } +} diff --git a/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/FirebaseFirestoreUtils.swift b/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/FirebaseFirestoreUtils.swift new file mode 100644 index 000000000000..58a1e4cd1e54 --- /dev/null +++ b/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/FirebaseFirestoreUtils.swift @@ -0,0 +1,223 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import FirebaseFirestore +import Foundation + +#if os(iOS) + import Flutter +#elseif os(macOS) + import FlutterMacOS +#endif + +enum FirestoreDataType: UInt8 { + case dateTime = 180 + case geoPoint = 181 + case documentReference = 182 + case blob = 183 + case arrayUnion = 184 + case arrayRemove = 185 + case delete = 186 + case serverTimestamp = 187 + case timestamp = 188 + case incrementDouble = 189 + case incrementInteger = 190 + case documentId = 191 + case fieldPath = 192 + case nan = 193 + case infinity = 194 + case negativeInfinity = 195 + case firestoreInstance = 196 + case firestoreQuery = 197 + case firestoreSettings = 198 + case vectorValue = 199 +} + +enum FirebaseFirestoreUtils { + static let pipelineParseErrorCode: Int = -1 + static let errorDomain = "FLTFirebaseFirestore" + + private static let cacheLock = NSLock() + private static var firestoreInstanceCache: [String: FirebaseFirestoreExtension] = [:] + + private static func key(appName: String, databaseURL: String) -> String { + "\(appName)|\(databaseURL)" + } + + static func cachedInstance(appName: String, databaseURL: String) -> FirebaseFirestoreExtension? { + cacheLock.lock() + defer { cacheLock.unlock() } + return firestoreInstanceCache[key(appName: appName, databaseURL: databaseURL)] + } + + static func setCachedInstance(_ firestore: Firestore, appName: String, databaseURL: String) { + cacheLock.lock() + defer { cacheLock.unlock() } + firestoreInstanceCache[key(appName: appName, databaseURL: databaseURL)] = + FirebaseFirestoreExtension(firestoreInstance: firestore, databaseURL: databaseURL) + } + + static func destroyCachedInstance(appName: String, databaseURL: String) { + cacheLock.lock() + defer { cacheLock.unlock() } + firestoreInstanceCache.removeValue(forKey: key(appName: appName, databaseURL: databaseURL)) + } + + static func firestoreInstance(appName: String, databaseURL: String) -> Firestore? { + cachedInstance(appName: appName, databaseURL: databaseURL)?.instance + } + + static var count: Int { + cacheLock.lock() + defer { cacheLock.unlock() } + return firestoreInstanceCache.count + } + + static func cachedInstance(for firestore: Firestore) -> FirebaseFirestoreExtension { + cacheLock.lock() + defer { cacheLock.unlock() } + if let match = firestoreInstanceCache.values.first(where: { $0.instance === firestore }) { + return match + } + NSException( + name: NSExceptionName("NoCachedInstance"), + reason: "No cached instance of Firestore", + userInfo: nil + ).raise() + fatalError("No cached instance of Firestore") + } + + static func cleanupFirestoreInstances(_ completion: (() -> Void)?) { + cacheLock.lock() + let entries = Array(firestoreInstanceCache.values) + cacheLock.unlock() + + let numberOfInstances = entries.count + if numberOfInstances == 0 { + completion?() + return + } + + var instancesTerminated = 0 + for extensionInstance in entries { + let firestore = extensionInstance.instance + DispatchQueue.global(qos: .userInitiated).async { + firestore.terminate { _ in + destroyCachedInstance( + appName: firestore.app.name, databaseURL: extensionInstance.databaseURL + ) + instancesTerminated += 1 + if instancesTerminated == numberOfInstances { + completion?() + } + } + } + } + } + + static func errorCodeAndMessage(from error: Error?) -> (String, String) { + var code = "unknown" + var message = "An unknown error has occurred." + + guard let error = error as NSError? else { + return (code, message) + } + + switch error.code { + case FirestoreErrorCode.aborted.rawValue: + code = "aborted" + message = + "The operation was aborted, typically due to a concurrency issue like transaction aborts, etc." + case FirestoreErrorCode.alreadyExists.rawValue: + code = "already-exists" + message = "Some document that we attempted to create already exists." + case FirestoreErrorCode.cancelled.rawValue: + code = "cancelled" + message = "The operation was cancelled (typically by the caller)." + case FirestoreErrorCode.dataLoss.rawValue: + code = "data-loss" + message = "Unrecoverable data loss or corruption." + case FirestoreErrorCode.deadlineExceeded.rawValue: + code = "deadline-exceeded" + message = + "Deadline expired before operation could complete. For operations that change the state of the system, this error may be returned even if the operation has completed successfully. For example, a successful response from a server could have been delayed long enough for the deadline to expire." + case FirestoreErrorCode.failedPrecondition.rawValue: + code = "failed-precondition" + if error.localizedDescription.contains("index") { + message = error.localizedDescription + } else { + message = + "Operation was rejected because the system is not in a state required for the operation's execution. If performing a query, ensure it has been indexed via the Firebase console." + } + case FirestoreErrorCode.internal.rawValue: + code = "internal" + message = + "Internal errors. Means some invariants expected by underlying system has been broken. If you see one of these errors, something is very broken." + case FirestoreErrorCode.invalidArgument.rawValue: + code = "invalid-argument" + message = + "Client specified an invalid argument. Note that this differs from failed-precondition. invalid-argument indicates arguments that are problematic regardless of the state of the system (e.g., an invalid field name)." + case FirestoreErrorCode.notFound.rawValue: + code = "not-found" + message = "Some requested document was not found." + case FirestoreErrorCode.outOfRange.rawValue: + code = "out-of-range" + message = "Operation was attempted past the valid range." + case FirestoreErrorCode.permissionDenied.rawValue: + code = "permission-denied" + message = "The caller does not have permission to execute the specified operation." + case FirestoreErrorCode.resourceExhausted.rawValue: + code = "resource-exhausted" + message = + "Some resource has been exhausted, perhaps a per-user quota, or perhaps the entire file system is out of space." + case FirestoreErrorCode.unauthenticated.rawValue: + code = "unauthenticated" + message = "The request does not have valid authentication credentials for the operation." + case FirestoreErrorCode.unavailable.rawValue: + code = "unavailable" + message = + "The service is currently unavailable. This is a most likely a transient condition and may be corrected by retrying with a backoff." + case FirestoreErrorCode.unimplemented.rawValue: + code = "unimplemented" + message = "Operation is not implemented or not supported/enabled." + case FirestoreErrorCode.unknown.rawValue: + code = "unknown" + message = "Unknown error or an error from a different error domain." + case pipelineParseErrorCode: + code = "parse-error" + message = + error.localizedDescription.isEmpty + ? "An unknown error occurred." : error.localizedDescription + default: + code = "unknown" + message = "An unknown error occurred." + } + + if !error.localizedDescription.isEmpty { + message = error.localizedDescription + } + + return (code, message) + } + + static func flutterError(from error: Error) -> FlutterError { + let (code, message) = errorCodeAndMessage(from: error) + return FlutterError( + code: code, + message: message, + details: [ + "code": code, + "message": message, + ] + ) + } + + static func parseError(_ message: String) -> NSError { + NSError( + domain: errorDomain, + code: pipelineParseErrorCode, + userInfo: [NSLocalizedDescriptionKey: message] + ) + } +} diff --git a/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/FirebaseFirestoreWriter.swift b/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/FirebaseFirestoreWriter.swift new file mode 100644 index 000000000000..3fe2f5ffc528 --- /dev/null +++ b/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/FirebaseFirestoreWriter.swift @@ -0,0 +1,222 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import FirebaseFirestore +import Foundation + +#if canImport(firebase_core) + import firebase_core +#else + import firebase_core_shared +#endif + +#if os(iOS) + import Flutter +#elseif os(macOS) + import FlutterMacOS +#endif + +private let kStandardFieldList: UInt8 = 12 +private let kStandardFieldMap: UInt8 = 13 + +class FirebaseFirestoreWriter: FlutterStandardWriter { + override func writeValue(_ value: Any) { + if let date = value as? Date { + writeByte(FirestoreDataType.dateTime.rawValue) + var ms = Int64(date.timeIntervalSince1970 * 1000.0) + writeBytes(&ms, length: 8) + } else if let timestamp = value as? Timestamp { + var seconds = timestamp.seconds + var nanoseconds = timestamp.nanoseconds + writeByte(FirestoreDataType.timestamp.rawValue) + writeBytes(&seconds, length: 8) + writeBytes(&nanoseconds, length: 4) + } else if let geoPoint = value as? GeoPoint { + var latitude = geoPoint.latitude + var longitude = geoPoint.longitude + writeByte(FirestoreDataType.geoPoint.rawValue) + writeAlignment(8) + writeBytes(&latitude, length: 8) + writeBytes(&longitude, length: 8) + } else if let vector = value as? VectorValue { + writeByte(FirestoreDataType.vectorValue.rawValue) + writeValue(vector.array) + } else if let document = value as? DocumentReference { + writeByte(FirestoreDataType.documentReference.rawValue) + writeValue(FLTFirebasePlugin.firebaseAppName(fromIosName: document.firestore.app.name)) + writeValue(document.path) + let extensionInstance = FirebaseFirestoreUtils.cachedInstance(for: document.firestore) + writeValue(extensionInstance.databaseURL) + } else if let snapshot = value as? DocumentSnapshot { + writeValue(documentSnapshotMap(snapshot)) + } else if let progress = value as? LoadBundleTaskProgress { + writeValue(loadBundleTaskProgressMap(progress)) + } else if let snapshot = value as? QuerySnapshot { + writeValue(querySnapshotMap(snapshot)) + } else if let change = value as? DocumentChange { + writeValue(documentChangeMap(change)) + } else if let metadata = value as? SnapshotMetadata { + writeValue(snapshotMetadataMap(metadata)) + } else if let list = value as? [Any] { + writeByte(kStandardFieldList) + writeSize(UInt32(list.count)) + for item in list { + writeValue(item) + } + } else if let map = value as? [AnyHashable: Any] { + writeByte(kStandardFieldMap) + writeSize(UInt32(map.count)) + for (key, item) in map { + writeValue(key) + writeValue(item) + } + } else if let number = value as? NSNumber { + if number == NSNumber(value: Double.infinity) { + writeByte(FirestoreDataType.infinity.rawValue) + return + } + if number == NSNumber(value: -Double.infinity) { + writeByte(FirestoreDataType.negativeInfinity.rawValue) + return + } + if number.description.lowercased() == "nan" { + writeByte(FirestoreDataType.nan.rawValue) + return + } + super.writeValue(value) + } else if let blob = value as? Data { + writeByte(FirestoreDataType.blob.rawValue) + writeSize(UInt32(blob.count)) + write(blob) + } else { + super.writeValue(value) + } + } + + private func snapshotMetadataMap(_ snapshotMetadata: SnapshotMetadata) -> [String: Any] { + [ + "hasPendingWrites": snapshotMetadata.hasPendingWrites, + "isFromCache": snapshotMetadata.isFromCache, + ] + } + + private func documentChangeMap(_ documentChange: DocumentChange) -> [String: Any] { + let type: String + switch documentChange.type { + case .added: + type = "DocumentChangeType.added" + case .modified: + type = "DocumentChangeType.modified" + case .removed: + type = "DocumentChangeType.removed" + @unknown default: + type = "DocumentChangeType.modified" + } + + let maxVal = NSNotFound + let newIndex: Int + if documentChange.newIndex == NSNotFound || documentChange.newIndex == 4_294_967_295 + || documentChange.newIndex == maxVal + { + newIndex = -1 + } else { + newIndex = Int(documentChange.newIndex) + } + + let oldIndex: Int + if documentChange.oldIndex == NSNotFound || documentChange.oldIndex == 4_294_967_295 + || documentChange.oldIndex == maxVal + { + oldIndex = -1 + } else { + oldIndex = Int(documentChange.oldIndex) + } + + return [ + "type": type, + "data": documentChange.document.data(), + "path": documentChange.document.reference.path, + "oldIndex": oldIndex, + "newIndex": newIndex, + "metadata": documentChange.document.metadata, + ] + } + + private func serverTimestampBehavior(from string: String?) + -> FirebaseFirestore + .ServerTimestampBehavior + { + switch string { + case "estimate": + return .estimate + case "previous": + return .previous + default: + return .none + } + } + + private func documentSnapshotMap(_ documentSnapshot: DocumentSnapshot) -> [String: Any]? { + let hash = NSNumber(value: documentSnapshot.hash) + let timestampBehaviorString = + FLTFirebaseFirestorePlugin.serverTimestampMap.object(forKey: hash) as String? + let behavior = serverTimestampBehavior(from: timestampBehaviorString) + FLTFirebaseFirestorePlugin.serverTimestampMap.removeObject(forKey: hash) + + let data: Any = + documentSnapshot.exists + ? documentSnapshot.data(with: behavior) as Any : NSNull() + return [ + "path": documentSnapshot.reference.path, + "data": data, + "metadata": documentSnapshot.metadata, + ] + } + + private func loadBundleTaskProgressMap(_ progress: LoadBundleTaskProgress) -> [String: Any] { + let state: String + switch progress.state { + case .error: + state = "error" + case .success: + state = "success" + case .inProgress: + state = "running" + @unknown default: + state = "running" + } + return [ + "bytesLoaded": progress.bytesLoaded, + "documentsLoaded": progress.documentsLoaded, + "totalBytes": progress.totalBytes, + "totalDocuments": progress.totalDocuments, + "taskState": state, + ] + } + + private func querySnapshotMap(_ querySnapshot: QuerySnapshot) -> [String: Any]? { + let hash = NSNumber(value: querySnapshot.hash) + let timestampBehaviorString = + FLTFirebaseFirestorePlugin.serverTimestampMap.object(forKey: hash) as String? + let behavior = serverTimestampBehavior(from: timestampBehaviorString) + FLTFirebaseFirestorePlugin.serverTimestampMap.removeObject(forKey: hash) + + var paths: [String] = [] + var documents: [[String: Any]] = [] + var metadatas: [SnapshotMetadata] = [] + for document in querySnapshot.documents { + paths.append(document.reference.path) + documents.append(document.data(with: behavior) ?? [:]) + metadatas.append(document.metadata) + } + + return [ + "paths": paths, + "documentChanges": querySnapshot.documentChanges, + "documents": documents, + "metadatas": metadatas, + "metadata": querySnapshot.metadata, + ] + } +} diff --git a/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/FirestoreMessages.g.m b/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/FirestoreMessages.g.m deleted file mode 100644 index f9594c6e943f..000000000000 --- a/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/FirestoreMessages.g.m +++ /dev/null @@ -1,2033 +0,0 @@ -// Copyright 2023, the Chromium project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. -// Autogenerated from Pigeon (v26.3.4), do not edit directly. -// See also: https://pub.dev/packages/pigeon - -#import "FirestoreMessages.g.h" -#import "FLTFirebaseFirestoreReader.h" -#import "FLTFirebaseFirestoreWriter.h" - -#if TARGET_OS_OSX -@import FlutterMacOS; -#else -@import Flutter; -#endif - -static BOOL __attribute__((unused)) FLTPigeonDeepEquals(id _Nullable a, id _Nullable b) { - if (a == b) { - return YES; - } - if (a == nil) { - return b == [NSNull null]; - } - if (b == nil) { - return a == [NSNull null]; - } - if ([a isKindOfClass:[NSNumber class]] && [b isKindOfClass:[NSNumber class]]) { - return - [a isEqual:b] || (isnan([(NSNumber *)a doubleValue]) && isnan([(NSNumber *)b doubleValue])); - } - if ([a isKindOfClass:[NSArray class]] && [b isKindOfClass:[NSArray class]]) { - NSArray *arrayA = (NSArray *)a; - NSArray *arrayB = (NSArray *)b; - if (arrayA.count != arrayB.count) { - return NO; - } - for (NSUInteger i = 0; i < arrayA.count; i++) { - if (!FLTPigeonDeepEquals(arrayA[i], arrayB[i])) { - return NO; - } - } - return YES; - } - if ([a isKindOfClass:[NSDictionary class]] && [b isKindOfClass:[NSDictionary class]]) { - NSDictionary *dictA = (NSDictionary *)a; - NSDictionary *dictB = (NSDictionary *)b; - if (dictA.count != dictB.count) { - return NO; - } - for (id keyA in dictA) { - id valueA = dictA[keyA]; - BOOL found = NO; - for (id keyB in dictB) { - if (FLTPigeonDeepEquals(keyA, keyB)) { - id valueB = dictB[keyB]; - if (FLTPigeonDeepEquals(valueA, valueB)) { - found = YES; - break; - } else { - return NO; - } - } - } - if (!found) { - return NO; - } - } - return YES; - } - return [a isEqual:b]; -} - -static NSUInteger __attribute__((unused)) FLTPigeonDeepHash(id _Nullable value) { - if (value == nil || value == (id)[NSNull null]) { - return 0; - } - if ([value isKindOfClass:[NSNumber class]]) { - NSNumber *n = (NSNumber *)value; - double d = n.doubleValue; - if (isnan(d)) { - // Normalize NaN to a consistent hash. - return (NSUInteger)0x7FF8000000000000; - } - if (d == 0.0) { - // Normalize -0.0 to 0.0 so they have the same hash code. - d = 0.0; - } - return @(d).hash; - } - if ([value isKindOfClass:[NSArray class]]) { - NSUInteger result = 1; - for (id item in (NSArray *)value) { - result = result * 31 + FLTPigeonDeepHash(item); - } - return result; - } - if ([value isKindOfClass:[NSDictionary class]]) { - NSUInteger result = 0; - NSDictionary *dict = (NSDictionary *)value; - for (id key in dict) { - result += ((FLTPigeonDeepHash(key) * 31) ^ FLTPigeonDeepHash(dict[key])); - } - return result; - } - return [value hash]; -} - -static NSArray *wrapResult(id result, FlutterError *error) { - if (error) { - return @[ - error.code ?: [NSNull null], error.message ?: [NSNull null], error.details ?: [NSNull null] - ]; - } - return @[ result ?: [NSNull null] ]; -} - -static id GetNullableObjectAtIndex(NSArray *array, NSInteger key) { - id result = array[key]; - return (result == [NSNull null]) ? nil : result; -} - -/// An enumeration of document change types. -@implementation DocumentChangeTypeBox -- (instancetype)initWithValue:(DocumentChangeType)value { - self = [super init]; - if (self) { - _value = value; - } - return self; -} -@end - -/// An enumeration of firestore source types. -@implementation SourceBox -- (instancetype)initWithValue:(Source)value { - self = [super init]; - if (self) { - _value = value; - } - return self; -} -@end - -/// The listener retrieves data and listens to updates from the local Firestore cache only. -/// If the cache is empty, an empty snapshot will be returned. -/// Snapshot events will be triggered on cache updates, like local mutations or load bundles. -/// -/// Note that the data might be stale if the cache hasn't synchronized with recent server-side -/// changes. -@implementation ListenSourceBox -- (instancetype)initWithValue:(ListenSource)value { - self = [super init]; - if (self) { - _value = value; - } - return self; -} -@end - -@implementation ServerTimestampBehaviorBox -- (instancetype)initWithValue:(ServerTimestampBehavior)value { - self = [super init]; - if (self) { - _value = value; - } - return self; -} -@end - -/// [AggregateSource] represents the source of data for an [AggregateQuery]. -@implementation AggregateSourceBox -- (instancetype)initWithValue:(AggregateSource)value { - self = [super init]; - if (self) { - _value = value; - } - return self; -} -@end - -/// [PersistenceCacheIndexManagerRequest] represents the request types for the persistence cache -/// index manager. -@implementation PersistenceCacheIndexManagerRequestBox -- (instancetype)initWithValue:(PersistenceCacheIndexManagerRequest)value { - self = [super init]; - if (self) { - _value = value; - } - return self; -} -@end - -@implementation InternalTransactionResultBox -- (instancetype)initWithValue:(InternalTransactionResult)value { - self = [super init]; - if (self) { - _value = value; - } - return self; -} -@end - -@implementation InternalTransactionTypeBox -- (instancetype)initWithValue:(InternalTransactionType)value { - self = [super init]; - if (self) { - _value = value; - } - return self; -} -@end - -@implementation AggregateTypeBox -- (instancetype)initWithValue:(AggregateType)value { - self = [super init]; - if (self) { - _value = value; - } - return self; -} -@end - -@interface InternalFirebaseSettings () -+ (InternalFirebaseSettings *)fromList:(NSArray *)list; -+ (nullable InternalFirebaseSettings *)nullableFromList:(NSArray *)list; -- (NSArray *)toList; -@end - -@interface FirestorePigeonFirebaseApp () -+ (FirestorePigeonFirebaseApp *)fromList:(NSArray *)list; -+ (nullable FirestorePigeonFirebaseApp *)nullableFromList:(NSArray *)list; -- (NSArray *)toList; -@end - -@interface InternalSnapshotMetadata () -+ (InternalSnapshotMetadata *)fromList:(NSArray *)list; -+ (nullable InternalSnapshotMetadata *)nullableFromList:(NSArray *)list; -- (NSArray *)toList; -@end - -@interface InternalDocumentSnapshot () -+ (InternalDocumentSnapshot *)fromList:(NSArray *)list; -+ (nullable InternalDocumentSnapshot *)nullableFromList:(NSArray *)list; -- (NSArray *)toList; -@end - -@interface InternalDocumentChange () -+ (InternalDocumentChange *)fromList:(NSArray *)list; -+ (nullable InternalDocumentChange *)nullableFromList:(NSArray *)list; -- (NSArray *)toList; -@end - -@interface InternalQuerySnapshot () -+ (InternalQuerySnapshot *)fromList:(NSArray *)list; -+ (nullable InternalQuerySnapshot *)nullableFromList:(NSArray *)list; -- (NSArray *)toList; -@end - -@interface InternalPipelineResult () -+ (InternalPipelineResult *)fromList:(NSArray *)list; -+ (nullable InternalPipelineResult *)nullableFromList:(NSArray *)list; -- (NSArray *)toList; -@end - -@interface InternalPipelineSnapshot () -+ (InternalPipelineSnapshot *)fromList:(NSArray *)list; -+ (nullable InternalPipelineSnapshot *)nullableFromList:(NSArray *)list; -- (NSArray *)toList; -@end - -@interface InternalGetOptions () -+ (InternalGetOptions *)fromList:(NSArray *)list; -+ (nullable InternalGetOptions *)nullableFromList:(NSArray *)list; -- (NSArray *)toList; -@end - -@interface InternalDocumentOption () -+ (InternalDocumentOption *)fromList:(NSArray *)list; -+ (nullable InternalDocumentOption *)nullableFromList:(NSArray *)list; -- (NSArray *)toList; -@end - -@interface InternalTransactionCommand () -+ (InternalTransactionCommand *)fromList:(NSArray *)list; -+ (nullable InternalTransactionCommand *)nullableFromList:(NSArray *)list; -- (NSArray *)toList; -@end - -@interface DocumentReferenceRequest () -+ (DocumentReferenceRequest *)fromList:(NSArray *)list; -+ (nullable DocumentReferenceRequest *)nullableFromList:(NSArray *)list; -- (NSArray *)toList; -@end - -@interface InternalQueryParameters () -+ (InternalQueryParameters *)fromList:(NSArray *)list; -+ (nullable InternalQueryParameters *)nullableFromList:(NSArray *)list; -- (NSArray *)toList; -@end - -@interface AggregateQuery () -+ (AggregateQuery *)fromList:(NSArray *)list; -+ (nullable AggregateQuery *)nullableFromList:(NSArray *)list; -- (NSArray *)toList; -@end - -@interface AggregateQueryResponse () -+ (AggregateQueryResponse *)fromList:(NSArray *)list; -+ (nullable AggregateQueryResponse *)nullableFromList:(NSArray *)list; -- (NSArray *)toList; -@end - -@implementation InternalFirebaseSettings -+ (instancetype)makeWithPersistenceEnabled:(nullable NSNumber *)persistenceEnabled - host:(nullable NSString *)host - sslEnabled:(nullable NSNumber *)sslEnabled - cacheSizeBytes:(nullable NSNumber *)cacheSizeBytes - ignoreUndefinedProperties:(BOOL)ignoreUndefinedProperties { - InternalFirebaseSettings *pigeonResult = [[InternalFirebaseSettings alloc] init]; - pigeonResult.persistenceEnabled = persistenceEnabled; - pigeonResult.host = host; - pigeonResult.sslEnabled = sslEnabled; - pigeonResult.cacheSizeBytes = cacheSizeBytes; - pigeonResult.ignoreUndefinedProperties = ignoreUndefinedProperties; - return pigeonResult; -} -+ (InternalFirebaseSettings *)fromList:(NSArray *)list { - InternalFirebaseSettings *pigeonResult = [[InternalFirebaseSettings alloc] init]; - pigeonResult.persistenceEnabled = GetNullableObjectAtIndex(list, 0); - pigeonResult.host = GetNullableObjectAtIndex(list, 1); - pigeonResult.sslEnabled = GetNullableObjectAtIndex(list, 2); - pigeonResult.cacheSizeBytes = GetNullableObjectAtIndex(list, 3); - pigeonResult.ignoreUndefinedProperties = [GetNullableObjectAtIndex(list, 4) boolValue]; - return pigeonResult; -} -+ (nullable InternalFirebaseSettings *)nullableFromList:(NSArray *)list { - return (list) ? [InternalFirebaseSettings fromList:list] : nil; -} -- (NSArray *)toList { - return @[ - self.persistenceEnabled ?: [NSNull null], - self.host ?: [NSNull null], - self.sslEnabled ?: [NSNull null], - self.cacheSizeBytes ?: [NSNull null], - @(self.ignoreUndefinedProperties), - ]; -} -- (BOOL)isEqual:(id)object { - if (self == object) { - return YES; - } - if (![object isKindOfClass:[self class]]) { - return NO; - } - InternalFirebaseSettings *other = (InternalFirebaseSettings *)object; - return FLTPigeonDeepEquals(self.persistenceEnabled, other.persistenceEnabled) && - FLTPigeonDeepEquals(self.host, other.host) && - FLTPigeonDeepEquals(self.sslEnabled, other.sslEnabled) && - FLTPigeonDeepEquals(self.cacheSizeBytes, other.cacheSizeBytes) && - self.ignoreUndefinedProperties == other.ignoreUndefinedProperties; -} - -- (NSUInteger)hash { - NSUInteger result = [self class].hash; - result = result * 31 + FLTPigeonDeepHash(self.persistenceEnabled); - result = result * 31 + FLTPigeonDeepHash(self.host); - result = result * 31 + FLTPigeonDeepHash(self.sslEnabled); - result = result * 31 + FLTPigeonDeepHash(self.cacheSizeBytes); - result = result * 31 + @(self.ignoreUndefinedProperties).hash; - return result; -} -@end - -@implementation FirestorePigeonFirebaseApp -+ (instancetype)makeWithAppName:(NSString *)appName - settings:(InternalFirebaseSettings *)settings - databaseURL:(NSString *)databaseURL { - FirestorePigeonFirebaseApp *pigeonResult = [[FirestorePigeonFirebaseApp alloc] init]; - pigeonResult.appName = appName; - pigeonResult.settings = settings; - pigeonResult.databaseURL = databaseURL; - return pigeonResult; -} -+ (FirestorePigeonFirebaseApp *)fromList:(NSArray *)list { - FirestorePigeonFirebaseApp *pigeonResult = [[FirestorePigeonFirebaseApp alloc] init]; - pigeonResult.appName = GetNullableObjectAtIndex(list, 0); - pigeonResult.settings = GetNullableObjectAtIndex(list, 1); - pigeonResult.databaseURL = GetNullableObjectAtIndex(list, 2); - return pigeonResult; -} -+ (nullable FirestorePigeonFirebaseApp *)nullableFromList:(NSArray *)list { - return (list) ? [FirestorePigeonFirebaseApp fromList:list] : nil; -} -- (NSArray *)toList { - return @[ - self.appName ?: [NSNull null], - self.settings ?: [NSNull null], - self.databaseURL ?: [NSNull null], - ]; -} -- (BOOL)isEqual:(id)object { - if (self == object) { - return YES; - } - if (![object isKindOfClass:[self class]]) { - return NO; - } - FirestorePigeonFirebaseApp *other = (FirestorePigeonFirebaseApp *)object; - return FLTPigeonDeepEquals(self.appName, other.appName) && - FLTPigeonDeepEquals(self.settings, other.settings) && - FLTPigeonDeepEquals(self.databaseURL, other.databaseURL); -} - -- (NSUInteger)hash { - NSUInteger result = [self class].hash; - result = result * 31 + FLTPigeonDeepHash(self.appName); - result = result * 31 + FLTPigeonDeepHash(self.settings); - result = result * 31 + FLTPigeonDeepHash(self.databaseURL); - return result; -} -@end - -@implementation InternalSnapshotMetadata -+ (instancetype)makeWithHasPendingWrites:(BOOL)hasPendingWrites isFromCache:(BOOL)isFromCache { - InternalSnapshotMetadata *pigeonResult = [[InternalSnapshotMetadata alloc] init]; - pigeonResult.hasPendingWrites = hasPendingWrites; - pigeonResult.isFromCache = isFromCache; - return pigeonResult; -} -+ (InternalSnapshotMetadata *)fromList:(NSArray *)list { - InternalSnapshotMetadata *pigeonResult = [[InternalSnapshotMetadata alloc] init]; - pigeonResult.hasPendingWrites = [GetNullableObjectAtIndex(list, 0) boolValue]; - pigeonResult.isFromCache = [GetNullableObjectAtIndex(list, 1) boolValue]; - return pigeonResult; -} -+ (nullable InternalSnapshotMetadata *)nullableFromList:(NSArray *)list { - return (list) ? [InternalSnapshotMetadata fromList:list] : nil; -} -- (NSArray *)toList { - return @[ - @(self.hasPendingWrites), - @(self.isFromCache), - ]; -} -- (BOOL)isEqual:(id)object { - if (self == object) { - return YES; - } - if (![object isKindOfClass:[self class]]) { - return NO; - } - InternalSnapshotMetadata *other = (InternalSnapshotMetadata *)object; - return self.hasPendingWrites == other.hasPendingWrites && self.isFromCache == other.isFromCache; -} - -- (NSUInteger)hash { - NSUInteger result = [self class].hash; - result = result * 31 + @(self.hasPendingWrites).hash; - result = result * 31 + @(self.isFromCache).hash; - return result; -} -@end - -@implementation InternalDocumentSnapshot -+ (instancetype)makeWithPath:(NSString *)path - data:(nullable NSDictionary *)data - metadata:(InternalSnapshotMetadata *)metadata { - InternalDocumentSnapshot *pigeonResult = [[InternalDocumentSnapshot alloc] init]; - pigeonResult.path = path; - pigeonResult.data = data; - pigeonResult.metadata = metadata; - return pigeonResult; -} -+ (InternalDocumentSnapshot *)fromList:(NSArray *)list { - InternalDocumentSnapshot *pigeonResult = [[InternalDocumentSnapshot alloc] init]; - pigeonResult.path = GetNullableObjectAtIndex(list, 0); - pigeonResult.data = GetNullableObjectAtIndex(list, 1); - pigeonResult.metadata = GetNullableObjectAtIndex(list, 2); - return pigeonResult; -} -+ (nullable InternalDocumentSnapshot *)nullableFromList:(NSArray *)list { - return (list) ? [InternalDocumentSnapshot fromList:list] : nil; -} -- (NSArray *)toList { - return @[ - self.path ?: [NSNull null], - self.data ?: [NSNull null], - self.metadata ?: [NSNull null], - ]; -} -- (BOOL)isEqual:(id)object { - if (self == object) { - return YES; - } - if (![object isKindOfClass:[self class]]) { - return NO; - } - InternalDocumentSnapshot *other = (InternalDocumentSnapshot *)object; - return FLTPigeonDeepEquals(self.path, other.path) && FLTPigeonDeepEquals(self.data, other.data) && - FLTPigeonDeepEquals(self.metadata, other.metadata); -} - -- (NSUInteger)hash { - NSUInteger result = [self class].hash; - result = result * 31 + FLTPigeonDeepHash(self.path); - result = result * 31 + FLTPigeonDeepHash(self.data); - result = result * 31 + FLTPigeonDeepHash(self.metadata); - return result; -} -@end - -@implementation InternalDocumentChange -+ (instancetype)makeWithType:(DocumentChangeType)type - document:(InternalDocumentSnapshot *)document - oldIndex:(NSInteger)oldIndex - newIndex:(NSInteger)newIndex { - InternalDocumentChange *pigeonResult = [[InternalDocumentChange alloc] init]; - pigeonResult.type = type; - pigeonResult.document = document; - pigeonResult.oldIndex = oldIndex; - pigeonResult.newIndex = newIndex; - return pigeonResult; -} -+ (InternalDocumentChange *)fromList:(NSArray *)list { - InternalDocumentChange *pigeonResult = [[InternalDocumentChange alloc] init]; - DocumentChangeTypeBox *boxedDocumentChangeType = GetNullableObjectAtIndex(list, 0); - pigeonResult.type = boxedDocumentChangeType.value; - pigeonResult.document = GetNullableObjectAtIndex(list, 1); - pigeonResult.oldIndex = [GetNullableObjectAtIndex(list, 2) integerValue]; - pigeonResult.newIndex = [GetNullableObjectAtIndex(list, 3) integerValue]; - return pigeonResult; -} -+ (nullable InternalDocumentChange *)nullableFromList:(NSArray *)list { - return (list) ? [InternalDocumentChange fromList:list] : nil; -} -- (NSArray *)toList { - return @[ - [[DocumentChangeTypeBox alloc] initWithValue:self.type], - self.document ?: [NSNull null], - @(self.oldIndex), - @(self.newIndex), - ]; -} -- (BOOL)isEqual:(id)object { - if (self == object) { - return YES; - } - if (![object isKindOfClass:[self class]]) { - return NO; - } - InternalDocumentChange *other = (InternalDocumentChange *)object; - return self.type == other.type && FLTPigeonDeepEquals(self.document, other.document) && - self.oldIndex == other.oldIndex && self.newIndex == other.newIndex; -} - -- (NSUInteger)hash { - NSUInteger result = [self class].hash; - result = result * 31 + @(self.type).hash; - result = result * 31 + FLTPigeonDeepHash(self.document); - result = result * 31 + @(self.oldIndex).hash; - result = result * 31 + @(self.newIndex).hash; - return result; -} -@end - -@implementation InternalQuerySnapshot -+ (instancetype)makeWithDocuments:(NSArray *)documents - documentChanges:(NSArray *)documentChanges - metadata:(InternalSnapshotMetadata *)metadata { - InternalQuerySnapshot *pigeonResult = [[InternalQuerySnapshot alloc] init]; - pigeonResult.documents = documents; - pigeonResult.documentChanges = documentChanges; - pigeonResult.metadata = metadata; - return pigeonResult; -} -+ (InternalQuerySnapshot *)fromList:(NSArray *)list { - InternalQuerySnapshot *pigeonResult = [[InternalQuerySnapshot alloc] init]; - pigeonResult.documents = GetNullableObjectAtIndex(list, 0); - pigeonResult.documentChanges = GetNullableObjectAtIndex(list, 1); - pigeonResult.metadata = GetNullableObjectAtIndex(list, 2); - return pigeonResult; -} -+ (nullable InternalQuerySnapshot *)nullableFromList:(NSArray *)list { - return (list) ? [InternalQuerySnapshot fromList:list] : nil; -} -- (NSArray *)toList { - return @[ - self.documents ?: [NSNull null], - self.documentChanges ?: [NSNull null], - self.metadata ?: [NSNull null], - ]; -} -- (BOOL)isEqual:(id)object { - if (self == object) { - return YES; - } - if (![object isKindOfClass:[self class]]) { - return NO; - } - InternalQuerySnapshot *other = (InternalQuerySnapshot *)object; - return FLTPigeonDeepEquals(self.documents, other.documents) && - FLTPigeonDeepEquals(self.documentChanges, other.documentChanges) && - FLTPigeonDeepEquals(self.metadata, other.metadata); -} - -- (NSUInteger)hash { - NSUInteger result = [self class].hash; - result = result * 31 + FLTPigeonDeepHash(self.documents); - result = result * 31 + FLTPigeonDeepHash(self.documentChanges); - result = result * 31 + FLTPigeonDeepHash(self.metadata); - return result; -} -@end - -@implementation InternalPipelineResult -+ (instancetype)makeWithDocumentPath:(nullable NSString *)documentPath - createTime:(nullable NSNumber *)createTime - updateTime:(nullable NSNumber *)updateTime - data:(nullable NSDictionary *)data { - InternalPipelineResult *pigeonResult = [[InternalPipelineResult alloc] init]; - pigeonResult.documentPath = documentPath; - pigeonResult.createTime = createTime; - pigeonResult.updateTime = updateTime; - pigeonResult.data = data; - return pigeonResult; -} -+ (InternalPipelineResult *)fromList:(NSArray *)list { - InternalPipelineResult *pigeonResult = [[InternalPipelineResult alloc] init]; - pigeonResult.documentPath = GetNullableObjectAtIndex(list, 0); - pigeonResult.createTime = GetNullableObjectAtIndex(list, 1); - pigeonResult.updateTime = GetNullableObjectAtIndex(list, 2); - pigeonResult.data = GetNullableObjectAtIndex(list, 3); - return pigeonResult; -} -+ (nullable InternalPipelineResult *)nullableFromList:(NSArray *)list { - return (list) ? [InternalPipelineResult fromList:list] : nil; -} -- (NSArray *)toList { - return @[ - self.documentPath ?: [NSNull null], - self.createTime ?: [NSNull null], - self.updateTime ?: [NSNull null], - self.data ?: [NSNull null], - ]; -} -- (BOOL)isEqual:(id)object { - if (self == object) { - return YES; - } - if (![object isKindOfClass:[self class]]) { - return NO; - } - InternalPipelineResult *other = (InternalPipelineResult *)object; - return FLTPigeonDeepEquals(self.documentPath, other.documentPath) && - FLTPigeonDeepEquals(self.createTime, other.createTime) && - FLTPigeonDeepEquals(self.updateTime, other.updateTime) && - FLTPigeonDeepEquals(self.data, other.data); -} - -- (NSUInteger)hash { - NSUInteger result = [self class].hash; - result = result * 31 + FLTPigeonDeepHash(self.documentPath); - result = result * 31 + FLTPigeonDeepHash(self.createTime); - result = result * 31 + FLTPigeonDeepHash(self.updateTime); - result = result * 31 + FLTPigeonDeepHash(self.data); - return result; -} -@end - -@implementation InternalPipelineSnapshot -+ (instancetype)makeWithResults:(NSArray *)results - executionTime:(NSInteger)executionTime { - InternalPipelineSnapshot *pigeonResult = [[InternalPipelineSnapshot alloc] init]; - pigeonResult.results = results; - pigeonResult.executionTime = executionTime; - return pigeonResult; -} -+ (InternalPipelineSnapshot *)fromList:(NSArray *)list { - InternalPipelineSnapshot *pigeonResult = [[InternalPipelineSnapshot alloc] init]; - pigeonResult.results = GetNullableObjectAtIndex(list, 0); - pigeonResult.executionTime = [GetNullableObjectAtIndex(list, 1) integerValue]; - return pigeonResult; -} -+ (nullable InternalPipelineSnapshot *)nullableFromList:(NSArray *)list { - return (list) ? [InternalPipelineSnapshot fromList:list] : nil; -} -- (NSArray *)toList { - return @[ - self.results ?: [NSNull null], - @(self.executionTime), - ]; -} -- (BOOL)isEqual:(id)object { - if (self == object) { - return YES; - } - if (![object isKindOfClass:[self class]]) { - return NO; - } - InternalPipelineSnapshot *other = (InternalPipelineSnapshot *)object; - return FLTPigeonDeepEquals(self.results, other.results) && - self.executionTime == other.executionTime; -} - -- (NSUInteger)hash { - NSUInteger result = [self class].hash; - result = result * 31 + FLTPigeonDeepHash(self.results); - result = result * 31 + @(self.executionTime).hash; - return result; -} -@end - -@implementation InternalGetOptions -+ (instancetype)makeWithSource:(Source)source - serverTimestampBehavior:(ServerTimestampBehavior)serverTimestampBehavior { - InternalGetOptions *pigeonResult = [[InternalGetOptions alloc] init]; - pigeonResult.source = source; - pigeonResult.serverTimestampBehavior = serverTimestampBehavior; - return pigeonResult; -} -+ (InternalGetOptions *)fromList:(NSArray *)list { - InternalGetOptions *pigeonResult = [[InternalGetOptions alloc] init]; - SourceBox *boxedSource = GetNullableObjectAtIndex(list, 0); - pigeonResult.source = boxedSource.value; - ServerTimestampBehaviorBox *boxedServerTimestampBehavior = GetNullableObjectAtIndex(list, 1); - pigeonResult.serverTimestampBehavior = boxedServerTimestampBehavior.value; - return pigeonResult; -} -+ (nullable InternalGetOptions *)nullableFromList:(NSArray *)list { - return (list) ? [InternalGetOptions fromList:list] : nil; -} -- (NSArray *)toList { - return @[ - [[SourceBox alloc] initWithValue:self.source], - [[ServerTimestampBehaviorBox alloc] initWithValue:self.serverTimestampBehavior], - ]; -} -- (BOOL)isEqual:(id)object { - if (self == object) { - return YES; - } - if (![object isKindOfClass:[self class]]) { - return NO; - } - InternalGetOptions *other = (InternalGetOptions *)object; - return self.source == other.source && - self.serverTimestampBehavior == other.serverTimestampBehavior; -} - -- (NSUInteger)hash { - NSUInteger result = [self class].hash; - result = result * 31 + @(self.source).hash; - result = result * 31 + @(self.serverTimestampBehavior).hash; - return result; -} -@end - -@implementation InternalDocumentOption -+ (instancetype)makeWithMerge:(nullable NSNumber *)merge - mergeFields:(nullable NSArray *> *)mergeFields { - InternalDocumentOption *pigeonResult = [[InternalDocumentOption alloc] init]; - pigeonResult.merge = merge; - pigeonResult.mergeFields = mergeFields; - return pigeonResult; -} -+ (InternalDocumentOption *)fromList:(NSArray *)list { - InternalDocumentOption *pigeonResult = [[InternalDocumentOption alloc] init]; - pigeonResult.merge = GetNullableObjectAtIndex(list, 0); - pigeonResult.mergeFields = GetNullableObjectAtIndex(list, 1); - return pigeonResult; -} -+ (nullable InternalDocumentOption *)nullableFromList:(NSArray *)list { - return (list) ? [InternalDocumentOption fromList:list] : nil; -} -- (NSArray *)toList { - return @[ - self.merge ?: [NSNull null], - self.mergeFields ?: [NSNull null], - ]; -} -- (BOOL)isEqual:(id)object { - if (self == object) { - return YES; - } - if (![object isKindOfClass:[self class]]) { - return NO; - } - InternalDocumentOption *other = (InternalDocumentOption *)object; - return FLTPigeonDeepEquals(self.merge, other.merge) && - FLTPigeonDeepEquals(self.mergeFields, other.mergeFields); -} - -- (NSUInteger)hash { - NSUInteger result = [self class].hash; - result = result * 31 + FLTPigeonDeepHash(self.merge); - result = result * 31 + FLTPigeonDeepHash(self.mergeFields); - return result; -} -@end - -@implementation InternalTransactionCommand -+ (instancetype)makeWithType:(InternalTransactionType)type - path:(NSString *)path - data:(nullable NSDictionary *)data - option:(nullable InternalDocumentOption *)option { - InternalTransactionCommand *pigeonResult = [[InternalTransactionCommand alloc] init]; - pigeonResult.type = type; - pigeonResult.path = path; - pigeonResult.data = data; - pigeonResult.option = option; - return pigeonResult; -} -+ (InternalTransactionCommand *)fromList:(NSArray *)list { - InternalTransactionCommand *pigeonResult = [[InternalTransactionCommand alloc] init]; - InternalTransactionTypeBox *boxedInternalTransactionType = GetNullableObjectAtIndex(list, 0); - pigeonResult.type = boxedInternalTransactionType.value; - pigeonResult.path = GetNullableObjectAtIndex(list, 1); - pigeonResult.data = GetNullableObjectAtIndex(list, 2); - pigeonResult.option = GetNullableObjectAtIndex(list, 3); - return pigeonResult; -} -+ (nullable InternalTransactionCommand *)nullableFromList:(NSArray *)list { - return (list) ? [InternalTransactionCommand fromList:list] : nil; -} -- (NSArray *)toList { - return @[ - [[InternalTransactionTypeBox alloc] initWithValue:self.type], - self.path ?: [NSNull null], - self.data ?: [NSNull null], - self.option ?: [NSNull null], - ]; -} -- (BOOL)isEqual:(id)object { - if (self == object) { - return YES; - } - if (![object isKindOfClass:[self class]]) { - return NO; - } - InternalTransactionCommand *other = (InternalTransactionCommand *)object; - return self.type == other.type && FLTPigeonDeepEquals(self.path, other.path) && - FLTPigeonDeepEquals(self.data, other.data) && - FLTPigeonDeepEquals(self.option, other.option); -} - -- (NSUInteger)hash { - NSUInteger result = [self class].hash; - result = result * 31 + @(self.type).hash; - result = result * 31 + FLTPigeonDeepHash(self.path); - result = result * 31 + FLTPigeonDeepHash(self.data); - result = result * 31 + FLTPigeonDeepHash(self.option); - return result; -} -@end - -@implementation DocumentReferenceRequest -+ (instancetype)makeWithPath:(NSString *)path - data:(nullable NSDictionary *)data - option:(nullable InternalDocumentOption *)option - source:(nullable SourceBox *)source - serverTimestampBehavior:(nullable ServerTimestampBehaviorBox *)serverTimestampBehavior { - DocumentReferenceRequest *pigeonResult = [[DocumentReferenceRequest alloc] init]; - pigeonResult.path = path; - pigeonResult.data = data; - pigeonResult.option = option; - pigeonResult.source = source; - pigeonResult.serverTimestampBehavior = serverTimestampBehavior; - return pigeonResult; -} -+ (DocumentReferenceRequest *)fromList:(NSArray *)list { - DocumentReferenceRequest *pigeonResult = [[DocumentReferenceRequest alloc] init]; - pigeonResult.path = GetNullableObjectAtIndex(list, 0); - pigeonResult.data = GetNullableObjectAtIndex(list, 1); - pigeonResult.option = GetNullableObjectAtIndex(list, 2); - pigeonResult.source = GetNullableObjectAtIndex(list, 3); - pigeonResult.serverTimestampBehavior = GetNullableObjectAtIndex(list, 4); - return pigeonResult; -} -+ (nullable DocumentReferenceRequest *)nullableFromList:(NSArray *)list { - return (list) ? [DocumentReferenceRequest fromList:list] : nil; -} -- (NSArray *)toList { - return @[ - self.path ?: [NSNull null], - self.data ?: [NSNull null], - self.option ?: [NSNull null], - self.source ?: [NSNull null], - self.serverTimestampBehavior ?: [NSNull null], - ]; -} -- (BOOL)isEqual:(id)object { - if (self == object) { - return YES; - } - if (![object isKindOfClass:[self class]]) { - return NO; - } - DocumentReferenceRequest *other = (DocumentReferenceRequest *)object; - return FLTPigeonDeepEquals(self.path, other.path) && FLTPigeonDeepEquals(self.data, other.data) && - FLTPigeonDeepEquals(self.option, other.option) && - FLTPigeonDeepEquals(self.source, other.source) && - FLTPigeonDeepEquals(self.serverTimestampBehavior, other.serverTimestampBehavior); -} - -- (NSUInteger)hash { - NSUInteger result = [self class].hash; - result = result * 31 + FLTPigeonDeepHash(self.path); - result = result * 31 + FLTPigeonDeepHash(self.data); - result = result * 31 + FLTPigeonDeepHash(self.option); - result = result * 31 + FLTPigeonDeepHash(self.source); - result = result * 31 + FLTPigeonDeepHash(self.serverTimestampBehavior); - return result; -} -@end - -@implementation InternalQueryParameters -+ (instancetype)makeWithWhere:(nullable NSArray *> *)where - orderBy:(nullable NSArray *> *)orderBy - limit:(nullable NSNumber *)limit - limitToLast:(nullable NSNumber *)limitToLast - startAt:(nullable NSArray *)startAt - startAfter:(nullable NSArray *)startAfter - endAt:(nullable NSArray *)endAt - endBefore:(nullable NSArray *)endBefore - filters:(nullable NSDictionary *)filters { - InternalQueryParameters *pigeonResult = [[InternalQueryParameters alloc] init]; - pigeonResult.where = where; - pigeonResult.orderBy = orderBy; - pigeonResult.limit = limit; - pigeonResult.limitToLast = limitToLast; - pigeonResult.startAt = startAt; - pigeonResult.startAfter = startAfter; - pigeonResult.endAt = endAt; - pigeonResult.endBefore = endBefore; - pigeonResult.filters = filters; - return pigeonResult; -} -+ (InternalQueryParameters *)fromList:(NSArray *)list { - InternalQueryParameters *pigeonResult = [[InternalQueryParameters alloc] init]; - pigeonResult.where = GetNullableObjectAtIndex(list, 0); - pigeonResult.orderBy = GetNullableObjectAtIndex(list, 1); - pigeonResult.limit = GetNullableObjectAtIndex(list, 2); - pigeonResult.limitToLast = GetNullableObjectAtIndex(list, 3); - pigeonResult.startAt = GetNullableObjectAtIndex(list, 4); - pigeonResult.startAfter = GetNullableObjectAtIndex(list, 5); - pigeonResult.endAt = GetNullableObjectAtIndex(list, 6); - pigeonResult.endBefore = GetNullableObjectAtIndex(list, 7); - pigeonResult.filters = GetNullableObjectAtIndex(list, 8); - return pigeonResult; -} -+ (nullable InternalQueryParameters *)nullableFromList:(NSArray *)list { - return (list) ? [InternalQueryParameters fromList:list] : nil; -} -- (NSArray *)toList { - return @[ - self.where ?: [NSNull null], - self.orderBy ?: [NSNull null], - self.limit ?: [NSNull null], - self.limitToLast ?: [NSNull null], - self.startAt ?: [NSNull null], - self.startAfter ?: [NSNull null], - self.endAt ?: [NSNull null], - self.endBefore ?: [NSNull null], - self.filters ?: [NSNull null], - ]; -} -- (BOOL)isEqual:(id)object { - if (self == object) { - return YES; - } - if (![object isKindOfClass:[self class]]) { - return NO; - } - InternalQueryParameters *other = (InternalQueryParameters *)object; - return FLTPigeonDeepEquals(self.where, other.where) && - FLTPigeonDeepEquals(self.orderBy, other.orderBy) && - FLTPigeonDeepEquals(self.limit, other.limit) && - FLTPigeonDeepEquals(self.limitToLast, other.limitToLast) && - FLTPigeonDeepEquals(self.startAt, other.startAt) && - FLTPigeonDeepEquals(self.startAfter, other.startAfter) && - FLTPigeonDeepEquals(self.endAt, other.endAt) && - FLTPigeonDeepEquals(self.endBefore, other.endBefore) && - FLTPigeonDeepEquals(self.filters, other.filters); -} - -- (NSUInteger)hash { - NSUInteger result = [self class].hash; - result = result * 31 + FLTPigeonDeepHash(self.where); - result = result * 31 + FLTPigeonDeepHash(self.orderBy); - result = result * 31 + FLTPigeonDeepHash(self.limit); - result = result * 31 + FLTPigeonDeepHash(self.limitToLast); - result = result * 31 + FLTPigeonDeepHash(self.startAt); - result = result * 31 + FLTPigeonDeepHash(self.startAfter); - result = result * 31 + FLTPigeonDeepHash(self.endAt); - result = result * 31 + FLTPigeonDeepHash(self.endBefore); - result = result * 31 + FLTPigeonDeepHash(self.filters); - return result; -} -@end - -@implementation AggregateQuery -+ (instancetype)makeWithType:(AggregateType)type field:(nullable NSString *)field { - AggregateQuery *pigeonResult = [[AggregateQuery alloc] init]; - pigeonResult.type = type; - pigeonResult.field = field; - return pigeonResult; -} -+ (AggregateQuery *)fromList:(NSArray *)list { - AggregateQuery *pigeonResult = [[AggregateQuery alloc] init]; - AggregateTypeBox *boxedAggregateType = GetNullableObjectAtIndex(list, 0); - pigeonResult.type = boxedAggregateType.value; - pigeonResult.field = GetNullableObjectAtIndex(list, 1); - return pigeonResult; -} -+ (nullable AggregateQuery *)nullableFromList:(NSArray *)list { - return (list) ? [AggregateQuery fromList:list] : nil; -} -- (NSArray *)toList { - return @[ - [[AggregateTypeBox alloc] initWithValue:self.type], - self.field ?: [NSNull null], - ]; -} -- (BOOL)isEqual:(id)object { - if (self == object) { - return YES; - } - if (![object isKindOfClass:[self class]]) { - return NO; - } - AggregateQuery *other = (AggregateQuery *)object; - return self.type == other.type && FLTPigeonDeepEquals(self.field, other.field); -} - -- (NSUInteger)hash { - NSUInteger result = [self class].hash; - result = result * 31 + @(self.type).hash; - result = result * 31 + FLTPigeonDeepHash(self.field); - return result; -} -@end - -@implementation AggregateQueryResponse -+ (instancetype)makeWithType:(AggregateType)type - field:(nullable NSString *)field - value:(nullable NSNumber *)value { - AggregateQueryResponse *pigeonResult = [[AggregateQueryResponse alloc] init]; - pigeonResult.type = type; - pigeonResult.field = field; - pigeonResult.value = value; - return pigeonResult; -} -+ (AggregateQueryResponse *)fromList:(NSArray *)list { - AggregateQueryResponse *pigeonResult = [[AggregateQueryResponse alloc] init]; - AggregateTypeBox *boxedAggregateType = GetNullableObjectAtIndex(list, 0); - pigeonResult.type = boxedAggregateType.value; - pigeonResult.field = GetNullableObjectAtIndex(list, 1); - pigeonResult.value = GetNullableObjectAtIndex(list, 2); - return pigeonResult; -} -+ (nullable AggregateQueryResponse *)nullableFromList:(NSArray *)list { - return (list) ? [AggregateQueryResponse fromList:list] : nil; -} -- (NSArray *)toList { - return @[ - [[AggregateTypeBox alloc] initWithValue:self.type], - self.field ?: [NSNull null], - self.value ?: [NSNull null], - ]; -} -- (BOOL)isEqual:(id)object { - if (self == object) { - return YES; - } - if (![object isKindOfClass:[self class]]) { - return NO; - } - AggregateQueryResponse *other = (AggregateQueryResponse *)object; - return self.type == other.type && FLTPigeonDeepEquals(self.field, other.field) && - FLTPigeonDeepEquals(self.value, other.value); -} - -- (NSUInteger)hash { - NSUInteger result = [self class].hash; - result = result * 31 + @(self.type).hash; - result = result * 31 + FLTPigeonDeepHash(self.field); - result = result * 31 + FLTPigeonDeepHash(self.value); - return result; -} -@end - -@interface FirebaseFirestoreHostApiCodecReader : FLTFirebaseFirestoreReader -@end -@implementation FirebaseFirestoreHostApiCodecReader -- (nullable id)readValueOfType:(UInt8)type { - switch (type) { - case 129: { - NSNumber *enumAsNumber = [self readValue]; - return enumAsNumber == nil - ? nil - : [[DocumentChangeTypeBox alloc] initWithValue:[enumAsNumber integerValue]]; - } - case 130: { - NSNumber *enumAsNumber = [self readValue]; - return enumAsNumber == nil ? nil - : [[SourceBox alloc] initWithValue:[enumAsNumber integerValue]]; - } - case 131: { - NSNumber *enumAsNumber = [self readValue]; - return enumAsNumber == nil - ? nil - : [[ListenSourceBox alloc] initWithValue:[enumAsNumber integerValue]]; - } - case 132: { - NSNumber *enumAsNumber = [self readValue]; - return enumAsNumber == nil - ? nil - : [[ServerTimestampBehaviorBox alloc] initWithValue:[enumAsNumber integerValue]]; - } - case 133: { - NSNumber *enumAsNumber = [self readValue]; - return enumAsNumber == nil - ? nil - : [[AggregateSourceBox alloc] initWithValue:[enumAsNumber integerValue]]; - } - case 134: { - NSNumber *enumAsNumber = [self readValue]; - return enumAsNumber == nil ? nil - : [[PersistenceCacheIndexManagerRequestBox alloc] - initWithValue:[enumAsNumber integerValue]]; - } - case 135: { - NSNumber *enumAsNumber = [self readValue]; - return enumAsNumber == nil - ? nil - : [[InternalTransactionResultBox alloc] initWithValue:[enumAsNumber integerValue]]; - } - case 136: { - NSNumber *enumAsNumber = [self readValue]; - return enumAsNumber == nil - ? nil - : [[InternalTransactionTypeBox alloc] initWithValue:[enumAsNumber integerValue]]; - } - case 137: { - NSNumber *enumAsNumber = [self readValue]; - return enumAsNumber == nil - ? nil - : [[AggregateTypeBox alloc] initWithValue:[enumAsNumber integerValue]]; - } - case 138: - return [InternalFirebaseSettings fromList:[self readValue]]; - case 139: - return [FirestorePigeonFirebaseApp fromList:[self readValue]]; - case 140: - return [InternalSnapshotMetadata fromList:[self readValue]]; - case 141: - return [InternalDocumentSnapshot fromList:[self readValue]]; - case 142: - return [InternalDocumentChange fromList:[self readValue]]; - case 143: - return [InternalQuerySnapshot fromList:[self readValue]]; - case 144: - return [InternalPipelineResult fromList:[self readValue]]; - case 145: - return [InternalPipelineSnapshot fromList:[self readValue]]; - case 146: - return [InternalGetOptions fromList:[self readValue]]; - case 147: - return [InternalDocumentOption fromList:[self readValue]]; - case 148: - return [InternalTransactionCommand fromList:[self readValue]]; - case 149: - return [DocumentReferenceRequest fromList:[self readValue]]; - case 150: - return [InternalQueryParameters fromList:[self readValue]]; - case 151: - return [AggregateQuery fromList:[self readValue]]; - case 152: - return [AggregateQueryResponse fromList:[self readValue]]; - default: - return [super readValueOfType:type]; - } -} -@end - -@interface FirebaseFirestoreHostApiCodecWriter : FLTFirebaseFirestoreWriter -@end -@implementation FirebaseFirestoreHostApiCodecWriter -- (void)writeValue:(id)value { - if ([value isKindOfClass:[DocumentChangeTypeBox class]]) { - DocumentChangeTypeBox *box = (DocumentChangeTypeBox *)value; - [self writeByte:129]; - [self writeValue:(value == nil ? [NSNull null] : [NSNumber numberWithInteger:box.value])]; - } else if ([value isKindOfClass:[SourceBox class]]) { - SourceBox *box = (SourceBox *)value; - [self writeByte:130]; - [self writeValue:(value == nil ? [NSNull null] : [NSNumber numberWithInteger:box.value])]; - } else if ([value isKindOfClass:[ListenSourceBox class]]) { - ListenSourceBox *box = (ListenSourceBox *)value; - [self writeByte:131]; - [self writeValue:(value == nil ? [NSNull null] : [NSNumber numberWithInteger:box.value])]; - } else if ([value isKindOfClass:[ServerTimestampBehaviorBox class]]) { - ServerTimestampBehaviorBox *box = (ServerTimestampBehaviorBox *)value; - [self writeByte:132]; - [self writeValue:(value == nil ? [NSNull null] : [NSNumber numberWithInteger:box.value])]; - } else if ([value isKindOfClass:[AggregateSourceBox class]]) { - AggregateSourceBox *box = (AggregateSourceBox *)value; - [self writeByte:133]; - [self writeValue:(value == nil ? [NSNull null] : [NSNumber numberWithInteger:box.value])]; - } else if ([value isKindOfClass:[PersistenceCacheIndexManagerRequestBox class]]) { - PersistenceCacheIndexManagerRequestBox *box = (PersistenceCacheIndexManagerRequestBox *)value; - [self writeByte:134]; - [self writeValue:(value == nil ? [NSNull null] : [NSNumber numberWithInteger:box.value])]; - } else if ([value isKindOfClass:[InternalTransactionResultBox class]]) { - InternalTransactionResultBox *box = (InternalTransactionResultBox *)value; - [self writeByte:135]; - [self writeValue:(value == nil ? [NSNull null] : [NSNumber numberWithInteger:box.value])]; - } else if ([value isKindOfClass:[InternalTransactionTypeBox class]]) { - InternalTransactionTypeBox *box = (InternalTransactionTypeBox *)value; - [self writeByte:136]; - [self writeValue:(value == nil ? [NSNull null] : [NSNumber numberWithInteger:box.value])]; - } else if ([value isKindOfClass:[AggregateTypeBox class]]) { - AggregateTypeBox *box = (AggregateTypeBox *)value; - [self writeByte:137]; - [self writeValue:(value == nil ? [NSNull null] : [NSNumber numberWithInteger:box.value])]; - } else if ([value isKindOfClass:[InternalFirebaseSettings class]]) { - [self writeByte:138]; - [self writeValue:[value toList]]; - } else if ([value isKindOfClass:[FirestorePigeonFirebaseApp class]]) { - [self writeByte:139]; - [self writeValue:[value toList]]; - } else if ([value isKindOfClass:[InternalSnapshotMetadata class]]) { - [self writeByte:140]; - [self writeValue:[value toList]]; - } else if ([value isKindOfClass:[InternalDocumentSnapshot class]]) { - [self writeByte:141]; - [self writeValue:[value toList]]; - } else if ([value isKindOfClass:[InternalDocumentChange class]]) { - [self writeByte:142]; - [self writeValue:[value toList]]; - } else if ([value isKindOfClass:[InternalQuerySnapshot class]]) { - [self writeByte:143]; - [self writeValue:[value toList]]; - } else if ([value isKindOfClass:[InternalPipelineResult class]]) { - [self writeByte:144]; - [self writeValue:[value toList]]; - } else if ([value isKindOfClass:[InternalPipelineSnapshot class]]) { - [self writeByte:145]; - [self writeValue:[value toList]]; - } else if ([value isKindOfClass:[InternalGetOptions class]]) { - [self writeByte:146]; - [self writeValue:[value toList]]; - } else if ([value isKindOfClass:[InternalDocumentOption class]]) { - [self writeByte:147]; - [self writeValue:[value toList]]; - } else if ([value isKindOfClass:[InternalTransactionCommand class]]) { - [self writeByte:148]; - [self writeValue:[value toList]]; - } else if ([value isKindOfClass:[DocumentReferenceRequest class]]) { - [self writeByte:149]; - [self writeValue:[value toList]]; - } else if ([value isKindOfClass:[InternalQueryParameters class]]) { - [self writeByte:150]; - [self writeValue:[value toList]]; - } else if ([value isKindOfClass:[AggregateQuery class]]) { - [self writeByte:151]; - [self writeValue:[value toList]]; - } else if ([value isKindOfClass:[AggregateQueryResponse class]]) { - [self writeByte:152]; - [self writeValue:[value toList]]; - } else { - [super writeValue:value]; - } -} -@end - -@interface FirebaseFirestoreHostApiCodecReaderWriter : FlutterStandardReaderWriter -@end -@implementation FirebaseFirestoreHostApiCodecReaderWriter -- (FlutterStandardWriter *)writerWithData:(NSMutableData *)data { - return [[FirebaseFirestoreHostApiCodecWriter alloc] initWithData:data]; -} -- (FlutterStandardReader *)readerWithData:(NSData *)data { - return [[FirebaseFirestoreHostApiCodecReader alloc] initWithData:data]; -} -@end - -NSObject *GetFirebaseFirestoreHostApiCodec(void) { - static FlutterStandardMessageCodec *sSharedObject = nil; - static dispatch_once_t sPred = 0; - dispatch_once(&sPred, ^{ - FirebaseFirestoreHostApiCodecReaderWriter *readerWriter = - [[FirebaseFirestoreHostApiCodecReaderWriter alloc] init]; - sSharedObject = [FlutterStandardMessageCodec codecWithReaderWriter:readerWriter]; - }); - return sSharedObject; -} -void SetUpFirebaseFirestoreHostApi(id binaryMessenger, - NSObject *api) { - SetUpFirebaseFirestoreHostApiWithSuffix(binaryMessenger, api, @""); -} - -void SetUpFirebaseFirestoreHostApiWithSuffix(id binaryMessenger, - NSObject *api, - NSString *messageChannelSuffix) { - messageChannelSuffix = messageChannelSuffix.length > 0 - ? [NSString stringWithFormat:@".%@", messageChannelSuffix] - : @""; - { - FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] - initWithName:[NSString stringWithFormat:@"%@%@", - @"dev.flutter.pigeon.cloud_firestore_platform_" - @"interface.FirebaseFirestoreHostApi.loadBundle", - messageChannelSuffix] - binaryMessenger:binaryMessenger - codec:GetFirebaseFirestoreHostApiCodec()]; - if (api) { - NSCAssert([api respondsToSelector:@selector(loadBundleApp:bundle:completion:)], - @"FirebaseFirestoreHostApi api (%@) doesn't respond to " - @"@selector(loadBundleApp:bundle:completion:)", - api); - [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { - NSArray *args = message; - FirestorePigeonFirebaseApp *arg_app = GetNullableObjectAtIndex(args, 0); - FlutterStandardTypedData *arg_bundle = GetNullableObjectAtIndex(args, 1); - [api loadBundleApp:arg_app - bundle:arg_bundle - completion:^(NSString *_Nullable output, FlutterError *_Nullable error) { - callback(wrapResult(output, error)); - }]; - }]; - } else { - [channel setMessageHandler:nil]; - } - } - { - FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] - initWithName:[NSString - stringWithFormat:@"%@%@", - @"dev.flutter.pigeon.cloud_firestore_platform_" - @"interface.FirebaseFirestoreHostApi.namedQueryGet", - messageChannelSuffix] - binaryMessenger:binaryMessenger - codec:GetFirebaseFirestoreHostApiCodec()]; - if (api) { - NSCAssert([api respondsToSelector:@selector(namedQueryGetApp:name:options:completion:)], - @"FirebaseFirestoreHostApi api (%@) doesn't respond to " - @"@selector(namedQueryGetApp:name:options:completion:)", - api); - [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { - NSArray *args = message; - FirestorePigeonFirebaseApp *arg_app = GetNullableObjectAtIndex(args, 0); - NSString *arg_name = GetNullableObjectAtIndex(args, 1); - InternalGetOptions *arg_options = GetNullableObjectAtIndex(args, 2); - [api namedQueryGetApp:arg_app - name:arg_name - options:arg_options - completion:^(InternalQuerySnapshot *_Nullable output, - FlutterError *_Nullable error) { - callback(wrapResult(output, error)); - }]; - }]; - } else { - [channel setMessageHandler:nil]; - } - } - { - FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] - initWithName:[NSString - stringWithFormat:@"%@%@", - @"dev.flutter.pigeon.cloud_firestore_platform_" - @"interface.FirebaseFirestoreHostApi.clearPersistence", - messageChannelSuffix] - binaryMessenger:binaryMessenger - codec:GetFirebaseFirestoreHostApiCodec()]; - if (api) { - NSCAssert([api respondsToSelector:@selector(clearPersistenceApp:completion:)], - @"FirebaseFirestoreHostApi api (%@) doesn't respond to " - @"@selector(clearPersistenceApp:completion:)", - api); - [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { - NSArray *args = message; - FirestorePigeonFirebaseApp *arg_app = GetNullableObjectAtIndex(args, 0); - [api clearPersistenceApp:arg_app - completion:^(FlutterError *_Nullable error) { - callback(wrapResult(nil, error)); - }]; - }]; - } else { - [channel setMessageHandler:nil]; - } - } - { - FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] - initWithName:[NSString - stringWithFormat:@"%@%@", - @"dev.flutter.pigeon.cloud_firestore_platform_" - @"interface.FirebaseFirestoreHostApi.disableNetwork", - messageChannelSuffix] - binaryMessenger:binaryMessenger - codec:GetFirebaseFirestoreHostApiCodec()]; - if (api) { - NSCAssert([api respondsToSelector:@selector(disableNetworkApp:completion:)], - @"FirebaseFirestoreHostApi api (%@) doesn't respond to " - @"@selector(disableNetworkApp:completion:)", - api); - [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { - NSArray *args = message; - FirestorePigeonFirebaseApp *arg_app = GetNullableObjectAtIndex(args, 0); - [api disableNetworkApp:arg_app - completion:^(FlutterError *_Nullable error) { - callback(wrapResult(nil, error)); - }]; - }]; - } else { - [channel setMessageHandler:nil]; - } - } - { - FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] - initWithName:[NSString - stringWithFormat:@"%@%@", - @"dev.flutter.pigeon.cloud_firestore_platform_" - @"interface.FirebaseFirestoreHostApi.enableNetwork", - messageChannelSuffix] - binaryMessenger:binaryMessenger - codec:GetFirebaseFirestoreHostApiCodec()]; - if (api) { - NSCAssert([api respondsToSelector:@selector(enableNetworkApp:completion:)], - @"FirebaseFirestoreHostApi api (%@) doesn't respond to " - @"@selector(enableNetworkApp:completion:)", - api); - [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { - NSArray *args = message; - FirestorePigeonFirebaseApp *arg_app = GetNullableObjectAtIndex(args, 0); - [api enableNetworkApp:arg_app - completion:^(FlutterError *_Nullable error) { - callback(wrapResult(nil, error)); - }]; - }]; - } else { - [channel setMessageHandler:nil]; - } - } - { - FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] - initWithName:[NSString stringWithFormat:@"%@%@", - @"dev.flutter.pigeon.cloud_firestore_platform_" - @"interface.FirebaseFirestoreHostApi.terminate", - messageChannelSuffix] - binaryMessenger:binaryMessenger - codec:GetFirebaseFirestoreHostApiCodec()]; - if (api) { - NSCAssert([api respondsToSelector:@selector(terminateApp:completion:)], - @"FirebaseFirestoreHostApi api (%@) doesn't respond to " - @"@selector(terminateApp:completion:)", - api); - [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { - NSArray *args = message; - FirestorePigeonFirebaseApp *arg_app = GetNullableObjectAtIndex(args, 0); - [api terminateApp:arg_app - completion:^(FlutterError *_Nullable error) { - callback(wrapResult(nil, error)); - }]; - }]; - } else { - [channel setMessageHandler:nil]; - } - } - { - FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] - initWithName: - [NSString stringWithFormat:@"%@%@", - @"dev.flutter.pigeon.cloud_firestore_platform_interface." - @"FirebaseFirestoreHostApi.waitForPendingWrites", - messageChannelSuffix] - binaryMessenger:binaryMessenger - codec:GetFirebaseFirestoreHostApiCodec()]; - if (api) { - NSCAssert([api respondsToSelector:@selector(waitForPendingWritesApp:completion:)], - @"FirebaseFirestoreHostApi api (%@) doesn't respond to " - @"@selector(waitForPendingWritesApp:completion:)", - api); - [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { - NSArray *args = message; - FirestorePigeonFirebaseApp *arg_app = GetNullableObjectAtIndex(args, 0); - [api waitForPendingWritesApp:arg_app - completion:^(FlutterError *_Nullable error) { - callback(wrapResult(nil, error)); - }]; - }]; - } else { - [channel setMessageHandler:nil]; - } - } - { - FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] - initWithName: - [NSString stringWithFormat:@"%@%@", - @"dev.flutter.pigeon.cloud_firestore_platform_interface." - @"FirebaseFirestoreHostApi.setIndexConfiguration", - messageChannelSuffix] - binaryMessenger:binaryMessenger - codec:GetFirebaseFirestoreHostApiCodec()]; - if (api) { - NSCAssert( - [api respondsToSelector:@selector( - setIndexConfigurationApp:indexConfiguration:completion:)], - @"FirebaseFirestoreHostApi api (%@) doesn't respond to " - @"@selector(setIndexConfigurationApp:indexConfiguration:completion:)", - api); - [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { - NSArray *args = message; - FirestorePigeonFirebaseApp *arg_app = GetNullableObjectAtIndex(args, 0); - NSString *arg_indexConfiguration = GetNullableObjectAtIndex(args, 1); - [api setIndexConfigurationApp:arg_app - indexConfiguration:arg_indexConfiguration - completion:^(FlutterError *_Nullable error) { - callback(wrapResult(nil, error)); - }]; - }]; - } else { - [channel setMessageHandler:nil]; - } - } - { - FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] - initWithName: - [NSString stringWithFormat:@"%@%@", - @"dev.flutter.pigeon.cloud_firestore_platform_interface." - @"FirebaseFirestoreHostApi.setLoggingEnabled", - messageChannelSuffix] - binaryMessenger:binaryMessenger - codec:GetFirebaseFirestoreHostApiCodec()]; - if (api) { - NSCAssert([api respondsToSelector:@selector(setLoggingEnabledLoggingEnabled:completion:)], - @"FirebaseFirestoreHostApi api (%@) doesn't respond to " - @"@selector(setLoggingEnabledLoggingEnabled:completion:)", - api); - [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { - NSArray *args = message; - BOOL arg_loggingEnabled = [GetNullableObjectAtIndex(args, 0) boolValue]; - [api setLoggingEnabledLoggingEnabled:arg_loggingEnabled - completion:^(FlutterError *_Nullable error) { - callback(wrapResult(nil, error)); - }]; - }]; - } else { - [channel setMessageHandler:nil]; - } - } - { - FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] - initWithName: - [NSString stringWithFormat:@"%@%@", - @"dev.flutter.pigeon.cloud_firestore_platform_interface." - @"FirebaseFirestoreHostApi.snapshotsInSyncSetup", - messageChannelSuffix] - binaryMessenger:binaryMessenger - codec:GetFirebaseFirestoreHostApiCodec()]; - if (api) { - NSCAssert([api respondsToSelector:@selector(snapshotsInSyncSetupApp:completion:)], - @"FirebaseFirestoreHostApi api (%@) doesn't respond to " - @"@selector(snapshotsInSyncSetupApp:completion:)", - api); - [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { - NSArray *args = message; - FirestorePigeonFirebaseApp *arg_app = GetNullableObjectAtIndex(args, 0); - [api snapshotsInSyncSetupApp:arg_app - completion:^(NSString *_Nullable output, FlutterError *_Nullable error) { - callback(wrapResult(output, error)); - }]; - }]; - } else { - [channel setMessageHandler:nil]; - } - } - { - FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] - initWithName: - [NSString stringWithFormat:@"%@%@", - @"dev.flutter.pigeon.cloud_firestore_platform_interface." - @"FirebaseFirestoreHostApi.transactionCreate", - messageChannelSuffix] - binaryMessenger:binaryMessenger - codec:GetFirebaseFirestoreHostApiCodec()]; - if (api) { - NSCAssert( - [api respondsToSelector:@selector(transactionCreateApp:timeout:maxAttempts:completion:)], - @"FirebaseFirestoreHostApi api (%@) doesn't respond to " - @"@selector(transactionCreateApp:timeout:maxAttempts:completion:)", - api); - [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { - NSArray *args = message; - FirestorePigeonFirebaseApp *arg_app = GetNullableObjectAtIndex(args, 0); - NSInteger arg_timeout = [GetNullableObjectAtIndex(args, 1) integerValue]; - NSInteger arg_maxAttempts = [GetNullableObjectAtIndex(args, 2) integerValue]; - [api transactionCreateApp:arg_app - timeout:arg_timeout - maxAttempts:arg_maxAttempts - completion:^(NSString *_Nullable output, FlutterError *_Nullable error) { - callback(wrapResult(output, error)); - }]; - }]; - } else { - [channel setMessageHandler:nil]; - } - } - { - FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] - initWithName: - [NSString stringWithFormat:@"%@%@", - @"dev.flutter.pigeon.cloud_firestore_platform_interface." - @"FirebaseFirestoreHostApi.transactionStoreResult", - messageChannelSuffix] - binaryMessenger:binaryMessenger - codec:GetFirebaseFirestoreHostApiCodec()]; - if (api) { - NSCAssert([api respondsToSelector:@selector(transactionStoreResultTransactionId:resultType: - commands:completion:)], - @"FirebaseFirestoreHostApi api (%@) doesn't respond to " - @"@selector(transactionStoreResultTransactionId:resultType:commands:completion:)", - api); - [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { - NSArray *args = message; - NSString *arg_transactionId = GetNullableObjectAtIndex(args, 0); - InternalTransactionResultBox *boxedInternalTransactionResult = - GetNullableObjectAtIndex(args, 1); - InternalTransactionResult arg_resultType = boxedInternalTransactionResult.value; - NSArray *arg_commands = GetNullableObjectAtIndex(args, 2); - [api transactionStoreResultTransactionId:arg_transactionId - resultType:arg_resultType - commands:arg_commands - completion:^(FlutterError *_Nullable error) { - callback(wrapResult(nil, error)); - }]; - }]; - } else { - [channel setMessageHandler:nil]; - } - } - { - FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] - initWithName:[NSString - stringWithFormat:@"%@%@", - @"dev.flutter.pigeon.cloud_firestore_platform_" - @"interface.FirebaseFirestoreHostApi.transactionGet", - messageChannelSuffix] - binaryMessenger:binaryMessenger - codec:GetFirebaseFirestoreHostApiCodec()]; - if (api) { - NSCAssert( - [api respondsToSelector:@selector(transactionGetApp:transactionId:path:completion:)], - @"FirebaseFirestoreHostApi api (%@) doesn't respond to " - @"@selector(transactionGetApp:transactionId:path:completion:)", - api); - [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { - NSArray *args = message; - FirestorePigeonFirebaseApp *arg_app = GetNullableObjectAtIndex(args, 0); - NSString *arg_transactionId = GetNullableObjectAtIndex(args, 1); - NSString *arg_path = GetNullableObjectAtIndex(args, 2); - [api transactionGetApp:arg_app - transactionId:arg_transactionId - path:arg_path - completion:^(InternalDocumentSnapshot *_Nullable output, - FlutterError *_Nullable error) { - callback(wrapResult(output, error)); - }]; - }]; - } else { - [channel setMessageHandler:nil]; - } - } - { - FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] - initWithName: - [NSString stringWithFormat:@"%@%@", - @"dev.flutter.pigeon.cloud_firestore_platform_interface." - @"FirebaseFirestoreHostApi.documentReferenceSet", - messageChannelSuffix] - binaryMessenger:binaryMessenger - codec:GetFirebaseFirestoreHostApiCodec()]; - if (api) { - NSCAssert([api respondsToSelector:@selector(documentReferenceSetApp:request:completion:)], - @"FirebaseFirestoreHostApi api (%@) doesn't respond to " - @"@selector(documentReferenceSetApp:request:completion:)", - api); - [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { - NSArray *args = message; - FirestorePigeonFirebaseApp *arg_app = GetNullableObjectAtIndex(args, 0); - DocumentReferenceRequest *arg_request = GetNullableObjectAtIndex(args, 1); - [api documentReferenceSetApp:arg_app - request:arg_request - completion:^(FlutterError *_Nullable error) { - callback(wrapResult(nil, error)); - }]; - }]; - } else { - [channel setMessageHandler:nil]; - } - } - { - FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] - initWithName: - [NSString stringWithFormat:@"%@%@", - @"dev.flutter.pigeon.cloud_firestore_platform_interface." - @"FirebaseFirestoreHostApi.documentReferenceUpdate", - messageChannelSuffix] - binaryMessenger:binaryMessenger - codec:GetFirebaseFirestoreHostApiCodec()]; - if (api) { - NSCAssert([api respondsToSelector:@selector(documentReferenceUpdateApp:request:completion:)], - @"FirebaseFirestoreHostApi api (%@) doesn't respond to " - @"@selector(documentReferenceUpdateApp:request:completion:)", - api); - [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { - NSArray *args = message; - FirestorePigeonFirebaseApp *arg_app = GetNullableObjectAtIndex(args, 0); - DocumentReferenceRequest *arg_request = GetNullableObjectAtIndex(args, 1); - [api documentReferenceUpdateApp:arg_app - request:arg_request - completion:^(FlutterError *_Nullable error) { - callback(wrapResult(nil, error)); - }]; - }]; - } else { - [channel setMessageHandler:nil]; - } - } - { - FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] - initWithName: - [NSString stringWithFormat:@"%@%@", - @"dev.flutter.pigeon.cloud_firestore_platform_interface." - @"FirebaseFirestoreHostApi.documentReferenceGet", - messageChannelSuffix] - binaryMessenger:binaryMessenger - codec:GetFirebaseFirestoreHostApiCodec()]; - if (api) { - NSCAssert([api respondsToSelector:@selector(documentReferenceGetApp:request:completion:)], - @"FirebaseFirestoreHostApi api (%@) doesn't respond to " - @"@selector(documentReferenceGetApp:request:completion:)", - api); - [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { - NSArray *args = message; - FirestorePigeonFirebaseApp *arg_app = GetNullableObjectAtIndex(args, 0); - DocumentReferenceRequest *arg_request = GetNullableObjectAtIndex(args, 1); - [api documentReferenceGetApp:arg_app - request:arg_request - completion:^(InternalDocumentSnapshot *_Nullable output, - FlutterError *_Nullable error) { - callback(wrapResult(output, error)); - }]; - }]; - } else { - [channel setMessageHandler:nil]; - } - } - { - FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] - initWithName: - [NSString stringWithFormat:@"%@%@", - @"dev.flutter.pigeon.cloud_firestore_platform_interface." - @"FirebaseFirestoreHostApi.documentReferenceDelete", - messageChannelSuffix] - binaryMessenger:binaryMessenger - codec:GetFirebaseFirestoreHostApiCodec()]; - if (api) { - NSCAssert([api respondsToSelector:@selector(documentReferenceDeleteApp:request:completion:)], - @"FirebaseFirestoreHostApi api (%@) doesn't respond to " - @"@selector(documentReferenceDeleteApp:request:completion:)", - api); - [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { - NSArray *args = message; - FirestorePigeonFirebaseApp *arg_app = GetNullableObjectAtIndex(args, 0); - DocumentReferenceRequest *arg_request = GetNullableObjectAtIndex(args, 1); - [api documentReferenceDeleteApp:arg_app - request:arg_request - completion:^(FlutterError *_Nullable error) { - callback(wrapResult(nil, error)); - }]; - }]; - } else { - [channel setMessageHandler:nil]; - } - } - { - FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] - initWithName:[NSString stringWithFormat:@"%@%@", - @"dev.flutter.pigeon.cloud_firestore_platform_" - @"interface.FirebaseFirestoreHostApi.queryGet", - messageChannelSuffix] - binaryMessenger:binaryMessenger - codec:GetFirebaseFirestoreHostApiCodec()]; - if (api) { - NSCAssert([api respondsToSelector:@selector(queryGetApp:path:isCollectionGroup:parameters: - options:completion:)], - @"FirebaseFirestoreHostApi api (%@) doesn't respond to " - @"@selector(queryGetApp:path:isCollectionGroup:parameters:options:completion:)", - api); - [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { - NSArray *args = message; - FirestorePigeonFirebaseApp *arg_app = GetNullableObjectAtIndex(args, 0); - NSString *arg_path = GetNullableObjectAtIndex(args, 1); - BOOL arg_isCollectionGroup = [GetNullableObjectAtIndex(args, 2) boolValue]; - InternalQueryParameters *arg_parameters = GetNullableObjectAtIndex(args, 3); - InternalGetOptions *arg_options = GetNullableObjectAtIndex(args, 4); - [api queryGetApp:arg_app - path:arg_path - isCollectionGroup:arg_isCollectionGroup - parameters:arg_parameters - options:arg_options - completion:^(InternalQuerySnapshot *_Nullable output, - FlutterError *_Nullable error) { - callback(wrapResult(output, error)); - }]; - }]; - } else { - [channel setMessageHandler:nil]; - } - } - { - FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] - initWithName:[NSString - stringWithFormat:@"%@%@", - @"dev.flutter.pigeon.cloud_firestore_platform_" - @"interface.FirebaseFirestoreHostApi.aggregateQuery", - messageChannelSuffix] - binaryMessenger:binaryMessenger - codec:GetFirebaseFirestoreHostApiCodec()]; - if (api) { - NSCAssert([api respondsToSelector:@selector(aggregateQueryApp:path:parameters:source:queries: - isCollectionGroup:completion:)], - @"FirebaseFirestoreHostApi api (%@) doesn't respond to " - @"@selector(aggregateQueryApp:path:parameters:source:queries:isCollectionGroup:" - @"completion:)", - api); - [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { - NSArray *args = message; - FirestorePigeonFirebaseApp *arg_app = GetNullableObjectAtIndex(args, 0); - NSString *arg_path = GetNullableObjectAtIndex(args, 1); - InternalQueryParameters *arg_parameters = GetNullableObjectAtIndex(args, 2); - AggregateSourceBox *boxedAggregateSource = GetNullableObjectAtIndex(args, 3); - AggregateSource arg_source = boxedAggregateSource.value; - NSArray *arg_queries = GetNullableObjectAtIndex(args, 4); - BOOL arg_isCollectionGroup = [GetNullableObjectAtIndex(args, 5) boolValue]; - [api aggregateQueryApp:arg_app - path:arg_path - parameters:arg_parameters - source:arg_source - queries:arg_queries - isCollectionGroup:arg_isCollectionGroup - completion:^(NSArray *_Nullable output, - FlutterError *_Nullable error) { - callback(wrapResult(output, error)); - }]; - }]; - } else { - [channel setMessageHandler:nil]; - } - } - { - FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] - initWithName:[NSString - stringWithFormat:@"%@%@", - @"dev.flutter.pigeon.cloud_firestore_platform_" - @"interface.FirebaseFirestoreHostApi.writeBatchCommit", - messageChannelSuffix] - binaryMessenger:binaryMessenger - codec:GetFirebaseFirestoreHostApiCodec()]; - if (api) { - NSCAssert([api respondsToSelector:@selector(writeBatchCommitApp:writes:completion:)], - @"FirebaseFirestoreHostApi api (%@) doesn't respond to " - @"@selector(writeBatchCommitApp:writes:completion:)", - api); - [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { - NSArray *args = message; - FirestorePigeonFirebaseApp *arg_app = GetNullableObjectAtIndex(args, 0); - NSArray *arg_writes = GetNullableObjectAtIndex(args, 1); - [api writeBatchCommitApp:arg_app - writes:arg_writes - completion:^(FlutterError *_Nullable error) { - callback(wrapResult(nil, error)); - }]; - }]; - } else { - [channel setMessageHandler:nil]; - } - } - { - FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] - initWithName:[NSString - stringWithFormat:@"%@%@", - @"dev.flutter.pigeon.cloud_firestore_platform_" - @"interface.FirebaseFirestoreHostApi.querySnapshot", - messageChannelSuffix] - binaryMessenger:binaryMessenger - codec:GetFirebaseFirestoreHostApiCodec()]; - if (api) { - NSCAssert( - [api respondsToSelector:@selector(querySnapshotApp:path:isCollectionGroup:parameters: - options:includeMetadataChanges:source:completion:)], - @"FirebaseFirestoreHostApi api (%@) doesn't respond to " - @"@selector(querySnapshotApp:path:isCollectionGroup:parameters:options:" - @"includeMetadataChanges:source:completion:)", - api); - [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { - NSArray *args = message; - FirestorePigeonFirebaseApp *arg_app = GetNullableObjectAtIndex(args, 0); - NSString *arg_path = GetNullableObjectAtIndex(args, 1); - BOOL arg_isCollectionGroup = [GetNullableObjectAtIndex(args, 2) boolValue]; - InternalQueryParameters *arg_parameters = GetNullableObjectAtIndex(args, 3); - InternalGetOptions *arg_options = GetNullableObjectAtIndex(args, 4); - BOOL arg_includeMetadataChanges = [GetNullableObjectAtIndex(args, 5) boolValue]; - ListenSourceBox *boxedListenSource = GetNullableObjectAtIndex(args, 6); - ListenSource arg_source = boxedListenSource.value; - [api querySnapshotApp:arg_app - path:arg_path - isCollectionGroup:arg_isCollectionGroup - parameters:arg_parameters - options:arg_options - includeMetadataChanges:arg_includeMetadataChanges - source:arg_source - completion:^(NSString *_Nullable output, FlutterError *_Nullable error) { - callback(wrapResult(output, error)); - }]; - }]; - } else { - [channel setMessageHandler:nil]; - } - } - { - FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] - initWithName: - [NSString stringWithFormat:@"%@%@", - @"dev.flutter.pigeon.cloud_firestore_platform_interface." - @"FirebaseFirestoreHostApi.documentReferenceSnapshot", - messageChannelSuffix] - binaryMessenger:binaryMessenger - codec:GetFirebaseFirestoreHostApiCodec()]; - if (api) { - NSCAssert([api respondsToSelector:@selector(documentReferenceSnapshotApp:parameters: - includeMetadataChanges:source:completion:)], - @"FirebaseFirestoreHostApi api (%@) doesn't respond to " - @"@selector(documentReferenceSnapshotApp:parameters:includeMetadataChanges:source:" - @"completion:)", - api); - [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { - NSArray *args = message; - FirestorePigeonFirebaseApp *arg_app = GetNullableObjectAtIndex(args, 0); - DocumentReferenceRequest *arg_parameters = GetNullableObjectAtIndex(args, 1); - BOOL arg_includeMetadataChanges = [GetNullableObjectAtIndex(args, 2) boolValue]; - ListenSourceBox *boxedListenSource = GetNullableObjectAtIndex(args, 3); - ListenSource arg_source = boxedListenSource.value; - [api documentReferenceSnapshotApp:arg_app - parameters:arg_parameters - includeMetadataChanges:arg_includeMetadataChanges - source:arg_source - completion:^(NSString *_Nullable output, - FlutterError *_Nullable error) { - callback(wrapResult(output, error)); - }]; - }]; - } else { - [channel setMessageHandler:nil]; - } - } - { - FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] - initWithName: - [NSString - stringWithFormat:@"%@%@", - @"dev.flutter.pigeon.cloud_firestore_platform_interface." - @"FirebaseFirestoreHostApi.persistenceCacheIndexManagerRequest", - messageChannelSuffix] - binaryMessenger:binaryMessenger - codec:GetFirebaseFirestoreHostApiCodec()]; - if (api) { - NSCAssert( - [api respondsToSelector:@selector( - persistenceCacheIndexManagerRequestApp:request:completion:)], - @"FirebaseFirestoreHostApi api (%@) doesn't respond to " - @"@selector(persistenceCacheIndexManagerRequestApp:request:completion:)", - api); - [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { - NSArray *args = message; - FirestorePigeonFirebaseApp *arg_app = GetNullableObjectAtIndex(args, 0); - PersistenceCacheIndexManagerRequestBox *boxedPersistenceCacheIndexManagerRequest = - GetNullableObjectAtIndex(args, 1); - PersistenceCacheIndexManagerRequest arg_request = - boxedPersistenceCacheIndexManagerRequest.value; - [api persistenceCacheIndexManagerRequestApp:arg_app - request:arg_request - completion:^(FlutterError *_Nullable error) { - callback(wrapResult(nil, error)); - }]; - }]; - } else { - [channel setMessageHandler:nil]; - } - } - { - FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] - initWithName:[NSString - stringWithFormat:@"%@%@", - @"dev.flutter.pigeon.cloud_firestore_platform_" - @"interface.FirebaseFirestoreHostApi.executePipeline", - messageChannelSuffix] - binaryMessenger:binaryMessenger - codec:GetFirebaseFirestoreHostApiCodec()]; - if (api) { - NSCAssert([api respondsToSelector:@selector(executePipelineApp:stages:options:completion:)], - @"FirebaseFirestoreHostApi api (%@) doesn't respond to " - @"@selector(executePipelineApp:stages:options:completion:)", - api); - [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { - NSArray *args = message; - FirestorePigeonFirebaseApp *arg_app = GetNullableObjectAtIndex(args, 0); - NSArray *> *arg_stages = GetNullableObjectAtIndex(args, 1); - NSDictionary *arg_options = GetNullableObjectAtIndex(args, 2); - [api executePipelineApp:arg_app - stages:arg_stages - options:arg_options - completion:^(InternalPipelineSnapshot *_Nullable output, - FlutterError *_Nullable error) { - callback(wrapResult(output, error)); - }]; - }]; - } else { - [channel setMessageHandler:nil]; - } - } -} diff --git a/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/FirestoreMessages.g.swift b/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/FirestoreMessages.g.swift new file mode 100644 index 000000000000..270e4af3b76a --- /dev/null +++ b/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/FirestoreMessages.g.swift @@ -0,0 +1,1922 @@ +// Copyright 2023, the Chromium project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. +// Autogenerated from Pigeon (v26.3.4), do not edit directly. +// See also: https://pub.dev/packages/pigeon + +import Foundation + +#if os(iOS) + import Flutter +#elseif os(macOS) + import FlutterMacOS +#else + #error("Unsupported platform.") +#endif + +/// Error class for passing custom error details to Dart side. +final class PigeonError: Error { + let code: String + let message: String? + let details: Sendable? + + init(code: String, message: String?, details: Sendable?) { + self.code = code + self.message = message + self.details = details + } + + var localizedDescription: String { + "PigeonError(code: \(code), message: \(message ?? ""), details: \(details ?? "")" + } +} + +private func wrapResult(_ result: Any?) -> [Any?] { + [result] +} + +private func wrapError(_ error: Any) -> [Any?] { + if let pigeonError = error as? PigeonError { + return [ + pigeonError.code, + pigeonError.message, + pigeonError.details, + ] + } + if let flutterError = error as? FlutterError { + return [ + flutterError.code, + flutterError.message, + flutterError.details, + ] + } + return [ + "\(error)", + "\(Swift.type(of: error))", + "Stacktrace: \(Thread.callStackSymbols)", + ] +} + +private func isNullish(_ value: Any?) -> Bool { + value is NSNull || value == nil +} + +private func nilOrValue(_ value: Any?) -> T? { + if value is NSNull { return nil } + return value as! T? +} + +private func doubleEqualsFirestoreMessages(_ lhs: Double, _ rhs: Double) -> Bool { + (lhs.isNaN && rhs.isNaN) || lhs == rhs +} + +private func doubleHashFirestoreMessages(_ value: Double, _ hasher: inout Hasher) { + if value.isNaN { + hasher.combine(0x7FF8_0000_0000_0000) + } else { + // Normalize -0.0 to 0.0 + hasher.combine(value == 0 ? 0 : value) + } +} + +func deepEqualsFirestoreMessages(_ lhs: Any?, _ rhs: Any?) -> Bool { + let cleanLhs = nilOrValue(lhs) as Any? + let cleanRhs = nilOrValue(rhs) as Any? + switch (cleanLhs, cleanRhs) { + case (nil, nil): + return true + + case (nil, _), (_, nil): + return false + + case (let lhs as AnyObject, let rhs as AnyObject) where lhs === rhs: + return true + + case is (Void, Void): + return true + + case (let lhsArray, let rhsArray) as ([Any?], [Any?]): + guard lhsArray.count == rhsArray.count else { return false } + for (index, element) in lhsArray.enumerated() { + if !deepEqualsFirestoreMessages(element, rhsArray[index]) { + return false + } + } + return true + + case (let lhsArray, let rhsArray) as ([Double], [Double]): + guard lhsArray.count == rhsArray.count else { return false } + for (index, element) in lhsArray.enumerated() { + if !doubleEqualsFirestoreMessages(element, rhsArray[index]) { + return false + } + } + return true + + case (let lhsDictionary, let rhsDictionary) as ([AnyHashable: Any?], [AnyHashable: Any?]): + guard lhsDictionary.count == rhsDictionary.count else { return false } + for (lhsKey, lhsValue) in lhsDictionary { + var found = false + for (rhsKey, rhsValue) in rhsDictionary { + if deepEqualsFirestoreMessages(lhsKey, rhsKey) { + if deepEqualsFirestoreMessages(lhsValue, rhsValue) { + found = true + break + } else { + return false + } + } + } + if !found { return false } + } + return true + + case (let lhs as Double, let rhs as Double): + return doubleEqualsFirestoreMessages(lhs, rhs) + + case (let lhsHashable, let rhsHashable) as (AnyHashable, AnyHashable): + return lhsHashable == rhsHashable + + default: + return false + } +} + +func deepHashFirestoreMessages(value: Any?, hasher: inout Hasher) { + let cleanValue = nilOrValue(value) as Any? + if let cleanValue { + if let doubleValue = cleanValue as? Double { + doubleHashFirestoreMessages(doubleValue, &hasher) + } else if let valueList = cleanValue as? [Any?] { + for item in valueList { + deepHashFirestoreMessages(value: item, hasher: &hasher) + } + } else if let valueList = cleanValue as? [Double] { + for item in valueList { + doubleHashFirestoreMessages(item, &hasher) + } + } else if let valueDict = cleanValue as? [AnyHashable: Any?] { + var result = 0 + for (key, value) in valueDict { + var entryKeyHasher = Hasher() + deepHashFirestoreMessages(value: key, hasher: &entryKeyHasher) + var entryValueHasher = Hasher() + deepHashFirestoreMessages(value: value, hasher: &entryValueHasher) + result = result &+ ((entryKeyHasher.finalize() &* 31) ^ entryValueHasher.finalize()) + } + hasher.combine(result) + } else if let hashableValue = cleanValue as? AnyHashable { + hasher.combine(hashableValue) + } else { + hasher.combine(String(describing: cleanValue)) + } + } else { + hasher.combine(0) + } +} + +/// An enumeration of document change types. +enum DocumentChangeType: Int { + /// Indicates a new document was added to the set of documents matching the + /// query. + case added = 0 + /// Indicates a document within the query was modified. + case modified = 1 + /// Indicates a document within the query was removed (either deleted or no + /// longer matches the query. + case removed = 2 +} + +/// An enumeration of firestore source types. +enum Source: Int { + /// Causes Firestore to try to retrieve an up-to-date (server-retrieved) snapshot, but fall back + /// to + /// returning cached data if the server can't be reached. + case serverAndCache = 0 + /// Causes Firestore to avoid the cache, generating an error if the server cannot be reached. Note + /// that the cache will still be updated if the server request succeeds. Also note that + /// latency-compensation still takes effect, so any pending write operations will be visible in + /// the + /// returned data (merged into the server-provided data). + case server = 1 + /// Causes Firestore to immediately return a value from the cache, ignoring the server completely + /// (implying that the returned value may be stale with respect to the value on the server). If + /// there is no data in the cache to satisfy the `get` call, + /// [DocumentReference.get] will throw a [FirebaseException] and + /// [Query.get] will return an empty [QuerySnapshotPlatform] with no documents. + case cache = 2 +} + +/// The listener retrieves data and listens to updates from the local Firestore cache only. +/// If the cache is empty, an empty snapshot will be returned. +/// Snapshot events will be triggered on cache updates, like local mutations or load bundles. +/// +/// Note that the data might be stale if the cache hasn't synchronized with recent server-side +/// changes. +enum ListenSource: Int { + /// The default behavior. The listener attempts to return initial snapshot from cache and retrieve + /// up-to-date snapshots from the Firestore server. + /// Snapshot events will be triggered on local mutations and server side updates. + case defaultSource = 0 + /// The listener retrieves data and listens to updates from the local Firestore cache only. + /// If the cache is empty, an empty snapshot will be returned. + /// Snapshot events will be triggered on cache updates, like local mutations or load bundles. + case cache = 1 +} + +enum ServerTimestampBehavior: Int { + /// Return null for [FieldValue.serverTimestamp()] values that have not yet + case none = 0 + /// Return local estimates for [FieldValue.serverTimestamp()] values that have not yet been set to + /// their final value. + case estimate = 1 + /// Return the previous value for [FieldValue.serverTimestamp()] values that have not yet been set + /// to their final value. + case previous = 2 +} + +/// [AggregateSource] represents the source of data for an [AggregateQuery]. +enum AggregateSource: Int { + /// Indicates that the data should be retrieved from the server. + case server = 0 +} + +/// [PersistenceCacheIndexManagerRequest] represents the request types for the persistence cache +/// index manager. +enum PersistenceCacheIndexManagerRequest: Int { + case enableIndexAutoCreation = 0 + case disableIndexAutoCreation = 1 + case deleteAllIndexes = 2 +} + +enum InternalTransactionResult: Int { + case success = 0 + case failure = 1 +} + +enum InternalTransactionType: Int { + case get = 0 + case update = 1 + case set = 2 + case deleteType = 3 +} + +enum AggregateType: Int { + case count = 0 + case sum = 1 + case average = 2 +} + +/// Generated class from Pigeon that represents data sent in messages. +struct InternalFirebaseSettings: Hashable { + var persistenceEnabled: Bool? + var host: String? + var sslEnabled: Bool? + var cacheSizeBytes: Int64? + var ignoreUndefinedProperties: Bool + + // swift-format-ignore: AlwaysUseLowerCamelCase + static func fromList(_ pigeonVar_list: [Any?]) -> InternalFirebaseSettings? { + let persistenceEnabled: Bool? = nilOrValue(pigeonVar_list[0]) + let host: String? = nilOrValue(pigeonVar_list[1]) + let sslEnabled: Bool? = nilOrValue(pigeonVar_list[2]) + let cacheSizeBytes: Int64? = nilOrValue(pigeonVar_list[3]) + let ignoreUndefinedProperties = pigeonVar_list[4] as! Bool + + return InternalFirebaseSettings( + persistenceEnabled: persistenceEnabled, + host: host, + sslEnabled: sslEnabled, + cacheSizeBytes: cacheSizeBytes, + ignoreUndefinedProperties: ignoreUndefinedProperties + ) + } + + func toList() -> [Any?] { + [ + persistenceEnabled, + host, + sslEnabled, + cacheSizeBytes, + ignoreUndefinedProperties, + ] + } + + static func == (lhs: InternalFirebaseSettings, rhs: InternalFirebaseSettings) -> Bool { + if Swift.type(of: lhs) != Swift.type(of: rhs) { + return false + } + return deepEqualsFirestoreMessages(lhs.persistenceEnabled, rhs.persistenceEnabled) + && deepEqualsFirestoreMessages( + lhs.host, + rhs.host + ) && deepEqualsFirestoreMessages(lhs.sslEnabled, rhs.sslEnabled) + && deepEqualsFirestoreMessages( + lhs.cacheSizeBytes, + rhs.cacheSizeBytes + ) + && deepEqualsFirestoreMessages( + lhs.ignoreUndefinedProperties, + rhs.ignoreUndefinedProperties + ) + } + + func hash(into hasher: inout Hasher) { + hasher.combine("InternalFirebaseSettings") + deepHashFirestoreMessages(value: persistenceEnabled, hasher: &hasher) + deepHashFirestoreMessages(value: host, hasher: &hasher) + deepHashFirestoreMessages(value: sslEnabled, hasher: &hasher) + deepHashFirestoreMessages(value: cacheSizeBytes, hasher: &hasher) + deepHashFirestoreMessages(value: ignoreUndefinedProperties, hasher: &hasher) + } +} + +/// Generated class from Pigeon that represents data sent in messages. +struct FirestorePigeonFirebaseApp: Hashable { + var appName: String + var settings: InternalFirebaseSettings + var databaseURL: String + + // swift-format-ignore: AlwaysUseLowerCamelCase + static func fromList(_ pigeonVar_list: [Any?]) -> FirestorePigeonFirebaseApp? { + let appName = pigeonVar_list[0] as! String + let settings = pigeonVar_list[1] as! InternalFirebaseSettings + let databaseURL = pigeonVar_list[2] as! String + + return FirestorePigeonFirebaseApp( + appName: appName, + settings: settings, + databaseURL: databaseURL + ) + } + + func toList() -> [Any?] { + [ + appName, + settings, + databaseURL, + ] + } + + static func == (lhs: FirestorePigeonFirebaseApp, rhs: FirestorePigeonFirebaseApp) -> Bool { + if Swift.type(of: lhs) != Swift.type(of: rhs) { + return false + } + return deepEqualsFirestoreMessages(lhs.appName, rhs.appName) + && deepEqualsFirestoreMessages( + lhs.settings, + rhs.settings + ) && deepEqualsFirestoreMessages(lhs.databaseURL, rhs.databaseURL) + } + + func hash(into hasher: inout Hasher) { + hasher.combine("FirestorePigeonFirebaseApp") + deepHashFirestoreMessages(value: appName, hasher: &hasher) + deepHashFirestoreMessages(value: settings, hasher: &hasher) + deepHashFirestoreMessages(value: databaseURL, hasher: &hasher) + } +} + +/// Generated class from Pigeon that represents data sent in messages. +struct InternalSnapshotMetadata: Hashable { + var hasPendingWrites: Bool + var isFromCache: Bool + + // swift-format-ignore: AlwaysUseLowerCamelCase + static func fromList(_ pigeonVar_list: [Any?]) -> InternalSnapshotMetadata? { + let hasPendingWrites = pigeonVar_list[0] as! Bool + let isFromCache = pigeonVar_list[1] as! Bool + + return InternalSnapshotMetadata( + hasPendingWrites: hasPendingWrites, + isFromCache: isFromCache + ) + } + + func toList() -> [Any?] { + [ + hasPendingWrites, + isFromCache, + ] + } + + static func == (lhs: InternalSnapshotMetadata, rhs: InternalSnapshotMetadata) -> Bool { + if Swift.type(of: lhs) != Swift.type(of: rhs) { + return false + } + return deepEqualsFirestoreMessages(lhs.hasPendingWrites, rhs.hasPendingWrites) + && deepEqualsFirestoreMessages( + lhs.isFromCache, + rhs.isFromCache + ) + } + + func hash(into hasher: inout Hasher) { + hasher.combine("InternalSnapshotMetadata") + deepHashFirestoreMessages(value: hasPendingWrites, hasher: &hasher) + deepHashFirestoreMessages(value: isFromCache, hasher: &hasher) + } +} + +/// Generated class from Pigeon that represents data sent in messages. +struct InternalDocumentSnapshot: Hashable { + var path: String + var data: [String?: Any?]? + var metadata: InternalSnapshotMetadata + + // swift-format-ignore: AlwaysUseLowerCamelCase + static func fromList(_ pigeonVar_list: [Any?]) -> InternalDocumentSnapshot? { + let path = pigeonVar_list[0] as! String + let data: [String?: Any?]? = nilOrValue(pigeonVar_list[1]) + let metadata = pigeonVar_list[2] as! InternalSnapshotMetadata + + return InternalDocumentSnapshot( + path: path, + data: data, + metadata: metadata + ) + } + + func toList() -> [Any?] { + [ + path, + data, + metadata, + ] + } + + static func == (lhs: InternalDocumentSnapshot, rhs: InternalDocumentSnapshot) -> Bool { + if Swift.type(of: lhs) != Swift.type(of: rhs) { + return false + } + return deepEqualsFirestoreMessages(lhs.path, rhs.path) + && deepEqualsFirestoreMessages( + lhs.data, + rhs.data + ) && deepEqualsFirestoreMessages(lhs.metadata, rhs.metadata) + } + + func hash(into hasher: inout Hasher) { + hasher.combine("InternalDocumentSnapshot") + deepHashFirestoreMessages(value: path, hasher: &hasher) + deepHashFirestoreMessages(value: data, hasher: &hasher) + deepHashFirestoreMessages(value: metadata, hasher: &hasher) + } +} + +/// Generated class from Pigeon that represents data sent in messages. +struct InternalDocumentChange: Hashable { + var type: DocumentChangeType + var document: InternalDocumentSnapshot + var oldIndex: Int64 + var newIndex: Int64 + + // swift-format-ignore: AlwaysUseLowerCamelCase + static func fromList(_ pigeonVar_list: [Any?]) -> InternalDocumentChange? { + let type = pigeonVar_list[0] as! DocumentChangeType + let document = pigeonVar_list[1] as! InternalDocumentSnapshot + let oldIndex = pigeonVar_list[2] as! Int64 + let newIndex = pigeonVar_list[3] as! Int64 + + return InternalDocumentChange( + type: type, + document: document, + oldIndex: oldIndex, + newIndex: newIndex + ) + } + + func toList() -> [Any?] { + [ + type, + document, + oldIndex, + newIndex, + ] + } + + static func == (lhs: InternalDocumentChange, rhs: InternalDocumentChange) -> Bool { + if Swift.type(of: lhs) != Swift.type(of: rhs) { + return false + } + return deepEqualsFirestoreMessages(lhs.type, rhs.type) + && deepEqualsFirestoreMessages( + lhs.document, + rhs.document + ) && deepEqualsFirestoreMessages(lhs.oldIndex, rhs.oldIndex) + && deepEqualsFirestoreMessages( + lhs.newIndex, + rhs.newIndex + ) + } + + func hash(into hasher: inout Hasher) { + hasher.combine("InternalDocumentChange") + deepHashFirestoreMessages(value: type, hasher: &hasher) + deepHashFirestoreMessages(value: document, hasher: &hasher) + deepHashFirestoreMessages(value: oldIndex, hasher: &hasher) + deepHashFirestoreMessages(value: newIndex, hasher: &hasher) + } +} + +/// Generated class from Pigeon that represents data sent in messages. +struct InternalQuerySnapshot: Hashable { + var documents: [InternalDocumentSnapshot?] + var documentChanges: [InternalDocumentChange?] + var metadata: InternalSnapshotMetadata + + // swift-format-ignore: AlwaysUseLowerCamelCase + static func fromList(_ pigeonVar_list: [Any?]) -> InternalQuerySnapshot? { + let documents = pigeonVar_list[0] as! [InternalDocumentSnapshot?] + let documentChanges = pigeonVar_list[1] as! [InternalDocumentChange?] + let metadata = pigeonVar_list[2] as! InternalSnapshotMetadata + + return InternalQuerySnapshot( + documents: documents, + documentChanges: documentChanges, + metadata: metadata + ) + } + + func toList() -> [Any?] { + [ + documents, + documentChanges, + metadata, + ] + } + + static func == (lhs: InternalQuerySnapshot, rhs: InternalQuerySnapshot) -> Bool { + if Swift.type(of: lhs) != Swift.type(of: rhs) { + return false + } + return deepEqualsFirestoreMessages(lhs.documents, rhs.documents) + && deepEqualsFirestoreMessages( + lhs.documentChanges, + rhs.documentChanges + ) && deepEqualsFirestoreMessages(lhs.metadata, rhs.metadata) + } + + func hash(into hasher: inout Hasher) { + hasher.combine("InternalQuerySnapshot") + deepHashFirestoreMessages(value: documents, hasher: &hasher) + deepHashFirestoreMessages(value: documentChanges, hasher: &hasher) + deepHashFirestoreMessages(value: metadata, hasher: &hasher) + } +} + +/// Generated class from Pigeon that represents data sent in messages. +struct InternalPipelineResult: Hashable { + var documentPath: String? + var createTime: Int64? + var updateTime: Int64? + /// All fields in the result (from PipelineResult.data() on Android). + var data: [String?: Any?]? + + // swift-format-ignore: AlwaysUseLowerCamelCase + static func fromList(_ pigeonVar_list: [Any?]) -> InternalPipelineResult? { + let documentPath: String? = nilOrValue(pigeonVar_list[0]) + let createTime: Int64? = nilOrValue(pigeonVar_list[1]) + let updateTime: Int64? = nilOrValue(pigeonVar_list[2]) + let data: [String?: Any?]? = nilOrValue(pigeonVar_list[3]) + + return InternalPipelineResult( + documentPath: documentPath, + createTime: createTime, + updateTime: updateTime, + data: data + ) + } + + func toList() -> [Any?] { + [ + documentPath, + createTime, + updateTime, + data, + ] + } + + static func == (lhs: InternalPipelineResult, rhs: InternalPipelineResult) -> Bool { + if Swift.type(of: lhs) != Swift.type(of: rhs) { + return false + } + return deepEqualsFirestoreMessages(lhs.documentPath, rhs.documentPath) + && deepEqualsFirestoreMessages( + lhs.createTime, + rhs.createTime + ) && deepEqualsFirestoreMessages(lhs.updateTime, rhs.updateTime) + && deepEqualsFirestoreMessages( + lhs.data, + rhs.data + ) + } + + func hash(into hasher: inout Hasher) { + hasher.combine("InternalPipelineResult") + deepHashFirestoreMessages(value: documentPath, hasher: &hasher) + deepHashFirestoreMessages(value: createTime, hasher: &hasher) + deepHashFirestoreMessages(value: updateTime, hasher: &hasher) + deepHashFirestoreMessages(value: data, hasher: &hasher) + } +} + +/// Generated class from Pigeon that represents data sent in messages. +struct InternalPipelineSnapshot: Hashable { + var results: [InternalPipelineResult?] + var executionTime: Int64 + + // swift-format-ignore: AlwaysUseLowerCamelCase + static func fromList(_ pigeonVar_list: [Any?]) -> InternalPipelineSnapshot? { + let results = pigeonVar_list[0] as! [InternalPipelineResult?] + let executionTime = pigeonVar_list[1] as! Int64 + + return InternalPipelineSnapshot( + results: results, + executionTime: executionTime + ) + } + + func toList() -> [Any?] { + [ + results, + executionTime, + ] + } + + static func == (lhs: InternalPipelineSnapshot, rhs: InternalPipelineSnapshot) -> Bool { + if Swift.type(of: lhs) != Swift.type(of: rhs) { + return false + } + return deepEqualsFirestoreMessages(lhs.results, rhs.results) + && deepEqualsFirestoreMessages( + lhs.executionTime, + rhs.executionTime + ) + } + + func hash(into hasher: inout Hasher) { + hasher.combine("InternalPipelineSnapshot") + deepHashFirestoreMessages(value: results, hasher: &hasher) + deepHashFirestoreMessages(value: executionTime, hasher: &hasher) + } +} + +/// Generated class from Pigeon that represents data sent in messages. +struct InternalGetOptions: Hashable { + var source: Source + var serverTimestampBehavior: ServerTimestampBehavior + + // swift-format-ignore: AlwaysUseLowerCamelCase + static func fromList(_ pigeonVar_list: [Any?]) -> InternalGetOptions? { + let source = pigeonVar_list[0] as! Source + let serverTimestampBehavior = pigeonVar_list[1] as! ServerTimestampBehavior + + return InternalGetOptions( + source: source, + serverTimestampBehavior: serverTimestampBehavior + ) + } + + func toList() -> [Any?] { + [ + source, + serverTimestampBehavior, + ] + } + + static func == (lhs: InternalGetOptions, rhs: InternalGetOptions) -> Bool { + if Swift.type(of: lhs) != Swift.type(of: rhs) { + return false + } + return deepEqualsFirestoreMessages(lhs.source, rhs.source) + && deepEqualsFirestoreMessages( + lhs.serverTimestampBehavior, + rhs.serverTimestampBehavior + ) + } + + func hash(into hasher: inout Hasher) { + hasher.combine("InternalGetOptions") + deepHashFirestoreMessages(value: source, hasher: &hasher) + deepHashFirestoreMessages(value: serverTimestampBehavior, hasher: &hasher) + } +} + +/// Generated class from Pigeon that represents data sent in messages. +struct InternalDocumentOption: Hashable { + var merge: Bool? + var mergeFields: [[String?]?]? + + // swift-format-ignore: AlwaysUseLowerCamelCase + static func fromList(_ pigeonVar_list: [Any?]) -> InternalDocumentOption? { + let merge: Bool? = nilOrValue(pigeonVar_list[0]) + let mergeFields: [[String?]?]? = nilOrValue(pigeonVar_list[1]) + + return InternalDocumentOption( + merge: merge, + mergeFields: mergeFields + ) + } + + func toList() -> [Any?] { + [ + merge, + mergeFields, + ] + } + + static func == (lhs: InternalDocumentOption, rhs: InternalDocumentOption) -> Bool { + if Swift.type(of: lhs) != Swift.type(of: rhs) { + return false + } + return deepEqualsFirestoreMessages(lhs.merge, rhs.merge) + && deepEqualsFirestoreMessages( + lhs.mergeFields, + rhs.mergeFields + ) + } + + func hash(into hasher: inout Hasher) { + hasher.combine("InternalDocumentOption") + deepHashFirestoreMessages(value: merge, hasher: &hasher) + deepHashFirestoreMessages(value: mergeFields, hasher: &hasher) + } +} + +/// Generated class from Pigeon that represents data sent in messages. +struct InternalTransactionCommand: Hashable { + var type: InternalTransactionType + var path: String + var data: [AnyHashable?: Any?]? + var option: InternalDocumentOption? + + // swift-format-ignore: AlwaysUseLowerCamelCase + static func fromList(_ pigeonVar_list: [Any?]) -> InternalTransactionCommand? { + let type = pigeonVar_list[0] as! InternalTransactionType + let path = pigeonVar_list[1] as! String + let data: [AnyHashable?: Any?]? = nilOrValue(pigeonVar_list[2]) + let option: InternalDocumentOption? = nilOrValue(pigeonVar_list[3]) + + return InternalTransactionCommand( + type: type, + path: path, + data: data, + option: option + ) + } + + func toList() -> [Any?] { + [ + type, + path, + data, + option, + ] + } + + static func == (lhs: InternalTransactionCommand, rhs: InternalTransactionCommand) -> Bool { + if Swift.type(of: lhs) != Swift.type(of: rhs) { + return false + } + return deepEqualsFirestoreMessages(lhs.type, rhs.type) + && deepEqualsFirestoreMessages( + lhs.path, + rhs.path + ) && deepEqualsFirestoreMessages(lhs.data, rhs.data) + && deepEqualsFirestoreMessages( + lhs.option, + rhs.option + ) + } + + func hash(into hasher: inout Hasher) { + hasher.combine("InternalTransactionCommand") + deepHashFirestoreMessages(value: type, hasher: &hasher) + deepHashFirestoreMessages(value: path, hasher: &hasher) + deepHashFirestoreMessages(value: data, hasher: &hasher) + deepHashFirestoreMessages(value: option, hasher: &hasher) + } +} + +/// Generated class from Pigeon that represents data sent in messages. +struct DocumentReferenceRequest: Hashable { + var path: String + var data: [AnyHashable?: Any?]? + var option: InternalDocumentOption? + var source: Source? + var serverTimestampBehavior: ServerTimestampBehavior? + + // swift-format-ignore: AlwaysUseLowerCamelCase + static func fromList(_ pigeonVar_list: [Any?]) -> DocumentReferenceRequest? { + let path = pigeonVar_list[0] as! String + let data: [AnyHashable?: Any?]? = nilOrValue(pigeonVar_list[1]) + let option: InternalDocumentOption? = nilOrValue(pigeonVar_list[2]) + let source: Source? = nilOrValue(pigeonVar_list[3]) + let serverTimestampBehavior: ServerTimestampBehavior? = nilOrValue(pigeonVar_list[4]) + + return DocumentReferenceRequest( + path: path, + data: data, + option: option, + source: source, + serverTimestampBehavior: serverTimestampBehavior + ) + } + + func toList() -> [Any?] { + [ + path, + data, + option, + source, + serverTimestampBehavior, + ] + } + + static func == (lhs: DocumentReferenceRequest, rhs: DocumentReferenceRequest) -> Bool { + if Swift.type(of: lhs) != Swift.type(of: rhs) { + return false + } + return deepEqualsFirestoreMessages(lhs.path, rhs.path) + && deepEqualsFirestoreMessages( + lhs.data, + rhs.data + ) && deepEqualsFirestoreMessages(lhs.option, rhs.option) + && deepEqualsFirestoreMessages( + lhs.source, + rhs.source + ) && deepEqualsFirestoreMessages(lhs.serverTimestampBehavior, rhs.serverTimestampBehavior) + } + + func hash(into hasher: inout Hasher) { + hasher.combine("DocumentReferenceRequest") + deepHashFirestoreMessages(value: path, hasher: &hasher) + deepHashFirestoreMessages(value: data, hasher: &hasher) + deepHashFirestoreMessages(value: option, hasher: &hasher) + deepHashFirestoreMessages(value: source, hasher: &hasher) + deepHashFirestoreMessages(value: serverTimestampBehavior, hasher: &hasher) + } +} + +/// Generated class from Pigeon that represents data sent in messages. +struct InternalQueryParameters: Hashable { + var `where`: [[Any?]?]? + var orderBy: [[Any?]?]? + var limit: Int64? + var limitToLast: Int64? + var startAt: [Any?]? + var startAfter: [Any?]? + var endAt: [Any?]? + var endBefore: [Any?]? + var filters: [String?: Any?]? + + // swift-format-ignore: AlwaysUseLowerCamelCase + static func fromList(_ pigeonVar_list: [Any?]) -> InternalQueryParameters? { + let `where`: [[Any?]?]? = nilOrValue(pigeonVar_list[0]) + let orderBy: [[Any?]?]? = nilOrValue(pigeonVar_list[1]) + let limit: Int64? = nilOrValue(pigeonVar_list[2]) + let limitToLast: Int64? = nilOrValue(pigeonVar_list[3]) + let startAt: [Any?]? = nilOrValue(pigeonVar_list[4]) + let startAfter: [Any?]? = nilOrValue(pigeonVar_list[5]) + let endAt: [Any?]? = nilOrValue(pigeonVar_list[6]) + let endBefore: [Any?]? = nilOrValue(pigeonVar_list[7]) + let filters: [String?: Any?]? = nilOrValue(pigeonVar_list[8]) + + return InternalQueryParameters( + where: `where`, + orderBy: orderBy, + limit: limit, + limitToLast: limitToLast, + startAt: startAt, + startAfter: startAfter, + endAt: endAt, + endBefore: endBefore, + filters: filters + ) + } + + func toList() -> [Any?] { + [ + `where`, + orderBy, + limit, + limitToLast, + startAt, + startAfter, + endAt, + endBefore, + filters, + ] + } + + static func == (lhs: InternalQueryParameters, rhs: InternalQueryParameters) -> Bool { + if Swift.type(of: lhs) != Swift.type(of: rhs) { + return false + } + return deepEqualsFirestoreMessages(lhs.where, rhs.where) + && deepEqualsFirestoreMessages( + lhs.orderBy, + rhs.orderBy + ) && deepEqualsFirestoreMessages(lhs.limit, rhs.limit) + && deepEqualsFirestoreMessages( + lhs.limitToLast, + rhs.limitToLast + ) && deepEqualsFirestoreMessages(lhs.startAt, rhs.startAt) + && deepEqualsFirestoreMessages( + lhs.startAfter, + rhs.startAfter + ) && deepEqualsFirestoreMessages(lhs.endAt, rhs.endAt) + && deepEqualsFirestoreMessages( + lhs.endBefore, + rhs.endBefore + ) && deepEqualsFirestoreMessages(lhs.filters, rhs.filters) + } + + func hash(into hasher: inout Hasher) { + hasher.combine("InternalQueryParameters") + deepHashFirestoreMessages(value: `where`, hasher: &hasher) + deepHashFirestoreMessages(value: orderBy, hasher: &hasher) + deepHashFirestoreMessages(value: limit, hasher: &hasher) + deepHashFirestoreMessages(value: limitToLast, hasher: &hasher) + deepHashFirestoreMessages(value: startAt, hasher: &hasher) + deepHashFirestoreMessages(value: startAfter, hasher: &hasher) + deepHashFirestoreMessages(value: endAt, hasher: &hasher) + deepHashFirestoreMessages(value: endBefore, hasher: &hasher) + deepHashFirestoreMessages(value: filters, hasher: &hasher) + } +} + +/// Generated class from Pigeon that represents data sent in messages. +struct AggregateQuery: Hashable { + var type: AggregateType + var field: String? + + // swift-format-ignore: AlwaysUseLowerCamelCase + static func fromList(_ pigeonVar_list: [Any?]) -> AggregateQuery? { + let type = pigeonVar_list[0] as! AggregateType + let field: String? = nilOrValue(pigeonVar_list[1]) + + return AggregateQuery( + type: type, + field: field + ) + } + + func toList() -> [Any?] { + [ + type, + field, + ] + } + + static func == (lhs: AggregateQuery, rhs: AggregateQuery) -> Bool { + if Swift.type(of: lhs) != Swift.type(of: rhs) { + return false + } + return deepEqualsFirestoreMessages(lhs.type, rhs.type) + && deepEqualsFirestoreMessages( + lhs.field, + rhs.field + ) + } + + func hash(into hasher: inout Hasher) { + hasher.combine("AggregateQuery") + deepHashFirestoreMessages(value: type, hasher: &hasher) + deepHashFirestoreMessages(value: field, hasher: &hasher) + } +} + +/// Generated class from Pigeon that represents data sent in messages. +struct AggregateQueryResponse: Hashable { + var type: AggregateType + var field: String? + var value: Double? + + // swift-format-ignore: AlwaysUseLowerCamelCase + static func fromList(_ pigeonVar_list: [Any?]) -> AggregateQueryResponse? { + let type = pigeonVar_list[0] as! AggregateType + let field: String? = nilOrValue(pigeonVar_list[1]) + let value: Double? = nilOrValue(pigeonVar_list[2]) + + return AggregateQueryResponse( + type: type, + field: field, + value: value + ) + } + + func toList() -> [Any?] { + [ + type, + field, + value, + ] + } + + static func == (lhs: AggregateQueryResponse, rhs: AggregateQueryResponse) -> Bool { + if Swift.type(of: lhs) != Swift.type(of: rhs) { + return false + } + return deepEqualsFirestoreMessages(lhs.type, rhs.type) + && deepEqualsFirestoreMessages( + lhs.field, + rhs.field + ) && deepEqualsFirestoreMessages(lhs.value, rhs.value) + } + + func hash(into hasher: inout Hasher) { + hasher.combine("AggregateQueryResponse") + deepHashFirestoreMessages(value: type, hasher: &hasher) + deepHashFirestoreMessages(value: field, hasher: &hasher) + deepHashFirestoreMessages(value: value, hasher: &hasher) + } +} + +class FirestoreMessagesPigeonCodecReader: FirebaseFirestoreReader { + override func readValue(ofType type: UInt8) -> Any? { + switch type { + case 129: + let enumResultAsInt: Int? = nilOrValue(readValue() as! Int?) + if let enumResultAsInt { + return DocumentChangeType(rawValue: enumResultAsInt) + } + return nil + case 130: + let enumResultAsInt: Int? = nilOrValue(readValue() as! Int?) + if let enumResultAsInt { + return Source(rawValue: enumResultAsInt) + } + return nil + case 131: + let enumResultAsInt: Int? = nilOrValue(readValue() as! Int?) + if let enumResultAsInt { + return ListenSource(rawValue: enumResultAsInt) + } + return nil + case 132: + let enumResultAsInt: Int? = nilOrValue(readValue() as! Int?) + if let enumResultAsInt { + return ServerTimestampBehavior(rawValue: enumResultAsInt) + } + return nil + case 133: + let enumResultAsInt: Int? = nilOrValue(readValue() as! Int?) + if let enumResultAsInt { + return AggregateSource(rawValue: enumResultAsInt) + } + return nil + case 134: + let enumResultAsInt: Int? = nilOrValue(readValue() as! Int?) + if let enumResultAsInt { + return PersistenceCacheIndexManagerRequest(rawValue: enumResultAsInt) + } + return nil + case 135: + let enumResultAsInt: Int? = nilOrValue(readValue() as! Int?) + if let enumResultAsInt { + return InternalTransactionResult(rawValue: enumResultAsInt) + } + return nil + case 136: + let enumResultAsInt: Int? = nilOrValue(readValue() as! Int?) + if let enumResultAsInt { + return InternalTransactionType(rawValue: enumResultAsInt) + } + return nil + case 137: + let enumResultAsInt: Int? = nilOrValue(readValue() as! Int?) + if let enumResultAsInt { + return AggregateType(rawValue: enumResultAsInt) + } + return nil + case 138: + return InternalFirebaseSettings.fromList(readValue() as! [Any?]) + case 139: + return FirestorePigeonFirebaseApp.fromList(readValue() as! [Any?]) + case 140: + return InternalSnapshotMetadata.fromList(readValue() as! [Any?]) + case 141: + return InternalDocumentSnapshot.fromList(readValue() as! [Any?]) + case 142: + return InternalDocumentChange.fromList(readValue() as! [Any?]) + case 143: + return InternalQuerySnapshot.fromList(readValue() as! [Any?]) + case 144: + return InternalPipelineResult.fromList(readValue() as! [Any?]) + case 145: + return InternalPipelineSnapshot.fromList(readValue() as! [Any?]) + case 146: + return InternalGetOptions.fromList(readValue() as! [Any?]) + case 147: + return InternalDocumentOption.fromList(readValue() as! [Any?]) + case 148: + return InternalTransactionCommand.fromList(readValue() as! [Any?]) + case 149: + return DocumentReferenceRequest.fromList(readValue() as! [Any?]) + case 150: + return InternalQueryParameters.fromList(readValue() as! [Any?]) + case 151: + return AggregateQuery.fromList(readValue() as! [Any?]) + case 152: + return AggregateQueryResponse.fromList(readValue() as! [Any?]) + default: + return super.readValue(ofType: type) + } + } +} + +class FirestoreMessagesPigeonCodecWriter: FirebaseFirestoreWriter { + override func writeValue(_ value: Any) { + if let value = value as? DocumentChangeType { + super.writeByte(129) + super.writeValue(value.rawValue) + } else if let value = value as? Source { + super.writeByte(130) + super.writeValue(value.rawValue) + } else if let value = value as? ListenSource { + super.writeByte(131) + super.writeValue(value.rawValue) + } else if let value = value as? ServerTimestampBehavior { + super.writeByte(132) + super.writeValue(value.rawValue) + } else if let value = value as? AggregateSource { + super.writeByte(133) + super.writeValue(value.rawValue) + } else if let value = value as? PersistenceCacheIndexManagerRequest { + super.writeByte(134) + super.writeValue(value.rawValue) + } else if let value = value as? InternalTransactionResult { + super.writeByte(135) + super.writeValue(value.rawValue) + } else if let value = value as? InternalTransactionType { + super.writeByte(136) + super.writeValue(value.rawValue) + } else if let value = value as? AggregateType { + super.writeByte(137) + super.writeValue(value.rawValue) + } else if let value = value as? InternalFirebaseSettings { + super.writeByte(138) + super.writeValue(value.toList()) + } else if let value = value as? FirestorePigeonFirebaseApp { + super.writeByte(139) + super.writeValue(value.toList()) + } else if let value = value as? InternalSnapshotMetadata { + super.writeByte(140) + super.writeValue(value.toList()) + } else if let value = value as? InternalDocumentSnapshot { + super.writeByte(141) + super.writeValue(value.toList()) + } else if let value = value as? InternalDocumentChange { + super.writeByte(142) + super.writeValue(value.toList()) + } else if let value = value as? InternalQuerySnapshot { + super.writeByte(143) + super.writeValue(value.toList()) + } else if let value = value as? InternalPipelineResult { + super.writeByte(144) + super.writeValue(value.toList()) + } else if let value = value as? InternalPipelineSnapshot { + super.writeByte(145) + super.writeValue(value.toList()) + } else if let value = value as? InternalGetOptions { + super.writeByte(146) + super.writeValue(value.toList()) + } else if let value = value as? InternalDocumentOption { + super.writeByte(147) + super.writeValue(value.toList()) + } else if let value = value as? InternalTransactionCommand { + super.writeByte(148) + super.writeValue(value.toList()) + } else if let value = value as? DocumentReferenceRequest { + super.writeByte(149) + super.writeValue(value.toList()) + } else if let value = value as? InternalQueryParameters { + super.writeByte(150) + super.writeValue(value.toList()) + } else if let value = value as? AggregateQuery { + super.writeByte(151) + super.writeValue(value.toList()) + } else if let value = value as? AggregateQueryResponse { + super.writeByte(152) + super.writeValue(value.toList()) + } else { + super.writeValue(value) + } + } +} + +class FirestoreMessagesPigeonCodecReaderWriter: FlutterStandardReaderWriter { + override func reader(with data: Data) -> FlutterStandardReader { + FirestoreMessagesPigeonCodecReader(data: data) + } + + override func writer(with data: NSMutableData) -> FlutterStandardWriter { + FirestoreMessagesPigeonCodecWriter(data: data) + } +} + +class FirestoreMessagesPigeonCodec: FlutterStandardMessageCodec, @unchecked Sendable { + static let shared = + FirestoreMessagesPigeonCodec(readerWriter: FirestoreMessagesPigeonCodecReaderWriter()) +} + +/// Generated protocol from Pigeon that represents a handler of messages from Flutter. +protocol FirebaseFirestoreHostApi { + func loadBundle( + app: FirestorePigeonFirebaseApp, bundle: FlutterStandardTypedData, + completion: @escaping (Result) -> Void) + func namedQueryGet( + app: FirestorePigeonFirebaseApp, name: String, options: InternalGetOptions, + completion: @escaping (Result) -> Void) + func clearPersistence( + app: FirestorePigeonFirebaseApp, + completion: @escaping (Result) -> Void) + func disableNetwork( + app: FirestorePigeonFirebaseApp, + completion: @escaping (Result) -> Void) + func enableNetwork( + app: FirestorePigeonFirebaseApp, + completion: @escaping (Result) -> Void) + func terminate( + app: FirestorePigeonFirebaseApp, + completion: @escaping (Result) -> Void) + func waitForPendingWrites( + app: FirestorePigeonFirebaseApp, + completion: @escaping (Result) -> Void) + func setIndexConfiguration( + app: FirestorePigeonFirebaseApp, indexConfiguration: String, + completion: @escaping (Result) -> Void) + func setLoggingEnabled(loggingEnabled: Bool, completion: @escaping (Result) -> Void) + func snapshotsInSyncSetup( + app: FirestorePigeonFirebaseApp, + completion: @escaping (Result) -> Void) + func transactionCreate( + app: FirestorePigeonFirebaseApp, timeout: Int64, maxAttempts: Int64, + completion: @escaping (Result) -> Void) + func transactionStoreResult( + transactionId: String, resultType: InternalTransactionResult, + commands: [InternalTransactionCommand?]?, + completion: @escaping (Result) -> Void) + func transactionGet( + app: FirestorePigeonFirebaseApp, transactionId: String, path: String, + completion: @escaping (Result) -> Void) + func documentReferenceSet( + app: FirestorePigeonFirebaseApp, request: DocumentReferenceRequest, + completion: @escaping (Result) -> Void) + func documentReferenceUpdate( + app: FirestorePigeonFirebaseApp, request: DocumentReferenceRequest, + completion: @escaping (Result) -> Void) + func documentReferenceGet( + app: FirestorePigeonFirebaseApp, request: DocumentReferenceRequest, + completion: @escaping (Result) -> Void) + func documentReferenceDelete( + app: FirestorePigeonFirebaseApp, request: DocumentReferenceRequest, + completion: @escaping (Result) -> Void) + func queryGet( + app: FirestorePigeonFirebaseApp, path: String, isCollectionGroup: Bool, + parameters: InternalQueryParameters, options: InternalGetOptions, + completion: @escaping (Result) -> Void) + func aggregateQuery( + app: FirestorePigeonFirebaseApp, path: String, + parameters: InternalQueryParameters, source: AggregateSource, + queries: [AggregateQuery?], isCollectionGroup: Bool, + completion: @escaping (Result<[AggregateQueryResponse?], Error>) -> Void) + func writeBatchCommit( + app: FirestorePigeonFirebaseApp, writes: [InternalTransactionCommand?], + completion: @escaping (Result) -> Void) + func querySnapshot( + app: FirestorePigeonFirebaseApp, path: String, isCollectionGroup: Bool, + parameters: InternalQueryParameters, options: InternalGetOptions, + includeMetadataChanges: Bool, source: ListenSource, + completion: @escaping (Result) -> Void) + func documentReferenceSnapshot( + app: FirestorePigeonFirebaseApp, + parameters: DocumentReferenceRequest, includeMetadataChanges: Bool, + source: ListenSource, + completion: @escaping (Result) -> Void) + func persistenceCacheIndexManagerRequest( + app: FirestorePigeonFirebaseApp, + request: PersistenceCacheIndexManagerRequest, + completion: @escaping (Result) -> Void) + func executePipeline( + app: FirestorePigeonFirebaseApp, stages: [[String?: Any?]?], + options: [String?: Any?]?, + completion: @escaping (Result) -> Void) +} + +/// Generated setup class from Pigeon to handle messages through the `binaryMessenger`. +class FirebaseFirestoreHostApiSetup { + static var codec: FlutterStandardMessageCodec { + FirestoreMessagesPigeonCodec.shared + } + + /// Sets up an instance of `FirebaseFirestoreHostApi` to handle messages through the + /// `binaryMessenger`. + static func setUp( + binaryMessenger: FlutterBinaryMessenger, api: FirebaseFirestoreHostApi?, + messageChannelSuffix: String = "" + ) { + let channelSuffix = messageChannelSuffix.count > 0 ? ".\(messageChannelSuffix)" : "" + let loadBundleChannel = FlutterBasicMessageChannel( + name: + "dev.flutter.pigeon.cloud_firestore_platform_interface.FirebaseFirestoreHostApi.loadBundle\(channelSuffix)", + binaryMessenger: binaryMessenger, + codec: codec + ) + if let api { + loadBundleChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let appArg = args[0] as! FirestorePigeonFirebaseApp + let bundleArg = args[1] as! FlutterStandardTypedData + api.loadBundle(app: appArg, bundle: bundleArg) { result in + switch result { + case .success(let res): + reply(wrapResult(res)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + loadBundleChannel.setMessageHandler(nil) + } + let namedQueryGetChannel = FlutterBasicMessageChannel( + name: + "dev.flutter.pigeon.cloud_firestore_platform_interface.FirebaseFirestoreHostApi.namedQueryGet\(channelSuffix)", + binaryMessenger: binaryMessenger, + codec: codec + ) + if let api { + namedQueryGetChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let appArg = args[0] as! FirestorePigeonFirebaseApp + let nameArg = args[1] as! String + let optionsArg = args[2] as! InternalGetOptions + api.namedQueryGet(app: appArg, name: nameArg, options: optionsArg) { result in + switch result { + case .success(let res): + reply(wrapResult(res)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + namedQueryGetChannel.setMessageHandler(nil) + } + let clearPersistenceChannel = FlutterBasicMessageChannel( + name: + "dev.flutter.pigeon.cloud_firestore_platform_interface.FirebaseFirestoreHostApi.clearPersistence\(channelSuffix)", + binaryMessenger: binaryMessenger, + codec: codec + ) + if let api { + clearPersistenceChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let appArg = args[0] as! FirestorePigeonFirebaseApp + api.clearPersistence(app: appArg) { result in + switch result { + case .success: + reply(wrapResult(nil)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + clearPersistenceChannel.setMessageHandler(nil) + } + let disableNetworkChannel = FlutterBasicMessageChannel( + name: + "dev.flutter.pigeon.cloud_firestore_platform_interface.FirebaseFirestoreHostApi.disableNetwork\(channelSuffix)", + binaryMessenger: binaryMessenger, + codec: codec + ) + if let api { + disableNetworkChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let appArg = args[0] as! FirestorePigeonFirebaseApp + api.disableNetwork(app: appArg) { result in + switch result { + case .success: + reply(wrapResult(nil)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + disableNetworkChannel.setMessageHandler(nil) + } + let enableNetworkChannel = FlutterBasicMessageChannel( + name: + "dev.flutter.pigeon.cloud_firestore_platform_interface.FirebaseFirestoreHostApi.enableNetwork\(channelSuffix)", + binaryMessenger: binaryMessenger, + codec: codec + ) + if let api { + enableNetworkChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let appArg = args[0] as! FirestorePigeonFirebaseApp + api.enableNetwork(app: appArg) { result in + switch result { + case .success: + reply(wrapResult(nil)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + enableNetworkChannel.setMessageHandler(nil) + } + let terminateChannel = FlutterBasicMessageChannel( + name: + "dev.flutter.pigeon.cloud_firestore_platform_interface.FirebaseFirestoreHostApi.terminate\(channelSuffix)", + binaryMessenger: binaryMessenger, + codec: codec + ) + if let api { + terminateChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let appArg = args[0] as! FirestorePigeonFirebaseApp + api.terminate(app: appArg) { result in + switch result { + case .success: + reply(wrapResult(nil)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + terminateChannel.setMessageHandler(nil) + } + let waitForPendingWritesChannel = FlutterBasicMessageChannel( + name: + "dev.flutter.pigeon.cloud_firestore_platform_interface.FirebaseFirestoreHostApi.waitForPendingWrites\(channelSuffix)", + binaryMessenger: binaryMessenger, + codec: codec + ) + if let api { + waitForPendingWritesChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let appArg = args[0] as! FirestorePigeonFirebaseApp + api.waitForPendingWrites(app: appArg) { result in + switch result { + case .success: + reply(wrapResult(nil)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + waitForPendingWritesChannel.setMessageHandler(nil) + } + let setIndexConfigurationChannel = FlutterBasicMessageChannel( + name: + "dev.flutter.pigeon.cloud_firestore_platform_interface.FirebaseFirestoreHostApi.setIndexConfiguration\(channelSuffix)", + binaryMessenger: binaryMessenger, + codec: codec + ) + if let api { + setIndexConfigurationChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let appArg = args[0] as! FirestorePigeonFirebaseApp + let indexConfigurationArg = args[1] as! String + api + .setIndexConfiguration(app: appArg, indexConfiguration: indexConfigurationArg) { result in + switch result { + case .success: + reply(wrapResult(nil)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + setIndexConfigurationChannel.setMessageHandler(nil) + } + let setLoggingEnabledChannel = FlutterBasicMessageChannel( + name: + "dev.flutter.pigeon.cloud_firestore_platform_interface.FirebaseFirestoreHostApi.setLoggingEnabled\(channelSuffix)", + binaryMessenger: binaryMessenger, + codec: codec + ) + if let api { + setLoggingEnabledChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let loggingEnabledArg = args[0] as! Bool + api.setLoggingEnabled(loggingEnabled: loggingEnabledArg) { result in + switch result { + case .success: + reply(wrapResult(nil)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + setLoggingEnabledChannel.setMessageHandler(nil) + } + let snapshotsInSyncSetupChannel = FlutterBasicMessageChannel( + name: + "dev.flutter.pigeon.cloud_firestore_platform_interface.FirebaseFirestoreHostApi.snapshotsInSyncSetup\(channelSuffix)", + binaryMessenger: binaryMessenger, + codec: codec + ) + if let api { + snapshotsInSyncSetupChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let appArg = args[0] as! FirestorePigeonFirebaseApp + api.snapshotsInSyncSetup(app: appArg) { result in + switch result { + case .success(let res): + reply(wrapResult(res)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + snapshotsInSyncSetupChannel.setMessageHandler(nil) + } + let transactionCreateChannel = FlutterBasicMessageChannel( + name: + "dev.flutter.pigeon.cloud_firestore_platform_interface.FirebaseFirestoreHostApi.transactionCreate\(channelSuffix)", + binaryMessenger: binaryMessenger, + codec: codec + ) + if let api { + transactionCreateChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let appArg = args[0] as! FirestorePigeonFirebaseApp + let timeoutArg = args[1] as! Int64 + let maxAttemptsArg = args[2] as! Int64 + api + .transactionCreate( + app: appArg, timeout: timeoutArg, + maxAttempts: maxAttemptsArg + ) { result in + switch result { + case .success(let res): + reply(wrapResult(res)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + transactionCreateChannel.setMessageHandler(nil) + } + let transactionStoreResultChannel = FlutterBasicMessageChannel( + name: + "dev.flutter.pigeon.cloud_firestore_platform_interface.FirebaseFirestoreHostApi.transactionStoreResult\(channelSuffix)", + binaryMessenger: binaryMessenger, + codec: codec + ) + if let api { + transactionStoreResultChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let transactionIdArg = args[0] as! String + let resultTypeArg = args[1] as! InternalTransactionResult + let commandsArg: [InternalTransactionCommand?]? = nilOrValue(args[2]) + api.transactionStoreResult( + transactionId: transactionIdArg, + resultType: resultTypeArg, + commands: commandsArg + ) { result in + switch result { + case .success: + reply(wrapResult(nil)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + transactionStoreResultChannel.setMessageHandler(nil) + } + let transactionGetChannel = FlutterBasicMessageChannel( + name: + "dev.flutter.pigeon.cloud_firestore_platform_interface.FirebaseFirestoreHostApi.transactionGet\(channelSuffix)", + binaryMessenger: binaryMessenger, + codec: codec + ) + if let api { + transactionGetChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let appArg = args[0] as! FirestorePigeonFirebaseApp + let transactionIdArg = args[1] as! String + let pathArg = args[2] as! String + api.transactionGet(app: appArg, transactionId: transactionIdArg, path: pathArg) { result in + switch result { + case .success(let res): + reply(wrapResult(res)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + transactionGetChannel.setMessageHandler(nil) + } + let documentReferenceSetChannel = FlutterBasicMessageChannel( + name: + "dev.flutter.pigeon.cloud_firestore_platform_interface.FirebaseFirestoreHostApi.documentReferenceSet\(channelSuffix)", + binaryMessenger: binaryMessenger, + codec: codec + ) + if let api { + documentReferenceSetChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let appArg = args[0] as! FirestorePigeonFirebaseApp + let requestArg = args[1] as! DocumentReferenceRequest + api.documentReferenceSet(app: appArg, request: requestArg) { result in + switch result { + case .success: + reply(wrapResult(nil)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + documentReferenceSetChannel.setMessageHandler(nil) + } + let documentReferenceUpdateChannel = FlutterBasicMessageChannel( + name: + "dev.flutter.pigeon.cloud_firestore_platform_interface.FirebaseFirestoreHostApi.documentReferenceUpdate\(channelSuffix)", + binaryMessenger: binaryMessenger, + codec: codec + ) + if let api { + documentReferenceUpdateChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let appArg = args[0] as! FirestorePigeonFirebaseApp + let requestArg = args[1] as! DocumentReferenceRequest + api.documentReferenceUpdate(app: appArg, request: requestArg) { result in + switch result { + case .success: + reply(wrapResult(nil)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + documentReferenceUpdateChannel.setMessageHandler(nil) + } + let documentReferenceGetChannel = FlutterBasicMessageChannel( + name: + "dev.flutter.pigeon.cloud_firestore_platform_interface.FirebaseFirestoreHostApi.documentReferenceGet\(channelSuffix)", + binaryMessenger: binaryMessenger, + codec: codec + ) + if let api { + documentReferenceGetChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let appArg = args[0] as! FirestorePigeonFirebaseApp + let requestArg = args[1] as! DocumentReferenceRequest + api.documentReferenceGet(app: appArg, request: requestArg) { result in + switch result { + case .success(let res): + reply(wrapResult(res)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + documentReferenceGetChannel.setMessageHandler(nil) + } + let documentReferenceDeleteChannel = FlutterBasicMessageChannel( + name: + "dev.flutter.pigeon.cloud_firestore_platform_interface.FirebaseFirestoreHostApi.documentReferenceDelete\(channelSuffix)", + binaryMessenger: binaryMessenger, + codec: codec + ) + if let api { + documentReferenceDeleteChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let appArg = args[0] as! FirestorePigeonFirebaseApp + let requestArg = args[1] as! DocumentReferenceRequest + api.documentReferenceDelete(app: appArg, request: requestArg) { result in + switch result { + case .success: + reply(wrapResult(nil)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + documentReferenceDeleteChannel.setMessageHandler(nil) + } + let queryGetChannel = FlutterBasicMessageChannel( + name: + "dev.flutter.pigeon.cloud_firestore_platform_interface.FirebaseFirestoreHostApi.queryGet\(channelSuffix)", + binaryMessenger: binaryMessenger, + codec: codec + ) + if let api { + queryGetChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let appArg = args[0] as! FirestorePigeonFirebaseApp + let pathArg = args[1] as! String + let isCollectionGroupArg = args[2] as! Bool + let parametersArg = args[3] as! InternalQueryParameters + let optionsArg = args[4] as! InternalGetOptions + api.queryGet( + app: appArg, + path: pathArg, + isCollectionGroup: isCollectionGroupArg, + parameters: parametersArg, + options: optionsArg + ) { result in + switch result { + case .success(let res): + reply(wrapResult(res)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + queryGetChannel.setMessageHandler(nil) + } + let aggregateQueryChannel = FlutterBasicMessageChannel( + name: + "dev.flutter.pigeon.cloud_firestore_platform_interface.FirebaseFirestoreHostApi.aggregateQuery\(channelSuffix)", + binaryMessenger: binaryMessenger, + codec: codec + ) + if let api { + aggregateQueryChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let appArg = args[0] as! FirestorePigeonFirebaseApp + let pathArg = args[1] as! String + let parametersArg = args[2] as! InternalQueryParameters + let sourceArg = args[3] as! AggregateSource + let queriesArg = args[4] as! [AggregateQuery?] + let isCollectionGroupArg = args[5] as! Bool + api.aggregateQuery( + app: appArg, + path: pathArg, + parameters: parametersArg, + source: sourceArg, + queries: queriesArg, + isCollectionGroup: isCollectionGroupArg + ) { result in + switch result { + case .success(let res): + reply(wrapResult(res)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + aggregateQueryChannel.setMessageHandler(nil) + } + let writeBatchCommitChannel = FlutterBasicMessageChannel( + name: + "dev.flutter.pigeon.cloud_firestore_platform_interface.FirebaseFirestoreHostApi.writeBatchCommit\(channelSuffix)", + binaryMessenger: binaryMessenger, + codec: codec + ) + if let api { + writeBatchCommitChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let appArg = args[0] as! FirestorePigeonFirebaseApp + let writesArg = args[1] as! [InternalTransactionCommand?] + api.writeBatchCommit(app: appArg, writes: writesArg) { result in + switch result { + case .success: + reply(wrapResult(nil)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + writeBatchCommitChannel.setMessageHandler(nil) + } + let querySnapshotChannel = FlutterBasicMessageChannel( + name: + "dev.flutter.pigeon.cloud_firestore_platform_interface.FirebaseFirestoreHostApi.querySnapshot\(channelSuffix)", + binaryMessenger: binaryMessenger, + codec: codec + ) + if let api { + querySnapshotChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let appArg = args[0] as! FirestorePigeonFirebaseApp + let pathArg = args[1] as! String + let isCollectionGroupArg = args[2] as! Bool + let parametersArg = args[3] as! InternalQueryParameters + let optionsArg = args[4] as! InternalGetOptions + let includeMetadataChangesArg = args[5] as! Bool + let sourceArg = args[6] as! ListenSource + api.querySnapshot( + app: appArg, + path: pathArg, + isCollectionGroup: isCollectionGroupArg, + parameters: parametersArg, + options: optionsArg, + includeMetadataChanges: includeMetadataChangesArg, + source: sourceArg + ) { result in + switch result { + case .success(let res): + reply(wrapResult(res)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + querySnapshotChannel.setMessageHandler(nil) + } + let documentReferenceSnapshotChannel = FlutterBasicMessageChannel( + name: + "dev.flutter.pigeon.cloud_firestore_platform_interface.FirebaseFirestoreHostApi.documentReferenceSnapshot\(channelSuffix)", + binaryMessenger: binaryMessenger, + codec: codec + ) + if let api { + documentReferenceSnapshotChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let appArg = args[0] as! FirestorePigeonFirebaseApp + let parametersArg = args[1] as! DocumentReferenceRequest + let includeMetadataChangesArg = args[2] as! Bool + let sourceArg = args[3] as! ListenSource + api.documentReferenceSnapshot( + app: appArg, + parameters: parametersArg, + includeMetadataChanges: includeMetadataChangesArg, + source: sourceArg + ) { result in + switch result { + case .success(let res): + reply(wrapResult(res)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + documentReferenceSnapshotChannel.setMessageHandler(nil) + } + let persistenceCacheIndexManagerRequestChannel = FlutterBasicMessageChannel( + name: + "dev.flutter.pigeon.cloud_firestore_platform_interface.FirebaseFirestoreHostApi.persistenceCacheIndexManagerRequest\(channelSuffix)", + binaryMessenger: binaryMessenger, + codec: codec + ) + if let api { + persistenceCacheIndexManagerRequestChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let appArg = args[0] as! FirestorePigeonFirebaseApp + let requestArg = args[1] as! PersistenceCacheIndexManagerRequest + api.persistenceCacheIndexManagerRequest(app: appArg, request: requestArg) { result in + switch result { + case .success: + reply(wrapResult(nil)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + persistenceCacheIndexManagerRequestChannel.setMessageHandler(nil) + } + let executePipelineChannel = FlutterBasicMessageChannel( + name: + "dev.flutter.pigeon.cloud_firestore_platform_interface.FirebaseFirestoreHostApi.executePipeline\(channelSuffix)", + binaryMessenger: binaryMessenger, + codec: codec + ) + if let api { + executePipelineChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let appArg = args[0] as! FirestorePigeonFirebaseApp + let stagesArg = args[1] as! [[String?: Any?]?] + let optionsArg: [String?: Any?]? = nilOrValue(args[2]) + api.executePipeline(app: appArg, stages: stagesArg, options: optionsArg) { result in + switch result { + case .success(let res): + reply(wrapResult(res)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + executePipelineChannel.setMessageHandler(nil) + } + } +} diff --git a/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/FirestorePigeonParser.m b/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/FirestorePigeonParser.m deleted file mode 100644 index 0178847b7426..000000000000 --- a/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/FirestorePigeonParser.m +++ /dev/null @@ -1,311 +0,0 @@ -// Copyright 2023, the Chromium project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -#import "FirestorePigeonParser.h" -#import - -@implementation FirestorePigeonParser - -+ (FIRFilter *_Nonnull)filterFromJson:(NSDictionary *_Nullable)map { - if (map[@"fieldPath"]) { - // Deserialize a FilterQuery - NSString *op = map[@"op"]; - FIRFieldPath *fieldPath = map[@"fieldPath"]; - id value = map[@"value"]; - - // All the operators from Firebase - if ([op isEqualToString:@"=="]) { - return [FIRFilter filterWhereFieldPath:fieldPath isEqualTo:value]; - } else if ([op isEqualToString:@"!="]) { - return [FIRFilter filterWhereFieldPath:fieldPath isNotEqualTo:value]; - } else if ([op isEqualToString:@"<"]) { - return [FIRFilter filterWhereFieldPath:fieldPath isLessThan:value]; - } else if ([op isEqualToString:@"<="]) { - return [FIRFilter filterWhereFieldPath:fieldPath isLessThanOrEqualTo:value]; - } else if ([op isEqualToString:@">"]) { - return [FIRFilter filterWhereFieldPath:fieldPath isGreaterThan:value]; - } else if ([op isEqualToString:@">="]) { - return [FIRFilter filterWhereFieldPath:fieldPath isGreaterThanOrEqualTo:value]; - } else if ([op isEqualToString:@"array-contains"]) { - return [FIRFilter filterWhereFieldPath:fieldPath arrayContains:value]; - } else if ([op isEqualToString:@"array-contains-any"]) { - return [FIRFilter filterWhereFieldPath:fieldPath arrayContainsAny:value]; - } else if ([op isEqualToString:@"in"]) { - return [FIRFilter filterWhereFieldPath:fieldPath in:value]; - } else if ([op isEqualToString:@"not-in"]) { - return [FIRFilter filterWhereFieldPath:fieldPath notIn:value]; - } else { - @throw [NSException exceptionWithName:@"InvalidOperator" - reason:@"Invalid operator" - userInfo:nil]; - } - } - // Deserialize a FilterOperator - NSString *op = map[@"op"]; - NSArray *> *queries = map[@"queries"]; - - // Map queries recursively - NSMutableArray *parsedFilters = [NSMutableArray array]; - for (NSDictionary *query in queries) { - [parsedFilters addObject:[self filterFromJson:query]]; - } - - if ([op isEqualToString:@"OR"]) { - return [FIRFilter orFilterWithFilters:parsedFilters]; - } else if ([op isEqualToString:@"AND"]) { - return [FIRFilter andFilterWithFilters:parsedFilters]; - } - - @throw [NSException exceptionWithName:@"InvalidOperator" reason:@"Invalid operator" userInfo:nil]; -} - -+ (FIRQuery *_Nonnull)parseQueryWithParameters:(nonnull InternalQueryParameters *)parameters - firestore:(nonnull FIRFirestore *)firestore - path:(nonnull NSString *)path - isCollectionGroup:(Boolean)isCollectionGroup { - @try { - FIRQuery *query; - - NSArray *whereConditions = parameters.where; - - if (isCollectionGroup) { - query = [firestore collectionGroupWithID:path]; - } else { - query = (FIRQuery *)[firestore collectionWithPath:path]; - } - - BOOL isFilterQuery = parameters.filters != nil; - if (isFilterQuery) { - FIRFilter *filter = [FirestorePigeonParser filterFromJson:parameters.filters]; - query = [query queryWhereFilter:filter]; - } - - // Filters - for (id item in whereConditions) { - NSArray *condition = item; - FIRFieldPath *fieldPath = (FIRFieldPath *)condition[0]; - NSString *operator= condition[1]; - id value = condition[2]; - if ([operator isEqualToString:@"=="]) { - query = [query queryWhereFieldPath:fieldPath isEqualTo:value]; - } else if ([operator isEqualToString:@"!="]) { - query = [query queryWhereFieldPath:fieldPath isNotEqualTo:value]; - } else if ([operator isEqualToString:@"<"]) { - query = [query queryWhereFieldPath:fieldPath isLessThan:value]; - } else if ([operator isEqualToString:@"<="]) { - query = [query queryWhereFieldPath:fieldPath isLessThanOrEqualTo:value]; - } else if ([operator isEqualToString:@">"]) { - query = [query queryWhereFieldPath:fieldPath isGreaterThan:value]; - } else if ([operator isEqualToString:@">="]) { - query = [query queryWhereFieldPath:fieldPath isGreaterThanOrEqualTo:value]; - } else if ([operator isEqualToString:@"array-contains"]) { - query = [query queryWhereFieldPath:fieldPath arrayContains:value]; - } else if ([operator isEqualToString:@"array-contains-any"]) { - query = [query queryWhereFieldPath:fieldPath arrayContainsAny:value]; - } else if ([operator isEqualToString:@"in"]) { - query = [query queryWhereFieldPath:fieldPath in:value]; - } else if ([operator isEqualToString:@"not-in"]) { - query = [query queryWhereFieldPath:fieldPath notIn:value]; - } else { - NSLog( - @"FLTFirebaseFirestore: An invalid query operator %@ was received but not handled.", - operator); - } - } - - // Limit - id limit = parameters.limit; - if (limit) { - query = [query queryLimitedTo:((NSNumber *)limit).intValue]; - } - - // Limit To Last - id limitToLast = parameters.limitToLast; - if (limitToLast) { - query = [query queryLimitedToLast:((NSNumber *)limitToLast).intValue]; - } - - // Ordering - NSArray *orderBy = parameters.orderBy; - if (!orderBy) { - // We return early if no ordering set as cursor queries below require at least one orderBy - // set - return query; - } - - for (NSArray *orderByParameters in orderBy) { - FIRFieldPath *fieldPath = (FIRFieldPath *)orderByParameters[0]; - NSNumber *descending = orderByParameters[1]; - query = [query queryOrderedByFieldPath:fieldPath descending:[descending boolValue]]; - } - - // Start At - id startAt = parameters.startAt; - if (startAt) query = [query queryStartingAtValues:(NSArray *)startAt]; - // Start After - id startAfter = parameters.startAfter; - if (startAfter) query = [query queryStartingAfterValues:(NSArray *)startAfter]; - // End At - id endAt = parameters.endAt; - if (endAt) query = [query queryEndingAtValues:(NSArray *)endAt]; - // End Before - id endBefore = parameters.endBefore; - if (endBefore) query = [query queryEndingBeforeValues:(NSArray *)endBefore]; - - return query; - } @catch (NSException *exception) { - NSLog(@"An error occurred while parsing query arguments, this is most likely an error with " - @"this SDK. %@", - [exception callStackSymbols]); - return nil; - } -} - -+ (FIRFirestoreSource)parseSource:(Source)source { - switch (source) { - case SourceServerAndCache: - return FIRFirestoreSourceDefault; - case SourceServer: - return FIRFirestoreSourceServer; - case SourceCache: - return FIRFirestoreSourceCache; - default: - @throw [NSException exceptionWithName:@"Invalid Source" - reason:@"This source is not supported by the SDK" - userInfo:nil]; - } -} - -+ (NSArray *_Nonnull)parseFieldPath: - (NSArray *> *_Nonnull)fieldPaths { - NSMutableArray *paths = [NSMutableArray arrayWithCapacity:[fieldPaths count]]; - for (NSArray *fieldPath in fieldPaths) { - FIRFieldPath *parsed = [[FIRFieldPath alloc] initWithFields:fieldPath]; - [paths addObject:parsed]; - } - return [NSArray arrayWithArray:paths]; -} - -+ (FIRServerTimestampBehavior)parseServerTimestampBehavior: - (ServerTimestampBehavior)serverTimestampBehavior { - switch (serverTimestampBehavior) { - case ServerTimestampBehaviorNone: - return FIRServerTimestampBehaviorNone; - case ServerTimestampBehaviorEstimate: - return FIRServerTimestampBehaviorEstimate; - case ServerTimestampBehaviorPrevious: - return FIRServerTimestampBehaviorPrevious; - default: - @throw [NSException - exceptionWithName:@"Invalid Server Timestamp Behavior" - reason:@"This Server Timestamp Behavior is not supported by the SDK" - userInfo:nil]; - } -} - -+ (FIRListenSource)parseListenSource:(ListenSource)source { - switch (source) { - case ListenSourceDefaultSource: - return FIRListenSourceDefault; - case ListenSourceCache: - return FIRListenSourceCache; - default: - @throw - [NSException exceptionWithName:@"Invalid ListenSource" - reason:@"This ListenSource Behavior is not supported by the SDK" - userInfo:nil]; - } -} - -+ (InternalSnapshotMetadata *_Nonnull)toPigeonSnapshotMetadata: - (FIRSnapshotMetadata *_Nonnull)snapshotMetadata { - return [InternalSnapshotMetadata makeWithHasPendingWrites:snapshotMetadata.hasPendingWrites - isFromCache:snapshotMetadata.isFromCache]; -} - -+ (InternalDocumentSnapshot *_Nonnull) - toPigeonDocumentSnapshot:(FIRDocumentSnapshot *_Nonnull)documentSnapshot - serverTimestampBehavior:(FIRServerTimestampBehavior)serverTimestampBehavior { - return [InternalDocumentSnapshot - makeWithPath:documentSnapshot.reference.path - data:[documentSnapshot dataWithServerTimestampBehavior:serverTimestampBehavior] - metadata:[FirestorePigeonParser toPigeonSnapshotMetadata:documentSnapshot.metadata]]; -} - -+ (DocumentChangeType)toPigeonDocumentChangeType:(FIRDocumentChangeType)documentChangeType { - switch (documentChangeType) { - case FIRDocumentChangeTypeAdded: - return DocumentChangeTypeAdded; - case FIRDocumentChangeTypeModified: - return DocumentChangeTypeModified; - case FIRDocumentChangeTypeRemoved: - return DocumentChangeTypeRemoved; - default: - @throw [NSException exceptionWithName:@"InvalidDocumentChangeType" - reason:@"Invalid document change type" - userInfo:nil]; - } -} - -+ (InternalDocumentChange *_Nonnull) - toPigeonDocumentChange:(FIRDocumentChange *_Nonnull)documentChange - serverTimestampBehavior:(FIRServerTimestampBehavior)serverTimestampBehavior { - NSInteger oldIndex; - NSInteger newIndex; - - // Note the Firestore C++ SDK here returns a maxed UInt that is != NSUIntegerMax, so we make one - // ourselves so we can convert to -1 for Dart. - NSUInteger MAX_VAL = (NSUInteger)[@(-1) integerValue]; - - if (documentChange.newIndex == NSNotFound || documentChange.newIndex == 4294967295 || - documentChange.newIndex == MAX_VAL) { - newIndex = -1; - } else { - newIndex = (NSInteger)documentChange.newIndex; - } - - if (documentChange.oldIndex == NSNotFound || documentChange.oldIndex == 4294967295 || - documentChange.oldIndex == MAX_VAL) { - oldIndex = -1; - } else { - oldIndex = (NSInteger)documentChange.oldIndex; - } - - return [InternalDocumentChange - makeWithType:[FirestorePigeonParser toPigeonDocumentChangeType:documentChange.type] - document:[FirestorePigeonParser toPigeonDocumentSnapshot:documentChange.document - serverTimestampBehavior:serverTimestampBehavior] - oldIndex:oldIndex - newIndex:newIndex]; -} - -+ (NSArray *_Nonnull) - toPigeonDocumentChanges:(NSArray *_Nonnull)documentChanges - serverTimestampBehavior:(FIRServerTimestampBehavior)serverTimestampBehavior { - NSMutableArray *pigeonDocumentChanges = [NSMutableArray array]; - for (FIRDocumentChange *documentChange in documentChanges) { - [pigeonDocumentChanges - addObject:[FirestorePigeonParser toPigeonDocumentChange:documentChange - serverTimestampBehavior:serverTimestampBehavior]]; - } - return pigeonDocumentChanges; -} - -+ (InternalQuerySnapshot *_Nonnull)toPigeonQuerySnapshot:(FIRQuerySnapshot *_Nonnull)querySnaphot - serverTimestampBehavior: - (FIRServerTimestampBehavior)serverTimestampBehavior { - NSMutableArray *documentSnapshots = [NSMutableArray array]; - for (FIRDocumentSnapshot *documentSnapshot in querySnaphot.documents) { - [documentSnapshots - addObject:[FirestorePigeonParser toPigeonDocumentSnapshot:documentSnapshot - serverTimestampBehavior:serverTimestampBehavior]]; - } - return [InternalQuerySnapshot - makeWithDocuments:documentSnapshots - documentChanges:[FirestorePigeonParser toPigeonDocumentChanges:querySnaphot.documentChanges - serverTimestampBehavior:serverTimestampBehavior] - metadata:[FirestorePigeonParser toPigeonSnapshotMetadata:querySnaphot.metadata]]; -} - -@end diff --git a/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/LoadBundleStreamHandler.swift b/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/LoadBundleStreamHandler.swift new file mode 100644 index 000000000000..1261c7515fff --- /dev/null +++ b/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/LoadBundleStreamHandler.swift @@ -0,0 +1,65 @@ +// Copyright 2022, the Chromium project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import FirebaseFirestore +import Foundation + +#if canImport(firebase_core) + import firebase_core +#else + import firebase_core_shared +#endif + +#if os(iOS) + import Flutter +#elseif os(macOS) + import FlutterMacOS +#endif + +final class LoadBundleStreamHandler: NSObject, FlutterStreamHandler { + private let firestore: Firestore + private let bundle: FlutterStandardTypedData + private var task: LoadBundleTask? + + init(firestore: Firestore, bundle: FlutterStandardTypedData) { + self.firestore = firestore + self.bundle = bundle + } + + func onListen(withArguments arguments: Any?, eventSink events: @escaping FlutterEventSink) + -> FlutterError? + { + task = firestore.loadBundle(bundle.data) { _, error in + if let error { + let (code, message) = FirebaseFirestoreUtils.errorCodeAndMessage(from: error) + DispatchQueue.main.async { + events( + FLTFirebasePlugin.createFlutterError( + fromCode: code, + message: message, + optionalDetails: ["code": code, "message": message], + andOptionalNSError: error as NSError + ) + ) + } + } + } + + task?.addObserver { progress in + DispatchQueue.main.async { + if progress.state != .error { + events(progress) + } + } + } + + return nil + } + + func onCancel(withArguments arguments: Any?) -> FlutterError? { + task?.removeAllObservers() + task = nil + return nil + } +} diff --git a/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/PigeonParser.swift b/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/PigeonParser.swift new file mode 100644 index 000000000000..1faf23473fb3 --- /dev/null +++ b/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/PigeonParser.swift @@ -0,0 +1,327 @@ +// Copyright 2023, the Chromium project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import FirebaseFirestore +import Foundation + +enum PigeonParser { + static func queryParseError(_ message: String) -> NSError { + NSError( + domain: "FLTFirebaseFirestore", + code: 0, + userInfo: [NSLocalizedDescriptionKey: message] + ) + } + + static func toPigeonMap(_ data: [String: Any]?) -> [String?: Any?]? { + guard let data else { return nil } + var mapped: [String?: Any?] = [:] + mapped.reserveCapacity(data.count) + for (key, value) in data { + mapped[key] = value + } + return mapped + } + + static func filterFromJson(_ map: [String: Any]?) throws -> Filter { + guard let map else { + throw queryParseError("Invalid operator") + } + + if map["fieldPath"] != nil { + guard let op = map["op"] as? String else { + throw queryParseError("Filter is missing an operator") + } + guard let fieldPath = map["fieldPath"] as? FieldPath else { + throw queryParseError("Filter is missing a field path") + } + let value = map["value"] as Any + switch op { + case "==": + return Filter.whereField(fieldPath, isEqualTo: value) + case "!=": + return Filter.whereField(fieldPath, isNotEqualTo: value) + case "<": + return Filter.whereField(fieldPath, isLessThan: value) + case "<=": + return Filter.whereField(fieldPath, isLessThanOrEqualTo: value) + case ">": + return Filter.whereField(fieldPath, isGreaterThan: value) + case ">=": + return Filter.whereField(fieldPath, isGreaterOrEqualTo: value) + case "array-contains": + return Filter.whereField(fieldPath, arrayContains: value) + case "array-contains-any": + return Filter.whereField(fieldPath, arrayContainsAny: value as? [Any] ?? []) + case "in": + return Filter.whereField(fieldPath, in: value as? [Any] ?? []) + case "not-in": + return Filter.whereField(fieldPath, notIn: value as? [Any] ?? []) + default: + throw queryParseError("Invalid operator") + } + } + + guard let op = map["op"] as? String else { + throw queryParseError("Compound filter is missing an operator") + } + guard let queries = map["queries"] as? [[String: Any]] else { + throw queryParseError("Compound filter is missing queries") + } + let parsedFilters = try queries.map { try filterFromJson($0) } + if op == "OR" { + return Filter.orFilter(parsedFilters) + } + if op == "AND" { + return Filter.andFilter(parsedFilters) + } + throw queryParseError("Invalid operator") + } + + static func parseQuery( + parameters: InternalQueryParameters, + firestore: Firestore, + path: String, + isCollectionGroup: Bool + ) -> Query? { + do { + var query: Query + if isCollectionGroup { + query = firestore.collectionGroup(path) + } else { + query = firestore.collection(path) + } + + if let filters = parameters.filters as? [String: Any] { + query = try query.whereFilter(filterFromJson(filters)) + } + + if let whereConditions = parameters.where { + for item in whereConditions { + guard let condition = item, condition.count >= 3 else { continue } + guard let fieldPath = condition[0] as? FieldPath, let op = condition[1] as? String else { + throw queryParseError("Invalid query condition") + } + let value = condition[2] + switch op { + case "==": + query = query.whereField(fieldPath, isEqualTo: value as Any) + case "!=": + query = query.whereField(fieldPath, isNotEqualTo: value as Any) + case "<": + query = query.whereField(fieldPath, isLessThan: value as Any) + case "<=": + query = query.whereField(fieldPath, isLessThanOrEqualTo: value as Any) + case ">": + query = query.whereField(fieldPath, isGreaterThan: value as Any) + case ">=": + query = query.whereField(fieldPath, isGreaterThanOrEqualTo: value as Any) + case "array-contains": + query = query.whereField(fieldPath, arrayContains: value as Any) + case "array-contains-any": + query = query.whereField(fieldPath, arrayContainsAny: value as? [Any] ?? []) + case "in": + query = query.whereField(fieldPath, in: value as? [Any] ?? []) + case "not-in": + query = query.whereField(fieldPath, notIn: value as? [Any] ?? []) + default: + NSLog( + "FLTFirebaseFirestore: An invalid query operator %@ was received but not handled.", + op + ) + } + } + } + + if let limit = parameters.limit { + query = query.limit(to: Int(limit)) + } + if let limitToLast = parameters.limitToLast { + query = query.limit(toLast: Int(limitToLast)) + } + + guard let orderBy = parameters.orderBy else { + return query + } + + for orderByParameters in orderBy { + guard let orderByParameters, orderByParameters.count >= 2 else { continue } + guard let fieldPath = orderByParameters[0] as? FieldPath else { + throw queryParseError("Invalid orderBy field path") + } + let descending: Bool + if let number = orderByParameters[1] as? NSNumber { + descending = number.boolValue + } else if let boolValue = orderByParameters[1] as? Bool { + descending = boolValue + } else { + throw queryParseError("Invalid orderBy direction") + } + query = query.order(by: fieldPath, descending: descending) + } + + if let startAt = parameters.startAt { + query = query.start(at: startAt as [Any]) + } + if let startAfter = parameters.startAfter { + query = query.start(after: startAfter as [Any]) + } + if let endAt = parameters.endAt { + query = query.end(at: endAt as [Any]) + } + if let endBefore = parameters.endBefore { + query = query.end(before: endBefore as [Any]) + } + + return query + } catch { + NSLog( + "An error occurred while parsing query arguments, this is most likely an error with this SDK." + ) + return nil + } + } + + static func parseSource(_ source: Source) -> FirestoreSource { + switch source { + case .serverAndCache: + return .default + case .server: + return .server + case .cache: + return .cache + } + } + + static func parseFieldPath(_ fieldPaths: [[String?]?]) -> [FieldPath] { + fieldPaths.compactMap { components in + guard let components else { return nil } + return FieldPath(components.compactMap { $0 }) + } + } + + static func parseServerTimestampBehavior(_ behavior: ServerTimestampBehavior) + -> FirebaseFirestore.ServerTimestampBehavior + { + switch behavior { + case .none: + return .none + case .estimate: + return .estimate + case .previous: + return .previous + } + } + + static func parseListenSource(_ source: ListenSource) -> FirebaseFirestore.ListenSource { + switch source { + case .defaultSource: + return .default + case .cache: + return .cache + } + } + + static func toPigeonSnapshotMetadata(_ snapshotMetadata: SnapshotMetadata) + -> InternalSnapshotMetadata + { + InternalSnapshotMetadata( + hasPendingWrites: snapshotMetadata.hasPendingWrites, + isFromCache: snapshotMetadata.isFromCache + ) + } + + static func toPigeonDocumentSnapshot( + _ documentSnapshot: DocumentSnapshot, + serverTimestampBehavior: FirebaseFirestore + .ServerTimestampBehavior + ) -> InternalDocumentSnapshot { + let data = documentSnapshot.data(with: serverTimestampBehavior) + return InternalDocumentSnapshot( + path: documentSnapshot.reference.path, + data: toPigeonMap(data), + metadata: toPigeonSnapshotMetadata(documentSnapshot.metadata) + ) + } + + static func toPigeonDocumentChangeType(_ documentChangeType: DocumentChangeType) + -> DocumentChangeType + { + documentChangeType + } + + static func toPigeonDocumentChange( + _ documentChange: DocumentChange, + serverTimestampBehavior: FirebaseFirestore + .ServerTimestampBehavior + ) -> InternalDocumentChange { + let maxVal = NSNotFound + let newIndex: Int64 + if documentChange.newIndex == NSNotFound || documentChange.newIndex == 4_294_967_295 + || documentChange.newIndex == maxVal + { + newIndex = -1 + } else { + newIndex = Int64(documentChange.newIndex) + } + + let oldIndex: Int64 + if documentChange.oldIndex == NSNotFound || documentChange.oldIndex == 4_294_967_295 + || documentChange.oldIndex == maxVal + { + oldIndex = -1 + } else { + oldIndex = Int64(documentChange.oldIndex) + } + + let type: DocumentChangeType + switch documentChange.type { + case .added: + type = .added + case .modified: + type = .modified + case .removed: + type = .removed + @unknown default: + type = .modified + } + + return InternalDocumentChange( + type: type, + document: toPigeonDocumentSnapshot( + documentChange.document, serverTimestampBehavior: serverTimestampBehavior + ), + oldIndex: oldIndex, + newIndex: newIndex + ) + } + + static func toPigeonDocumentChanges( + _ documentChanges: [DocumentChange], + serverTimestampBehavior: FirebaseFirestore + .ServerTimestampBehavior + ) -> [InternalDocumentChange?] { + documentChanges.map { + toPigeonDocumentChange($0, serverTimestampBehavior: serverTimestampBehavior) + } + } + + static func toPigeonQuerySnapshot( + _ querySnapshot: QuerySnapshot, + serverTimestampBehavior: FirebaseFirestore + .ServerTimestampBehavior + ) -> InternalQuerySnapshot { + let documents = querySnapshot.documents.map { + toPigeonDocumentSnapshot($0, serverTimestampBehavior: serverTimestampBehavior) + as InternalDocumentSnapshot? + } + return InternalQuerySnapshot( + documents: documents, + documentChanges: toPigeonDocumentChanges( + querySnapshot.documentChanges, serverTimestampBehavior: serverTimestampBehavior + ), + metadata: toPigeonSnapshotMetadata(querySnapshot.metadata) + ) + } +} diff --git a/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/PipelineParser.swift b/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/PipelineParser.swift new file mode 100644 index 000000000000..9f565dc9ccca --- /dev/null +++ b/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/PipelineParser.swift @@ -0,0 +1,1487 @@ +// Copyright 2026, the Chromium project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import FirebaseFirestore +import Foundation + +#if os(iOS) + import Flutter +#elseif os(macOS) + import FlutterMacOS +#endif + +private let kPipelineNotAvailable = + "Pipeline API is not available. Firestore Pipelines require Firebase iOS SDK with pipeline support." +private let kPipelineErrorDomain = "FLTFirebaseFirestore" +private let kPipelineParseErrorCode = -1 +private let kMaxPipelineExpressionDepth = 64 +private let kMaxPipelineStageDepth = 32 + +private let kBinaryNames: [String] = [ + "equal", "not_equal", "greater_than", "greater_than_or_equal", "less_than", + "less_than_or_equal", "add", "subtract", "multiply", "divide", "mod", "bit_and", + "bit_or", "bit_left_shift", "bit_right_shift", +] + +private let kFilterComparisonKeys: [String] = [ + "isEqualTo", "isNotEqualTo", "isGreaterThan", "isGreaterThanOrEqualTo", "isLessThan", + "isLessThanOrEqualTo", "arrayContains", "arrayContainsAny", "whereIn", "whereNotIn", + "isNull", "isNotNull", +] + +private func pipelineUnavailableError() -> NSError { + NSError( + domain: kPipelineErrorDomain, + code: kPipelineParseErrorCode, + userInfo: [NSLocalizedDescriptionKey: kPipelineNotAvailable] + ) +} + +private func parseError(_ message: String) -> NSError { + NSError( + domain: kPipelineErrorDomain, + code: kPipelineParseErrorCode, + userInfo: [NSLocalizedDescriptionKey: message] + ) +} + +private func asMap(_ value: Any?) -> [String: Any]? { + guard let value, !(value is NSNull) else { return nil } + if let dict = value as? [String: Any] { + return dict + } + if let dict = value as? [String: Any?] { + var result: [String: Any] = [:] + for (key, nested) in dict { + result[key] = nested ?? NSNull() + } + return result + } + if let dict = value as? [AnyHashable: Any] { + var result: [String: Any] = [:] + for (key, nested) in dict { + if let key = key as? String { + result[key] = nested + } + } + return result + } + return nil +} + +private func asArray(_ value: Any?) -> [Any]? { + guard let value, !(value is NSNull) else { return nil } + if let array = value as? [Any] { + return array + } + if let array = value as? NSArray { + return array.map { $0 as Any } + } + return nil +} + +private func dictionaryFromOptionalKeyed(_ map: [String: Any?]) -> [String: Any] { + var result: [String: Any] = [:] + for (key, value) in map { + result[key] = value ?? NSNull() + } + return result +} + +private func nestedValue(_ map: [String: Any], keyPath: String) -> Any? { + let parts = keyPath.split(separator: ".").map(String.init) + var current: Any? = map + for part in parts { + guard let currentMap = asMap(current) else { return nil } + current = currentMap[part] + } + return current +} + +private func toExprBridge(_ expression: any FirebaseFirestore.Expression) throws -> ExprBridge { + if let bridge = exprBridge(from: expression) { + return bridge + } + throw parseError("Could not convert pipeline expression into a native bridge") +} + +/// Typed pipeline expressions must be lowered to `ExprBridge` for stage constructors. +/// `Score` and `DocumentMatches` expose a public `.bridge`. Other SDK expression types +/// (`Field`, `Constant`, `FunctionExpression`, internal boolean wrappers) keep `bridge` +/// internal, and `Expression.toBridge()` is also internal, so there is no supported public +/// accessor. Mirror is the same approach React Native Firebase uses until Firebase exposes one. +private func exprBridge(from value: Any) -> ExprBridge? { + if let bridge = value as? ExprBridge { + return bridge + } + if let score = value as? Score { + return score.bridge + } + if let matches = value as? DocumentMatches { + return matches.bridge + } + + var mirror: Mirror? = Mirror(reflecting: value) + while let current = mirror { + for child in current.children { + if child.label == "bridge", let bridge = child.value as? ExprBridge { + return bridge + } + } + mirror = current.superclassMirror + } + + for child in Mirror(reflecting: value).children { + if child.label == "expr" || child.label == "constant" || child.label == "field", + let nested = exprBridge(from: child.value) + { + return nested + } + } + return nil +} + +private func sendableExpressions(_ expressions: [any FirebaseFirestore.Expression]) + -> [any Sendable] +{ + expressions.map { $0 as any Sendable } +} + +private func constantExpression(from value: Any) throws -> any FirebaseFirestore.Expression { + if value is NSNull { + return Constant.nil + } + if let number = value as? NSNumber { + if CFGetTypeID(number) == CFBooleanGetTypeID() { + return Constant(number.boolValue) + } + let doubleValue = number.doubleValue + if doubleValue.isFinite, doubleValue.rounded() == doubleValue, + doubleValue >= Double(Int.min), doubleValue <= Double(Int.max) + { + return Constant(number.intValue) + } + return Constant(number.doubleValue) + } + if let stringValue = value as? String { + return Constant(stringValue) + } + if let boolValue = value as? Bool { + return Constant(boolValue) + } + if let intValue = value as? Int { + return Constant(intValue) + } + if let doubleValue = value as? Double { + return Constant(doubleValue) + } + if let dateValue = value as? Date { + return Constant(dateValue) + } + if let timestampValue = value as? Timestamp { + return Constant(timestampValue) + } + if let geoPointValue = value as? GeoPoint { + return Constant(geoPointValue) + } + if let referenceValue = value as? DocumentReference { + return Constant(referenceValue) + } + if let vectorValue = value as? VectorValue { + return Constant(vectorValue) + } + if let data = value as? Data { + return Constant(data) + } + if let typedData = value as? FlutterStandardTypedData { + return Constant(typedData.data) + } + throw parseError("Unsupported constant value: \(type(of: value))") +} + +private func functionExpression( + name: String, + args: [any FirebaseFirestore.Expression] +) -> FunctionExpression { + FunctionExpression(functionName: name, args: args) +} + +private final class PipelineExpressionParser { + let firestore: Firestore + private var expressionDepth = 0 + + init(firestore: Firestore) { + self.firestore = firestore + } + + func parseExpression(_ map: [String: Any]) throws -> ExprBridge { + try toExprBridge(parseTypedExpression(map)) + } + + func parseBooleanExpression(_ map: [String: Any]) throws -> ExprBridge { + try toExprBridge(parseBooleanTypedExpression(map)) + } + + private func parseBooleanTypedExpression(_ map: [String: Any]) throws + -> any FirebaseFirestore.BooleanExpression + { + let expression = try parseTypedExpression(map) + if let booleanExpression = expression as? any FirebaseFirestore.BooleanExpression { + return booleanExpression + } + return expression.asBoolean() + } + + private func parseTypedExpressions( + _ maps: [Any], + errorMessage: String + ) throws + -> [any FirebaseFirestore.Expression] + { + var expressions: [any FirebaseFirestore.Expression] = [] + for value in maps { + guard let map = asMap(value) else { continue } + try expressions.append(parseTypedExpression(map)) + } + if expressions.isEmpty { + throw parseError(errorMessage) + } + return expressions + } + + private func parseTypedExpression(_ map: [String: Any]) throws -> any FirebaseFirestore + .Expression + { + expressionDepth += 1 + defer { expressionDepth -= 1 } + if expressionDepth > kMaxPipelineExpressionDepth { + throw parseError("Pipeline expression nested too deeply") + } + + let name = map["name"] as? String + if name == nil { + if let args = asMap(map["args"]), let field = args["field"] as? String { + return Field(field) + } + throw parseError("Expression must have a 'name' field") + } + + let resolvedName = name! + let args = asMap(map["args"]) ?? [:] + + if resolvedName == "field" { + guard let field = args["field"] as? String else { + throw parseError("Field expression requires 'field' argument") + } + return Field(field) + } + + if resolvedName == "constant" { + guard let value = args["value"] else { + throw parseError("Constant requires 'value' argument") + } + if let valueMap = asMap(value), let path = valueMap["path"] as? String { + return Constant(firestore.document(path)) + } + return try constantExpression(from: value) + } + + if resolvedName == "alias" { + guard let exprMap = asMap(args["expression"]) else { + throw parseError("Alias requires 'expression'") + } + return try parseTypedExpression(exprMap) + } + + if resolvedName == "null" { + return Constant.nil + } + + if resolvedName == "score" { + return Score() + } + + if resolvedName == "document_id_from_ref" { + guard let path = args["doc_ref"] as? String, !path.isEmpty else { + throw parseError("document_id_from_ref requires doc_ref path") + } + return Constant(firestore.document(path)).documentId() + } + + if resolvedName == "as_boolean" { + guard let exprMap = asMap(args["expression"]) else { + throw parseError("as_boolean requires expression") + } + return try parseBooleanTypedExpression(exprMap) + } + + if resolvedName == "document_matches" { + guard let query = args["query"] as? String else { + throw parseError("document_matches requires query") + } + return DocumentMatches(query) + } + + var sdkName = resolvedName + if resolvedName == "bit_xor" { sdkName = "xor" } + if resolvedName == "modulo" { sdkName = "mod" } + + if kBinaryNames.contains(sdkName) || resolvedName == "bit_xor" { + guard let leftMap = asMap(args["left"]), let rightMap = asMap(args["right"]) else { + throw parseError("\(resolvedName) requires left and right expressions") + } + let left = try parseTypedExpression(leftMap) + let right = try parseTypedExpression(rightMap) + switch sdkName { + case "equal": + return left.equal(right) + case "not_equal": + return left.notEqual(right) + case "greater_than": + return left.greaterThan(right) + case "greater_than_or_equal": + return left.greaterThanOrEqual(right) + case "less_than": + return left.lessThan(right) + case "less_than_or_equal": + return left.lessThanOrEqual(right) + case "add": + return left.add(right) + case "subtract": + return left.subtract(right) + case "multiply": + return left.multiply(right) + case "divide": + return left.divide(right) + case "mod": + return left.mod(right) + default: + return functionExpression(name: sdkName, args: [left, right]) + } + } + + if resolvedName == "exists" || resolvedName == "is_error" || resolvedName == "is_absent" + || resolvedName == "not" + { + guard let exprMap = asMap(args["expression"]) else { + throw parseError("\(resolvedName) requires expression") + } + if resolvedName == "not" { + return try !parseBooleanTypedExpression(exprMap) + } + let expr = try parseTypedExpression(exprMap) + switch resolvedName { + case "exists": + return expr.exists() + case "is_error": + return expr.isError() + default: + return expr.isAbsent() + } + } + + if [ + "length", "to_lower_case", "to_upper_case", "trim", "abs", "array_length", + "array_reverse", "bit_not", "document_id", "collection_id", + ].contains(resolvedName) { + guard let exprMap = asMap(args["expression"]) else { + throw parseError("\(resolvedName) requires expression") + } + let expr = try parseTypedExpression(exprMap) + switch resolvedName { + case "length": + return expr.length() + case "to_lower_case": + return expr.toLower() + case "to_upper_case": + return expr.toUpper() + case "trim": + return expr.trim() + case "abs": + return expr.abs() + case "array_length": + return expr.arrayLength() + case "array_reverse": + return expr.arrayReverse() + case "document_id": + return expr.documentId() + case "collection_id": + return expr.collectionId() + default: + return functionExpression(name: resolvedName, args: [expr]) + } + } + + if resolvedName == "and" || resolvedName == "or" || resolvedName == "xor" + || resolvedName == "nor" + { + guard let exprMaps = asArray(args["expressions"]), !exprMaps.isEmpty else { + throw parseError("\(resolvedName) requires at least one expression") + } + var booleanExprs: [any FirebaseFirestore.BooleanExpression] = [] + for em in exprMaps { + guard let emMap = asMap(em) else { continue } + try booleanExprs.append(parseBooleanTypedExpression(emMap)) + } + guard let first = booleanExprs.first else { + throw parseError("\(resolvedName) requires at least one expression") + } + if resolvedName == "and" { + return booleanExprs.dropFirst().reduce(first) { $0 && $1 } + } + if resolvedName == "or" { + return booleanExprs.dropFirst().reduce(first) { $0 || $1 } + } + if resolvedName == "xor" { + return booleanExprs.dropFirst().reduce(first) { $0 ^ $1 } + } + return !(booleanExprs.dropFirst().reduce(first) { $0 || $1 }) + } + + if resolvedName == "equal_any" || resolvedName == "not_equal_any" { + let valuesMaps = asArray(args["values"]) + guard let valueMap = asMap(args["value"]), + let valuesMaps, !valuesMaps.isEmpty + else { + throw parseError("\(resolvedName) requires value and non-empty values") + } + let valueExpr = try parseTypedExpression(valueMap) + let valueExprs = try parseTypedExpressions( + valuesMaps, + errorMessage: "\(resolvedName) requires at least one value" + ) + if resolvedName == "equal_any" { + return valueExpr.equalAny(valueExprs) + } + return valueExpr.notEqualAny(valueExprs) + } + + if resolvedName == "array_contains" { + guard let arrayMap = asMap(args["array"]), let elementMap = asMap(args["element"]) else { + throw parseError("array_contains requires array and element") + } + return try parseTypedExpression(arrayMap) + .arrayContains(parseTypedExpression(elementMap)) + } + + if resolvedName == "array_contains_all" || resolvedName == "array_contains_any" { + guard let arrayMap = asMap(args["array"]) else { + throw parseError("\(resolvedName) requires array") + } + let arrayExpr = try parseTypedExpression(arrayMap) + + var valuesMaps = asArray(args["values"]) + if valuesMaps == nil { + valuesMaps = asArray(args["elements"]) + } + + if let valuesMaps, !valuesMaps.isEmpty { + let valueExprs = try parseTypedExpressions( + valuesMaps, + errorMessage: "\(resolvedName) requires at least one value" + ) + if resolvedName == "array_contains_all" { + return arrayExpr.arrayContainsAll(valueExprs) + } + return arrayExpr.arrayContainsAny(valueExprs) + } + + if resolvedName == "array_contains_all", + let arrayExpressionMap = asMap(args["array_expression"]) + { + return try arrayExpr.arrayContainsAll(parseTypedExpression(arrayExpressionMap)) + } + + throw parseError( + "\(resolvedName) requires array and values/elements, or array_contains_all with array_expression" + ) + } + + if resolvedName == "concat" { + guard let exprMaps = asArray(args["expressions"]), !exprMaps.isEmpty else { + throw parseError("concat requires non-empty expressions") + } + let expressions = try parseTypedExpressions( + exprMaps, + errorMessage: "concat requires at least one expression" + ) + if expressions.count == 1 { + return expressions[0] + } + return expressions[0].concat(sendableExpressions(Array(expressions.dropFirst()))) + } + + if resolvedName == "substring" { + guard let exprMap = asMap(args["expression"]), + let startMap = asMap(args["start"]), + let endMap = asMap(args["end"]) + else { + throw parseError("substring requires expression, start, and end") + } + return try parseTypedExpression(exprMap).substring( + position: parseTypedExpression(startMap), + length: parseTypedExpression(endMap) + ) + } + + if resolvedName == "replace" || resolvedName == "string_replace_all" { + guard let exprMap = asMap(args["expression"]), + let findMap = asMap(args["find"]), + let replacementMap = asMap(args["replacement"]) + else { + throw parseError("\(resolvedName) requires expression, find, and replacement") + } + return try parseTypedExpression(exprMap).stringReplaceAll( + parseTypedExpression(findMap), + with: parseTypedExpression(replacementMap) + ) + } + + if resolvedName == "string_replace_one" { + guard let exprMap = asMap(args["expression"]), + let findMap = asMap(args["find"]), + let replacementMap = asMap(args["replacement"]) + else { + throw parseError("string_replace_one requires expression, find, and replacement") + } + return try parseTypedExpression(exprMap).stringReplaceOne( + parseTypedExpression(findMap), + with: parseTypedExpression(replacementMap) + ) + } + + if resolvedName == "string_index_of" || resolvedName == "string_repeat" { + let argumentName = resolvedName == "string_index_of" ? "search" : "repetitions" + guard let exprMap = asMap(args["expression"]), + let argumentMap = asMap(args[argumentName]) + else { + throw parseError("\(resolvedName) requires expression and \(argumentName)") + } + let expr = try parseTypedExpression(exprMap) + let argument = try parseTypedExpression(argumentMap) + if resolvedName == "string_index_of" { + return expr.stringIndexOf(argument) + } + return expr.stringRepeat(argument) + } + + if resolvedName == "ltrim" || resolvedName == "rtrim" { + guard let exprMap = asMap(args["expression"]) else { + throw parseError("\(resolvedName) requires expression") + } + let expr = try parseTypedExpression(exprMap) + guard let valueMap = asMap(args["value"]) else { + return resolvedName == "ltrim" ? expr.ltrim() : expr.rtrim() + } + let value = try parseTypedExpression(valueMap) + return resolvedName == "ltrim" ? expr.ltrim(value) : expr.rtrim(value) + } + + if resolvedName == "split" || resolvedName == "join" { + guard let exprMap = asMap(args["expression"]), + let delimiterMap = asMap(args["delimiter"]) + else { + throw parseError("\(resolvedName) requires expression and delimiter") + } + let expr = try parseTypedExpression(exprMap) + let delimiter = try parseTypedExpression(delimiterMap) + if resolvedName == "split" { + return expr.split(delimiter: delimiter) + } + if let delimiterMap = asMap(args["delimiter"]), + (delimiterMap["name"] as? String) == "constant", + let delimiterValue = asMap(delimiterMap["args"])?["value"] as? String + { + return expr.join(delimiter: delimiterValue) + } + return functionExpression(name: "join", args: [expr, delimiter]) + } + + if resolvedName == "array_concat" { + guard let firstMap = asMap(args["first"]), let secondMap = asMap(args["second"]) else { + throw parseError("array_concat requires first and second") + } + return try parseTypedExpression(firstMap) + .arrayConcat([parseTypedExpression(secondMap)]) + } + + if resolvedName == "array_concat_multiple" { + guard let arraysMaps = asArray(args["arrays"]), !arraysMaps.isEmpty else { + throw parseError("array_concat_multiple requires non-empty arrays") + } + let expressions = try parseTypedExpressions( + arraysMaps, + errorMessage: "array_concat_multiple requires at least one array" + ) + if expressions.count == 1 { + return expressions[0] + } + return expressions[0].arrayConcat(Array(expressions.dropFirst())) + } + + if resolvedName == "array_slice" { + guard let exprMap = asMap(args["expression"]), let offsetMap = asMap(args["offset"]) else { + throw parseError("array_slice requires expression and offset") + } + let expr = try parseTypedExpression(exprMap) + let offset = try parseTypedExpression(offsetMap) + if let lengthMap = asMap(args["length"]) { + return try expr.arraySlice(offset: offset, length: parseTypedExpression(lengthMap)) + } + return expr.arraySlice(offset: offset) + } + + if resolvedName == "array_filter" { + guard let exprMap = asMap(args["expression"]), + let alias = args["alias"] as? String, + let filterMap = asMap(args["filter"]) + else { + throw parseError("array_filter requires expression, alias, and filter") + } + return try parseTypedExpression(exprMap).arrayFilter( + alias: alias, + filter: parseBooleanTypedExpression(filterMap) + ) + } + + if resolvedName == "array_transform" { + guard let exprMap = asMap(args["expression"]), + let elementAlias = args["element_alias"] as? String, + let transformMap = asMap(args["transform"]) + else { + throw parseError("array_transform requires expression, element_alias, and transform") + } + return try parseTypedExpression(exprMap).arrayTransform( + elementAlias: elementAlias, + transform: parseTypedExpression(transformMap) + ) + } + + if resolvedName == "array_transform_with_index" { + guard let exprMap = asMap(args["expression"]), + let elementAlias = args["element_alias"] as? String, + let indexAlias = args["index_alias"] as? String, + let transformMap = asMap(args["transform"]) + else { + throw parseError( + "array_transform_with_index requires expression, element_alias, index_alias, and transform" + ) + } + return try parseTypedExpression(exprMap).arrayTransformWithIndex( + elementAlias: elementAlias, + indexAlias: indexAlias, + transform: parseTypedExpression(transformMap) + ) + } + + if resolvedName == "array" { + guard let elementsMaps = asArray(args["elements"]), !elementsMaps.isEmpty else { + throw parseError("array requires non-empty elements") + } + return try ArrayExpression( + sendableExpressions( + parseTypedExpressions( + elementsMaps, + errorMessage: "array requires at least one element" + ) + ) + ) + } + + if resolvedName == "map" { + guard let dataMap = asMap(args["data"]), !dataMap.isEmpty else { + throw parseError("map requires non-empty data") + } + var elements: [String: any Sendable] = [:] + for (key, rawValue) in dataMap { + guard let valueMap = asMap(rawValue) else { continue } + elements[key] = try parseTypedExpression(valueMap) + } + if elements.isEmpty { + throw parseError("map requires at least one key-value pair") + } + return MapExpression(elements) + } + + if resolvedName == "map_get" { + guard let mapMap = asMap(args["map"]), let keyMap = asMap(args["key"]) else { + throw parseError("map_get requires map and key") + } + let mapExpr = try parseTypedExpression(mapMap) + let keyExpr = try parseTypedExpression(keyMap) + return mapExpr.getField(keyExpr) + } + + if resolvedName == "if_absent" { + guard let exprMap = asMap(args["expression"]), let elseMap = asMap(args["else"]) else { + throw parseError("if_absent requires expression and else") + } + return try parseTypedExpression(exprMap).ifAbsent(parseTypedExpression(elseMap)) + } + + if resolvedName == "if_error" { + guard let exprMap = asMap(args["expression"]), let catchMap = asMap(args["catch"]) else { + throw parseError("if_error requires expression and catch") + } + return try parseTypedExpression(exprMap).ifError(parseTypedExpression(catchMap)) + } + + if resolvedName == "conditional" { + guard let conditionMap = asMap(args["condition"]), + let thenMap = asMap(args["then"]), + let elseMap = asMap(args["else"]) + else { + throw parseError("conditional requires condition, then, and else") + } + return try ConditionalExpression( + parseBooleanTypedExpression(conditionMap), + then: parseTypedExpression(thenMap), + else: parseTypedExpression(elseMap) + ) + } + + if resolvedName == "timestamp_add" || resolvedName == "timestamp_subtract" { + let unitVal = args["unit"] + guard let timestampMap = asMap(args["timestamp"]), + unitVal != nil, + let amountMap = asMap(args["amount"]) + else { + throw parseError("\(resolvedName) requires timestamp, unit, and amount") + } + let timestampExpr = try parseTypedExpression(timestampMap) + let amountExpr = try parseTypedExpression(amountMap) + if resolvedName == "timestamp_add" { + if let unit = unitVal as? String { + return timestampExpr.timestampAdd(amount: amountExpr, unit: unit) + } + return try timestampExpr.timestampAdd( + amount: amountExpr, + unit: parseTypedExpression(asMap(unitVal) ?? [:]) + ) + } + if let unit = unitVal as? String { + return timestampExpr.timestampSubtract(amount: amountExpr, unit: unit) + } + return try timestampExpr.timestampSubtract( + amount: amountExpr, + unit: parseTypedExpression(asMap(unitVal) ?? [:]) + ) + } + + if resolvedName == "current_timestamp" { + return CurrentTimestamp() + } + + if resolvedName == "timestamp_truncate" { + let unitVal = args["unit"] + guard let timestampMap = asMap(args["timestamp"]), unitVal != nil else { + throw parseError("timestamp_truncate requires timestamp and unit") + } + let timestampExpr = try parseTypedExpression(timestampMap) + if let unit = unitVal as? String { + return timestampExpr.timestampTruncate(granularity: unit) + } + return try timestampExpr.timestampTruncate( + granularity: parseTypedExpression(asMap(unitVal) ?? [:]) + ) + } + + if resolvedName == "map_keys" { + guard let exprMap = asMap(args["expression"]) else { + throw parseError("map_keys requires expression") + } + return try parseTypedExpression(exprMap).mapKeys() + } + + if resolvedName == "map_values" { + guard let exprMap = asMap(args["expression"]) else { + throw parseError("map_values requires expression") + } + return try parseTypedExpression(exprMap).mapValues() + } + + if resolvedName == "parent" { + if let docPath = args["doc_ref"] as? String, !docPath.isEmpty { + return Constant(firestore.document(docPath)).parent() + } + guard let exprMap = asMap(args["expression"]) else { + throw parseError("parent requires expression or doc_ref") + } + return try parseTypedExpression(exprMap).parent() + } + + if resolvedName == "timestamp_diff" { + let unitObj = args["unit"] + guard let endMap = asMap(args["end"]), + let startMap = asMap(args["start"]), + unitObj != nil + else { + throw parseError("timestamp_diff requires end, start, and unit") + } + let endExpr = try parseTypedExpression(endMap) + let startExpr = try parseTypedExpression(startMap) + if let unit = unitObj as? String { + return endExpr.timestampDiff(startExpr, unit) + } + guard let unitMap = asMap(unitObj) else { + throw parseError("timestamp_diff unit must be string or expression") + } + return try endExpr.timestampDiff(startExpr, parseTypedExpression(unitMap)) + } + + if resolvedName == "timestamp_extract" { + guard let timestampMap = asMap(args["timestamp"]), let partMap = asMap(args["part"]) else { + throw parseError("timestamp_extract requires timestamp and part") + } + let tsExpr = try parseTypedExpression(timestampMap) + let partExpr = try parseTypedExpression(partMap) + let tzRaw = args["timezone"] + if tzRaw == nil { + return tsExpr.timestampExtract(part: partExpr) + } + if let tzRaw = tzRaw as? String { + return tsExpr.timestampExtract(part: partExpr, timezone: tzRaw) + } + guard let tzMap = asMap(tzRaw) else { + throw parseError("timestamp_extract timezone must be string or expression") + } + return try tsExpr.timestampExtract(part: partExpr, timezone: parseTypedExpression(tzMap)) + } + + if resolvedName == "if_null" { + guard let exprMap = asMap(args["expression"]), + let replMap = asMap(args["replacement"]) + else { + throw parseError("if_null requires expression and replacement") + } + return try parseTypedExpression(exprMap).ifNull(parseTypedExpression(replMap)) + } + + if resolvedName == "coalesce" { + guard let exprMaps = asArray(args["expressions"]), exprMaps.count >= 2 else { + throw parseError("coalesce requires at least two expressions") + } + let exprs = try parseTypedExpressions( + exprMaps, + errorMessage: "coalesce requires at least two expressions" + ) + guard exprs.count >= 2 else { + throw parseError("coalesce requires at least two expressions") + } + return exprs[0].coalesce(Array(exprs.dropFirst())) + } + + if resolvedName == "switch_on" { + guard let exprMaps = asArray(args["expressions"]), exprMaps.count >= 2 else { + throw parseError("switch_on requires at least two expressions") + } + var switchArgs: [any FirebaseFirestore.Expression] = [] + for i in 0.. any FirebaseFirestore.Expression { + if let map = asMap(value) { + return try parseTypedExpression(map) + } + return try constantExpression(from: value as Any) + } + + private func parseFilterTypedExpression(args: [String: Any]) throws + -> any FirebaseFirestore.Expression + { + let op = args["operator"] as? String + let exprMaps = asArray(args["expressions"]) + if let op, let exprMaps { + if exprMaps.isEmpty { + throw parseError("filter with operator requires at least one expression") + } + var booleanExprs: [any FirebaseFirestore.BooleanExpression] = [] + for em in exprMaps { + guard let emMap = asMap(em) else { continue } + try booleanExprs.append(parseBooleanTypedExpression(emMap)) + } + guard let first = booleanExprs.first else { + throw parseError("filter with operator requires at least one expression") + } + if booleanExprs.count == 1 { + return first + } + if op == "or" || op == "OR" { + return booleanExprs.dropFirst().reduce(first) { $0 || $1 } + } + return booleanExprs.dropFirst().reduce(first) { $0 && $1 } + } + + guard let fieldName = args["field"] as? String else { + throw parseError("filter requires operator+expressions or field") + } + let fieldExpr = Field(fieldName) + + for key in kFilterComparisonKeys { + let value = args[key] + if value == nil { continue } + + switch key { + case "isEqualTo": + return try fieldExpr.equal(rightTypedExpression(from: value)) + case "isNotEqualTo": + return try fieldExpr.notEqual(rightTypedExpression(from: value)) + case "isGreaterThan": + return try fieldExpr.greaterThan(rightTypedExpression(from: value)) + case "isGreaterThanOrEqualTo": + return try fieldExpr.greaterThanOrEqual(rightTypedExpression(from: value)) + case "isLessThan": + return try fieldExpr.lessThan(rightTypedExpression(from: value)) + case "isLessThanOrEqualTo": + return try fieldExpr.lessThanOrEqual(rightTypedExpression(from: value)) + case "arrayContains": + return try fieldExpr.arrayContains(rightTypedExpression(from: value)) + case "arrayContainsAny": + let valuesList = asArray(value) ?? [] + let valueExprs = try valuesList.map { try rightTypedExpression(from: $0) } + if valueExprs.isEmpty { + throw parseError("arrayContainsAny requires non-empty list") + } + return fieldExpr.arrayContainsAny(valueExprs) + case "whereIn": + let valuesList = asArray(value) ?? [] + let valueExprs = try valuesList.map { try rightTypedExpression(from: $0) } + if valueExprs.isEmpty { + throw parseError("whereIn requires non-empty list") + } + return fieldExpr.equalAny(valueExprs) + case "whereNotIn": + let valuesList = asArray(value) ?? [] + let valueExprs = try valuesList.map { try rightTypedExpression(from: $0) } + if valueExprs.isEmpty { + throw parseError("whereNotIn requires non-empty list") + } + return fieldExpr.notEqualAny(valueExprs) + case "isNull": + return fieldExpr.equal(Constant.nil) + case "isNotNull": + return fieldExpr.notEqual(Constant.nil) + default: + continue + } + } + + throw parseError( + "filter requires at least one comparison (isEqualTo, isGreaterThan, etc.)" + ) + } +} + +enum PipelineParser { + static func executePipeline( + firestore: Firestore, + stages: [[String: Any?]], + options: [String: Any?]?, + completion: @escaping (Any?, Error?) -> Void + ) { + _ = options + if NSClassFromString("FIRPipelineBridge") == nil { + completion(nil, pipelineUnavailableError()) + return + } + + if stages.isEmpty { + completion(nil, parseError("Pipeline requires at least one stage")) + return + } + + let stageMaps = stages.map { dictionaryFromOptionalKeyed($0) } + do { + let stageBridges = try parseStages(firestore: firestore, stages: stageMaps) + let pipeline = PipelineBridge(stages: stageBridges, db: firestore) + pipeline.execute { snapshot, execError in + if let execError { + completion(nil, execError) + return + } + completion(snapshot, nil) + } + } catch { + completion(nil, error) + } + } + + private static func keyForExpressionMap(_ em: [String: Any]) throws -> String { + if let alias = nestedValue(em, keyPath: "args.alias") as? String, !alias.isEmpty { + return alias + } + if (em["name"] as? String) == "field" { + if let field = nestedValue(em, keyPath: "args.field") as? String { + return field + } + throw parseError("field expression must have args.field") + } + throw parseError("expression must have alias or be a field reference") + } + + private static func parseSearchFields( + expressionMaps exprMaps: [Any], + exprParser: PipelineExpressionParser + ) throws -> [String: ExprBridge] { + var fields: [String: ExprBridge] = [:] + for em in exprMaps { + guard let emMap = asMap(em) else { continue } + let expr = try exprParser.parseExpression(emMap) + let key = try keyForExpressionMap(emMap) + if key.isEmpty { + throw parseError("expression must have alias or be a field reference") + } + fields[key] = expr + } + return fields + } + + private static func parseSearchStage( + args: [String: Any], + exprParser: PipelineExpressionParser + ) throws -> StageBridge { + let queryType = args["query_type"] as? String + let query = args["query"] + var options: [String: ExprBridge] = [:] + + if queryType == "string" { + guard let query = query as? String else { + throw parseError("search query_type 'string' requires string query") + } + options["query"] = DocumentMatches(query).bridge + } else if queryType == "expression" { + guard let queryMap = asMap(query) else { + throw parseError("search query_type 'expression' requires expression query") + } + options["query"] = try exprParser.parseBooleanExpression(queryMap) + } else { + throw parseError("search requires query_type to be 'string' or 'expression'") + } + + if let limit = args["limit"] as? NSNumber { + options["limit"] = ConstantBridge(limit) + } + if let offset = args["offset"] as? NSNumber { + options["offset"] = ConstantBridge(offset) + } + if let retrievalDepth = args["retrieval_depth"] as? NSNumber { + options["retrieval_depth"] = ConstantBridge(retrievalDepth) + } + if let languageCode = args["language_code"] as? String { + options["language_code"] = ConstantBridge(languageCode) + } + + var sort: [OrderingBridge] = [] + if let orderingMaps = asArray(args["sort"]) { + for om in orderingMaps { + guard let omMap = asMap(om), let exprMap = asMap(omMap["expression"]) else { continue } + let dir = omMap["order_direction"] as? String + let expr = try exprParser.parseExpression(exprMap) + let direction = dir == "asc" ? "ascending" : "descending" + sort.append(OrderingBridge(expr: expr, direction: direction)) + } + } + + var addFields: [String: ExprBridge] = [:] + if let addFieldMaps = asArray(args["add_fields"]), !addFieldMaps.isEmpty { + addFields = try parseSearchFields(expressionMaps: addFieldMaps, exprParser: exprParser) + } + + return SearchStageBridge( + options: options, + addFields: addFields, + select: [:], + sort: sort + ) + } + + private static func parseStages( + firestore: Firestore, + stages: [[String: Any]], + depth: Int = 0 + ) throws -> [StageBridge] { + if depth > kMaxPipelineStageDepth { + throw parseError("Pipeline nested too deeply") + } + let exprParser = PipelineExpressionParser(firestore: firestore) + var stageBridges: [StageBridge] = [] + + for i in 0.. AggregateFunctionBridge + { + guard let name = funcMap["name"] as? String else { + throw parseError("Aggregate function must have a 'name'") + } + var iosName = name + if name == "count_all" { + iosName = "count" + } else if name == "minimum" { + iosName = "min" + } else if name == "maximum" { + iosName = "max" + } + var argsArray: [ExprBridge] = [] + if let argsDict = asMap(funcMap["args"]), let exprMap = asMap(argsDict["expression"]) { + let expr = try exprParser.parseExpression(exprMap) + argsArray.append(expr) + } + return AggregateFunctionBridge(name: iosName, args: argsArray) + } + + private static func parseAggregateStage( + args: [String: Any], + exprParser: PipelineExpressionParser + ) throws + -> StageBridge + { + guard let accumulatorMaps = asArray(args["aggregate_functions"]), !accumulatorMaps.isEmpty + else { + throw parseError("aggregate requires aggregate_functions") + } + return try parseAggregateStage( + accumulatorMaps: accumulatorMaps, + groupMaps: nil, + exprParser: exprParser + ) + } + + private static func parseAggregateStageWithOptions( + args: [String: Any], + exprParser: PipelineExpressionParser + ) throws + -> StageBridge + { + guard let stageMap = asMap(args["aggregate_stage"]) else { + throw parseError("aggregate_with_options requires aggregate_stage") + } + var accumulatorMaps = asArray(stageMap["accumulators"]) + if accumulatorMaps == nil || accumulatorMaps?.isEmpty == true { + accumulatorMaps = asArray(stageMap["aggregate_functions"]) + } + guard let accumulatorMaps, !accumulatorMaps.isEmpty else { + throw parseError("aggregate_stage requires accumulators or aggregate_functions") + } + let groupMaps = asArray(stageMap["groups"]) + return try parseAggregateStage( + accumulatorMaps: accumulatorMaps, + groupMaps: groupMaps, + exprParser: exprParser + ) + } + + private static func parseAggregateStage( + accumulatorMaps: [Any], + groupMaps: [Any]?, + exprParser: PipelineExpressionParser + ) throws + -> StageBridge + { + var accumulators: [String: AggregateFunctionBridge] = [:] + for accMap in accumulatorMaps { + guard let accMap = asMap(accMap) else { continue } + var alias: String? + var funcMap: [String: Any]? + if (accMap["name"] as? String) == "alias" { + guard let accArgs = asMap(accMap["args"]) else { continue } + alias = accArgs["alias"] as? String + funcMap = asMap(accArgs["aggregate_function"]) + } + guard let alias, let funcMap else { + throw parseError("Each accumulator must have alias and aggregate_function") + } + let funcBridge = try aggregateFunction(from: funcMap, exprParser: exprParser) + accumulators[alias] = funcBridge + } + if accumulators.isEmpty { + throw parseError("aggregate requires at least one valid accumulator") + } + + var groups: [String: ExprBridge] = [:] + if let groupMaps, !groupMaps.isEmpty { + for gm in groupMaps { + guard let gmMap = asMap(gm) else { continue } + guard let expr = try? exprParser.parseExpression(gmMap) else { continue } + let groupKey = try keyForExpressionMap(gmMap) + if groupKey.isEmpty { + throw parseError( + "aggregate group expression must be a field reference or have an alias" + ) + } + groups[groupKey] = expr + } + } + + return AggregateStageBridge(accumulators: accumulators, groups: groups) + } + + private static func buildPipeline( + firestore: Firestore, + stages: [[String: Any]], + depth: Int = 0 + ) throws -> PipelineBridge { + let stageBridges = try parseStages(firestore: firestore, stages: stages, depth: depth) + return PipelineBridge(stages: stageBridges, db: firestore) + } +} diff --git a/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/QuerySnapshotStreamHandler.swift b/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/QuerySnapshotStreamHandler.swift new file mode 100644 index 000000000000..5a38338e808a --- /dev/null +++ b/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/QuerySnapshotStreamHandler.swift @@ -0,0 +1,94 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import FirebaseFirestore +import Foundation + +#if canImport(firebase_core) + import firebase_core +#else + import firebase_core_shared +#endif + +#if os(iOS) + import Flutter +#elseif os(macOS) + import FlutterMacOS +#endif + +final class QuerySnapshotStreamHandler: NSObject, FlutterStreamHandler { + private let firestore: Firestore + private let query: Query? + private let includeMetadataChanges: Bool + private let serverTimestampBehavior: FirebaseFirestore.ServerTimestampBehavior + private let source: FirebaseFirestore.ListenSource + private var listenerRegistration: ListenerRegistration? + private let snapshotQueue = DispatchQueue( + label: "io.flutter.plugins.firebase.firestore.query_snapshot" + ) + + init( + firestore: Firestore, + query: Query?, + includeMetadataChanges: Bool, + serverTimestampBehavior: FirebaseFirestore.ServerTimestampBehavior, + source: FirebaseFirestore.ListenSource + ) { + self.firestore = firestore + self.query = query + self.includeMetadataChanges = includeMetadataChanges + self.serverTimestampBehavior = serverTimestampBehavior + self.source = source + } + + func onListen(withArguments arguments: Any?, eventSink events: @escaping FlutterEventSink) + -> FlutterError? + { + guard let query else { + return FlutterError( + code: "sdk-error", + message: + "An error occurred while parsing query arguments, see native logs for more information. Please report this issue.", + details: nil + ) + } + + let options = SnapshotListenOptions() + .withIncludeMetadataChanges(includeMetadataChanges) + .withSource(source) + + listenerRegistration = query.addSnapshotListener(options: options) { + [snapshotQueue, serverTimestampBehavior] snapshot, error in + if let error { + let (code, message) = FirebaseFirestoreUtils.errorCodeAndMessage(from: error) + DispatchQueue.main.async { + events( + FLTFirebasePlugin.createFlutterError( + fromCode: code, + message: message, + optionalDetails: ["code": code, "message": message], + andOptionalNSError: error as NSError + ) + ) + } + } else if let snapshot { + snapshotQueue.async { + let pigeonSnapshot = PigeonParser.toPigeonQuerySnapshot( + snapshot, serverTimestampBehavior: serverTimestampBehavior + ) + DispatchQueue.main.async { + events(pigeonSnapshot) + } + } + } + } + return nil + } + + func onCancel(withArguments arguments: Any?) -> FlutterError? { + listenerRegistration?.remove() + listenerRegistration = nil + return nil + } +} diff --git a/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/SnapshotsInSyncStreamHandler.swift b/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/SnapshotsInSyncStreamHandler.swift new file mode 100644 index 000000000000..88328f057450 --- /dev/null +++ b/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/SnapshotsInSyncStreamHandler.swift @@ -0,0 +1,38 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import FirebaseFirestore +import Foundation + +#if os(iOS) + import Flutter +#elseif os(macOS) + import FlutterMacOS +#endif + +final class SnapshotsInSyncStreamHandler: NSObject, FlutterStreamHandler { + private let firestore: Firestore + private var listenerRegistration: ListenerRegistration? + + init(firestore: Firestore) { + self.firestore = firestore + } + + func onListen(withArguments arguments: Any?, eventSink events: @escaping FlutterEventSink) + -> FlutterError? + { + listenerRegistration = firestore.addSnapshotsInSyncListener { + DispatchQueue.main.async { + events(nil) + } + } + return nil + } + + func onCancel(withArguments arguments: Any?) -> FlutterError? { + listenerRegistration?.remove() + listenerRegistration = nil + return nil + } +} diff --git a/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/TransactionStreamHandler.swift b/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/TransactionStreamHandler.swift new file mode 100644 index 000000000000..97dd6a4f370c --- /dev/null +++ b/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/TransactionStreamHandler.swift @@ -0,0 +1,149 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import FirebaseFirestore +import Foundation + +#if canImport(firebase_core) + import firebase_core +#else + import firebase_core_shared +#endif + +#if os(iOS) + import Flutter +#elseif os(macOS) + import FlutterMacOS +#endif + +final class TransactionStreamHandler: NSObject, FlutterStreamHandler { + private let transactionId: String + private let firestore: Firestore + private let timeout: Int + private let maxAttempts: Int + private let started: (Transaction) -> Void + private let ended: () -> Void + private let semaphore = DispatchSemaphore(value: 0) + private var resultType: InternalTransactionResult = .success + private var commands: [InternalTransactionCommand?] = [] + + init( + id transactionId: String, + firestore: Firestore, + timeout: Int, + maxAttempts: Int, + started: @escaping (Transaction) -> Void, + ended: @escaping () -> Void + ) { + self.transactionId = transactionId + self.firestore = firestore + self.timeout = timeout + self.maxAttempts = maxAttempts + self.started = started + self.ended = ended + } + + func onListen(withArguments arguments: Any?, eventSink events: @escaping FlutterEventSink) + -> FlutterError? + { + let options = TransactionOptions() + options.maxAttempts = maxAttempts + + firestore.runTransaction( + with: options, + block: { [weak self] transaction, _ in + guard let self else { return nil } + self.started(transaction) + + DispatchQueue.main.async { + events([ + "appName": FLTFirebasePlugin.firebaseAppName(fromIosName: self.firestore.app.name) + as Any + ]) + } + + let timedOut = self.semaphore.wait( + timeout: .now() + .milliseconds(self.timeout) + ) + if timedOut == .timedOut { + let (code, message) = FirebaseFirestoreUtils.errorCodeAndMessage( + from: NSError( + domain: FirestoreErrorDomain, + code: FirestoreErrorCode.deadlineExceeded.rawValue, + userInfo: [:] + ) + ) + DispatchQueue.main.async { + events(["error": ["code": code, "message": message]]) + } + } + + if self.resultType == .failure { + return nil + } + + for command in self.commands { + guard let command else { continue } + let reference = self.firestore.document(command.path) + switch command.type { + case .deleteType: + transaction.deleteDocument(reference) + case .update: + if let data = command.data as? [AnyHashable: Any] { + transaction.updateData(data, forDocument: reference) + } + case .set: + let data = command.data as? [String: Any] ?? [:] + if command.option?.merge == true { + transaction.setData(data, forDocument: reference, merge: true) + } else if let mergeFields = command.option?.mergeFields { + transaction.setData( + data, + forDocument: reference, + mergeFields: PigeonParser.parseFieldPath(mergeFields) + ) + } else { + transaction.setData(data, forDocument: reference) + } + case .get: + break + } + } + return nil + }, + completion: { [weak self] _, error in + if let error { + let (code, message) = FirebaseFirestoreUtils.errorCodeAndMessage(from: error) + DispatchQueue.main.async { + events(["error": ["code": code, "message": message]]) + } + } else { + DispatchQueue.main.async { + events(["complete": true]) + } + } + DispatchQueue.main.async { + events(FlutterEndOfEventStream) + } + self?.ended() + } + ) + + return nil + } + + func onCancel(withArguments arguments: Any?) -> FlutterError? { + semaphore.signal() + return nil + } + + func receiveTransactionResponse( + _ resultType: InternalTransactionResult, + commands: [InternalTransactionCommand?]? + ) { + self.resultType = resultType + self.commands = commands ?? [] + semaphore.signal() + } +} diff --git a/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/include/cloud_firestore/Private/FLTDocumentSnapshotStreamHandler.h b/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/include/cloud_firestore/Private/FLTDocumentSnapshotStreamHandler.h deleted file mode 100644 index fc97756c5d90..000000000000 --- a/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/include/cloud_firestore/Private/FLTDocumentSnapshotStreamHandler.h +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2021 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -#import - -#if TARGET_OS_OSX -#import -#else -#import -#endif - -#if TARGET_OS_OSX -#import -#else -@import FirebaseFirestore; -#endif - -#import - -NS_ASSUME_NONNULL_BEGIN - -@interface FLTDocumentSnapshotStreamHandler : NSObject -@property(nonatomic, strong) FIRFirestore *firestore; -@property(nonatomic, strong) FIRDocumentReference *reference; -@property(nonatomic, assign) BOOL includeMetadataChanges; -@property(nonatomic, assign) FIRListenSource source; -@property(nonatomic, assign) FIRServerTimestampBehavior serverTimestampBehavior; - -- (instancetype)initWithFirestore:(FIRFirestore *)firestore - reference:(FIRDocumentReference *)reference - includeMetadataChanges:(BOOL)includeMetadataChanges - serverTimestampBehavior:(FIRServerTimestampBehavior)serverTimestampBehavior - source:(FIRListenSource)source; - -@end - -NS_ASSUME_NONNULL_END diff --git a/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/include/cloud_firestore/Private/FLTFirebaseFirestoreExtension.h b/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/include/cloud_firestore/Private/FLTFirebaseFirestoreExtension.h deleted file mode 100644 index 522a87991de3..000000000000 --- a/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/include/cloud_firestore/Private/FLTFirebaseFirestoreExtension.h +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2023 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -#import -#import - -@interface FLTFirebaseFirestoreExtension : NSObject - -@property(nonatomic, strong, readonly) FIRFirestore *instance; -@property(nonatomic, strong, readonly) NSString *databaseURL; - -- (instancetype)initWithFirestoreInstance:(FIRFirestore *)instance - databaseURL:(NSString *)databaseURL; - -@end diff --git a/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/include/cloud_firestore/Private/FLTFirebaseFirestoreReader.h b/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/include/cloud_firestore/Private/FLTFirebaseFirestoreReader.h deleted file mode 100644 index 7f49b71eb7e1..000000000000 --- a/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/include/cloud_firestore/Private/FLTFirebaseFirestoreReader.h +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -#import - -#if TARGET_OS_OSX -#import -#else -#import -#endif - -#import - -@interface FLTFirebaseFirestoreReader : FlutterStandardReader -- (id)readValueOfType:(UInt8)type; -+ (dispatch_queue_t)getFirestoreQueue; -@end diff --git a/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/include/cloud_firestore/Private/FLTFirebaseFirestoreUtils.h b/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/include/cloud_firestore/Private/FLTFirebaseFirestoreUtils.h deleted file mode 100644 index e04b30b5483e..000000000000 --- a/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/include/cloud_firestore/Private/FLTFirebaseFirestoreUtils.h +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#import - -#if TARGET_OS_OSX -#import -#else -#import -#endif - -#if TARGET_OS_OSX -#import -#else -@import FirebaseFirestore; -#endif -#import -#import "FLTFirebaseFirestoreExtension.h" - -/// Error code used by the pipeline parser for parse/unsupported expression errors. -/// Handled in ErrorCodeAndMessageFromNSError to return code "parse-error" and the error message. -FOUNDATION_EXPORT const NSInteger FLTFirebaseFirestoreErrorCodePipelineParse; - -typedef NS_ENUM(UInt8, FirestoreDataType) { - FirestoreDataTypeDateTime = 180, - FirestoreDataTypeGeoPoint = 181, - FirestoreDataTypeDocumentReference = 182, - FirestoreDataTypeBlob = 183, - FirestoreDataTypeArrayUnion = 184, - FirestoreDataTypeArrayRemove = 185, - FirestoreDataTypeDelete = 186, - FirestoreDataTypeServerTimestamp = 187, - FirestoreDataTypeTimestamp = 188, - FirestoreDataTypeIncrementDouble = 189, - FirestoreDataTypeIncrementInteger = 190, - FirestoreDataTypeDocumentId = 191, - FirestoreDataTypeFieldPath = 192, - FirestoreDataTypeNaN = 193, - FirestoreDataTypeInfinity = 194, - FirestoreDataTypeNegativeInfinity = 195, - FirestoreDataTypeFirestoreInstance = 196, - FirestoreDataTypeFirestoreQuery = 197, - FirestoreDataTypeFirestoreSettings = 198, - FirestoreDataTypeVectorValue = 199, -}; - -@interface FLTFirebaseFirestoreReaderWriter : FlutterStandardReaderWriter -- (FlutterStandardWriter *_Nonnull)writerWithData:(NSMutableData *_Nullable)data; -- (FlutterStandardReader *_Nonnull)readerWithData:(NSData *_Nullable)data; -@end - -@interface FLTFirebaseFirestoreUtils : NSObject -+ (FIRFirestoreSource)FIRFirestoreSourceFromArguments:(NSDictionary *_Nonnull)arguments; -+ (NSArray *_Nonnull)ErrorCodeAndMessageFromNSError:(NSError *_Nonnull)error; -+ (FLTFirebaseFirestoreExtension *_Nullable) - getCachedFIRFirestoreInstanceForAppName:(NSString *_Nonnull)appName - databaseURL:(NSString *_Nonnull)url; -+ (void)setCachedFIRFirestoreInstance:(FIRFirestore *_Nonnull)firestore - forAppName:(NSString *_Nonnull)appName - databaseURL:(NSString *_Nonnull)url; -+ (void)destroyCachedInstanceForFirestore:(NSString *_Nonnull)appName - databaseURL:(NSString *_Nonnull)databaseURL; -+ (FIRFirestore *_Nullable)getFirestoreInstanceByName:(NSString *_Nonnull)appName - databaseURL:(NSString *_Nonnull)databaseURL; -+ (void)cleanupFirestoreInstances:(void (^_Nullable)(void))completion; -+ (NSUInteger)count; -+ (FLTFirebaseFirestoreExtension *_Nullable)getCachedInstanceForFirestore: - (FIRFirestore *_Nonnull)firestore; -@end diff --git a/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/include/cloud_firestore/Private/FLTFirebaseFirestoreWriter.h b/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/include/cloud_firestore/Private/FLTFirebaseFirestoreWriter.h deleted file mode 100644 index f40262d6b98d..000000000000 --- a/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/include/cloud_firestore/Private/FLTFirebaseFirestoreWriter.h +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -#import - -#if TARGET_OS_OSX -#import -#else -#import -#endif - -#import - -@interface FLTFirebaseFirestoreWriter : FlutterStandardWriter -- (void)writeValue:(id)value; -@end diff --git a/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/include/cloud_firestore/Private/FLTLoadBundleStreamHandler.h b/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/include/cloud_firestore/Private/FLTLoadBundleStreamHandler.h deleted file mode 100644 index 30dbfcd72dc8..000000000000 --- a/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/include/cloud_firestore/Private/FLTLoadBundleStreamHandler.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2022, the Chromium project authors. Please see the AUTHORS file - * for details. All rights reserved. Use of this source code is governed by a - * BSD-style license that can be found in the LICENSE file. - */ - -// -// FLTLoadBundleStreamHandler.h -// Pods -// -// Created by Russell Wheatley on 05/05/2021. -// -#import - -#if TARGET_OS_OSX -#import -#else -#import -#endif - -#if TARGET_OS_OSX -#import -#else -@import FirebaseFirestore; -#endif - -#import - -NS_ASSUME_NONNULL_BEGIN - -@interface FLTLoadBundleStreamHandler : NSObject -@property(nonatomic, strong) FIRFirestore *firestore; -@property(nonatomic, strong) FlutterStandardTypedData *bundle; - -- (instancetype)initWithFirestore:(FIRFirestore *)firestore - bundle:(FlutterStandardTypedData *)bundle; - -@end - -NS_ASSUME_NONNULL_END diff --git a/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/include/cloud_firestore/Private/FLTPipelineParser.h b/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/include/cloud_firestore/Private/FLTPipelineParser.h deleted file mode 100644 index 97c77f0e2a88..000000000000 --- a/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/include/cloud_firestore/Private/FLTPipelineParser.h +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright 2026, the Chromium project authors. Please see the AUTHORS file - * for details. All rights reserved. Use of this source code is governed by a - * BSD-style license that can be found in the LICENSE file. - */ - -#import - -@class FIRFirestore; - -NS_ASSUME_NONNULL_BEGIN - -@interface FLTPipelineParser : NSObject - -+ (void)executePipelineWithFirestore:(FIRFirestore *)firestore - stages:(NSArray *> *)stages - options:(nullable NSDictionary *)options - completion: - (void (^)(id _Nullable snapshot, NSError *_Nullable error))completion; - -@end - -NS_ASSUME_NONNULL_END diff --git a/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/include/cloud_firestore/Private/FLTQuerySnapshotStreamHandler.h b/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/include/cloud_firestore/Private/FLTQuerySnapshotStreamHandler.h deleted file mode 100644 index 8528b72e5af0..000000000000 --- a/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/include/cloud_firestore/Private/FLTQuerySnapshotStreamHandler.h +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2021 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -#import - -#if TARGET_OS_OSX -#import -#else -#import -#endif - -#import - -NS_ASSUME_NONNULL_BEGIN - -@interface FLTQuerySnapshotStreamHandler : NSObject -@property(nonatomic, strong) FIRFirestore *firestore; -@property(nonatomic, strong) FIRQuery *query; -@property(nonatomic, assign) BOOL includeMetadataChanges; -@property(nonatomic, assign) FIRListenSource source; -@property(nonatomic, assign) FIRServerTimestampBehavior serverTimestampBehavior; - -- (instancetype)initWithFirestore:(FIRFirestore *)firestore - query:(FIRQuery *)query - includeMetadataChanges:(BOOL)includeMetadataChanges - serverTimestampBehavior:(FIRServerTimestampBehavior)serverTimestampBehavior - source:(FIRListenSource)source; - -@end - -NS_ASSUME_NONNULL_END diff --git a/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/include/cloud_firestore/Private/FLTSnapshotsInSyncStreamHandler.h b/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/include/cloud_firestore/Private/FLTSnapshotsInSyncStreamHandler.h deleted file mode 100644 index 1a05f121f6e4..000000000000 --- a/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/include/cloud_firestore/Private/FLTSnapshotsInSyncStreamHandler.h +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2021 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -#import - -#if TARGET_OS_OSX -#import -#else -#import -#endif - -#import - -NS_ASSUME_NONNULL_BEGIN - -@interface FLTSnapshotsInSyncStreamHandler : NSObject -@property(nonatomic, strong) FIRFirestore *firestore; - -- (instancetype)initWithFirestore:(FIRFirestore *)firestore; - -@end - -NS_ASSUME_NONNULL_END diff --git a/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/include/cloud_firestore/Private/FLTTransactionStreamHandler.h b/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/include/cloud_firestore/Private/FLTTransactionStreamHandler.h deleted file mode 100644 index c40a148efa5d..000000000000 --- a/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/include/cloud_firestore/Private/FLTTransactionStreamHandler.h +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2021 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -#import - -#if TARGET_OS_OSX -#import -#else -#import -#endif - -#if TARGET_OS_OSX -#import -#else -@import FirebaseFirestore; -#endif -#if __has_include() -#import -#else -#import "../Public/FirestoreMessages.g.h" -#endif -#import - -NS_ASSUME_NONNULL_BEGIN - -@interface FLTTransactionStreamHandler : NSObject -@property(nonatomic, strong) FIRFirestore *firestore; -@property(nonatomic, assign) NSInteger timeout; -@property(nonatomic, assign) NSInteger maxAttempts; - -- (instancetype)initWithId:(NSString *)transactionId - firestore:(FIRFirestore *)firestore - timeout:(NSInteger)timeout - maxAttempts:(NSInteger)maxAttempts - started:(void (^)(FIRTransaction *))startedListener - ended:(void (^)(void))endedListener; -- (void)receiveTransactionResponse:(InternalTransactionResult)resultType - commands:(NSArray *)commands; - -@end - -NS_ASSUME_NONNULL_END diff --git a/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/include/cloud_firestore/Private/FirestorePigeonParser.h b/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/include/cloud_firestore/Private/FirestorePigeonParser.h deleted file mode 100644 index 5fa20d98759f..000000000000 --- a/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/include/cloud_firestore/Private/FirestorePigeonParser.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2023, the Chromium project authors. Please see the AUTHORS file - * for details. All rights reserved. Use of this source code is governed by a - * BSD-style license that can be found in the LICENSE file. - */ - -#if TARGET_OS_OSX -#import -#else -@import FirebaseFirestore; -#endif -#import -#if __has_include() -#import -#else -#import "../Public/FirestoreMessages.g.h" -#endif -@interface FirestorePigeonParser : NSObject - -+ (FIRFilter *_Nonnull)filterFromJson:(NSDictionary *_Nullable)map; - -+ (FIRQuery *_Nonnull)parseQueryWithParameters:(nonnull InternalQueryParameters *)parameters - firestore:(nonnull FIRFirestore *)firestore - path:(nonnull NSString *)path - isCollectionGroup:(Boolean)isCollectionGroup; - -+ (FIRFirestoreSource)parseSource:(Source)source; - -+ (NSArray *_Nonnull)parseFieldPath: - (NSArray *> *_Nonnull)fieldPaths; - -+ (FIRServerTimestampBehavior)parseServerTimestampBehavior: - (ServerTimestampBehavior)serverTimestampBehavior; - -+ (FIRListenSource)parseListenSource:(ListenSource)source; - -+ (InternalSnapshotMetadata *_Nonnull)toPigeonSnapshotMetadata: - (FIRSnapshotMetadata *_Nonnull)snapshotMetadata; - -+ (InternalDocumentSnapshot *_Nonnull) - toPigeonDocumentSnapshot:(FIRDocumentSnapshot *_Nonnull)documentSnapshot - serverTimestampBehavior:(FIRServerTimestampBehavior)serverTimestampBehavior; - -+ (DocumentChangeType)toPigeonDocumentChangeType:(FIRDocumentChangeType)documentChangeType; - -+ (InternalDocumentChange *_Nonnull) - toPigeonDocumentChange:(FIRDocumentChange *_Nonnull)documentChange - serverTimestampBehavior:(FIRServerTimestampBehavior)serverTimestampBehavior; - -+ (NSArray *_Nonnull) - toPigeonDocumentChanges:(NSArray *_Nonnull)documentChanges - serverTimestampBehavior:(FIRServerTimestampBehavior)serverTimestampBehavior; - -+ (InternalQuerySnapshot *_Nonnull)toPigeonQuerySnapshot:(FIRQuerySnapshot *_Nonnull)querySnaphot - serverTimestampBehavior: - (FIRServerTimestampBehavior)serverTimestampBehavior; - -@end diff --git a/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/include/cloud_firestore/Public/CustomPigeonHeaderFirestore.h b/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/include/cloud_firestore/Public/CustomPigeonHeaderFirestore.h deleted file mode 100644 index 7127b0061f58..000000000000 --- a/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/include/cloud_firestore/Public/CustomPigeonHeaderFirestore.h +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2021 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -#import "FirestoreMessages.g.h" - -@interface InternalDocumentSnapshot (Map) -- (NSDictionary *)toList; -@end - -@interface InternalDocumentChange (Map) -- (NSDictionary *)toList; -@end - -@interface InternalSnapshotMetadata (Map) -- (NSDictionary *)toList; -@end diff --git a/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/include/cloud_firestore/Public/FLTFirebaseFirestorePlugin.h b/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/include/cloud_firestore/Public/FLTFirebaseFirestorePlugin.h deleted file mode 100644 index 85e38b5ee2a5..000000000000 --- a/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/include/cloud_firestore/Public/FLTFirebaseFirestorePlugin.h +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -#import - -#if TARGET_OS_OSX -#import -#else -#import -#endif - -#import -#if __has_include() -#import -#else -#import -#endif -#import "FirestoreMessages.g.h" - -@interface FLTFirebaseFirestorePlugin - : FLTFirebasePlugin -+ (NSMutableDictionary *)serverTimestampMap; -@end diff --git a/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/include/cloud_firestore/Public/FirestoreMessages.g.h b/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/include/cloud_firestore/Public/FirestoreMessages.g.h deleted file mode 100644 index 7fd40daf7fcf..000000000000 --- a/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/include/cloud_firestore/Public/FirestoreMessages.g.h +++ /dev/null @@ -1,457 +0,0 @@ -// Copyright 2023, the Chromium project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. -// Autogenerated from Pigeon (v26.3.4), do not edit directly. -// See also: https://pub.dev/packages/pigeon - -@import Foundation; - -@protocol FlutterBinaryMessenger; -@protocol FlutterMessageCodec; -@class FlutterError; -@class FlutterStandardTypedData; - -NS_ASSUME_NONNULL_BEGIN - -/// An enumeration of document change types. -typedef NS_ENUM(NSUInteger, DocumentChangeType) { - /// Indicates a new document was added to the set of documents matching the - /// query. - DocumentChangeTypeAdded = 0, - /// Indicates a document within the query was modified. - DocumentChangeTypeModified = 1, - /// Indicates a document within the query was removed (either deleted or no - /// longer matches the query. - DocumentChangeTypeRemoved = 2, -}; - -/// Wrapper for DocumentChangeType to allow for nullability. -@interface DocumentChangeTypeBox : NSObject -@property(nonatomic, assign) DocumentChangeType value; -- (instancetype)initWithValue:(DocumentChangeType)value; -@end - -/// An enumeration of firestore source types. -typedef NS_ENUM(NSUInteger, Source) { - /// Causes Firestore to try to retrieve an up-to-date (server-retrieved) snapshot, but fall back - /// to - /// returning cached data if the server can't be reached. - SourceServerAndCache = 0, - /// Causes Firestore to avoid the cache, generating an error if the server cannot be reached. Note - /// that the cache will still be updated if the server request succeeds. Also note that - /// latency-compensation still takes effect, so any pending write operations will be visible in - /// the - /// returned data (merged into the server-provided data). - SourceServer = 1, - /// Causes Firestore to immediately return a value from the cache, ignoring the server completely - /// (implying that the returned value may be stale with respect to the value on the server). If - /// there is no data in the cache to satisfy the `get` call, - /// [DocumentReference.get] will throw a [FirebaseException] and - /// [Query.get] will return an empty [QuerySnapshotPlatform] with no documents. - SourceCache = 2, -}; - -/// Wrapper for Source to allow for nullability. -@interface SourceBox : NSObject -@property(nonatomic, assign) Source value; -- (instancetype)initWithValue:(Source)value; -@end - -/// The listener retrieves data and listens to updates from the local Firestore cache only. -/// If the cache is empty, an empty snapshot will be returned. -/// Snapshot events will be triggered on cache updates, like local mutations or load bundles. -/// -/// Note that the data might be stale if the cache hasn't synchronized with recent server-side -/// changes. -typedef NS_ENUM(NSUInteger, ListenSource) { - /// The default behavior. The listener attempts to return initial snapshot from cache and retrieve - /// up-to-date snapshots from the Firestore server. - /// Snapshot events will be triggered on local mutations and server side updates. - ListenSourceDefaultSource = 0, - /// The listener retrieves data and listens to updates from the local Firestore cache only. - /// If the cache is empty, an empty snapshot will be returned. - /// Snapshot events will be triggered on cache updates, like local mutations or load bundles. - ListenSourceCache = 1, -}; - -/// Wrapper for ListenSource to allow for nullability. -@interface ListenSourceBox : NSObject -@property(nonatomic, assign) ListenSource value; -- (instancetype)initWithValue:(ListenSource)value; -@end - -typedef NS_ENUM(NSUInteger, ServerTimestampBehavior) { - /// Return null for [FieldValue.serverTimestamp()] values that have not yet - ServerTimestampBehaviorNone = 0, - /// Return local estimates for [FieldValue.serverTimestamp()] values that have not yet been set to - /// their final value. - ServerTimestampBehaviorEstimate = 1, - /// Return the previous value for [FieldValue.serverTimestamp()] values that have not yet been set - /// to their final value. - ServerTimestampBehaviorPrevious = 2, -}; - -/// Wrapper for ServerTimestampBehavior to allow for nullability. -@interface ServerTimestampBehaviorBox : NSObject -@property(nonatomic, assign) ServerTimestampBehavior value; -- (instancetype)initWithValue:(ServerTimestampBehavior)value; -@end - -/// [AggregateSource] represents the source of data for an [AggregateQuery]. -typedef NS_ENUM(NSUInteger, AggregateSource) { - /// Indicates that the data should be retrieved from the server. - AggregateSourceServer = 0, -}; - -/// Wrapper for AggregateSource to allow for nullability. -@interface AggregateSourceBox : NSObject -@property(nonatomic, assign) AggregateSource value; -- (instancetype)initWithValue:(AggregateSource)value; -@end - -/// [PersistenceCacheIndexManagerRequest] represents the request types for the persistence cache -/// index manager. -typedef NS_ENUM(NSUInteger, PersistenceCacheIndexManagerRequest) { - PersistenceCacheIndexManagerRequestEnableIndexAutoCreation = 0, - PersistenceCacheIndexManagerRequestDisableIndexAutoCreation = 1, - PersistenceCacheIndexManagerRequestDeleteAllIndexes = 2, -}; - -/// Wrapper for PersistenceCacheIndexManagerRequest to allow for nullability. -@interface PersistenceCacheIndexManagerRequestBox : NSObject -@property(nonatomic, assign) PersistenceCacheIndexManagerRequest value; -- (instancetype)initWithValue:(PersistenceCacheIndexManagerRequest)value; -@end - -typedef NS_ENUM(NSUInteger, InternalTransactionResult) { - InternalTransactionResultSuccess = 0, - InternalTransactionResultFailure = 1, -}; - -/// Wrapper for InternalTransactionResult to allow for nullability. -@interface InternalTransactionResultBox : NSObject -@property(nonatomic, assign) InternalTransactionResult value; -- (instancetype)initWithValue:(InternalTransactionResult)value; -@end - -typedef NS_ENUM(NSUInteger, InternalTransactionType) { - InternalTransactionTypeGet = 0, - InternalTransactionTypeUpdate = 1, - InternalTransactionTypeSet = 2, - InternalTransactionTypeDeleteType = 3, -}; - -/// Wrapper for InternalTransactionType to allow for nullability. -@interface InternalTransactionTypeBox : NSObject -@property(nonatomic, assign) InternalTransactionType value; -- (instancetype)initWithValue:(InternalTransactionType)value; -@end - -typedef NS_ENUM(NSUInteger, AggregateType) { - AggregateTypeCount = 0, - AggregateTypeSum = 1, - AggregateTypeAverage = 2, -}; - -/// Wrapper for AggregateType to allow for nullability. -@interface AggregateTypeBox : NSObject -@property(nonatomic, assign) AggregateType value; -- (instancetype)initWithValue:(AggregateType)value; -@end - -@class InternalFirebaseSettings; -@class FirestorePigeonFirebaseApp; -@class InternalSnapshotMetadata; -@class InternalDocumentSnapshot; -@class InternalDocumentChange; -@class InternalQuerySnapshot; -@class InternalPipelineResult; -@class InternalPipelineSnapshot; -@class InternalGetOptions; -@class InternalDocumentOption; -@class InternalTransactionCommand; -@class DocumentReferenceRequest; -@class InternalQueryParameters; -@class AggregateQuery; -@class AggregateQueryResponse; - -@interface InternalFirebaseSettings : NSObject -/// `init` unavailable to enforce nonnull fields, see the `make` class method. -- (instancetype)init NS_UNAVAILABLE; -+ (instancetype)makeWithPersistenceEnabled:(nullable NSNumber *)persistenceEnabled - host:(nullable NSString *)host - sslEnabled:(nullable NSNumber *)sslEnabled - cacheSizeBytes:(nullable NSNumber *)cacheSizeBytes - ignoreUndefinedProperties:(BOOL)ignoreUndefinedProperties; -@property(nonatomic, strong, nullable) NSNumber *persistenceEnabled; -@property(nonatomic, copy, nullable) NSString *host; -@property(nonatomic, strong, nullable) NSNumber *sslEnabled; -@property(nonatomic, strong, nullable) NSNumber *cacheSizeBytes; -@property(nonatomic, assign) BOOL ignoreUndefinedProperties; -@end - -@interface FirestorePigeonFirebaseApp : NSObject -/// `init` unavailable to enforce nonnull fields, see the `make` class method. -- (instancetype)init NS_UNAVAILABLE; -+ (instancetype)makeWithAppName:(NSString *)appName - settings:(InternalFirebaseSettings *)settings - databaseURL:(NSString *)databaseURL; -@property(nonatomic, copy) NSString *appName; -@property(nonatomic, strong) InternalFirebaseSettings *settings; -@property(nonatomic, copy) NSString *databaseURL; -@end - -@interface InternalSnapshotMetadata : NSObject -/// `init` unavailable to enforce nonnull fields, see the `make` class method. -- (instancetype)init NS_UNAVAILABLE; -+ (instancetype)makeWithHasPendingWrites:(BOOL)hasPendingWrites isFromCache:(BOOL)isFromCache; -@property(nonatomic, assign) BOOL hasPendingWrites; -@property(nonatomic, assign) BOOL isFromCache; -@end - -@interface InternalDocumentSnapshot : NSObject -/// `init` unavailable to enforce nonnull fields, see the `make` class method. -- (instancetype)init NS_UNAVAILABLE; -+ (instancetype)makeWithPath:(NSString *)path - data:(nullable NSDictionary *)data - metadata:(InternalSnapshotMetadata *)metadata; -@property(nonatomic, copy) NSString *path; -@property(nonatomic, copy, nullable) NSDictionary *data; -@property(nonatomic, strong) InternalSnapshotMetadata *metadata; -@end - -@interface InternalDocumentChange : NSObject -/// `init` unavailable to enforce nonnull fields, see the `make` class method. -- (instancetype)init NS_UNAVAILABLE; -+ (instancetype)makeWithType:(DocumentChangeType)type - document:(InternalDocumentSnapshot *)document - oldIndex:(NSInteger)oldIndex - newIndex:(NSInteger)newIndex; -@property(nonatomic, assign) DocumentChangeType type; -@property(nonatomic, strong) InternalDocumentSnapshot *document; -@property(nonatomic, assign) NSInteger oldIndex; -@property(nonatomic, assign) NSInteger newIndex; -@end - -@interface InternalQuerySnapshot : NSObject -/// `init` unavailable to enforce nonnull fields, see the `make` class method. -- (instancetype)init NS_UNAVAILABLE; -+ (instancetype)makeWithDocuments:(NSArray *)documents - documentChanges:(NSArray *)documentChanges - metadata:(InternalSnapshotMetadata *)metadata; -@property(nonatomic, copy) NSArray *documents; -@property(nonatomic, copy) NSArray *documentChanges; -@property(nonatomic, strong) InternalSnapshotMetadata *metadata; -@end - -@interface InternalPipelineResult : NSObject -+ (instancetype)makeWithDocumentPath:(nullable NSString *)documentPath - createTime:(nullable NSNumber *)createTime - updateTime:(nullable NSNumber *)updateTime - data:(nullable NSDictionary *)data; -@property(nonatomic, copy, nullable) NSString *documentPath; -@property(nonatomic, strong, nullable) NSNumber *createTime; -@property(nonatomic, strong, nullable) NSNumber *updateTime; -/// All fields in the result (from PipelineResult.data() on Android). -@property(nonatomic, copy, nullable) NSDictionary *data; -@end - -@interface InternalPipelineSnapshot : NSObject -/// `init` unavailable to enforce nonnull fields, see the `make` class method. -- (instancetype)init NS_UNAVAILABLE; -+ (instancetype)makeWithResults:(NSArray *)results - executionTime:(NSInteger)executionTime; -@property(nonatomic, copy) NSArray *results; -@property(nonatomic, assign) NSInteger executionTime; -@end - -@interface InternalGetOptions : NSObject -/// `init` unavailable to enforce nonnull fields, see the `make` class method. -- (instancetype)init NS_UNAVAILABLE; -+ (instancetype)makeWithSource:(Source)source - serverTimestampBehavior:(ServerTimestampBehavior)serverTimestampBehavior; -@property(nonatomic, assign) Source source; -@property(nonatomic, assign) ServerTimestampBehavior serverTimestampBehavior; -@end - -@interface InternalDocumentOption : NSObject -+ (instancetype)makeWithMerge:(nullable NSNumber *)merge - mergeFields:(nullable NSArray *> *)mergeFields; -@property(nonatomic, strong, nullable) NSNumber *merge; -@property(nonatomic, copy, nullable) NSArray *> *mergeFields; -@end - -@interface InternalTransactionCommand : NSObject -/// `init` unavailable to enforce nonnull fields, see the `make` class method. -- (instancetype)init NS_UNAVAILABLE; -+ (instancetype)makeWithType:(InternalTransactionType)type - path:(NSString *)path - data:(nullable NSDictionary *)data - option:(nullable InternalDocumentOption *)option; -@property(nonatomic, assign) InternalTransactionType type; -@property(nonatomic, copy) NSString *path; -@property(nonatomic, copy, nullable) NSDictionary *data; -@property(nonatomic, strong, nullable) InternalDocumentOption *option; -@end - -@interface DocumentReferenceRequest : NSObject -/// `init` unavailable to enforce nonnull fields, see the `make` class method. -- (instancetype)init NS_UNAVAILABLE; -+ (instancetype)makeWithPath:(NSString *)path - data:(nullable NSDictionary *)data - option:(nullable InternalDocumentOption *)option - source:(nullable SourceBox *)source - serverTimestampBehavior:(nullable ServerTimestampBehaviorBox *)serverTimestampBehavior; -@property(nonatomic, copy) NSString *path; -@property(nonatomic, copy, nullable) NSDictionary *data; -@property(nonatomic, strong, nullable) InternalDocumentOption *option; -@property(nonatomic, strong, nullable) SourceBox *source; -@property(nonatomic, strong, nullable) ServerTimestampBehaviorBox *serverTimestampBehavior; -@end - -@interface InternalQueryParameters : NSObject -+ (instancetype)makeWithWhere:(nullable NSArray *> *)where - orderBy:(nullable NSArray *> *)orderBy - limit:(nullable NSNumber *)limit - limitToLast:(nullable NSNumber *)limitToLast - startAt:(nullable NSArray *)startAt - startAfter:(nullable NSArray *)startAfter - endAt:(nullable NSArray *)endAt - endBefore:(nullable NSArray *)endBefore - filters:(nullable NSDictionary *)filters; -@property(nonatomic, copy, nullable) NSArray *> *where; -@property(nonatomic, copy, nullable) NSArray *> *orderBy; -@property(nonatomic, strong, nullable) NSNumber *limit; -@property(nonatomic, strong, nullable) NSNumber *limitToLast; -@property(nonatomic, copy, nullable) NSArray *startAt; -@property(nonatomic, copy, nullable) NSArray *startAfter; -@property(nonatomic, copy, nullable) NSArray *endAt; -@property(nonatomic, copy, nullable) NSArray *endBefore; -@property(nonatomic, copy, nullable) NSDictionary *filters; -@end - -@interface AggregateQuery : NSObject -/// `init` unavailable to enforce nonnull fields, see the `make` class method. -- (instancetype)init NS_UNAVAILABLE; -+ (instancetype)makeWithType:(AggregateType)type field:(nullable NSString *)field; -@property(nonatomic, assign) AggregateType type; -@property(nonatomic, copy, nullable) NSString *field; -@end - -@interface AggregateQueryResponse : NSObject -/// `init` unavailable to enforce nonnull fields, see the `make` class method. -- (instancetype)init NS_UNAVAILABLE; -+ (instancetype)makeWithType:(AggregateType)type - field:(nullable NSString *)field - value:(nullable NSNumber *)value; -@property(nonatomic, assign) AggregateType type; -@property(nonatomic, copy, nullable) NSString *field; -@property(nonatomic, strong, nullable) NSNumber *value; -@end - -/// The codec used by all APIs. -NSObject *GetFirebaseFirestoreHostApiCodec(void); - -@protocol FirebaseFirestoreHostApi -- (void)loadBundleApp:(FirestorePigeonFirebaseApp *)app - bundle:(FlutterStandardTypedData *)bundle - completion:(void (^)(NSString *_Nullable, FlutterError *_Nullable))completion; -- (void)namedQueryGetApp:(FirestorePigeonFirebaseApp *)app - name:(NSString *)name - options:(InternalGetOptions *)options - completion: - (void (^)(InternalQuerySnapshot *_Nullable, FlutterError *_Nullable))completion; -- (void)clearPersistenceApp:(FirestorePigeonFirebaseApp *)app - completion:(void (^)(FlutterError *_Nullable))completion; -- (void)disableNetworkApp:(FirestorePigeonFirebaseApp *)app - completion:(void (^)(FlutterError *_Nullable))completion; -- (void)enableNetworkApp:(FirestorePigeonFirebaseApp *)app - completion:(void (^)(FlutterError *_Nullable))completion; -- (void)terminateApp:(FirestorePigeonFirebaseApp *)app - completion:(void (^)(FlutterError *_Nullable))completion; -- (void)waitForPendingWritesApp:(FirestorePigeonFirebaseApp *)app - completion:(void (^)(FlutterError *_Nullable))completion; -- (void)setIndexConfigurationApp:(FirestorePigeonFirebaseApp *)app - indexConfiguration:(NSString *)indexConfiguration - completion:(void (^)(FlutterError *_Nullable))completion; -- (void)setLoggingEnabledLoggingEnabled:(BOOL)loggingEnabled - completion:(void (^)(FlutterError *_Nullable))completion; -- (void)snapshotsInSyncSetupApp:(FirestorePigeonFirebaseApp *)app - completion:(void (^)(NSString *_Nullable, FlutterError *_Nullable))completion; -- (void)transactionCreateApp:(FirestorePigeonFirebaseApp *)app - timeout:(NSInteger)timeout - maxAttempts:(NSInteger)maxAttempts - completion:(void (^)(NSString *_Nullable, FlutterError *_Nullable))completion; -- (void)transactionStoreResultTransactionId:(NSString *)transactionId - resultType:(InternalTransactionResult)resultType - commands: - (nullable NSArray *)commands - completion:(void (^)(FlutterError *_Nullable))completion; -- (void)transactionGetApp:(FirestorePigeonFirebaseApp *)app - transactionId:(NSString *)transactionId - path:(NSString *)path - completion:(void (^)(InternalDocumentSnapshot *_Nullable, - FlutterError *_Nullable))completion; -- (void)documentReferenceSetApp:(FirestorePigeonFirebaseApp *)app - request:(DocumentReferenceRequest *)request - completion:(void (^)(FlutterError *_Nullable))completion; -- (void)documentReferenceUpdateApp:(FirestorePigeonFirebaseApp *)app - request:(DocumentReferenceRequest *)request - completion:(void (^)(FlutterError *_Nullable))completion; -- (void)documentReferenceGetApp:(FirestorePigeonFirebaseApp *)app - request:(DocumentReferenceRequest *)request - completion:(void (^)(InternalDocumentSnapshot *_Nullable, - FlutterError *_Nullable))completion; -- (void)documentReferenceDeleteApp:(FirestorePigeonFirebaseApp *)app - request:(DocumentReferenceRequest *)request - completion:(void (^)(FlutterError *_Nullable))completion; -- (void)queryGetApp:(FirestorePigeonFirebaseApp *)app - path:(NSString *)path - isCollectionGroup:(BOOL)isCollectionGroup - parameters:(InternalQueryParameters *)parameters - options:(InternalGetOptions *)options - completion: - (void (^)(InternalQuerySnapshot *_Nullable, FlutterError *_Nullable))completion; -- (void)aggregateQueryApp:(FirestorePigeonFirebaseApp *)app - path:(NSString *)path - parameters:(InternalQueryParameters *)parameters - source:(AggregateSource)source - queries:(NSArray *)queries - isCollectionGroup:(BOOL)isCollectionGroup - completion:(void (^)(NSArray *_Nullable, - FlutterError *_Nullable))completion; -- (void)writeBatchCommitApp:(FirestorePigeonFirebaseApp *)app - writes:(NSArray *)writes - completion:(void (^)(FlutterError *_Nullable))completion; -- (void)querySnapshotApp:(FirestorePigeonFirebaseApp *)app - path:(NSString *)path - isCollectionGroup:(BOOL)isCollectionGroup - parameters:(InternalQueryParameters *)parameters - options:(InternalGetOptions *)options - includeMetadataChanges:(BOOL)includeMetadataChanges - source:(ListenSource)source - completion:(void (^)(NSString *_Nullable, FlutterError *_Nullable))completion; -- (void)documentReferenceSnapshotApp:(FirestorePigeonFirebaseApp *)app - parameters:(DocumentReferenceRequest *)parameters - includeMetadataChanges:(BOOL)includeMetadataChanges - source:(ListenSource)source - completion: - (void (^)(NSString *_Nullable, FlutterError *_Nullable))completion; -- (void)persistenceCacheIndexManagerRequestApp:(FirestorePigeonFirebaseApp *)app - request:(PersistenceCacheIndexManagerRequest)request - completion:(void (^)(FlutterError *_Nullable))completion; -- (void)executePipelineApp:(FirestorePigeonFirebaseApp *)app - stages:(NSArray *> *)stages - options:(nullable NSDictionary *)options - completion:(void (^)(InternalPipelineSnapshot *_Nullable, - FlutterError *_Nullable))completion; -@end - -extern void SetUpFirebaseFirestoreHostApi(id binaryMessenger, - NSObject *_Nullable api); - -extern void SetUpFirebaseFirestoreHostApiWithSuffix( - id binaryMessenger, NSObject *_Nullable api, - NSString *messageChannelSuffix); - -NS_ASSUME_NONNULL_END diff --git a/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/FLTFirestoreClientLanguage.mm b/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore_objc/FLTFirestoreClientLanguage.mm similarity index 87% rename from packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/FLTFirestoreClientLanguage.mm rename to packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore_objc/FLTFirestoreClientLanguage.mm index 399944ededf8..1780724473f7 100644 --- a/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/FLTFirestoreClientLanguage.mm +++ b/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore_objc/FLTFirestoreClientLanguage.mm @@ -18,9 +18,7 @@ } // namespace firestore } // namespace firebase -@interface FLTFirestoreClientLanguage : NSObject -+ (void)setClientLanguage:(NSString *)language; -@end +#import "FLTFirestoreClientLanguage.h" @implementation FLTFirestoreClientLanguage + (void)setClientLanguage:(NSString *)language { diff --git a/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore_objc/include/FLTFirestoreClientLanguage.h b/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore_objc/include/FLTFirestoreClientLanguage.h new file mode 100644 index 000000000000..818da8efbfd0 --- /dev/null +++ b/packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore_objc/include/FLTFirestoreClientLanguage.h @@ -0,0 +1,13 @@ +// Copyright 2025 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface FLTFirestoreClientLanguage : NSObject ++ (void)setClientLanguage:(NSString *)language; +@end + +NS_ASSUME_NONNULL_END diff --git a/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore.podspec b/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore.podspec index 44815fe6d85a..54e4676ac255 100755 --- a/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore.podspec +++ b/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore.podspec @@ -43,9 +43,10 @@ Pod::Spec.new do |s| s.authors = 'The Chromium Authors' s.source = { :path => '.' } - s.source_files = 'cloud_firestore/Sources/cloud_firestore/**/*.{h,m}' - s.public_header_files = 'cloud_firestore/Sources/cloud_firestore/include/Public/**/*.h' - s.private_header_files = 'cloud_firestore/Sources/cloud_firestore/include/Private/**/*.h' + s.source_files = 'cloud_firestore/Sources/**/*.{swift,h,m,mm}' + s.public_header_files = 'cloud_firestore/Sources/cloud_firestore_objc/include/*.h' + + s.swift_version = '5.0' s.platform = :osx, '10.13' @@ -59,7 +60,6 @@ Pod::Spec.new do |s| s.static_framework = true s.pod_target_xcconfig = { - 'GCC_PREPROCESSOR_DEFINITIONS' => "LIBRARY_VERSION=\\\"#{library_version}\\\" LIBRARY_NAME=\\\"flutter-fire-fst\\\"", 'DEFINES_MODULE' => 'YES' } end diff --git a/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Package.swift b/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Package.swift index 899f7bb2eb7f..759bf200bf0e 100644 --- a/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Package.swift +++ b/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Package.swift @@ -24,22 +24,30 @@ let package = Package( .package(name: "FlutterFramework", path: "../FlutterFramework"), ], targets: [ + // SPM does not allow mixing Swift and ObjC in a single target. + .target( + name: "cloud_firestore_objc", + dependencies: [ + .product(name: "FirebaseFirestore", package: "firebase-ios-sdk") + ], + path: "Sources/cloud_firestore_objc", + publicHeadersPath: "include", + cSettings: [ + .headerSearchPath("include") + ] + ), .target( name: "cloud_firestore", dependencies: [ + "cloud_firestore_objc", .product(name: "FirebaseFirestore", package: "firebase-ios-sdk"), .product(name: "firebase-core", package: "firebase_core"), .product(name: "FlutterFramework", package: "FlutterFramework"), ], + path: "Sources/cloud_firestore", resources: [ .process("Resources") - ], - cSettings: [ - .headerSearchPath("include/cloud_firestore/Private"), - .headerSearchPath("include/cloud_firestore/Public"), - .define("LIBRARY_VERSION", to: "\"\(libraryVersion)\""), - .define("LIBRARY_NAME", to: "\"flutter-fire-fst\""), ] - ) + ), ] ) diff --git a/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/Constants.swift b/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/Constants.swift new file mode 120000 index 000000000000..0dd2a14ae8c5 --- /dev/null +++ b/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/Constants.swift @@ -0,0 +1 @@ +../../../../ios/cloud_firestore/Sources/cloud_firestore/Constants.swift \ No newline at end of file diff --git a/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/DocumentSnapshotStreamHandler.swift b/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/DocumentSnapshotStreamHandler.swift new file mode 120000 index 000000000000..a41ddb12f40b --- /dev/null +++ b/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/DocumentSnapshotStreamHandler.swift @@ -0,0 +1 @@ +../../../../ios/cloud_firestore/Sources/cloud_firestore/DocumentSnapshotStreamHandler.swift \ No newline at end of file diff --git a/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/FLTDocumentSnapshotStreamHandler.m b/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/FLTDocumentSnapshotStreamHandler.m deleted file mode 120000 index aeb6ebc5c006..000000000000 --- a/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/FLTDocumentSnapshotStreamHandler.m +++ /dev/null @@ -1 +0,0 @@ -../../../../ios/cloud_firestore/Sources/cloud_firestore/FLTDocumentSnapshotStreamHandler.m \ No newline at end of file diff --git a/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/FLTFirebaseFirestoreExtension.m b/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/FLTFirebaseFirestoreExtension.m deleted file mode 120000 index bd4cf1dd5fde..000000000000 --- a/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/FLTFirebaseFirestoreExtension.m +++ /dev/null @@ -1 +0,0 @@ -../../../../ios/cloud_firestore/Sources/cloud_firestore/FLTFirebaseFirestoreExtension.m \ No newline at end of file diff --git a/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/FLTFirebaseFirestorePlugin.m b/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/FLTFirebaseFirestorePlugin.m deleted file mode 120000 index f791caf0cc3c..000000000000 --- a/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/FLTFirebaseFirestorePlugin.m +++ /dev/null @@ -1 +0,0 @@ -../../../../ios/cloud_firestore/Sources/cloud_firestore/FLTFirebaseFirestorePlugin.m \ No newline at end of file diff --git a/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/FLTFirebaseFirestorePlugin.swift b/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/FLTFirebaseFirestorePlugin.swift new file mode 120000 index 000000000000..40a74af9337c --- /dev/null +++ b/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/FLTFirebaseFirestorePlugin.swift @@ -0,0 +1 @@ +../../../../ios/cloud_firestore/Sources/cloud_firestore/FLTFirebaseFirestorePlugin.swift \ No newline at end of file diff --git a/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/FLTFirebaseFirestoreReader.m b/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/FLTFirebaseFirestoreReader.m deleted file mode 120000 index e89ebb8929cc..000000000000 --- a/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/FLTFirebaseFirestoreReader.m +++ /dev/null @@ -1 +0,0 @@ -../../../../ios/cloud_firestore/Sources/cloud_firestore/FLTFirebaseFirestoreReader.m \ No newline at end of file diff --git a/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/FLTFirebaseFirestoreUtils.m b/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/FLTFirebaseFirestoreUtils.m deleted file mode 120000 index babea1c24081..000000000000 --- a/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/FLTFirebaseFirestoreUtils.m +++ /dev/null @@ -1 +0,0 @@ -../../../../ios/cloud_firestore/Sources/cloud_firestore/FLTFirebaseFirestoreUtils.m \ No newline at end of file diff --git a/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/FLTFirebaseFirestoreWriter.m b/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/FLTFirebaseFirestoreWriter.m deleted file mode 120000 index e4b626a19876..000000000000 --- a/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/FLTFirebaseFirestoreWriter.m +++ /dev/null @@ -1 +0,0 @@ -../../../../ios/cloud_firestore/Sources/cloud_firestore/FLTFirebaseFirestoreWriter.m \ No newline at end of file diff --git a/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/FLTLoadBundleStreamHandler.m b/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/FLTLoadBundleStreamHandler.m deleted file mode 120000 index b4114c3d04d5..000000000000 --- a/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/FLTLoadBundleStreamHandler.m +++ /dev/null @@ -1 +0,0 @@ -../../../../ios/cloud_firestore/Sources/cloud_firestore/FLTLoadBundleStreamHandler.m \ No newline at end of file diff --git a/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/FLTPipelineParser.m b/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/FLTPipelineParser.m deleted file mode 120000 index 0ab2d722c4a0..000000000000 --- a/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/FLTPipelineParser.m +++ /dev/null @@ -1 +0,0 @@ -../../../../ios/cloud_firestore/Sources/cloud_firestore/FLTPipelineParser.m \ No newline at end of file diff --git a/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/FLTQuerySnapshotStreamHandler.m b/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/FLTQuerySnapshotStreamHandler.m deleted file mode 120000 index 1f1bbb9f3bef..000000000000 --- a/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/FLTQuerySnapshotStreamHandler.m +++ /dev/null @@ -1 +0,0 @@ -../../../../ios/cloud_firestore/Sources/cloud_firestore/FLTQuerySnapshotStreamHandler.m \ No newline at end of file diff --git a/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/FLTSnapshotsInSyncStreamHandler.m b/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/FLTSnapshotsInSyncStreamHandler.m deleted file mode 120000 index 7e50903ad6be..000000000000 --- a/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/FLTSnapshotsInSyncStreamHandler.m +++ /dev/null @@ -1 +0,0 @@ -../../../../ios/cloud_firestore/Sources/cloud_firestore/FLTSnapshotsInSyncStreamHandler.m \ No newline at end of file diff --git a/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/FLTTransactionStreamHandler.m b/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/FLTTransactionStreamHandler.m deleted file mode 120000 index 66555a825643..000000000000 --- a/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/FLTTransactionStreamHandler.m +++ /dev/null @@ -1 +0,0 @@ -../../../../ios/cloud_firestore/Sources/cloud_firestore/FLTTransactionStreamHandler.m \ No newline at end of file diff --git a/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/FirebaseFirestoreExtension.swift b/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/FirebaseFirestoreExtension.swift new file mode 120000 index 000000000000..0416128c51e4 --- /dev/null +++ b/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/FirebaseFirestoreExtension.swift @@ -0,0 +1 @@ +../../../../ios/cloud_firestore/Sources/cloud_firestore/FirebaseFirestoreExtension.swift \ No newline at end of file diff --git a/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/FirebaseFirestoreReader.swift b/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/FirebaseFirestoreReader.swift new file mode 120000 index 000000000000..3e7fa59845d2 --- /dev/null +++ b/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/FirebaseFirestoreReader.swift @@ -0,0 +1 @@ +../../../../ios/cloud_firestore/Sources/cloud_firestore/FirebaseFirestoreReader.swift \ No newline at end of file diff --git a/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/FirebaseFirestoreUtils.swift b/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/FirebaseFirestoreUtils.swift new file mode 120000 index 000000000000..40aee5d2ff3b --- /dev/null +++ b/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/FirebaseFirestoreUtils.swift @@ -0,0 +1 @@ +../../../../ios/cloud_firestore/Sources/cloud_firestore/FirebaseFirestoreUtils.swift \ No newline at end of file diff --git a/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/FirebaseFirestoreWriter.swift b/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/FirebaseFirestoreWriter.swift new file mode 120000 index 000000000000..9c35a48e9cc1 --- /dev/null +++ b/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/FirebaseFirestoreWriter.swift @@ -0,0 +1 @@ +../../../../ios/cloud_firestore/Sources/cloud_firestore/FirebaseFirestoreWriter.swift \ No newline at end of file diff --git a/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/FirestoreMessages.g.m b/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/FirestoreMessages.g.m deleted file mode 120000 index 83b8548becc8..000000000000 --- a/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/FirestoreMessages.g.m +++ /dev/null @@ -1 +0,0 @@ -../../../../ios/cloud_firestore/Sources/cloud_firestore/FirestoreMessages.g.m \ No newline at end of file diff --git a/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/FirestoreMessages.g.swift b/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/FirestoreMessages.g.swift new file mode 120000 index 000000000000..020be4407a2d --- /dev/null +++ b/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/FirestoreMessages.g.swift @@ -0,0 +1 @@ +../../../../ios/cloud_firestore/Sources/cloud_firestore/FirestoreMessages.g.swift \ No newline at end of file diff --git a/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/FirestorePigeonParser.m b/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/FirestorePigeonParser.m deleted file mode 120000 index 32c6ef6bf146..000000000000 --- a/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/FirestorePigeonParser.m +++ /dev/null @@ -1 +0,0 @@ -../../../../ios/cloud_firestore/Sources/cloud_firestore/FirestorePigeonParser.m \ No newline at end of file diff --git a/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/LoadBundleStreamHandler.swift b/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/LoadBundleStreamHandler.swift new file mode 120000 index 000000000000..9a804a49e3d2 --- /dev/null +++ b/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/LoadBundleStreamHandler.swift @@ -0,0 +1 @@ +../../../../ios/cloud_firestore/Sources/cloud_firestore/LoadBundleStreamHandler.swift \ No newline at end of file diff --git a/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/PigeonParser.swift b/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/PigeonParser.swift new file mode 120000 index 000000000000..d8499f4160c6 --- /dev/null +++ b/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/PigeonParser.swift @@ -0,0 +1 @@ +../../../../ios/cloud_firestore/Sources/cloud_firestore/PigeonParser.swift \ No newline at end of file diff --git a/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/PipelineParser.swift b/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/PipelineParser.swift new file mode 120000 index 000000000000..503c300d6114 --- /dev/null +++ b/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/PipelineParser.swift @@ -0,0 +1 @@ +../../../../ios/cloud_firestore/Sources/cloud_firestore/PipelineParser.swift \ No newline at end of file diff --git a/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/QuerySnapshotStreamHandler.swift b/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/QuerySnapshotStreamHandler.swift new file mode 120000 index 000000000000..4eaa2e2e155c --- /dev/null +++ b/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/QuerySnapshotStreamHandler.swift @@ -0,0 +1 @@ +../../../../ios/cloud_firestore/Sources/cloud_firestore/QuerySnapshotStreamHandler.swift \ No newline at end of file diff --git a/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/Resources/.gitkeep b/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/Resources/.gitkeep deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/Resources/.gitkeep b/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/Resources/.gitkeep new file mode 120000 index 000000000000..877cc63276af --- /dev/null +++ b/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/Resources/.gitkeep @@ -0,0 +1 @@ +../../../../../../ios/cloud_firestore/Sources/cloud_firestore/Resources/.gitkeep \ No newline at end of file diff --git a/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/SnapshotsInSyncStreamHandler.swift b/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/SnapshotsInSyncStreamHandler.swift new file mode 120000 index 000000000000..7108d5049e86 --- /dev/null +++ b/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/SnapshotsInSyncStreamHandler.swift @@ -0,0 +1 @@ +../../../../ios/cloud_firestore/Sources/cloud_firestore/SnapshotsInSyncStreamHandler.swift \ No newline at end of file diff --git a/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/TransactionStreamHandler.swift b/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/TransactionStreamHandler.swift new file mode 120000 index 000000000000..c531ab274b29 --- /dev/null +++ b/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/TransactionStreamHandler.swift @@ -0,0 +1 @@ +../../../../ios/cloud_firestore/Sources/cloud_firestore/TransactionStreamHandler.swift \ No newline at end of file diff --git a/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/include/cloud_firestore/Private/FLTDocumentSnapshotStreamHandler.h b/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/include/cloud_firestore/Private/FLTDocumentSnapshotStreamHandler.h deleted file mode 120000 index 61d4d26dcb13..000000000000 --- a/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/include/cloud_firestore/Private/FLTDocumentSnapshotStreamHandler.h +++ /dev/null @@ -1 +0,0 @@ -../../../../../../../ios/cloud_firestore/Sources/cloud_firestore/include/cloud_firestore/Private/FLTDocumentSnapshotStreamHandler.h \ No newline at end of file diff --git a/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/include/cloud_firestore/Private/FLTFirebaseFirestoreExtension.h b/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/include/cloud_firestore/Private/FLTFirebaseFirestoreExtension.h deleted file mode 120000 index 878691155dfe..000000000000 --- a/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/include/cloud_firestore/Private/FLTFirebaseFirestoreExtension.h +++ /dev/null @@ -1 +0,0 @@ -../../../../../../../ios/cloud_firestore/Sources/cloud_firestore/include/cloud_firestore/Private/FLTFirebaseFirestoreExtension.h \ No newline at end of file diff --git a/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/include/cloud_firestore/Private/FLTFirebaseFirestoreReader.h b/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/include/cloud_firestore/Private/FLTFirebaseFirestoreReader.h deleted file mode 120000 index 408a177ffc29..000000000000 --- a/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/include/cloud_firestore/Private/FLTFirebaseFirestoreReader.h +++ /dev/null @@ -1 +0,0 @@ -../../../../../../../ios/cloud_firestore/Sources/cloud_firestore/include/cloud_firestore/Private/FLTFirebaseFirestoreReader.h \ No newline at end of file diff --git a/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/include/cloud_firestore/Private/FLTFirebaseFirestoreUtils.h b/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/include/cloud_firestore/Private/FLTFirebaseFirestoreUtils.h deleted file mode 120000 index f09ad17e8322..000000000000 --- a/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/include/cloud_firestore/Private/FLTFirebaseFirestoreUtils.h +++ /dev/null @@ -1 +0,0 @@ -../../../../../../../ios/cloud_firestore/Sources/cloud_firestore/include/cloud_firestore/Private/FLTFirebaseFirestoreUtils.h \ No newline at end of file diff --git a/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/include/cloud_firestore/Private/FLTFirebaseFirestoreWriter.h b/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/include/cloud_firestore/Private/FLTFirebaseFirestoreWriter.h deleted file mode 120000 index 4c7ea1f49445..000000000000 --- a/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/include/cloud_firestore/Private/FLTFirebaseFirestoreWriter.h +++ /dev/null @@ -1 +0,0 @@ -../../../../../../../ios/cloud_firestore/Sources/cloud_firestore/include/cloud_firestore/Private/FLTFirebaseFirestoreWriter.h \ No newline at end of file diff --git a/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/include/cloud_firestore/Private/FLTLoadBundleStreamHandler.h b/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/include/cloud_firestore/Private/FLTLoadBundleStreamHandler.h deleted file mode 120000 index be3fee9e19a9..000000000000 --- a/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/include/cloud_firestore/Private/FLTLoadBundleStreamHandler.h +++ /dev/null @@ -1 +0,0 @@ -../../../../../../../ios/cloud_firestore/Sources/cloud_firestore/include/cloud_firestore/Private/FLTLoadBundleStreamHandler.h \ No newline at end of file diff --git a/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/include/cloud_firestore/Private/FLTPipelineParser.h b/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/include/cloud_firestore/Private/FLTPipelineParser.h deleted file mode 120000 index fb086ff6b78c..000000000000 --- a/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/include/cloud_firestore/Private/FLTPipelineParser.h +++ /dev/null @@ -1 +0,0 @@ -../../../../../../../ios/cloud_firestore/Sources/cloud_firestore/include/cloud_firestore/Private/FLTPipelineParser.h \ No newline at end of file diff --git a/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/include/cloud_firestore/Private/FLTQuerySnapshotStreamHandler.h b/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/include/cloud_firestore/Private/FLTQuerySnapshotStreamHandler.h deleted file mode 120000 index 31805df68cc2..000000000000 --- a/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/include/cloud_firestore/Private/FLTQuerySnapshotStreamHandler.h +++ /dev/null @@ -1 +0,0 @@ -../../../../../../../ios/cloud_firestore/Sources/cloud_firestore/include/cloud_firestore/Private/FLTQuerySnapshotStreamHandler.h \ No newline at end of file diff --git a/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/include/cloud_firestore/Private/FLTSnapshotsInSyncStreamHandler.h b/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/include/cloud_firestore/Private/FLTSnapshotsInSyncStreamHandler.h deleted file mode 120000 index a144ccda21cf..000000000000 --- a/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/include/cloud_firestore/Private/FLTSnapshotsInSyncStreamHandler.h +++ /dev/null @@ -1 +0,0 @@ -../../../../../../../ios/cloud_firestore/Sources/cloud_firestore/include/cloud_firestore/Private/FLTSnapshotsInSyncStreamHandler.h \ No newline at end of file diff --git a/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/include/cloud_firestore/Private/FLTTransactionStreamHandler.h b/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/include/cloud_firestore/Private/FLTTransactionStreamHandler.h deleted file mode 120000 index 25a76252d90e..000000000000 --- a/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/include/cloud_firestore/Private/FLTTransactionStreamHandler.h +++ /dev/null @@ -1 +0,0 @@ -../../../../../../../ios/cloud_firestore/Sources/cloud_firestore/include/cloud_firestore/Private/FLTTransactionStreamHandler.h \ No newline at end of file diff --git a/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/include/cloud_firestore/Private/FirestorePigeonParser.h b/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/include/cloud_firestore/Private/FirestorePigeonParser.h deleted file mode 120000 index 34aeced7af29..000000000000 --- a/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/include/cloud_firestore/Private/FirestorePigeonParser.h +++ /dev/null @@ -1 +0,0 @@ -../../../../../../../ios/cloud_firestore/Sources/cloud_firestore/include/cloud_firestore/Private/FirestorePigeonParser.h \ No newline at end of file diff --git a/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/include/cloud_firestore/Public/CustomPigeonHeaderFirestore.h b/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/include/cloud_firestore/Public/CustomPigeonHeaderFirestore.h deleted file mode 120000 index 111ed085e8b8..000000000000 --- a/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/include/cloud_firestore/Public/CustomPigeonHeaderFirestore.h +++ /dev/null @@ -1 +0,0 @@ -../../../../../../../ios/cloud_firestore/Sources/cloud_firestore/include/cloud_firestore/Public/CustomPigeonHeaderFirestore.h \ No newline at end of file diff --git a/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/include/cloud_firestore/Public/FLTFirebaseFirestorePlugin.h b/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/include/cloud_firestore/Public/FLTFirebaseFirestorePlugin.h deleted file mode 120000 index 9d774a9ce963..000000000000 --- a/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/include/cloud_firestore/Public/FLTFirebaseFirestorePlugin.h +++ /dev/null @@ -1 +0,0 @@ -../../../../../../../ios/cloud_firestore/Sources/cloud_firestore/include/cloud_firestore/Public/FLTFirebaseFirestorePlugin.h \ No newline at end of file diff --git a/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/include/cloud_firestore/Public/FirestoreMessages.g.h b/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/include/cloud_firestore/Public/FirestoreMessages.g.h deleted file mode 120000 index cfab6484dd12..000000000000 --- a/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore/include/cloud_firestore/Public/FirestoreMessages.g.h +++ /dev/null @@ -1 +0,0 @@ -../../../../../../../ios/cloud_firestore/Sources/cloud_firestore/include/cloud_firestore/Public/FirestoreMessages.g.h \ No newline at end of file diff --git a/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore_objc/FLTFirestoreClientLanguage.mm b/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore_objc/FLTFirestoreClientLanguage.mm new file mode 120000 index 000000000000..8c834e6bc84f --- /dev/null +++ b/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore_objc/FLTFirestoreClientLanguage.mm @@ -0,0 +1 @@ +../../../../ios/cloud_firestore/Sources/cloud_firestore_objc/FLTFirestoreClientLanguage.mm \ No newline at end of file diff --git a/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore_objc/include/FLTFirestoreClientLanguage.h b/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore_objc/include/FLTFirestoreClientLanguage.h new file mode 120000 index 000000000000..30882d4c3beb --- /dev/null +++ b/packages/cloud_firestore/cloud_firestore/macos/cloud_firestore/Sources/cloud_firestore_objc/include/FLTFirestoreClientLanguage.h @@ -0,0 +1 @@ +../../../../../ios/cloud_firestore/Sources/cloud_firestore_objc/include/FLTFirestoreClientLanguage.h \ No newline at end of file diff --git a/packages/cloud_firestore/cloud_firestore/windows/messages.g.h b/packages/cloud_firestore/cloud_firestore/windows/messages.g.h index fcc6a5e80a11..4a39a0af5b9c 100644 --- a/packages/cloud_firestore/cloud_firestore/windows/messages.g.h +++ b/packages/cloud_firestore/cloud_firestore/windows/messages.g.h @@ -194,13 +194,7 @@ class InternalFirebaseSettings { private: static InternalFirebaseSettings FromEncodableList( const ::flutter::EncodableList& list); - - public: - public: ::flutter::EncodableList ToEncodableList() const; - - private: - private: friend class FirestorePigeonFirebaseApp; friend class FirebaseFirestoreHostApi; friend class FirebaseFirestoreHostApiCodecSerializer; @@ -244,13 +238,7 @@ class FirestorePigeonFirebaseApp { private: static FirestorePigeonFirebaseApp FromEncodableList( const ::flutter::EncodableList& list); - - public: - public: ::flutter::EncodableList ToEncodableList() const; - - private: - private: friend class FirebaseFirestoreHostApi; friend class FirebaseFirestoreHostApiCodecSerializer; std::string app_name_; @@ -279,13 +267,8 @@ class InternalSnapshotMetadata { static InternalSnapshotMetadata FromEncodableList( const ::flutter::EncodableList& list); - - public: - public: ::flutter::EncodableList ToEncodableList() const; - private: - private: private: friend class InternalDocumentSnapshot; friend class InternalQuerySnapshot; @@ -331,13 +314,8 @@ class InternalDocumentSnapshot { static InternalDocumentSnapshot FromEncodableList( const ::flutter::EncodableList& list); - - public: - public: ::flutter::EncodableList ToEncodableList() const; - private: - private: private: friend class InternalDocumentChange; friend class FirebaseFirestoreHostApi; @@ -381,13 +359,8 @@ class InternalDocumentChange { static InternalDocumentChange FromEncodableList( const ::flutter::EncodableList& list); - - public: - public: ::flutter::EncodableList ToEncodableList() const; - private: - private: private: friend class FirebaseFirestoreHostApi; friend class FirebaseFirestoreHostApiCodecSerializer; @@ -430,13 +403,7 @@ class InternalQuerySnapshot { private: static InternalQuerySnapshot FromEncodableList( const ::flutter::EncodableList& list); - - public: - public: ::flutter::EncodableList ToEncodableList() const; - - private: - private: friend class FirebaseFirestoreHostApi; friend class FirebaseFirestoreHostApiCodecSerializer; ::flutter::EncodableList documents_; @@ -482,13 +449,7 @@ class InternalPipelineResult { private: static InternalPipelineResult FromEncodableList( const ::flutter::EncodableList& list); - - public: - public: ::flutter::EncodableList ToEncodableList() const; - - private: - private: friend class FirebaseFirestoreHostApi; friend class FirebaseFirestoreHostApiCodecSerializer; std::optional document_path_; @@ -519,13 +480,7 @@ class InternalPipelineSnapshot { private: static InternalPipelineSnapshot FromEncodableList( const ::flutter::EncodableList& list); - - public: - public: ::flutter::EncodableList ToEncodableList() const; - - private: - private: friend class FirebaseFirestoreHostApi; friend class FirebaseFirestoreHostApiCodecSerializer; ::flutter::EncodableList results_; @@ -555,13 +510,7 @@ class InternalGetOptions { private: static InternalGetOptions FromEncodableList( const ::flutter::EncodableList& list); - - public: - public: ::flutter::EncodableList ToEncodableList() const; - - private: - private: friend class FirebaseFirestoreHostApi; friend class FirebaseFirestoreHostApiCodecSerializer; Source source_; @@ -595,13 +544,7 @@ class InternalDocumentOption { private: static InternalDocumentOption FromEncodableList( const ::flutter::EncodableList& list); - - public: - public: ::flutter::EncodableList ToEncodableList() const; - - private: - private: friend class InternalTransactionCommand; friend class DocumentReferenceRequest; friend class FirebaseFirestoreHostApi; @@ -653,13 +596,7 @@ class InternalTransactionCommand { private: static InternalTransactionCommand FromEncodableList( const ::flutter::EncodableList& list); - - public: - public: ::flutter::EncodableList ToEncodableList() const; - - private: - private: friend class FirebaseFirestoreHostApi; friend class FirebaseFirestoreHostApiCodecSerializer; InternalTransactionType type_; @@ -714,13 +651,7 @@ class DocumentReferenceRequest { private: static DocumentReferenceRequest FromEncodableList( const ::flutter::EncodableList& list); - - public: - public: ::flutter::EncodableList ToEncodableList() const; - - private: - private: friend class FirebaseFirestoreHostApi; friend class FirebaseFirestoreHostApiCodecSerializer; std::string path_; @@ -792,13 +723,7 @@ class InternalQueryParameters { private: static InternalQueryParameters FromEncodableList( const ::flutter::EncodableList& list); - - public: - public: ::flutter::EncodableList ToEncodableList() const; - - private: - private: friend class FirebaseFirestoreHostApi; friend class FirebaseFirestoreHostApiCodecSerializer; std::optional<::flutter::EncodableList> where_; @@ -836,13 +761,7 @@ class AggregateQuery { private: static AggregateQuery FromEncodableList(const ::flutter::EncodableList& list); - - public: - public: ::flutter::EncodableList ToEncodableList() const; - - private: - private: friend class FirebaseFirestoreHostApi; friend class FirebaseFirestoreHostApiCodecSerializer; AggregateType type_; @@ -880,13 +799,7 @@ class AggregateQueryResponse { private: static AggregateQueryResponse FromEncodableList( const ::flutter::EncodableList& list); - - public: - public: ::flutter::EncodableList ToEncodableList() const; - - private: - private: friend class FirebaseFirestoreHostApi; friend class FirebaseFirestoreHostApiCodecSerializer; AggregateType type_; diff --git a/packages/cloud_firestore/cloud_firestore_platform_interface/pigeons/generate_pigeon.sh b/packages/cloud_firestore/cloud_firestore_platform_interface/pigeons/generate_pigeon.sh index 0bf9dabad9d7..dd60c61206b1 100755 --- a/packages/cloud_firestore/cloud_firestore_platform_interface/pigeons/generate_pigeon.sh +++ b/packages/cloud_firestore/cloud_firestore_platform_interface/pigeons/generate_pigeon.sh @@ -20,25 +20,20 @@ sed -i '' 's/private static class PigeonCodec extends StandardMessageCodec {/pub echo "Android modification complete." -# Fix iOS files -FILE_NAME="../../cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/FirestoreMessages.g.m" -sed -i '' '/#import "FirestoreMessages.g.h"/a\ -#import "FLTFirebaseFirestoreReader.h"\ -#import "FLTFirebaseFirestoreWriter.h" -' $FILE_NAME -# Pigeon 26 generates ObjC codec classes with a `nullPigeonCodec*` prefix when no -# ObjcOptions prefix is configured. Rename them to stable, readable names first. -sed -i '' 's/nullFirestoreMessagesPigeonCodecReaderWriter/FirebaseFirestoreHostApiCodecReaderWriter/g' $FILE_NAME -sed -i '' 's/nullFirestoreMessagesPigeonCodecReader/FirebaseFirestoreHostApiCodecReader/g' $FILE_NAME -sed -i '' 's/nullFirestoreMessagesPigeonCodecWriter/FirebaseFirestoreHostApiCodecWriter/g' $FILE_NAME -# Rename the public codec getter from `nullGetFirestoreMessagesCodec` so the plugin can reuse -# it on EventChannels without an awkward `null` prefix. -sed -i '' 's/nullGetFirestoreMessagesCodec/GetFirebaseFirestoreHostApiCodec/g' $FILE_NAME -sed -i '' 's/nullGetFirestoreMessagesCodec/GetFirebaseFirestoreHostApiCodec/g' ../../cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/include/cloud_firestore/Public/FirestoreMessages.g.h -# Reparent the reader/writer onto our custom Firestore reader/writer so Firestore-specific -# types (Timestamp, GeoPoint, FieldValue, DocumentReference, FieldPath, ...) round-trip. -sed -i '' 's/@interface FirebaseFirestoreHostApiCodecReader : FlutterStandardReader/@interface FirebaseFirestoreHostApiCodecReader : FLTFirebaseFirestoreReader/' $FILE_NAME -sed -i '' 's/@interface FirebaseFirestoreHostApiCodecWriter : FlutterStandardWriter/@interface FirebaseFirestoreHostApiCodecWriter : FLTFirebaseFirestoreWriter/' $FILE_NAME +# Fix iOS Swift files. +# Pigeon has no custom-codec hook, so reparent the generated reader/writer onto our +# Firestore codec (Timestamp, GeoPoint, FieldValue, DocumentReference, ...) and expose +# the ReaderWriter so EventChannels can reuse it. +FILE_NAME="../../cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/FirestoreMessages.g.swift" +sed -i '' 's/private class FirestoreMessagesPigeonCodecReader: FlutterStandardReader/class FirestoreMessagesPigeonCodecReader: FirebaseFirestoreReader/' "$FILE_NAME" +sed -i '' 's/private class FirestoreMessagesPigeonCodecWriter: FlutterStandardWriter/class FirestoreMessagesPigeonCodecWriter: FirebaseFirestoreWriter/' "$FILE_NAME" +sed -i '' 's/private class FirestoreMessagesPigeonCodecReaderWriter/class FirestoreMessagesPigeonCodecReaderWriter/' "$FILE_NAME" +# `where` is a Swift keyword; Pigeon emits it as a property name on InternalQueryParameters. +perl -i -pe 's/\bvar where:/var `where`:/g; s/\blet where:/let `where`:/g; s/\bwhere: where,/`where`: `where`,/g; s/\blhs\.where\b/lhs.`where`/g; s/\brhs\.where\b/rhs.`where`/g; s/value: where,/value: `where`,/g' "$FILE_NAME" +# The toList() array entry is a bare `where,` on its own line. +sed -i '' '/func toList()/,/^ }/{ + s/^ where,$/ `where`,/ +}' "$FILE_NAME" echo "iOS modification complete." diff --git a/packages/cloud_firestore/cloud_firestore_platform_interface/pigeons/messages.dart b/packages/cloud_firestore/cloud_firestore_platform_interface/pigeons/messages.dart index 27a61ef98f0d..619fd469d432 100644 --- a/packages/cloud_firestore/cloud_firestore_platform_interface/pigeons/messages.dart +++ b/packages/cloud_firestore/cloud_firestore_platform_interface/pigeons/messages.dart @@ -16,10 +16,8 @@ import 'package:pigeon/pigeon.dart'; package: 'io.flutter.plugins.firebase.firestore', className: 'GeneratedAndroidFirebaseFirestore', ), - objcHeaderOut: - '../cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/include/cloud_firestore/Public/FirestoreMessages.g.h', - objcSourceOut: - '../cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/FirestoreMessages.g.m', + swiftOut: + '../cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/FirestoreMessages.g.swift', cppHeaderOut: '../cloud_firestore/windows/messages.g.h', cppSourceOut: '../cloud_firestore/windows/messages.g.cpp', cppOptions: CppOptions(namespace: 'cloud_firestore_windows'), diff --git a/packages/cloud_firestore/cloud_firestore_platform_interface/test/pigeon/test_api.dart b/packages/cloud_firestore/cloud_firestore_platform_interface/test/pigeon/test_api.dart index 726d510a1f69..3877b1886a72 100644 --- a/packages/cloud_firestore/cloud_firestore_platform_interface/test/pigeon/test_api.dart +++ b/packages/cloud_firestore/cloud_firestore_platform_interface/test/pigeon/test_api.dart @@ -173,10 +173,7 @@ abstract class TestFirebaseFirestoreHostApi { Future loadBundle(FirestorePigeonFirebaseApp app, Uint8List bundle); Future namedQueryGet( - FirestorePigeonFirebaseApp app, - String name, - InternalGetOptions options, - ); + FirestorePigeonFirebaseApp app, String name, InternalGetOptions options); Future clearPersistence(FirestorePigeonFirebaseApp app); @@ -189,101 +186,76 @@ abstract class TestFirebaseFirestoreHostApi { Future waitForPendingWrites(FirestorePigeonFirebaseApp app); Future setIndexConfiguration( - FirestorePigeonFirebaseApp app, - String indexConfiguration, - ); + FirestorePigeonFirebaseApp app, String indexConfiguration); Future setLoggingEnabled(bool loggingEnabled); Future snapshotsInSyncSetup(FirestorePigeonFirebaseApp app); Future transactionCreate( - FirestorePigeonFirebaseApp app, - int timeout, - int maxAttempts, - ); + FirestorePigeonFirebaseApp app, int timeout, int maxAttempts); Future transactionStoreResult( - String transactionId, - InternalTransactionResult resultType, - List? commands, - ); + String transactionId, + InternalTransactionResult resultType, + List? commands); Future transactionGet( - FirestorePigeonFirebaseApp app, - String transactionId, - String path, - ); + FirestorePigeonFirebaseApp app, String transactionId, String path); Future documentReferenceSet( - FirestorePigeonFirebaseApp app, - DocumentReferenceRequest request, - ); + FirestorePigeonFirebaseApp app, DocumentReferenceRequest request); Future documentReferenceUpdate( - FirestorePigeonFirebaseApp app, - DocumentReferenceRequest request, - ); + FirestorePigeonFirebaseApp app, DocumentReferenceRequest request); Future documentReferenceGet( - FirestorePigeonFirebaseApp app, - DocumentReferenceRequest request, - ); + FirestorePigeonFirebaseApp app, DocumentReferenceRequest request); Future documentReferenceDelete( - FirestorePigeonFirebaseApp app, - DocumentReferenceRequest request, - ); + FirestorePigeonFirebaseApp app, DocumentReferenceRequest request); Future queryGet( - FirestorePigeonFirebaseApp app, - String path, - bool isCollectionGroup, - InternalQueryParameters parameters, - InternalGetOptions options, - ); + FirestorePigeonFirebaseApp app, + String path, + bool isCollectionGroup, + InternalQueryParameters parameters, + InternalGetOptions options); Future> aggregateQuery( - FirestorePigeonFirebaseApp app, - String path, - InternalQueryParameters parameters, - AggregateSource source, - List queries, - bool isCollectionGroup, - ); + FirestorePigeonFirebaseApp app, + String path, + InternalQueryParameters parameters, + AggregateSource source, + List queries, + bool isCollectionGroup); Future writeBatchCommit( - FirestorePigeonFirebaseApp app, - List writes, - ); + FirestorePigeonFirebaseApp app, List writes); Future querySnapshot( - FirestorePigeonFirebaseApp app, - String path, - bool isCollectionGroup, - InternalQueryParameters parameters, - InternalGetOptions options, - bool includeMetadataChanges, - ListenSource source, - ); + FirestorePigeonFirebaseApp app, + String path, + bool isCollectionGroup, + InternalQueryParameters parameters, + InternalGetOptions options, + bool includeMetadataChanges, + ListenSource source); Future documentReferenceSnapshot( - FirestorePigeonFirebaseApp app, - DocumentReferenceRequest parameters, - bool includeMetadataChanges, - ListenSource source, - ); + FirestorePigeonFirebaseApp app, + DocumentReferenceRequest parameters, + bool includeMetadataChanges, + ListenSource source); Future persistenceCacheIndexManagerRequest( - FirestorePigeonFirebaseApp app, - PersistenceCacheIndexManagerRequest request, - ); + FirestorePigeonFirebaseApp app, + PersistenceCacheIndexManagerRequest request); Future executePipeline( - FirestorePigeonFirebaseApp app, - List?> stages, - Map? options, - ); + FirestorePigeonFirebaseApp app, + List?> stages, + Map? options); static void setUp( TestFirebaseFirestoreHostApi? api, { @@ -294,10 +266,9 @@ abstract class TestFirebaseFirestoreHostApi { messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; { final pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.cloud_firestore_platform_interface.FirebaseFirestoreHostApi.loadBundle$messageChannelSuffix', - pigeonChannelCodec, - binaryMessenger: binaryMessenger, - ); + 'dev.flutter.pigeon.cloud_firestore_platform_interface.FirebaseFirestoreHostApi.loadBundle$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger); if (api == null) { _testBinaryMessengerBinding!.defaultBinaryMessenger .setMockDecodedMessageHandler(pigeonVar_channel, null); @@ -316,18 +287,16 @@ abstract class TestFirebaseFirestoreHostApi { return wrapResponse(error: e); } catch (e) { return wrapResponse( - error: PlatformException(code: 'error', message: e.toString()), - ); + error: PlatformException(code: 'error', message: e.toString())); } }); } } { final pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.cloud_firestore_platform_interface.FirebaseFirestoreHostApi.namedQueryGet$messageChannelSuffix', - pigeonChannelCodec, - binaryMessenger: binaryMessenger, - ); + 'dev.flutter.pigeon.cloud_firestore_platform_interface.FirebaseFirestoreHostApi.namedQueryGet$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger); if (api == null) { _testBinaryMessengerBinding!.defaultBinaryMessenger .setMockDecodedMessageHandler(pigeonVar_channel, null); @@ -348,18 +317,16 @@ abstract class TestFirebaseFirestoreHostApi { return wrapResponse(error: e); } catch (e) { return wrapResponse( - error: PlatformException(code: 'error', message: e.toString()), - ); + error: PlatformException(code: 'error', message: e.toString())); } }); } } { final pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.cloud_firestore_platform_interface.FirebaseFirestoreHostApi.clearPersistence$messageChannelSuffix', - pigeonChannelCodec, - binaryMessenger: binaryMessenger, - ); + 'dev.flutter.pigeon.cloud_firestore_platform_interface.FirebaseFirestoreHostApi.clearPersistence$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger); if (api == null) { _testBinaryMessengerBinding!.defaultBinaryMessenger .setMockDecodedMessageHandler(pigeonVar_channel, null); @@ -377,18 +344,16 @@ abstract class TestFirebaseFirestoreHostApi { return wrapResponse(error: e); } catch (e) { return wrapResponse( - error: PlatformException(code: 'error', message: e.toString()), - ); + error: PlatformException(code: 'error', message: e.toString())); } }); } } { final pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.cloud_firestore_platform_interface.FirebaseFirestoreHostApi.disableNetwork$messageChannelSuffix', - pigeonChannelCodec, - binaryMessenger: binaryMessenger, - ); + 'dev.flutter.pigeon.cloud_firestore_platform_interface.FirebaseFirestoreHostApi.disableNetwork$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger); if (api == null) { _testBinaryMessengerBinding!.defaultBinaryMessenger .setMockDecodedMessageHandler(pigeonVar_channel, null); @@ -406,18 +371,16 @@ abstract class TestFirebaseFirestoreHostApi { return wrapResponse(error: e); } catch (e) { return wrapResponse( - error: PlatformException(code: 'error', message: e.toString()), - ); + error: PlatformException(code: 'error', message: e.toString())); } }); } } { final pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.cloud_firestore_platform_interface.FirebaseFirestoreHostApi.enableNetwork$messageChannelSuffix', - pigeonChannelCodec, - binaryMessenger: binaryMessenger, - ); + 'dev.flutter.pigeon.cloud_firestore_platform_interface.FirebaseFirestoreHostApi.enableNetwork$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger); if (api == null) { _testBinaryMessengerBinding!.defaultBinaryMessenger .setMockDecodedMessageHandler(pigeonVar_channel, null); @@ -435,18 +398,16 @@ abstract class TestFirebaseFirestoreHostApi { return wrapResponse(error: e); } catch (e) { return wrapResponse( - error: PlatformException(code: 'error', message: e.toString()), - ); + error: PlatformException(code: 'error', message: e.toString())); } }); } } { final pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.cloud_firestore_platform_interface.FirebaseFirestoreHostApi.terminate$messageChannelSuffix', - pigeonChannelCodec, - binaryMessenger: binaryMessenger, - ); + 'dev.flutter.pigeon.cloud_firestore_platform_interface.FirebaseFirestoreHostApi.terminate$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger); if (api == null) { _testBinaryMessengerBinding!.defaultBinaryMessenger .setMockDecodedMessageHandler(pigeonVar_channel, null); @@ -464,18 +425,16 @@ abstract class TestFirebaseFirestoreHostApi { return wrapResponse(error: e); } catch (e) { return wrapResponse( - error: PlatformException(code: 'error', message: e.toString()), - ); + error: PlatformException(code: 'error', message: e.toString())); } }); } } { final pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.cloud_firestore_platform_interface.FirebaseFirestoreHostApi.waitForPendingWrites$messageChannelSuffix', - pigeonChannelCodec, - binaryMessenger: binaryMessenger, - ); + 'dev.flutter.pigeon.cloud_firestore_platform_interface.FirebaseFirestoreHostApi.waitForPendingWrites$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger); if (api == null) { _testBinaryMessengerBinding!.defaultBinaryMessenger .setMockDecodedMessageHandler(pigeonVar_channel, null); @@ -493,18 +452,16 @@ abstract class TestFirebaseFirestoreHostApi { return wrapResponse(error: e); } catch (e) { return wrapResponse( - error: PlatformException(code: 'error', message: e.toString()), - ); + error: PlatformException(code: 'error', message: e.toString())); } }); } } { final pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.cloud_firestore_platform_interface.FirebaseFirestoreHostApi.setIndexConfiguration$messageChannelSuffix', - pigeonChannelCodec, - binaryMessenger: binaryMessenger, - ); + 'dev.flutter.pigeon.cloud_firestore_platform_interface.FirebaseFirestoreHostApi.setIndexConfiguration$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger); if (api == null) { _testBinaryMessengerBinding!.defaultBinaryMessenger .setMockDecodedMessageHandler(pigeonVar_channel, null); @@ -523,18 +480,16 @@ abstract class TestFirebaseFirestoreHostApi { return wrapResponse(error: e); } catch (e) { return wrapResponse( - error: PlatformException(code: 'error', message: e.toString()), - ); + error: PlatformException(code: 'error', message: e.toString())); } }); } } { final pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.cloud_firestore_platform_interface.FirebaseFirestoreHostApi.setLoggingEnabled$messageChannelSuffix', - pigeonChannelCodec, - binaryMessenger: binaryMessenger, - ); + 'dev.flutter.pigeon.cloud_firestore_platform_interface.FirebaseFirestoreHostApi.setLoggingEnabled$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger); if (api == null) { _testBinaryMessengerBinding!.defaultBinaryMessenger .setMockDecodedMessageHandler(pigeonVar_channel, null); @@ -551,18 +506,16 @@ abstract class TestFirebaseFirestoreHostApi { return wrapResponse(error: e); } catch (e) { return wrapResponse( - error: PlatformException(code: 'error', message: e.toString()), - ); + error: PlatformException(code: 'error', message: e.toString())); } }); } } { final pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.cloud_firestore_platform_interface.FirebaseFirestoreHostApi.snapshotsInSyncSetup$messageChannelSuffix', - pigeonChannelCodec, - binaryMessenger: binaryMessenger, - ); + 'dev.flutter.pigeon.cloud_firestore_platform_interface.FirebaseFirestoreHostApi.snapshotsInSyncSetup$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger); if (api == null) { _testBinaryMessengerBinding!.defaultBinaryMessenger .setMockDecodedMessageHandler(pigeonVar_channel, null); @@ -580,18 +533,16 @@ abstract class TestFirebaseFirestoreHostApi { return wrapResponse(error: e); } catch (e) { return wrapResponse( - error: PlatformException(code: 'error', message: e.toString()), - ); + error: PlatformException(code: 'error', message: e.toString())); } }); } } { final pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.cloud_firestore_platform_interface.FirebaseFirestoreHostApi.transactionCreate$messageChannelSuffix', - pigeonChannelCodec, - binaryMessenger: binaryMessenger, - ); + 'dev.flutter.pigeon.cloud_firestore_platform_interface.FirebaseFirestoreHostApi.transactionCreate$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger); if (api == null) { _testBinaryMessengerBinding!.defaultBinaryMessenger .setMockDecodedMessageHandler(pigeonVar_channel, null); @@ -606,27 +557,22 @@ abstract class TestFirebaseFirestoreHostApi { final int arg_maxAttempts = args[2]! as int; try { final String output = await api.transactionCreate( - arg_app, - arg_timeout, - arg_maxAttempts, - ); + arg_app, arg_timeout, arg_maxAttempts); return [output]; } on PlatformException catch (e) { return wrapResponse(error: e); } catch (e) { return wrapResponse( - error: PlatformException(code: 'error', message: e.toString()), - ); + error: PlatformException(code: 'error', message: e.toString())); } }); } } { final pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.cloud_firestore_platform_interface.FirebaseFirestoreHostApi.transactionStoreResult$messageChannelSuffix', - pigeonChannelCodec, - binaryMessenger: binaryMessenger, - ); + 'dev.flutter.pigeon.cloud_firestore_platform_interface.FirebaseFirestoreHostApi.transactionStoreResult$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger); if (api == null) { _testBinaryMessengerBinding!.defaultBinaryMessenger .setMockDecodedMessageHandler(pigeonVar_channel, null); @@ -642,27 +588,22 @@ abstract class TestFirebaseFirestoreHostApi { (args[2] as List?)?.cast(); try { await api.transactionStoreResult( - arg_transactionId, - arg_resultType, - arg_commands, - ); + arg_transactionId, arg_resultType, arg_commands); return wrapResponse(empty: true); } on PlatformException catch (e) { return wrapResponse(error: e); } catch (e) { return wrapResponse( - error: PlatformException(code: 'error', message: e.toString()), - ); + error: PlatformException(code: 'error', message: e.toString())); } }); } } { final pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.cloud_firestore_platform_interface.FirebaseFirestoreHostApi.transactionGet$messageChannelSuffix', - pigeonChannelCodec, - binaryMessenger: binaryMessenger, - ); + 'dev.flutter.pigeon.cloud_firestore_platform_interface.FirebaseFirestoreHostApi.transactionGet$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger); if (api == null) { _testBinaryMessengerBinding!.defaultBinaryMessenger .setMockDecodedMessageHandler(pigeonVar_channel, null); @@ -683,18 +624,16 @@ abstract class TestFirebaseFirestoreHostApi { return wrapResponse(error: e); } catch (e) { return wrapResponse( - error: PlatformException(code: 'error', message: e.toString()), - ); + error: PlatformException(code: 'error', message: e.toString())); } }); } } { final pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.cloud_firestore_platform_interface.FirebaseFirestoreHostApi.documentReferenceSet$messageChannelSuffix', - pigeonChannelCodec, - binaryMessenger: binaryMessenger, - ); + 'dev.flutter.pigeon.cloud_firestore_platform_interface.FirebaseFirestoreHostApi.documentReferenceSet$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger); if (api == null) { _testBinaryMessengerBinding!.defaultBinaryMessenger .setMockDecodedMessageHandler(pigeonVar_channel, null); @@ -714,18 +653,16 @@ abstract class TestFirebaseFirestoreHostApi { return wrapResponse(error: e); } catch (e) { return wrapResponse( - error: PlatformException(code: 'error', message: e.toString()), - ); + error: PlatformException(code: 'error', message: e.toString())); } }); } } { final pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.cloud_firestore_platform_interface.FirebaseFirestoreHostApi.documentReferenceUpdate$messageChannelSuffix', - pigeonChannelCodec, - binaryMessenger: binaryMessenger, - ); + 'dev.flutter.pigeon.cloud_firestore_platform_interface.FirebaseFirestoreHostApi.documentReferenceUpdate$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger); if (api == null) { _testBinaryMessengerBinding!.defaultBinaryMessenger .setMockDecodedMessageHandler(pigeonVar_channel, null); @@ -745,18 +682,16 @@ abstract class TestFirebaseFirestoreHostApi { return wrapResponse(error: e); } catch (e) { return wrapResponse( - error: PlatformException(code: 'error', message: e.toString()), - ); + error: PlatformException(code: 'error', message: e.toString())); } }); } } { final pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.cloud_firestore_platform_interface.FirebaseFirestoreHostApi.documentReferenceGet$messageChannelSuffix', - pigeonChannelCodec, - binaryMessenger: binaryMessenger, - ); + 'dev.flutter.pigeon.cloud_firestore_platform_interface.FirebaseFirestoreHostApi.documentReferenceGet$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger); if (api == null) { _testBinaryMessengerBinding!.defaultBinaryMessenger .setMockDecodedMessageHandler(pigeonVar_channel, null); @@ -777,18 +712,16 @@ abstract class TestFirebaseFirestoreHostApi { return wrapResponse(error: e); } catch (e) { return wrapResponse( - error: PlatformException(code: 'error', message: e.toString()), - ); + error: PlatformException(code: 'error', message: e.toString())); } }); } } { final pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.cloud_firestore_platform_interface.FirebaseFirestoreHostApi.documentReferenceDelete$messageChannelSuffix', - pigeonChannelCodec, - binaryMessenger: binaryMessenger, - ); + 'dev.flutter.pigeon.cloud_firestore_platform_interface.FirebaseFirestoreHostApi.documentReferenceDelete$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger); if (api == null) { _testBinaryMessengerBinding!.defaultBinaryMessenger .setMockDecodedMessageHandler(pigeonVar_channel, null); @@ -808,18 +741,16 @@ abstract class TestFirebaseFirestoreHostApi { return wrapResponse(error: e); } catch (e) { return wrapResponse( - error: PlatformException(code: 'error', message: e.toString()), - ); + error: PlatformException(code: 'error', message: e.toString())); } }); } } { final pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.cloud_firestore_platform_interface.FirebaseFirestoreHostApi.queryGet$messageChannelSuffix', - pigeonChannelCodec, - binaryMessenger: binaryMessenger, - ); + 'dev.flutter.pigeon.cloud_firestore_platform_interface.FirebaseFirestoreHostApi.queryGet$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger); if (api == null) { _testBinaryMessengerBinding!.defaultBinaryMessenger .setMockDecodedMessageHandler(pigeonVar_channel, null); @@ -836,30 +767,23 @@ abstract class TestFirebaseFirestoreHostApi { args[3]! as InternalQueryParameters; final InternalGetOptions arg_options = args[4]! as InternalGetOptions; try { - final InternalQuerySnapshot output = await api.queryGet( - arg_app, - arg_path, - arg_isCollectionGroup, - arg_parameters, - arg_options, - ); + final InternalQuerySnapshot output = await api.queryGet(arg_app, + arg_path, arg_isCollectionGroup, arg_parameters, arg_options); return [output]; } on PlatformException catch (e) { return wrapResponse(error: e); } catch (e) { return wrapResponse( - error: PlatformException(code: 'error', message: e.toString()), - ); + error: PlatformException(code: 'error', message: e.toString())); } }); } } { final pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.cloud_firestore_platform_interface.FirebaseFirestoreHostApi.aggregateQuery$messageChannelSuffix', - pigeonChannelCodec, - binaryMessenger: binaryMessenger, - ); + 'dev.flutter.pigeon.cloud_firestore_platform_interface.FirebaseFirestoreHostApi.aggregateQuery$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger); if (api == null) { _testBinaryMessengerBinding!.defaultBinaryMessenger .setMockDecodedMessageHandler(pigeonVar_channel, null); @@ -879,31 +803,23 @@ abstract class TestFirebaseFirestoreHostApi { final bool arg_isCollectionGroup = args[5]! as bool; try { final List output = - await api.aggregateQuery( - arg_app, - arg_path, - arg_parameters, - arg_source, - arg_queries, - arg_isCollectionGroup, - ); + await api.aggregateQuery(arg_app, arg_path, arg_parameters, + arg_source, arg_queries, arg_isCollectionGroup); return [output]; } on PlatformException catch (e) { return wrapResponse(error: e); } catch (e) { return wrapResponse( - error: PlatformException(code: 'error', message: e.toString()), - ); + error: PlatformException(code: 'error', message: e.toString())); } }); } } { final pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.cloud_firestore_platform_interface.FirebaseFirestoreHostApi.writeBatchCommit$messageChannelSuffix', - pigeonChannelCodec, - binaryMessenger: binaryMessenger, - ); + 'dev.flutter.pigeon.cloud_firestore_platform_interface.FirebaseFirestoreHostApi.writeBatchCommit$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger); if (api == null) { _testBinaryMessengerBinding!.defaultBinaryMessenger .setMockDecodedMessageHandler(pigeonVar_channel, null); @@ -923,18 +839,16 @@ abstract class TestFirebaseFirestoreHostApi { return wrapResponse(error: e); } catch (e) { return wrapResponse( - error: PlatformException(code: 'error', message: e.toString()), - ); + error: PlatformException(code: 'error', message: e.toString())); } }); } } { final pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.cloud_firestore_platform_interface.FirebaseFirestoreHostApi.querySnapshot$messageChannelSuffix', - pigeonChannelCodec, - binaryMessenger: binaryMessenger, - ); + 'dev.flutter.pigeon.cloud_firestore_platform_interface.FirebaseFirestoreHostApi.querySnapshot$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger); if (api == null) { _testBinaryMessengerBinding!.defaultBinaryMessenger .setMockDecodedMessageHandler(pigeonVar_channel, null); @@ -954,31 +868,28 @@ abstract class TestFirebaseFirestoreHostApi { final ListenSource arg_source = args[6]! as ListenSource; try { final String output = await api.querySnapshot( - arg_app, - arg_path, - arg_isCollectionGroup, - arg_parameters, - arg_options, - arg_includeMetadataChanges, - arg_source, - ); + arg_app, + arg_path, + arg_isCollectionGroup, + arg_parameters, + arg_options, + arg_includeMetadataChanges, + arg_source); return [output]; } on PlatformException catch (e) { return wrapResponse(error: e); } catch (e) { return wrapResponse( - error: PlatformException(code: 'error', message: e.toString()), - ); + error: PlatformException(code: 'error', message: e.toString())); } }); } } { final pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.cloud_firestore_platform_interface.FirebaseFirestoreHostApi.documentReferenceSnapshot$messageChannelSuffix', - pigeonChannelCodec, - binaryMessenger: binaryMessenger, - ); + 'dev.flutter.pigeon.cloud_firestore_platform_interface.FirebaseFirestoreHostApi.documentReferenceSnapshot$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger); if (api == null) { _testBinaryMessengerBinding!.defaultBinaryMessenger .setMockDecodedMessageHandler(pigeonVar_channel, null); @@ -994,29 +905,23 @@ abstract class TestFirebaseFirestoreHostApi { final bool arg_includeMetadataChanges = args[2]! as bool; final ListenSource arg_source = args[3]! as ListenSource; try { - final String output = await api.documentReferenceSnapshot( - arg_app, - arg_parameters, - arg_includeMetadataChanges, - arg_source, - ); + final String output = await api.documentReferenceSnapshot(arg_app, + arg_parameters, arg_includeMetadataChanges, arg_source); return [output]; } on PlatformException catch (e) { return wrapResponse(error: e); } catch (e) { return wrapResponse( - error: PlatformException(code: 'error', message: e.toString()), - ); + error: PlatformException(code: 'error', message: e.toString())); } }); } } { final pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.cloud_firestore_platform_interface.FirebaseFirestoreHostApi.persistenceCacheIndexManagerRequest$messageChannelSuffix', - pigeonChannelCodec, - binaryMessenger: binaryMessenger, - ); + 'dev.flutter.pigeon.cloud_firestore_platform_interface.FirebaseFirestoreHostApi.persistenceCacheIndexManagerRequest$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger); if (api == null) { _testBinaryMessengerBinding!.defaultBinaryMessenger .setMockDecodedMessageHandler(pigeonVar_channel, null); @@ -1036,18 +941,16 @@ abstract class TestFirebaseFirestoreHostApi { return wrapResponse(error: e); } catch (e) { return wrapResponse( - error: PlatformException(code: 'error', message: e.toString()), - ); + error: PlatformException(code: 'error', message: e.toString())); } }); } } { final pigeonVar_channel = BasicMessageChannel( - 'dev.flutter.pigeon.cloud_firestore_platform_interface.FirebaseFirestoreHostApi.executePipeline$messageChannelSuffix', - pigeonChannelCodec, - binaryMessenger: binaryMessenger, - ); + 'dev.flutter.pigeon.cloud_firestore_platform_interface.FirebaseFirestoreHostApi.executePipeline$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger); if (api == null) { _testBinaryMessengerBinding!.defaultBinaryMessenger .setMockDecodedMessageHandler(pigeonVar_channel, null); @@ -1070,8 +973,7 @@ abstract class TestFirebaseFirestoreHostApi { return wrapResponse(error: e); } catch (e) { return wrapResponse( - error: PlatformException(code: 'error', message: e.toString()), - ); + error: PlatformException(code: 'error', message: e.toString())); } }); } diff --git a/scripts/generate_versions_spm.dart b/scripts/generate_versions_spm.dart index 2b7766dedcdb..645696665077 100644 --- a/scripts/generate_versions_spm.dart +++ b/scripts/generate_versions_spm.dart @@ -118,6 +118,7 @@ void updateLibraryVersionPureSwiftPlugins() { 'firebase_in_app_messaging', 'firebase_crashlytics', 'firebase_core', + 'cloud_firestore', ]; for (final package in packages) {