FSTFieldValue.mm 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787
  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/Model/FSTFieldValue.h"
  17. #include <functional>
  18. #include <utility>
  19. #import "FIRDocumentSnapshot.h"
  20. #import "FIRTimestamp.h"
  21. #import "Firestore/Source/API/FIRGeoPoint+Internal.h"
  22. #import "Firestore/Source/Model/FSTDocumentKey.h"
  23. #import "Firestore/Source/Util/FSTClasses.h"
  24. #include "Firestore/core/src/firebase/firestore/model/database_id.h"
  25. #include "Firestore/core/src/firebase/firestore/model/document_key.h"
  26. #include "Firestore/core/src/firebase/firestore/model/field_path.h"
  27. #include "Firestore/core/src/firebase/firestore/util/comparison.h"
  28. #include "Firestore/core/src/firebase/firestore/util/hard_assert.h"
  29. #include "Firestore/core/src/firebase/firestore/util/string_apple.h"
  30. namespace util = firebase::firestore::util;
  31. using firebase::firestore::GeoPoint;
  32. using firebase::firestore::model::DatabaseId;
  33. using firebase::firestore::model::FieldMask;
  34. using firebase::firestore::model::FieldPath;
  35. using firebase::firestore::model::FieldValue;
  36. using firebase::firestore::model::FieldValueOptions;
  37. using firebase::firestore::model::ServerTimestampBehavior;
  38. using firebase::firestore::util::Comparator;
  39. using firebase::firestore::util::CompareMixedNumber;
  40. using firebase::firestore::util::DoubleBitwiseEquals;
  41. using firebase::firestore::util::DoubleBitwiseHash;
  42. using firebase::firestore::util::MakeStringView;
  43. using firebase::firestore::util::ReverseOrder;
  44. using firebase::firestore::util::WrapCompare;
  45. NS_ASSUME_NONNULL_BEGIN
  46. #pragma mark - FSTFieldValue
  47. @interface FSTFieldValue ()
  48. - (NSComparisonResult)defaultCompare:(FSTFieldValue *)other;
  49. @end
  50. @implementation FSTFieldValue
  51. @dynamic type;
  52. @dynamic typeOrder;
  53. - (FieldValue::Type)type {
  54. @throw FSTAbstractMethodException(); // NOLINT
  55. }
  56. - (FSTTypeOrder)typeOrder {
  57. @throw FSTAbstractMethodException(); // NOLINT
  58. }
  59. - (id)value {
  60. @throw FSTAbstractMethodException(); // NOLINT
  61. }
  62. - (id)valueWithOptions:(const FieldValueOptions &)options {
  63. return [self value];
  64. }
  65. - (BOOL)isEqual:(id)other {
  66. @throw FSTAbstractMethodException(); // NOLINT
  67. }
  68. - (NSUInteger)hash {
  69. @throw FSTAbstractMethodException(); // NOLINT
  70. }
  71. - (NSComparisonResult)compare:(FSTFieldValue *)other {
  72. @throw FSTAbstractMethodException(); // NOLINT
  73. }
  74. - (NSString *)description {
  75. return [[self value] description];
  76. }
  77. - (NSComparisonResult)defaultCompare:(FSTFieldValue *)other {
  78. if (self.typeOrder > other.typeOrder) {
  79. return NSOrderedDescending;
  80. } else {
  81. HARD_ASSERT(self.typeOrder < other.typeOrder,
  82. "defaultCompare should not be used for values of same type.");
  83. return NSOrderedAscending;
  84. }
  85. }
  86. - (int64_t)integerValue {
  87. return static_cast<FSTDelegateValue *>(self).internalValue.integer_value();
  88. }
  89. - (bool)isNAN {
  90. if (self.type != FieldValue::Type::Double) return false;
  91. return static_cast<FSTDelegateValue *>(self).internalValue.is_nan();
  92. }
  93. - (double)doubleValue {
  94. return static_cast<FSTDelegateValue *>(self).internalValue.double_value();
  95. }
  96. @end
  97. #pragma mark - FSTTimestampValue
  98. @interface FSTTimestampValue ()
  99. @property(nonatomic, strong, readonly) FIRTimestamp *internalValue;
  100. @end
  101. @implementation FSTTimestampValue
  102. + (instancetype)timestampValue:(FIRTimestamp *)value {
  103. return [[FSTTimestampValue alloc] initWithValue:value];
  104. }
  105. - (id)initWithValue:(FIRTimestamp *)value {
  106. self = [super init];
  107. if (self) {
  108. _internalValue = value; // FIRTimestamp is immutable.
  109. }
  110. return self;
  111. }
  112. - (FieldValue::Type)type {
  113. return FieldValue::Type::Timestamp;
  114. }
  115. - (FSTTypeOrder)typeOrder {
  116. return FSTTypeOrderTimestamp;
  117. }
  118. - (id)value {
  119. return self.internalValue;
  120. }
  121. - (id)valueWithOptions:(const FieldValueOptions &)options {
  122. if (options.timestamps_in_snapshots_enabled()) {
  123. return self.value;
  124. } else {
  125. return [self.value dateValue];
  126. }
  127. }
  128. - (BOOL)isEqual:(id)other {
  129. return [other isKindOfClass:[FSTFieldValue class]] &&
  130. ((FSTFieldValue *)other).type == FieldValue::Type::Timestamp &&
  131. [self.internalValue isEqual:((FSTTimestampValue *)other).internalValue];
  132. }
  133. - (NSUInteger)hash {
  134. return [self.internalValue hash];
  135. }
  136. - (NSComparisonResult)compare:(FSTFieldValue *)other {
  137. if (other.type == FieldValue::Type::Timestamp) {
  138. return [self.internalValue compare:((FSTTimestampValue *)other).internalValue];
  139. } else if (other.type == FieldValue::Type::ServerTimestamp) {
  140. // Concrete timestamps come before server timestamps.
  141. return NSOrderedAscending;
  142. } else {
  143. return [self defaultCompare:other];
  144. }
  145. }
  146. @end
  147. #pragma mark - FSTServerTimestampValue
  148. @implementation FSTServerTimestampValue
  149. + (instancetype)serverTimestampValueWithLocalWriteTime:(FIRTimestamp *)localWriteTime
  150. previousValue:(nullable FSTFieldValue *)previousValue {
  151. return [[FSTServerTimestampValue alloc] initWithLocalWriteTime:localWriteTime
  152. previousValue:previousValue];
  153. }
  154. - (id)initWithLocalWriteTime:(FIRTimestamp *)localWriteTime
  155. previousValue:(nullable FSTFieldValue *)previousValue {
  156. self = [super init];
  157. if (self) {
  158. _localWriteTime = localWriteTime;
  159. _previousValue = previousValue;
  160. }
  161. return self;
  162. }
  163. - (FieldValue::Type)type {
  164. return FieldValue::Type::ServerTimestamp;
  165. }
  166. - (FSTTypeOrder)typeOrder {
  167. return FSTTypeOrderTimestamp;
  168. }
  169. - (id)value {
  170. return [NSNull null];
  171. }
  172. - (id)valueWithOptions:(const FieldValueOptions &)options {
  173. switch (options.server_timestamp_behavior()) {
  174. case ServerTimestampBehavior::kNone:
  175. return [NSNull null];
  176. case ServerTimestampBehavior::kEstimate:
  177. return [[FSTTimestampValue timestampValue:self.localWriteTime] valueWithOptions:options];
  178. case ServerTimestampBehavior::kPrevious:
  179. return self.previousValue ? [self.previousValue valueWithOptions:options] : [NSNull null];
  180. default:
  181. HARD_FAIL("Unexpected server timestamp option: %s", options.server_timestamp_behavior());
  182. }
  183. }
  184. - (BOOL)isEqual:(id)other {
  185. return [other isKindOfClass:[FSTFieldValue class]] &&
  186. ((FSTFieldValue *)other).type == FieldValue::Type::ServerTimestamp &&
  187. [self.localWriteTime isEqual:((FSTServerTimestampValue *)other).localWriteTime];
  188. }
  189. - (NSUInteger)hash {
  190. return [self.localWriteTime hash];
  191. }
  192. - (NSString *)description {
  193. return [NSString stringWithFormat:@"<ServerTimestamp localTime=%@>", self.localWriteTime];
  194. }
  195. - (NSComparisonResult)compare:(FSTFieldValue *)other {
  196. if (other.type == FieldValue::Type::ServerTimestamp) {
  197. return [self.localWriteTime compare:((FSTServerTimestampValue *)other).localWriteTime];
  198. } else if (other.type == FieldValue::Type::Timestamp) {
  199. // Server timestamps come after all concrete timestamps.
  200. return NSOrderedDescending;
  201. } else {
  202. return [self defaultCompare:other];
  203. }
  204. }
  205. @end
  206. #pragma mark - FSTBlobValue
  207. static NSComparisonResult CompareBytes(NSData *left, NSData *right) {
  208. NSUInteger minLength = MIN(left.length, right.length);
  209. int result = memcmp(left.bytes, right.bytes, minLength);
  210. if (result < 0) {
  211. return NSOrderedAscending;
  212. } else if (result > 0) {
  213. return NSOrderedDescending;
  214. } else if (left.length < right.length) {
  215. return NSOrderedAscending;
  216. } else if (left.length > right.length) {
  217. return NSOrderedDescending;
  218. } else {
  219. return NSOrderedSame;
  220. }
  221. }
  222. @interface FSTBlobValue ()
  223. @property(nonatomic, copy, readonly) NSData *internalValue;
  224. @end
  225. // TODO(b/37267885): Add truncation support
  226. @implementation FSTBlobValue
  227. + (instancetype)blobValue:(NSData *)value {
  228. return [[FSTBlobValue alloc] initWithValue:value];
  229. }
  230. - (id)initWithValue:(NSData *)value {
  231. self = [super init];
  232. if (self) {
  233. _internalValue = [value copy];
  234. }
  235. return self;
  236. }
  237. - (FieldValue::Type)type {
  238. return FieldValue::Type::Blob;
  239. }
  240. - (FSTTypeOrder)typeOrder {
  241. return FSTTypeOrderBlob;
  242. }
  243. - (id)value {
  244. return self.internalValue;
  245. }
  246. - (BOOL)isEqual:(id)other {
  247. return [other isKindOfClass:[FSTFieldValue class]] &&
  248. ((FSTFieldValue *)other).type == FieldValue::Type::Blob &&
  249. [self.internalValue isEqual:((FSTBlobValue *)other).internalValue];
  250. }
  251. - (NSUInteger)hash {
  252. return [self.internalValue hash];
  253. }
  254. - (NSComparisonResult)compare:(FSTFieldValue *)other {
  255. if (other.type == FieldValue::Type::Blob) {
  256. return CompareBytes(self.internalValue, ((FSTBlobValue *)other).internalValue);
  257. } else {
  258. return [self defaultCompare:other];
  259. }
  260. }
  261. @end
  262. #pragma mark - FSTReferenceValue
  263. @interface FSTReferenceValue ()
  264. @property(nonatomic, strong, readonly) FSTDocumentKey *key;
  265. @end
  266. @implementation FSTReferenceValue {
  267. DatabaseId _databaseID;
  268. }
  269. + (instancetype)referenceValue:(FSTDocumentKey *)value databaseID:(DatabaseId)databaseID {
  270. return [[FSTReferenceValue alloc] initWithValue:value databaseID:std::move(databaseID)];
  271. }
  272. - (id)initWithValue:(FSTDocumentKey *)value databaseID:(DatabaseId)databaseID {
  273. self = [super init];
  274. if (self) {
  275. _key = value;
  276. _databaseID = std::move(databaseID);
  277. }
  278. return self;
  279. }
  280. - (id)value {
  281. return self.key;
  282. }
  283. - (FieldValue::Type)type {
  284. return FieldValue::Type::Reference;
  285. }
  286. - (FSTTypeOrder)typeOrder {
  287. return FSTTypeOrderReference;
  288. }
  289. - (BOOL)isEqual:(id)other {
  290. if (other == self) {
  291. return YES;
  292. }
  293. if (!([other isKindOfClass:[FSTFieldValue class]] &&
  294. ((FSTFieldValue *)other).type == FieldValue::Type::Reference)) {
  295. return NO;
  296. }
  297. FSTReferenceValue *otherRef = (FSTReferenceValue *)other;
  298. return self.key.key == otherRef.key.key && self.databaseID == otherRef.databaseID;
  299. }
  300. - (NSUInteger)hash {
  301. NSUInteger result = self.databaseID.Hash();
  302. result = 31 * result + [self.key hash];
  303. return result;
  304. }
  305. - (NSComparisonResult)compare:(FSTFieldValue *)other {
  306. if (other.type == FieldValue::Type::Reference) {
  307. FSTReferenceValue *ref = (FSTReferenceValue *)other;
  308. NSComparisonResult cmp = WrapCompare(self.databaseID.project_id(), ref.databaseID.project_id());
  309. if (cmp != NSOrderedSame) {
  310. return cmp;
  311. }
  312. cmp = WrapCompare(self.databaseID.database_id(), ref.databaseID.database_id());
  313. return cmp != NSOrderedSame ? cmp : WrapCompare(self.key.key, ref.key.key);
  314. } else {
  315. return [self defaultCompare:other];
  316. }
  317. }
  318. @end
  319. #pragma mark - FSTObjectValue
  320. /**
  321. * Specialization of Comparator for NSStrings.
  322. */
  323. static const NSComparator StringComparator = ^NSComparisonResult(NSString *left, NSString *right) {
  324. return WrapCompare(left, right);
  325. };
  326. @interface FSTObjectValue ()
  327. @property(nonatomic, strong, readonly)
  328. FSTImmutableSortedDictionary<NSString *, FSTFieldValue *> *internalValue;
  329. @end
  330. @implementation FSTObjectValue
  331. + (instancetype)objectValue {
  332. static FSTObjectValue *sharedEmptyInstance = nil;
  333. static dispatch_once_t onceToken;
  334. dispatch_once(&onceToken, ^{
  335. FSTImmutableSortedDictionary<NSString *, FSTFieldValue *> *empty =
  336. [FSTImmutableSortedDictionary dictionaryWithComparator:StringComparator];
  337. sharedEmptyInstance = [[FSTObjectValue alloc] initWithImmutableDictionary:empty];
  338. });
  339. return sharedEmptyInstance;
  340. }
  341. - (instancetype)initWithImmutableDictionary:
  342. (FSTImmutableSortedDictionary<NSString *, FSTFieldValue *> *)value {
  343. self = [super init];
  344. if (self) {
  345. _internalValue = value; // FSTImmutableSortedDictionary is immutable.
  346. }
  347. return self;
  348. }
  349. - (id)initWithDictionary:(NSDictionary<NSString *, FSTFieldValue *> *)value {
  350. FSTImmutableSortedDictionary<NSString *, FSTFieldValue *> *dictionary =
  351. [FSTImmutableSortedDictionary dictionaryWithDictionary:value comparator:StringComparator];
  352. return [self initWithImmutableDictionary:dictionary];
  353. }
  354. - (id)value {
  355. NSMutableDictionary *result = [NSMutableDictionary dictionary];
  356. [self.internalValue
  357. enumerateKeysAndObjectsUsingBlock:^(NSString *key, FSTFieldValue *obj, BOOL *stop) {
  358. result[key] = [obj value];
  359. }];
  360. return result;
  361. }
  362. - (id)valueWithOptions:(const FieldValueOptions &)options {
  363. NSMutableDictionary *result = [NSMutableDictionary dictionary];
  364. [self.internalValue
  365. enumerateKeysAndObjectsUsingBlock:^(NSString *key, FSTFieldValue *obj, BOOL *stop) {
  366. result[key] = [obj valueWithOptions:options];
  367. }];
  368. return result;
  369. }
  370. - (FieldValue::Type)type {
  371. return FieldValue::Type::Object;
  372. }
  373. - (FSTTypeOrder)typeOrder {
  374. return FSTTypeOrderObject;
  375. }
  376. - (BOOL)isEqual:(id)other {
  377. if (other == self) {
  378. return YES;
  379. }
  380. if (!([other isKindOfClass:[FSTFieldValue class]] &&
  381. ((FSTFieldValue *)other).type == FieldValue::Type::Object)) {
  382. return NO;
  383. }
  384. FSTObjectValue *otherObj = other;
  385. return [self.internalValue isEqual:otherObj.internalValue];
  386. }
  387. - (NSUInteger)hash {
  388. return [self.internalValue hash];
  389. }
  390. - (NSComparisonResult)compare:(FSTFieldValue *)other {
  391. if (other.type == FieldValue::Type::Object) {
  392. FSTImmutableSortedDictionary *selfDict = self.internalValue;
  393. FSTImmutableSortedDictionary *otherDict = ((FSTObjectValue *)other).internalValue;
  394. NSEnumerator *enumerator1 = [selfDict keyEnumerator];
  395. NSEnumerator *enumerator2 = [otherDict keyEnumerator];
  396. NSString *key1 = [enumerator1 nextObject];
  397. NSString *key2 = [enumerator2 nextObject];
  398. while (key1 && key2) {
  399. NSComparisonResult keyCompare = [key1 compare:key2];
  400. if (keyCompare != NSOrderedSame) {
  401. return keyCompare;
  402. }
  403. NSComparisonResult valueCompare = [selfDict[key1] compare:otherDict[key2]];
  404. if (valueCompare != NSOrderedSame) {
  405. return valueCompare;
  406. }
  407. key1 = [enumerator1 nextObject];
  408. key2 = [enumerator2 nextObject];
  409. }
  410. // Only equal if both enumerators are exhausted.
  411. return WrapCompare(key1 != nil, key2 != nil);
  412. } else {
  413. return [self defaultCompare:other];
  414. }
  415. }
  416. - (nullable FSTFieldValue *)valueForPath:(const FieldPath &)fieldPath {
  417. FSTFieldValue *value = self;
  418. for (size_t i = 0, max = fieldPath.size(); value && i < max; i++) {
  419. if (![value isMemberOfClass:[FSTObjectValue class]]) {
  420. return nil;
  421. }
  422. NSString *fieldName = util::WrapNSStringNoCopy(fieldPath[i]);
  423. value = ((FSTObjectValue *)value).internalValue[fieldName];
  424. }
  425. return value;
  426. }
  427. - (FSTObjectValue *)objectBySettingValue:(FSTFieldValue *)value
  428. forPath:(const FieldPath &)fieldPath {
  429. HARD_ASSERT(fieldPath.size() > 0, "Cannot set value with an empty path");
  430. NSString *childName = util::WrapNSString(fieldPath.first_segment());
  431. if (fieldPath.size() == 1) {
  432. // Recursive base case:
  433. return [self objectBySettingValue:value forField:childName];
  434. } else {
  435. // Nested path. Recursively generate a new sub-object and then wrap a new FSTObjectValue
  436. // around the result.
  437. FSTFieldValue *child = [_internalValue objectForKey:childName];
  438. FSTObjectValue *childObject;
  439. if (child.type == FieldValue::Type::Object) {
  440. childObject = (FSTObjectValue *)child;
  441. } else {
  442. // If the child is not found or is a primitive type, pretend as if an empty object lived
  443. // there.
  444. childObject = [FSTObjectValue objectValue];
  445. }
  446. FSTFieldValue *newChild = [childObject objectBySettingValue:value forPath:fieldPath.PopFirst()];
  447. return [self objectBySettingValue:newChild forField:childName];
  448. }
  449. }
  450. - (FSTObjectValue *)objectByDeletingPath:(const FieldPath &)fieldPath {
  451. HARD_ASSERT(fieldPath.size() > 0, "Cannot delete an empty path");
  452. NSString *childName = util::WrapNSString(fieldPath.first_segment());
  453. if (fieldPath.size() == 1) {
  454. return [[FSTObjectValue alloc]
  455. initWithImmutableDictionary:[_internalValue dictionaryByRemovingObjectForKey:childName]];
  456. } else {
  457. FSTFieldValue *child = _internalValue[childName];
  458. if (child.type == FieldValue::Type::Object) {
  459. FSTObjectValue *newChild =
  460. [((FSTObjectValue *)child) objectByDeletingPath:fieldPath.PopFirst()];
  461. return [self objectBySettingValue:newChild forField:childName];
  462. } else {
  463. // If the child is not found or is a primitive type, make no modifications
  464. return self;
  465. }
  466. }
  467. }
  468. - (FSTObjectValue *)objectBySettingValue:(FSTFieldValue *)value forField:(NSString *)field {
  469. return [[FSTObjectValue alloc]
  470. initWithImmutableDictionary:[_internalValue dictionaryBySettingObject:value forKey:field]];
  471. }
  472. - (FSTObjectValue *)objectByApplyingFieldMask:(const FieldMask &)fieldMask {
  473. FSTObjectValue *filteredObject = self;
  474. for (const FieldPath &path : fieldMask) {
  475. if (path.empty()) {
  476. return self;
  477. } else {
  478. FSTFieldValue *newValue = [self valueForPath:path];
  479. if (newValue) {
  480. filteredObject = [filteredObject objectBySettingValue:newValue forPath:path];
  481. }
  482. }
  483. }
  484. return filteredObject;
  485. }
  486. @end
  487. @interface FSTArrayValue ()
  488. @property(nonatomic, strong, readonly) NSArray<FSTFieldValue *> *internalValue;
  489. @end
  490. #pragma mark - FSTArrayValue
  491. @implementation FSTArrayValue
  492. - (id)initWithValueNoCopy:(NSArray<FSTFieldValue *> *)value {
  493. self = [super init];
  494. if (self) {
  495. // Does not copy, assumes the caller has already copied.
  496. _internalValue = value;
  497. }
  498. return self;
  499. }
  500. - (BOOL)isEqual:(id)other {
  501. if (other == self) {
  502. return YES;
  503. }
  504. if (![other isKindOfClass:[self class]]) {
  505. return NO;
  506. }
  507. // NSArray's isEqual does the right thing for our purposes.
  508. FSTArrayValue *otherArray = other;
  509. return [self.internalValue isEqual:otherArray.internalValue];
  510. }
  511. - (NSUInteger)hash {
  512. return [self.internalValue hash];
  513. }
  514. - (id)value {
  515. NSMutableArray *result = [NSMutableArray arrayWithCapacity:_internalValue.count];
  516. [self.internalValue enumerateObjectsUsingBlock:^(FSTFieldValue *obj, NSUInteger idx, BOOL *stop) {
  517. [result addObject:[obj value]];
  518. }];
  519. return result;
  520. }
  521. - (id)valueWithOptions:(const FieldValueOptions &)options {
  522. NSMutableArray *result = [NSMutableArray arrayWithCapacity:_internalValue.count];
  523. [self.internalValue enumerateObjectsUsingBlock:^(FSTFieldValue *obj, NSUInteger idx, BOOL *stop) {
  524. [result addObject:[obj valueWithOptions:options]];
  525. }];
  526. return result;
  527. }
  528. - (FieldValue::Type)type {
  529. return FieldValue::Type::Array;
  530. }
  531. - (FSTTypeOrder)typeOrder {
  532. return FSTTypeOrderArray;
  533. }
  534. - (NSComparisonResult)compare:(FSTFieldValue *)other {
  535. if (other.type == FieldValue::Type::Array) {
  536. NSArray<FSTFieldValue *> *selfArray = self.internalValue;
  537. NSArray<FSTFieldValue *> *otherArray = ((FSTArrayValue *)other).internalValue;
  538. NSUInteger minLength = MIN(selfArray.count, otherArray.count);
  539. for (NSUInteger i = 0; i < minLength; i++) {
  540. NSComparisonResult cmp = [selfArray[i] compare:otherArray[i]];
  541. if (cmp != NSOrderedSame) {
  542. return cmp;
  543. }
  544. }
  545. return WrapCompare<int64_t>(selfArray.count, otherArray.count);
  546. } else {
  547. return [self defaultCompare:other];
  548. }
  549. }
  550. @end
  551. @implementation FSTDelegateValue {
  552. FieldValue _internalValue;
  553. }
  554. + (instancetype)delegateWithValue:(FieldValue &&)value {
  555. return [[FSTDelegateValue alloc] initWithValue:std::move(value)];
  556. }
  557. - (const FieldValue &)internalValue {
  558. return _internalValue;
  559. }
  560. - (id)initWithValue:(FieldValue &&)value {
  561. self = [super init];
  562. if (self) {
  563. _internalValue = std::move(value);
  564. }
  565. return self;
  566. }
  567. - (FieldValue::Type)type {
  568. return self.internalValue.type();
  569. }
  570. - (FSTTypeOrder)typeOrder {
  571. switch (self.internalValue.type()) {
  572. case FieldValue::Type::Null:
  573. return FSTTypeOrderNull;
  574. case FieldValue::Type::Boolean:
  575. return FSTTypeOrderBoolean;
  576. case FieldValue::Type::Integer:
  577. case FieldValue::Type::Double:
  578. return FSTTypeOrderNumber;
  579. case FieldValue::Type::Timestamp:
  580. case FieldValue::Type::ServerTimestamp:
  581. return FSTTypeOrderTimestamp;
  582. case FieldValue::Type::String:
  583. return FSTTypeOrderString;
  584. case FieldValue::Type::Blob:
  585. return FSTTypeOrderBlob;
  586. case FieldValue::Type::Reference:
  587. return FSTTypeOrderReference;
  588. case FieldValue::Type::GeoPoint:
  589. return FSTTypeOrderGeoPoint;
  590. case FieldValue::Type::Array:
  591. return FSTTypeOrderArray;
  592. case FieldValue::Type::Object:
  593. return FSTTypeOrderObject;
  594. }
  595. UNREACHABLE();
  596. }
  597. - (BOOL)isEqual:(id)other {
  598. // TODO(rsgowman): Port the other FST*Value's, and then remove this comment:
  599. //
  600. // Simplification: We'll assume that (eg) FSTBooleanValue(true) !=
  601. // FSTDelegateValue(FieldValue::FromBoolean(true)). That's not great. We'll
  602. // handle this by ensuring that we remove (eg) FSTBooleanValue at the same
  603. // time that FSTDelegateValue handles (eg) booleans to ensure this case never
  604. // occurs.
  605. if (other == self) {
  606. return YES;
  607. }
  608. if (![other isKindOfClass:[self class]]) {
  609. return NO;
  610. }
  611. return self.internalValue == ((FSTDelegateValue *)other).internalValue;
  612. }
  613. - (id)value {
  614. switch (self.internalValue.type()) {
  615. case FieldValue::Type::Null:
  616. return [NSNull null];
  617. case FieldValue::Type::Boolean:
  618. return self.internalValue.boolean_value() ? @YES : @NO;
  619. case FieldValue::Type::Integer:
  620. return @(self.internalValue.integer_value());
  621. case FieldValue::Type::Double:
  622. return @(self.internalValue.double_value());
  623. case FieldValue::Type::Timestamp:
  624. case FieldValue::Type::ServerTimestamp:
  625. HARD_FAIL("TODO(rsgowman): implement");
  626. case FieldValue::Type::String:
  627. return util::WrapNSString(self.internalValue.string_value());
  628. case FieldValue::Type::Blob:
  629. case FieldValue::Type::Reference:
  630. HARD_FAIL("TODO(rsgowman): implement");
  631. case FieldValue::Type::GeoPoint: {
  632. GeoPoint value = self.internalValue.geo_point_value();
  633. return [[FIRGeoPoint alloc] initWithLatitude:value.latitude() longitude:value.longitude()];
  634. }
  635. case FieldValue::Type::Array:
  636. case FieldValue::Type::Object:
  637. HARD_FAIL("TODO(rsgowman): implement");
  638. }
  639. UNREACHABLE();
  640. }
  641. - (NSComparisonResult)compare:(FSTFieldValue *)other {
  642. // TODO(rsgowman): Port the other FST*Value's, and then remove this comment:
  643. //
  644. // Simplification: We'll assume that if Comparable(self.type, other.type),
  645. // then other must be a FSTDelegateValue. That's not great. We'll handle this
  646. // by ensuring that we remove (eg) FSTBooleanValue at the same time that
  647. // FSTDelegateValue handles (eg) booleans to ensure this case never occurs.
  648. if (FieldValue::Comparable(self.type, other.type)) {
  649. HARD_ASSERT([other isKindOfClass:[FSTDelegateValue class]]);
  650. return WrapCompare<FieldValue>(self.internalValue, ((FSTDelegateValue *)other).internalValue);
  651. } else {
  652. return [self defaultCompare:other];
  653. }
  654. }
  655. - (NSUInteger)hash {
  656. return self.internalValue.Hash();
  657. }
  658. @end
  659. NS_ASSUME_NONNULL_END