FSTSerializerBeta.mm 48 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257
  1. /*
  2. * Copyright 2017 Google
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #import "Firestore/Source/Remote/FSTSerializerBeta.h"
  17. #include <algorithm>
  18. #include <cinttypes>
  19. #include <set>
  20. #include <string>
  21. #include <utility>
  22. #include <vector>
  23. #import "Firestore/Protos/objc/google/firestore/v1/Common.pbobjc.h"
  24. #import "Firestore/Protos/objc/google/firestore/v1/Document.pbobjc.h"
  25. #import "Firestore/Protos/objc/google/firestore/v1/Firestore.pbobjc.h"
  26. #import "Firestore/Protos/objc/google/firestore/v1/Query.pbobjc.h"
  27. #import "Firestore/Protos/objc/google/firestore/v1/Write.pbobjc.h"
  28. #import "Firestore/Protos/objc/google/rpc/Status.pbobjc.h"
  29. #import "Firestore/Protos/objc/google/type/Latlng.pbobjc.h"
  30. #import "FIRFirestoreErrors.h"
  31. #import "FIRGeoPoint.h"
  32. #import "FIRTimestamp.h"
  33. #include "Firestore/core/include/firebase/firestore/firestore_errors.h"
  34. #include "Firestore/core/include/firebase/firestore/geo_point.h"
  35. #include "Firestore/core/src/firebase/firestore/core/bound.h"
  36. #include "Firestore/core/src/firebase/firestore/core/field_filter.h"
  37. #include "Firestore/core/src/firebase/firestore/core/filter.h"
  38. #include "Firestore/core/src/firebase/firestore/core/query.h"
  39. #include "Firestore/core/src/firebase/firestore/local/query_data.h"
  40. #include "Firestore/core/src/firebase/firestore/model/database_id.h"
  41. #include "Firestore/core/src/firebase/firestore/model/delete_mutation.h"
  42. #include "Firestore/core/src/firebase/firestore/model/document.h"
  43. #include "Firestore/core/src/firebase/firestore/model/document_key.h"
  44. #include "Firestore/core/src/firebase/firestore/model/field_mask.h"
  45. #include "Firestore/core/src/firebase/firestore/model/field_path.h"
  46. #include "Firestore/core/src/firebase/firestore/model/field_transform.h"
  47. #include "Firestore/core/src/firebase/firestore/model/field_value.h"
  48. #include "Firestore/core/src/firebase/firestore/model/maybe_document.h"
  49. #include "Firestore/core/src/firebase/firestore/model/no_document.h"
  50. #include "Firestore/core/src/firebase/firestore/model/patch_mutation.h"
  51. #include "Firestore/core/src/firebase/firestore/model/precondition.h"
  52. #include "Firestore/core/src/firebase/firestore/model/resource_path.h"
  53. #include "Firestore/core/src/firebase/firestore/model/set_mutation.h"
  54. #include "Firestore/core/src/firebase/firestore/model/transform_mutation.h"
  55. #include "Firestore/core/src/firebase/firestore/model/transform_operation.h"
  56. #include "Firestore/core/src/firebase/firestore/model/unknown_document.h"
  57. #include "Firestore/core/src/firebase/firestore/nanopb/byte_string.h"
  58. #include "Firestore/core/src/firebase/firestore/nanopb/nanopb_util.h"
  59. #include "Firestore/core/src/firebase/firestore/remote/existence_filter.h"
  60. #include "Firestore/core/src/firebase/firestore/remote/watch_change.h"
  61. #include "Firestore/core/src/firebase/firestore/util/hard_assert.h"
  62. #include "Firestore/core/src/firebase/firestore/util/status.h"
  63. #include "Firestore/core/src/firebase/firestore/util/string_apple.h"
  64. #include "absl/memory/memory.h"
  65. #include "absl/types/optional.h"
  66. namespace util = firebase::firestore::util;
  67. using firebase::Timestamp;
  68. using firebase::firestore::Error;
  69. using firebase::firestore::GeoPoint;
  70. using firebase::firestore::core::Bound;
  71. using firebase::firestore::core::CollectionGroupId;
  72. using firebase::firestore::core::Direction;
  73. using firebase::firestore::core::FieldFilter;
  74. using firebase::firestore::core::Filter;
  75. using firebase::firestore::core::FilterList;
  76. using firebase::firestore::core::OrderBy;
  77. using firebase::firestore::core::OrderByList;
  78. using firebase::firestore::core::Query;
  79. using firebase::firestore::local::QueryData;
  80. using firebase::firestore::local::QueryPurpose;
  81. using firebase::firestore::model::ArrayTransform;
  82. using firebase::firestore::model::DatabaseId;
  83. using firebase::firestore::model::DeleteMutation;
  84. using firebase::firestore::model::Document;
  85. using firebase::firestore::model::DocumentKey;
  86. using firebase::firestore::model::DocumentState;
  87. using firebase::firestore::model::FieldMask;
  88. using firebase::firestore::model::FieldPath;
  89. using firebase::firestore::model::FieldTransform;
  90. using firebase::firestore::model::FieldValue;
  91. using firebase::firestore::model::MaybeDocument;
  92. using firebase::firestore::model::Mutation;
  93. using firebase::firestore::model::MutationResult;
  94. using firebase::firestore::model::NoDocument;
  95. using firebase::firestore::model::NumericIncrementTransform;
  96. using firebase::firestore::model::ObjectValue;
  97. using firebase::firestore::model::PatchMutation;
  98. using firebase::firestore::model::Precondition;
  99. using firebase::firestore::model::ResourcePath;
  100. using firebase::firestore::model::ServerTimestampTransform;
  101. using firebase::firestore::model::SetMutation;
  102. using firebase::firestore::model::SnapshotVersion;
  103. using firebase::firestore::model::TargetId;
  104. using firebase::firestore::model::TransformMutation;
  105. using firebase::firestore::model::TransformOperation;
  106. using firebase::firestore::model::UnknownDocument;
  107. using firebase::firestore::nanopb::ByteString;
  108. using firebase::firestore::nanopb::MakeByteString;
  109. using firebase::firestore::nanopb::MakeNSData;
  110. using firebase::firestore::remote::DocumentWatchChange;
  111. using firebase::firestore::remote::ExistenceFilter;
  112. using firebase::firestore::remote::ExistenceFilterWatchChange;
  113. using firebase::firestore::remote::WatchChange;
  114. using firebase::firestore::remote::WatchTargetChange;
  115. using firebase::firestore::remote::WatchTargetChangeState;
  116. using Operator = Filter::Operator;
  117. NS_ASSUME_NONNULL_BEGIN
  118. namespace {
  119. absl::any Wrap(GCFSDocument *doc) {
  120. return absl::make_any<GCFSDocument *>(doc);
  121. }
  122. } // namespace
  123. @implementation FSTSerializerBeta {
  124. DatabaseId _databaseID;
  125. }
  126. - (instancetype)initWithDatabaseID:(DatabaseId)databaseID {
  127. self = [super init];
  128. if (self) {
  129. _databaseID = std::move(databaseID);
  130. }
  131. return self;
  132. }
  133. #pragma mark - SnapshotVersion <=> GPBTimestamp
  134. - (GPBTimestamp *)encodedTimestamp:(const Timestamp &)timestamp {
  135. GPBTimestamp *result = [GPBTimestamp message];
  136. result.seconds = timestamp.seconds();
  137. result.nanos = timestamp.nanoseconds();
  138. return result;
  139. }
  140. - (Timestamp)decodedTimestamp:(GPBTimestamp *)timestamp {
  141. return Timestamp{timestamp.seconds, timestamp.nanos};
  142. }
  143. - (GPBTimestamp *)encodedVersion:(const SnapshotVersion &)version {
  144. return [self encodedTimestamp:version.timestamp()];
  145. }
  146. - (SnapshotVersion)decodedVersion:(GPBTimestamp *)version {
  147. return SnapshotVersion{[self decodedTimestamp:version]};
  148. }
  149. #pragma mark - FIRGeoPoint <=> GTPLatLng
  150. - (GTPLatLng *)encodedGeoPoint:(const GeoPoint &)geoPoint {
  151. GTPLatLng *latLng = [GTPLatLng message];
  152. latLng.latitude = geoPoint.latitude();
  153. latLng.longitude = geoPoint.longitude();
  154. return latLng;
  155. }
  156. - (GeoPoint)decodedGeoPoint:(GTPLatLng *)latLng {
  157. return GeoPoint(latLng.latitude, latLng.longitude);
  158. }
  159. #pragma mark - DocumentKey <=> Key proto
  160. - (NSString *)encodedDocumentKey:(const DocumentKey &)key {
  161. return [self encodedResourcePathForDatabaseID:_databaseID path:key.path()];
  162. }
  163. - (DocumentKey)decodedDocumentKey:(NSString *)name {
  164. const ResourcePath path = [self decodedResourcePathWithDatabaseID:name];
  165. HARD_ASSERT(path[1] == _databaseID.project_id(),
  166. "Tried to deserialize key from different project.");
  167. HARD_ASSERT(path[3] == _databaseID.database_id(),
  168. "Tried to deserialize key from different datbase.");
  169. return DocumentKey{[self localResourcePathForQualifiedResourcePath:path]};
  170. }
  171. - (NSString *)encodedResourcePathForDatabaseID:(const DatabaseId &)databaseID
  172. path:(const ResourcePath &)path {
  173. return util::MakeNSString([self encodedResourcePathForDatabaseID:databaseID]
  174. .Append("documents")
  175. .Append(path)
  176. .CanonicalString());
  177. }
  178. - (ResourcePath)decodedResourcePathWithDatabaseID:(NSString *)name {
  179. const ResourcePath path = ResourcePath::FromString(util::MakeString(name));
  180. HARD_ASSERT([self validQualifiedResourcePath:path], "Tried to deserialize invalid key %s",
  181. path.CanonicalString());
  182. return path;
  183. }
  184. - (NSString *)encodedQueryPath:(const ResourcePath &)path {
  185. return [self encodedResourcePathForDatabaseID:_databaseID path:path];
  186. }
  187. - (ResourcePath)decodedQueryPath:(NSString *)name {
  188. const ResourcePath resource = [self decodedResourcePathWithDatabaseID:name];
  189. if (resource.size() == 4) {
  190. // In v1beta1 queries for collections at the root did not have a trailing "/documents". In v1
  191. // all resource paths contain "/documents". Preserve the ability to read the v1beta1 form for
  192. // compatibility with queries persisted in the local query cache.
  193. return ResourcePath{};
  194. } else {
  195. return [self localResourcePathForQualifiedResourcePath:resource];
  196. }
  197. }
  198. - (ResourcePath)encodedResourcePathForDatabaseID:(const DatabaseId &)databaseID {
  199. return ResourcePath{"projects", databaseID.project_id(), "databases", databaseID.database_id()};
  200. }
  201. - (ResourcePath)localResourcePathForQualifiedResourcePath:(const ResourcePath &)resourceName {
  202. HARD_ASSERT(resourceName.size() > 4 && resourceName[4] == "documents",
  203. "Tried to deserialize invalid key %s", resourceName.CanonicalString());
  204. return resourceName.PopFirst(5);
  205. }
  206. - (BOOL)validQualifiedResourcePath:(const ResourcePath &)path {
  207. return path.size() >= 4 && path[0] == "projects" && path[2] == "databases";
  208. }
  209. - (NSString *)encodedDatabaseID {
  210. return util::MakeNSString([self encodedResourcePathForDatabaseID:_databaseID].CanonicalString());
  211. }
  212. #pragma mark - FieldValue <=> Value proto
  213. - (GCFSValue *)encodedFieldValue:(const FieldValue &)fieldValue {
  214. switch (fieldValue.type()) {
  215. case FieldValue::Type::Null:
  216. return [self encodedNull];
  217. case FieldValue::Type::Boolean:
  218. return [self encodedBool:fieldValue.boolean_value()];
  219. case FieldValue::Type::Integer:
  220. return [self encodedInteger:fieldValue.integer_value()];
  221. case FieldValue::Type::Double:
  222. return [self encodedDouble:fieldValue.double_value()];
  223. case FieldValue::Type::Timestamp:
  224. return [self encodedTimestampValue:fieldValue.timestamp_value()];
  225. case FieldValue::Type::String:
  226. return [self encodedString:fieldValue.string_value()];
  227. case FieldValue::Type::Blob:
  228. return [self encodedBlobValue:fieldValue.blob_value()];
  229. case FieldValue::Type::Reference: {
  230. const auto &ref = fieldValue.reference_value();
  231. return [self encodedReferenceValueForDatabaseID:ref.database_id() key:ref.key()];
  232. }
  233. case FieldValue::Type::GeoPoint:
  234. return [self encodedGeoPointValue:fieldValue.geo_point_value()];
  235. case FieldValue::Type::Array: {
  236. GCFSValue *result = [GCFSValue message];
  237. result.arrayValue = [self encodedArrayValue:fieldValue.array_value()];
  238. return result;
  239. }
  240. case FieldValue::Type::Object: {
  241. GCFSValue *result = [GCFSValue message];
  242. result.mapValue = [self encodedMapValue:fieldValue.object_value()];
  243. return result;
  244. }
  245. case FieldValue::Type::ServerTimestamp:
  246. HARD_FAIL("Unhandled type %s on %s", fieldValue.type(), fieldValue.ToString());
  247. }
  248. UNREACHABLE();
  249. }
  250. - (FieldValue)decodedFieldValue:(GCFSValue *)valueProto {
  251. switch (valueProto.valueTypeOneOfCase) {
  252. case GCFSValue_ValueType_OneOfCase_NullValue:
  253. return FieldValue::Null();
  254. case GCFSValue_ValueType_OneOfCase_BooleanValue:
  255. return FieldValue::FromBoolean(valueProto.booleanValue);
  256. case GCFSValue_ValueType_OneOfCase_IntegerValue:
  257. return FieldValue::FromInteger(valueProto.integerValue);
  258. case GCFSValue_ValueType_OneOfCase_DoubleValue:
  259. return FieldValue::FromDouble(valueProto.doubleValue);
  260. case GCFSValue_ValueType_OneOfCase_StringValue:
  261. return FieldValue::FromString(util::MakeString(valueProto.stringValue));
  262. case GCFSValue_ValueType_OneOfCase_TimestampValue: {
  263. Timestamp value = [self decodedTimestamp:valueProto.timestampValue];
  264. return FieldValue::FromTimestamp(value);
  265. }
  266. case GCFSValue_ValueType_OneOfCase_GeoPointValue:
  267. return FieldValue::FromGeoPoint([self decodedGeoPoint:valueProto.geoPointValue]);
  268. case GCFSValue_ValueType_OneOfCase_BytesValue:
  269. return FieldValue::FromBlob(MakeByteString(valueProto.bytesValue));
  270. case GCFSValue_ValueType_OneOfCase_ReferenceValue:
  271. return [self decodedReferenceValue:valueProto.referenceValue];
  272. case GCFSValue_ValueType_OneOfCase_ArrayValue:
  273. return [self decodedArrayValue:valueProto.arrayValue];
  274. case GCFSValue_ValueType_OneOfCase_MapValue:
  275. return [self decodedMapValue:valueProto.mapValue];
  276. default:
  277. HARD_FAIL("Unhandled type %s on %s", valueProto.valueTypeOneOfCase, valueProto);
  278. }
  279. }
  280. - (GCFSValue *)encodedNull {
  281. GCFSValue *result = [GCFSValue message];
  282. result.nullValue = GPBNullValue_NullValue;
  283. return result;
  284. }
  285. - (GCFSValue *)encodedBool:(bool)value {
  286. GCFSValue *result = [GCFSValue message];
  287. result.booleanValue = value;
  288. return result;
  289. }
  290. - (GCFSValue *)encodedDouble:(double)value {
  291. GCFSValue *result = [GCFSValue message];
  292. result.doubleValue = value;
  293. return result;
  294. }
  295. - (GCFSValue *)encodedInteger:(int64_t)value {
  296. GCFSValue *result = [GCFSValue message];
  297. result.integerValue = value;
  298. return result;
  299. }
  300. - (GCFSValue *)encodedString:(absl::string_view)value {
  301. GCFSValue *result = [GCFSValue message];
  302. result.stringValue = util::MakeNSString(value);
  303. return result;
  304. }
  305. - (GCFSValue *)encodedTimestampValue:(const Timestamp &)value {
  306. GCFSValue *result = [GCFSValue message];
  307. result.timestampValue = [self encodedTimestamp:value];
  308. return result;
  309. }
  310. - (GCFSValue *)encodedGeoPointValue:(const GeoPoint &)value {
  311. GCFSValue *result = [GCFSValue message];
  312. result.geoPointValue = [self encodedGeoPoint:value];
  313. return result;
  314. }
  315. - (GCFSValue *)encodedBlobValue:(const ByteString &)value {
  316. GCFSValue *result = [GCFSValue message];
  317. result.bytesValue = MakeNSData(value);
  318. return result;
  319. }
  320. - (GCFSValue *)encodedReferenceValueForDatabaseID:(const DatabaseId &)databaseID
  321. key:(const DocumentKey &)key {
  322. HARD_ASSERT(databaseID == _databaseID, "Database %s:%s cannot encode reference from %s:%s",
  323. _databaseID.project_id(), _databaseID.database_id(), databaseID.project_id(),
  324. databaseID.database_id());
  325. GCFSValue *result = [GCFSValue message];
  326. result.referenceValue = [self encodedResourcePathForDatabaseID:databaseID path:key.path()];
  327. return result;
  328. }
  329. - (FieldValue)decodedReferenceValue:(NSString *)resourceName {
  330. const ResourcePath path = [self decodedResourcePathWithDatabaseID:resourceName];
  331. const std::string &project = path[1];
  332. const std::string &database = path[3];
  333. const DocumentKey key{[self localResourcePathForQualifiedResourcePath:path]};
  334. const DatabaseId database_id(project, database);
  335. HARD_ASSERT(database_id == _databaseID, "Database %s:%s cannot encode reference from %s:%s",
  336. _databaseID.project_id(), _databaseID.database_id(), database_id.project_id(),
  337. database_id.database_id());
  338. return FieldValue::FromReference(_databaseID, key);
  339. }
  340. - (GCFSArrayValue *)encodedArrayValue:(const FieldValue::Array &)arrayValue {
  341. GCFSArrayValue *proto = [GCFSArrayValue message];
  342. NSMutableArray<GCFSValue *> *protoContents = [proto valuesArray];
  343. for (const FieldValue &value : arrayValue) {
  344. GCFSValue *converted = [self encodedFieldValue:value];
  345. [protoContents addObject:converted];
  346. }
  347. return proto;
  348. }
  349. - (FieldValue)decodedArrayValue:(GCFSArrayValue *)arrayValue {
  350. FieldValue::Array contents;
  351. contents.reserve(arrayValue.valuesArray_Count);
  352. for (GCFSValue *value in arrayValue.valuesArray) {
  353. contents.push_back([self decodedFieldValue:value]);
  354. }
  355. return FieldValue::FromArray(std::move(contents));
  356. }
  357. - (GCFSMapValue *)encodedMapValue:(const FieldValue::Map &)value {
  358. GCFSMapValue *result = [GCFSMapValue message];
  359. result.fields = [self encodedMapFields:value];
  360. return result;
  361. }
  362. - (ObjectValue)decodedMapValue:(GCFSMapValue *)map {
  363. return [self decodedFields:map.fields];
  364. }
  365. /**
  366. * Encodes an ObjectValue into a dictionary.
  367. * @return a new dictionary that can be assigned to a field in another proto.
  368. */
  369. - (NSMutableDictionary<NSString *, GCFSValue *> *)encodedFields:(const ObjectValue &)value {
  370. return [self encodedMapFields:value.GetInternalValue()];
  371. }
  372. - (NSMutableDictionary<NSString *, GCFSValue *> *)encodedMapFields:(const FieldValue::Map &)value {
  373. NSMutableDictionary<NSString *, GCFSValue *> *result = [NSMutableDictionary dictionary];
  374. for (const auto &kv : value) {
  375. NSString *key = util::MakeNSString(kv.first);
  376. GCFSValue *converted = [self encodedFieldValue:kv.second];
  377. result[key] = converted;
  378. }
  379. return result;
  380. }
  381. - (ObjectValue)decodedFields:(NSDictionary<NSString *, GCFSValue *> *)fields {
  382. __block ObjectValue result = ObjectValue::Empty();
  383. [fields enumerateKeysAndObjectsUsingBlock:^(NSString *_Nonnull key, GCFSValue *_Nonnull obj,
  384. BOOL *_Nonnull stop) {
  385. FieldPath path{util::MakeString(key)};
  386. FieldValue value = [self decodedFieldValue:obj];
  387. result = result.Set(path, std::move(value));
  388. }];
  389. return result;
  390. }
  391. #pragma mark - ObjectValue <=> Document proto
  392. - (GCFSDocument *)encodedDocumentWithFields:(const ObjectValue &)objectValue
  393. key:(const DocumentKey &)key {
  394. GCFSDocument *proto = [GCFSDocument message];
  395. proto.name = [self encodedDocumentKey:key];
  396. proto.fields = [self encodedFields:objectValue];
  397. return proto;
  398. }
  399. #pragma mark - MaybeDocument <= BatchGetDocumentsResponse proto
  400. - (MaybeDocument)decodedMaybeDocumentFromBatch:(GCFSBatchGetDocumentsResponse *)response {
  401. switch (response.resultOneOfCase) {
  402. case GCFSBatchGetDocumentsResponse_Result_OneOfCase_Found:
  403. return [self decodedFoundDocument:response];
  404. case GCFSBatchGetDocumentsResponse_Result_OneOfCase_Missing:
  405. return [self decodedDeletedDocument:response];
  406. default:
  407. HARD_FAIL("Unknown document type: %s", response);
  408. }
  409. }
  410. - (Document)decodedFoundDocument:(GCFSBatchGetDocumentsResponse *)response {
  411. HARD_ASSERT(!!response.found, "Tried to deserialize a found document from a deleted document.");
  412. DocumentKey key = [self decodedDocumentKey:response.found.name];
  413. ObjectValue value = [self decodedFields:response.found.fields];
  414. SnapshotVersion version = [self decodedVersion:response.found.updateTime];
  415. HARD_ASSERT(version != SnapshotVersion::None(),
  416. "Got a document response with no snapshot version");
  417. return Document(std::move(value), std::move(key), version, DocumentState::kSynced,
  418. Wrap(response.found));
  419. }
  420. - (NoDocument)decodedDeletedDocument:(GCFSBatchGetDocumentsResponse *)response {
  421. HARD_ASSERT(!!response.missing, "Tried to deserialize a deleted document from a found document.");
  422. DocumentKey key = [self decodedDocumentKey:response.missing];
  423. SnapshotVersion version = [self decodedVersion:response.readTime];
  424. HARD_ASSERT(version != SnapshotVersion::None(),
  425. "Got a no document response with no snapshot version");
  426. return NoDocument(std::move(key), version, /* has_commited_mutations= */ false);
  427. }
  428. #pragma mark - Mutation => GCFSWrite proto
  429. - (GCFSWrite *)encodedMutation:(const Mutation &)mutation {
  430. using Type = Mutation::Type;
  431. GCFSWrite *proto = [GCFSWrite message];
  432. if (!mutation.precondition().is_none()) {
  433. proto.currentDocument = [self encodedPrecondition:mutation.precondition()];
  434. }
  435. switch (mutation.type()) {
  436. case Type::Set: {
  437. SetMutation set(mutation);
  438. proto.update = [self encodedDocumentWithFields:set.value() key:set.key()];
  439. return proto;
  440. }
  441. case Type::Patch: {
  442. PatchMutation patch(mutation);
  443. proto.update = [self encodedDocumentWithFields:patch.value() key:patch.key()];
  444. proto.updateMask = [self encodedFieldMask:patch.mask()];
  445. return proto;
  446. }
  447. case Type::Transform: {
  448. TransformMutation transform(mutation);
  449. proto.transform = [GCFSDocumentTransform message];
  450. proto.transform.document = [self encodedDocumentKey:transform.key()];
  451. proto.transform.fieldTransformsArray =
  452. [self encodedFieldTransforms:transform.field_transforms()];
  453. // NOTE: We set a precondition of exists: true as a safety-check, since we always combine
  454. // TransformMutations with a SetMutation or PatchMutation which (if successful) should
  455. // end up with an existing document.
  456. proto.currentDocument.exists = YES;
  457. return proto;
  458. }
  459. case Type::Delete: {
  460. DeleteMutation deleteMutation(mutation);
  461. proto.delete_p = [self encodedDocumentKey:deleteMutation.key()];
  462. return proto;
  463. }
  464. }
  465. UNREACHABLE();
  466. }
  467. - (Mutation)decodedMutation:(GCFSWrite *)mutation {
  468. Precondition precondition = [mutation hasCurrentDocument]
  469. ? [self decodedPrecondition:mutation.currentDocument]
  470. : Precondition::None();
  471. switch (mutation.operationOneOfCase) {
  472. case GCFSWrite_Operation_OneOfCase_Update:
  473. if (mutation.hasUpdateMask) {
  474. return PatchMutation([self decodedDocumentKey:mutation.update.name],
  475. [self decodedFields:mutation.update.fields],
  476. [self decodedFieldMask:mutation.updateMask], precondition);
  477. } else {
  478. return SetMutation([self decodedDocumentKey:mutation.update.name],
  479. [self decodedFields:mutation.update.fields], precondition);
  480. }
  481. case GCFSWrite_Operation_OneOfCase_Delete_p:
  482. return DeleteMutation([self decodedDocumentKey:mutation.delete_p], precondition);
  483. case GCFSWrite_Operation_OneOfCase_Transform: {
  484. HARD_ASSERT(precondition == Precondition::Exists(true),
  485. "Transforms must have precondition \"exists == true\"");
  486. return TransformMutation(
  487. [self decodedDocumentKey:mutation.transform.document],
  488. [self decodedFieldTransforms:mutation.transform.fieldTransformsArray]);
  489. }
  490. default:
  491. // Note that insert is intentionally unhandled, since we don't ever deal in them.
  492. HARD_FAIL("Unknown mutation operation: %s", mutation.operationOneOfCase);
  493. }
  494. }
  495. - (GCFSPrecondition *)encodedPrecondition:(const Precondition &)precondition {
  496. HARD_ASSERT(!precondition.is_none(), "Can't serialize an empty precondition");
  497. GCFSPrecondition *message = [GCFSPrecondition message];
  498. if (precondition.type() == Precondition::Type::UpdateTime) {
  499. message.updateTime = [self encodedVersion:precondition.update_time()];
  500. } else if (precondition.type() == Precondition::Type::Exists) {
  501. message.exists = precondition == Precondition::Exists(true);
  502. } else {
  503. HARD_FAIL("Unknown precondition: %s", precondition.ToString());
  504. }
  505. return message;
  506. }
  507. - (Precondition)decodedPrecondition:(GCFSPrecondition *)precondition {
  508. switch (precondition.conditionTypeOneOfCase) {
  509. case GCFSPrecondition_ConditionType_OneOfCase_GPBUnsetOneOfCase:
  510. return Precondition::None();
  511. case GCFSPrecondition_ConditionType_OneOfCase_Exists:
  512. return Precondition::Exists(precondition.exists);
  513. case GCFSPrecondition_ConditionType_OneOfCase_UpdateTime:
  514. return Precondition::UpdateTime([self decodedVersion:precondition.updateTime]);
  515. default:
  516. HARD_FAIL("Unrecognized Precondition one-of case %s", precondition);
  517. }
  518. }
  519. - (GCFSDocumentMask *)encodedFieldMask:(const FieldMask &)fieldMask {
  520. GCFSDocumentMask *mask = [GCFSDocumentMask message];
  521. for (const FieldPath &field : fieldMask) {
  522. [mask.fieldPathsArray addObject:util::MakeNSString(field.CanonicalString())];
  523. }
  524. return mask;
  525. }
  526. - (FieldMask)decodedFieldMask:(GCFSDocumentMask *)fieldMask {
  527. std::set<FieldPath> fields;
  528. for (NSString *path in fieldMask.fieldPathsArray) {
  529. fields.insert(FieldPath::FromServerFormat(util::MakeString(path)));
  530. }
  531. return FieldMask(std::move(fields));
  532. }
  533. - (NSMutableArray<GCFSDocumentTransform_FieldTransform *> *)encodedFieldTransforms:
  534. (const std::vector<FieldTransform> &)fieldTransforms {
  535. NSMutableArray *protos = [NSMutableArray array];
  536. for (const FieldTransform &fieldTransform : fieldTransforms) {
  537. GCFSDocumentTransform_FieldTransform *proto = [self encodedFieldTransform:fieldTransform];
  538. [protos addObject:proto];
  539. }
  540. return protos;
  541. }
  542. - (GCFSDocumentTransform_FieldTransform *)encodedFieldTransform:
  543. (const FieldTransform &)fieldTransform {
  544. GCFSDocumentTransform_FieldTransform *proto = [GCFSDocumentTransform_FieldTransform message];
  545. proto.fieldPath = util::MakeNSString(fieldTransform.path().CanonicalString());
  546. if (fieldTransform.transformation().type() == TransformOperation::Type::ServerTimestamp) {
  547. proto.setToServerValue = GCFSDocumentTransform_FieldTransform_ServerValue_RequestTime;
  548. } else if (fieldTransform.transformation().type() == TransformOperation::Type::ArrayUnion) {
  549. proto.appendMissingElements = [self
  550. encodedArrayTransformElements:ArrayTransform(fieldTransform.transformation()).elements()];
  551. } else if (fieldTransform.transformation().type() == TransformOperation::Type::ArrayRemove) {
  552. proto.removeAllFromArray_p = [self
  553. encodedArrayTransformElements:ArrayTransform(fieldTransform.transformation()).elements()];
  554. } else if (fieldTransform.transformation().type() == TransformOperation::Type::Increment) {
  555. const NumericIncrementTransform &incrementTransform =
  556. static_cast<const NumericIncrementTransform &>(fieldTransform.transformation());
  557. proto.increment = [self encodedFieldValue:incrementTransform.operand()];
  558. } else {
  559. HARD_FAIL("Unknown transform: %s type", fieldTransform.transformation().type());
  560. }
  561. return proto;
  562. }
  563. - (GCFSArrayValue *)encodedArrayTransformElements:(const std::vector<FieldValue> &)elements {
  564. GCFSArrayValue *proto = [GCFSArrayValue message];
  565. NSMutableArray<GCFSValue *> *protoContents = [proto valuesArray];
  566. for (const FieldValue &element : elements) {
  567. GCFSValue *converted = [self encodedFieldValue:element];
  568. [protoContents addObject:converted];
  569. }
  570. return proto;
  571. }
  572. - (std::vector<FieldTransform>)decodedFieldTransforms:
  573. (NSArray<GCFSDocumentTransform_FieldTransform *> *)protos {
  574. std::vector<FieldTransform> fieldTransforms;
  575. fieldTransforms.reserve(protos.count);
  576. for (GCFSDocumentTransform_FieldTransform *proto in protos) {
  577. switch (proto.transformTypeOneOfCase) {
  578. case GCFSDocumentTransform_FieldTransform_TransformType_OneOfCase_SetToServerValue: {
  579. HARD_ASSERT(
  580. proto.setToServerValue == GCFSDocumentTransform_FieldTransform_ServerValue_RequestTime,
  581. "Unknown transform setToServerValue: %s", proto.setToServerValue);
  582. fieldTransforms.emplace_back(FieldPath::FromServerFormat(util::MakeString(proto.fieldPath)),
  583. ServerTimestampTransform());
  584. break;
  585. }
  586. case GCFSDocumentTransform_FieldTransform_TransformType_OneOfCase_AppendMissingElements: {
  587. std::vector<FieldValue> elements =
  588. [self decodedArrayTransformElements:proto.appendMissingElements];
  589. fieldTransforms.emplace_back(
  590. FieldPath::FromServerFormat(util::MakeString(proto.fieldPath)),
  591. ArrayTransform(TransformOperation::Type::ArrayUnion, std::move(elements)));
  592. break;
  593. }
  594. case GCFSDocumentTransform_FieldTransform_TransformType_OneOfCase_RemoveAllFromArray_p: {
  595. std::vector<FieldValue> elements =
  596. [self decodedArrayTransformElements:proto.removeAllFromArray_p];
  597. fieldTransforms.emplace_back(
  598. FieldPath::FromServerFormat(util::MakeString(proto.fieldPath)),
  599. ArrayTransform(TransformOperation::Type::ArrayRemove, std::move(elements)));
  600. break;
  601. }
  602. case GCFSDocumentTransform_FieldTransform_TransformType_OneOfCase_Increment: {
  603. FieldValue operand = [self decodedFieldValue:proto.increment];
  604. fieldTransforms.emplace_back(FieldPath::FromServerFormat(util::MakeString(proto.fieldPath)),
  605. NumericIncrementTransform(std::move(operand)));
  606. break;
  607. }
  608. default:
  609. HARD_FAIL("Unknown transform: %s", proto);
  610. }
  611. }
  612. return fieldTransforms;
  613. }
  614. - (std::vector<FieldValue>)decodedArrayTransformElements:(GCFSArrayValue *)proto {
  615. __block std::vector<FieldValue> elements;
  616. [proto.valuesArray enumerateObjectsUsingBlock:^(GCFSValue *value, NSUInteger idx, BOOL *stop) {
  617. elements.push_back([self decodedFieldValue:value]);
  618. }];
  619. return elements;
  620. }
  621. #pragma mark - MutationResult <= GCFSWriteResult proto
  622. - (MutationResult)decodedMutationResult:(GCFSWriteResult *)mutation
  623. commitVersion:(const SnapshotVersion &)commitVersion {
  624. // NOTE: Deletes don't have an updateTime. Use commitVersion instead.
  625. SnapshotVersion version =
  626. mutation.hasUpdateTime ? [self decodedVersion:mutation.updateTime] : commitVersion;
  627. absl::optional<std::vector<FieldValue>> transformResults;
  628. if (mutation.transformResultsArray.count > 0) {
  629. transformResults = std::vector<FieldValue>{};
  630. for (GCFSValue *result in mutation.transformResultsArray) {
  631. transformResults->push_back([self decodedFieldValue:result]);
  632. }
  633. }
  634. return MutationResult(std::move(version), std::move(transformResults));
  635. }
  636. #pragma mark - QueryData => GCFSTarget proto
  637. - (nullable NSMutableDictionary<NSString *, NSString *> *)encodedListenRequestLabelsForQueryData:
  638. (const QueryData &)queryData {
  639. NSString *value = [self encodedLabelForPurpose:queryData.purpose()];
  640. if (!value) {
  641. return nil;
  642. }
  643. NSMutableDictionary<NSString *, NSString *> *result =
  644. [NSMutableDictionary dictionaryWithCapacity:1];
  645. [result setObject:value forKey:@"goog-listen-tags"];
  646. return result;
  647. }
  648. - (nullable NSString *)encodedLabelForPurpose:(QueryPurpose)purpose {
  649. switch (purpose) {
  650. case QueryPurpose::Listen:
  651. return nil;
  652. case QueryPurpose::ExistenceFilterMismatch:
  653. return @"existence-filter-mismatch";
  654. case QueryPurpose::LimboResolution:
  655. return @"limbo-document";
  656. default:
  657. HARD_FAIL("Unrecognized query purpose: %s", purpose);
  658. }
  659. }
  660. - (GCFSTarget *)encodedTarget:(const QueryData &)queryData {
  661. GCFSTarget *result = [GCFSTarget message];
  662. const Query &query = queryData.query();
  663. if (query.IsDocumentQuery()) {
  664. result.documents = [self encodedDocumentsTarget:query];
  665. } else {
  666. result.query = [self encodedQueryTarget:query];
  667. }
  668. result.targetId = queryData.target_id();
  669. result.resumeToken = MakeNullableNSData(queryData.resume_token());
  670. return result;
  671. }
  672. - (GCFSTarget_DocumentsTarget *)encodedDocumentsTarget:(const Query &)query {
  673. GCFSTarget_DocumentsTarget *result = [GCFSTarget_DocumentsTarget message];
  674. NSMutableArray<NSString *> *docs = result.documentsArray;
  675. [docs addObject:[self encodedQueryPath:query.path()]];
  676. return result;
  677. }
  678. - (Query)decodedQueryFromDocumentsTarget:(GCFSTarget_DocumentsTarget *)target {
  679. NSArray<NSString *> *documents = target.documentsArray;
  680. HARD_ASSERT(documents.count == 1, "DocumentsTarget contained other than 1 document %s",
  681. (unsigned long)documents.count);
  682. NSString *name = documents[0];
  683. return Query([self decodedQueryPath:name]);
  684. }
  685. - (GCFSTarget_QueryTarget *)encodedQueryTarget:(const Query &)query {
  686. // Dissect the path into parent, collectionId, and optional key filter.
  687. GCFSTarget_QueryTarget *queryTarget = [GCFSTarget_QueryTarget message];
  688. const ResourcePath &path = query.path();
  689. if (query.collection_group()) {
  690. HARD_ASSERT(path.size() % 2 == 0,
  691. "Collection group queries should be within a document path or root.");
  692. queryTarget.parent = [self encodedQueryPath:path];
  693. GCFSStructuredQuery_CollectionSelector *from = [GCFSStructuredQuery_CollectionSelector message];
  694. from.collectionId = util::MakeNSString(query.collection_group());
  695. from.allDescendants = YES;
  696. [queryTarget.structuredQuery.fromArray addObject:from];
  697. } else {
  698. HARD_ASSERT(path.size() % 2 != 0, "Document queries with filters are not supported.");
  699. queryTarget.parent = [self encodedQueryPath:path.PopLast()];
  700. GCFSStructuredQuery_CollectionSelector *from = [GCFSStructuredQuery_CollectionSelector message];
  701. from.collectionId = util::MakeNSString(path.last_segment());
  702. [queryTarget.structuredQuery.fromArray addObject:from];
  703. }
  704. // Encode the filters.
  705. GCFSStructuredQuery_Filter *_Nullable where = [self encodedFilters:query.filters()];
  706. if (where) {
  707. queryTarget.structuredQuery.where = where;
  708. }
  709. NSArray<GCFSStructuredQuery_Order *> *orders = [self encodedSortOrders:query.order_bys()];
  710. if (orders.count) {
  711. [queryTarget.structuredQuery.orderByArray addObjectsFromArray:orders];
  712. }
  713. if (query.limit() != Query::kNoLimit) {
  714. queryTarget.structuredQuery.limit.value = (int32_t)query.limit();
  715. }
  716. if (query.start_at()) {
  717. queryTarget.structuredQuery.startAt = [self encodedBound:*query.start_at()];
  718. }
  719. if (query.end_at()) {
  720. queryTarget.structuredQuery.endAt = [self encodedBound:*query.end_at()];
  721. }
  722. return queryTarget;
  723. }
  724. - (Query)decodedQueryFromQueryTarget:(GCFSTarget_QueryTarget *)target {
  725. ResourcePath path = [self decodedQueryPath:target.parent];
  726. GCFSStructuredQuery *query = target.structuredQuery;
  727. CollectionGroupId collectionGroup;
  728. NSUInteger fromCount = query.fromArray_Count;
  729. if (fromCount > 0) {
  730. HARD_ASSERT(fromCount == 1,
  731. "StructuredQuery.from with more than one collection is not supported.");
  732. GCFSStructuredQuery_CollectionSelector *from = query.fromArray[0];
  733. if (from.allDescendants) {
  734. collectionGroup = util::MakeStringPtr(from.collectionId);
  735. } else {
  736. path = path.Append(util::MakeString(from.collectionId));
  737. }
  738. }
  739. FilterList filterBy;
  740. if (query.hasWhere) {
  741. filterBy = [self decodedFilters:query.where];
  742. }
  743. OrderByList orderBy;
  744. if (query.orderByArray_Count > 0) {
  745. orderBy = [self decodedSortOrders:query.orderByArray];
  746. }
  747. int32_t limit = Query::kNoLimit;
  748. if (query.hasLimit) {
  749. limit = query.limit.value;
  750. }
  751. std::shared_ptr<Bound> startAt;
  752. if (query.hasStartAt) {
  753. startAt = [self decodedBound:query.startAt];
  754. }
  755. std::shared_ptr<Bound> endAt;
  756. if (query.hasEndAt) {
  757. endAt = [self decodedBound:query.endAt];
  758. }
  759. return Query(std::move(path), std::move(collectionGroup), std::move(filterBy), std::move(orderBy),
  760. limit, std::move(startAt), std::move(endAt));
  761. }
  762. #pragma mark Filters
  763. - (GCFSStructuredQuery_Filter *_Nullable)encodedFilters:(const FilterList &)filters {
  764. if (filters.empty()) {
  765. return nil;
  766. }
  767. NSMutableArray<GCFSStructuredQuery_Filter *> *protos = [NSMutableArray array];
  768. for (const auto &filter : filters) {
  769. if (filter.IsAFieldFilter()) {
  770. [protos addObject:[self encodedUnaryOrFieldFilter:FieldFilter(filter)]];
  771. }
  772. }
  773. if (protos.count == 1) {
  774. // Special case: no existing filters and we only need to add one filter. This can be made the
  775. // single root filter without a composite filter.
  776. return protos[0];
  777. }
  778. GCFSStructuredQuery_Filter *composite = [GCFSStructuredQuery_Filter message];
  779. composite.compositeFilter.op = GCFSStructuredQuery_CompositeFilter_Operator_And;
  780. composite.compositeFilter.filtersArray = protos;
  781. return composite;
  782. }
  783. - (FilterList)decodedFilters:(GCFSStructuredQuery_Filter *)proto {
  784. FilterList result;
  785. NSArray<GCFSStructuredQuery_Filter *> *filters;
  786. if (proto.filterTypeOneOfCase ==
  787. GCFSStructuredQuery_Filter_FilterType_OneOfCase_CompositeFilter) {
  788. HARD_ASSERT(proto.compositeFilter.op == GCFSStructuredQuery_CompositeFilter_Operator_And,
  789. "Only AND-type composite filters are supported, got %s", proto.compositeFilter.op);
  790. filters = proto.compositeFilter.filtersArray;
  791. } else {
  792. filters = @[ proto ];
  793. }
  794. result = result.reserve(filters.count);
  795. for (GCFSStructuredQuery_Filter *filter in filters) {
  796. switch (filter.filterTypeOneOfCase) {
  797. case GCFSStructuredQuery_Filter_FilterType_OneOfCase_CompositeFilter:
  798. HARD_FAIL("Nested composite filters are not supported");
  799. case GCFSStructuredQuery_Filter_FilterType_OneOfCase_FieldFilter:
  800. result = result.push_back([self decodedFieldFilter:filter.fieldFilter]);
  801. break;
  802. case GCFSStructuredQuery_Filter_FilterType_OneOfCase_UnaryFilter:
  803. result = result.push_back([self decodedUnaryFilter:filter.unaryFilter]);
  804. break;
  805. default:
  806. HARD_FAIL("Unrecognized Filter.filterType %s", filter.filterTypeOneOfCase);
  807. }
  808. }
  809. return result;
  810. }
  811. - (GCFSStructuredQuery_Filter *)encodedUnaryOrFieldFilter:(const FieldFilter &)filter {
  812. GCFSStructuredQuery_Filter *proto = [GCFSStructuredQuery_Filter message];
  813. if (filter.op() == Operator::Equal) {
  814. if (filter.value().is_null()) {
  815. proto.unaryFilter.field = [self encodedFieldPath:filter.field()];
  816. proto.unaryFilter.op = GCFSStructuredQuery_UnaryFilter_Operator_IsNull;
  817. return proto;
  818. }
  819. if (filter.value().is_nan()) {
  820. proto.unaryFilter.field = [self encodedFieldPath:filter.field()];
  821. proto.unaryFilter.op = GCFSStructuredQuery_UnaryFilter_Operator_IsNan;
  822. return proto;
  823. }
  824. }
  825. GCFSStructuredQuery_FieldFilter *fieldFilter = proto.fieldFilter;
  826. fieldFilter.field = [self encodedFieldPath:filter.field()];
  827. fieldFilter.op = [self encodedFieldFilterOperator:filter.op()];
  828. fieldFilter.value = [self encodedFieldValue:filter.value()];
  829. return proto;
  830. }
  831. - (const FieldFilter)decodedFieldFilter:(GCFSStructuredQuery_FieldFilter *)proto {
  832. FieldPath fieldPath = FieldPath::FromServerFormat(util::MakeString(proto.field.fieldPath));
  833. Filter::Operator op = [self decodedFieldFilterOperator:proto.op];
  834. FieldValue value = [self decodedFieldValue:proto.value];
  835. return FieldFilter::Create(std::move(fieldPath), op, std::move(value));
  836. }
  837. - (FieldFilter)decodedUnaryFilter:(GCFSStructuredQuery_UnaryFilter *)proto {
  838. FieldPath field = FieldPath::FromServerFormat(util::MakeString(proto.field.fieldPath));
  839. switch (proto.op) {
  840. case GCFSStructuredQuery_UnaryFilter_Operator_IsNull:
  841. return FieldFilter::Create(std::move(field), Operator::Equal, FieldValue::Null());
  842. case GCFSStructuredQuery_UnaryFilter_Operator_IsNan:
  843. return FieldFilter::Create(std::move(field), Operator::Equal, FieldValue::Nan());
  844. default:
  845. HARD_FAIL("Unrecognized UnaryFilter.operator %s", proto.op);
  846. }
  847. }
  848. - (GCFSStructuredQuery_FieldReference *)encodedFieldPath:(const FieldPath &)fieldPath {
  849. GCFSStructuredQuery_FieldReference *ref = [GCFSStructuredQuery_FieldReference message];
  850. ref.fieldPath = util::MakeNSString(fieldPath.CanonicalString());
  851. return ref;
  852. }
  853. - (GCFSStructuredQuery_FieldFilter_Operator)encodedFieldFilterOperator:
  854. (Filter::Operator)filterOperator {
  855. switch (filterOperator) {
  856. case Filter::Operator::LessThan:
  857. return GCFSStructuredQuery_FieldFilter_Operator_LessThan;
  858. case Filter::Operator::LessThanOrEqual:
  859. return GCFSStructuredQuery_FieldFilter_Operator_LessThanOrEqual;
  860. case Filter::Operator::Equal:
  861. return GCFSStructuredQuery_FieldFilter_Operator_Equal;
  862. case Filter::Operator::GreaterThanOrEqual:
  863. return GCFSStructuredQuery_FieldFilter_Operator_GreaterThanOrEqual;
  864. case Filter::Operator::GreaterThan:
  865. return GCFSStructuredQuery_FieldFilter_Operator_GreaterThan;
  866. case Filter::Operator::ArrayContains:
  867. return GCFSStructuredQuery_FieldFilter_Operator_ArrayContains;
  868. case Filter::Operator::In:
  869. return GCFSStructuredQuery_FieldFilter_Operator_In;
  870. case Filter::Operator::ArrayContainsAny:
  871. return GCFSStructuredQuery_FieldFilter_Operator_ArrayContainsAny;
  872. default:
  873. HARD_FAIL("Unhandled Filter::Operator: %s", filterOperator);
  874. }
  875. }
  876. - (Filter::Operator)decodedFieldFilterOperator:
  877. (GCFSStructuredQuery_FieldFilter_Operator)filterOperator {
  878. switch (filterOperator) {
  879. case GCFSStructuredQuery_FieldFilter_Operator_LessThan:
  880. return Filter::Operator::LessThan;
  881. case GCFSStructuredQuery_FieldFilter_Operator_LessThanOrEqual:
  882. return Filter::Operator::LessThanOrEqual;
  883. case GCFSStructuredQuery_FieldFilter_Operator_Equal:
  884. return Filter::Operator::Equal;
  885. case GCFSStructuredQuery_FieldFilter_Operator_GreaterThanOrEqual:
  886. return Filter::Operator::GreaterThanOrEqual;
  887. case GCFSStructuredQuery_FieldFilter_Operator_GreaterThan:
  888. return Filter::Operator::GreaterThan;
  889. case GCFSStructuredQuery_FieldFilter_Operator_ArrayContains:
  890. return Filter::Operator::ArrayContains;
  891. case GCFSStructuredQuery_FieldFilter_Operator_In:
  892. return Filter::Operator::In;
  893. case GCFSStructuredQuery_FieldFilter_Operator_ArrayContainsAny:
  894. return Filter::Operator::ArrayContainsAny;
  895. default:
  896. HARD_FAIL("Unhandled FieldFilter.operator: %s", filterOperator);
  897. }
  898. }
  899. #pragma mark Property Orders
  900. - (NSArray<GCFSStructuredQuery_Order *> *)encodedSortOrders:(const OrderByList &)orders {
  901. NSMutableArray<GCFSStructuredQuery_Order *> *protos = [NSMutableArray array];
  902. for (const OrderBy &order : orders) {
  903. [protos addObject:[self encodedSortOrder:order]];
  904. }
  905. return protos;
  906. }
  907. - (OrderByList)decodedSortOrders:(NSArray<GCFSStructuredQuery_Order *> *)protos {
  908. OrderByList result;
  909. result = result.reserve(protos.count);
  910. for (GCFSStructuredQuery_Order *orderProto in protos) {
  911. result = result.push_back([self decodedSortOrder:orderProto]);
  912. }
  913. return result;
  914. }
  915. - (GCFSStructuredQuery_Order *)encodedSortOrder:(const OrderBy &)sortOrder {
  916. GCFSStructuredQuery_Order *proto = [GCFSStructuredQuery_Order message];
  917. proto.field = [self encodedFieldPath:sortOrder.field()];
  918. if (sortOrder.ascending()) {
  919. proto.direction = GCFSStructuredQuery_Direction_Ascending;
  920. } else {
  921. proto.direction = GCFSStructuredQuery_Direction_Descending;
  922. }
  923. return proto;
  924. }
  925. - (OrderBy)decodedSortOrder:(GCFSStructuredQuery_Order *)proto {
  926. FieldPath fieldPath = FieldPath::FromServerFormat(util::MakeString(proto.field.fieldPath));
  927. Direction direction;
  928. switch (proto.direction) {
  929. case GCFSStructuredQuery_Direction_Ascending:
  930. direction = Direction::Ascending;
  931. break;
  932. case GCFSStructuredQuery_Direction_Descending:
  933. direction = Direction::Descending;
  934. break;
  935. default:
  936. HARD_FAIL("Unrecognized GCFSStructuredQuery_Direction %s", proto.direction);
  937. }
  938. return OrderBy(std::move(fieldPath), direction);
  939. }
  940. #pragma mark - Bounds/Cursors
  941. - (GCFSCursor *)encodedBound:(const Bound &)bound {
  942. GCFSCursor *proto = [GCFSCursor message];
  943. proto.before = bound.before();
  944. for (const FieldValue &fieldValue : bound.position()) {
  945. GCFSValue *value = [self encodedFieldValue:fieldValue];
  946. [proto.valuesArray addObject:value];
  947. }
  948. return proto;
  949. }
  950. - (std::shared_ptr<Bound>)decodedBound:(GCFSCursor *)proto {
  951. std::vector<FieldValue> indexComponents;
  952. for (GCFSValue *valueProto in proto.valuesArray) {
  953. FieldValue value = [self decodedFieldValue:valueProto];
  954. indexComponents.push_back(std::move(value));
  955. }
  956. return std::make_shared<Bound>(std::move(indexComponents), proto.before);
  957. }
  958. #pragma mark - WatchChange <= GCFSListenResponse proto
  959. - (std::unique_ptr<WatchChange>)decodedWatchChange:(GCFSListenResponse *)watchChange {
  960. switch (watchChange.responseTypeOneOfCase) {
  961. case GCFSListenResponse_ResponseType_OneOfCase_TargetChange:
  962. return [self decodedTargetChangeFromWatchChange:watchChange.targetChange];
  963. case GCFSListenResponse_ResponseType_OneOfCase_DocumentChange:
  964. return [self decodedDocumentChange:watchChange.documentChange];
  965. case GCFSListenResponse_ResponseType_OneOfCase_DocumentDelete:
  966. return [self decodedDocumentDelete:watchChange.documentDelete];
  967. case GCFSListenResponse_ResponseType_OneOfCase_DocumentRemove:
  968. return [self decodedDocumentRemove:watchChange.documentRemove];
  969. case GCFSListenResponse_ResponseType_OneOfCase_Filter:
  970. return [self decodedExistenceFilterWatchChange:watchChange.filter];
  971. default:
  972. HARD_FAIL("Unknown WatchChange.changeType %s", watchChange.responseTypeOneOfCase);
  973. }
  974. }
  975. - (SnapshotVersion)versionFromListenResponse:(GCFSListenResponse *)watchChange {
  976. // We have only reached a consistent snapshot for the entire stream if there is a read_time set
  977. // and it applies to all targets (i.e. the list of targets is empty). The backend is guaranteed to
  978. // send such responses.
  979. if (watchChange.responseTypeOneOfCase != GCFSListenResponse_ResponseType_OneOfCase_TargetChange) {
  980. return SnapshotVersion::None();
  981. }
  982. if (watchChange.targetChange.targetIdsArray.count != 0) {
  983. return SnapshotVersion::None();
  984. }
  985. return [self decodedVersion:watchChange.targetChange.readTime];
  986. }
  987. - (std::unique_ptr<WatchChange>)decodedTargetChangeFromWatchChange:(GCFSTargetChange *)change {
  988. WatchTargetChangeState state = [self decodedWatchTargetChangeState:change.targetChangeType];
  989. __block std::vector<TargetId> targetIDs;
  990. [change.targetIdsArray enumerateValuesWithBlock:^(int32_t value, NSUInteger idx, BOOL *stop) {
  991. targetIDs.push_back(value);
  992. }];
  993. ByteString resumeToken = MakeByteString(change.resumeToken);
  994. util::Status cause;
  995. if (change.hasCause) {
  996. cause =
  997. util::Status{static_cast<Error>(change.cause.code), util::MakeString(change.cause.message)};
  998. }
  999. return absl::make_unique<WatchTargetChange>(state, std::move(targetIDs), std::move(resumeToken),
  1000. std::move(cause));
  1001. }
  1002. - (WatchTargetChangeState)decodedWatchTargetChangeState:(GCFSTargetChange_TargetChangeType)state {
  1003. switch (state) {
  1004. case GCFSTargetChange_TargetChangeType_NoChange:
  1005. return WatchTargetChangeState::NoChange;
  1006. case GCFSTargetChange_TargetChangeType_Add:
  1007. return WatchTargetChangeState::Added;
  1008. case GCFSTargetChange_TargetChangeType_Remove:
  1009. return WatchTargetChangeState::Removed;
  1010. case GCFSTargetChange_TargetChangeType_Current:
  1011. return WatchTargetChangeState::Current;
  1012. case GCFSTargetChange_TargetChangeType_Reset:
  1013. return WatchTargetChangeState::Reset;
  1014. default:
  1015. HARD_FAIL("Unexpected TargetChange.state: %s", state);
  1016. }
  1017. }
  1018. - (std::vector<TargetId>)decodedIntegerArray:(GPBInt32Array *)values {
  1019. __block std::vector<TargetId> result;
  1020. result.reserve(values.count);
  1021. [values enumerateValuesWithBlock:^(int32_t value, NSUInteger idx, BOOL *stop) {
  1022. result.push_back(value);
  1023. }];
  1024. return result;
  1025. }
  1026. - (std::unique_ptr<WatchChange>)decodedDocumentChange:(GCFSDocumentChange *)change {
  1027. ObjectValue value = [self decodedFields:change.document.fields];
  1028. DocumentKey key = [self decodedDocumentKey:change.document.name];
  1029. SnapshotVersion version = [self decodedVersion:change.document.updateTime];
  1030. HARD_ASSERT(version != SnapshotVersion::None(), "Got a document change with no snapshot version");
  1031. // The document may soon be re-serialized back to protos in order to store it in local
  1032. // persistence. Memoize the encoded form to avoid encoding it again.
  1033. Document document(std::move(value), key, version, DocumentState::kSynced, Wrap(change.document));
  1034. std::vector<TargetId> updatedTargetIDs = [self decodedIntegerArray:change.targetIdsArray];
  1035. std::vector<TargetId> removedTargetIDs = [self decodedIntegerArray:change.removedTargetIdsArray];
  1036. return absl::make_unique<DocumentWatchChange>(std::move(updatedTargetIDs),
  1037. std::move(removedTargetIDs), std::move(key),
  1038. std::move(document));
  1039. }
  1040. - (std::unique_ptr<WatchChange>)decodedDocumentDelete:(GCFSDocumentDelete *)change {
  1041. DocumentKey key = [self decodedDocumentKey:change.document];
  1042. // Note that version might be unset in which case we use SnapshotVersion::None()
  1043. SnapshotVersion version = [self decodedVersion:change.readTime];
  1044. NoDocument document(key, version, /* has_committed_mutations= */ false);
  1045. std::vector<TargetId> removedTargetIDs = [self decodedIntegerArray:change.removedTargetIdsArray];
  1046. return absl::make_unique<DocumentWatchChange>(
  1047. std::vector<TargetId>{}, std::move(removedTargetIDs), std::move(key), std::move(document));
  1048. }
  1049. - (std::unique_ptr<WatchChange>)decodedDocumentRemove:(GCFSDocumentRemove *)change {
  1050. DocumentKey key = [self decodedDocumentKey:change.document];
  1051. std::vector<TargetId> removedTargetIDs = [self decodedIntegerArray:change.removedTargetIdsArray];
  1052. return absl::make_unique<DocumentWatchChange>(
  1053. std::vector<TargetId>{}, std::move(removedTargetIDs), std::move(key), absl::nullopt);
  1054. }
  1055. - (std::unique_ptr<WatchChange>)decodedExistenceFilterWatchChange:(GCFSExistenceFilter *)filter {
  1056. ExistenceFilter existenceFilter{filter.count};
  1057. TargetId targetID = filter.targetId;
  1058. return absl::make_unique<ExistenceFilterWatchChange>(existenceFilter, targetID);
  1059. }
  1060. @end
  1061. NS_ASSUME_NONNULL_END