FSTFieldValue.mm 21 KB

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