FSTSerializerBeta.mm 48 KB

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