FSTSerializerBeta.mm 48 KB

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