Skip to content

Commit de7eb4f

Browse files
authored
Migrate FSTServerTimestampValue to FSTDelegateValue (#3174)
* Migrate FSTServerTimetsampValue to FSTDelegateValue * Make ServerTimestamp use FSTFieldValue for previous value This makes it possible integrate the FSTServerTimestampValue changes earlier.
1 parent bbbe77e commit de7eb4f

28 files changed

+296
-190
lines changed

FirebaseFirestore.podspec

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ Google Cloud Firestore is a NoSQL document database built for automatic scaling,
2525
s.prefix_header_file = false
2626

2727
s.source_files = [
28-
'Firestore/Source/**/*',
28+
'Firestore/Source/**/*.{h,m,mm}',
2929
'Firestore/Protos/nanopb/**/*.{h,cc}',
3030
'Firestore/Protos/objc/**/*.[hm]',
3131
'Firestore/core/include/**/*.{h,cc,mm}',

Firestore/CMakeLists.txt

+3
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@
1313
# limitations under the License.
1414

1515
add_subdirectory(Example/Benchmarks)
16+
add_subdirectory(Source)
17+
add_subdirectory(third_party/Immutable)
18+
1619
add_subdirectory(Protos)
1720
add_subdirectory(core)
1821
add_subdirectory(fuzzing)

Firestore/Example/Tests/Model/FSTFieldValueTests.mm

+8-12
Original file line numberDiff line numberDiff line change
@@ -51,13 +51,12 @@
5151
// Server Timestamp values can't be parsed directly, so we have a couple predefined sentinel
5252
// strings that can be used instead.
5353
if ([value isEqual:@"server-timestamp-1"]) {
54-
wrappedValue = [FSTServerTimestampValue
55-
serverTimestampValueWithLocalWriteTime:testutil::MakeTimestamp(2016, 5, 20, 10, 20, 0)
56-
previousValue:nil];
54+
wrappedValue =
55+
FieldValue::FromServerTimestamp(testutil::MakeTimestamp(2016, 5, 20, 10, 20, 0)).Wrap();
5756
} else if ([value isEqual:@"server-timestamp-2"]) {
58-
wrappedValue = [FSTServerTimestampValue
59-
serverTimestampValueWithLocalWriteTime:testutil::MakeTimestamp(2016, 10, 21, 15, 32, 0)
60-
previousValue:nil];
57+
wrappedValue =
58+
FieldValue::FromServerTimestamp(testutil::MakeTimestamp(2016, 10, 21, 15, 32, 0))
59+
.Wrap();
6160
} else if ([value isKindOfClass:[FSTDocumentKeyReference class]]) {
6261
// We directly convert these here so that the databaseIDs can be different.
6362
FSTDocumentKeyReference *reference = (FSTDocumentKeyReference *)value;
@@ -311,13 +310,10 @@ - (void)testValueEquality {
311310
@[ FSTTestFieldValue(date2) ],
312311
@[
313312
// NOTE: ServerTimestampValues can't be parsed via FSTTestFieldValue().
314-
[FSTServerTimestampValue serverTimestampValueWithLocalWriteTime:MakeTimestamp(date1)
315-
previousValue:nil],
316-
[FSTServerTimestampValue serverTimestampValueWithLocalWriteTime:MakeTimestamp(date1)
317-
previousValue:nil]
313+
FieldValue::FromServerTimestamp(MakeTimestamp(date1)).Wrap(),
314+
FieldValue::FromServerTimestamp(MakeTimestamp(date1)).Wrap()
318315
],
319-
@[ [FSTServerTimestampValue serverTimestampValueWithLocalWriteTime:MakeTimestamp(date2)
320-
previousValue:nil] ],
316+
@[ FieldValue::FromServerTimestamp(MakeTimestamp(date2)).Wrap() ],
321317
@[ FSTTestFieldValue(FSTTestGeoPoint(0, 1)), FieldValue::FromGeoPoint(GeoPoint(0, 1)).Wrap() ],
322318
@[ FSTTestFieldValue(FSTTestGeoPoint(1, 0)) ],
323319
@[

Firestore/Example/Tests/Model/FSTMutationTests.mm

+1-3
Original file line numberDiff line numberDiff line change
@@ -144,9 +144,7 @@ - (void)testAppliesLocalServerTimestampTransformToDocuments {
144144
FSTObjectValue *expectedData =
145145
FSTTestObjectValue(@{@"foo" : @{@"bar" : @"<server-timestamp>"}, @"baz" : @"baz-value"});
146146
expectedData =
147-
[expectedData objectBySettingValue:[FSTServerTimestampValue
148-
serverTimestampValueWithLocalWriteTime:_timestamp
149-
previousValue:nil]
147+
[expectedData objectBySettingValue:FieldValue::FromServerTimestamp(_timestamp).Wrap()
150148
forPath:testutil::Field("foo.bar")];
151149

152150
FSTDocument *expectedDoc = [FSTDocument documentWithData:expectedData

Firestore/Source/API/CMakeLists.txt

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# Copyright 2019 Google
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+
15+
# Public types to be used both internally and externally.
16+
if(APPLE)
17+
cc_library(
18+
firebase_firestore_objc_api
19+
SOURCES
20+
FIRGeoPoint+Internal.h
21+
FIRGeoPoint.mm
22+
FIRTimestamp.m
23+
FIRTimestamp+Internal.h
24+
converters.h
25+
converters.mm
26+
DEPENDS
27+
firebase_firestore_api
28+
firebase_firestore_util
29+
)
30+
31+
target_include_directories(
32+
firebase_firestore_objc_api
33+
PUBLIC ${PROJECT_SOURCE_DIR}/Firestore/Source/Public
34+
)
35+
36+
target_compile_options(
37+
firebase_firestore_objc_api PRIVATE
38+
-Wno-unused-parameter
39+
)
40+
endif()

Firestore/Source/API/FIRFieldPath.mm

+5-5
Original file line numberDiff line numberDiff line change
@@ -48,13 +48,13 @@ - (instancetype)initWithFields:(NSArray<NSString *> *)fieldNames {
4848
ThrowInvalidArgument("Invalid field path. Provided names must not be empty.");
4949
}
5050

51-
std::vector<std::string> field_names;
52-
field_names.reserve(fieldNames.count);
53-
for (int i = 0; i < fieldNames.count; ++i) {
54-
field_names.emplace_back(util::MakeString(fieldNames[i]));
51+
std::vector<std::string> converted;
52+
converted.reserve(fieldNames.count);
53+
for (NSString *fieldName in fieldNames) {
54+
converted.emplace_back(util::MakeString(fieldName));
5555
}
5656

57-
return [self initPrivate:FieldPath::FromSegments(std::move(field_names))];
57+
return [self initPrivate:FieldPath::FromSegments(std::move(converted))];
5858
}
5959

6060
+ (instancetype)documentID {

Firestore/Source/API/FIRFieldValue.mm

+1-2
Original file line numberDiff line numberDiff line change
@@ -130,8 +130,7 @@ - (instancetype)initWithOperand:(NSNumber *)operand;
130130
@end
131131

132132
@implementation FSTNumericIncrementFieldValue
133-
- (instancetype)initWithOperand:(NSNumber *)operand;
134-
{
133+
- (instancetype)initWithOperand:(NSNumber *)operand {
135134
if (self = [super initPrivate]) {
136135
_operand = operand;
137136
}

Firestore/Source/CMakeLists.txt

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# Copyright 2019 Google
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+
15+
add_subdirectory(API)
16+
add_subdirectory(Model)

Firestore/Source/Model/CMakeLists.txt

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# Copyright 2019 Google
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+
15+
if(APPLE)
16+
cc_library(
17+
firebase_firestore_objc_model
18+
SOURCES
19+
FSTDocument.h
20+
FSTDocument.mm
21+
FSTDocumentKey.h
22+
FSTDocumentKey.mm
23+
FSTFieldValue.h
24+
FSTFieldValue.mm
25+
FSTMutation.h
26+
FSTMutation.mm
27+
FSTMutationBatch.h
28+
FSTMutationBatch.mm
29+
DEPENDS
30+
firebase_firestore_model
31+
firebase_firestore_objc_api
32+
firebase_firestore_objc_immutable
33+
firebase_firestore_util
34+
)
35+
36+
target_compile_options(
37+
firebase_firestore_objc_model PRIVATE
38+
-Wno-unused-parameter
39+
)
40+
endif()

Firestore/Source/Model/FSTDocumentKey.mm

-2
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,6 @@
1919
#include <string>
2020
#include <utility>
2121

22-
#import "Firestore/Source/Core/FSTFirestoreClient.h"
23-
2422
#include "Firestore/core/src/firebase/firestore/model/document_key.h"
2523
#include "Firestore/core/src/firebase/firestore/util/hard_assert.h"
2624
#include "Firestore/core/src/firebase/firestore/util/hashing.h"

Firestore/Source/Model/FSTFieldValue.h

-21
Original file line numberDiff line numberDiff line change
@@ -103,27 +103,6 @@ typedef NS_ENUM(NSInteger, FSTTypeOrder) {
103103

104104
@end
105105

106-
/**
107-
* Represents a locally-applied Server Timestamp.
108-
*
109-
* Notes:
110-
* - FSTServerTimestampValue instances are created as the result of applying an FSTTransformMutation
111-
* (see [FSTTransformMutation applyTo]). They can only exist in the local view of a document.
112-
* Therefore they do not need to be parsed or serialized.
113-
* - When evaluated locally (e.g. via FSTDocumentSnapshot data), they by default evaluate to NSNull.
114-
* This behavior can be configured by passing custom FieldValueOptions to `valueWithOptions:`.
115-
* - They sort after all Timestamp values. With respect to other FSTServerTimestampValues, they
116-
* sort by their localWriteTime.
117-
*/
118-
@interface FSTServerTimestampValue : FSTFieldValue <id>
119-
+ (instancetype)serverTimestampValueWithLocalWriteTime:(const firebase::Timestamp &)localWriteTime
120-
previousValue:(nullable FSTFieldValue *)previousValue;
121-
122-
@property(nonatomic, assign, readonly) const firebase::Timestamp &localWriteTime;
123-
@property(nonatomic, strong, readonly, nullable) FSTFieldValue *previousValue;
124-
125-
@end
126-
127106
/**
128107
* A reference value stored in Firestore.
129108
*/

Firestore/Source/Model/FSTFieldValue.mm

+23-89
Original file line numberDiff line numberDiff line change
@@ -128,81 +128,6 @@ - (double)doubleValue {
128128

129129
@end
130130

131-
#pragma mark - FSTServerTimestampValue
132-
133-
@implementation FSTServerTimestampValue {
134-
Timestamp _localWriteTime;
135-
}
136-
137-
+ (instancetype)serverTimestampValueWithLocalWriteTime:(const Timestamp &)localWriteTime
138-
previousValue:(nullable FSTFieldValue *)previousValue {
139-
return [[FSTServerTimestampValue alloc] initWithLocalWriteTime:localWriteTime
140-
previousValue:previousValue];
141-
}
142-
143-
- (id)initWithLocalWriteTime:(const Timestamp &)localWriteTime
144-
previousValue:(nullable FSTFieldValue *)previousValue {
145-
self = [super init];
146-
if (self) {
147-
_localWriteTime = localWriteTime;
148-
_previousValue = previousValue;
149-
}
150-
return self;
151-
}
152-
153-
- (FieldValue::Type)type {
154-
return FieldValue::Type::ServerTimestamp;
155-
}
156-
157-
- (FSTTypeOrder)typeOrder {
158-
return FSTTypeOrderTimestamp;
159-
}
160-
161-
- (id)value {
162-
return [NSNull null];
163-
}
164-
165-
- (id)valueWithOptions:(const FieldValueOptions &)options {
166-
switch (options.server_timestamp_behavior()) {
167-
case ServerTimestampBehavior::kNone:
168-
return [NSNull null];
169-
case ServerTimestampBehavior::kEstimate:
170-
return [FieldValue::FromTimestamp(self.localWriteTime).Wrap() valueWithOptions:options];
171-
case ServerTimestampBehavior::kPrevious:
172-
return self.previousValue ? [self.previousValue valueWithOptions:options] : [NSNull null];
173-
default:
174-
HARD_FAIL("Unexpected server timestamp option: %s", options.server_timestamp_behavior());
175-
}
176-
}
177-
178-
- (BOOL)isEqual:(id)other {
179-
return [other isKindOfClass:[FSTFieldValue class]] &&
180-
((FSTFieldValue *)other).type == FieldValue::Type::ServerTimestamp &&
181-
self.localWriteTime == ((FSTServerTimestampValue *)other).localWriteTime;
182-
}
183-
184-
- (NSUInteger)hash {
185-
return TimestampInternal::Hash(self.localWriteTime);
186-
}
187-
188-
- (NSString *)description {
189-
return [NSString
190-
stringWithFormat:@"<ServerTimestamp localTime=%s>", self.localWriteTime.ToString().c_str()];
191-
}
192-
193-
- (NSComparisonResult)compare:(FSTFieldValue *)other {
194-
if (other.type == FieldValue::Type::ServerTimestamp) {
195-
return WrapCompare(self.localWriteTime, ((FSTServerTimestampValue *)other).localWriteTime);
196-
} else if (other.type == FieldValue::Type::Timestamp) {
197-
// Server timestamps come after all concrete timestamps.
198-
return NSOrderedDescending;
199-
} else {
200-
return [self defaultCompare:other];
201-
}
202-
}
203-
204-
@end
205-
206131
#pragma mark - FSTReferenceValue
207132

208133
@interface FSTReferenceValue ()
@@ -617,20 +542,19 @@ - (BOOL)isEqual:(id)other {
617542
- (id)value {
618543
switch (self.internalValue.type()) {
619544
case FieldValue::Type::Null:
545+
// NSDictionary disallows storing `nil` values. Use NSNull as an
546+
// explicitly existing null value.
620547
return [NSNull null];
621548
case FieldValue::Type::Boolean:
622549
return self.internalValue.boolean_value() ? @YES : @NO;
623550
case FieldValue::Type::Integer:
624551
return @(self.internalValue.integer_value());
625552
case FieldValue::Type::Double:
626553
return @(self.internalValue.double_value());
627-
case FieldValue::Type::Timestamp: {
628-
auto timestamp = self.internalValue.timestamp_value();
629-
return [[FIRTimestamp alloc] initWithSeconds:timestamp.seconds()
630-
nanoseconds:timestamp.nanoseconds()];
631-
}
554+
case FieldValue::Type::Timestamp:
555+
return MakeFIRTimestamp(self.internalValue.timestamp_value());
632556
case FieldValue::Type::ServerTimestamp:
633-
HARD_FAIL("TODO(rsgowman): implement");
557+
return [NSNull null];
634558
case FieldValue::Type::String:
635559
return util::WrapNSString(self.internalValue.string_value());
636560
case FieldValue::Type::Blob:
@@ -655,6 +579,22 @@ - (id)valueWithOptions:(const model::FieldValueOptions &)options {
655579
return [[self value] dateValue];
656580
}
657581

582+
case FieldValue::Type::ServerTimestamp: {
583+
const auto &sts = self.internalValue.server_timestamp_value();
584+
switch (options.server_timestamp_behavior()) {
585+
case ServerTimestampBehavior::kNone:
586+
return [NSNull null];
587+
case ServerTimestampBehavior::kEstimate:
588+
return
589+
[FieldValue::FromTimestamp(sts.local_write_time()).Wrap() valueWithOptions:options];
590+
case ServerTimestampBehavior::kPrevious:
591+
return sts.previous_value() ? [sts.previous_value() valueWithOptions:options]
592+
: [NSNull null];
593+
default:
594+
HARD_FAIL("Unexpected server timestamp option: %s", options.server_timestamp_behavior());
595+
}
596+
}
597+
658598
default:
659599
return [self value];
660600
}
@@ -669,14 +609,8 @@ - (NSComparisonResult)compare:(FSTFieldValue *)other {
669609
// FSTDelegateValue handles (eg) booleans to ensure this case never occurs.
670610

671611
if (FieldValue::Comparable(self.type, other.type)) {
672-
if ([other isKindOfClass:[FSTServerTimestampValue class]]) {
673-
HARD_ASSERT(self.type == FieldValue::Type::Timestamp);
674-
// Server timestamps come after all concrete timestamps.
675-
return NSOrderedAscending;
676-
} else {
677-
HARD_ASSERT([other isKindOfClass:[FSTDelegateValue class]]);
678-
return WrapCompare<FieldValue>(self.internalValue, ((FSTDelegateValue *)other).internalValue);
679-
}
612+
HARD_ASSERT([other isKindOfClass:[FSTDelegateValue class]]);
613+
return WrapCompare<FieldValue>(self.internalValue, ((FSTDelegateValue *)other).internalValue);
680614
} else {
681615
return [self defaultCompare:other];
682616
}

Firestore/Source/Model/FSTMutation.mm

+1-1
Original file line numberDiff line numberDiff line change
@@ -481,7 +481,7 @@ - (FSTMaybeDocument *)applyToRemoteDocument:(nullable FSTMaybeDocument *)maybeDo
481481
*
482482
* @param baseDocument The document prior to applying this mutation batch.
483483
* @param localWriteTime The local time of the transform mutation (used to generate
484-
* FSTServerTimestampValues).
484+
* ServerTimestampValues).
485485
* @return The transform results array.
486486
*/
487487
- (NSArray<FSTFieldValue *> *)

Firestore/core/src/firebase/firestore/api/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -51,5 +51,6 @@ cc_library(
5151
absl_meta
5252
firebase_firestore_api_input_validation
5353
firebase_firestore_core
54+
firebase_firestore_model
5455
firebase_firestore_util
5556
)

0 commit comments

Comments
 (0)