FSTSerializerBeta.mm 49 KB

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