FSTUserDataWriter.mm 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. // Copyright 2021 Google LLC
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. #include "Firestore/Source/API/FSTUserDataWriter.h"
  15. #import <Foundation/Foundation.h>
  16. #include <string>
  17. #include <utility>
  18. #include "Firestore/Protos/nanopb/google/firestore/v1/document.nanopb.h"
  19. #include "Firestore/Source/API/FIRDocumentReference+Internal.h"
  20. #include "Firestore/Source/API/FIRFieldValue+Internal.h"
  21. #include "Firestore/Source/API/converters.h"
  22. #include "Firestore/core/include/firebase/firestore/geo_point.h"
  23. #include "Firestore/core/include/firebase/firestore/timestamp.h"
  24. #include "Firestore/core/src/api/firestore.h"
  25. #include "Firestore/core/src/model/database_id.h"
  26. #include "Firestore/core/src/model/document_key.h"
  27. #include "Firestore/core/src/model/server_timestamp_util.h"
  28. #include "Firestore/core/src/model/value_util.h"
  29. #include "Firestore/core/src/nanopb/nanopb_util.h"
  30. #include "Firestore/core/src/util/hard_assert.h"
  31. #include "Firestore/core/src/util/log.h"
  32. #include "Firestore/core/src/util/string_apple.h"
  33. @class FIRTimestamp;
  34. namespace api = firebase::firestore::api;
  35. namespace model = firebase::firestore::model;
  36. namespace nanopb = firebase::firestore::nanopb;
  37. using api::MakeFIRDocumentReference;
  38. using api::MakeFIRGeoPoint;
  39. using api::MakeFIRTimestamp;
  40. using firebase::firestore::GeoPoint;
  41. using firebase::firestore::google_firestore_v1_ArrayValue;
  42. using firebase::firestore::google_firestore_v1_MapValue;
  43. using firebase::firestore::google_firestore_v1_Value;
  44. using firebase::firestore::google_protobuf_Timestamp;
  45. using firebase::firestore::util::MakeNSString;
  46. using model::DatabaseId;
  47. using model::DocumentKey;
  48. using model::GetLocalWriteTime;
  49. using model::GetPreviousValue;
  50. using model::GetTypeOrder;
  51. using model::TypeOrder;
  52. using nanopb::MakeBytesArray;
  53. using nanopb::MakeByteString;
  54. using nanopb::MakeNSData;
  55. using nanopb::MakeString;
  56. using nanopb::MakeStringView;
  57. NS_ASSUME_NONNULL_BEGIN
  58. @implementation FSTUserDataWriter {
  59. std::shared_ptr<api::Firestore> _firestore;
  60. FIRServerTimestampBehavior _serverTimestampBehavior;
  61. }
  62. - (instancetype)initWithFirestore:(std::shared_ptr<api::Firestore>)firestore
  63. serverTimestampBehavior:(FIRServerTimestampBehavior)serverTimestampBehavior {
  64. self = [super init];
  65. if (self) {
  66. _firestore = std::move(firestore);
  67. _serverTimestampBehavior = serverTimestampBehavior;
  68. }
  69. return self;
  70. }
  71. - (id)convertedValue:(const google_firestore_v1_Value &)value {
  72. switch (GetTypeOrder(value)) {
  73. case TypeOrder::kMap:
  74. return [self convertedObject:value.map_value];
  75. case TypeOrder::kArray:
  76. return [self convertedArray:value.array_value];
  77. case TypeOrder::kReference:
  78. return [self convertedReference:value];
  79. case TypeOrder::kTimestamp:
  80. return [self convertedTimestamp:value.timestamp_value];
  81. case TypeOrder::kServerTimestamp:
  82. return [self convertedServerTimestamp:value];
  83. case TypeOrder::kNull:
  84. return [NSNull null];
  85. case TypeOrder::kBoolean:
  86. return value.boolean_value ? @YES : @NO;
  87. case TypeOrder::kNumber:
  88. return value.which_value_type == google_firestore_v1_Value_integer_value_tag
  89. ? @(value.integer_value)
  90. : @(value.double_value);
  91. case TypeOrder::kString:
  92. return MakeNSString(MakeStringView(value.string_value));
  93. case TypeOrder::kBlob:
  94. return MakeNSData(value.bytes_value);
  95. case TypeOrder::kGeoPoint:
  96. return MakeFIRGeoPoint(
  97. GeoPoint(value.geo_point_value.latitude, value.geo_point_value.longitude));
  98. case TypeOrder::kVector:
  99. return [self convertedVector:value.map_value];
  100. case TypeOrder::kMaxValue:
  101. // It is not possible for users to construct a kMaxValue manually.
  102. break;
  103. }
  104. UNREACHABLE();
  105. }
  106. - (NSDictionary<NSString *, id> *)convertedObject:(const google_firestore_v1_MapValue &)mapValue {
  107. NSMutableDictionary *result = [NSMutableDictionary dictionary];
  108. for (pb_size_t i = 0; i < mapValue.fields_count; ++i) {
  109. absl::string_view key = MakeStringView(mapValue.fields[i].key);
  110. const google_firestore_v1_Value &value = mapValue.fields[i].value;
  111. result[MakeNSString(key)] = [self convertedValue:value];
  112. }
  113. return result;
  114. }
  115. - (FIRVectorValue *)convertedVector:(const google_firestore_v1_MapValue &)mapValue {
  116. for (pb_size_t i = 0; i < mapValue.fields_count; ++i) {
  117. absl::string_view key = MakeStringView(mapValue.fields[i].key);
  118. const google_firestore_v1_Value &value = mapValue.fields[i].value;
  119. if ((0 == key.compare(absl::string_view("value"))) &&
  120. value.which_value_type == google_firestore_v1_Value_array_value_tag) {
  121. return [FIRFieldValue vectorWithArray:[self convertedArray:value.array_value]];
  122. }
  123. }
  124. return [FIRFieldValue vectorWithArray:@[]];
  125. }
  126. - (NSArray<id> *)convertedArray:(const google_firestore_v1_ArrayValue &)arrayValue {
  127. NSMutableArray *result = [NSMutableArray arrayWithCapacity:arrayValue.values_count];
  128. for (pb_size_t i = 0; i < arrayValue.values_count; ++i) {
  129. [result addObject:[self convertedValue:arrayValue.values[i]]];
  130. }
  131. return result;
  132. }
  133. - (id)convertedServerTimestamp:(const google_firestore_v1_Value &)serverTimestampValue {
  134. switch (_serverTimestampBehavior) {
  135. case FIRServerTimestampBehavior::FIRServerTimestampBehaviorNone:
  136. return [NSNull null];
  137. case FIRServerTimestampBehavior::FIRServerTimestampBehaviorEstimate:
  138. return [self convertedTimestamp:GetLocalWriteTime(serverTimestampValue)];
  139. case FIRServerTimestampBehavior::FIRServerTimestampBehaviorPrevious: {
  140. auto previous_value = GetPreviousValue(serverTimestampValue);
  141. return previous_value ? [self convertedValue:*previous_value] : [NSNull null];
  142. }
  143. }
  144. UNREACHABLE();
  145. }
  146. - (FIRTimestamp *)convertedTimestamp:(const google_protobuf_Timestamp &)value {
  147. return MakeFIRTimestamp(firebase::Timestamp{value.seconds, value.nanos});
  148. }
  149. - (FIRDocumentReference *)convertedReference:(const google_firestore_v1_Value &)value {
  150. std::string ref = MakeString(value.reference_value);
  151. DatabaseId databaseID = DatabaseId::FromName(ref);
  152. DocumentKey key = DocumentKey::FromName(ref);
  153. if (databaseID != _firestore->database_id()) {
  154. LOG_WARN("Document reference is for a different database (%s/%s) which "
  155. "is not supported. It will be treated as a reference within the current database "
  156. "(%s/%s) instead.",
  157. databaseID.project_id(), databaseID.database_id(), databaseID.project_id(),
  158. databaseID.database_id());
  159. }
  160. return MakeFIRDocumentReference(key, _firestore);
  161. }
  162. @end
  163. NS_ASSUME_NONNULL_END