@event-driven-io/dumbo 0.13.0-beta.46 → 0.13.0-beta.47

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/dist/cloudflare.cjs +432 -69
  2. package/dist/cloudflare.cjs.map +1 -1
  3. package/dist/cloudflare.d.cts +2 -2
  4. package/dist/cloudflare.d.ts +2 -2
  5. package/dist/cloudflare.js +432 -69
  6. package/dist/cloudflare.js.map +1 -1
  7. package/dist/{index-B5krjjrh.d.ts → index-4hcCG4SA.d.ts} +66 -30
  8. package/dist/{index-BaLXbc2l.d.ts → index-B7366zWR.d.ts} +1 -1
  9. package/dist/{index-_dj3upBo.d.cts → index-BJ-dm7dG.d.cts} +66 -30
  10. package/dist/{index-kYttgYkC.d.cts → index-BkJ1pipM.d.cts} +1 -1
  11. package/dist/{index-C9B46a1u.d.ts → index-CQokD3za.d.cts} +2 -2
  12. package/dist/{index-BoLWBnxd.d.cts → index-DIJv-L6M.d.ts} +2 -2
  13. package/dist/index.cjs +523 -269
  14. package/dist/index.cjs.map +1 -1
  15. package/dist/index.d.cts +2 -2
  16. package/dist/index.d.ts +2 -2
  17. package/dist/index.js +522 -270
  18. package/dist/index.js.map +1 -1
  19. package/dist/pg.cjs +168 -28
  20. package/dist/pg.cjs.map +1 -1
  21. package/dist/pg.d.cts +2 -2
  22. package/dist/pg.d.ts +2 -2
  23. package/dist/pg.js +168 -28
  24. package/dist/pg.js.map +1 -1
  25. package/dist/postgresql.cjs +4 -0
  26. package/dist/postgresql.cjs.map +1 -1
  27. package/dist/postgresql.d.cts +2 -2
  28. package/dist/postgresql.d.ts +2 -2
  29. package/dist/postgresql.js +4 -0
  30. package/dist/postgresql.js.map +1 -1
  31. package/dist/sqlite.cjs +429 -68
  32. package/dist/sqlite.cjs.map +1 -1
  33. package/dist/sqlite.d.cts +2 -2
  34. package/dist/sqlite.d.ts +2 -2
  35. package/dist/sqlite.js +429 -68
  36. package/dist/sqlite.js.map +1 -1
  37. package/dist/sqlite3.cjs +639 -343
  38. package/dist/sqlite3.cjs.map +1 -1
  39. package/dist/sqlite3.d.cts +10 -10
  40. package/dist/sqlite3.d.ts +10 -10
  41. package/dist/sqlite3.js +639 -343
  42. package/dist/sqlite3.js.map +1 -1
  43. package/package.json +1 -1
package/dist/sqlite.js CHANGED
@@ -172,6 +172,294 @@ var InvalidOperationError = class InvalidOperationError extends DumboError {
172
172
  }
173
173
  };
174
174
 
