@event-driven-io/dumbo 0.13.0-beta.45 → 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
@@ -201,6 +201,294 @@ var InvalidOperationError = class InvalidOperationError extends DumboError {
201
201
  }
202
202
  };
203
203
 
204
+ //#endregion
205
+ //#region src/core/taskProcessing/abort.ts
206
+ const never = { signal: new AbortController().signal };
207
+ const from = (options) => options?.abort ?? never;
208
+ const getSignal = (abort) => "signal" in abort ? abort.signal : abort;
209
+ const reason = (abort) => {
210
+ const signal = getSignal(abort);
211
+ return signal.reason instanceof Error ? signal.reason : new DumboError(typeof signal.reason === "string" ? signal.reason : "Operation aborted");
212
+ };
213
+ const scope = (parent, onAbort) => {
214
+ const controller = new AbortController();
215
+ return {
216
+ abort: (reason) => controller.abort(reason),
217
+ dispose: onAbortSignal(parent, (reason) => {
218
+ controller.abort(reason);
219
+ onAbort?.(reason);
220
+ }),
221
+ signal: controller.signal
222
+ };
223
+ };
224
+ const execute = (operation, options) => {
225
+ const abort = options?.abort;
226
+ if (!abort) return operation();
227
+ const signal = abort.signal;
228
+ if (signal.aborted) return Promise.reject(reason(abort));
229
+ return new Promise((resolve, reject) => {
230
+ let finished = false;
231
+ const rejectOnAbort = () => {
232
+ if (finished) return;
233
+ finished = true;
234
+ reject(reason(abort));
235
+ };
236
+ signal.addEventListener("abort", rejectOnAbort, { once: true });
237
+ let operationPromise;
238
+ try {
239
+ operationPromise = operation();
240
+ } catch (error) {
241
+ finished = true;
242
+ signal.removeEventListener("abort", rejectOnAbort);
243
+ reject(error);
244
+ return;
245
+ }
246
+ operationPromise.then((result) => {
247
+ if (finished) return;
248
+ finished = true;
249
+ signal.removeEventListener("abort", rejectOnAbort);
250
+ resolve(result);
251
+ }).catch((error) => {
252
+ if (finished) return;
253
+ finished = true;
254
+ signal.removeEventListener("abort", rejectOnAbort);
255
+ reject(error);
256
+ });
257
+ });
258
+ };
259
+ const throwIfAborted = (options) => {
260
+ const abort = options?.abort;
261
+ if (abort?.signal.aborted) throw reason(abort);
262
+ };
263
+ const rejectIfAborted = (options) => {
264
+ const abort = options?.abort;
265
+ return abort?.signal.aborted ? Promise.reject(reason(abort)) : void 0;
266
+ };
267
+ const onAbortSignal = (abort, handle) => {
268
+ if (!abort) return () => {};
269
+ const signal = abort.signal;
270
+ if (signal.aborted) {
271
+ handle(reason(abort));
272
+ return () => {};
273
+ }
274
+ const abortListener = () => handle(reason(abort));
275
+ signal.addEventListener("abort", abortListener, { once: true });
276
+ return () => signal.removeEventListener("abort", abortListener);
277
+ };
278
+ const Abort = {
279
+ execute,
280
+ from,
281
+ never,
282
+ onAbort: onAbortSignal,
283
+ reason,
284
+ rejectIfAborted,
285
+ scope,
286
+ throwIfAborted
287
+ };
288
+
289
+ //#endregion
290
+ //#region src/core/taskProcessing/taskProcessor.ts
291
+ var TaskProcessor = class {
292
+ queue = [];
293
+ isProcessing = false;
294
+ activeTasks = 0;
295
+ activeGroups = /* @__PURE__ */ new Set();
296
+ options;
297
+ stopped = false;
298
+ idleWaiters = [];
299
+ activeTaskAbortCallbacks = /* @__PURE__ */ new Set();
300
+ constructor(options) {
301
+ this.options = options;
302
+ }
303
+ enqueue(task, options) {
304
+ if (options?.abort?.signal.aborted) return Promise.reject(Abort.reason(options.abort.signal));
305
+ if (this.stopped) return Promise.reject(new DumboError("TaskProcessor has been stopped"));
306
+ if (this.queue.length >= this.options.maxQueueSize) return Promise.reject(new TransientDatabaseError("Too many pending connections. Please try again later."));
307
+ return this.schedule(task, options);
308
+ }
309
+ waitForEndOfProcessing() {
310
+ if (this.activeTasks === 0 && this.queue.length === 0) return Promise.resolve();
311
+ return new Promise((resolve) => {
312
+ this.idleWaiters.push(resolve);
313
+ });
314
+ }
315
+ async stop(options) {
316
+ if (this.stopped) return;
317
+ this.stopped = true;
318
+ const stoppedError = new DumboError("TaskProcessor has been stopped");
319
+ for (const item of this.queue.splice(0)) {
320
+ item.abort(stoppedError);
321
+ item.reject(stoppedError);
322
+ }
323
+ this.activeGroups.clear();
324
+ if (options?.force) for (const abort of this.activeTaskAbortCallbacks) abort(stoppedError);
325
+ if (options?.force) return;
326
+ if (options?.closeDeadline === void 0) {
327
+ await this.waitForEndOfProcessing();
328
+ return;
329
+ }
330
+ if (!await waitForProcessingOrDeadline(this.waitForEndOfProcessing(), options.closeDeadline)) for (const abort of this.activeTaskAbortCallbacks) abort(stoppedError);
331
+ }
332
+ schedule(task, options) {
333
+ return new Promise((resolve, reject) => {
334
+ let didQueueTimeout = false;
335
+ let didAbortBeforeStart = false;
336
+ let didStart = false;
337
+ let queueWaitTimer = noopQueueWaitTimer;
338
+ const abortScope = Abort.scope(options?.abort, (reason) => {
339
+ queueWaitTimer.cancel();
340
+ didAbortBeforeStart = !didStart;
341
+ reject(reason);
342
+ });
343
+ queueWaitTimer = createQueueWaitTimer(this.options.maxTaskIdleTime, (reason) => {
344
+ didQueueTimeout = true;
345
+ abortScope.abort(reason);
346
+ abortScope.dispose();
347
+ reject(reason);
348
+ });
349
+ const taskWithContext = () => {
350
+ return new Promise((resolveTask) => {
351
+ if (didQueueTimeout || didAbortBeforeStart) {
352
+ resolveTask();
353
+ return;
354
+ }
355
+ let taskPromise;
356
+ try {
357
+ taskPromise = task({
358
+ ack: resolveTask,
359
+ abort: abortScope
360
+ });
361
+ } catch (err) {
362
+ abortScope.dispose();
363
+ resolveTask();
364
+ reject(err);
365
+ return;
366
+ }
367
+ taskPromise.then((result) => {
368
+ abortScope.dispose();
369
+ resolve(result);
370
+ }).catch((err) => {
371
+ abortScope.dispose();
372
+ resolveTask();
373
+ reject(err);
374
+ });
375
+ });
376
+ };
377
+ this.queue.push({
378
+ task: taskWithContext,
379
+ options,
380
+ reject: (reason) => {
381
+ queueWaitTimer.cancel();
382
+ abortScope.dispose();
383
+ reject(reason);
384
+ },
385
+ markStarted: () => {
386
+ didStart = true;
387
+ queueWaitTimer.cancel();
388
+ },
389
+ abort: (reason) => {
390
+ abortScope.dispose();
391
+ abortScope.abort(reason);
392
+ }
393
+ });
394
+ if (!this.isProcessing) this.ensureProcessing();
395
+ });
396
+ }
397
+ ensureProcessing() {
398
+ if (this.isProcessing) return;
399
+ this.isProcessing = true;
400
+ this.processQueue();
401
+ }
402
+ processQueue() {
403
+ try {
404
+ while (this.activeTasks < this.options.maxActiveTasks && this.queue.length > 0) {
405
+ const item = this.takeFirstAvailableItem();
406
+ if (item === null) return;
407
+ const groupId = item.options?.taskGroupId;
408
+ if (groupId) this.activeGroups.add(groupId);
409
+ this.activeTasks++;
410
+ this.executeItem(item);
411
+ }
412
+ } catch (error) {
413
+ console.error(error);
414
+ throw error;
415
+ } finally {
416
+ this.isProcessing = false;
417
+ if (this.hasItemsToProcess() && this.activeTasks < this.options.maxActiveTasks) this.ensureProcessing();
418
+ }
419
+ }
420
+ async executeItem({ task, options, markStarted, abort }) {
421
+ markStarted();
422
+ this.activeTaskAbortCallbacks.add(abort);
423
+ try {
424
+ await task();
425
+ } finally {
426
+ this.activeTaskAbortCallbacks.delete(abort);
427
+ this.activeTasks--;
428
+ if (options && options.taskGroupId) this.activeGroups.delete(options.taskGroupId);
429
+ this.resolveIdleWaiters();
430
+ this.ensureProcessing();
431
+ }
432
+ }
433
+ takeFirstAvailableItem = () => {
434
+ const taskIndex = this.queue.findIndex((item) => !item.options?.taskGroupId || !this.activeGroups.has(item.options.taskGroupId));
435
+ if (taskIndex === -1) return null;
436
+ const [item] = this.queue.splice(taskIndex, 1);
437
+ return item ?? null;
438
+ };
439
+ hasItemsToProcess = () => this.queue.findIndex((item) => !item.options?.taskGroupId || !this.activeGroups.has(item.options.taskGroupId)) !== -1;
440
+ resolveIdleWaiters = () => {
441
+ if (this.activeTasks > 0 || this.queue.length > 0) return;
442
+ const waiters = this.idleWaiters.splice(0);
443
+ for (const resolve of waiters) resolve();
444
+ };
445
+ };
446
+ const noopQueueWaitTimer = { cancel: () => {} };
447
+ const createQueueWaitTimer = (timeoutMs, reject) => {
448
+ if (timeoutMs === void 0) return noopQueueWaitTimer;
449
+ let timeoutId = setTimeout(() => {
450
+ reject(/* @__PURE__ */ new Error("Task was not started within the maximum waiting time"));
451
+ }, timeoutMs);
452
+ timeoutId.unref();
453
+ return { cancel: () => {
454
+ if (!timeoutId) return;
455
+ clearTimeout(timeoutId);
456
+ timeoutId = null;
457
+ } };
458
+ };
459
+ const waitForProcessingOrDeadline = async (processing, closeDeadline) => {
460
+ let timeoutId = null;
461
+ try {
462
+ return await Promise.race([processing.then(() => true), new Promise((resolve) => {
463
+ timeoutId = setTimeout(() => resolve(false), closeDeadline);
464
+ timeoutId.unref();
465
+ })]);
466
+ } finally {
467
+ if (timeoutId) clearTimeout(timeoutId);
468
+ }
469
+ };
470
+
471
+ //#endregion
472
+ //#region src/core/taskProcessing/executionGuards.ts
473
+ const guardConcurrentAccess = (options) => {
474
+ const taskProcessor = new TaskProcessor({
475
+ maxActiveTasks: options?.maxActiveTasks ?? Number.MAX_SAFE_INTEGER,
476
+ maxQueueSize: options?.maxQueueSize ?? Number.MAX_SAFE_INTEGER,
477
+ ...options?.maxTaskIdleTime !== void 0 ? { maxTaskIdleTime: options.maxTaskIdleTime } : {}
478
+ });
479
+ return {
480
+ execute: (operation, options) => taskProcessor.enqueue(async (context) => {
481
+ try {
482
+ return await operation({ abort: context.abort });
483
+ } finally {
484
+ context.ack();
485
+ }
486
+ }, options),
487
+ waitForIdle: () => taskProcessor.waitForEndOfProcessing(),
488
+ stop: (options) => taskProcessor.stop(options)
489
+ };
490
+ };
491
+
204
492
  //#endregion
