FSTFieldValue.mm 28 KB

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