Skip to content

Commit e8960f9

Browse files
UserDataWriter (#7842)
1 parent 38cefe1 commit e8960f9

20 files changed

+403
-114
lines changed

Firestore/Example/Tests/API/FSTAPIHelpers.mm

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@
9191
doc = Doc(path, version, parsed,
9292
hasMutations ? DocumentState::kLocalMutations : DocumentState::kSynced);
9393
}
94-
return [[FIRDocumentSnapshot alloc] initWithFirestore:FSTTestFirestore().wrapped
94+
return [[FIRDocumentSnapshot alloc] initWithFirestore:FSTTestFirestore()
9595
documentKey:testutil::Key(path)
9696
document:doc
9797
fromCache:fromCache

Firestore/Source/API/FIRDocumentSnapshot+Internal.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
#include "Firestore/core/src/api/api_fwd.h"
2222
#include "Firestore/core/src/model/model_fwd.h"
2323

24+
@class FIRFirestore;
25+
2426
namespace api = firebase::firestore::api;
2527
namespace model = firebase::firestore::model;
2628

@@ -30,12 +32,12 @@ NS_ASSUME_NONNULL_BEGIN
3032

3133
- (instancetype)initWithSnapshot:(api::DocumentSnapshot &&)snapshot NS_DESIGNATED_INITIALIZER;
3234

33-
- (instancetype)initWithFirestore:(std::shared_ptr<api::Firestore>)firestore
35+
- (instancetype)initWithFirestore:(FIRFirestore *)firestore
3436
documentKey:(model::DocumentKey)documentKey
3537
document:(const absl::optional<model::Document> &)document
3638
metadata:(api::SnapshotMetadata)metadata;
3739

38-
- (instancetype)initWithFirestore:(std::shared_ptr<api::Firestore>)firestore
40+
- (instancetype)initWithFirestore:(FIRFirestore *)firestore
3941
documentKey:(model::DocumentKey)documentKey
4042
document:(const absl::optional<model::Document> &)document
4143
fromCache:(bool)fromCache

Firestore/Source/API/FIRDocumentSnapshot.mm

Lines changed: 28 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,10 @@
2727
#import "Firestore/Source/API/FIRGeoPoint+Internal.h"
2828
#import "Firestore/Source/API/FIRSnapshotMetadata+Internal.h"
2929
#import "Firestore/Source/API/FIRTimestamp+Internal.h"
30+
#import "Firestore/Source/API/FSTUserDataWriter.h"
3031
#import "Firestore/Source/API/converters.h"
3132

33+
#include "Firestore/Protos/nanopb/google/firestore/v1/document.nanopb.h"
3234
#include "Firestore/core/src/api/document_reference.h"
3335
#include "Firestore/core/src/api/document_snapshot.h"
3436
#include "Firestore/core/src/api/firestore.h"
@@ -39,6 +41,7 @@
3941
#include "Firestore/core/src/model/field_value.h"
4042
#include "Firestore/core/src/model/field_value_options.h"
4143
#include "Firestore/core/src/nanopb/nanopb_util.h"
44+
#include "Firestore/core/src/remote/serializer.h"
4245
#include "Firestore/core/src/util/exception.h"
4346
#include "Firestore/core/src/util/hard_assert.h"
4447
#include "Firestore/core/src/util/log.h"
@@ -60,9 +63,11 @@
6063
using firebase::firestore::model::FieldValueOptions;
6164
using firebase::firestore::model::ObjectValue;
6265
using firebase::firestore::model::ServerTimestampBehavior;
66+
using firebase::firestore::remote::Serializer;
6367
using firebase::firestore::nanopb::MakeNSData;
6468
using firebase::firestore::util::MakeString;
6569
using firebase::firestore::util::ThrowInvalidArgument;
70+
using firebase::firestore::google_firestore_v1_Value;
6671

6772
NS_ASSUME_NONNULL_BEGIN
6873

@@ -90,32 +95,35 @@ ServerTimestampBehavior InternalServerTimestampBehavior(FIRServerTimestampBehavi
9095
@implementation FIRDocumentSnapshot {
9196
DocumentSnapshot _snapshot;
9297

98+
std::unique_ptr<Serializer> _serializer;
9399
FIRSnapshotMetadata *_cachedMetadata;
94100
}
95101

96102
- (instancetype)initWithSnapshot:(DocumentSnapshot &&)snapshot {
97103
if (self = [super init]) {
98104
_snapshot = std::move(snapshot);
105+
_serializer.reset(new Serializer(_snapshot.firestore()->database_id()));
99106
}
100107
return self;
101108
}
102109

103-
- (instancetype)initWithFirestore:(std::shared_ptr<Firestore>)firestore
110+
- (instancetype)initWithFirestore:(FIRFirestore *)firestore
104111
documentKey:(DocumentKey)documentKey
105112
document:(const absl::optional<Document> &)document
106113
metadata:(SnapshotMetadata)metadata {
107114
DocumentSnapshot wrapped;
108115
if (document.has_value()) {
109116
wrapped =
110-
DocumentSnapshot::FromDocument(std::move(firestore), document.value(), std::move(metadata));
117+
DocumentSnapshot::FromDocument(firestore.wrapped, document.value(), std::move(metadata));
111118
} else {
112-
wrapped = DocumentSnapshot::FromNoDocument(std::move(firestore), std::move(documentKey),
119+
wrapped = DocumentSnapshot::FromNoDocument(firestore.wrapped, std::move(documentKey),
113120
std::move(metadata));
114121
}
122+
_serializer.reset(new Serializer(firestore.databaseID));
115123
return [self initWithSnapshot:std::move(wrapped)];
116124
}
117125

118-
- (instancetype)initWithFirestore:(std::shared_ptr<Firestore>)firestore
126+
- (instancetype)initWithFirestore:(FIRFirestore *)firestore
119127
documentKey:(DocumentKey)documentKey
120128
document:(const absl::optional<Document> &)document
121129
fromCache:(bool)fromCache
@@ -176,7 +184,7 @@ - (FIRSnapshotMetadata *)metadata {
176184
absl::optional<ObjectValue> data = _snapshot.GetData();
177185
if (!data) return nil;
178186

179-
return [self convertedObject:data->GetInternalValue() options:options];
187+
return [self convertedValue:*data options:options];
180188
}
181189

182190
- (nullable id)valueForField:(id)field {
@@ -208,94 +216,27 @@ - (FieldValueOptions)optionsForServerTimestampBehavior:
208216
return FieldValueOptions(InternalServerTimestampBehavior(serverTimestampBehavior));
209217
}
210218

211-
// TODO(mutabledocuments): Replace with UserDataWriter
219+
// TODO(mutabledocuments): Replace this method and call UserDataWriter directly
212220
- (id)convertedValue:(FieldValue)value options:(const FieldValueOptions &)options {
213-
switch (value.type()) {
214-
case FieldValue::Type::Null:
215-
return [NSNull null];
216-
case FieldValue::Type::Boolean:
217-
return value.boolean_value() ? @YES : @NO;
218-
case FieldValue::Type::Integer:
219-
return @(value.integer_value());
220-
case FieldValue::Type::Double:
221-
return @(value.double_value());
222-
case FieldValue::Type::Timestamp:
223-
return [self convertedTimestamp:value];
224-
case FieldValue::Type::ServerTimestamp:
225-
return [self convertedServerTimestamp:value options:options];
226-
case FieldValue::Type::String:
227-
return util::MakeNSString(value.string_value());
228-
case FieldValue::Type::Blob:
229-
return MakeNSData(value.blob_value());
230-
case FieldValue::Type::Reference:
231-
return [self convertedReference:value];
232-
case FieldValue::Type::GeoPoint:
233-
return MakeFIRGeoPoint(value.geo_point_value());
234-
case FieldValue::Type::Array:
235-
return [self convertedArray:value.array_value() options:options];
236-
case FieldValue::Type::Object:
237-
return [self convertedObject:value.object_value() options:options];
238-
}
239-
240-
UNREACHABLE();
241-
}
242-
243-
- (id)convertedTimestamp:(const FieldValue &)value {
244-
return MakeFIRTimestamp(value.timestamp_value());
245-
}
246-
247-
- (id)convertedServerTimestamp:(const FieldValue &)value
248-
options:(const FieldValueOptions &)options {
249-
const auto &sts = value.server_timestamp_value();
221+
FIRServerTimestampBehavior behavior;
250222
switch (options.server_timestamp_behavior()) {
251223
case ServerTimestampBehavior::kNone:
252-
return [NSNull null];
253-
case ServerTimestampBehavior::kEstimate: {
254-
FieldValue local_write_time = FieldValue::FromTimestamp(sts.local_write_time());
255-
return [self convertedTimestamp:local_write_time];
256-
}
224+
behavior = FIRServerTimestampBehaviorNone;
225+
break;
226+
case ServerTimestampBehavior::kEstimate:
227+
behavior = FIRServerTimestampBehaviorEstimate;
228+
break;
257229
case ServerTimestampBehavior::kPrevious:
258-
return sts.previous_value() ? [self convertedValue:*sts.previous_value() options:options]
259-
: [NSNull null];
260-
}
261-
262-
UNREACHABLE();
263-
}
264-
265-
- (id)convertedReference:(const FieldValue &)value {
266-
const auto &ref = value.reference_value();
267-
const DatabaseId &refDatabase = ref.database_id();
268-
const DatabaseId &database = _snapshot.firestore()->database_id();
269-
if (refDatabase != database) {
270-
LOG_WARN("Document %s contains a document reference within a different database (%s/%s) which "
271-
"is not supported. It will be treated as a reference within the current database "
272-
"(%s/%s) instead.",
273-
_snapshot.CreateReference().Path(), refDatabase.project_id(),
274-
refDatabase.database_id(), database.project_id(), database.database_id());
275-
}
276-
const DocumentKey &key = ref.key();
277-
return [[FIRDocumentReference alloc] initWithKey:key firestore:_snapshot.firestore()];
278-
}
279-
280-
- (NSArray<id> *)convertedArray:(const FieldValue::Array &)arrayContents
281-
options:(const FieldValueOptions &)options {
282-
NSMutableArray *result = [NSMutableArray arrayWithCapacity:arrayContents.size()];
283-
for (const FieldValue &value : arrayContents) {
284-
[result addObject:[self convertedValue:value options:options]];
230+
behavior = FIRServerTimestampBehaviorPrevious;
231+
break;
232+
default:
233+
HARD_FAIL("Unexpected server timestamp option: %s", options.server_timestamp_behavior());
285234
}
286-
return result;
287-
}
288235

289-
- (NSDictionary<NSString *, id> *)convertedObject:(const FieldValue::Map &)objectValue
290-
options:(const FieldValueOptions &)options {
291-
NSMutableDictionary *result = [NSMutableDictionary dictionary];
292-
for (const auto &kv : objectValue) {
293-
const std::string &key = kv.first;
294-
const FieldValue &value = kv.second;
295-
296-
result[util::MakeNSString(key)] = [self convertedValue:value options:options];
297-
}
298-
return result;
236+
FSTUserDataWriter *dataWriter = [[FSTUserDataWriter alloc] initWithFirestore:_snapshot.firestore()
237+
serverTimestampBehavior:behavior];
238+
google_firestore_v1_Value protoValue = _serializer->EncodeFieldValue(value);
239+
return [dataWriter convertedValue:protoValue];
299240
}
300241

301242
@end

Firestore/Source/API/FIRTransaction.mm

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -134,16 +134,15 @@ - (void)getDocument:(FIRDocumentReference *)document
134134
HARD_ASSERT(documents.size() == 1, "Mismatch in docs returned from document lookup.");
135135
const MaybeDocument &internalDoc = documents.front();
136136
if (internalDoc.is_no_document()) {
137-
FIRDocumentSnapshot *doc =
138-
[[FIRDocumentSnapshot alloc] initWithFirestore:self.firestore.wrapped
139-
documentKey:document.key
140-
document:absl::nullopt
141-
fromCache:false
142-
hasPendingWrites:false];
137+
FIRDocumentSnapshot *doc = [[FIRDocumentSnapshot alloc] initWithFirestore:self.firestore
138+
documentKey:document.key
139+
document:absl::nullopt
140+
fromCache:false
141+
hasPendingWrites:false];
143142
completion(doc, nil);
144143
} else if (internalDoc.is_document()) {
145144
FIRDocumentSnapshot *doc =
146-
[[FIRDocumentSnapshot alloc] initWithFirestore:self.firestore.wrapped
145+
[[FIRDocumentSnapshot alloc] initWithFirestore:self.firestore
147146
documentKey:internalDoc.key()
148147
document:Document(internalDoc)
149148
fromCache:false

Firestore/Source/API/FSTUserDataReader.mm

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -340,7 +340,7 @@ - (google_firestore_v1_Value)parseDictionary:(NSDictionary<NSString *, id> *)dic
340340
// Compute the final size of the fields array, which contains an entry for
341341
// all fields that are not FieldValue sentinels
342342
__block pb_size_t count = 0;
343-
[dict enumerateKeysAndObjectsUsingBlock:^(NSString *key, id value, BOOL *) {
343+
[dict enumerateKeysAndObjectsUsingBlock:^(NSString *, id value, BOOL *) {
344344
if (![value isKindOfClass:[FIRFieldValue class]]) {
345345
++count;
346346
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/*
2+
* Copyright 2021 Google LLC
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+
17+
#import <Foundation/Foundation.h>
18+
19+
#include <memory>
20+
21+
#include "Firestore/Protos/nanopb/google/firestore/v1/document.nanopb.h"
22+
#include "Firestore/Source/API/FIRDocumentSnapshot+Internal.h"
23+
#include "Firestore/core/src/api/api_fwd.h"
24+
25+
namespace api = firebase::firestore::api;
26+
27+
/**
28+
* Converts Firestore's internal types to the API types that we expose to the
29+
* user.
30+
*/
31+
@interface FSTUserDataWriter : NSObject
32+
33+
- (instancetype)init NS_UNAVAILABLE;
34+
35+
- (instancetype)initWithFirestore:(std::shared_ptr<api::Firestore>)firestore
36+
serverTimestampBehavior:(FIRServerTimestampBehavior)serverTimestampBehavior;
37+
38+
- (id)convertedValue:(const firebase::firestore::google_firestore_v1_Value&)value;
39+
40+
@end

0 commit comments

Comments
 (0)