FIRDocumentSnapshot.m 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  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 "FIRDocumentSnapshot.h"
  17. #import "Firestore/Source/API/FIRDocumentReference+Internal.h"
  18. #import "Firestore/Source/API/FIRFieldPath+Internal.h"
  19. #import "Firestore/Source/API/FIRFirestore+Internal.h"
  20. #import "Firestore/Source/API/FIRSnapshotMetadata+Internal.h"
  21. #import "Firestore/Source/Model/FSTDatabaseID.h"
  22. #import "Firestore/Source/Model/FSTDocument.h"
  23. #import "Firestore/Source/Model/FSTDocumentKey.h"
  24. #import "Firestore/Source/Model/FSTFieldValue.h"
  25. #import "Firestore/Source/Model/FSTPath.h"
  26. #import "Firestore/Source/Util/FSTUsageValidation.h"
  27. NS_ASSUME_NONNULL_BEGIN
  28. @interface FIRDocumentSnapshot ()
  29. - (instancetype)initWithFirestore:(FIRFirestore *)firestore
  30. documentKey:(FSTDocumentKey *)documentKey
  31. document:(nullable FSTDocument *)document
  32. fromCache:(BOOL)fromCache NS_DESIGNATED_INITIALIZER;
  33. @property(nonatomic, strong, readonly) FIRFirestore *firestore;
  34. @property(nonatomic, strong, readonly) FSTDocumentKey *internalKey;
  35. @property(nonatomic, strong, readonly, nullable) FSTDocument *internalDocument;
  36. @property(nonatomic, assign, readonly) BOOL fromCache;
  37. @end
  38. @implementation FIRDocumentSnapshot (Internal)
  39. + (instancetype)snapshotWithFirestore:(FIRFirestore *)firestore
  40. documentKey:(FSTDocumentKey *)documentKey
  41. document:(nullable FSTDocument *)document
  42. fromCache:(BOOL)fromCache {
  43. return [[FIRDocumentSnapshot alloc] initWithFirestore:firestore
  44. documentKey:documentKey
  45. document:document
  46. fromCache:fromCache];
  47. }
  48. @end
  49. @implementation FIRDocumentSnapshot {
  50. FIRSnapshotMetadata *_cachedMetadata;
  51. }
  52. @dynamic metadata;
  53. - (instancetype)initWithFirestore:(FIRFirestore *)firestore
  54. documentKey:(FSTDocumentKey *)documentKey
  55. document:(nullable FSTDocument *)document
  56. fromCache:(BOOL)fromCache {
  57. if (self = [super init]) {
  58. _firestore = firestore;
  59. _internalKey = documentKey;
  60. _internalDocument = document;
  61. _fromCache = fromCache;
  62. }
  63. return self;
  64. }
  65. @dynamic exists;
  66. - (BOOL)exists {
  67. return _internalDocument != nil;
  68. }
  69. - (FIRDocumentReference *)reference {
  70. return [FIRDocumentReference referenceWithKey:self.internalKey firestore:self.firestore];
  71. }
  72. - (NSString *)documentID {
  73. return [self.internalKey.path lastSegment];
  74. }
  75. - (FIRSnapshotMetadata *)metadata {
  76. if (!_cachedMetadata) {
  77. _cachedMetadata = [FIRSnapshotMetadata
  78. snapshotMetadataWithPendingWrites:self.internalDocument.hasLocalMutations
  79. fromCache:self.fromCache];
  80. }
  81. return _cachedMetadata;
  82. }
  83. - (NSDictionary<NSString *, id> *)data {
  84. FSTDocument *document = self.internalDocument;
  85. if (!document) {
  86. FSTThrowInvalidUsage(
  87. @"NonExistentDocumentException",
  88. @"Document '%@' doesn't exist. "
  89. @"Check document.exists to make sure the document exists before calling document.data.",
  90. self.internalKey);
  91. }
  92. return [self convertedObject:[self.internalDocument data]];
  93. }
  94. - (nullable id)objectForKeyedSubscript:(id)key {
  95. FIRFieldPath *fieldPath;
  96. if ([key isKindOfClass:[NSString class]]) {
  97. fieldPath = [FIRFieldPath pathWithDotSeparatedString:key];
  98. } else if ([key isKindOfClass:[FIRFieldPath class]]) {
  99. fieldPath = key;
  100. } else {
  101. FSTThrowInvalidArgument(@"Subscript key must be an NSString or FIRFieldPath.");
  102. }
  103. FSTFieldValue *fieldValue = [[self.internalDocument data] valueForPath:fieldPath.internalValue];
  104. return [self convertedValue:fieldValue];
  105. }
  106. - (id)convertedValue:(FSTFieldValue *)value {
  107. if ([value isKindOfClass:[FSTObjectValue class]]) {
  108. return [self convertedObject:(FSTObjectValue *)value];
  109. } else if ([value isKindOfClass:[FSTArrayValue class]]) {
  110. return [self convertedArray:(FSTArrayValue *)value];
  111. } else if ([value isKindOfClass:[FSTReferenceValue class]]) {
  112. FSTReferenceValue *ref = (FSTReferenceValue *)value;
  113. FSTDatabaseID *refDatabase = ref.databaseID;
  114. FSTDatabaseID *database = self.firestore.databaseID;
  115. if (![refDatabase isEqualToDatabaseId:database]) {
  116. // TODO(b/32073923): Log this as a proper warning.
  117. NSLog(
  118. @"WARNING: Document %@ contains a document reference within a different database "
  119. "(%@/%@) which is not supported. It will be treated as a reference within the "
  120. "current database (%@/%@) instead.",
  121. self.reference.path, refDatabase.projectID, refDatabase.databaseID, database.projectID,
  122. database.databaseID);
  123. }
  124. return [FIRDocumentReference referenceWithKey:ref.value firestore:self.firestore];
  125. } else {
  126. return value.value;
  127. }
  128. }
  129. - (NSDictionary<NSString *, id> *)convertedObject:(FSTObjectValue *)objectValue {
  130. NSMutableDictionary *result = [NSMutableDictionary dictionary];
  131. [objectValue.internalValue
  132. enumerateKeysAndObjectsUsingBlock:^(NSString *key, FSTFieldValue *value, BOOL *stop) {
  133. result[key] = [self convertedValue:value];
  134. }];
  135. return result;
  136. }
  137. - (NSArray<id> *)convertedArray:(FSTArrayValue *)arrayValue {
  138. NSArray<FSTFieldValue *> *internalValue = arrayValue.internalValue;
  139. NSMutableArray *result = [NSMutableArray arrayWithCapacity:internalValue.count];
  140. [internalValue enumerateObjectsUsingBlock:^(id value, NSUInteger idx, BOOL *stop) {
  141. [result addObject:[self convertedValue:value]];
  142. }];
  143. return result;
  144. }
  145. @end
  146. NS_ASSUME_NONNULL_END