@@ -47,11 +47,18 @@ export class LockedAsyncDatabaseAdapter
4747 private _db : AsyncDatabaseConnection | null = null ;
4848 protected _disposeTableChangeListener : ( ( ) => void ) | null = null ;
4949 private _config : ResolvedWebSQLOpenOptions | null = null ;
50+ protected pendingAbortControllers : Set < AbortController > ;
51+
52+ closing : boolean ;
53+ closed : boolean ;
5054
5155 constructor ( protected options : LockedAsyncDatabaseAdapterOptions ) {
5256 super ( ) ;
5357 this . _dbIdentifier = options . name ;
5458 this . logger = options . logger ?? createLogger ( `LockedAsyncDatabaseAdapter - ${ this . _dbIdentifier } ` ) ;
59+ this . pendingAbortControllers = new Set < AbortController > ( ) ;
60+ this . closed = false ;
61+ this . closing = false ;
5562 // Set the name if provided. We can query for the name if not available yet
5663 this . debugMode = options . debugMode ?? false ;
5764 if ( this . debugMode ) {
@@ -154,8 +161,11 @@ export class LockedAsyncDatabaseAdapter
154161 * tabs are still using it.
155162 */
156163 async close ( ) {
164+ this . closing = true ;
157165 this . _disposeTableChangeListener ?.( ) ;
166+ this . pendingAbortControllers . forEach ( ( controller ) => controller . abort ( 'Closed' ) ) ;
158167 await this . baseDB ?. close ?.( ) ;
168+ this . closed = true ;
159169 }
160170
161171 async getAll < T > ( sql : string , parameters ?: any [ ] | undefined ) : Promise < T [ ] > {
@@ -175,20 +185,49 @@ export class LockedAsyncDatabaseAdapter
175185
176186 async readLock < T > ( fn : ( tx : LockContext ) => Promise < T > , options ?: DBLockOptions | undefined ) : Promise < T > {
177187 await this . waitForInitialized ( ) ;
178- return this . acquireLock ( async ( ) =>
179- fn ( this . generateDBHelpers ( { execute : this . _execute , executeRaw : this . _executeRaw } ) )
188+ return this . acquireLock (
189+ async ( ) => fn ( this . generateDBHelpers ( { execute : this . _execute , executeRaw : this . _executeRaw } ) ) ,
190+ {
191+ timeoutMs : options ?. timeoutMs
192+ }
180193 ) ;
181194 }
182195
183196 async writeLock < T > ( fn : ( tx : LockContext ) => Promise < T > , options ?: DBLockOptions | undefined ) : Promise < T > {
184197 await this . waitForInitialized ( ) ;
185- return this . acquireLock ( async ( ) =>
186- fn ( this . generateDBHelpers ( { execute : this . _execute , executeRaw : this . _executeRaw } ) )
198+ return this . acquireLock (
199+ async ( ) => fn ( this . generateDBHelpers ( { execute : this . _execute , executeRaw : this . _executeRaw } ) ) ,
200+ {
201+ timeoutMs : options ?. timeoutMs
202+ }
187203 ) ;
188204 }
189205
190- protected acquireLock ( callback : ( ) => Promise < any > ) : Promise < any > {
191- return getNavigatorLocks ( ) . request ( `db-lock-${ this . _dbIdentifier } ` , callback ) ;
206+ protected async acquireLock ( callback : ( ) => Promise < any > , options ?: { timeoutMs ?: number } ) : Promise < any > {
207+ await this . waitForInitialized ( ) ;
208+
209+ if ( this . closing ) {
210+ throw new Error ( `Cannot acquire lock, the database is closing` ) ;
211+ }
212+
213+ const abortController = new AbortController ( ) ;
214+ this . pendingAbortControllers . add ( abortController ) ;
215+ const { timeoutMs } = options ?? { } ;
216+
217+ const timoutId = timeoutMs
218+ ? setTimeout ( ( ) => {
219+ abortController . abort ( `Timeout after ${ timeoutMs } ms` ) ;
220+ this . pendingAbortControllers . delete ( abortController ) ;
221+ } , timeoutMs )
222+ : null ;
223+
224+ return getNavigatorLocks ( ) . request ( `db-lock-${ this . _dbIdentifier } ` , { signal : abortController . signal } , ( ) => {
225+ this . pendingAbortControllers . delete ( abortController ) ;
226+ if ( timoutId ) {
227+ clearTimeout ( timoutId ) ;
228+ }
229+ return callback ( ) ;
230+ } ) ;
192231 }
193232
194233 async readTransaction < T > ( fn : ( tx : Transaction ) => Promise < T > , options ?: DBLockOptions | undefined ) : Promise < T > {
@@ -286,6 +325,7 @@ export class LockedAsyncDatabaseAdapter
286325 */
287326 private _execute = async ( sql : string , bindings ?: any [ ] ) : Promise < QueryResult > => {
288327 await this . waitForInitialized ( ) ;
328+
289329 const result = await this . baseDB . execute ( sql , bindings ) ;
290330 return {
291331 ...result ,
0 commit comments