Skip to content

Commit 77911b8

Browse files
authored
feat(firestore, iOS): iOS implementation for Pipeline APIs (#18099)
* feat(firestore): iOS implementation for Pipeline APIs * fix: conditionally import FIRPipelineBridge.h for iOS * chore: add macOS support for FLTPipelineParser by linking to iOS implementation * fix: conditionally include FIRPipelineBridge.h for macOS support in FLTPipelineParser * chore: add support for missing Expression function * refactor: clean up formatting in FLTPipelineParser.m for improved readability * chore: enhance FLTPipelineParser with support for array and map expressions, ensuring proper argument handling * chore: implement conditional expression and current timestamp handling in FLTPipelineParser * chore: add 'find_nearest' stage support in FLTPipelineParser with validation for vector_field, vector_value, and distance_measure * chore: introduce FLTFirebaseFirestoreErrorCodePipelineParse for improved error handling in pipeline parsing * trigger CI * fix: update header inclusion logic for FirebaseFirestore in FLTPipelineParser.m * trigger CI * chore: enhance FLTPipelineParser with new expression handling
1 parent d6a945e commit 77911b8

File tree

10 files changed

+1588
-8
lines changed

10 files changed

+1588
-8
lines changed

packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/FLTFirebaseFirestorePlugin.m

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#import "include/cloud_firestore/Private/FLTFirebaseFirestoreReader.h"
1616
#import "include/cloud_firestore/Private/FLTFirebaseFirestoreUtils.h"
1717
#import "include/cloud_firestore/Private/FLTLoadBundleStreamHandler.h"
18+
#import "include/cloud_firestore/Private/FLTPipelineParser.h"
1819
#import "include/cloud_firestore/Private/FLTQuerySnapshotStreamHandler.h"
1920
#import "include/cloud_firestore/Private/FLTSnapshotsInSyncStreamHandler.h"
2021
#import "include/cloud_firestore/Private/FLTTransactionStreamHandler.h"
@@ -73,6 +74,20 @@ - (NSString *)registerEventChannelWithPrefix:(NSString *)prefix
7374

7475
static NSCache<NSNumber *, NSString *> *_serverTimestampMap;
7576

77+
static id _Nullable FLTPipelineNullSafe(id value) {
78+
return (value == nil || [value isKindOfClass:[NSNull class]]) ? nil : value;
79+
}
80+
81+
static NSNumber *_Nullable FLTPipelineTimestampToMs(id value) {
82+
if (!value) return nil;
83+
if ([value isKindOfClass:[NSNumber class]]) return value;
84+
if ([value isKindOfClass:[FIRTimestamp class]]) {
85+
FIRTimestamp *ts = value;
86+
return @((int64_t)ts.seconds * 1000 + (int64_t)ts.nanoseconds / 1000000);
87+
}
88+
return nil;
89+
}
90+
7691
@implementation FLTFirebaseFirestorePlugin {
7792
NSMutableDictionary<NSString *, FlutterEventChannel *> *_eventChannels;
7893
NSMutableDictionary<NSString *, NSObject<FlutterStreamHandler> *> *_streamHandlers;
@@ -883,4 +898,66 @@ - (void)aggregateQueryApp:(nonnull FirestorePigeonFirebaseApp *)app
883898
}];
884899
}
885900

901+
- (void)executePipelineApp:(nonnull FirestorePigeonFirebaseApp *)app
902+
stages:(nonnull NSArray<NSDictionary<NSString *, id> *> *)stages
903+
options:(nullable NSDictionary<NSString *, id> *)options
904+
completion:(nonnull void (^)(PigeonPipelineSnapshot *_Nullable,
905+
FlutterError *_Nullable))completion {
906+
FIRFirestore *firestore = [self getFIRFirestoreFromAppNameFromPigeon:app];
907+
908+
[FLTPipelineParser
909+
executePipelineWithFirestore:firestore
910+
stages:stages
911+
options:options
912+
completion:^(id _Nullable snapshot, NSError *_Nullable error) {
913+
if (error) {
914+
completion(nil, [self convertToFlutterError:error]);
915+
return;
916+
}
917+
if (snapshot == nil) {
918+
completion(
919+
nil,
920+
[FlutterError errorWithCode:@"error"
921+
message:@"Pipeline execution returned no result"
922+
details:nil]);
923+
return;
924+
}
925+
926+
NSMutableArray<PigeonPipelineResult *> *pigeonResults =
927+
[NSMutableArray array];
928+
NSArray *results = [snapshot results];
929+
if ([results isKindOfClass:[NSArray class]]) {
930+
for (id result in results) {
931+
id ref = [result reference];
932+
NSString *path = (ref && [ref respondsToSelector:@selector(path)])
933+
? [ref path]
934+
: FLTPipelineNullSafe([result documentID]);
935+
NSNumber *createTime =
936+
FLTPipelineTimestampToMs([result valueForKey:@"create_time"]);
937+
NSNumber *updateTime =
938+
FLTPipelineTimestampToMs([result valueForKey:@"update_time"]);
939+
NSDictionary *data = FLTPipelineNullSafe([result data]);
940+
PigeonPipelineResult *pigeonResult =
941+
[PigeonPipelineResult makeWithDocumentPath:path
942+
createTime:createTime
943+
updateTime:updateTime
944+
data:data];
945+
[pigeonResults addObject:pigeonResult];
946+
}
947+
}
948+
949+
NSNumber *executionTime =
950+
FLTPipelineTimestampToMs([snapshot execution_time]);
951+
if (executionTime == nil) {
952+
executionTime =
953+
@((int64_t)([[NSDate date] timeIntervalSince1970] * 1000));
954+
}
955+
956+
PigeonPipelineSnapshot *pigeonSnapshot =
957+
[PigeonPipelineSnapshot makeWithResults:pigeonResults
958+
executionTime:executionTime];
959+
completion(pigeonSnapshot, nil);
960+
}];
961+
}
962+
886963
@end

packages/cloud_firestore/cloud_firestore/ios/cloud_firestore/Sources/cloud_firestore/FLTFirebaseFirestoreUtils.m

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ - (FlutterStandardReader *_Nonnull)readerWithData:(NSData *)data {
2121

2222
NSMutableDictionary<NSString *, FLTFirebaseFirestoreExtension *> *firestoreInstanceCache;
2323

24+
const NSInteger FLTFirebaseFirestoreErrorCodePipelineParse = -1;
25+
2426
@implementation FLTFirebaseFirestoreUtils
2527

2628
+ (NSString *)generateKeyForAppName:(NSString *)appName andDatabaseURL:(NSString *)databaseURL {
@@ -240,6 +242,11 @@ + (NSArray *)ErrorCodeAndMessageFromNSError:(NSError *)error {
240242
code = @"unknown";
241243
message = @"Unknown error or an error from a different error domain.";
242244
break;
245+
case FLTFirebaseFirestoreErrorCodePipelineParse:
246+
code = @"parse-error";
247+
message = (error.localizedDescription.length > 0) ? error.localizedDescription
248+
: @"An unknown error occurred.";
249+
break;
243250
default:
244251
code = @"unknown";
245252
message = @"An unknown error occurred.";

0 commit comments

Comments
 (0)