Skip to content

Commit c33f64a

Browse files
committed
[realppl 9] realppl public api and integration tests
1 parent f164452 commit c33f64a

28 files changed

+1466
-155
lines changed

Firestore/Example/Firestore.xcodeproj/project.pbxproj

Lines changed: 60 additions & 39 deletions
Large diffs are not rendered by default.

Firestore/Example/Tests/Util/FSTIntegrationTestCase.mm

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,8 @@ + (void)setUpDefaults {
193193
NSString *databaseId = [[NSProcessInfo processInfo] environment][@"TARGET_DATABASE_ID"];
194194
if (databaseId) {
195195
defaultDatabaseId = databaseId;
196+
} else {
197+
defaultDatabaseId = @"enterprise";
196198
}
197199

198200
// Check for a MobileHarness configuration, running against nightly or prod, which have live

Firestore/Source/API/FIRPipelineBridge+Internal.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "Firestore/core/src/api/expressions.h"
2222
#include "Firestore/core/src/api/firestore.h"
2323
#include "Firestore/core/src/api/pipeline.h"
24+
#include "Firestore/core/src/api/pipeline_result_change.h"
2425
#include "Firestore/core/src/api/stages.h"
2526

2627
@class FIRFilter;
@@ -59,6 +60,12 @@ NS_ASSUME_NONNULL_BEGIN
5960

6061
@end
6162

63+
@interface __FIRPipelineResultChangeBridge (Internal)
64+
65+
- (id)initWithCppChange:(api::PipelineResultChange)change db:(std::shared_ptr<api::Firestore>)db;
66+
67+
@end
68+
6269
@interface FIRPipelineBridge (Internal)
6370

6471
- (std::shared_ptr<api::Pipeline>)cppPipelineWithReader:(FSTUserDataReader *)reader;

Firestore/Source/API/FIRPipelineBridge.mm

Lines changed: 252 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@
2424
#import "Firestore/Source/API/FIRDocumentReference+Internal.h"
2525
#import "Firestore/Source/API/FIRFieldPath+Internal.h"
2626
#import "Firestore/Source/API/FIRFirestore+Internal.h"
27+
#import "Firestore/Source/API/FIRListenerRegistration+Internal.h"
2728
#import "Firestore/Source/API/FIRPipelineBridge+Internal.h"
29+
#import "Firestore/Source/API/FIRSnapshotMetadata+Internal.h"
2830
#import "Firestore/Source/API/FSTUserDataReader.h"
2931
#import "Firestore/Source/API/FSTUserDataWriter.h"
3032
#import "Firestore/Source/API/converters.h"
@@ -38,8 +40,17 @@
3840
#include "Firestore/core/src/api/ordering.h"
3941
#include "Firestore/core/src/api/pipeline.h"
4042
#include "Firestore/core/src/api/pipeline_result.h"
43+
#include "Firestore/core/src/api/pipeline_result_change.h"
4144
#include "Firestore/core/src/api/pipeline_snapshot.h"
45+
#include "Firestore/core/src/api/query_listener_registration.h"
46+
#include "Firestore/core/src/api/realtime_pipeline.h"
47+
#include "Firestore/core/src/api/realtime_pipeline_snapshot.h"
48+
#include "Firestore/core/src/api/snapshot_metadata.h"
4249
#include "Firestore/core/src/api/stages.h"
50+
#include "Firestore/core/src/core/event_listener.h"
51+
#include "Firestore/core/src/core/firestore_client.h"
52+
#include "Firestore/core/src/core/listen_options.h"
53+
#include "Firestore/core/src/core/view_snapshot.h"
4354
#include "Firestore/core/src/util/comparison.h"
4455
#include "Firestore/core/src/util/error_apple.h"
4556
#include "Firestore/core/src/util/status.h"
@@ -53,6 +64,7 @@
5364
using firebase::firestore::api::Constant;
5465
using firebase::firestore::api::DatabaseSource;
5566
using firebase::firestore::api::DistinctStage;
67+
using firebase::firestore::api::DocumentChange;
5668
using firebase::firestore::api::DocumentReference;
5769
using firebase::firestore::api::DocumentsSource;
5870
using firebase::firestore::api::Expr;
@@ -64,15 +76,22 @@
6476
using firebase::firestore::api::OffsetStage;
6577
using firebase::firestore::api::Ordering;
6678
using firebase::firestore::api::Pipeline;
79+
using firebase::firestore::api::PipelineResultChange;
80+
using firebase::firestore::api::QueryListenerRegistration;
81+
using firebase::firestore::api::RealtimePipeline;
82+
using firebase::firestore::api::RealtimePipelineSnapshot;
6783
using firebase::firestore::api::RawStage;
6884
using firebase::firestore::api::RemoveFieldsStage;
6985
using firebase::firestore::api::ReplaceWith;
7086
using firebase::firestore::api::Sample;
7187
using firebase::firestore::api::SelectStage;
88+
using firebase::firestore::api::SnapshotMetadata;
7289
using firebase::firestore::api::SortStage;
7390
using firebase::firestore::api::Union;
7491
using firebase::firestore::api::Unnest;
7592
using firebase::firestore::api::Where;
93+
using firebase::firestore::core::EventListener;
94+
using firebase::firestore::core::ViewSnapshot;
7695
using firebase::firestore::model::DeepClone;
7796
using firebase::firestore::model::FieldPath;
7897
using firebase::firestore::nanopb::MakeSharedMessage;
@@ -1016,6 +1035,48 @@ - (nullable id)get:(id)field
10161035

10171036
@end
10181037

1038+
@implementation __FIRPipelineResultChangeBridge {
1039+
api::PipelineResultChange change_;
1040+
std::shared_ptr<api::Firestore> db_;
1041+
}
1042+
1043+
- (FIRDocumentChangeType)type {
1044+
switch (change_.type()) {
1045+
case PipelineResultChange::Type::Added:
1046+
return FIRDocumentChangeTypeAdded;
1047+
case PipelineResultChange::Type::Modified:
1048+
return FIRDocumentChangeTypeModified;
1049+
case PipelineResultChange::Type::Removed:
1050+
return FIRDocumentChangeTypeRemoved;
1051+
}
1052+
1053+
HARD_FAIL("Unknown PipelineResultChange::Type: %s", change_.type());
1054+
}
1055+
1056+
- (__FIRPipelineResultBridge *)result {
1057+
return [[__FIRPipelineResultBridge alloc] initWithCppResult:change_.result() db:db_];
1058+
}
1059+
1060+
- (NSUInteger)oldIndex {
1061+
return change_.old_index() == PipelineResultChange::npos ? NSNotFound : change_.old_index();
1062+
}
1063+
1064+
- (NSUInteger)newIndex {
1065+
return change_.new_index() == PipelineResultChange::npos ? NSNotFound : change_.new_index();
1066+
}
1067+
1068+
- (id)initWithCppChange:(api::PipelineResultChange)change db:(std::shared_ptr<api::Firestore>)db {
1069+
self = [super init];
1070+
if (self) {
1071+
change_ = std::move(change);
1072+
db_ = std::move(db);
1073+
}
1074+
1075+
return self;
1076+
}
1077+
1078+
@end
1079+
10191080
@implementation FIRPipelineBridge {
10201081
NSArray<FIRStageBridge *> *_stages;
10211082
FIRFirestore *firestore;
@@ -1059,4 +1120,195 @@ - (void)executeWithCompletion:(void (^)(__FIRPipelineSnapshotBridge *_Nullable r
10591120

10601121
@end
10611122

1123+
@interface __FIRRealtimePipelineSnapshotBridge ()
1124+
1125+
@property(nonatomic, strong, readwrite) NSArray<__FIRPipelineResultBridge *> *results;
1126+
1127+
@property(nonatomic, strong, readwrite) NSArray<__FIRPipelineResultChangeBridge *> *changes;
1128+
1129+
@end
1130+
1131+
@implementation __FIRRealtimePipelineSnapshotBridge {
1132+
absl::optional<api::RealtimePipelineSnapshot> snapshot_;
1133+
NSMutableArray<__FIRPipelineResultBridge *> *results_;
1134+
NSMutableArray<__FIRPipelineResultChangeBridge *> *changes_;
1135+
FIRSnapshotMetadata *_metadata;
1136+
}
1137+
1138+
- (id)initWithCppSnapshot:(api::RealtimePipelineSnapshot)snapshot {
1139+
self = [super init];
1140+
if (self) {
1141+
snapshot_ = std::move(snapshot);
1142+
if (!snapshot_.has_value()) {
1143+
results_ = nil;
1144+
} else {
1145+
_metadata =
1146+
[[FIRSnapshotMetadata alloc] initWithMetadata:snapshot_.value().snapshot_metadata()];
1147+
1148+
NSMutableArray<__FIRPipelineResultBridge *> *results = [NSMutableArray array];
1149+
for (auto &result : snapshot_.value().view_snapshot().documents()) {
1150+
[results addObject:[[__FIRPipelineResultBridge alloc]
1151+
initWithCppResult:api::PipelineResult(result)
1152+
db:snapshot_.value().firestore()]];
1153+
}
1154+
results_ = results;
1155+
1156+
NSMutableArray<__FIRPipelineResultChangeBridge *> *changes = [NSMutableArray array];
1157+
for (auto &change : snapshot_.value().CalculateResultChanges(false)) {
1158+
[changes addObject:[[__FIRPipelineResultChangeBridge alloc]
1159+
initWithCppChange:change
1160+
db:snapshot_.value().firestore()]];
1161+
}
1162+
changes_ = changes;
1163+
}
1164+
}
1165+
1166+
return self;
1167+
}
1168+
1169+
- (NSArray<__FIRPipelineResultBridge *> *)results {
1170+
return results_;
1171+
}
1172+
1173+
- (NSArray<__FIRPipelineResultChangeBridge *> *)changes {
1174+
return changes_;
1175+
}
1176+
1177+
- (FIRSnapshotMetadata *)metadata {
1178+
return _metadata;
1179+
}
1180+
1181+
@end
1182+
1183+
@implementation __FIRPipelineListenOptionsBridge
1184+
1185+
- (instancetype)initWithServerTimestampBehavior:(NSString *)serverTimestampBehavior
1186+
includeMetadata:(BOOL)includeMetadata
1187+
source:(FIRListenSource)source {
1188+
// Call the designated initializer of the superclass (NSObject).
1189+
self = [super init];
1190+
if (self) {
1191+
// Assign the passed-in values to the backing instance variables
1192+
// for the readonly properties.
1193+
// We use `copy` here for the string to ensure our object owns an immutable version.
1194+
_serverTimestampBehavior = [serverTimestampBehavior copy];
1195+
_includeMetadata = includeMetadata;
1196+
_source = source;
1197+
}
1198+
return self;
1199+
}
1200+
1201+
@end
1202+
1203+
@implementation FIRRealtimePipelineBridge {
1204+
NSArray<FIRStageBridge *> *_stages;
1205+
FIRFirestore *firestore;
1206+
std::shared_ptr<api::RealtimePipeline> cpp_pipeline;
1207+
}
1208+
1209+
- (id)initWithStages:(NSArray<FIRStageBridge *> *)stages db:(FIRFirestore *)db {
1210+
_stages = stages;
1211+
firestore = db;
1212+
return [super init];
1213+
}
1214+
1215+
core::ListenOptions ToListenOptions(__FIRPipelineListenOptionsBridge *_Nullable bridge) {
1216+
// If the bridge object is nil, return a default-constructed ListenOptions.
1217+
if (bridge == nil) {
1218+
return core::ListenOptions::DefaultOptions();
1219+
}
1220+
1221+
// 1. Translate include_metadata_changes
1222+
bool include_metadata = bridge.includeMetadata;
1223+
1224+
// 2. Translate ListenSource
1225+
core::ListenSource source = core::ListenSource::Default;
1226+
switch (bridge.source) {
1227+
case FIRListenSourceDefault:
1228+
source = core::ListenSource::Default;
1229+
break;
1230+
case FIRListenSourceCache:
1231+
source = core::ListenSource::Cache;
1232+
break;
1233+
}
1234+
1235+
// 3. Translate ServerTimestampBehavior
1236+
core::ListenOptions::ServerTimestampBehavior behavior =
1237+
core::ListenOptions::ServerTimestampBehavior::kNone;
1238+
if ([bridge.serverTimestampBehavior isEqual:@"estimate"]) {
1239+
behavior = core::ListenOptions::ServerTimestampBehavior::kEstimate;
1240+
} else if ([bridge.serverTimestampBehavior isEqual:@"previous"]) {
1241+
behavior = core::ListenOptions::ServerTimestampBehavior::kPrevious;
1242+
} else {
1243+
// "none" or any other value defaults to kNone.
1244+
behavior = core::ListenOptions::ServerTimestampBehavior::kNone;
1245+
}
1246+
1247+
// 4. Construct the final C++ object using the canonical private constructor.
1248+
// Note: wait_for_sync_when_online is not part of the bridge, so we use 'false'
1249+
// to match the behavior of the existing static factories.
1250+
return core::ListenOptions(
1251+
/*include_query_metadata_changes=*/include_metadata,
1252+
/*include_document_metadata_changes=*/include_metadata,
1253+
/*wait_for_sync_when_online=*/false, source, behavior);
1254+
}
1255+
1256+
- (id<FIRListenerRegistration>)
1257+
addSnapshotListenerWithOptions:(__FIRPipelineListenOptionsBridge *)options
1258+
listener:
1259+
(void (^)(__FIRRealtimePipelineSnapshotBridge *_Nullable snapshot,
1260+
NSError *_Nullable error))listener {
1261+
std::shared_ptr<api::Firestore> wrapped_firestore = firestore.wrapped;
1262+
1263+
std::vector<std::shared_ptr<firebase::firestore::api::EvaluableStage>> cpp_stages;
1264+
for (FIRStageBridge *stage in _stages) {
1265+
auto evaluable_stage = std::dynamic_pointer_cast<api::EvaluableStage>(
1266+
[stage cppStageWithReader:firestore.dataReader]);
1267+
if (evaluable_stage) {
1268+
cpp_stages.push_back(evaluable_stage);
1269+
} else {
1270+
HARD_FAIL("Failed to convert cpp stage to EvaluableStage for RealtimePipeline");
1271+
}
1272+
}
1273+
1274+
cpp_pipeline = std::make_shared<RealtimePipeline>(
1275+
cpp_stages, std::make_unique<remote::Serializer>(wrapped_firestore->database_id()));
1276+
1277+
// Convert from ViewSnapshots to RealtimePipelineSnapshots.
1278+
auto view_listener = EventListener<ViewSnapshot>::Create(
1279+
[listener, wrapped_firestore](StatusOr<ViewSnapshot> maybe_snapshot) {
1280+
if (!maybe_snapshot.status().ok()) {
1281+
listener(nil, MakeNSError(maybe_snapshot.status()));
1282+
return;
1283+
}
1284+
1285+
ViewSnapshot snapshot = std::move(maybe_snapshot).ValueOrDie();
1286+
SnapshotMetadata metadata(snapshot.has_pending_writes(), snapshot.from_cache());
1287+
1288+
listener(
1289+
[[__FIRRealtimePipelineSnapshotBridge alloc]
1290+
initWithCppSnapshot:RealtimePipelineSnapshot(wrapped_firestore, std::move(snapshot),
1291+
std::move(metadata))],
1292+
nil);
1293+
});
1294+
1295+
// Call the view_listener on the user Executor.
1296+
auto async_listener = core::AsyncEventListener<ViewSnapshot>::Create(
1297+
wrapped_firestore->client()->user_executor(), std::move(view_listener));
1298+
1299+
std::shared_ptr<core::QueryListener> query_listener = wrapped_firestore->client()->ListenToQuery(
1300+
*cpp_pipeline, ToListenOptions(options), async_listener);
1301+
1302+
return [[FSTListenerRegistration alloc]
1303+
initWithRegistration:absl::make_unique<QueryListenerRegistration>(wrapped_firestore->client(),
1304+
std::move(async_listener),
1305+
std::move(query_listener))];
1306+
}
1307+
1308+
- (std::shared_ptr<api::RealtimePipeline>)cppPipelineWithReader:(FSTUserDataReader *)reader {
1309+
return cpp_pipeline;
1310+
}
1311+
1312+
@end
1313+
10621314
NS_ASSUME_NONNULL_END

0 commit comments

Comments
 (0)