205
493
  //#region src/core/execute/execute.ts
206
494
  const mapSQLQueryResult = (result, mapping) => {
@@ -225,26 +513,63 @@ var BatchCommandNoChangesError = class BatchCommandNoChangesError extends DumboE
225
513
  }
226
514
  };
227
515
  const sqlExecutor = (sqlExecutor, options) => ({
228
- query: (sql, queryOptions) => executeInNewDbClient((client) => sqlExecutor.query(client, sql, queryOptions), options),
229
- batchQuery: (sqls, queryOptions) => executeInNewDbClient((client) => sqlExecutor.batchQuery(client, sqls, queryOptions), options),
230
- command: (sql, commandOptions) => executeInNewDbClient((client) => sqlExecutor.command(client, sql, commandOptions), options),
231
- batchCommand: (sqls, commandOptions) => executeInNewDbClient((client) => sqlExecutor.batchCommand(client, sqls, commandOptions), options)
516
+ query: (sql, queryOptions) => executeInNewDbClient((client) => sqlExecutor.query(client, sql, queryOptions), {
517
+ ...options,
518
+ ...queryOptions
519
+ }),
520
+ batchQuery: (sqls, queryOptions) => executeInNewDbClient((client) => sqlExecutor.batchQuery(client, sqls, queryOptions), {
521
+ ...options,
522
+ ...queryOptions
523
+ }),
524
+ command: (sql, commandOptions) => executeInNewDbClient((client) => sqlExecutor.command(client, sql, commandOptions), {
525
+ ...options,
526
+ ...commandOptions
527
+ }),
528
+ batchCommand: (sqls, commandOptions) => executeInNewDbClient((client) => sqlExecutor.batchCommand(client, sqls, commandOptions), {
529
+ ...options,
530
+ ...commandOptions
531
+ })
232
532
  });
