FIRPipelineBridge.mm 30 KB

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