FSTSerializerBeta.mm 47 KB

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