FSTUserDataWriter.mm 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  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. // 💥 Doesnt work!
  19. //@import FirebaseFirestoreInternalSwift; // Use of '@import' when C++ modules are disabled, consider using -fmodules and -fcxx-modules
  20. //
  21. // And we cannot import the generated `-Swift` because https://github.com/swiftlang/swift-package-manager/issues/7099
  22. // But, we can import an ObjC file
  23. #include "Firestore/Source/API/FIRFooWrapper.h"
  24. #include "Firestore/Protos/nanopb/google/firestore/v1/document.nanopb.h"
  25. #include "Firestore/Source/API/FIRDocumentReference+Internal.h"
  26. #include "Firestore/Source/API/FIRFieldValue+Internal.h"
  27. #include "Firestore/Source/API/converters.h"
  28. #include "Firestore/core/include/firebase/firestore/geo_point.h"
  29. #include "Firestore/core/include/firebase/firestore/timestamp.h"
  30. #include "Firestore/core/src/api/firestore.h"
  31. #include "Firestore/core/src/model/database_id.h"
  32. #include "Firestore/core/src/model/document_key.h"
  33. #include "Firestore/core/src/model/server_timestamp_util.h"
  34. #include "Firestore/core/src/model/value_util.h"
  35. #include "Firestore/core/src/nanopb/nanopb_util.h"
  36. #include "Firestore/core/src/util/hard_assert.h"
  37. #include "Firestore/core/src/util/log.h"
  38. #include "Firestore/core/src/util/string_apple.h"
  39. @class FIRTimestamp;
  40. namespace api = firebase::firestore::api;
  41. namespace model = firebase::firestore::model;
  42. namespace nanopb = firebase::firestore::nanopb;
  43. using api::MakeFIRDocumentReference;
  44. using api::MakeFIRGeoPoint;
  45. using api::MakeFIRTimestamp;
  46. using firebase::firestore::GeoPoint;
  47. using firebase::firestore::google_firestore_v1_ArrayValue;
  48. using firebase::firestore::google_firestore_v1_MapValue;
  49. using firebase::firestore::google_firestore_v1_Value;
  50. using firebase::firestore::google_protobuf_Timestamp;
  51. using firebase::firestore::util::MakeNSString;
  52. using model::DatabaseId;
  53. using model::DocumentKey;
  54. using model::GetLocalWriteTime;
  55. using model::GetPreviousValue;
  56. using model::GetTypeOrder;
  57. using model::TypeOrder;
  58. using nanopb::MakeBytesArray;
  59. using nanopb::MakeByteString;
  60. using nanopb::MakeNSData;
  61. using nanopb::MakeString;
  62. using nanopb::MakeStringView;
  63. NS_ASSUME_NONNULL_BEGIN
  64. @implementation FSTUserDataWriter {
  65. std::shared_ptr<api::Firestore> _firestore;
  66. FIRServerTimestampBehavior _serverTimestampBehavior;
  67. }
  68. - (instancetype)initWithFirestore:(std::shared_ptr<api::Firestore>)firestore
  69. serverTimestampBehavior:(FIRServerTimestampBehavior)serverTimestampBehavior {
  70. self = [super init];
  71. if (self) {
  72. _firestore = std::move(firestore);
  73. _serverTimestampBehavior = serverTimestampBehavior;
  74. }
  75. return self;
  76. }
  77. - (void)example:(FIRFooWrapper *)fooWrapper {
  78. [fooWrapper doStuff];
  79. // Calls into ObjC fooWrapper definition, which calls into source-of-truth Swift module
  80. }
  81. - (id)convertedValue:(const google_firestore_v1_Value &)value {
  82. switch (GetTypeOrder(value)) {
  83. case TypeOrder::kMap:
  84. return [self convertedObject:value.map_value];
  85. case TypeOrder::kArray:
  86. return [self convertedArray:value.array_value];
  87. case TypeOrder::kReference:
  88. return [self convertedReference:value];
  89. case TypeOrder::kTimestamp:
  90. return [self convertedTimestamp:value.timestamp_value];
  91. case TypeOrder::kServerTimestamp:
  92. return [self convertedServerTimestamp:value];
  93. case TypeOrder::kNull:
  94. return [NSNull null];
  95. case TypeOrder::kBoolean:
  96. return value.boolean_value ? @YES : @NO;
  97. case TypeOrder::kNumber:
  98. return value.which_value_type == google_firestore_v1_Value_integer_value_tag
  99. ? @(value.integer_value)
  100. : @(value.double_value);
  101. case TypeOrder::kString:
  102. return MakeNSString(MakeStringView(value.string_value));
  103. case TypeOrder::kBlob:
  104. return MakeNSData(value.bytes_value);
  105. case TypeOrder::kGeoPoint:
  106. return MakeFIRGeoPoint(
  107. GeoPoint(value.geo_point_value.latitude, value.geo_point_value.longitude));
  108. case TypeOrder::kVector:
  109. return [self convertedVector:value.map_value];
  110. case TypeOrder::kMaxValue:
  111. // It is not possible for users to construct a kMaxValue manually.
  112. break;
  113. }
  114. UNREACHABLE();
  115. }
  116. - (NSDictionary<NSString *, id> *)convertedObject:(const google_firestore_v1_MapValue &)mapValue {
  117. NSMutableDictionary *result = [NSMutableDictionary dictionary];
  118. for (pb_size_t i = 0; i < mapValue.fields_count; ++i) {
  119. absl::string_view key = MakeStringView(mapValue.fields[i].key);
  120. const google_firestore_v1_Value &value = mapValue.fields[i].value;
  121. result[MakeNSString(key)] = [self convertedValue:value];
  122. }
  123. return result;
  124. }
  125. - (FIRVectorValue *)convertedVector:(const google_firestore_v1_MapValue &)mapValue {
  126. for (pb_size_t i = 0; i < mapValue.fields_count; ++i) {
  127. absl::string_view key = MakeStringView(mapValue.fields[i].key);
  128. const google_firestore_v1_Value &value = mapValue.fields[i].value;
  129. if ((0 == key.compare(absl::string_view("value"))) &&
  130. value.which_value_type == google_firestore_v1_Value_array_value_tag) {
  131. return [FIRFieldValue vectorWithArray:[self convertedArray:value.array_value]];
  132. }
  133. }
  134. return [FIRFieldValue vectorWithArray:@[]];
  135. }
  136. - (NSArray<id> *)convertedArray:(const google_firestore_v1_ArrayValue &)arrayValue {
  137. NSMutableArray *result = [NSMutableArray arrayWithCapacity:arrayValue.values_count];
  138. for (pb_size_t i = 0; i < arrayValue.values_count; ++i) {
  139. [result addObject:[self convertedValue:arrayValue.values[i]]];
  140. }
  141. return result;
  142. }
  143. - (id)convertedServerTimestamp:(const google_firestore_v1_Value &)serverTimestampValue {
  144. switch (_serverTimestampBehavior) {
  145. case FIRServerTimestampBehavior::FIRServerTimestampBehaviorNone:
  146. return [NSNull null];
  147. case FIRServerTimestampBehavior::FIRServerTimestampBehaviorEstimate:
  148. return [self convertedTimestamp:GetLocalWriteTime(serverTimestampValue)];
  149. case FIRServerTimestampBehavior::FIRServerTimestampBehaviorPrevious: {
  150. auto previous_value = GetPreviousValue(serverTimestampValue);
  151. return previous_value ? [self convertedValue:*previous_value] : [NSNull null];
  152. }
  153. }
  154. UNREACHABLE();
  155. }
  156. - (FIRTimestamp *)convertedTimestamp:(const google_protobuf_Timestamp &)value {
  157. return MakeFIRTimestamp(firebase::Timestamp{value.seconds, value.nanos});
  158. }
  159. - (FIRDocumentReference *)convertedReference:(const google_firestore_v1_Value &)value {
  160. std::string ref = MakeString(value.reference_value);
  161. DatabaseId databaseID = DatabaseId::FromName(ref);
  162. DocumentKey key = DocumentKey::FromName(ref);
  163. if (databaseID != _firestore->database_id()) {
  164. LOG_WARN("Document reference is for a different database (%s/%s) which "
  165. "is not supported. It will be treated as a reference within the current database "
  166. "(%s/%s) instead.",
  167. databaseID.project_id(), databaseID.database_id(), databaseID.project_id(),
  168. databaseID.database_id());
  169. }
  170. return MakeFIRDocumentReference(key, _firestore);
  171. }
  172. @end
  173. NS_ASSUME_NONNULL_END