FSTSerializerBeta.mm 46 KB

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