Skip to content

Commit 01df95f

Browse files
committed
[realppl 9] realppl public api and integration tests
1 parent 8139cf4 commit 01df95f

28 files changed

+1463
-148
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
@@ -23,7 +23,9 @@
2323
#import "Firestore/Source/API/FIRDocumentReference+Internal.h"
2424
#import "Firestore/Source/API/FIRFieldPath+Internal.h"
2525
#import "Firestore/Source/API/FIRFirestore+Internal.h"
26+
#import "Firestore/Source/API/FIRListenerRegistration+Internal.h"
2627
#import "Firestore/Source/API/FIRPipelineBridge+Internal.h"
28+
#import "Firestore/Source/API/FIRSnapshotMetadata+Internal.h"
2729
#import "Firestore/Source/API/FSTUserDataReader.h"
2830
#import "Firestore/Source/API/FSTUserDataWriter.h"
2931
#import "Firestore/Source/API/converters.h"
@@ -37,8 +39,17 @@
3739
#include "Firestore/core/src/api/ordering.h"
3840
#include "Firestore/core/src/api/pipeline.h"
3941
#include "Firestore/core/src/api/pipeline_result.h"
42+
#include "Firestore/core/src/api/pipeline_result_change.h"
4043
#include "Firestore/core/src/api/pipeline_snapshot.h"
44+
#include "Firestore/core/src/api/query_listener_registration.h"
45+
#include "Firestore/core/src/api/realtime_pipeline.h"
46+
#include "Firestore/core/src/api/realtime_pipeline_snapshot.h"
47+
#include "Firestore/core/src/api/snapshot_metadata.h"
4148
#include "Firestore/core/src/api/stages.h"
49+
#include "Firestore/core/src/core/event_listener.h"
50+
#include "Firestore/core/src/core/firestore_client.h"
51+
#include "Firestore/core/src/core/listen_options.h"
52+
#include "Firestore/core/src/core/view_snapshot.h"
4253
#include "Firestore/core/src/util/error_apple.h"
4354
#include "Firestore/core/src/util/status.h"
4455
#include "Firestore/core/src/util/string_apple.h"
@@ -51,6 +62,7 @@
5162
using firebase::firestore::api::Constant;
5263
using firebase::firestore::api::DatabaseSource;
5364
using firebase::firestore::api::DistinctStage;
65+
using firebase::firestore::api::DocumentChange;
5466
using firebase::firestore::api::DocumentReference;
5567
using firebase::firestore::api::DocumentsSource;
5668
using firebase::firestore::api::Expr;
@@ -63,14 +75,21 @@
6375
using firebase::firestore::api::OffsetStage;
6476
using firebase::firestore::api::Ordering;
6577
using firebase::firestore::api::Pipeline;
78+
using firebase::firestore::api::PipelineResultChange;
79+
using firebase::firestore::api::QueryListenerRegistration;
80+
using firebase::firestore::api::RealtimePipeline;
81+
using firebase::firestore::api::RealtimePipelineSnapshot;
6682
using firebase::firestore::api::RemoveFieldsStage;
6783
using firebase::firestore::api::ReplaceWith;
6884
using firebase::firestore::api::Sample;
6985
using firebase::firestore::api::SelectStage;
86+
using firebase::firestore::api::SnapshotMetadata;
7087
using firebase::firestore::api::SortStage;
7188
using firebase::firestore::api::Union;
7289
using firebase::firestore::api::Unnest;
7390
using firebase::firestore::api::Where;
91+
using firebase::firestore::core::EventListener;
92+
using firebase::firestore::core::ViewSnapshot;
7493
using firebase::firestore::model::FieldPath;
7594
using firebase::firestore::nanopb::SharedMessage;
7695
using firebase::firestore::util::MakeCallback;
@@ -928,6 +947,48 @@ - (nullable id)get:(id)field
928947

929948
@end
930949