175
+ //#endregion
176
+ //#region src/core/taskProcessing/abort.ts
177
+ const never = { signal: new AbortController().signal };
178
+ const from = (options) => options?.abort ?? never;
179
+ const getSignal = (abort) => "signal" in abort ? abort.signal : abort;
180
+ const reason = (abort) => {
181
+ const signal = getSignal(abort);
182
+ return signal.reason instanceof Error ? signal.reason : new DumboError(typeof signal.reason === "string" ? signal.reason : "Operation aborted");
183
+ };
184
+ const scope = (parent, onAbort) => {
185
+ const controller = new AbortController();
186
+ return {
187
+ abort: (reason) => controller.abort(reason),
188
+ dispose: onAbortSignal(parent, (reason) => {
189
+ controller.abort(reason);
190
+ onAbort?.(reason);
191
+ }),
192
+ signal: controller.signal
193
+ };
194
+ };
195
+ const execute = (operation, options) => {
196
+ const abort = options?.abort;
197
+ if (!abort) return operation();
198
+ const signal = abort.signal;
199
+ if (signal.aborted) return Promise.reject(reason(abort));
200
+ return new Promise((resolve, reject) => {
201
+ let finished = false;
202
+ const rejectOnAbort = () => {
203
+ if (finished) return;
204
+ finished = true;
205
+ reject(reason(abort));
206
+ };
207
+ signal.addEventListener("abort", rejectOnAbort, { once: true });
208
+ let operationPromise;
209
+ try {
210
+ operationPromise = operation();
211
+ } catch (error) {
212
+ finished = true;
213
+ signal.removeEventListener("abort", rejectOnAbort);
214
+ reject(error);
215
+ return;
216
+ }
217
+ operationPromise.then((result) => {
218
+ if (finished) return;
219
+ finished = true;
220
+ signal.removeEventListener("abort", rejectOnAbort);
221
+ resolve(result);
222
+ }).catch((error) => {
223
+ if (finished) return;
224
+ finished = true;
225
+ signal.removeEventListener("abort", rejectOnAbort);
226
+ reject(error);
227
+ });
228
+ });
229
+ };
230
+ const throwIfAborted = (options) => {
231
+ const abort = options?.abort;
232
+ if (abort?.signal.aborted) throw reason(abort);
233
+ };
234
+ const rejectIfAborted = (options) => {
235
+ const abort = options?.abort;
236
+ return abort?.signal.aborted ? Promise.reject(reason(abort)) : void 0;
237
+ };
238
+ const onAbortSignal = (abort, handle) => {
239
+ if (!abort) return () => {};
240
+ const signal = abort.signal;
241
+ if (signal.aborted) {
242
+ handle(reason(abort));
243
+ return () => {};
244
+ }
245
+ const abortListener = () => handle(reason(abort));
246
+ signal.addEventListener("abort", abortListener, { once: true });
247
+ return () => signal.removeEventListener("abort", abortListener);
248
+ };
249
+ const Abort = {
250
+ execute,
251
+ from,
252
+ never,
253
+ onAbort: onAbortSignal,
254
+ reason,
255
+ rejectIfAborted,
256
+ scope,
257
+ throwIfAborted
258
+ };
259
+
260
+ //#endregion
261
+ //#region src/core/taskProcessing/taskProcessor.ts
262
+ var TaskProcessor = class {
263
+ queue = [];
264
+ isProcessing = false;
265
+ activeTasks = 0;
266
+ activeGroups = /* @__PURE__ */ new Set();
267
+ options;
268
+ stopped = false;
269
+ idleWaiters = [];
270
+ activeTaskAbortCallbacks = /* @__PURE__ */ new Set();
271
+ constructor(options) {
272
+ this.options = options;
273
+ }
274
+ enqueue(task, options) {
275
+ if (options?.abort?.signal.aborted) return Promise.reject(Abort.reason(options.abort.signal));
276
+ if (this.stopped) return Promise.reject(new DumboError("TaskProcessor has been stopped"));
277
+ if (this.queue.length >= this.options.maxQueueSize) return Promise.reject(new TransientDatabaseError("Too many pending connections. Please try again later."));
278
+ return this.schedule(task, options);
279
+ }
280
+ waitForEndOfProcessing() {
281
+ if (this.activeTasks === 0 && this.queue.length === 0) return Promise.resolve();
282
+ return new Promise((resolve) => {
283
+ this.idleWaiters.push(resolve);
284
+ });
285
+ }
286
+ async stop(options) {
287
+ if (this.stopped) return;
288
+ this.stopped = true;
289
+ const stoppedError = new DumboError("TaskProcessor has been stopped");
290
+ for (const item of this.queue.splice(0)) {
291
+ item.abort(stoppedError);
292
+ item.reject(stoppedError);
293
+ }
294
+ this.activeGroups.clear();
295
+ if (options?.force) for (const abort of this.activeTaskAbortCallbacks) abort(stoppedError);
296
+ if (options?.force) return;
297
+ if (options?.closeDeadline === void 0) {
298
+ await this.waitForEndOfProcessing();
299
+ return;
300
+ }
301
+ if (!await waitForProcessingOrDeadline(this.waitForEndOfProcessing(), options.closeDeadline)) for (const abort of this.activeTaskAbortCallbacks) abort(stoppedError);
302
+ }
303
+ schedule(task, options) {
304
+ return new Promise((resolve, reject) => {
305
+ let didQueueTimeout = false;
306
+ let didAbortBeforeStart = false;
307
+ let didStart = false;
308
+ let queueWaitTimer = noopQueueWaitTimer;
309
+ const abortScope = Abort.scope(options?.abort, (reason) => {
310
+ queueWaitTimer.cancel();
311
+ didAbortBeforeStart = !didStart;
312
+ reject(reason);
313
+ });
314
+ queueWaitTimer = createQueueWaitTimer(this.options.maxTaskIdleTime, (reason) => {
315
+ didQueueTimeout = true;
316
+ abortScope.abort(reason);
317
+ abortScope.dispose();
318
+ reject(reason);
319
+ });
320
+ const taskWithContext = () => {
321
+ return new Promise((resolveTask) => {
322
+ if (didQueueTimeout || didAbortBeforeStart) {
323
+ resolveTask();
324
+ return;
325
+ }
326
+ let taskPromise;
327
+ try {
328
+ taskPromise = task({
329
+ ack: resolveTask,
330
+ abort: abortScope
331
+ });
332
+ } catch (err) {
333
+ abortScope.dispose();
334
+ resolveTask();
335
+ reject(err);
336
+ return;
337
+ }
338
+ taskPromise.then((result) => {
339
+ abortScope.dispose();
340
+ resolve(result);
341
+ }).catch((err) => {
342
+ abortScope.dispose();
343
+ resolveTask();
344
+ reject(err);
345
+ });
346
+ });
347
+ };
348
+ this.queue.push({
349
+ task: taskWithContext,
350
+ options,
351
+ reject: (reason) => {
352
+ queueWaitTimer.cancel();
353
+ abortScope.dispose();
354
+ reject(reason);
355
+ },
356
+ markStarted: () => {
357
+ didStart = true;
358
+ queueWaitTimer.cancel();
359
+ },
360
+ abort: (reason) => {
361
+ abortScope.dispose();
362
+ abortScope.abort(reason);
363
+ }
364
+ });
365
+ if (!this.isProcessing) this.ensureProcessing();
366
+ });
367
+ }
368
+ ensureProcessing() {
369
+ if (this.isProcessing) return;
370
+ this.isProcessing = true;
371
+ this.processQueue();
372
+ }
373
+ processQueue() {
374
+ try {
375
+ while (this.activeTasks < this.options.maxActiveTasks && this.queue.length > 0) {
376
+ const item = this.takeFirstAvailableItem();
377
+ if (item === null) return;
378
+ const groupId = item.options?.taskGroupId;
379
+ if (groupId) this.activeGroups.add(groupId);
380
+ this.activeTasks++;
381
+ this.executeItem(item);
382
+ }
383
+ } catch (error) {
384
+ console.error(error);
385
+ throw error;
386
+ } finally {
387
+ this.isProcessing = false;
388
+ if (this.hasItemsToProcess() && this.activeTasks < this.options.maxActiveTasks) this.ensureProcessing();
389
+ }
390
+ }
391
+ async executeItem({ task, options, markStarted, abort }) {
392
+ markStarted();
393
+ this.activeTaskAbortCallbacks.add(abort);
394
+ try {
395
+ await task();
396
+ } finally {
397
+ this.activeTaskAbortCallbacks.delete(abort);
398
+ this.activeTasks--;
399
+ if (options && options.taskGroupId) this.activeGroups.delete(options.taskGroupId);
400
+ this.resolveIdleWaiters();
401
+ this.ensureProcessing();
402
+ }
403
+ }
404
+ takeFirstAvailableItem = () => {
405
+ const taskIndex = this.queue.findIndex((item) => !item.options?.taskGroupId || !this.activeGroups.has(item.options.taskGroupId));
406
+ if (taskIndex === -1) return null;
407
+ const [item] = this.queue.splice(taskIndex, 1);
408
+ return item ?? null;
409
+ };
410
+ hasItemsToProcess = () => this.queue.findIndex((item) => !item.options?.taskGroupId || !this.activeGroups.has(item.options.taskGroupId)) !== -1;
411
+ resolveIdleWaiters = () => {
412
+ if (this.activeTasks > 0 || this.queue.length > 0) return;
413
+ const waiters = this.idleWaiters.splice(0);
414
+ for (const resolve of waiters) resolve();
415
+ };
416
+ };
417
+ const noopQueueWaitTimer = { cancel: () => {} };
418
+ const createQueueWaitTimer = (timeoutMs, reject) => {
419
+ if (timeoutMs === void 0) return noopQueueWaitTimer;
420
+ let timeoutId = setTimeout(() => {
421
+ reject(/* @__PURE__ */ new Error("Task was not started within the maximum waiting time"));
422
+ }, timeoutMs);
423
+ timeoutId.unref();
424
+ return { cancel: () => {
425
+ if (!timeoutId) return;
426
+ clearTimeout(timeoutId);
427
+ timeoutId = null;
428
+ } };
429
+ };
430
+ const waitForProcessingOrDeadline = async (processing, closeDeadline) => {
431
+ let timeoutId = null;
432
+ try {
433
+ return await Promise.race([processing.then(() => true), new Promise((resolve) => {
434
+ timeoutId = setTimeout(() => resolve(false), closeDeadline);
435
+ timeoutId.unref();
436
+ })]);
437
+ } finally {
438
+ if (timeoutId) clearTimeout(timeoutId);
439
+ }
440
+ };
441
+
442
+ //#endregion
443
+ //#region src/core/taskProcessing/executionGuards.ts
444
+ const guardConcurrentAccess = (options) => {
445
+ const taskProcessor = new TaskProcessor({
446
+ maxActiveTasks: options?.maxActiveTasks ?? Number.MAX_SAFE_INTEGER,
447
+ maxQueueSize: options?.maxQueueSize ?? Number.MAX_SAFE_INTEGER,
448
+ ...options?.maxTaskIdleTime !== void 0 ? { maxTaskIdleTime: options.maxTaskIdleTime } : {}
449
+ });
450
+ return {
451
+ execute: (operation, options) => taskProcessor.enqueue(async (context) => {
452
+ try {
453
+ return await operation({ abort: context.abort });
454
+ } finally {
455
+ context.ack();
456
+ }
457
+ }, options),
458
+ waitForIdle: () => taskProcessor.waitForEndOfProcessing(),
459
+ stop: (options) => taskProcessor.stop(options)
460
+ };
461
+ };
462
+
175
463
  //#endregion
