@@ -162,24 +162,57 @@ export interface IdbDatabaseDebugIdPair {
162
162
163
163
class SimpleDbStateNew {
164
164
readonly name = 'new' as const ;
165
+
166
+ constructor (
167
+ readonly databaseDeletedListener : DatabaseDeletedListener | null
168
+ ) { }
169
+
170
+ withDatabaseDeletedListener (
171
+ databaseDeletedListener : DatabaseDeletedListener
172
+ ) : SimpleDbStateNew {
173
+ return new SimpleDbStateNew ( databaseDeletedListener ) ;
174
+ }
165
175
}
166
176
167
177
class SimpleDbStateOpening {
168
178
readonly name = 'opening' as const ;
169
179
170
- constructor ( readonly promise : Promise < unknown > ) { }
180
+ constructor (
181
+ readonly promise : Promise < unknown > ,
182
+ readonly databaseDeletedListener : DatabaseDeletedListener | null
183
+ ) { }
184
+
185
+ withDatabaseDeletedListener (
186
+ databaseDeletedListener : DatabaseDeletedListener
187
+ ) : SimpleDbStateOpening {
188
+ return new SimpleDbStateOpening ( this . promise , databaseDeletedListener ) ;
189
+ }
171
190
}
172
191
173
192
class SimpleDbStateOpened {
174
193
readonly name = 'opened' as const ;
175
194
176
- constructor ( readonly db : IdbDatabaseDebugIdPair ) { }
195
+ constructor (
196
+ readonly db : IdbDatabaseDebugIdPair ,
197
+ readonly databaseDeletedListener : DatabaseDeletedListener | null
198
+ ) { }
199
+
200
+ withDatabaseDeletedListener (
201
+ databaseDeletedListener : DatabaseDeletedListener
202
+ ) : SimpleDbStateOpened {
203
+ return new SimpleDbStateOpened ( this . db , databaseDeletedListener ) ;
204
+ }
205
+ }
206
+
207
+ class SimpleDbStateClosed {
208
+ readonly name = 'closed' as const ;
177
209
}
178
210
179
211
type SimpleDbState =
180
212
| SimpleDbStateNew
181
213
| SimpleDbStateOpened
182
- | SimpleDbStateOpening ;
214
+ | SimpleDbStateOpening
215
+ | SimpleDbStateClosed ;
183
216
184
217
/**
185
218
* Provides a wrapper around IndexedDb with a simplified interface that uses
@@ -190,8 +223,7 @@ type SimpleDbState =
190
223
*/
191
224
export class SimpleDb {
192
225
readonly debugId = `SimpleDb@${ generateUniqueDebugId ( ) } ` ;
193
- private state : SimpleDbState = new SimpleDbStateNew ( ) ;
194
- private databaseDeletedListener : DatabaseDeletedListener | null = null ;
226
+ private state : SimpleDbState = new SimpleDbStateNew ( null ) ;
195
227
196
228
/** Deletes the specified database. */
197
229
static delete ( name : string ) : Promise < void > {
@@ -331,26 +363,41 @@ export class SimpleDb {
331
363
async ensureDb ( action : string ) : Promise < IdbDatabaseDebugIdPair > {
332
364
while ( true ) {
333
365
const currentState = this . state ;
334
- if ( currentState . name === 'opening' ) {
366
+ if ( currentState . name === 'closed' ) {
367
+ console . trace (
368
+ `zzyzx ${ this . debugId } ` +
369
+ `ensureDb(${ JSON . stringify ( action ) } ) called after close()`
370
+ ) ;
371
+ dumpLogBuffer ( 'SimpleDb.ensureDb after close' ) ;
372
+ throw new Error ( `${ this . debugId } has been closed` ) ;
373
+ } else if ( currentState . name === 'opening' ) {
335
374
await currentState . promise . catch ( _ => { } ) ;
336
375
} else if ( currentState . name === 'opened' ) {
337
376
return currentState . db ;
338
377
} else {
339
378
hardAssert ( currentState . name === 'new' , 0x56e8 , { state : this . state } ) ;
340
379
const promise = this . openDb ( action ) ;
341
- const openingState = new SimpleDbStateOpening ( promise ) ;
380
+ const openingState = new SimpleDbStateOpening (
381
+ promise ,
382
+ currentState . databaseDeletedListener
383
+ ) ;
342
384
this . state = openingState ;
343
385
try {
344
386
const db = await promise ;
345
387
if ( this . state === openingState ) {
346
- this . state = new SimpleDbStateOpened ( db ) ;
388
+ this . state = new SimpleDbStateOpened (
389
+ db ,
390
+ openingState . databaseDeletedListener
391
+ ) ;
347
392
return db ;
348
393
} else {
349
394
db . idbDatabase . close ( ) ;
350
395
}
351
396
} catch ( e ) {
352
397
if ( this . state === openingState ) {
353
- this . state = new SimpleDbStateNew ( ) ;
398
+ this . state = new SimpleDbStateNew (
399
+ this . state . databaseDeletedListener
400
+ ) ;
354
401
throw e ;
355
402
}
356
403
}
@@ -454,7 +501,9 @@ export class SimpleDb {
454
501
`Received "versionchange" event with newVersion===null; ` +
455
502
'notifying the registered DatabaseDeletedListener, if any'
456
503
) ;
457
- this . databaseDeletedListener ?.( ) ;
504
+ if ( 'databaseDeletedListener' in this . state ) {
505
+ this . state . databaseDeletedListener ?.( ) ;
506
+ }
458
507
}
459
508
} ,
460
509
{ passive : true }
@@ -471,9 +520,6 @@ export class SimpleDb {
471
520
`in a web browser.`
472
521
) ;
473
522
dumpLogBuffer ( 'SimpleDbCloseEvent' ) ;
474
- if ( this . state . name === 'opened' && this . state . db . idbDatabase === db ) {
475
- this . state = new SimpleDbStateNew ( ) ;
476
- }
477
523
} ,
478
524
{ passive : true }
479
525
) ;
@@ -484,10 +530,15 @@ export class SimpleDb {
484
530
setDatabaseDeletedListener (
485
531
databaseDeletedListener : DatabaseDeletedListener
486
532
) : void {
487
- if ( this . databaseDeletedListener ) {
533
+ if ( ! ( 'databaseDeletedListener' in this . state ) ) {
534
+ return ;
535
+ }
536
+ if ( this . state . databaseDeletedListener ) {
488
537
throw new Error ( 'setDatabaseDeletedListener() has already been called' ) ;
489
538
}
490
- this . databaseDeletedListener = databaseDeletedListener ;
539
+ this . state = this . state . withDatabaseDeletedListener (
540
+ databaseDeletedListener
541
+ ) ;
491
542
}
492
543
493
544
async runTransaction < T > (
@@ -568,7 +619,7 @@ export class SimpleDb {
568
619
) ;
569
620
570
621
if ( 'db' in this . state && dbBefore === this . state . db ) {
571
- this . state = new SimpleDbStateNew ( ) ;
622
+ this . state = new SimpleDbStateNew ( this . state . databaseDeletedListener ) ;
572
623
logWarn (
573
624
this . debugId ,
574
625
`Transaction transactionId=${ transactionId } closing IDBDatabase ` +
@@ -586,11 +637,15 @@ export class SimpleDb {
586
637
}
587
638
588
639
close ( ) : void {
640
+ if ( this . state . name === 'closed' ) {
641
+ dumpLogBuffer ( 'SimpleDb.close' ) ;
642
+ return ;
643
+ }
589
644
logDebug ( this . debugId , 'close()' ) ;
590
645
if ( 'db' in this . state ) {
591
646
this . state . db . idbDatabase . close ( ) ;
592
647
}
593
- this . state = new SimpleDbStateNew ( ) ;
648
+ this . state = new SimpleDbStateClosed ( ) ;
594
649
}
595
650
}
596
651
0 commit comments