FSTSerializerBeta.mm 48 KB

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