FSTSerializerBeta.mm 48 KB

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