123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169 |
- // Copyright 2021 Google LLC
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
- #include "Firestore/Source/API/FSTUserDataWriter.h"
- #import <Foundation/Foundation.h>
- #include <string>
- #include <utility>
- #include "Firestore/Protos/nanopb/google/firestore/v1/document.nanopb.h"
- #include "Firestore/Source/API/FIRDocumentReference+Internal.h"
- #include "Firestore/Source/API/converters.h"
- #include "Firestore/core/include/firebase/firestore/geo_point.h"
- #include "Firestore/core/include/firebase/firestore/timestamp.h"
- #include "Firestore/core/src/api/firestore.h"
- #include "Firestore/core/src/model/database_id.h"
- #include "Firestore/core/src/model/document_key.h"
- #include "Firestore/core/src/model/server_timestamp_util.h"
- #include "Firestore/core/src/model/value_util.h"
- #include "Firestore/core/src/nanopb/nanopb_util.h"
- #include "Firestore/core/src/util/hard_assert.h"
- #include "Firestore/core/src/util/log.h"
- #include "Firestore/core/src/util/string_apple.h"
- @class FIRTimestamp;
- namespace api = firebase::firestore::api;
- namespace model = firebase::firestore::model;
- namespace nanopb = firebase::firestore::nanopb;
- using api::MakeFIRDocumentReference;
- using api::MakeFIRGeoPoint;
- using api::MakeFIRTimestamp;
- using firebase::firestore::GeoPoint;
- using firebase::firestore::google_firestore_v1_ArrayValue;
- using firebase::firestore::google_firestore_v1_MapValue;
- using firebase::firestore::google_firestore_v1_Value;
- using firebase::firestore::google_protobuf_Timestamp;
- using firebase::firestore::util::MakeNSString;
- using model::DatabaseId;
- using model::DocumentKey;
- using model::GetLocalWriteTime;
- using model::GetPreviousValue;
- using model::GetTypeOrder;
- using model::TypeOrder;
- using nanopb::MakeBytesArray;
- using nanopb::MakeByteString;
- using nanopb::MakeNSData;
- using nanopb::MakeString;
- using nanopb::MakeStringView;
- NS_ASSUME_NONNULL_BEGIN
- @implementation FSTUserDataWriter {
- std::shared_ptr<api::Firestore> _firestore;
- FIRServerTimestampBehavior _serverTimestampBehavior;
- }
- - (instancetype)initWithFirestore:(std::shared_ptr<api::Firestore>)firestore
- serverTimestampBehavior:(FIRServerTimestampBehavior)serverTimestampBehavior {
- self = [super init];
- if (self) {
- _firestore = std::move(firestore);
- _serverTimestampBehavior = serverTimestampBehavior;
- }
- return self;
- }
- - (id)convertedValue:(const google_firestore_v1_Value &)value {
- switch (GetTypeOrder(value)) {
- case TypeOrder::kMap:
- return [self convertedObject:value.map_value];
- case TypeOrder::kArray:
- return [self convertedArray:value.array_value];
- case TypeOrder::kReference:
- return [self convertedReference:value];
- case TypeOrder::kTimestamp:
- return [self convertedTimestamp:value.timestamp_value];
- case TypeOrder::kServerTimestamp:
- return [self convertedServerTimestamp:value];
- case TypeOrder::kNull:
- return [NSNull null];
- case TypeOrder::kBoolean:
- return value.boolean_value ? @YES : @NO;
- case TypeOrder::kNumber:
- return value.which_value_type == google_firestore_v1_Value_integer_value_tag
- ? @(value.integer_value)
- : @(value.double_value);
- case TypeOrder::kString:
- return MakeNSString(MakeStringView(value.string_value));
- case TypeOrder::kBlob:
- return MakeNSData(value.bytes_value);
- case TypeOrder::kGeoPoint:
- return MakeFIRGeoPoint(
- GeoPoint(value.geo_point_value.latitude, value.geo_point_value.longitude));
- case TypeOrder::kMaxValue:
- // It is not possible for users to construct a kMaxValue manually.
- break;
- }
- UNREACHABLE();
- }
- - (NSDictionary<NSString *, id> *)convertedObject:(const google_firestore_v1_MapValue &)mapValue {
- NSMutableDictionary *result = [NSMutableDictionary dictionary];
- for (pb_size_t i = 0; i < mapValue.fields_count; ++i) {
- absl::string_view key = MakeStringView(mapValue.fields[i].key);
- const google_firestore_v1_Value &value = mapValue.fields[i].value;
- result[MakeNSString(key)] = [self convertedValue:value];
- }
- return result;
- }
- - (NSArray<id> *)convertedArray:(const google_firestore_v1_ArrayValue &)arrayValue {
- NSMutableArray *result = [NSMutableArray arrayWithCapacity:arrayValue.values_count];
- for (pb_size_t i = 0; i < arrayValue.values_count; ++i) {
- [result addObject:[self convertedValue:arrayValue.values[i]]];
- }
- return result;
- }
- - (id)convertedServerTimestamp:(const google_firestore_v1_Value &)serverTimestampValue {
- switch (_serverTimestampBehavior) {
- case FIRServerTimestampBehavior::FIRServerTimestampBehaviorNone:
- return [NSNull null];
- case FIRServerTimestampBehavior::FIRServerTimestampBehaviorEstimate:
- return [self convertedTimestamp:GetLocalWriteTime(serverTimestampValue)];
- case FIRServerTimestampBehavior::FIRServerTimestampBehaviorPrevious: {
- auto previous_value = GetPreviousValue(serverTimestampValue);
- return previous_value ? [self convertedValue:*previous_value] : [NSNull null];
- }
- }
- UNREACHABLE();
- }
- - (FIRTimestamp *)convertedTimestamp:(const google_protobuf_Timestamp &)value {
- return MakeFIRTimestamp(firebase::Timestamp{value.seconds, value.nanos});
- }
- - (FIRDocumentReference *)convertedReference:(const google_firestore_v1_Value &)value {
- std::string ref = MakeString(value.reference_value);
- DatabaseId databaseID = DatabaseId::FromName(ref);
- DocumentKey key = DocumentKey::FromName(ref);
- if (databaseID != _firestore->database_id()) {
- LOG_WARN("Document reference is for a different database (%s/%s) which "
- "is not supported. It will be treated as a reference within the current database "
- "(%s/%s) instead.",
- databaseID.project_id(), databaseID.database_id(), databaseID.project_id(),
- databaseID.database_id());
- }
- return MakeFIRDocumentReference(key, _firestore);
- }
- @end
- NS_ASSUME_NONNULL_END
|