950+
@implementation __FIRPipelineResultChangeBridge {
951+
api::PipelineResultChange change_;
952+
std::shared_ptr<api::Firestore> db_;
953+
}
954+
955+
- (FIRDocumentChangeType)type {
956+
switch (change_.type()) {
957+
case PipelineResultChange::Type::Added:
958+
return FIRDocumentChangeTypeAdded;
959+
case PipelineResultChange::Type::Modified:
960+
return FIRDocumentChangeTypeModified;
961+
case PipelineResultChange::Type::Removed:
962+
return FIRDocumentChangeTypeRemoved;
963+
}
964+
965+
HARD_FAIL("Unknown PipelineResultChange::Type: %s", change_.type());
966+
}
967+
968+
- (__FIRPipelineResultBridge *)result {
969+
return [[__FIRPipelineResultBridge alloc] initWithCppResult:change_.result() db:db_];
970+
}
971+
972+
- (NSUInteger)oldIndex {
973+
return change_.old_index() == PipelineResultChange::npos ? NSNotFound : change_.old_index();
974+
}
975+
976+
- (NSUInteger)newIndex {
977+
return change_.new_index() == PipelineResultChange::npos ? NSNotFound : change_.new_index();
978+
}
979+
980+
- (id)initWithCppChange:(api::PipelineResultChange)change db:(std::shared_ptr<api::Firestore>)db {
981+
self = [super init];
982+
if (self) {
983+
change_ = std::move(change);
984+
db_ = std::move(db);
985+
}
986+
987+
return self;
988+
}
989+
990+
@end
991+
931992
@implementation FIRPipelineBridge {
932993
NSArray<FIRStageBridge *> *_stages;
933994
FIRFirestore *firestore;
@@ -965,4 +1026,195 @@ - (void)executeWithCompletion:(void (^)(__FIRPipelineSnapshotBridge *_Nullable r
9651026

9661027
@end
9671028

1029+
@interface __FIRRealtimePipelineSnapshotBridge ()
1030+
1031+
@property(nonatomic, strong, readwrite) NSArray<__FIRPipelineResultBridge *> *results;
1032+
1033+
@property(nonatomic, strong, readwrite) NSArray<__FIRPipelineResultChangeBridge *> *changes;
1034+
1035+
@end
1036+
1037+
@implementation __FIRRealtimePipelineSnapshotBridge {
1038+
absl::optional<api::RealtimePipelineSnapshot> snapshot_;
1039+
NSMutableArray<__FIRPipelineResultBridge *> *results_;
1040+
NSMutableArray<__FIRPipelineResultChangeBridge *> *changes_;
1041+
FIRSnapshotMetadata *_metadata;
1042+
}
1043+
1044+
- (id)initWithCppSnapshot:(api::RealtimePipelineSnapshot)snapshot {
1045+
self = [super init];
1046+
if (self) {
1047+
snapshot_ = std::move(snapshot);
1048+
if (!snapshot_.has_value()) {
1049+
results_ = nil;
1050+
} else {
1051+
_metadata =
1052+
[[FIRSnapshotMetadata alloc] initWithMetadata:snapshot_.value().snapshot_metadata()];
1053+
1054+
NSMutableArray<__FIRPipelineResultBridge *> *results = [NSMutableArray array];
1055+
for (auto &result : snapshot_.value().view_snapshot().documents()) {
1056+
[results addObject:[[__FIRPipelineResultBridge alloc]
1057+
initWithCppResult:api::PipelineResult(result)
1058+
db:snapshot_.value().firestore()]];
1059+
}
1060+
results_ = results;
1061+
1062+
NSMutableArray<__FIRPipelineResultChangeBridge *> *changes = [NSMutableArray array];
1063+
for (auto &change : snapshot_.value().CalculateResultChanges(false)) {
1064+
[changes addObject:[[__FIRPipelineResultChangeBridge alloc]
1065+
initWithCppChange:change
1066+
db:snapshot_.value().firestore()]];
1067+
}
1068+
changes_ = changes;
1069+
}
1070+
}
1071+
1072+
return self;
1073+
}
1074+
1075+
- (NSArray<__FIRPipelineResultBridge *> *)results {
1076+
return results_;
1077+
}
1078+
1079+
- (NSArray<__FIRPipelineResultChangeBridge *> *)changes {
1080+
return changes_;
1081+
}
1082+
1083+
- (FIRSnapshotMetadata *)metadata {
1084+
return _metadata;
1085+
}
1086+
1087+
@end
1088+
1089+
@implementation __FIRPipelineListenOptionsBridge
1090+
1091+
- (instancetype)initWithServerTimestampBehavior:(NSString *)serverTimestampBehavior
1092+
includeMetadata:(BOOL)includeMetadata
1093+
source:(FIRListenSource)source {
1094+
// Call the designated initializer of the superclass (NSObject).
1095+
self = [super init];
1096+
if (self) {
1097+
// Assign the passed-in values to the backing instance variables
1098+
// for the readonly properties.
1099+
// We use `copy` here for the string to ensure our object owns an immutable version.
1100+
_serverTimestampBehavior = [serverTimestampBehavior copy];
1101+
_includeMetadata = includeMetadata;
1102+
_source = source;
1103+
}
1104+
return self;
1105+
}
1106+
1107+
@end
1108+
1109+
@implementation FIRRealtimePipelineBridge {
1110+
NSArray<FIRStageBridge *> *_stages;
1111+
FIRFirestore *firestore;
1112+
std::shared_ptr<api::RealtimePipeline> cpp_pipeline;
1113+
}
1114+
1115+
- (id)initWithStages:(NSArray<FIRStageBridge *> *)stages db:(FIRFirestore *)db {
1116+
_stages = stages;
1117+
firestore = db;
1118+
return [super init];
1119+
}
1120+
1121+
core::ListenOptions ToListenOptions(__FIRPipelineListenOptionsBridge *_Nullable bridge) {
1122+
// If the bridge object is nil, return a default-constructed ListenOptions.
1123+
if (bridge == nil) {
1124+
return core::ListenOptions::DefaultOptions();
1125+
}
1126+
1127+
// 1. Translate include_metadata_changes
1128+
bool include_metadata = bridge.includeMetadata;
1129+
1130+
// 2. Translate ListenSource
1131+
core::ListenSource source = core::ListenSource::Default;
1132+
switch (bridge.source) {
1133+
case FIRListenSourceDefault:
1134+
source = core::ListenSource::Default;
1135+
break;
1136+
case FIRListenSourceCache:
1137+
source = core::ListenSource::Cache;
1138+
break;
1139+
}
1140+
1141+
// 3. Translate ServerTimestampBehavior
1142+
core::ListenOptions::ServerTimestampBehavior behavior =
1143+
core::ListenOptions::ServerTimestampBehavior::kNone;
1144+
if ([bridge.serverTimestampBehavior isEqual:@"estimate"]) {
1145+
behavior = core::ListenOptions::ServerTimestampBehavior::kEstimate;
1146+
} else if ([bridge.serverTimestampBehavior isEqual:@"previous"]) {
1147+
behavior = core::ListenOptions::ServerTimestampBehavior::kPrevious;
1148+
} else {
1149+
// "none" or any other value defaults to kNone.
1150+
behavior = core::ListenOptions::ServerTimestampBehavior::kNone;
1151+
}
1152+
1153+
// 4. Construct the final C++ object using the canonical private constructor.
1154+
// Note: wait_for_sync_when_online is not part of the bridge, so we use 'false'
1155+
// to match the behavior of the existing static factories.
1156+
return core::ListenOptions(
1157+
/*include_query_metadata_changes=*/include_metadata,
1158+
/*include_document_metadata_changes=*/include_metadata,
1159+
/*wait_for_sync_when_online=*/false, source, behavior);
1160+
}
1161+
1162+
- (id<FIRListenerRegistration>)
1163+
addSnapshotListenerWithOptions:(__FIRPipelineListenOptionsBridge *)options
1164+
listener:
1165+
(void (^)(__FIRRealtimePipelineSnapshotBridge *_Nullable snapshot,
1166+
NSError *_Nullable error))listener {
1167+
std::shared_ptr<api::Firestore> wrapped_firestore = firestore.wrapped;
1168+
1169+
std::vector<std::shared_ptr<firebase::firestore::api::EvaluableStage>> cpp_stages;
1170+
for (FIRStageBridge *stage in _stages) {
1171+
auto evaluable_stage = std::dynamic_pointer_cast<api::EvaluableStage>(
1172+
[stage cppStageWithReader:firestore.dataReader]);
1173+
if (evaluable_stage) {
1174+
cpp_stages.push_back(evaluable_stage);
1175+
} else {
1176+
HARD_FAIL("Failed to convert cpp stage to EvaluableStage for RealtimePipeline");
1177+
}
1178+
}
1179+
1180+
cpp_pipeline = std::make_shared<RealtimePipeline>(
1181+
cpp_stages, std::make_unique<remote::Serializer>(wrapped_firestore->database_id()));
1182+
1183+
// Convert from ViewSnapshots to RealtimePipelineSnapshots.
1184+
auto view_listener = EventListener<ViewSnapshot>::Create(
1185+
[listener, wrapped_firestore](StatusOr<ViewSnapshot> maybe_snapshot) {
1186+
if (!maybe_snapshot.status().ok()) {
1187+
listener(nil, MakeNSError(maybe_snapshot.status()));
1188+
return;
1189+
}
1190+
1191+
ViewSnapshot snapshot = std::move(maybe_snapshot).ValueOrDie();
1192+
SnapshotMetadata metadata(snapshot.has_pending_writes(), snapshot.from_cache());
1193+
1194+
listener(
1195+
[[__FIRRealtimePipelineSnapshotBridge alloc]
1196+
initWithCppSnapshot:RealtimePipelineSnapshot(wrapped_firestore, std::move(snapshot),
1197+
std::move(metadata))],
1198+
nil);
1199+
});
1200+
1201+
// Call the view_listener on the user Executor.
1202+
auto async_listener = core::AsyncEventListener<ViewSnapshot>::Create(
1203+
wrapped_firestore->client()->user_executor(), std::move(view_listener));
1204+
1205+
std::shared_ptr<core::QueryListener> query_listener = wrapped_firestore->client()->ListenToQuery(
1206+
*cpp_pipeline, ToListenOptions(options), async_listener);
1207+
1208+
return [[FSTListenerRegistration alloc]
1209+
initWithRegistration:absl::make_unique<QueryListenerRegistration>(wrapped_firestore->client(),
1210+
std::move(async_listener),
1211+
std::move(query_listener))];
1212+
}
1213+
1214+
- (std::shared_ptr<api::RealtimePipeline>)cppPipelineWithReader:(FSTUserDataReader *)reader {
1215+
return cpp_pipeline;
1216+
}
1217+
1218+
@end
1219+
9681220
NS_ASSUME_NONNULL_END

0 commit comments

Comments
 (0)