233
533
  const sqlExecutorInNewConnection = (options) => ({
234
- query: (sql, queryOptions) => executeInNewConnection((connection) => connection.execute.query(sql, queryOptions), options),
235
- batchQuery: (sqls, queryOptions) => executeInNewConnection((connection) => connection.execute.batchQuery(sqls, queryOptions), options),
236
- command: (sql, commandOptions) => executeInNewConnection((connection) => connection.execute.command(sql, commandOptions), options),
237
- batchCommand: (sqls, commandOptions) => executeInNewConnection((connection) => connection.execute.batchCommand(sqls, commandOptions), options)
534
+ query: (sql, queryOptions) => executeInNewConnection((connection) => connection.execute.query(sql, queryOptions), {
535
+ ...options,
536
+ ...queryOptions
537
+ }),
538
+ batchQuery: (sqls, queryOptions) => executeInNewConnection((connection) => connection.execute.batchQuery(sqls, queryOptions), {
539
+ ...options,
540
+ ...queryOptions
541
+ }),
542
+ command: (sql, commandOptions) => executeInNewConnection((connection) => connection.execute.command(sql, commandOptions), {
543
+ ...options,
544
+ ...commandOptions
545
+ }),
546
+ batchCommand: (sqls, commandOptions) => executeInNewConnection((connection) => connection.execute.batchCommand(sqls, commandOptions), {
547
+ ...options,
548
+ ...commandOptions
549
+ })
238
550
  });