176
464
  //#region src/core/execute/execute.ts
177
465
  const mapSQLQueryResult = (result, mapping) => {
@@ -181,26 +469,63 @@ const mapSQLQueryResult = (result, mapping) => {
181
469
  return mappedResult;
182
470
  };
183
471
  const sqlExecutor = (sqlExecutor, options) => ({
184
- query: (sql, queryOptions) => executeInNewDbClient((client) => sqlExecutor.query(client, sql, queryOptions), options),
185
- batchQuery: (sqls, queryOptions) => executeInNewDbClient((client) => sqlExecutor.batchQuery(client, sqls, queryOptions), options),
186
- command: (sql, commandOptions) => executeInNewDbClient((client) => sqlExecutor.command(client, sql, commandOptions), options),
187
- batchCommand: (sqls, commandOptions) => executeInNewDbClient((client) => sqlExecutor.batchCommand(client, sqls, commandOptions), options)
472
+ query: (sql, queryOptions) => executeInNewDbClient((client) => sqlExecutor.query(client, sql, queryOptions), {
473
+ ...options,
474
+ ...queryOptions
475
+ }),
476
+ batchQuery: (sqls, queryOptions) => executeInNewDbClient((client) => sqlExecutor.batchQuery(client, sqls, queryOptions), {
477
+ ...options,
478
+ ...queryOptions
479
+ }),
480
+ command: (sql, commandOptions) => executeInNewDbClient((client) => sqlExecutor.command(client, sql, commandOptions), {
481
+ ...options,
482
+ ...commandOptions
483
+ }),
484
+ batchCommand: (sqls, commandOptions) => executeInNewDbClient((client) => sqlExecutor.batchCommand(client, sqls, commandOptions), {
485
+ ...options,
486
+ ...commandOptions
487
+ })
188
488
  });
189
489
  const sqlExecutorInNewConnection = (options) => ({
190
- query: (sql, queryOptions) => executeInNewConnection((connection) => connection.execute.query(sql, queryOptions), options),
191
- batchQuery: (sqls, queryOptions) => executeInNewConnection((connection) => connection.execute.batchQuery(sqls, queryOptions), options),
192
- command: (sql, commandOptions) => executeInNewConnection((connection) => connection.execute.command(sql, commandOptions), options),
193
- batchCommand: (sqls, commandOptions) => executeInNewConnection((connection) => connection.execute.batchCommand(sqls, commandOptions), options)
490
+ query: (sql, queryOptions) => executeInNewConnection((connection) => connection.execute.query(sql, queryOptions), {
491
+ ...options,
492
+ ...queryOptions
493
+ }),
494
+ batchQuery: (sqls, queryOptions) => executeInNewConnection((connection) => connection.execute.batchQuery(sqls, queryOptions), {
495
+ ...options,
496
+ ...queryOptions
497
+ }),
498
+ command: (sql, commandOptions) => executeInNewConnection((connection) => connection.execute.command(sql, commandOptions), {
499
+ ...options,
500
+ ...commandOptions
501
+ }),
502
+ batchCommand: (sqls, commandOptions) => executeInNewConnection((connection) => connection.execute.batchCommand(sqls, commandOptions), {
503
+ ...options,
504
+ ...commandOptions
505
+ })
194
506
  });
195
507
  const sqlExecutorInAmbientConnection = (options) => ({
196
- query: (sql, queryOptions) => executeInAmbientConnection((connection) => connection.execute.query(sql, queryOptions), options),
197
- batchQuery: (sqls, queryOptions) => executeInAmbientConnection((connection) => connection.execute.batchQuery(sqls, queryOptions), options),
198
- command: (sql, commandOptions) => executeInAmbientConnection((connection) => connection.execute.command(sql, commandOptions), options),
199
- batchCommand: (sqls, commandOptions) => executeInAmbientConnection((connection) => connection.execute.batchCommand(sqls, commandOptions), options)
508
+ query: (sql, queryOptions) => executeInAmbientConnection((connection) => connection.execute.query(sql, queryOptions), {
509
+ ...options,
510
+ ...queryOptions
511
+ }),
512
+ batchQuery: (sqls, queryOptions) => executeInAmbientConnection((connection) => connection.execute.batchQuery(sqls, queryOptions), {
513
+ ...options,
514
+ ...queryOptions
515
+ }),
516
+ command: (sql, commandOptions) => executeInAmbientConnection((connection) => connection.execute.command(sql, commandOptions), {
517
+ ...options,
518
+ ...commandOptions
519
+ }),
520
+ batchCommand: (sqls, commandOptions) => executeInAmbientConnection((connection) => connection.execute.batchCommand(sqls, commandOptions), {
521
+ ...options,
522
+ ...commandOptions
523
+ })
200
524
  });
201
525
  const executeInNewDbClient = async (handle, options) => {
526
+ Abort.throwIfAborted(options);
202
527
  const { connect, close } = options;
203
- const client = await connect();
528
+ const client = await connect({ abort: Abort.from(options) });
204
529
  try {
205
530
  return await handle(client);
206
531
  } catch (error) {
@@ -209,7 +534,8 @@ const executeInNewDbClient = async (handle, options) => {
209
534
  }
210
535
  };
211
536
  const executeInNewConnection = async (handle, options) => {
212
- const connection = await options.connection();
537
+ Abort.throwIfAborted(options);
538
+ const connection = await options.connection({ abort: Abort.from(options) });
213
539
  try {
214
540
  return await handle(connection);
215
541
  } finally {
@@ -217,10 +543,8 @@ const executeInNewConnection = async (handle, options) => {
217
543
  }
218
544
  };
219
545
  const executeInAmbientConnection = async (handle, options) => {
220
- const connection = await options.connection();
221
- try {
222
- return await handle(connection);
223
- } finally {}
546
+ Abort.throwIfAborted(options);
547
+ return handle(await options.connection({ abort: Abort.from(options) }));
224
548
  };
225
549
 
226
550
  //#endregion
@@ -288,10 +612,10 @@ const toTransactionResult = (transactionResult) => transactionResult !== void 0
288
612
  success: true,
289
613
  result: transactionResult
290
614
  };
291
- const executeInTransaction = async (transaction, handle) => {
615
+ const executeInTransaction = async (transaction, handle, context = { abort: Abort.never }) => {
292
616
  await transaction.begin();
293
617
  try {
294
- const { success, result } = toTransactionResult(await handle(transaction));
618
+ const { success, result } = toTransactionResult(await handle(transaction, context));
295
619
  if (success) await transaction.commit();
296
620
  else await transaction.rollback();
297
621
  return result;
@@ -300,18 +624,32 @@ const executeInTransaction = async (transaction, handle) => {
300
624
  throw e;
301
625
  }
302
626
  };
627
+ const executeInNestedTransaction = async (transaction, handle, options, context) => {
628
+ Abort.throwIfAborted(options);
629
+ if (!(options?.allowNestedTransactions ?? transaction._transactionOptions.allowNestedTransactions ?? false)) throw new InvalidOperationError("Cannot start a nested transaction: allowNestedTransactions is false. Set transactionOptions: { allowNestedTransactions: true } on your pool or connection.");
630
+ return executeInTransaction(transaction, handle, context);
631
+ };
303
632
  const transactionFactoryWithDbClient = (connect, initTransaction) => {
304
633
  let currentTransaction = void 0;
305
- const getOrInitCurrentTransaction = (options) => currentTransaction ?? (currentTransaction = initTransaction(connect(), {
306
- close: () => {
307
- currentTransaction = void 0;
308
- return Promise.resolve();
309
- },
310
- ...options ?? {}
311
- }));
634
+ const getOrInitCurrentTransaction = (options) => {
635
+ Abort.throwIfAborted(options);
636
+ if (currentTransaction) return currentTransaction;
637
+ currentTransaction = initTransaction(connect({ abort: Abort.from(options) }), {
638
+ close: () => {
639
+ currentTransaction = void 0;
640
+ return Promise.resolve();
641
+ },
642
+ ...options ?? {}
643
+ });
644
+ return currentTransaction;
645
+ };
312
646
  return {
313
647
  transaction: getOrInitCurrentTransaction,
314
- withTransaction: (handle, options) => executeInTransaction(getOrInitCurrentTransaction(options), handle)
648
+ withTransaction: (handle, options) => {
649
+ const abortRejection = Abort.rejectIfAborted(options);
650
+ if (abortRejection) return abortRejection;
651
+ return executeInTransaction(getOrInitCurrentTransaction(options), handle, { abort: Abort.from(options) });
652
+ }
315
653
  };
316
654
  };
317
655
  const wrapInConnectionClosure = async (connection, handle) => {
@@ -323,7 +661,8 @@ const wrapInConnectionClosure = async (connection, handle) => {
323
661
  };
324
662
  const transactionFactoryWithNewConnection = (connect) => ({
325
663
  transaction: (options) => {
326
- const connection = connect();
664
+ Abort.throwIfAborted(options);
665
+ const connection = connect({ abort: Abort.from(options) });
327
666
  const transaction = connection.transaction(options);
328
667
  return {
329
668
  ...transaction,
@@ -332,7 +671,9 @@ const transactionFactoryWithNewConnection = (connect) => ({
332
671
  };
333
672
  },
334
673
  withTransaction: (handle, options) => {
335
- const connection = connect();
674
+ const abortRejection = Abort.rejectIfAborted(options);
675
+ if (abortRejection) return abortRejection;
676
+ const connection = connect({ abort: Abort.from(options) });
336
677
  const withTx = connection.withTransaction;
337
678
  return wrapInConnectionClosure(connection, () => withTx(handle, options));
338
679
  }
@@ -341,19 +682,21 @@ const transactionFactoryWithAsyncAmbientConnection = (driverType, connect, close
341
682
  close ??= () => Promise.resolve();
342
683
  return {
343
684
  transaction: (options) => {
685
+ Abort.throwIfAborted(options);
344
686
  let conn = null;
345
687
  let innerTx = null;
346
688
  let connectingPromise = null;
347
689
  const ensureConnection = async () => {
348
690
  if (conn) return innerTx;
349
691
  if (!connectingPromise) connectingPromise = (async () => {
350
- conn = await connect();
692
+ Abort.throwIfAborted(options);
693
+ conn = await connect({ abort: Abort.from(options) });
351
694
  innerTx = conn.transaction(options);
352
695
  })();
353
696
  await connectingPromise;
354
697
  return innerTx;
355
698
  };
356
- return {
699
+ const tx = {
357
700
  driverType,
358
701
  get connection() {
359
702
  if (!conn) throw new Error("Transaction not started - call begin() first");
@@ -395,11 +738,14 @@ const transactionFactoryWithAsyncAmbientConnection = (driverType, connect, close
395
738
  if (conn) await close(conn);
396
739
  }
397
740
  },
398
- _transactionOptions: void 0
741
+ withTransaction: (handle, options) => executeInNestedTransaction(tx, handle, options, { abort: Abort.from(options) }),
742
+ _transactionOptions: options ?? {}
399
743
  };
744
+ return tx;
400
745
  },
401
746
  withTransaction: async (handle, options) => {
402
- const conn = await connect();
747
+ Abort.throwIfAborted(options);
748
+ const conn = await connect({ abort: Abort.from(options) });
403
749
  try {
404
750
  const withTx = conn.withTransaction;
405
751
  return await withTx(handle, options);
@@ -416,7 +762,10 @@ const createAmbientConnection = (options) => {
416
762
  const { driverType, client, executor, initTransaction, serializer } = options;
417
763
  const clientPromise = Promise.resolve(client);
418
764
  const closePromise = Promise.resolve();
419
- const open = () => clientPromise;
765
+ const open = (context) => {
766
+ Abort.throwIfAborted(context);
767
+ return clientPromise;
768
+ };
420
769
  const close = () => closePromise;
421
770
  const typedConnection = {
422
771
  driverType,
@@ -432,9 +781,10 @@ const createConnection = (options) => {
432
781
  const { driverType, connect, close, initTransaction, executor, serializer } = options;
433
782
  let client = null;
434
783
  let connectPromise = null;
435
- const getClient = async () => {
784
+ const getClient = async (context) => {
785
+ Abort.throwIfAborted(context);
436
786
  if (client) return client;
437
- if (!connectPromise) connectPromise = connect().then((c) => {
787
+ if (!connectPromise) connectPromise = connect(context ?? { abort: Abort.never }).then((c) => {
438
788
  client = c;
439
789
  return c;
440
790
  });
@@ -464,7 +814,10 @@ const createAmbientConnectionPool = (options) => {
464
814
  getConnection: () => connection,
465
815
  execute: connection.execute,
466
816
  transaction: (options) => connection.transaction(options),
467
- withConnection: (handle, _options) => handle(connection),
817
+ withConnection: (handle, options) => {
818
+ Abort.throwIfAborted(options);
819
+ return handle(connection, { abort: Abort.from(options) });
820
+ },
468
821
  withTransaction: (handle, options) => {
469
822
  const withTx = connection.withTransaction;
470
823
  return withTx(handle, options);
@@ -475,48 +828,45 @@ const createSingletonConnectionPool = (options) => {
475
828
  const { driverType, getConnection } = options;
476
829
  let connectionPromise = null;
477
830
  let closed = false;
478
- const activeOperations = /* @__PURE__ */ new Set();
831
+ const operationGuard = guardConcurrentAccess();
479
832
  const closedError = () => /* @__PURE__ */ new Error("Singleton connection pool has been closed");
480
- const run = async (operation) => {
833
+ const executeIfOpen = async (operation, operationOptions) => {
481
834
  if (closed) throw closedError();
482
- const activeOperation = operation();
483
- activeOperations.add(activeOperation);
484
- try {
485
- return await activeOperation;
486
- } finally {
487
- activeOperations.delete(activeOperation);
488
- }
835
+ return operationGuard.execute(operation, operationOptions);
489
836
  };
490
- const getExistingOrNewConnection = () => {
491
- if (!connectionPromise) connectionPromise ??= Promise.resolve(getConnection());
837
+ const getExistingOrNewConnection = (context) => {
838
+ if (!connectionPromise) connectionPromise ??= Promise.resolve(getConnection(context));
492
839
  return connectionPromise;
493
840
  };
494
841
  const innerTransactionFactory = transactionFactoryWithAsyncAmbientConnection(options.driverType, getExistingOrNewConnection, options.closeConnection);
495
842
  return {
496
843
  driverType,
497
- connection: () => run(() => getExistingOrNewConnection().then((conn) => wrapPooledConnection(conn, () => Promise.resolve()))),
844
+ connection: (connectionOptions) => executeIfOpen((context) => getExistingOrNewConnection(context).then((conn) => wrapPooledConnection(conn, () => Promise.resolve())), connectionOptions),
498
845
  execute: (() => {
499
846
  const ambientExecutor = sqlExecutorInAmbientConnection({
500
847
  driverType,
501
848
  connection: getExistingOrNewConnection
502
849
  });
503
850
  return {
504
- query: (sql, opts) => run(() => ambientExecutor.query(sql, opts)),
505
- batchQuery: (sqls, opts) => run(() => ambientExecutor.batchQuery(sqls, opts)),
506
- command: (sql, opts) => run(() => ambientExecutor.command(sql, opts)),
507
- batchCommand: (sqls, opts) => run(() => ambientExecutor.batchCommand(sqls, opts))
851
+ query: (sql, opts) => executeIfOpen(() => ambientExecutor.query(sql, opts), opts),
852
+ batchQuery: (sqls, opts) => executeIfOpen(() => ambientExecutor.batchQuery(sqls, opts), opts),
853
+ command: (sql, opts) => executeIfOpen(() => ambientExecutor.command(sql, opts), opts),
854
+ batchCommand: (sqls, opts) => executeIfOpen(() => ambientExecutor.batchCommand(sqls, opts), opts)
508
855
  };
509
856
  })(),
510
- withConnection: (handle, _options) => run(() => executeInAmbientConnection(handle, { connection: getExistingOrNewConnection })),
857
+ withConnection: (handle, options) => executeIfOpen((context) => executeInAmbientConnection((connection) => handle(connection, context), {
858
+ connection: getExistingOrNewConnection,
859
+ ...options
860
+ }), options),
511
861
  transaction: (transactionOptions) => {
512
862
  if (closed) throw closedError();
513
863
  return innerTransactionFactory.transaction(transactionOptions);
514
864
  },
515
- withTransaction: (handle, transactionOptions) => run(() => innerTransactionFactory.withTransaction(handle, transactionOptions)),
865
+ withTransaction: (handle, transactionOptions) => executeIfOpen((context) => innerTransactionFactory.withTransaction((tx) => handle(tx, context), transactionOptions), transactionOptions),
516
866
  close: async (closeOptions) => {
517
867
  if (closed) return;
518
868
  closed = true;
519
- if (!closeOptions?.force) await Promise.allSettled([...activeOperations]);
869
+ await operationGuard.stop(closeOptions);
520
870
  if (!connectionPromise) return;
521
871
  const connection = await connectionPromise;
522
872
  connectionPromise = null;
@@ -528,16 +878,22 @@ const createAlwaysNewConnectionPool = (options) => {
528
878
  const { driverType, getConnection, connectionOptions } = options;
529
879
  return createConnectionPool({
530
880
  driverType,
531
- getConnection: () => connectionOptions ? getConnection(connectionOptions) : getConnection()
881
+ getConnection: (context) => connectionOptions ? getConnection(connectionOptions, context) : getConnection(context)
532
882
  });
533
883
  };
534
884
  const createConnectionPool = (pool) => {
535
885
  const { driverType, getConnection } = pool;
536
- const connection = "connection" in pool ? pool.connection : () => Promise.resolve(getConnection());
886
+ const connection = "connection" in pool ? pool.connection : (options) => {
887
+ Abort.throwIfAborted(options);
888
+ return Promise.resolve(getConnection({ abort: Abort.from(options) }));
889
+ };
537
890
  return {
538
891
  driverType,
539
892
  connection,
540
- withConnection: "withConnection" in pool ? pool.withConnection : (handle, _options) => executeInNewConnection(handle, { connection }),
893
+ withConnection: "withConnection" in pool ? pool.withConnection : (handle, options) => executeInNewConnection((connection) => handle(connection, { abort: Abort.from(options) }), {
894
+ connection,
895
+ ...options
896
+ }),
541
897
  close: "close" in pool ? pool.close : () => Promise.resolve(),
542
898
  execute: "execute" in pool ? pool.execute : sqlExecutorInNewConnection({
543
899
  driverType,
@@ -1872,9 +2228,9 @@ const sqliteSQLExecutor = (driverType, serializer, formatter, errorMapper) => ({
1872
2228
 
1873
2229
  //#endregion
1874
2230
  //#region src/storage/sqlite/core/transactions/index.ts
1875
- const sqliteTransaction = (driverType, connection, allowNestedTransactions, serializer, defaultTransactionMode) => (getClient, options) => {
1876
- allowNestedTransactions = options?.allowNestedTransactions ?? allowNestedTransactions;
1877
- const useSavepoints = options?.useSavepoints ?? false;
2231
+ const sqliteTransaction = (driverType, connection, defaultOptions, serializer, defaultTransactionMode) => (getClient, options) => {
2232
+ const defaultTransactionOptions = typeof defaultOptions === "boolean" ? { allowNestedTransactions: defaultOptions } : defaultOptions;
2233
+ const allowNestedTransactions = options?.allowNestedTransactions ?? defaultTransactionOptions.allowNestedTransactions ?? false;
1878
2234
  const tx = databaseTransaction({
1879
2235
  begin: async () => {
1880
2236
  const client = await getClient;
@@ -1902,23 +2258,28 @@ const sqliteTransaction = (driverType, connection, allowNestedTransactions, seri
1902
2258
  },
1903
2259
  releaseSavepoint: async (level) => {
1904
2260
  await (await getClient).command(SQL`RELEASE transaction${SQL.plain(level.toString())}`);
2261
+ },
2262
+ rollbackToSavepoint: async (level) => {
2263
+ await (await getClient).command(SQL`ROLLBACK TO transaction${SQL.plain(level.toString())}`);
1905
2264
  }
1906
2265
  }, {
1907
2266
  allowNestedTransactions,
1908
- useSavepoints
2267
+ useSavepoints: options?.useSavepoints ?? defaultTransactionOptions.useSavepoints ?? false
1909
2268
  });
1910
- return {
2269
+ const transaction = {
1911
2270
  connection: connection(),
1912
2271
  driverType,
1913
2272
  begin: tx.begin,
1914
2273
  commit: tx.commit,
1915
2274
  rollback: tx.rollback,
1916
2275
  execute: sqlExecutor(sqliteSQLExecutor(driverType, serializer), { connect: () => getClient }),
2276
+ withTransaction: (handle, options) => executeInNestedTransaction(transaction, handle, options),
1917
2277
  _transactionOptions: {
1918
2278
  ...options,
1919
2279
  allowNestedTransactions
1920
2280
  }
1921
2281
  };
2282
+ return transaction;
1922
2283
  };
1923
2284
 
1924
2285
  //#endregion
@@ -1963,7 +2324,7 @@ const sqliteAmbientClientConnection = (options) => {
1963
2324
  return createAmbientConnection({
1964
2325
  driverType,
1965
2326
  client,
1966
- initTransaction: initTransaction ?? ((connection) => sqliteTransaction(driverType, connection, allowNestedTransactions ?? false, serializer, defaultTransactionMode)),
2327
+ initTransaction: initTransaction ?? ((connection) => sqliteTransaction(driverType, connection, { allowNestedTransactions: allowNestedTransactions ?? false }, serializer, defaultTransactionMode)),
1967
2328
  executor: ({ serializer }) => sqliteSQLExecutor(driverType, serializer, void 0, errorMapper),
1968
2329
  serializer
1969
2330
  });
@@ -1988,7 +2349,7 @@ const sqliteClientConnection = (options) => {
1988
2349
  if (client && "close" in client && typeof client.close === "function") await client.close();
1989
2350
  else if (client && "release" in client && typeof client.release === "function") client.release();
1990
2351
  },
1991
- initTransaction: (connection) => sqliteTransaction(options.driverType, connection, connectionOptions.transactionOptions?.allowNestedTransactions ?? false, serializer, connectionOptions.defaultTransactionMode),
2352
+ initTransaction: (connection) => sqliteTransaction(options.driverType, connection, connectionOptions.transactionOptions ?? {}, serializer, connectionOptions.defaultTransactionMode),
1992
2353
  executor: ({ serializer }) => sqliteSQLExecutor(options.driverType, serializer),
1993
2354
  serializer
1994
2355
  });
@@ -2010,7 +2371,7 @@ const sqlitePoolClientConnection = (options) => {
2010
2371
  driverType: options.driverType,
2011
2372
  connect,
2012
2373
  close: () => client !== null ? Promise.resolve(client.release()) : Promise.resolve(),
2013
- initTransaction: (connection) => sqliteTransaction(options.driverType, connection, connectionOptions.transactionOptions?.allowNestedTransactions ?? false, serializer, connectionOptions.defaultTransactionMode),
2374
+ initTransaction: (connection) => sqliteTransaction(options.driverType, connection, connectionOptions.transactionOptions ?? {}, serializer, connectionOptions.defaultTransactionMode),
2014
2375
  executor: ({ serializer }) => sqliteSQLExecutor(options.driverType, serializer),
2015
2376
  serializer
2016
2377
  });