Skip to content

Commit 3ad6d7b

Browse files
committed
Firestore pipeline prototype
1 parent 8b099b2 commit 3ad6d7b

35 files changed

+1276
-2
lines changed

Firestore/Example/Firestore.xcodeproj/project.pbxproj

+10-2
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,9 @@
127127
11F8EE69182C9699E90A9E3D /* database_info_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = AB38D92E20235D22000A432D /* database_info_test.cc */; };
128128
12158DFCEE09D24B7988A340 /* maybe_document.pb.cc in Sources */ = {isa = PBXBuildFile; fileRef = 618BBE7E20B89AAC00B5BCE7 /* maybe_document.pb.cc */; };
129129
121F0FB9DCCBFB7573C7AF48 /* bundle_serializer_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = B5C2A94EE24E60543F62CC35 /* bundle_serializer_test.cc */; };
130+
12260A2A2D56A3CE001766EB /* PipelineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12260A292D56A3CE001766EB /* PipelineTests.swift */; };
131+
12260A2B2D56A3CE001766EB /* PipelineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12260A292D56A3CE001766EB /* PipelineTests.swift */; };
132+
12260A2C2D56A3CE001766EB /* PipelineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12260A292D56A3CE001766EB /* PipelineTests.swift */; };
130133
124AAEE987451820F24EEA8E /* user_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = CCC9BD953F121B9E29F9AA42 /* user_test.cc */; };
131134
125B1048ECB755C2106802EB /* executor_std_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = B6FB4687208F9B9100554BA2 /* executor_std_test.cc */; };
132135
1290FA77A922B76503AE407C /* lru_garbage_collector_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 277EAACC4DD7C21332E8496A /* lru_garbage_collector_test.cc */; };
@@ -1735,6 +1738,7 @@
17351738
0D964D4936953635AC7E0834 /* Validation_BloomFilterTest_MD5_1_01_bloom_filter_proto.json */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.json; name = Validation_BloomFilterTest_MD5_1_01_bloom_filter_proto.json; path = bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_1_01_bloom_filter_proto.json; sourceTree = "<group>"; };
17361739
0EE5300F8233D14025EF0456 /* string_apple_test.mm */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.objcpp; path = string_apple_test.mm; sourceTree = "<group>"; };
17371740
11984BA0A99D7A7ABA5B0D90 /* Pods-Firestore_Example_iOS-Firestore_SwiftTests_iOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Firestore_Example_iOS-Firestore_SwiftTests_iOS.release.xcconfig"; path = "Pods/Target Support Files/Pods-Firestore_Example_iOS-Firestore_SwiftTests_iOS/Pods-Firestore_Example_iOS-Firestore_SwiftTests_iOS.release.xcconfig"; sourceTree = "<group>"; };
1741+
12260A292D56A3CE001766EB /* PipelineTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PipelineTests.swift; sourceTree = "<group>"; };
17381742
1235769122B7E915007DDFA9 /* EncodableFieldValueTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EncodableFieldValueTests.swift; sourceTree = "<group>"; };
17391743
1235769422B86E65007DDFA9 /* FirestoreEncoderTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FirestoreEncoderTests.swift; sourceTree = "<group>"; };
17401744
124C932B22C1642C00CA8C2D /* CodableIntegrationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CodableIntegrationTests.swift; sourceTree = "<group>"; };
@@ -1797,7 +1801,7 @@
17971801
4334F87873015E3763954578 /* status_testing.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = status_testing.h; sourceTree = "<group>"; };
17981802
4375BDCDBCA9938C7F086730 /* Validation_BloomFilterTest_MD5_5000_1_bloom_filter_proto.json */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.json; name = Validation_BloomFilterTest_MD5_5000_1_bloom_filter_proto.json; path = bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_5000_1_bloom_filter_proto.json; sourceTree = "<group>"; };
17991803
444B7AB3F5A2929070CB1363 /* hard_assert_test.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; path = hard_assert_test.cc; sourceTree = "<group>"; };
1800-
4564AD9C55EC39C080EB9476 /* globals_cache_test.cc */ = {isa = PBXFileReference; includeInIndex = 1; path = globals_cache_test.cc; sourceTree = "<group>"; };
1804+
4564AD9C55EC39C080EB9476 /* globals_cache_test.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; path = globals_cache_test.cc; sourceTree = "<group>"; };
18011805
478DC75A0DCA6249A616DD30 /* Validation_BloomFilterTest_MD5_500_0001_membership_test_result.json */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.json; name = Validation_BloomFilterTest_MD5_500_0001_membership_test_result.json; path = bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_500_0001_membership_test_result.json; sourceTree = "<group>"; };
18021806
48D0915834C3D234E5A875A9 /* grpc_stream_tester.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = grpc_stream_tester.h; sourceTree = "<group>"; };
18031807
4B3E4A77493524333133C5DC /* Validation_BloomFilterTest_MD5_50000_1_bloom_filter_proto.json */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.json; name = Validation_BloomFilterTest_MD5_50000_1_bloom_filter_proto.json; path = bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_50000_1_bloom_filter_proto.json; sourceTree = "<group>"; };
@@ -1915,7 +1919,7 @@
19151919
5B5414D28802BC76FDADABD6 /* stream_test.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; path = stream_test.cc; sourceTree = "<group>"; };
19161920
5B96CC29E9946508F022859C /* Validation_BloomFilterTest_MD5_50000_0001_membership_test_result.json */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.json; name = Validation_BloomFilterTest_MD5_50000_0001_membership_test_result.json; path = bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_50000_0001_membership_test_result.json; sourceTree = "<group>"; };
19171921
5C68EE4CB94C0DD6E333F546 /* Validation_BloomFilterTest_MD5_1_01_membership_test_result.json */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.json; name = Validation_BloomFilterTest_MD5_1_01_membership_test_result.json; path = bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_1_01_membership_test_result.json; sourceTree = "<group>"; };
1918-
5C6DEA63FBDE19D841291723 /* memory_globals_cache_test.cc */ = {isa = PBXFileReference; includeInIndex = 1; path = memory_globals_cache_test.cc; sourceTree = "<group>"; };
1922+
5C6DEA63FBDE19D841291723 /* memory_globals_cache_test.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; path = memory_globals_cache_test.cc; sourceTree = "<group>"; };
19191923
5C7942B6244F4C416B11B86C /* leveldb_mutation_queue_test.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; path = leveldb_mutation_queue_test.cc; sourceTree = "<group>"; };
19201924
5CAE131920FFFED600BE9A4A /* Firestore_Benchmarks_iOS.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Firestore_Benchmarks_iOS.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
19211925
5CAE131D20FFFED600BE9A4A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
@@ -2296,6 +2300,7 @@
22962300
124C932B22C1642C00CA8C2D /* CodableIntegrationTests.swift */,
22972301
3355BE9391CC4857AF0BDAE3 /* DatabaseTests.swift */,
22982302
62E54B832A9E910A003347C8 /* IndexingTests.swift */,
2303+
12260A292D56A3CE001766EB /* PipelineTests.swift */,
22992304
621D620928F9CE7400D2FA26 /* QueryIntegrationTests.swift */,
23002305
4D65F6E69993611D47DC8E7C /* SnapshotListenerSourceTests.swift */,
23012306
EFF22EA92C5060A4009A369B /* VectorIntegrationTests.swift */,
@@ -4685,6 +4690,7 @@
46854690
432056C4D1259F76C80FC2A8 /* FSTUserDataReaderTests.mm in Sources */,
46864691
3B1E27D951407FD237E64D07 /* FirestoreEncoderTests.swift in Sources */,
46874692
62E54B862A9E910B003347C8 /* IndexingTests.swift in Sources */,
4693+
12260A2C2D56A3CE001766EB /* PipelineTests.swift in Sources */,
46884694
621D620C28F9CE7400D2FA26 /* QueryIntegrationTests.swift in Sources */,
46894695
1CFBD4563960D8A20C4679A3 /* SnapshotListenerSourceTests.swift in Sources */,
46904696
EFF22EAC2C5060A4009A369B /* VectorIntegrationTests.swift in Sources */,
@@ -4935,6 +4941,7 @@
49354941
75A176239B37354588769206 /* FSTUserDataReaderTests.mm in Sources */,
49364942
5E89B1A5A5430713C79C4854 /* FirestoreEncoderTests.swift in Sources */,
49374943
62E54B852A9E910B003347C8 /* IndexingTests.swift in Sources */,
4944+
12260A2B2D56A3CE001766EB /* PipelineTests.swift in Sources */,
49384945
621D620B28F9CE7400D2FA26 /* QueryIntegrationTests.swift in Sources */,
49394946
A0BC30D482B0ABD1A3A24CDC /* SnapshotListenerSourceTests.swift in Sources */,
49404947
EFF22EAB2C5060A4009A369B /* VectorIntegrationTests.swift in Sources */,
@@ -5440,6 +5447,7 @@
54405447
F5BDECEB3B43BD1591EEADBD /* FSTUserDataReaderTests.mm in Sources */,
54415448
6F45846C159D3C063DBD3CBE /* FirestoreEncoderTests.swift in Sources */,
54425449
62E54B842A9E910B003347C8 /* IndexingTests.swift in Sources */,
5450+
12260A2A2D56A3CE001766EB /* PipelineTests.swift in Sources */,
54435451
621D620A28F9CE7400D2FA26 /* QueryIntegrationTests.swift in Sources */,
54445452
B00F8D1819EE20C45B660940 /* SnapshotListenerSourceTests.swift in Sources */,
54455453
EFF22EAA2C5060A4009A369B /* VectorIntegrationTests.swift in Sources */,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/*
2+
* Copyright 2025 Google
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#import "FIRPipelineBridge.h"
18+
19+
#include <memory>
20+
21+
#include "Firestore/core/src/api/expressions.h"
22+
#include "Firestore/core/src/api/pipeline.h"
23+
#include "Firestore/core/src/api/stages.h"
24+
25+
@class FIRFilter;
26+
27+
namespace api = firebase::firestore::api;
28+
29+
NS_ASSUME_NONNULL_BEGIN
30+
31+
@interface FIRExprBridge (Internal)
32+
33+
- (std::shared_ptr<api::Expr>)cpp_expr;
34+
35+
@end
36+
37+
@interface FIRStageBridge (Internal)
38+
39+
- (std::shared_ptr<api::Stage>)cpp_stage;
40+
41+
@end
42+
43+
@interface __FIRPipelineSnapshotBridge (Internal)
44+
45+
- (id)initWithCppSnapshot:(api::PipelineSnapshot)snapshot;
46+
47+
@end
48+
49+
NS_ASSUME_NONNULL_END
+176
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
//
2+
// FIRExprBridge.m
3+
// FirebaseFirestoreInternal
4+
//
5+
// Created by Hui Wu on 2/25/25.
6+
//
7+
8+
#import "FIRPipelineBridge.h"
9+
10+
#include <memory>
11+
12+
#import "Firestore/Source/API/FIRFirestore+Internal.h"
13+
#import "Firestore/Source/API/FIRPipelineBridge+Internal.h"
14+
15+
#include "Firestore/core/src/api/expressions.h"
16+
#include "Firestore/core/src/api/pipeline.h"
17+
#include "Firestore/core/src/api/pipeline_result.h"
18+
#include "Firestore/core/src/api/pipeline_snapshot.h"
19+
#include "Firestore/core/src/api/stages.h"
20+
#include "Firestore/core/src/util/error_apple.h"
21+
#include "Firestore/core/src/util/status.h"
22+
#include "Firestore/core/src/util/string_apple.h"
23+
24+
using firebase::firestore::api::CollectionSource;
25+
using firebase::firestore::api::Constant;
26+
using firebase::firestore::api::Eq;
27+
using firebase::firestore::api::Expr;
28+
using firebase::firestore::api::Field;
29+
using firebase::firestore::api::Pipeline;
30+
using firebase::firestore::api::Where;
31+
using firebase::firestore::util::MakeCallback;
32+
using firebase::firestore::util::MakeString;
33+
34+
NS_ASSUME_NONNULL_BEGIN
35+
36+
@implementation FIRExprBridge
37+
@end
38+
39+
@implementation FIRFieldBridge {
40+
std::shared_ptr<Field> field;
41+
}
42+
43+
- (id)init:(NSString *)name {
44+
self = [super init];
45+
if (self) {
46+
field = std::make_shared<Field>(MakeString(name));
47+
}
48+
return self;
49+
}
50+
51+
- (std::shared_ptr<api::Expr>)cpp_expr {
52+
return field;
53+
}
54+
55+
@end
56+
57+
@implementation FIRConstantBridge {
58+
std::shared_ptr<Constant> constant;
59+
}
60+
- (id)init:(NSNumber *)value {
61+
self = [super init];
62+
if (self) {
63+
constant = std::make_shared<Constant>(value.doubleValue);
64+
}
65+
return self;
66+
}
67+
68+
- (std::shared_ptr<api::Expr>)cpp_expr {
69+
return constant;
70+
}
71+
72+
@end
73+
74+
@implementation FIREqFunctionBridge {
75+
std::shared_ptr<Eq> eq;
76+
}
77+
- (id)initWithLeft:(FIRExprBridge *)left right:(FIRExprBridge *)right {
78+
self = [super init];
79+
if (self) {
80+
eq = std::make_shared<Eq>(left.cpp_expr, right.cpp_expr);
81+
}
82+
return self;
83+
}
84+
85+
- (std::shared_ptr<api::Expr>)cpp_expr {
86+
return eq;
87+
}
88+
89+
@end
90+
91+
@implementation FIRStageBridge
92+
@end
93+
94+
@implementation FIRCollectionSourceStageBridge {
95+
std::shared_ptr<CollectionSource> collection_source;
96+
}
97+
98+
- (id)initWithPath:(NSString *)path {
99+
self = [super init];
100+
if (self) {
101+
collection_source = std::make_shared<CollectionSource>(MakeString(path));
102+
}
103+
return self;
104+
}
105+
106+
- (std::shared_ptr<api::Stage>)cpp_stage {
107+
return collection_source;
108+
}
109+
110+
@end
111+
112+
@implementation FIRWhereStageBridge {
113+
std::shared_ptr<Where> where;
114+
}
115+
116+
- (id)initWithExpr:(FIRExprBridge *)expr {
117+
self = [super init];
118+
if (self) {
119+
where = std::make_shared<Where>(expr.cpp_expr);
120+
}
121+
return self;
122+
}
123+
124+
- (std::shared_ptr<api::Stage>)cpp_stage {
125+
return where;
126+
}
127+
128+
@end
129+
130+
@implementation __FIRPipelineSnapshotBridge {
131+
absl::optional<api::PipelineSnapshot> pipeline;
132+
}
133+
134+
- (id)initWithCppSnapshot:(api::PipelineSnapshot)snapshot {
135+
self = [super init];
136+
if (self) {
137+
pipeline = std::move(snapshot);
138+
}
139+
140+
return self;
141+
}
142+
143+
@end
144+
145+
@implementation FIRPipelineBridge {
146+
std::shared_ptr<Pipeline> pipeline;
147+
}
148+
149+
- (id)initWithStages:(NSArray<FIRStageBridge *> *)stages db:(FIRFirestore *)db {
150+
self = [super init];
151+
if (self) {
152+
std::vector<std::shared_ptr<firebase::firestore::api::Stage>> cpp_stages;
153+
for (FIRStageBridge *stage in stages) {
154+
cpp_stages.push_back(stage.cpp_stage);
155+
}
156+
pipeline = std::make_shared<Pipeline>(cpp_stages, db.wrapped);
157+
}
158+
return self;
159+
}
160+
161+
- (void)executeWithCompletion:(void (^)(__FIRPipelineSnapshotBridge *_Nullable result,
162+
NSError *_Nullable error))completion {
163+
pipeline->execute([completion](StatusOr<api::PipelineSnapshot> maybe_value) {
164+
if (maybe_value.ok()) {
165+
__FIRPipelineSnapshotBridge *bridge = [[__FIRPipelineSnapshotBridge alloc]
166+
initWithCppSnapshot:std::move(maybe_value).ValueOrDie()];
167+
completion(bridge, nil);
168+
} else {
169+
completion(nil, MakeNSError(std::move(maybe_value).status()));
170+
}
171+
});
172+
}
173+
174+
@end
175+
176+
NS_ASSUME_NONNULL_END
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
/*
2+
* Copyright 2025 Google
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#import "FIRFirestore.h"
18+
19+
#import <Foundation/Foundation.h>
20+
21+
NS_ASSUME_NONNULL_BEGIN
22+
23+
NS_SWIFT_NAME(ExprBridge)
24+
@interface FIRExprBridge : NSObject
25+
@end
26+
27+
NS_SWIFT_NAME(FieldBridge)
28+
@interface FIRFieldBridge : FIRExprBridge
29+
- (id)init:(NSString *)name;
30+
@end
31+
32+
NS_SWIFT_NAME(ConstantBridge)
33+
@interface FIRConstantBridge : FIRExprBridge
34+
- (id)init:(NSNumber *)value;
35+
@end
36+
37+
NS_SWIFT_NAME(EqFunctionBridge)
38+
@interface FIREqFunctionBridge : FIRExprBridge
39+
- (id)initWithLeft:(FIRExprBridge *)left right:(FIRExprBridge *)right;
40+
@end
41+
42+
NS_SWIFT_NAME(StageBridge)
43+
@interface FIRStageBridge : NSObject
44+
@end
45+
46+
NS_SWIFT_NAME(CollectionSourceStageBridge)
47+
@interface FIRCollectionSourceStageBridge : FIRStageBridge
48+
49+
- (id)initWithPath:(NSString *)path;
50+
51+
@end
52+
53+
NS_SWIFT_NAME(WhereStageBridge)
54+
@interface FIRWhereStageBridge : FIRStageBridge
55+
56+
- (id)initWithExpr:(FIRExprBridge *)expr;
57+
58+
@end
59+
60+
NS_SWIFT_NAME(__PipelineSnapshotBridge)
61+
@interface __FIRPipelineSnapshotBridge : NSObject
62+
63+
@property(nonatomic, strong, readonly) NSArray<__FIRPipelineSnapshotBridge *> *results;
64+
65+
@end
66+
67+
NS_SWIFT_NAME(__PipelineResultBridge)
68+
@interface __FIRPipelineResultBridge : NSObject
69+
70+
@property(nonatomic, strong, readonly) FIRDocumentReference *reference;
71+
72+
@property(nonatomic, copy, readonly) NSString *documentID;
73+
74+
- (nullable NSDictionary<NSString *, id> *)data;
75+
76+
@end
77+
78+
NS_SWIFT_NAME(PipelineBridge)
79+
@interface FIRPipelineBridge : NSObject
80+
81+
/** :nodoc: */
82+
- (id)initWithStages:(NSArray<FIRStageBridge *> *)stages db:(FIRFirestore *)db;
83+
84+
- (void)executeWithCompletion:(void (^)(__FIRPipelineSnapshotBridge *_Nullable result,
85+
NSError *_Nullable error))completion;
86+
87+
@end
88+
89+
NS_ASSUME_NONNULL_END

Firestore/Source/Public/FirebaseFirestore/FirebaseFirestore.h

+1
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
#import "FIRListenerRegistration.h"
3333
#import "FIRLoadBundleTask.h"
3434
#import "FIRLocalCacheSettings.h"
35+
#import "FIRPipelineBridge.h"
3536
#import "FIRQuery.h"
3637
#import "FIRQuerySnapshot.h"
3738
#import "FIRSnapshotListenOptions.h"

0 commit comments

Comments
 (0)