239
551
  const sqlExecutorInAmbientConnection = (options) => ({
240
- query: (sql, queryOptions) => executeInAmbientConnection((connection) => connection.execute.query(sql, queryOptions), options),
241
- batchQuery: (sqls, queryOptions) => executeInAmbientConnection((connection) => connection.execute.batchQuery(sqls, queryOptions), options),
242
- command: (sql, commandOptions) => executeInAmbientConnection((connection) => connection.execute.command(sql, commandOptions), options),
243
- batchCommand: (sqls, commandOptions) => executeInAmbientConnection((connection) => connection.execute.batchCommand(sqls, commandOptions), options)
552
+ query: (sql, queryOptions) => executeInAmbientConnection((connection) => connection.execute.query(sql, queryOptions), {
553
+ ...options,
554
+ ...queryOptions
555
+ }),
556
+ batchQuery: (sqls, queryOptions) => executeInAmbientConnection((connection) => connection.execute.batchQuery(sqls, queryOptions), {
557
+ ...options,
558
+ ...queryOptions
559
+ }),
560
+ command: (sql, commandOptions) => executeInAmbientConnection((connection) => connection.execute.command(sql, commandOptions), {
561
+ ...options,
562
+ ...commandOptions
563
+ }),
564
+ batchCommand: (sqls, commandOptions) => executeInAmbientConnection((connection) => connection.execute.batchCommand(sqls, commandOptions), {
565
+ ...options,
566
+ ...commandOptions
567
+ })
244
568
  });
