@@ -39,16 +39,11 @@ const getRequestId = () => {
39
39
const LockCallbacks : Record < ContextLockID , LockCallbackRecord > = { } ;
40
40
let proxy : ISQLite ;
41
41
42
- /**
43
- * Creates a unique identifier for all a database's lock requests
44
- */
45
- const lockKey = ( dbName : string , id : ContextLockID ) => `${ dbName } :${ id } ` ;
46
-
47
42
/**
48
43
* Closes the context in JS and C++
49
44
*/
50
45
function closeContextLock ( dbName : string , id : ContextLockID ) {
51
- delete LockCallbacks [ lockKey ( dbName , id ) ] ;
46
+ delete LockCallbacks [ id ] ;
52
47
53
48
// This is configured by the setupOpen function
54
49
proxy . releaseLock ( dbName , id ) ;
@@ -64,10 +59,9 @@ global.onLockContextIsAvailable = async (dbName: string, lockId: ContextLockID)
64
59
// Don't hold C++ bridge side up waiting to complete
65
60
setImmediate ( async ( ) => {
66
61
try {
67
- const key = lockKey ( dbName , lockId ) ;
68
- const record = LockCallbacks [ key ] ;
62
+ const record = LockCallbacks [ lockId ] ;
69
63
// clear record after fetching, the hash should only contain pending requests
70
- delete LockCallbacks [ key ] ;
64
+ delete LockCallbacks [ lockId ] ;
71
65
72
66
if ( record ?. timeout ) {
73
67
clearTimeout ( record . timeout ) ;
@@ -125,10 +119,21 @@ export function setupOpen(QuickSQLite: ISQLite) {
125
119
// Wrap the callback in a promise that will resolve to the callback result
126
120
return new Promise < T > ( ( resolve , reject ) => {
127
121
// Add callback to the queue for timing
128
- const key = lockKey ( dbName , id ) ;
129
- const record = ( LockCallbacks [ key ] = {
122
+ const closedListener = listenerManager . registerListener ( {
123
+ closed : ( ) => {
124
+ closedListener ?.( ) ;
125
+ // Remove callback from the queue
126
+ delete LockCallbacks [ id ] ;
127
+ // Reject the lock request if the connection is closed
128
+ reject ( new Error ( 'Connection is closed' ) ) ;
129
+ }
130
+ } ) ;
131
+
132
+ const record = ( LockCallbacks [ id ] = {
130
133
callback : async ( context : LockContext ) => {
131
134
try {
135
+ // Remove the close listener
136
+ closedListener ?.( ) ;
132
137
await hooks ?. lockAcquired ?.( ) ;
133
138
const res = await callback ( context ) ;
134
139
closeContextLock ( dbName , id ) ;
@@ -149,13 +154,14 @@ export function setupOpen(QuickSQLite: ISQLite) {
149
154
if ( timeout ) {
150
155
record . timeout = setTimeout ( ( ) => {
151
156
// The callback won't be executed
152
- delete LockCallbacks [ key ] ;
157
+ delete LockCallbacks [ id ] ;
153
158
reject ( new Error ( `Lock request timed out after ${ timeout } ms` ) ) ;
154
159
} , timeout ) ;
155
160
}
156
161
} catch ( ex ) {
162
+ closedListener ?.( ) ;
157
163
// Remove callback from the queue
158
- delete LockCallbacks [ key ] ;
164
+ delete LockCallbacks [ id ] ;
159
165
reject ( ex ) ;
160
166
}
161
167
} ) ;
@@ -236,23 +242,8 @@ export function setupOpen(QuickSQLite: ISQLite) {
236
242
return {
237
243
close : ( ) => {
238
244
QuickSQLite . close ( dbName ) ;
239
- // Reject any pending lock requests
240
- Object . entries ( LockCallbacks ) . forEach ( ( [ key , record ] ) => {
241
- const recordDBName = key . split ( ':' ) [ 0 ] ;
242
- if ( dbName !== recordDBName ) {
243
- return ;
244
- }
245
- // A bit of a hack, let the callbacks run with an execute method that will fail
246
- record
247
- . callback ( {
248
- execute : async ( ) => {
249
- throw new Error ( 'Connection is closed' ) ;
250
- }
251
- } )
252
- . catch ( ( ) => { } ) ;
253
-
254
- delete LockCallbacks [ key ] ;
255
- } ) ;
245
+ // Close any pending listeners
246
+ listenerManager . iterateListeners ( ( l ) => l . closed ?.( ) ) ;
256
247
} ,
257
248
refreshSchema : ( ) => QuickSQLite . refreshSchema ( dbName ) ,
258
249
execute : ( sql : string , args ?: any [ ] ) => writeLock ( ( context ) => context . execute ( sql , args ) ) ,
0 commit comments