@@ -23,6 +23,7 @@ import {
23
23
QueryDocumentSnapshot ,
24
24
Transaction ,
25
25
collection ,
26
+ deleteDoc ,
26
27
doc ,
27
28
DocumentReference ,
28
29
DocumentSnapshot ,
@@ -87,6 +88,16 @@ apiDescribe('Database transactions', (persistence: boolean) => {
87
88
await transaction . get ( docRef ) ;
88
89
}
89
90
91
+ enum FromDocumentType {
92
+ // The operation will be performed on a document that exists.
93
+ EXISTING = 'existing' ,
94
+ // The operation will be performed on a document that has never existed.
95
+ NON_EXISTENT = 'non_existent' ,
96
+ // The operation will be performed on a document that existed, but was
97
+ // deleted.
98
+ DELETED = 'deleted'
99
+ }
100
+
90
101
/**
91
102
* Used for testing that all possible combinations of executing transactions
92
103
* result in the desired document value or error.
@@ -101,16 +112,21 @@ apiDescribe('Database transactions', (persistence: boolean) => {
101
112
constructor ( readonly db : Firestore ) { }
102
113
103
114
private docRef ! : DocumentReference ;
104
- private fromExistingDoc : boolean = false ;
115
+ private fromDocumentType : FromDocumentType = FromDocumentType . NON_EXISTENT ;
105
116
private stages : TransactionStage [ ] = [ ] ;
106
117
107
118
withExistingDoc ( ) : this {
108
- this . fromExistingDoc = true ;
119
+ this . fromDocumentType = FromDocumentType . EXISTING ;
109
120
return this ;
110
121
}
111
122
112
123
withNonexistentDoc ( ) : this {
113
- this . fromExistingDoc = false ;
124
+ this . fromDocumentType = FromDocumentType . NON_EXISTENT ;
125
+ return this ;
126
+ }
127
+
128
+ withDeletedDoc ( ) : this {
129
+ this . fromDocumentType = FromDocumentType . DELETED ;
114
130
return this ;
115
131
}
116
132
@@ -176,8 +192,17 @@ apiDescribe('Database transactions', (persistence: boolean) => {
176
192
177
193
private async prepareDoc ( ) : Promise < void > {
178
194
this . docRef = doc ( collection ( this . db , 'tester-docref' ) ) ;
179
- if ( this . fromExistingDoc ) {
180
- await setDoc ( this . docRef , { foo : 'bar0' } ) ;
195
+ switch ( this . fromDocumentType ) {
196
+ case FromDocumentType . EXISTING :
197
+ await setDoc ( this . docRef , { foo : 'bar0' } ) ;
198
+ break ;
199
+ case FromDocumentType . NON_EXISTENT :
200
+ // Nothing to do; document does not exist.
201
+ break ;
202
+ case FromDocumentType . DELETED :
203
+ await setDoc ( this . docRef , { foo : 'bar0' } ) ;
204
+ await deleteDoc ( this . docRef ) ;
205
+ break ;
181
206
}
182
207
}
183
208
@@ -289,6 +314,42 @@ apiDescribe('Database transactions', (persistence: boolean) => {
289
314
} ) ;
290
315
} ) ;
291
316
317
+ it ( 'runs transactions after getting a deleted document' , async ( ) => {
318
+ return withTestDb ( persistence , async db => {
319
+ const tt = new TransactionTester ( db ) ;
320
+
321
+ await tt . withDeletedDoc ( ) . run ( get , delete1 , delete1 ) . expectNoDoc ( ) ;
322
+ await tt
323
+ . withDeletedDoc ( )
324
+ . run ( get , delete1 , update2 )
325
+ . expectError ( 'invalid-argument' ) ;
326
+ await tt
327
+ . withDeletedDoc ( )
328
+ . run ( get , delete1 , set2 )
329
+ . expectDoc ( { foo : 'bar2' } ) ;
330
+
331
+ await tt
332
+ . withDeletedDoc ( )
333
+ . run ( get , update1 , delete1 )
334
+ . expectError ( 'invalid-argument' ) ;
335
+ await tt
336
+ . withDeletedDoc ( )
337
+ . run ( get , update1 , update2 )
338
+ . expectError ( 'invalid-argument' ) ;
339
+ await tt
340
+ . withDeletedDoc ( )
341
+ . run ( get , update1 , set1 )
342
+ . expectError ( 'invalid-argument' ) ;
343
+
344
+ await tt . withDeletedDoc ( ) . run ( get , set1 , delete1 ) . expectNoDoc ( ) ;
345
+ await tt
346
+ . withDeletedDoc ( )
347
+ . run ( get , set1 , update2 )
348
+ . expectDoc ( { foo : 'bar2' } ) ;
349
+ await tt . withDeletedDoc ( ) . run ( get , set1 , set2 ) . expectDoc ( { foo : 'bar2' } ) ;
350
+ } ) ;
351
+ } ) ;
352
+
292
353
it ( 'runs transactions on existing document' , async ( ) => {
293
354
return withTestDb ( persistence , async db => {
294
355
const tt = new TransactionTester ( db ) ;
0 commit comments