Skip to content

Commit ddb1177

Browse files
committed
Revert "Revert "Add +[FIRServerValues increment:] (#4328)" (#4627)"
This reverts commit 339c840.
1 parent 096fc67 commit ddb1177

File tree

7 files changed

+335
-49
lines changed

7 files changed

+335
-49
lines changed

Example/Database/Tests/Integration/FData.m

Lines changed: 141 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#import "FEventTester.h"
2222
#import "FIRDatabaseConfig_Private.h"
2323
#import "FIRDatabaseQuery_Private.h"
24+
#import "FIRServerValue_unreleased.h"
2425
#import "FRepo_Private.h"
2526
#import "FTestHelpers.h"
2627
#import "FTupleEventTypeString.h"
@@ -2571,7 +2572,7 @@ - (void)testParentDeleteShadowsChildListenersWithNonDefaultQuery {
25712572
WAIT_FOR(done);
25722573
}
25732574

2574-
- (void)testLocalServerValuesEventuallyButNotImmediatelyMatchServer {
2575+
- (void)testLocalServerTimestampEventuallyButNotImmediatelyMatchServer {
25752576
FTupleFirebase *refs = [FTestHelpers getRandomNodePair];
25762577
FIRDatabaseReference *writer = refs.one;
25772578
FIRDatabaseReference *reader = refs.two;
@@ -2635,7 +2636,7 @@ - (void)testLocalServerValuesEventuallyButNotImmediatelyMatchServer {
26352636
@"Eventual reader and writer priorities should be equal");
26362637
}
26372638

2638-
- (void)testServerValuesSetWithPriorityRemoteEvents {
2639+
- (void)testServerTimestampSetWithPriorityRemoteEvents {
26392640
FTupleFirebase *refs = [FTestHelpers getRandomNodePair];
26402641
FIRDatabaseReference *writer = refs.one;
26412642
FIRDatabaseReference *reader = refs.two;
@@ -2676,7 +2677,7 @@ - (void)testServerValuesSetWithPriorityRemoteEvents {
26762677
}];
26772678
}
26782679

2679-
- (void)testServerValuesSetPriorityRemoteEvents {
2680+
- (void)testServerTimestampSetPriorityRemoteEvents {
26802681
FTupleFirebase *refs = [FTestHelpers getRandomNodePair];
26812682
FIRDatabaseReference *writer = refs.one;
26822683
FIRDatabaseReference *reader = refs.two;
@@ -2708,7 +2709,7 @@ - (void)testServerValuesSetPriorityRemoteEvents {
27082709
@"Number should be no more than 2 seconds ago");
27092710
}
27102711

2711-
- (void)testServerValuesUpdateRemoteEvents {
2712+
- (void)testServerTimestampUpdateRemoteEvents {
27122713
FTupleFirebase *refs = [FTestHelpers getRandomNodePair];
27132714
FIRDatabaseReference *writer = refs.one;
27142715
FIRDatabaseReference *reader = refs.two;
@@ -2738,7 +2739,7 @@ - (void)testServerValuesUpdateRemoteEvents {
27382739
@"Number should be no more than 2 seconds ago");
27392740
}
27402741

2741-
- (void)testServerValuesSetWithPriorityLocalEvents {
2742+
- (void)testServerTimestampSetWithPriorityLocalEvents {
27422743
FIRDatabaseReference *node = [FTestHelpers getRandomNode];
27432744

27442745
NSDictionary *data = @{
@@ -2783,7 +2784,7 @@ - (void)testServerValuesSetWithPriorityLocalEvents {
27832784
}];
27842785
}
27852786

2786-
- (void)testServerValuesSetPriorityLocalEvents {
2787+
- (void)testServerTimestampSetPriorityLocalEvents {
27872788
FIRDatabaseReference *node = [FTestHelpers getRandomNode];
27882789

27892790
__block FIRDataSnapshot *snap = nil;
@@ -2812,7 +2813,7 @@ - (void)testServerValuesSetPriorityLocalEvents {
28122813
@"Number should be no more than 2 seconds ago");
28132814
}
28142815

2815-
- (void)testServerValuesUpdateLocalEvents {
2816+
- (void)testServerTimestampUpdateLocalEvents {
28162817
FIRDatabaseReference *node1 = [FTestHelpers getRandomNode];
28172818

28182819
__block FIRDataSnapshot *snap1 = nil;
@@ -2849,7 +2850,7 @@ - (void)testServerValuesUpdateLocalEvents {
28492850
@"Number should be no more than 2 seconds ago");
28502851
}
28512852

2852-
- (void)testServerValuesTransactionLocalEvents {
2853+
- (void)testServerTimestampTransactionLocalEvents {
28532854
FIRDatabaseReference *node = [FTestHelpers getRandomNode];
28542855

28552856
__block FIRDataSnapshot *snap = nil;
@@ -2873,6 +2874,137 @@ - (void)testServerValuesTransactionLocalEvents {
28732874
@"Number should be no more than 2 seconds ago");
28742875
}
28752876

2877+
- (void)testServerIncrementOverwritesExistingData {
2878+
FIRDatabaseReference *ref = [FTestHelpers getRandomNode];
2879+
__block NSMutableArray *found = [NSMutableArray new];
2880+
NSMutableArray *expected = [NSMutableArray new];
2881+
[ref observeEventType:FIRDataEventTypeValue
2882+
withBlock:^(FIRDataSnapshot *snap) {
2883+
[found addObject:snap.value];
2884+
}];
2885+
2886+
// Going offline ensures that local events get queued up before server events
2887+
[ref.repo interrupt];
2888+
2889+
// null + incr
2890+
[ref setValue:[FIRServerValue increment:@1]];
2891+
[expected addObject:@1];
2892+
2893+
// number + incr
2894+
[ref setValue:@5];
2895+
[ref setValue:[FIRServerValue increment:@1]];
2896+
[expected addObject:@5];
2897+
[expected addObject:@6];
2898+
2899+
// string + incr
2900+
[ref setValue:@"hello"];
2901+
[ref setValue:[FIRServerValue increment:@1]];
2902+
[expected addObject:@"hello"];
2903+
[expected addObject:@1];
2904+
2905+
// object + incr
2906+
[ref setValue:@{@"hello" : @"world"}];
2907+
[ref setValue:[FIRServerValue increment:@1]];
2908+
[expected addObject:@{@"hello" : @"world"}];
2909+
[expected addObject:@1];
2910+
2911+
[self waitUntil:^BOOL {
2912+
return found.count == expected.count;
2913+
}];
2914+
XCTAssertEqualObjects(expected, found);
2915+
[ref.repo resume];
2916+
}
2917+
2918+
- (void)testServerIncrementPriority {
2919+
FIRDatabaseReference *ref = [FTestHelpers getRandomNode];
2920+
__block NSMutableArray *found = [NSMutableArray new];
2921+
NSMutableArray *expected = [NSMutableArray new];
2922+
[ref observeEventType:FIRDataEventTypeValue
2923+
withBlock:^(FIRDataSnapshot *snap) {
2924+
[found addObject:snap.priority];
2925+
}];
2926+
2927+
// Going offline ensures that local events get queued up before server events
2928+
// Also necessary because increment may not be live yet in the server.
2929+
[ref.repo interrupt];
2930+
2931+
// null + incr
2932+
[ref setValue:@0 andPriority:[FIRServerValue increment:@1]];
2933+
[expected addObject:@1];
2934+
[ref setValue:@0 andPriority:[FIRServerValue increment:@1.5]];
2935+
[expected addObject:@2.5];
2936+
2937+
[self waitUntil:^BOOL {
2938+
return found.count == expected.count;
2939+
}];
2940+
XCTAssertEqualObjects(expected, found);
2941+
[ref.repo resume];
2942+
}
2943+
2944+
- (void)testServerIncrementOverflowAndTypeCoercion {
2945+
FIRDatabaseReference *ref = [FTestHelpers getRandomNode];
2946+
__block NSMutableArray *found = [NSMutableArray new];
2947+
__block NSMutableArray *foundTypes = [NSMutableArray new];
2948+
NSMutableArray *expected = [NSMutableArray new];
2949+
NSMutableArray *expectedTypes = [NSMutableArray new];
2950+
[ref observeEventType:FIRDataEventTypeValue
2951+
withBlock:^(FIRDataSnapshot *snap) {
2952+
[found addObject:snap.value];
2953+
[foundTypes addObject:@([(NSNumber *)snap.value objCType])];
2954+
}];
2955+
2956+
// Going offline ensures that local events get queued up before server events
2957+
// Also necessary because increment may not be live yet in the server.
2958+
[ref.repo interrupt];
2959+
2960+
// long + double = double
2961+
[ref setValue:@1];
2962+
[ref setValue:[FIRServerValue increment:@1.0]];
2963+
[expected addObject:@1];
2964+
[expected addObject:@2.0];
2965+
[expectedTypes addObject:@(@encode(int))];
2966+
[expectedTypes addObject:@(@encode(double))];
2967+
2968+
// double + long = double
2969+
[ref setValue:@1.5];
2970+
[ref setValue:[FIRServerValue increment:@1]];
2971+
[expected addObject:@1.5];
2972+
[expected addObject:@2.5];
2973+
[expectedTypes addObject:@(@encode(double))];
2974+
[expectedTypes addObject:@(@encode(double))];
2975+
2976+
// long overflow = double
2977+
[ref setValue:@(1)];
2978+
[ref setValue:[FIRServerValue increment:@(LONG_MAX)]];
2979+
[expected addObject:@(1)];
2980+
[expected addObject:@(LONG_MAX + 1.0)];
2981+
[expectedTypes addObject:@(@encode(int))];
2982+
[expectedTypes addObject:@(@encode(double))];
2983+
2984+
// unsigned long long overflow = double
2985+
[ref setValue:@1];
2986+
[ref setValue:[FIRServerValue increment:@((unsigned long long)ULLONG_MAX)]];
2987+
[expected addObject:@1];
2988+
[expected addObject:@((double)ULLONG_MAX + 1)];
2989+
[expectedTypes addObject:@(@encode(int))];
2990+
[expectedTypes addObject:@(@encode(double))];
2991+
2992+
// long underflow = double
2993+
[ref setValue:@(-1)];
2994+
[ref setValue:[FIRServerValue increment:@(LONG_MIN)]];
2995+
[expected addObject:@(-1)];
2996+
[expected addObject:@(LONG_MIN - 1.0)];
2997+
[expectedTypes addObject:@(@encode(int))];
2998+
[expectedTypes addObject:@(@encode(double))];
2999+
3000+
[self waitUntil:^BOOL {
3001+
return found.count == expected.count && foundTypes.count == expectedTypes.count;
3002+
}];
3003+
XCTAssertEqualObjects(expectedTypes, foundTypes);
3004+
XCTAssertEqualObjects(expected, found);
3005+
[ref.repo resume];
3006+
}
3007+
28763008
- (void)testUpdateAfterChildSet {
28773009
FIRDatabaseReference *node = [FTestHelpers getRandomNode];
28783010

@@ -2949,7 +3081,7 @@ - (void)testDeltaSyncNoDataUpdatesAfterReconnect {
29493081
[FRepoManager disposeRepos:cfg];
29503082
}
29513083

2952-
- (void)testServerValuesEventualConsistencyBetweenLocalAndRemote {
3084+
- (void)testServerTimestampEventualConsistencyBetweenLocalAndRemote {
29533085
FTupleFirebase *refs = [FTestHelpers getRandomNodePair];
29543086
FIRDatabaseReference *writer = refs.one;
29553087
FIRDatabaseReference *reader = refs.two;

Firebase/Database/Api/FIRServerValue.m

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
*/
1616

1717
#import "FIRServerValue.h"
18-
#import "FIRDatabaseReference.h"
18+
#import "FIRServerValue_unreleased.h"
1919

2020
@implementation FIRServerValue
2121

@@ -27,4 +27,8 @@ + (NSDictionary *)timestamp {
2727
return timestamp;
2828
}
2929

30+
+ (NSDictionary *)increment:(NSNumber *)delta {
31+
return @{@".sv" : @{@"increment" : delta}};
32+
}
33+
3034
@end
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/*
2+
* Copyright 2019 Google
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+
#ifndef FIRServerValue_unreleased_h
18+
#define FIRServerValue_unreleased_h
19+
20+
#import "FIRServerValue.h"
21+
22+
@interface FIRServerValue (Unreleased)
23+
24+
/**
25+
* Adds the given delta to the current value at a location.
26+
*
27+
* The delta must be an long or a double value. If the current value is not an
28+
* integer or double, or if the data does not yet exist, the transformation will
29+
* set the data to the delta value. If either of the delta value or the existing
30+
* data are doubles, both values will be interpreted as doubles. Double
31+
* arithmetic and representation of double values follow IEEE 754 semantics. If
32+
* there is positive/negative integer overflow, the sum is calculated as a a
33+
* double.
34+
*
35+
* @param delta the amount to modify the current value atomically.
36+
* @return a placeholder value for modifying data atomically server-side.
37+
*/
38+
+ (NSDictionary *)increment:(NSNumber *)delta NS_SWIFT_NAME(increment(_:));
39+
40+
@end
41+
42+
#endif /* FIRServerValue_unreleased_h */

Firebase/Database/Core/FRepo.m

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,9 @@ - (void)restoreWrites {
238238
}
239239
lastWriteId = writeId;
240240
self.writeIdCounter = writeId + 1;
241+
id<FNode> existing =
242+
[self.serverSyncTree calcCompleteEventCacheAtPath:write.path
243+
excludeWriteIds:@[]];
241244
if ([write isOverwrite]) {
242245
FFLog(@"I-RDB038001", @"Restoring overwrite with id %ld",
243246
(long)write.writeId);
@@ -247,7 +250,8 @@ - (void)restoreWrites {
247250
withCallback:callback];
248251
id<FNode> resolved =
249252
[FServerValues resolveDeferredValueSnapshot:write.overwrite
250-
withServerValues:serverValues];
253+
withExisting:existing
254+
serverValues:serverValues];
251255
[self.serverSyncTree applyUserOverwriteAtPath:write.path
252256
newData:resolved
253257
writeId:writeId
@@ -260,7 +264,8 @@ - (void)restoreWrites {
260264
withCallback:callback];
261265
FCompoundWrite *resolved =
262266
[FServerValues resolveDeferredValueCompoundWrite:write.merge
263-
withServerValues:serverValues];
267+
withExisting:existing
268+
serverValues:serverValues];
264269
[self.serverSyncTree applyUserMergeAtPath:write.path
265270
changedChildren:resolved
266271
writeId:writeId];
@@ -314,9 +319,12 @@ - (void)set:(FPath *)path
314319
// where possible and / or (b) store unresolved paths on JSON parse
315320
NSDictionary *serverValues =
316321
[FServerValues generateServerValues:self.serverClock];
322+
id<FNode> existing = [self.serverSyncTree calcCompleteEventCacheAtPath:path
323+
excludeWriteIds:@[]];
317324
id<FNode> newNode =
318325
[FServerValues resolveDeferredValueSnapshot:node
319-
withServerValues:serverValues];
326+
withExisting:existing
327+
serverValues:serverValues];
320328

321329
NSInteger writeId = [self nextWriteId];
322330
[self.persistenceManager saveUserOverwrite:node
@@ -358,9 +366,12 @@ - (void)update:(FPath *)path
358366
[values description]);
359367
NSDictionary *serverValues =
360368
[FServerValues generateServerValues:self.serverClock];
369+
id<FNode> existing = [self.serverSyncTree calcCompleteEventCacheAtPath:path
370+
excludeWriteIds:@[]];
361371
FCompoundWrite *resolved =
362372
[FServerValues resolveDeferredValueCompoundWrite:nodes
363-
withServerValues:serverValues];
373+
withExisting:existing
374+
serverValues:serverValues];
364375

365376
if (!resolved.isEmpty) {
366377
NSInteger writeId = [self nextWriteId];
@@ -770,18 +781,22 @@ - (void)runOnDisconnectEvents {
770781
FFLog(@"I-RDB038019", @"Running onDisconnectEvents");
771782
NSDictionary *serverValues =
772783
[FServerValues generateServerValues:self.serverClock];
773-
FSparseSnapshotTree *resolvedTree =
774-
[FServerValues resolveDeferredValueTree:self.onDisconnect
775-
withServerValues:serverValues];
776784
NSMutableArray *events = [[NSMutableArray alloc] init];
777785

778-
[resolvedTree
786+
[self.onDisconnect
779787
forEachTreeAtPath:[FPath empty]
780788
do:^(FPath *path, id<FNode> node) {
789+
id<FNode> existing = [self.serverSyncTree
790+
calcCompleteEventCacheAtPath:path
791+
excludeWriteIds:@[]];
792+
id<FNode> resolved = [FServerValues
793+
resolveDeferredValueSnapshot:node
794+
withExisting:existing
795+
serverValues:serverValues];
781796
[events addObjectsFromArray:
782797
[self.serverSyncTree
783798
applyServerOverwriteAtPath:path
784-
newData:node]];
799+
newData:resolved]];
785800
FPath *affectedPath =
786801
[self abortTransactionsAtPath:path
787802
error:kFTransactionSet];
@@ -911,7 +926,8 @@ - (void)startTransactionOnPath:(FPath *)path
911926
id<FNode> newValUnresolved = [result.update nodeValue];
912927
id<FNode> newVal =
913928
[FServerValues resolveDeferredValueSnapshot:newValUnresolved
914-
withServerValues:serverValues];
929+
withExisting:currentState
930+
serverValues:serverValues];
915931
transaction.currentOutputSnapshotRaw = newValUnresolved;
916932
transaction.currentOutputSnapshotResolved = newVal;
917933
transaction.currentWriteId =
@@ -1192,7 +1208,9 @@ - (void)rerunTransactionQueue:(NSArray *)queue atPath:(FPath *)path {
11921208
id<FNode> newVal = [result.update nodeValue];
11931209
id<FNode> newValResolved = [FServerValues
11941210
resolveDeferredValueSnapshot:newVal
1195-
withServerValues:serverValues];
1211+
withExisting:transaction
1212+
.currentInputSnapshot
1213+
serverValues:serverValues];
11961214

11971215
transaction.currentOutputSnapshotRaw = newVal;
11981216
transaction.currentOutputSnapshotResolved = newValResolved;

0 commit comments

Comments
 (0)