FSTFieldValue.mm 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002
  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::model::DatabaseId;
  32. using firebase::firestore::model::FieldMask;
  33. using firebase::firestore::model::FieldPath;
  34. using firebase::firestore::model::FieldValue;
  35. using firebase::firestore::model::FieldValueOptions;
  36. using firebase::firestore::model::ServerTimestampBehavior;
  37. using firebase::firestore::util::Comparator;
  38. using firebase::firestore::util::CompareMixedNumber;
  39. using firebase::firestore::util::DoubleBitwiseEquals;
  40. using firebase::firestore::util::DoubleBitwiseHash;
  41. using firebase::firestore::util::MakeStringView;
  42. using firebase::firestore::util::ReverseOrder;
  43. using firebase::firestore::util::WrapCompare;
  44. NS_ASSUME_NONNULL_BEGIN
  45. #pragma mark - FSTFieldValue
  46. @interface FSTFieldValue ()
  47. - (NSComparisonResult)defaultCompare:(FSTFieldValue *)other;
  48. @end
  49. @implementation FSTFieldValue
  50. @dynamic type;
  51. @dynamic typeOrder;
  52. - (FieldValue::Type)type {
  53. @throw FSTAbstractMethodException(); // NOLINT
  54. }
  55. - (FSTTypeOrder)typeOrder {
  56. @throw FSTAbstractMethodException(); // NOLINT
  57. }
  58. - (id)value {
  59. @throw FSTAbstractMethodException(); // NOLINT
  60. }
  61. - (id)valueWithOptions:(const FieldValueOptions &)options {
  62. return [self value];
  63. }
  64. - (BOOL)isEqual:(id)other {
  65. @throw FSTAbstractMethodException(); // NOLINT
  66. }
  67. - (NSUInteger)hash {
  68. @throw FSTAbstractMethodException(); // NOLINT
  69. }
  70. - (NSComparisonResult)compare:(FSTFieldValue *)other {
  71. @throw FSTAbstractMethodException(); // NOLINT
  72. }
  73. - (NSString *)description {
  74. return [[self value] description];
  75. }
  76. - (NSComparisonResult)defaultCompare:(FSTFieldValue *)other {
  77. if (self.typeOrder > other.typeOrder) {
  78. return NSOrderedDescending;
  79. } else {
  80. HARD_ASSERT(self.typeOrder < other.typeOrder,
  81. "defaultCompare should not be used for values of same type.");
  82. return NSOrderedAscending;
  83. }
  84. }
  85. @end
  86. #pragma mark - FSTNullValue
  87. @implementation FSTNullValue
  88. + (instancetype)nullValue {
  89. static FSTNullValue *sharedInstance = nil;
  90. static dispatch_once_t onceToken;
  91. dispatch_once(&onceToken, ^{
  92. sharedInstance = [[FSTNullValue alloc] init];
  93. });
  94. return sharedInstance;
  95. }
  96. - (FieldValue::Type)type {
  97. return FieldValue::Type::Null;
  98. }
  99. - (FSTTypeOrder)typeOrder {
  100. return FSTTypeOrderNull;
  101. }
  102. - (id)value {
  103. return [NSNull null];
  104. }
  105. - (BOOL)isEqual:(id)other {
  106. return [other isKindOfClass:[self class]];
  107. }
  108. - (NSUInteger)hash {
  109. return 47;
  110. }
  111. - (NSComparisonResult)compare:(FSTFieldValue *)other {
  112. if ([other isKindOfClass:[self class]]) {
  113. return NSOrderedSame;
  114. } else {
  115. return [self defaultCompare:other];
  116. }
  117. }
  118. @end
  119. #pragma mark - FSTNumberValue
  120. @implementation FSTNumberValue
  121. - (FSTTypeOrder)typeOrder {
  122. return FSTTypeOrderNumber;
  123. }
  124. - (NSComparisonResult)compare:(FSTFieldValue *)other {
  125. if (!FieldValue::IsNumber(other.type)) {
  126. return [self defaultCompare:other];
  127. } else {
  128. if (self.type == FieldValue::Type::Double) {
  129. double thisDouble = ((FSTDoubleValue *)self).internalValue;
  130. if (other.type == FieldValue::Type::Double) {
  131. return WrapCompare(thisDouble, ((FSTDoubleValue *)other).internalValue);
  132. } else {
  133. HARD_ASSERT(other.type == FieldValue::Type::Integer, "Unknown number value: %s", other);
  134. auto result = CompareMixedNumber(thisDouble, ((FSTIntegerValue *)other).internalValue);
  135. return static_cast<NSComparisonResult>(result);
  136. }
  137. } else {
  138. int64_t thisInt = ((FSTIntegerValue *)self).internalValue;
  139. if (other.type == FieldValue::Type::Integer) {
  140. return WrapCompare(thisInt, ((FSTIntegerValue *)other).internalValue);
  141. } else {
  142. HARD_ASSERT(other.type == FieldValue::Type::Double, "Unknown number value: %s", other);
  143. double otherDouble = ((FSTDoubleValue *)other).internalValue;
  144. auto result = ReverseOrder(CompareMixedNumber(otherDouble, thisInt));
  145. return static_cast<NSComparisonResult>(result);
  146. }
  147. }
  148. }
  149. }
  150. @end
  151. #pragma mark - FSTIntegerValue
  152. @interface FSTIntegerValue ()
  153. @property(nonatomic, assign, readonly) int64_t internalValue;
  154. @end
  155. @implementation FSTIntegerValue
  156. + (instancetype)integerValue:(int64_t)value {
  157. return [[FSTIntegerValue alloc] initWithValue:value];
  158. }
  159. - (id)initWithValue:(int64_t)value {
  160. self = [super init];
  161. if (self) {
  162. _internalValue = value;
  163. }
  164. return self;
  165. }
  166. - (id)value {
  167. return @(self.internalValue);
  168. }
  169. - (FieldValue::Type)type {
  170. return FieldValue::Type::Integer;
  171. }
  172. - (BOOL)isEqual:(id)other {
  173. // NOTE: DoubleValue and LongValue instances may compare: the same, but that doesn't make them
  174. // equal via isEqual:
  175. return [other isKindOfClass:[FSTFieldValue class]] &&
  176. ((FSTFieldValue *)other).type == FieldValue::Type::Integer &&
  177. self.internalValue == ((FSTIntegerValue *)other).internalValue;
  178. }
  179. - (NSUInteger)hash {
  180. return (((NSUInteger)self.internalValue) ^ (NSUInteger)(self.internalValue >> 32));
  181. }
  182. // NOTE: compare: is implemented in NumberValue.
  183. @end
  184. #pragma mark - FSTDoubleValue
  185. @interface FSTDoubleValue ()
  186. @property(nonatomic, assign, readonly) double internalValue;
  187. @end
  188. @implementation FSTDoubleValue
  189. + (instancetype)doubleValue:(double)value {
  190. // Normalize NaNs to match the behavior on the backend (which uses Double.doubletoLongBits()).
  191. if (isnan(value)) {
  192. return [FSTDoubleValue nanValue];
  193. }
  194. return [[FSTDoubleValue alloc] initWithValue:value];
  195. }
  196. + (instancetype)nanValue {
  197. static FSTDoubleValue *sharedInstance = nil;
  198. static dispatch_once_t onceToken;
  199. dispatch_once(&onceToken, ^{
  200. sharedInstance = [[FSTDoubleValue alloc] initWithValue:NAN];
  201. });
  202. return sharedInstance;
  203. }
  204. - (id)initWithValue:(double)value {
  205. self = [super init];
  206. if (self) {
  207. _internalValue = value;
  208. }
  209. return self;
  210. }
  211. - (id)value {
  212. return @(self.internalValue);
  213. }
  214. - (FieldValue::Type)type {
  215. return FieldValue::Type::Double;
  216. }
  217. - (BOOL)isEqual:(id)other {
  218. // NOTE: DoubleValue and LongValue instances may compare: the same, but that doesn't make them
  219. // equal via isEqual:
  220. // NOTE: isEqual: should compare NaN equal to itself and -0.0 not equal to 0.0.
  221. return [other isKindOfClass:[FSTFieldValue class]] &&
  222. ((FSTFieldValue *)other).type == FieldValue::Type::Double &&
  223. DoubleBitwiseEquals(self.internalValue, ((FSTDoubleValue *)other).internalValue);
  224. }
  225. - (NSUInteger)hash {
  226. return DoubleBitwiseHash(self.internalValue);
  227. }
  228. // NOTE: compare: is implemented in NumberValue.
  229. @end
  230. #pragma mark - FSTTimestampValue
  231. @interface FSTTimestampValue ()
  232. @property(nonatomic, strong, readonly) FIRTimestamp *internalValue;
  233. @end
  234. @implementation FSTTimestampValue
  235. + (instancetype)timestampValue:(FIRTimestamp *)value {
  236. return [[FSTTimestampValue alloc] initWithValue:value];
  237. }
  238. - (id)initWithValue:(FIRTimestamp *)value {
  239. self = [super init];
  240. if (self) {
  241. _internalValue = value; // FIRTimestamp is immutable.
  242. }
  243. return self;
  244. }
  245. - (FieldValue::Type)type {
  246. return FieldValue::Type::Timestamp;
  247. }
  248. - (FSTTypeOrder)typeOrder {
  249. return FSTTypeOrderTimestamp;
  250. }
  251. - (id)value {
  252. return self.internalValue;
  253. }
  254. - (id)valueWithOptions:(const FieldValueOptions &)options {
  255. if (options.timestamps_in_snapshots_enabled()) {
  256. return self.value;
  257. } else {
  258. return [self.value dateValue];
  259. }
  260. }
  261. - (BOOL)isEqual:(id)other {
  262. return [other isKindOfClass:[FSTFieldValue class]] &&
  263. ((FSTFieldValue *)other).type == FieldValue::Type::Timestamp &&
  264. [self.internalValue isEqual:((FSTTimestampValue *)other).internalValue];
  265. }
  266. - (NSUInteger)hash {
  267. return [self.internalValue hash];
  268. }
  269. - (NSComparisonResult)compare:(FSTFieldValue *)other {
  270. if (other.type == FieldValue::Type::Timestamp) {
  271. return [self.internalValue compare:((FSTTimestampValue *)other).internalValue];
  272. } else if (other.type == FieldValue::Type::ServerTimestamp) {
  273. // Concrete timestamps come before server timestamps.
  274. return NSOrderedAscending;
  275. } else {
  276. return [self defaultCompare:other];
  277. }
  278. }
  279. @end
  280. #pragma mark - FSTServerTimestampValue
  281. @implementation FSTServerTimestampValue
  282. + (instancetype)serverTimestampValueWithLocalWriteTime:(FIRTimestamp *)localWriteTime
  283. previousValue:(nullable FSTFieldValue *)previousValue {
  284. return [[FSTServerTimestampValue alloc] initWithLocalWriteTime:localWriteTime
  285. previousValue:previousValue];
  286. }
  287. - (id)initWithLocalWriteTime:(FIRTimestamp *)localWriteTime
  288. previousValue:(nullable FSTFieldValue *)previousValue {
  289. self = [super init];
  290. if (self) {
  291. _localWriteTime = localWriteTime;
  292. _previousValue = previousValue;
  293. }
  294. return self;
  295. }
  296. - (FieldValue::Type)type {
  297. return FieldValue::Type::ServerTimestamp;
  298. }
  299. - (FSTTypeOrder)typeOrder {
  300. return FSTTypeOrderTimestamp;
  301. }
  302. - (id)value {
  303. return [NSNull null];
  304. }
  305. - (id)valueWithOptions:(const FieldValueOptions &)options {
  306. switch (options.server_timestamp_behavior()) {
  307. case ServerTimestampBehavior::kNone:
  308. return [NSNull null];
  309. case ServerTimestampBehavior::kEstimate:
  310. return [[FSTTimestampValue timestampValue:self.localWriteTime] valueWithOptions:options];
  311. case ServerTimestampBehavior::kPrevious:
  312. return self.previousValue ? [self.previousValue valueWithOptions:options] : [NSNull null];
  313. default:
  314. HARD_FAIL("Unexpected server timestamp option: %s", options.server_timestamp_behavior());
  315. }
  316. }
  317. - (BOOL)isEqual:(id)other {
  318. return [other isKindOfClass:[FSTFieldValue class]] &&
  319. ((FSTFieldValue *)other).type == FieldValue::Type::ServerTimestamp &&
  320. [self.localWriteTime isEqual:((FSTServerTimestampValue *)other).localWriteTime];
  321. }
  322. - (NSUInteger)hash {
  323. return [self.localWriteTime hash];
  324. }
  325. - (NSString *)description {
  326. return [NSString stringWithFormat:@"<ServerTimestamp localTime=%@>", self.localWriteTime];
  327. }
  328. - (NSComparisonResult)compare:(FSTFieldValue *)other {
  329. if (other.type == FieldValue::Type::ServerTimestamp) {
  330. return [self.localWriteTime compare:((FSTServerTimestampValue *)other).localWriteTime];
  331. } else if (other.type == FieldValue::Type::Timestamp) {
  332. // Server timestamps come after all concrete timestamps.
  333. return NSOrderedDescending;
  334. } else {
  335. return [self defaultCompare:other];
  336. }
  337. }
  338. @end
  339. #pragma mark - FSTGeoPointValue
  340. @interface FSTGeoPointValue ()
  341. @property(nonatomic, strong, readonly) FIRGeoPoint *internalValue;
  342. @end
  343. @implementation FSTGeoPointValue
  344. + (instancetype)geoPointValue:(FIRGeoPoint *)value {
  345. return [[FSTGeoPointValue alloc] initWithValue:value];
  346. }
  347. - (id)initWithValue:(FIRGeoPoint *)value {
  348. self = [super init];
  349. if (self) {
  350. _internalValue = value; // FIRGeoPoint is immutable.
  351. }
  352. return self;
  353. }
  354. - (FieldValue::Type)type {
  355. return FieldValue::Type::GeoPoint;
  356. }
  357. - (FSTTypeOrder)typeOrder {
  358. return FSTTypeOrderGeoPoint;
  359. }
  360. - (id)value {
  361. return self.internalValue;
  362. }
  363. - (BOOL)isEqual:(id)other {
  364. return [other isKindOfClass:[FSTFieldValue class]] &&
  365. ((FSTFieldValue *)other).type == FieldValue::Type::GeoPoint &&
  366. [self.internalValue isEqual:((FSTGeoPointValue *)other).internalValue];
  367. }
  368. - (NSUInteger)hash {
  369. return [self.internalValue hash];
  370. }
  371. - (NSComparisonResult)compare:(FSTFieldValue *)other {
  372. if (other.type == FieldValue::Type::GeoPoint) {
  373. return [self.internalValue compare:((FSTGeoPointValue *)other).internalValue];
  374. } else {
  375. return [self defaultCompare:other];
  376. }
  377. }
  378. @end
  379. #pragma mark - FSTBlobValue
  380. static NSComparisonResult CompareBytes(NSData *left, NSData *right) {
  381. NSUInteger minLength = MIN(left.length, right.length);
  382. int result = memcmp(left.bytes, right.bytes, minLength);
  383. if (result < 0) {
  384. return NSOrderedAscending;
  385. } else if (result > 0) {
  386. return NSOrderedDescending;
  387. } else if (left.length < right.length) {
  388. return NSOrderedAscending;
  389. } else if (left.length > right.length) {
  390. return NSOrderedDescending;
  391. } else {
  392. return NSOrderedSame;
  393. }
  394. }
  395. @interface FSTBlobValue ()
  396. @property(nonatomic, copy, readonly) NSData *internalValue;
  397. @end
  398. // TODO(b/37267885): Add truncation support
  399. @implementation FSTBlobValue
  400. + (instancetype)blobValue:(NSData *)value {
  401. return [[FSTBlobValue alloc] initWithValue:value];
  402. }
  403. - (id)initWithValue:(NSData *)value {
  404. self = [super init];
  405. if (self) {
  406. _internalValue = [value copy];
  407. }
  408. return self;
  409. }
  410. - (FieldValue::Type)type {
  411. return FieldValue::Type::Blob;
  412. }
  413. - (FSTTypeOrder)typeOrder {
  414. return FSTTypeOrderBlob;
  415. }
  416. - (id)value {
  417. return self.internalValue;
  418. }
  419. - (BOOL)isEqual:(id)other {
  420. return [other isKindOfClass:[FSTFieldValue class]] &&
  421. ((FSTFieldValue *)other).type == FieldValue::Type::Blob &&
  422. [self.internalValue isEqual:((FSTBlobValue *)other).internalValue];
  423. }
  424. - (NSUInteger)hash {
  425. return [self.internalValue hash];
  426. }
  427. - (NSComparisonResult)compare:(FSTFieldValue *)other {
  428. if (other.type == FieldValue::Type::Blob) {
  429. return CompareBytes(self.internalValue, ((FSTBlobValue *)other).internalValue);
  430. } else {
  431. return [self defaultCompare:other];
  432. }
  433. }
  434. @end
  435. #pragma mark - FSTReferenceValue
  436. @interface FSTReferenceValue ()
  437. @property(nonatomic, strong, readonly) FSTDocumentKey *key;
  438. @end
  439. @implementation FSTReferenceValue
  440. + (instancetype)referenceValue:(FSTDocumentKey *)value databaseID:(const DatabaseId *)databaseID {
  441. return [[FSTReferenceValue alloc] initWithValue:value databaseID:databaseID];
  442. }
  443. - (id)initWithValue:(FSTDocumentKey *)value databaseID:(const DatabaseId *)databaseID {
  444. self = [super init];
  445. if (self) {
  446. _key = value;
  447. _databaseID = databaseID;
  448. }
  449. return self;
  450. }
  451. - (id)value {
  452. return self.key;
  453. }
  454. - (FieldValue::Type)type {
  455. return FieldValue::Type::Reference;
  456. }
  457. - (FSTTypeOrder)typeOrder {
  458. return FSTTypeOrderReference;
  459. }
  460. - (BOOL)isEqual:(id)other {
  461. if (other == self) {
  462. return YES;
  463. }
  464. if (!([other isKindOfClass:[FSTFieldValue class]] &&
  465. ((FSTFieldValue *)other).type == FieldValue::Type::Reference)) {
  466. return NO;
  467. }
  468. FSTReferenceValue *otherRef = (FSTReferenceValue *)other;
  469. return self.key.key == otherRef.key.key && *self.databaseID == *otherRef.databaseID;
  470. }
  471. - (NSUInteger)hash {
  472. NSUInteger result = self.databaseID->Hash();
  473. result = 31 * result + [self.key hash];
  474. return result;
  475. }
  476. - (NSComparisonResult)compare:(FSTFieldValue *)other {
  477. if (other.type == FieldValue::Type::Reference) {
  478. FSTReferenceValue *ref = (FSTReferenceValue *)other;
  479. NSComparisonResult cmp =
  480. WrapCompare(self.databaseID->project_id(), ref.databaseID->project_id());
  481. if (cmp != NSOrderedSame) {
  482. return cmp;
  483. }
  484. cmp = WrapCompare(self.databaseID->database_id(), ref.databaseID->database_id());
  485. return cmp != NSOrderedSame ? cmp : WrapCompare(self.key.key, ref.key.key);
  486. } else {
  487. return [self defaultCompare:other];
  488. }
  489. }
  490. @end
  491. #pragma mark - FSTObjectValue
  492. /**
  493. * Specialization of Comparator for NSStrings.
  494. */
  495. static const NSComparator StringComparator = ^NSComparisonResult(NSString *left, NSString *right) {
  496. return WrapCompare(left, right);
  497. };
  498. @interface FSTObjectValue ()
  499. @property(nonatomic, strong, readonly)
  500. FSTImmutableSortedDictionary<NSString *, FSTFieldValue *> *internalValue;
  501. @end
  502. @implementation FSTObjectValue
  503. + (instancetype)objectValue {
  504. static FSTObjectValue *sharedEmptyInstance = nil;
  505. static dispatch_once_t onceToken;
  506. dispatch_once(&onceToken, ^{
  507. FSTImmutableSortedDictionary<NSString *, FSTFieldValue *> *empty =
  508. [FSTImmutableSortedDictionary dictionaryWithComparator:StringComparator];
  509. sharedEmptyInstance = [[FSTObjectValue alloc] initWithImmutableDictionary:empty];
  510. });
  511. return sharedEmptyInstance;
  512. }
  513. - (instancetype)initWithImmutableDictionary:
  514. (FSTImmutableSortedDictionary<NSString *, FSTFieldValue *> *)value {
  515. self = [super init];
  516. if (self) {
  517. _internalValue = value; // FSTImmutableSortedDictionary is immutable.
  518. }
  519. return self;
  520. }
  521. - (id)initWithDictionary:(NSDictionary<NSString *, FSTFieldValue *> *)value {
  522. FSTImmutableSortedDictionary<NSString *, FSTFieldValue *> *dictionary =
  523. [FSTImmutableSortedDictionary dictionaryWithDictionary:value comparator:StringComparator];
  524. return [self initWithImmutableDictionary:dictionary];
  525. }
  526. - (id)value {
  527. NSMutableDictionary *result = [NSMutableDictionary dictionary];
  528. [self.internalValue
  529. enumerateKeysAndObjectsUsingBlock:^(NSString *key, FSTFieldValue *obj, BOOL *stop) {
  530. result[key] = [obj value];
  531. }];
  532. return result;
  533. }
  534. - (id)valueWithOptions:(const FieldValueOptions &)options {
  535. NSMutableDictionary *result = [NSMutableDictionary dictionary];
  536. [self.internalValue
  537. enumerateKeysAndObjectsUsingBlock:^(NSString *key, FSTFieldValue *obj, BOOL *stop) {
  538. result[key] = [obj valueWithOptions:options];
  539. }];
  540. return result;
  541. }
  542. - (FieldValue::Type)type {
  543. return FieldValue::Type::Object;
  544. }
  545. - (FSTTypeOrder)typeOrder {
  546. return FSTTypeOrderObject;
  547. }
  548. - (BOOL)isEqual:(id)other {
  549. if (other == self) {
  550. return YES;
  551. }
  552. if (!([other isKindOfClass:[FSTFieldValue class]] &&
  553. ((FSTFieldValue *)other).type == FieldValue::Type::Object)) {
  554. return NO;
  555. }
  556. FSTObjectValue *otherObj = other;
  557. return [self.internalValue isEqual:otherObj.internalValue];
  558. }
  559. - (NSUInteger)hash {
  560. return [self.internalValue hash];
  561. }
  562. - (NSComparisonResult)compare:(FSTFieldValue *)other {
  563. if (other.type == FieldValue::Type::Object) {
  564. FSTImmutableSortedDictionary *selfDict = self.internalValue;
  565. FSTImmutableSortedDictionary *otherDict = ((FSTObjectValue *)other).internalValue;
  566. NSEnumerator *enumerator1 = [selfDict keyEnumerator];
  567. NSEnumerator *enumerator2 = [otherDict keyEnumerator];
  568. NSString *key1 = [enumerator1 nextObject];
  569. NSString *key2 = [enumerator2 nextObject];
  570. while (key1 && key2) {
  571. NSComparisonResult keyCompare = [key1 compare:key2];
  572. if (keyCompare != NSOrderedSame) {
  573. return keyCompare;
  574. }
  575. NSComparisonResult valueCompare = [selfDict[key1] compare:otherDict[key2]];
  576. if (valueCompare != NSOrderedSame) {
  577. return valueCompare;
  578. }
  579. key1 = [enumerator1 nextObject];
  580. key2 = [enumerator2 nextObject];
  581. }
  582. // Only equal if both enumerators are exhausted.
  583. return WrapCompare(key1 != nil, key2 != nil);
  584. } else {
  585. return [self defaultCompare:other];
  586. }
  587. }
  588. - (nullable FSTFieldValue *)valueForPath:(const FieldPath &)fieldPath {
  589. FSTFieldValue *value = self;
  590. for (size_t i = 0, max = fieldPath.size(); value && i < max; i++) {
  591. if (![value isMemberOfClass:[FSTObjectValue class]]) {
  592. return nil;
  593. }
  594. NSString *fieldName = util::WrapNSStringNoCopy(fieldPath[i]);
  595. value = ((FSTObjectValue *)value).internalValue[fieldName];
  596. }
  597. return value;
  598. }
  599. - (FSTObjectValue *)objectBySettingValue:(FSTFieldValue *)value
  600. forPath:(const FieldPath &)fieldPath {
  601. HARD_ASSERT(fieldPath.size() > 0, "Cannot set value with an empty path");
  602. NSString *childName = util::WrapNSString(fieldPath.first_segment());
  603. if (fieldPath.size() == 1) {
  604. // Recursive base case:
  605. return [self objectBySettingValue:value forField:childName];
  606. } else {
  607. // Nested path. Recursively generate a new sub-object and then wrap a new FSTObjectValue
  608. // around the result.
  609. FSTFieldValue *child = [_internalValue objectForKey:childName];
  610. FSTObjectValue *childObject;
  611. if (child.type == FieldValue::Type::Object) {
  612. childObject = (FSTObjectValue *)child;
  613. } else {
  614. // If the child is not found or is a primitive type, pretend as if an empty object lived
  615. // there.
  616. childObject = [FSTObjectValue objectValue];
  617. }
  618. FSTFieldValue *newChild = [childObject objectBySettingValue:value forPath:fieldPath.PopFirst()];
  619. return [self objectBySettingValue:newChild forField:childName];
  620. }
  621. }
  622. - (FSTObjectValue *)objectByDeletingPath:(const FieldPath &)fieldPath {
  623. HARD_ASSERT(fieldPath.size() > 0, "Cannot delete an empty path");
  624. NSString *childName = util::WrapNSString(fieldPath.first_segment());
  625. if (fieldPath.size() == 1) {
  626. return [[FSTObjectValue alloc]
  627. initWithImmutableDictionary:[_internalValue dictionaryByRemovingObjectForKey:childName]];
  628. } else {
  629. FSTFieldValue *child = _internalValue[childName];
  630. if (child.type == FieldValue::Type::Object) {
  631. FSTObjectValue *newChild =
  632. [((FSTObjectValue *)child) objectByDeletingPath:fieldPath.PopFirst()];
  633. return [self objectBySettingValue:newChild forField:childName];
  634. } else {
  635. // If the child is not found or is a primitive type, make no modifications
  636. return self;
  637. }
  638. }
  639. }
  640. - (FSTObjectValue *)objectBySettingValue:(FSTFieldValue *)value forField:(NSString *)field {
  641. return [[FSTObjectValue alloc]
  642. initWithImmutableDictionary:[_internalValue dictionaryBySettingObject:value forKey:field]];
  643. }
  644. - (FSTObjectValue *)objectByApplyingFieldMask:(const FieldMask &)fieldMask {
  645. FSTObjectValue *filteredObject = self;
  646. for (const FieldPath &path : fieldMask) {
  647. if (path.empty()) {
  648. return self;
  649. } else {
  650. FSTFieldValue *newValue = [self valueForPath:path];
  651. if (newValue) {
  652. filteredObject = [filteredObject objectBySettingValue:newValue forPath:path];
  653. }
  654. }
  655. }
  656. return filteredObject;
  657. }
  658. @end
  659. @interface FSTArrayValue ()
  660. @property(nonatomic, strong, readonly) NSArray<FSTFieldValue *> *internalValue;
  661. @end
  662. #pragma mark - FSTArrayValue
  663. @implementation FSTArrayValue
  664. - (id)initWithValueNoCopy:(NSArray<FSTFieldValue *> *)value {
  665. self = [super init];
  666. if (self) {
  667. // Does not copy, assumes the caller has already copied.
  668. _internalValue = value;
  669. }
  670. return self;
  671. }
  672. - (BOOL)isEqual:(id)other {
  673. if (other == self) {
  674. return YES;
  675. }
  676. if (![other isKindOfClass:[self class]]) {
  677. return NO;
  678. }
  679. // NSArray's isEqual does the right thing for our purposes.
  680. FSTArrayValue *otherArray = other;
  681. return [self.internalValue isEqual:otherArray.internalValue];
  682. }
  683. - (NSUInteger)hash {
  684. return [self.internalValue hash];
  685. }
  686. - (id)value {
  687. NSMutableArray *result = [NSMutableArray arrayWithCapacity:_internalValue.count];
  688. [self.internalValue enumerateObjectsUsingBlock:^(FSTFieldValue *obj, NSUInteger idx, BOOL *stop) {
  689. [result addObject:[obj value]];
  690. }];
  691. return result;
  692. }
  693. - (id)valueWithOptions:(const FieldValueOptions &)options {
  694. NSMutableArray *result = [NSMutableArray arrayWithCapacity:_internalValue.count];
  695. [self.internalValue enumerateObjectsUsingBlock:^(FSTFieldValue *obj, NSUInteger idx, BOOL *stop) {
  696. [result addObject:[obj valueWithOptions:options]];
  697. }];
  698. return result;
  699. }
  700. - (FieldValue::Type)type {
  701. return FieldValue::Type::Array;
  702. }
  703. - (FSTTypeOrder)typeOrder {
  704. return FSTTypeOrderArray;
  705. }
  706. - (NSComparisonResult)compare:(FSTFieldValue *)other {
  707. if (other.type == FieldValue::Type::Array) {
  708. NSArray<FSTFieldValue *> *selfArray = self.internalValue;
  709. NSArray<FSTFieldValue *> *otherArray = ((FSTArrayValue *)other).internalValue;
  710. NSUInteger minLength = MIN(selfArray.count, otherArray.count);
  711. for (NSUInteger i = 0; i < minLength; i++) {
  712. NSComparisonResult cmp = [selfArray[i] compare:otherArray[i]];
  713. if (cmp != NSOrderedSame) {
  714. return cmp;
  715. }
  716. }
  717. return WrapCompare<int64_t>(selfArray.count, otherArray.count);
  718. } else {
  719. return [self defaultCompare:other];
  720. }
  721. }
  722. @end
  723. @implementation FSTDelegateValue {
  724. FieldValue _internalValue;
  725. }
  726. + (instancetype)delegateWithValue:(FieldValue &&)value {
  727. return [[FSTDelegateValue alloc] initWithValue:std::move(value)];
  728. }
  729. - (const FieldValue &)internalValue {
  730. return _internalValue;
  731. }
  732. - (id)initWithValue:(FieldValue &&)value {
  733. self = [super init];
  734. if (self) {
  735. _internalValue = std::move(value);
  736. }
  737. return self;
  738. }
  739. - (FieldValue::Type)type {
  740. return self.internalValue.type();
  741. }
  742. - (FSTTypeOrder)typeOrder {
  743. switch (self.internalValue.type()) {
  744. case FieldValue::Type::Null:
  745. return FSTTypeOrderNull;
  746. case FieldValue::Type::Boolean:
  747. return FSTTypeOrderBoolean;
  748. case FieldValue::Type::Integer:
  749. case FieldValue::Type::Double:
  750. return FSTTypeOrderNumber;
  751. case FieldValue::Type::Timestamp:
  752. case FieldValue::Type::ServerTimestamp:
  753. return FSTTypeOrderTimestamp;
  754. case FieldValue::Type::String:
  755. return FSTTypeOrderString;
  756. case FieldValue::Type::Blob:
  757. return FSTTypeOrderBlob;
  758. case FieldValue::Type::Reference:
  759. return FSTTypeOrderReference;
  760. case FieldValue::Type::GeoPoint:
  761. return FSTTypeOrderGeoPoint;
  762. case FieldValue::Type::Array:
  763. return FSTTypeOrderArray;
  764. case FieldValue::Type::Object:
  765. return FSTTypeOrderObject;
  766. }
  767. UNREACHABLE();
  768. }
  769. - (BOOL)isEqual:(id)other {
  770. // TODO(rsgowman): Port the other FST*Value's, and then remove this comment:
  771. //
  772. // Simplification: We'll assume that (eg) FSTBooleanValue(true) !=
  773. // FSTDelegateValue(FieldValue::FromBoolean(true)). That's not great. We'll
  774. // handle this by ensuring that we remove (eg) FSTBooleanValue at the same
  775. // time that FSTDelegateValue handles (eg) booleans to ensure this case never
  776. // occurs.
  777. if (other == self) {
  778. return YES;
  779. }
  780. if (![other isKindOfClass:[self class]]) {
  781. return NO;
  782. }
  783. return self.internalValue == ((FSTDelegateValue *)other).internalValue;
  784. }
  785. - (id)value {
  786. switch (self.internalValue.type()) {
  787. case FieldValue::Type::Null:
  788. HARD_FAIL("TODO(rsgowman): implement");
  789. case FieldValue::Type::Boolean:
  790. return self.internalValue.boolean_value() ? @YES : @NO;
  791. case FieldValue::Type::Integer:
  792. case FieldValue::Type::Double:
  793. case FieldValue::Type::Timestamp:
  794. case FieldValue::Type::ServerTimestamp:
  795. HARD_FAIL("TODO(rsgowman): implement");
  796. case FieldValue::Type::String:
  797. return util::WrapNSString(self.internalValue.string_value());
  798. case FieldValue::Type::Blob:
  799. case FieldValue::Type::Reference:
  800. case FieldValue::Type::GeoPoint:
  801. case FieldValue::Type::Array:
  802. case FieldValue::Type::Object:
  803. HARD_FAIL("TODO(rsgowman): implement");
  804. }
  805. UNREACHABLE();
  806. }
  807. - (NSComparisonResult)compare:(FSTFieldValue *)other {
  808. // TODO(rsgowman): Port the other FST*Value's, and then remove this comment:
  809. //
  810. // Simplification: We'll assume that if Comparable(self.type, other.type),
  811. // then other must be a FSTDelegateValue. That's not great. We'll handle this
  812. // by ensuring that we remove (eg) FSTBooleanValue at the same time that
  813. // FSTDelegateValue handles (eg) booleans to ensure this case never occurs.
  814. if (FieldValue::Comparable(self.type, other.type)) {
  815. HARD_ASSERT([other isKindOfClass:[FSTDelegateValue class]]);
  816. return WrapCompare<FieldValue>(self.internalValue, ((FSTDelegateValue *)other).internalValue);
  817. } else {
  818. return [self defaultCompare:other];
  819. }
  820. }
  821. - (NSUInteger)hash {
  822. return self.internalValue.Hash();
  823. }
  824. @end
  825. NS_ASSUME_NONNULL_END