@@ -34,6 +34,8 @@ import {
34
34
import { AsyncQueue } from '../util/async_queue' ;
35
35
import { Platform } from '../platform/platform' ;
36
36
import { TargetIdSet , targetIdSet } from '../model/collections' ;
37
+ import { SnapshotVersion } from '../core/snapshot_version' ;
38
+ import { Timestamp } from '../api/timestamp' ;
37
39
38
40
const LOG_TAG = 'SharedClientState' ;
39
41
@@ -91,6 +93,7 @@ export interface SharedClientState {
91
93
*/
92
94
updateMutationState (
93
95
batchId : BatchId ,
96
+ snapshotVersion : SnapshotVersion ,
94
97
state : 'acknowledged' | 'rejected' ,
95
98
error ?: FirestoreError
96
99
) : void ;
@@ -113,6 +116,7 @@ export interface SharedClientState {
113
116
*/
114
117
updateQueryState (
115
118
targetId : TargetId ,
119
+ snapshotVersion : SnapshotVersion ,
116
120
state : QueryTargetState ,
117
121
error ?: FirestoreError
118
122
) : void ;
@@ -173,6 +177,7 @@ export interface SharedClientState {
173
177
* encoded as part of the key.
174
178
*/
175
179
interface MutationMetadataSchema {
180
+ snapshotVersion : { seconds : number ; nanos : number } ;
176
181
state : MutationBatchState ;
177
182
error ?: { code : string ; message : string } ; // Only set when state === 'rejected'
178
183
}
@@ -186,6 +191,7 @@ export class MutationMetadata {
186
191
constructor (
187
192
readonly user : User ,
188
193
readonly batchId : BatchId ,
194
+ readonly snapshotVersion : SnapshotVersion ,
189
195
readonly state : MutationBatchState ,
190
196
readonly error ?: FirestoreError
191
197
) {
@@ -210,6 +216,7 @@ export class MutationMetadata {
210
216
typeof mutationBatch === 'object' &&
211
217
[ 'pending' , 'acknowledged' , 'rejected' ] . indexOf ( mutationBatch . state ) !==
212
218
- 1 &&
219
+ isSnapshotVersion ( mutationBatch . snapshotVersion ) &&
213
220
( mutationBatch . error === undefined ||
214
221
typeof mutationBatch . error === 'object' ) ;
215
222
@@ -231,6 +238,12 @@ export class MutationMetadata {
231
238
return new MutationMetadata (
232
239
user ,
233
240
batchId ,
241
+ SnapshotVersion . fromTimestamp (
242
+ new Timestamp (
243
+ mutationBatch . snapshotVersion . seconds ,
244
+ mutationBatch . snapshotVersion . nanos
245
+ )
246
+ ) ,
234
247
mutationBatch . state ,
235
248
firestoreError
236
249
) ;
@@ -244,7 +257,12 @@ export class MutationMetadata {
244
257
}
245
258
246
259
toLocalStorageJSON ( ) : string {
260
+ const timestamp = this . snapshotVersion . toTimestamp ( ) ;
247
261
const batchMetadata : MutationMetadataSchema = {
262
+ snapshotVersion : {
263
+ seconds : timestamp . seconds ,
264
+ nanos : timestamp . nanoseconds
265
+ } ,
248
266
state : this . state
249
267
} ;
250
268
@@ -264,6 +282,7 @@ export class MutationMetadata {
264
282
* serialization. The TargetId is omitted as it is encoded as part of the key.
265
283
*/
266
284
interface QueryTargetStateSchema {
285
+ snapshotVersion : { seconds : number ; nanos : number } ;
267
286
state : QueryTargetState ;
268
287
error ?: { code : string ; message : string } ; // Only set when state === 'rejected'
269
288
}
@@ -276,6 +295,7 @@ interface QueryTargetStateSchema {
276
295
export class QueryTargetMetadata {
277
296
constructor (
278
297
readonly targetId : TargetId ,
298
+ readonly snapshotVersion : SnapshotVersion ,
279
299
readonly state : QueryTargetState ,
280
300
readonly error ?: FirestoreError
281
301
) {
@@ -297,6 +317,7 @@ export class QueryTargetMetadata {
297
317
298
318
let validData =
299
319
typeof targetState === 'object' &&
320
+ isSnapshotVersion ( targetState . snapshotVersion ) &&
300
321
[ 'not-current' , 'current' , 'rejected' ] . indexOf ( targetState . state ) !==
301
322
- 1 &&
302
323
( targetState . error === undefined ||
@@ -319,6 +340,12 @@ export class QueryTargetMetadata {
319
340
if ( validData ) {
320
341
return new QueryTargetMetadata (
321
342
targetId ,
343
+ SnapshotVersion . fromTimestamp (
344
+ new Timestamp (
345
+ targetState . snapshotVersion . seconds ,
346
+ targetState . snapshotVersion . nanos
347
+ )
348
+ ) ,
322
349
targetState . state ,
323
350
firestoreError
324
351
) ;
@@ -332,7 +359,12 @@ export class QueryTargetMetadata {
332
359
}
333
360
334
361
toLocalStorageJSON ( ) : string {
362
+ const timestamp = this . snapshotVersion . toTimestamp ( ) ;
335
363
const targetState : QueryTargetStateSchema = {
364
+ snapshotVersion : {
365
+ seconds : timestamp . seconds ,
366
+ nanos : timestamp . nanoseconds
367
+ } ,
336
368
state : this . state
337
369
} ;
338
370
@@ -654,15 +686,16 @@ export class WebStorageSharedClientState implements SharedClientState {
654
686
}
655
687
656
688
addPendingMutation ( batchId : BatchId ) : void {
657
- this . persistMutationState ( batchId , 'pending' ) ;
689
+ this . persistMutationState ( batchId , SnapshotVersion . MIN , 'pending' ) ;
658
690
}
659
691
660
692
updateMutationState (
661
693
batchId : BatchId ,
694
+ snapshotVersion : SnapshotVersion ,
662
695
state : 'acknowledged' | 'rejected' ,
663
696
error ?: FirestoreError
664
697
) : void {
665
- this . persistMutationState ( batchId , state , error ) ;
698
+ this . persistMutationState ( batchId , snapshotVersion , state , error ) ;
666
699
667
700
// Once a final mutation result is observed by other clients, they no longer
668
701
// access the mutation's metadata entry. Since LocalStorage replays events
@@ -708,10 +741,11 @@ export class WebStorageSharedClientState implements SharedClientState {
708
741
709
742
updateQueryState (
710
743
targetId : TargetId ,
744
+ snapshotVersion : SnapshotVersion ,
711
745
state : QueryTargetState ,
712
746
error ?: FirestoreError
713
747
) : void {
714
- this . persistQueryTargetState ( targetId , state , error ) ;
748
+ this . persistQueryTargetState ( targetId , snapshotVersion , state , error ) ;
715
749
}
716
750
717
751
handleUserChange (
@@ -836,12 +870,14 @@ export class WebStorageSharedClientState implements SharedClientState {
836
870
837
871
private persistMutationState (
838
872
batchId : BatchId ,
873
+ snapshotVersion : SnapshotVersion ,
839
874
state : MutationBatchState ,
840
875
error ?: FirestoreError
841
876
) : void {
842
877
const mutationState = new MutationMetadata (
843
878
this . currentUser ,
844
879
batchId ,
880
+ snapshotVersion ,
845
881
state ,
846
882
error
847
883
) ;
@@ -864,11 +900,17 @@ export class WebStorageSharedClientState implements SharedClientState {
864
900
865
901
private persistQueryTargetState (
866
902
targetId : TargetId ,
903
+ snapshotVersion : SnapshotVersion ,
867
904
state : QueryTargetState ,
868
905
error ?: FirestoreError
869
906
) : void {
870
907
const targetKey = this . toLocalStorageQueryTargetMetadataKey ( targetId ) ;
871
- const targetMetadata = new QueryTargetMetadata ( targetId , state , error ) ;
908
+ const targetMetadata = new QueryTargetMetadata (
909
+ targetId ,
910
+ snapshotVersion ,
911
+ state ,
912
+ error
913
+ ) ;
872
914
this . setItem ( targetKey , targetMetadata . toLocalStorageJSON ( ) ) ;
873
915
}
874
916
@@ -978,6 +1020,7 @@ export class WebStorageSharedClientState implements SharedClientState {
978
1020
979
1021
return this . syncEngine . applyBatchState (
980
1022
mutationBatch . batchId ,
1023
+ mutationBatch . snapshotVersion ,
981
1024
mutationBatch . state ,
982
1025
mutationBatch . error
983
1026
) ;
@@ -988,6 +1031,7 @@ export class WebStorageSharedClientState implements SharedClientState {
988
1031
) : Promise < void > {
989
1032
return this . syncEngine . applyTargetState (
990
1033
targetMetadata . targetId ,
1034
+ targetMetadata . snapshotVersion ,
991
1035
targetMetadata . state ,
992
1036
targetMetadata . error
993
1037
) ;
@@ -1058,6 +1102,7 @@ export class MemorySharedClientState implements SharedClientState {
1058
1102
1059
1103
updateMutationState (
1060
1104
batchId : BatchId ,
1105
+ snapshotVersion : SnapshotVersion ,
1061
1106
state : 'acknowledged' | 'rejected' ,
1062
1107
error ?: FirestoreError
1063
1108
) : void {
@@ -1071,6 +1116,7 @@ export class MemorySharedClientState implements SharedClientState {
1071
1116
1072
1117
updateQueryState (
1073
1118
targetId : TargetId ,
1119
+ snapshotVersion : SnapshotVersion ,
1074
1120
state : QueryTargetState ,
1075
1121
error ?: FirestoreError
1076
1122
) : void {
@@ -1112,3 +1158,14 @@ export class MemorySharedClientState implements SharedClientState {
1112
1158
1113
1159
shutdown ( ) : void { }
1114
1160
}
1161
+
1162
+ function isSnapshotVersion ( snapshotVersion : {
1163
+ seconds : number ;
1164
+ nanos : number ;
1165
+ } ) : boolean {
1166
+ return (
1167
+ typeof snapshotVersion === 'object' &&
1168
+ isSafeInteger ( snapshotVersion . seconds ) &&
1169
+ isSafeInteger ( snapshotVersion . nanos )
1170
+ ) ;
1171
+ }
0 commit comments