FIRPipelineBridge.mm 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996
  1. /*
  2. * Copyright 2025 Google LLC
  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. #import "FIRPipelineBridge.h"
  17. #import <FirebaseCore/FIRTimestamp.h>
  18. #include <memory>
  19. #import "Firestore/Source/API/FIRCollectionReference+Internal.h"
  20. #import "Firestore/Source/API/FIRDocumentReference+Internal.h"
  21. #import "Firestore/Source/API/FIRFieldPath+Internal.h"
  22. #import "Firestore/Source/API/FIRFirestore+Internal.h"
  23. #import "Firestore/Source/API/FIRPipelineBridge+Internal.h"
  24. #import "Firestore/Source/API/FSTUserDataReader.h"
  25. #import "Firestore/Source/API/FSTUserDataWriter.h"
  26. #import "Firestore/Source/API/converters.h"
  27. #import "Firestore/Source/Public/FirebaseFirestore/FIRVectorValue.h"
  28. #include "Firestore/Protos/nanopb/google/firestore/v1/document.nanopb.h"
  29. #include "Firestore/core/src/api/aggregate_expressions.h"
  30. #include "Firestore/core/src/api/document_reference.h"
  31. #include "Firestore/core/src/api/expressions.h"
  32. #include "Firestore/core/src/api/ordering.h"
  33. #include "Firestore/core/src/api/pipeline.h"
  34. #include "Firestore/core/src/api/pipeline_result.h"
  35. #include "Firestore/core/src/api/pipeline_snapshot.h"
  36. #include "Firestore/core/src/api/stages.h"
  37. #include "Firestore/core/src/util/comparison.h"
  38. #include "Firestore/core/src/util/error_apple.h"
  39. #include "Firestore/core/src/util/status.h"
  40. #include "Firestore/core/src/util/string_apple.h"
  41. using firebase::firestore::api::AddFields;
  42. using firebase::firestore::api::AddStage;
  43. using firebase::firestore::api::AggregateFunction;
  44. using firebase::firestore::api::AggregateStage;
  45. using firebase::firestore::api::CollectionGroupSource;
  46. using firebase::firestore::api::CollectionSource;
  47. using firebase::firestore::api::Constant;
  48. using firebase::firestore::api::DatabaseSource;
  49. using firebase::firestore::api::DistinctStage;
  50. using firebase::firestore::api::DocumentReference;
  51. using firebase::firestore::api::DocumentsSource;
  52. using firebase::firestore::api::Expr;
  53. using firebase::firestore::api::Field;
  54. using firebase::firestore::api::FindNearestStage;
  55. using firebase::firestore::api::FunctionExpr;
  56. using firebase::firestore::api::LimitStage;
  57. using firebase::firestore::api::MakeFIRTimestamp;
  58. using firebase::firestore::api::OffsetStage;
  59. using firebase::firestore::api::Ordering;
  60. using firebase::firestore::api::Pipeline;
  61. using firebase::firestore::api::RemoveFieldsStage;
  62. using firebase::firestore::api::ReplaceWith;
  63. using firebase::firestore::api::Sample;
  64. using firebase::firestore::api::SelectStage;
  65. using firebase::firestore::api::SortStage;
  66. using firebase::firestore::api::Union;
  67. using firebase::firestore::api::Unnest;
  68. using firebase::firestore::api::Where;
  69. using firebase::firestore::model::FieldPath;
  70. using firebase::firestore::nanopb::SharedMessage;
  71. using firebase::firestore::util::ComparisonResult;
  72. using firebase::firestore::util::MakeCallback;
  73. using firebase::firestore::util::MakeNSString;
  74. using firebase::firestore::util::MakeString;
  75. using firebase::firestore::util::ThrowInvalidArgument;
  76. NS_ASSUME_NONNULL_BEGIN
  77. inline std::string EnsureLeadingSlash(const std::string &path) {
  78. if (!path.empty() && path[0] == '/') {
  79. return path;
  80. }
  81. return "/" + path;
  82. }
  83. @implementation FIRExprBridge
  84. @end
  85. @implementation FIRFieldBridge {
  86. std::shared_ptr<Field> field;
  87. }
  88. - (id)init:(NSString *)name {
  89. self = [super init];
  90. if (self) {
  91. field = std::make_shared<Field>(MakeString(name));
  92. }
  93. return self;
  94. }
  95. - (std::shared_ptr<api::Expr>)cppExprWithReader:(FSTUserDataReader *)reader {
  96. return field;
  97. }
  98. @end
  99. @implementation FIRConstantBridge {
  100. std::shared_ptr<Constant> cpp_constant;
  101. id _input;
  102. Boolean isUserDataRead;
  103. }
  104. - (id)init:(id)input {
  105. self = [super init];
  106. _input = input;
  107. isUserDataRead = NO;
  108. return self;
  109. }
  110. - (std::shared_ptr<api::Expr>)cppExprWithReader:(FSTUserDataReader *)reader {
  111. if (!isUserDataRead) {
  112. cpp_constant = std::make_shared<Constant>([reader parsedQueryValue:_input]);
  113. }
  114. isUserDataRead = YES;
  115. return cpp_constant;
  116. }
  117. @end
  118. @implementation FIRFunctionExprBridge {
  119. std::shared_ptr<FunctionExpr> cpp_function;
  120. NSString *_name;
  121. NSArray<FIRExprBridge *> *_args;
  122. Boolean isUserDataRead;
  123. }
  124. - (nonnull id)initWithName:(NSString *)name Args:(nonnull NSArray<FIRExprBridge *> *)args {
  125. self = [super init];
  126. _name = name;
  127. _args = args;
  128. isUserDataRead = NO;
  129. return self;
  130. }
  131. - (std::shared_ptr<api::Expr>)cppExprWithReader:(FSTUserDataReader *)reader {
  132. if (!isUserDataRead) {
  133. std::vector<std::shared_ptr<Expr>> cpp_args;
  134. for (FIRExprBridge *arg in _args) {
  135. cpp_args.push_back([arg cppExprWithReader:reader]);
  136. }
  137. cpp_function = std::make_shared<FunctionExpr>(MakeString(_name), std::move(cpp_args));
  138. }
  139. isUserDataRead = YES;
  140. return cpp_function;
  141. }
  142. @end
  143. @implementation FIRAggregateFunctionBridge {
  144. std::shared_ptr<AggregateFunction> cpp_function;
  145. NSString *_name;
  146. NSArray<FIRExprBridge *> *_args;
  147. Boolean isUserDataRead;
  148. }
  149. - (nonnull id)initWithName:(NSString *)name Args:(nonnull NSArray<FIRExprBridge *> *)args {
  150. _name = name;
  151. _args = args;
  152. isUserDataRead = NO;
  153. return self;
  154. }
  155. - (std::shared_ptr<AggregateFunction>)cppExprWithReader:(FSTUserDataReader *)reader {
  156. if (!isUserDataRead) {
  157. std::vector<std::shared_ptr<Expr>> cpp_args;
  158. for (FIRExprBridge *arg in _args) {
  159. cpp_args.push_back([arg cppExprWithReader:reader]);
  160. }
  161. cpp_function = std::make_shared<AggregateFunction>(MakeString(_name), std::move(cpp_args));
  162. }
  163. isUserDataRead = YES;
  164. return cpp_function;
  165. }
  166. @end
  167. @implementation FIROrderingBridge {
  168. std::shared_ptr<Ordering> cpp_ordering;
  169. NSString *_direction;
  170. FIRExprBridge *_expr;
  171. Boolean isUserDataRead;
  172. }
  173. - (nonnull id)initWithExpr:(FIRExprBridge *)expr Direction:(NSString *)direction {
  174. _expr = expr;
  175. _direction = direction;
  176. isUserDataRead = NO;
  177. return self;
  178. }
  179. - (std::shared_ptr<Ordering>)cppOrderingWithReader:(FSTUserDataReader *)reader {
  180. if (!isUserDataRead) {
  181. cpp_ordering = std::make_shared<Ordering>(
  182. [_expr cppExprWithReader:reader], Ordering::DirectionFromString(MakeString(_direction)));
  183. }
  184. isUserDataRead = YES;
  185. return cpp_ordering;
  186. }
  187. @end
  188. @implementation FIRStageBridge
  189. @end
  190. @implementation FIRCollectionSourceStageBridge {
  191. std::shared_ptr<CollectionSource> collection_source;
  192. }
  193. - (id)initWithRef:(FIRCollectionReference *)ref firestore:(FIRFirestore *)db {
  194. self = [super init];
  195. if (self) {
  196. if (ref.firestore.databaseID.CompareTo(db.databaseID) != ComparisonResult::Same) {
  197. ThrowInvalidArgument(
  198. "Invalid CollectionReference. The project ID (\"%s\") or the database (\"%s\") does not "
  199. "match "
  200. "the project ID (\"%s\") and database (\"%s\") of the target database of this Pipeline.",
  201. ref.firestore.databaseID.project_id(), ref.firestore.databaseID.database_id(),
  202. db.databaseID.project_id(), db.databaseID.project_id());
  203. }
  204. collection_source =
  205. std::make_shared<CollectionSource>(EnsureLeadingSlash(MakeString(ref.path)));
  206. }
  207. return self;
  208. }
  209. - (std::shared_ptr<api::Stage>)cppStageWithReader:(FSTUserDataReader *)reader {
  210. return collection_source;
  211. }
  212. @end
  213. @implementation FIRDatabaseSourceStageBridge {
  214. std::shared_ptr<DatabaseSource> cpp_database_source;
  215. }
  216. - (id)init {
  217. self = [super init];
  218. if (self) {
  219. cpp_database_source = std::make_shared<DatabaseSource>();
  220. }
  221. return self;
  222. }
  223. - (std::shared_ptr<api::Stage>)cppStageWithReader:(FSTUserDataReader *)reader {
  224. return cpp_database_source;
  225. }
  226. @end
  227. @implementation FIRCollectionGroupSourceStageBridge {
  228. std::shared_ptr<CollectionGroupSource> cpp_collection_group_source;
  229. }
  230. - (id)initWithCollectionId:(NSString *)id {
  231. self = [super init];
  232. if (self) {
  233. cpp_collection_group_source = std::make_shared<CollectionGroupSource>(MakeString(id));
  234. }
  235. return self;
  236. }
  237. - (std::shared_ptr<api::Stage>)cppStageWithReader:(FSTUserDataReader *)reader {
  238. return cpp_collection_group_source;
  239. }
  240. @end
  241. @implementation FIRDocumentsSourceStageBridge {
  242. std::shared_ptr<DocumentsSource> cpp_document_source;
  243. }
  244. - (id)initWithDocuments:(NSArray<FIRDocumentReference *> *)documents firestore:(FIRFirestore *)db {
  245. self = [super init];
  246. if (self) {
  247. std::vector<std::string> cpp_documents;
  248. for (FIRDocumentReference *doc in documents) {
  249. if (doc.firestore.databaseID.CompareTo(db.databaseID) != ComparisonResult::Same) {
  250. ThrowInvalidArgument("Invalid DocumentReference. The project ID (\"%s\") or the database "
  251. "(\"%s\") does not match "
  252. "the project ID (\"%s\") and database (\"%s\") of the target database "
  253. "of this Pipeline.",
  254. doc.firestore.databaseID.project_id(),
  255. doc.firestore.databaseID.database_id(), db.databaseID.project_id(),
  256. db.databaseID.project_id());
  257. }
  258. cpp_documents.push_back(EnsureLeadingSlash(MakeString(doc.path)));
  259. }
  260. cpp_document_source = std::make_shared<DocumentsSource>(std::move(cpp_documents));
  261. }
  262. return self;
  263. }
  264. - (std::shared_ptr<api::Stage>)cppStageWithReader:(FSTUserDataReader *)reader {
  265. return cpp_document_source;
  266. }
  267. @end
  268. @implementation FIRWhereStageBridge {
  269. FIRExprBridge *_exprBridge;
  270. Boolean isUserDataRead;
  271. std::shared_ptr<Where> cpp_where;
  272. }
  273. - (id)initWithExpr:(FIRExprBridge *)expr {
  274. self = [super init];
  275. if (self) {
  276. _exprBridge = expr;
  277. isUserDataRead = NO;
  278. }
  279. return self;
  280. }
  281. - (std::shared_ptr<api::Stage>)cppStageWithReader:(FSTUserDataReader *)reader {
  282. if (!isUserDataRead) {
  283. cpp_where = std::make_shared<Where>([_exprBridge cppExprWithReader:reader]);
  284. }
  285. isUserDataRead = YES;
  286. return cpp_where;
  287. }
  288. @end
  289. @implementation FIRLimitStageBridge {
  290. Boolean isUserDataRead;
  291. std::shared_ptr<LimitStage> cpp_limit_stage;
  292. int32_t limit;
  293. }
  294. - (id)initWithLimit:(NSInteger)value {
  295. self = [super init];
  296. if (self) {
  297. isUserDataRead = NO;
  298. limit = static_cast<int32_t>(value);
  299. }
  300. return self;
  301. }
  302. - (std::shared_ptr<api::Stage>)cppStageWithReader:(FSTUserDataReader *)reader {
  303. if (!isUserDataRead) {
  304. cpp_limit_stage = std::make_shared<LimitStage>(limit);
  305. }
  306. isUserDataRead = YES;
  307. return cpp_limit_stage;
  308. }
  309. @end
  310. @implementation FIROffsetStageBridge {
  311. Boolean isUserDataRead;
  312. std::shared_ptr<OffsetStage> cpp_offset_stage;
  313. int32_t offset;
  314. }
  315. - (id)initWithOffset:(NSInteger)value {
  316. self = [super init];
  317. if (self) {
  318. isUserDataRead = NO;
  319. offset = static_cast<int32_t>(value);
  320. }
  321. return self;
  322. }
  323. - (std::shared_ptr<api::Stage>)cppStageWithReader:(FSTUserDataReader *)reader {
  324. if (!isUserDataRead) {
  325. cpp_offset_stage = std::make_shared<OffsetStage>(offset);
  326. }
  327. isUserDataRead = YES;
  328. return cpp_offset_stage;
  329. }
  330. @end
  331. // TBD
  332. @implementation FIRAddFieldsStageBridge {
  333. NSDictionary<NSString *, FIRExprBridge *> *_fields;
  334. Boolean isUserDataRead;
  335. std::shared_ptr<AddFields> cpp_add_fields;
  336. }
  337. - (id)initWithFields:(NSDictionary<NSString *, FIRExprBridge *> *)fields {
  338. self = [super init];
  339. if (self) {
  340. _fields = fields;
  341. isUserDataRead = NO;
  342. }
  343. return self;
  344. }
  345. - (std::shared_ptr<api::Stage>)cppStageWithReader:(FSTUserDataReader *)reader {
  346. if (!isUserDataRead) {
  347. std::unordered_map<std::string, std::shared_ptr<Expr>> cpp_fields;
  348. for (NSString *key in _fields) {
  349. cpp_fields[MakeString(key)] = [_fields[key] cppExprWithReader:reader];
  350. }
  351. cpp_add_fields = std::make_shared<AddFields>(std::move(cpp_fields));
  352. }
  353. isUserDataRead = YES;
  354. return cpp_add_fields;
  355. }
  356. @end
  357. @implementation FIRRemoveFieldsStageBridge {
  358. NSArray<NSString *> *_fields;
  359. Boolean isUserDataRead;
  360. std::shared_ptr<RemoveFieldsStage> cpp_remove_fields;
  361. }
  362. - (id)initWithFields:(NSArray<id> *)fields {
  363. self = [super init];
  364. if (self) {
  365. _fields = fields;
  366. isUserDataRead = NO;
  367. }
  368. return self;
  369. }
  370. - (std::shared_ptr<api::Stage>)cppStageWithReader:(FSTUserDataReader *)reader {
  371. if (!isUserDataRead) {
  372. std::vector<Field> cpp_fields;
  373. for (id field in _fields) {
  374. cpp_fields.push_back(Field(MakeString(field)));
  375. }
  376. cpp_remove_fields = std::make_shared<RemoveFieldsStage>(std::move(cpp_fields));
  377. }
  378. isUserDataRead = YES;
  379. return cpp_remove_fields;
  380. }
  381. @end
  382. @implementation FIRSelectStageBridge {
  383. NSDictionary<NSString *, FIRExprBridge *> *_selections;
  384. Boolean isUserDataRead;
  385. std::shared_ptr<SelectStage> cpp_select;
  386. }
  387. - (id)initWithSelections:(NSDictionary<NSString *, FIRExprBridge *> *)selections {
  388. self = [super init];
  389. if (self) {
  390. _selections = selections;
  391. isUserDataRead = NO;
  392. }
  393. return self;
  394. }
  395. - (std::shared_ptr<api::Stage>)cppStageWithReader:(FSTUserDataReader *)reader {
  396. if (!isUserDataRead) {
  397. std::unordered_map<std::string, std::shared_ptr<Expr>> cpp_selections;
  398. for (NSString *key in _selections) {
  399. cpp_selections[MakeString(key)] = [_selections[key] cppExprWithReader:reader];
  400. }
  401. cpp_select = std::make_shared<SelectStage>(std::move(cpp_selections));
  402. }
  403. isUserDataRead = YES;
  404. return cpp_select;
  405. }
  406. @end
  407. @implementation FIRDistinctStageBridge {
  408. NSDictionary<NSString *, FIRExprBridge *> *_groups;
  409. Boolean isUserDataRead;
  410. std::shared_ptr<DistinctStage> cpp_distinct;
  411. }
  412. - (id)initWithGroups:(NSDictionary<NSString *, FIRExprBridge *> *)groups {
  413. self = [super init];
  414. if (self) {
  415. _groups = groups;
  416. isUserDataRead = NO;
  417. }
  418. return self;
  419. }
  420. - (std::shared_ptr<api::Stage>)cppStageWithReader:(FSTUserDataReader *)reader {
  421. if (!isUserDataRead) {
  422. std::unordered_map<std::string, std::shared_ptr<Expr>> cpp_groups;
  423. for (NSString *key in _groups) {
  424. cpp_groups[MakeString(key)] = [_groups[key] cppExprWithReader:reader];
  425. }
  426. cpp_distinct = std::make_shared<DistinctStage>(std::move(cpp_groups));
  427. }
  428. isUserDataRead = YES;
  429. return cpp_distinct;
  430. }
  431. @end
  432. @implementation FIRAggregateStageBridge {
  433. NSDictionary<NSString *, FIRAggregateFunctionBridge *> *_accumulators;
  434. NSDictionary<NSString *, FIRExprBridge *> *_groups;
  435. Boolean isUserDataRead;
  436. std::shared_ptr<AggregateStage> cpp_aggregate;
  437. }
  438. - (id)initWithAccumulators:(NSDictionary<NSString *, FIRAggregateFunctionBridge *> *)accumulators
  439. groups:(NSDictionary<NSString *, FIRExprBridge *> *)groups {
  440. self = [super init];
  441. if (self) {
  442. _accumulators = accumulators;
  443. _groups = groups;
  444. isUserDataRead = NO;
  445. }
  446. return self;
  447. }
  448. - (std::shared_ptr<api::Stage>)cppStageWithReader:(FSTUserDataReader *)reader {
  449. if (!isUserDataRead) {
  450. std::unordered_map<std::string, std::shared_ptr<AggregateFunction>> cpp_accumulators;
  451. for (NSString *key in _accumulators) {
  452. cpp_accumulators[MakeString(key)] = [_accumulators[key] cppExprWithReader:reader];
  453. }
  454. std::unordered_map<std::string, std::shared_ptr<Expr>> cpp_groups;
  455. for (NSString *key in _groups) {
  456. cpp_groups[MakeString(key)] = [_groups[key] cppExprWithReader:reader];
  457. }
  458. cpp_aggregate =
  459. std::make_shared<AggregateStage>(std::move(cpp_accumulators), std::move(cpp_groups));
  460. }
  461. isUserDataRead = YES;
  462. return cpp_aggregate;
  463. }
  464. @end
  465. @implementation FIRFindNearestStageBridge {
  466. FIRFieldBridge *_field;
  467. FIRVectorValue *_vectorValue;
  468. NSString *_distanceMeasure;
  469. NSNumber *_limit;
  470. NSString *_Nullable _distanceField;
  471. Boolean isUserDataRead;
  472. std::shared_ptr<FindNearestStage> cpp_find_nearest;
  473. }
  474. - (id)initWithField:(FIRFieldBridge *)field
  475. vectorValue:(FIRVectorValue *)vectorValue
  476. distanceMeasure:(NSString *)distanceMeasure
  477. limit:(NSNumber *_Nullable)limit
  478. distanceField:(NSString *_Nullable)distanceField {
  479. self = [super init];
  480. if (self) {
  481. _field = field;
  482. _vectorValue = vectorValue;
  483. _distanceMeasure = distanceMeasure;
  484. _limit = limit;
  485. _distanceField = distanceField;
  486. isUserDataRead = NO;
  487. }
  488. return self;
  489. }
  490. - (std::shared_ptr<api::Stage>)cppStageWithReader:(FSTUserDataReader *)reader {
  491. if (!isUserDataRead) {
  492. std::unordered_map<std::string,
  493. nanopb::SharedMessage<firebase::firestore::google_firestore_v1_Value>>
  494. optional_value;
  495. if (_limit) {
  496. optional_value.emplace(
  497. std::make_pair(std::string("limit"),
  498. nanopb::SharedMessage<firebase::firestore::google_firestore_v1_Value>(
  499. [reader parsedQueryValue:_limit])));
  500. }
  501. if (_distanceField) {
  502. optional_value.emplace(
  503. std::make_pair(std::string("distance_field"),
  504. nanopb::SharedMessage<firebase::firestore::google_firestore_v1_Value>(
  505. [reader parsedQueryValue:_distanceField])));
  506. }
  507. FindNearestStage::DistanceMeasure::Measure measure_enum;
  508. if ([_distanceMeasure isEqualToString:@"cosine"]) {
  509. measure_enum = FindNearestStage::DistanceMeasure::COSINE;
  510. } else if ([_distanceMeasure isEqualToString:@"dot_product"]) {
  511. measure_enum = FindNearestStage::DistanceMeasure::DOT_PRODUCT;
  512. } else {
  513. measure_enum = FindNearestStage::DistanceMeasure::EUCLIDEAN;
  514. }
  515. cpp_find_nearest = std::make_shared<FindNearestStage>(
  516. [_field cppExprWithReader:reader], [reader parsedQueryValue:_vectorValue],
  517. FindNearestStage::DistanceMeasure(measure_enum), optional_value);
  518. }
  519. isUserDataRead = YES;
  520. return cpp_find_nearest;
  521. }
  522. @end
  523. @implementation FIRSorStageBridge {
  524. NSArray<FIROrderingBridge *> *_orderings;
  525. Boolean isUserDataRead;
  526. std::shared_ptr<SortStage> cpp_sort;
  527. }
  528. - (id)initWithOrderings:(NSArray<id> *)orderings {
  529. self = [super init];
  530. if (self) {
  531. _orderings = orderings;
  532. isUserDataRead = NO;
  533. }
  534. return self;
  535. }
  536. - (std::shared_ptr<api::Stage>)cppStageWithReader:(FSTUserDataReader *)reader {
  537. if (!isUserDataRead) {
  538. std::vector<std::shared_ptr<Ordering>> cpp_orderings;
  539. for (FIROrderingBridge *ordering in _orderings) {
  540. cpp_orderings.push_back([ordering cppOrderingWithReader:reader]);
  541. }
  542. cpp_sort = std::make_shared<SortStage>(std::move(cpp_orderings));
  543. }
  544. isUserDataRead = YES;
  545. return cpp_sort;
  546. }
  547. @end
  548. @implementation FIRReplaceWithStageBridge {
  549. FIRExprBridge *_expr;
  550. Boolean isUserDataRead;
  551. std::shared_ptr<ReplaceWith> cpp_replace_with;
  552. }
  553. - (id)initWithExpr:(FIRExprBridge *)expr {
  554. self = [super init];
  555. if (self) {
  556. _expr = expr;
  557. isUserDataRead = NO;
  558. }
  559. return self;
  560. }
  561. - (std::shared_ptr<api::Stage>)cppStageWithReader:(FSTUserDataReader *)reader {
  562. if (!isUserDataRead) {
  563. cpp_replace_with = std::make_shared<ReplaceWith>([_expr cppExprWithReader:reader]);
  564. }
  565. isUserDataRead = YES;
  566. return cpp_replace_with;
  567. }
  568. @end
  569. @implementation FIRSampleStageBridge {
  570. int64_t _count;
  571. double _percentage;
  572. Boolean isUserDataRead;
  573. NSString *type;
  574. std::shared_ptr<Sample> cpp_sample;
  575. }
  576. - (id)initWithCount:(int64_t)count {
  577. self = [super init];
  578. if (self) {
  579. _count = count;
  580. _percentage = 0;
  581. type = @"count";
  582. isUserDataRead = NO;
  583. }
  584. return self;
  585. }
  586. - (id)initWithPercentage:(double)percentage {
  587. self = [super init];
  588. if (self) {
  589. _percentage = percentage;
  590. _count = 0;
  591. type = @"percentage";
  592. isUserDataRead = NO;
  593. }
  594. return self;
  595. }
  596. - (std::shared_ptr<api::Stage>)cppStageWithReader:(FSTUserDataReader *)reader {
  597. if (!isUserDataRead) {
  598. if ([type isEqualToString:@"count"]) {
  599. cpp_sample = std::make_shared<Sample>("count", _count, 0);
  600. } else {
  601. cpp_sample = std::make_shared<Sample>("percentage", 0, _percentage);
  602. }
  603. }
  604. isUserDataRead = YES;
  605. return cpp_sample;
  606. }
  607. @end
  608. @implementation FIRUnionStageBridge {
  609. FIRPipelineBridge *_other;
  610. Boolean isUserDataRead;
  611. std::shared_ptr<Union> cpp_union_stage;
  612. }
  613. - (id)initWithOther:(FIRPipelineBridge *)other {
  614. self = [super init];
  615. if (self) {
  616. _other = other;
  617. isUserDataRead = NO;
  618. }
  619. return self;
  620. }
  621. - (std::shared_ptr<api::Stage>)cppStageWithReader:(FSTUserDataReader *)reader {
  622. if (!isUserDataRead) {
  623. cpp_union_stage = std::make_shared<Union>([_other cppPipelineWithReader:reader]);
  624. }
  625. isUserDataRead = YES;
  626. return cpp_union_stage;
  627. }
  628. @end
  629. @implementation FIRUnnestStageBridge {
  630. FIRExprBridge *_field;
  631. NSString *_Nullable _indexField;
  632. Boolean isUserDataRead;
  633. std::shared_ptr<Unnest> cpp_unnest;
  634. }
  635. - (id)initWithField:(FIRExprBridge *)field indexField:(NSString *_Nullable)indexField {
  636. self = [super init];
  637. if (self) {
  638. _field = field;
  639. _indexField = indexField;
  640. isUserDataRead = NO;
  641. }
  642. return self;
  643. }
  644. - (std::shared_ptr<api::Stage>)cppStageWithReader:(FSTUserDataReader *)reader {
  645. if (!isUserDataRead) {
  646. absl::optional<std::string> cpp_index_field;
  647. if (_indexField != nil) {
  648. cpp_index_field = MakeString(_indexField);
  649. } else {
  650. cpp_index_field = absl::nullopt;
  651. }
  652. cpp_unnest = std::make_shared<Unnest>([_field cppExprWithReader:reader], cpp_index_field);
  653. }
  654. isUserDataRead = YES;
  655. return cpp_unnest;
  656. }
  657. @end
  658. @implementation FIRAddStageBridge {
  659. NSString *_name;
  660. NSArray<FIRExprBridge *> *_params;
  661. NSDictionary<NSString *, FIRExprBridge *> *_Nullable _options;
  662. Boolean isUserDataRead;
  663. std::shared_ptr<AddStage> cpp_generic_stage;
  664. }
  665. - (id)initWithName:(NSString *)name
  666. params:(NSArray<FIRExprBridge *> *)params
  667. options:(NSDictionary<NSString *, FIRExprBridge *> *_Nullable)options {
  668. self = [super init];
  669. if (self) {
  670. _name = name;
  671. _params = params;
  672. _options = options;
  673. isUserDataRead = NO;
  674. }
  675. return self;
  676. }
  677. - (std::shared_ptr<api::Stage>)cppStageWithReader:(FSTUserDataReader *)reader {
  678. if (!isUserDataRead) {
  679. std::vector<std::shared_ptr<Expr>> cpp_params;
  680. for (FIRExprBridge *param in _params) {
  681. cpp_params.push_back([param cppExprWithReader:reader]);
  682. }
  683. std::unordered_map<std::string, std::shared_ptr<Expr>> cpp_options;
  684. if (_options) {
  685. for (NSString *key in _options) {
  686. cpp_options[MakeString(key)] = [_options[key] cppExprWithReader:reader];
  687. }
  688. }
  689. cpp_generic_stage = std::make_shared<AddStage>(MakeString(_name), std::move(cpp_params),
  690. std::move(cpp_options));
  691. }
  692. isUserDataRead = YES;
  693. return cpp_generic_stage;
  694. }
  695. @end
  696. @interface __FIRPipelineSnapshotBridge ()
  697. @property(nonatomic, strong, readwrite) NSArray<__FIRPipelineResultBridge *> *results;
  698. @end
  699. @implementation __FIRPipelineSnapshotBridge {
  700. absl::optional<api::PipelineSnapshot> snapshot_;
  701. NSMutableArray<__FIRPipelineResultBridge *> *results_;
  702. }
  703. - (id)initWithCppSnapshot:(api::PipelineSnapshot)snapshot {
  704. self = [super init];
  705. if (self) {
  706. snapshot_ = std::move(snapshot);
  707. if (!snapshot_.has_value()) {
  708. results_ = nil;
  709. } else {
  710. NSMutableArray<__FIRPipelineResultBridge *> *results = [NSMutableArray array];
  711. for (auto &result : snapshot_.value().results()) {
  712. [results addObject:[[__FIRPipelineResultBridge alloc]
  713. initWithCppResult:result
  714. db:snapshot_.value().firestore()]];
  715. }
  716. results_ = results;
  717. }
  718. }
  719. return self;
  720. }
  721. - (NSArray<__FIRPipelineResultBridge *> *)results {
  722. return results_;
  723. }
  724. - (FIRTimestamp *)execution_time {
  725. if (!snapshot_.has_value()) {
  726. return nil;
  727. } else {
  728. return MakeFIRTimestamp(snapshot_.value().execution_time().timestamp());
  729. }
  730. }
  731. @end
  732. @implementation __FIRPipelineResultBridge {
  733. api::PipelineResult _result;
  734. std::shared_ptr<api::Firestore> _db;
  735. }
  736. - (nullable FIRDocumentReference *)reference {
  737. if (!_result.internal_key().has_value()) return nil;
  738. return [[FIRDocumentReference alloc] initWithKey:_result.internal_key().value() firestore:_db];
  739. }
  740. - (nullable NSString *)documentID {
  741. if (!_result.document_id().has_value()) {
  742. return nil;
  743. }
  744. return MakeNSString(_result.document_id().value());
  745. }
  746. - (nullable FIRTimestamp *)create_time {
  747. if (!_result.create_time().has_value()) {
  748. return nil;
  749. }
  750. return MakeFIRTimestamp(_result.create_time().value().timestamp());
  751. }
  752. - (nullable FIRTimestamp *)update_time {
  753. if (!_result.update_time().has_value()) {
  754. return nil;
  755. }
  756. return MakeFIRTimestamp(_result.update_time().value().timestamp());
  757. }
  758. - (id)initWithCppResult:(api::PipelineResult)result db:(std::shared_ptr<api::Firestore>)db {
  759. self = [super init];
  760. if (self) {
  761. _result = std::move(result);
  762. _db = std::move(db);
  763. }
  764. return self;
  765. }
  766. - (NSDictionary<NSString *, id> *)data {
  767. return [self dataWithServerTimestampBehavior:FIRServerTimestampBehaviorNone];
  768. }
  769. - (NSDictionary<NSString *, id> *)dataWithServerTimestampBehavior:
  770. (FIRServerTimestampBehavior)serverTimestampBehavior {
  771. absl::optional<firebase::firestore::google_firestore_v1_Value> data =
  772. _result.internal_value()->Get();
  773. if (!data) return [NSDictionary dictionary];
  774. FSTUserDataWriter *dataWriter =
  775. [[FSTUserDataWriter alloc] initWithFirestore:_db
  776. serverTimestampBehavior:serverTimestampBehavior];
  777. return [dataWriter convertedValue:*data];
  778. }
  779. - (nullable id)get:(id)field {
  780. return [self get:field serverTimestampBehavior:FIRServerTimestampBehaviorNone];
  781. }
  782. - (nullable id)get:(id)field
  783. serverTimestampBehavior:(FIRServerTimestampBehavior)serverTimestampBehavior {
  784. FieldPath fieldPath;
  785. if ([field isKindOfClass:[NSString class]]) {
  786. fieldPath = FieldPath::FromDotSeparatedString(MakeString(field));
  787. } else if ([field isKindOfClass:[FIRFieldPath class]]) {
  788. fieldPath = ((FIRFieldPath *)field).internalValue;
  789. } else {
  790. ThrowInvalidArgument("Subscript key must be an NSString or FIRFieldPath.");
  791. }
  792. absl::optional<firebase::firestore::google_firestore_v1_Value> fieldValue =
  793. _result.internal_value()->Get(fieldPath);
  794. if (!fieldValue) return nil;
  795. FSTUserDataWriter *dataWriter =
  796. [[FSTUserDataWriter alloc] initWithFirestore:_db
  797. serverTimestampBehavior:serverTimestampBehavior];
  798. return [dataWriter convertedValue:*fieldValue];
  799. }
  800. @end
  801. @implementation FIRPipelineBridge {
  802. NSArray<FIRStageBridge *> *_stages;
  803. FIRFirestore *firestore;
  804. std::shared_ptr<Pipeline> cpp_pipeline;
  805. }
  806. - (id)initWithStages:(NSArray<FIRStageBridge *> *)stages db:(FIRFirestore *)db {
  807. _stages = stages;
  808. firestore = db;
  809. return [super init];
  810. }
  811. - (void)executeWithCompletion:(void (^)(__FIRPipelineSnapshotBridge *_Nullable result,
  812. NSError *_Nullable error))completion {
  813. std::vector<std::shared_ptr<firebase::firestore::api::Stage>> cpp_stages;
  814. for (FIRStageBridge *stage in _stages) {
  815. cpp_stages.push_back([stage cppStageWithReader:firestore.dataReader]);
  816. }
  817. cpp_pipeline = std::make_shared<Pipeline>(cpp_stages, firestore.wrapped);
  818. cpp_pipeline->execute([completion](StatusOr<api::PipelineSnapshot> maybe_value) {
  819. if (maybe_value.ok()) {
  820. __FIRPipelineSnapshotBridge *bridge = [[__FIRPipelineSnapshotBridge alloc]
  821. initWithCppSnapshot:std::move(maybe_value).ValueOrDie()];
  822. completion(bridge, nil);
  823. } else {
  824. completion(nil, MakeNSError(std::move(maybe_value).status()));
  825. }
  826. });
  827. }
  828. - (std::shared_ptr<api::Pipeline>)cppPipelineWithReader:(FSTUserDataReader *)reader {
  829. return cpp_pipeline;
  830. }
  831. @end
  832. NS_ASSUME_NONNULL_END