245
569
  const executeInNewDbClient = async (handle, options) => {
570
+ Abort.throwIfAborted(options);
246
571
  const { connect, close } = options;
247
- const client = await connect();
572
+ const client = await connect({ abort: Abort.from(options) });
248
573
  try {
249
574
  return await handle(client);
250
575
  } catch (error) {
@@ -253,7 +578,8 @@ const executeInNewDbClient = async (handle, options) => {
253
578
  }
254
579
  };
255
580
  const executeInNewConnection = async (handle, options) => {
256
- const connection = await options.connection();
581
+ Abort.throwIfAborted(options);
582
+ const connection = await options.connection({ abort: Abort.from(options) });
257
583
  try {
258
584
  return await handle(connection);
259
585
  } finally {
@@ -261,10 +587,8 @@ const executeInNewConnection = async (handle, options) => {
261
587
  }
262
588
  };
263
589
  const executeInAmbientConnection = async (handle, options) => {
264
- const connection = await options.connection();
265
- try {
266
- return await handle(connection);
267
- } finally {}
590
+ Abort.throwIfAborted(options);
591
+ return handle(await options.connection({ abort: Abort.from(options) }));
268
592
  };
269
593
 
270
594
  //#endregion
@@ -332,10 +656,10 @@ const toTransactionResult = (transactionResult) => transactionResult !== void 0
332
656
  success: true,
333
657
  result: transactionResult
334
658
  };
335
- const executeInTransaction = async (transaction, handle) => {
659
+ const executeInTransaction = async (transaction, handle, context = { abort: Abort.never }) => {
336
660
  await transaction.begin();
337
661
  try {
338
- const { success, result } = toTransactionResult(await handle(transaction));
662
+ const { success, result } = toTransactionResult(await handle(transaction, context));
339
663
  if (success) await transaction.commit();
340
664
  else await transaction.rollback();
341
665
  return result;
@@ -344,18 +668,32 @@ const executeInTransaction = async (transaction, handle) => {
344
668
  throw e;
345
669
  }
346
670
  };
671
+ const executeInNestedTransaction = async (transaction, handle, options, context) => {
672
+ Abort.throwIfAborted(options);
673
+ 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.");
674
+ return executeInTransaction(transaction, handle, context);
675
+ };
347
676
  const transactionFactoryWithDbClient = (connect, initTransaction) => {
348
677
  let currentTransaction = void 0;
349
- const getOrInitCurrentTransaction = (options) => currentTransaction ?? (currentTransaction = initTransaction(connect(), {
350
- close: () => {
351
- currentTransaction = void 0;
352
- return Promise.resolve();
353
- },
354
- ...options ?? {}
355
- }));
678
+ const getOrInitCurrentTransaction = (options) => {
679
+ Abort.throwIfAborted(options);
680
+ if (currentTransaction) return currentTransaction;
681
+ currentTransaction = initTransaction(connect({ abort: Abort.from(options) }), {
682
+ close: () => {
683
+ currentTransaction = void 0;
684
+ return Promise.resolve();
685
+ },
686
+ ...options ?? {}
687
+ });
688
+ return currentTransaction;
689
+ };
356
690
  return {
357
691
  transaction: getOrInitCurrentTransaction,
358
- withTransaction: (handle, options) => executeInTransaction(getOrInitCurrentTransaction(options), handle)
692
+ withTransaction: (handle, options) => {
693
+ const abortRejection = Abort.rejectIfAborted(options);
694
+ if (abortRejection) return abortRejection;
695
+ return executeInTransaction(getOrInitCurrentTransaction(options), handle, { abort: Abort.from(options) });
696
+ }
359
697
  };
360
698
  };
361
699
  const wrapInConnectionClosure = async (connection, handle) => {
@@ -367,7 +705,8 @@ const wrapInConnectionClosure = async (connection, handle) => {
367
705
  };
368
706
  const transactionFactoryWithNewConnection = (connect) => ({
369
707
  transaction: (options) => {
370
- const connection = connect();
708
+ Abort.throwIfAborted(options);
709
+ const connection = connect({ abort: Abort.from(options) });
371
710
  const transaction = connection.transaction(options);
372
711
  return {
373
712
  ...transaction,
@@ -376,7 +715,9 @@ const transactionFactoryWithNewConnection = (connect) => ({
376
715
  };
377
716
  },
378
717
  withTransaction: (handle, options) => {
379
- const connection = connect();
718
+ const abortRejection = Abort.rejectIfAborted(options);
719
+ if (abortRejection) return abortRejection;
720
+ const connection = connect({ abort: Abort.from(options) });
380
721
  const withTx = connection.withTransaction;
381
722
  return wrapInConnectionClosure(connection, () => withTx(handle, options));
382
723
  }
@@ -385,19 +726,21 @@ const transactionFactoryWithAsyncAmbientConnection = (driverType, connect, close
385
726
  close ??= () => Promise.resolve();
386
727
  return {
387
728
  transaction: (options) => {
729
+ Abort.throwIfAborted(options);
388
730
  let conn = null;
389
731
  let innerTx = null;
390
732
  let connectingPromise = null;
391
733
  const ensureConnection = async () => {
392
734
  if (conn) return innerTx;
393
735
  if (!connectingPromise) connectingPromise = (async () => {
394
- conn = await connect();
736
+ Abort.throwIfAborted(options);
737
+ conn = await connect({ abort: Abort.from(options) });
395
738
  innerTx = conn.transaction(options);
396
739
  })();
397
740
  await connectingPromise;
398
741
  return innerTx;
399
742
  };
400
- return {
743
+ const tx = {
401
744
  driverType,
402
745
  get connection() {
403
746
  if (!conn) throw new Error("Transaction not started - call begin() first");
@@ -439,11 +782,14 @@ const transactionFactoryWithAsyncAmbientConnection = (driverType, connect, close
439
782
  if (conn) await close(conn);
440
783
  }
441
784
  },
442
- _transactionOptions: void 0
785
+ withTransaction: (handle, options) => executeInNestedTransaction(tx, handle, options, { abort: Abort.from(options) }),
786
+ _transactionOptions: options ?? {}
443
787
  };
788
+ return tx;
444
789
  },
445
790
  withTransaction: async (handle, options) => {
446
- const conn = await connect();
791
+ Abort.throwIfAborted(options);
792
+ const conn = await connect({ abort: Abort.from(options) });
447
793
  try {
448
794
  const withTx = conn.withTransaction;
449
795
  return await withTx(handle, options);
@@ -460,7 +806,10 @@ const createAmbientConnection = (options) => {
460
806
  const { driverType, client, executor, initTransaction, serializer } = options;
461
807
  const clientPromise = Promise.resolve(client);
462
808
  const closePromise = Promise.resolve();
463
- const open = () => clientPromise;
809
+ const open = (context) => {
810
+ Abort.throwIfAborted(context);
811
+ return clientPromise;
812
+ };
464
813
  const close = () => closePromise;
465
814
  const typedConnection = {
466
815
  driverType,
@@ -476,9 +825,10 @@ const createConnection = (options) => {
476
825
  const { driverType, connect, close, initTransaction, executor, serializer } = options;
477
826
  let client = null;
478
827
  let connectPromise = null;
479
- const getClient = async () => {
828
+ const getClient = async (context) => {
829
+ Abort.throwIfAborted(context);
480
830
  if (client) return client;
481
- if (!connectPromise) connectPromise = connect().then((c) => {
831
+ if (!connectPromise) connectPromise = connect(context ?? { abort: Abort.never }).then((c) => {
482
832
  client = c;
483
833
  return c;
484
834
  });
@@ -508,7 +858,10 @@ const createAmbientConnectionPool = (options) => {
508
858
  getConnection: () => connection,
509
859
  execute: connection.execute,
510
860
  transaction: (options) => connection.transaction(options),
511
- withConnection: (handle, _options) => handle(connection),
861
+ withConnection: (handle, options) => {
862
+ Abort.throwIfAborted(options);
863
+ return handle(connection, { abort: Abort.from(options) });
864
+ },
512
865
  withTransaction: (handle, options) => {
513
866
  const withTx = connection.withTransaction;
514
867
  return withTx(handle, options);
@@ -519,48 +872,45 @@ const createSingletonConnectionPool = (options) => {
519
872
  const { driverType, getConnection } = options;
520
873
  let connectionPromise = null;
521
874
  let closed = false;
522
- const activeOperations = /* @__PURE__ */ new Set();
875
+ const operationGuard = guardConcurrentAccess();
523
876
  const closedError = () => /* @__PURE__ */ new Error("Singleton connection pool has been closed");
524
- const run = async (operation) => {
877
+ const executeIfOpen = async (operation, operationOptions) => {
525
878
  if (closed) throw closedError();
526
- const activeOperation = operation();
527
- activeOperations.add(activeOperation);
528
- try {
529
- return await activeOperation;
530
- } finally {
531
- activeOperations.delete(activeOperation);
532
- }
879
+ return operationGuard.execute(operation, operationOptions);
533
880
  };
534
- const getExistingOrNewConnection = () => {
535
- if (!connectionPromise) connectionPromise ??= Promise.resolve(getConnection());
881
+ const getExistingOrNewConnection = (context) => {
882
+ if (!connectionPromise) connectionPromise ??= Promise.resolve(getConnection(context));
536
883
  return connectionPromise;
537
884
  };
538
885
  const innerTransactionFactory = transactionFactoryWithAsyncAmbientConnection(options.driverType, getExistingOrNewConnection, options.closeConnection);
539
886
  return {
540
887
  driverType,
541
- connection: () => run(() => getExistingOrNewConnection().then((conn) => wrapPooledConnection(conn, () => Promise.resolve()))),
888
+ connection: (connectionOptions) => executeIfOpen((context) => getExistingOrNewConnection(context).then((conn) => wrapPooledConnection(conn, () => Promise.resolve())), connectionOptions),
542
889
  execute: (() => {
543
890
  const ambientExecutor = sqlExecutorInAmbientConnection({
544
891
  driverType,
545
892
  connection: getExistingOrNewConnection
546
893
  });
547
894
  return {
548
- query: (sql, opts) => run(() => ambientExecutor.query(sql, opts)),
549
- batchQuery: (sqls, opts) => run(() => ambientExecutor.batchQuery(sqls, opts)),
550
- command: (sql, opts) => run(() => ambientExecutor.command(sql, opts)),
551
- batchCommand: (sqls, opts) => run(() => ambientExecutor.batchCommand(sqls, opts))
895
+ query: (sql, opts) => executeIfOpen(() => ambientExecutor.query(sql, opts), opts),
896
+ batchQuery: (sqls, opts) => executeIfOpen(() => ambientExecutor.batchQuery(sqls, opts), opts),
897
+ command: (sql, opts) => executeIfOpen(() => ambientExecutor.command(sql, opts), opts),
898
+ batchCommand: (sqls, opts) => executeIfOpen(() => ambientExecutor.batchCommand(sqls, opts), opts)
552
899
  };
553
900
  })(),
554
- withConnection: (handle, _options) => run(() => executeInAmbientConnection(handle, { connection: getExistingOrNewConnection })),
901
+ withConnection: (handle, options) => executeIfOpen((context) => executeInAmbientConnection((connection) => handle(connection, context), {
902
+ connection: getExistingOrNewConnection,
903
+ ...options
904
+ }), options),
555
905
  transaction: (transactionOptions) => {
556
906
  if (closed) throw closedError();
557
907
  return innerTransactionFactory.transaction(transactionOptions);
558
908
  },
559
- withTransaction: (handle, transactionOptions) => run(() => innerTransactionFactory.withTransaction(handle, transactionOptions)),
909
+ withTransaction: (handle, transactionOptions) => executeIfOpen((context) => innerTransactionFactory.withTransaction((tx) => handle(tx, context), transactionOptions), transactionOptions),
560
910
  close: async (closeOptions) => {
561
911
  if (closed) return;
562
912
  closed = true;
563
- if (!closeOptions?.force) await Promise.allSettled([...activeOperations]);
913
+ await operationGuard.stop(closeOptions);
564
914
  if (!connectionPromise) return;
565
915
  const connection = await connectionPromise;
566
916
  connectionPromise = null;
@@ -572,16 +922,22 @@ const createAlwaysNewConnectionPool = (options) => {
572
922
  const { driverType, getConnection, connectionOptions } = options;
573
923
  return createConnectionPool({
574
924
  driverType,
575
- getConnection: () => connectionOptions ? getConnection(connectionOptions) : getConnection()
925
+ getConnection: (context) => connectionOptions ? getConnection(connectionOptions, context) : getConnection(context)
576
926
  });
577
927
  };
578
928
  const createConnectionPool = (pool) => {
579
929
  const { driverType, getConnection } = pool;
580
- const connection = "connection" in pool ? pool.connection : () => Promise.resolve(getConnection());
930
+ const connection = "connection" in pool ? pool.connection : (options) => {
931
+ Abort.throwIfAborted(options);
932
+ return Promise.resolve(getConnection({ abort: Abort.from(options) }));
933
+ };
581
934
  return {
582
935
  driverType,
583
936
  connection,
584
- withConnection: "withConnection" in pool ? pool.withConnection : (handle, _options) => executeInNewConnection(handle, { connection }),
937
+ withConnection: "withConnection" in pool ? pool.withConnection : (handle, options) => executeInNewConnection((connection) => handle(connection, { abort: Abort.from(options) }), {
938
+ connection,
939
+ ...options
940
+ }),
585
941
  close: "close" in pool ? pool.close : () => Promise.resolve(),
586
942
  execute: "execute" in pool ? pool.execute : sqlExecutorInNewConnection({
587
943
  driverType,
@@ -1916,9 +2272,9 @@ const sqliteSQLExecutor = (driverType, serializer, formatter, errorMapper) => ({
1916
2272
 
1917
2273
  //#endregion
1918
2274
  //#region src/storage/sqlite/core/transactions/index.ts
1919
- const sqliteTransaction = (driverType, connection, allowNestedTransactions, serializer, defaultTransactionMode) => (getClient, options) => {
1920
- allowNestedTransactions = options?.allowNestedTransactions ?? allowNestedTransactions;
1921
- const useSavepoints = options?.useSavepoints ?? false;
2275
+ const sqliteTransaction = (driverType, connection, defaultOptions, serializer, defaultTransactionMode) => (getClient, options) => {
2276
+ const defaultTransactionOptions = typeof defaultOptions === "boolean" ? { allowNestedTransactions: defaultOptions } : defaultOptions;
2277
+ const allowNestedTransactions = options?.allowNestedTransactions ?? defaultTransactionOptions.allowNestedTransactions ?? false;
1922
2278
  const tx = databaseTransaction({
1923
2279
  begin: async () => {
1924
2280
  const client = await getClient;
@@ -1946,23 +2302,28 @@ const sqliteTransaction = (driverType, connection, allowNestedTransactions, seri
1946
2302
  },
1947
2303
  releaseSavepoint: async (level) => {
1948
2304
  await (await getClient).command(SQL`RELEASE transaction${SQL.plain(level.toString())}`);
2305
+ },
2306
+ rollbackToSavepoint: async (level) => {
2307
+ await (await getClient).command(SQL`ROLLBACK TO transaction${SQL.plain(level.toString())}`);
1949
2308
  }
1950
2309
  }, {
1951
2310
  allowNestedTransactions,
1952
- useSavepoints
2311
+ useSavepoints: options?.useSavepoints ?? defaultTransactionOptions.useSavepoints ?? false
1953
2312
  });
1954
- return {
2313
+ const transaction = {
1955
2314
  connection: connection(),
1956
2315
  driverType,
1957
2316
  begin: tx.begin,
1958
2317
  commit: tx.commit,
1959
2318
  rollback: tx.rollback,
1960
2319
  execute: sqlExecutor(sqliteSQLExecutor(driverType, serializer), { connect: () => getClient }),
2320
+ withTransaction: (handle, options) => executeInNestedTransaction(transaction, handle, options),
1961
2321
  _transactionOptions: {
1962
2322
  ...options,
1963
2323
  allowNestedTransactions
1964
2324
  }
1965
2325
  };
2326
+ return transaction;
1966
2327
  };
1967
2328
 
1968
2329
  //#endregion
@@ -2007,7 +2368,7 @@ const sqliteAmbientClientConnection = (options) => {
2007
2368
  return createAmbientConnection({
2008
2369
  driverType,
2009
2370
  client,
2010
- initTransaction: initTransaction ?? ((connection) => sqliteTransaction(driverType, connection, allowNestedTransactions ?? false, serializer, defaultTransactionMode)),
2371
+ initTransaction: initTransaction ?? ((connection) => sqliteTransaction(driverType, connection, { allowNestedTransactions: allowNestedTransactions ?? false }, serializer, defaultTransactionMode)),
2011
2372
  executor: ({ serializer }) => sqliteSQLExecutor(driverType, serializer, void 0, errorMapper),
2012
2373
  serializer
2013
2374
  });
@@ -2032,7 +2393,7 @@ const sqliteClientConnection = (options) => {
2032
2393
  if (client && "close" in client && typeof client.close === "function") await client.close();
2033
2394
  else if (client && "release" in client && typeof client.release === "function") client.release();
2034
2395
  },
2035
- initTransaction: (connection) => sqliteTransaction(options.driverType, connection, connectionOptions.transactionOptions?.allowNestedTransactions ?? false, serializer, connectionOptions.defaultTransactionMode),
2396
+ initTransaction: (connection) => sqliteTransaction(options.driverType, connection, connectionOptions.transactionOptions ?? {}, serializer, connectionOptions.defaultTransactionMode),
2036
2397
  executor: ({ serializer }) => sqliteSQLExecutor(options.driverType, serializer),
2037
2398
  serializer
2038
2399
  });
@@ -2054,7 +2415,7 @@ const sqlitePoolClientConnection = (options) => {
2054
2415
  driverType: options.driverType,
2055
2416
  connect,
2056
2417
  close: () => client !== null ? Promise.resolve(client.release()) : Promise.resolve(),
2057
- initTransaction: (connection) => sqliteTransaction(options.driverType, connection, connectionOptions.transactionOptions?.allowNestedTransactions ?? false, serializer, connectionOptions.defaultTransactionMode),
2418
+ initTransaction: (connection) => sqliteTransaction(options.driverType, connection, connectionOptions.transactionOptions ?? {}, serializer, connectionOptions.defaultTransactionMode),
2058
2419
  executor: ({ serializer }) => sqliteSQLExecutor(options.driverType, serializer),
2059
2420
  serializer
2060
2421
  });
@@ -2424,7 +2785,7 @@ const d1Transaction = (connection, serializer, defaultOptions) => (getClient, op
2424
2785
  client = await getClient;
2425
2786
  return client;
2426
2787
  };
2427
- return {
2788
+ const transaction = {
2428
2789
  connection: connection(),
2429
2790
  driverType: D1DriverType,
2430
2791
  begin: async function() {
@@ -2468,8 +2829,10 @@ const d1Transaction = (connection, serializer, defaultOptions) => (getClient, op
2468
2829
  if (!sessionClient) throw new Error("Transaction has not been started. Call begin() first.");
2469
2830
  return Promise.resolve(sessionClient);
2470
2831
  } }),
2832
+ withTransaction: (handle, options) => executeInNestedTransaction(transaction, handle, options),
2471
2833
  _transactionOptions: options ?? {}
2472
2834
  };
2835
+ return transaction;
2473
2836
  };
2474
2837
 
2475
2838
  //#endregion