@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
package/dist/sqlite.cjs CHANGED
@@ -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) => {
@@ -210,26 +498,63 @@ const mapSQLQueryResult = (result, mapping) => {
210
498
  return mappedResult;
211
499
  };
212
500
  const sqlExecutor = (sqlExecutor, options) => ({
213
- query: (sql, queryOptions) => executeInNewDbClient((client) => sqlExecutor.query(client, sql, queryOptions), options),
214
- batchQuery: (sqls, queryOptions) => executeInNewDbClient((client) => sqlExecutor.batchQuery(client, sqls, queryOptions), options),
215
- command: (sql, commandOptions) => executeInNewDbClient((client) => sqlExecutor.command(client, sql, commandOptions), options),
216
- batchCommand: (sqls, commandOptions) => executeInNewDbClient((client) => sqlExecutor.batchCommand(client, sqls, commandOptions), options)
501
+ query: (sql, queryOptions) => executeInNewDbClient((client) => sqlExecutor.query(client, sql, queryOptions), {
502
+ ...options,
503
+ ...queryOptions
504
+ }),
505
+ batchQuery: (sqls, queryOptions) => executeInNewDbClient((client) => sqlExecutor.batchQuery(client, sqls, queryOptions), {
506
+ ...options,
507
+ ...queryOptions
508
+ }),
509
+ command: (sql, commandOptions) => executeInNewDbClient((client) => sqlExecutor.command(client, sql, commandOptions), {
510
+ ...options,
511
+ ...commandOptions
512
+ }),
513
+ batchCommand: (sqls, commandOptions) => executeInNewDbClient((client) => sqlExecutor.batchCommand(client, sqls, commandOptions), {
514
+ ...options,
515
+ ...commandOptions
516
+ })
217
517
  });
218
518
  const sqlExecutorInNewConnection = (options) => ({
219
- query: (sql, queryOptions) => executeInNewConnection((connection) => connection.execute.query(sql, queryOptions), options),
220
- batchQuery: (sqls, queryOptions) => executeInNewConnection((connection) => connection.execute.batchQuery(sqls, queryOptions), options),
221
- command: (sql, commandOptions) => executeInNewConnection((connection) => connection.execute.command(sql, commandOptions), options),
222
- batchCommand: (sqls, commandOptions) => executeInNewConnection((connection) => connection.execute.batchCommand(sqls, commandOptions), options)
519
+ query: (sql, queryOptions) => executeInNewConnection((connection) => connection.execute.query(sql, queryOptions), {
520
+ ...options,
521
+ ...queryOptions
522
+ }),
523
+ batchQuery: (sqls, queryOptions) => executeInNewConnection((connection) => connection.execute.batchQuery(sqls, queryOptions), {
524
+ ...options,
525
+ ...queryOptions
526
+ }),
527
+ command: (sql, commandOptions) => executeInNewConnection((connection) => connection.execute.command(sql, commandOptions), {
528
+ ...options,
529
+ ...commandOptions
530
+ }),
531
+ batchCommand: (sqls, commandOptions) => executeInNewConnection((connection) => connection.execute.batchCommand(sqls, commandOptions), {
532
+ ...options,
533
+ ...commandOptions
534
+ })
223
535
  });
224
536
  const sqlExecutorInAmbientConnection = (options) => ({
225
- query: (sql, queryOptions) => executeInAmbientConnection((connection) => connection.execute.query(sql, queryOptions), options),
226
- batchQuery: (sqls, queryOptions) => executeInAmbientConnection((connection) => connection.execute.batchQuery(sqls, queryOptions), options),
227
- command: (sql, commandOptions) => executeInAmbientConnection((connection) => connection.execute.command(sql, commandOptions), options),
228
- batchCommand: (sqls, commandOptions) => executeInAmbientConnection((connection) => connection.execute.batchCommand(sqls, commandOptions), options)
537
+ query: (sql, queryOptions) => executeInAmbientConnection((connection) => connection.execute.query(sql, queryOptions), {
538
+ ...options,
539
+ ...queryOptions
540
+ }),
541
+ batchQuery: (sqls, queryOptions) => executeInAmbientConnection((connection) => connection.execute.batchQuery(sqls, queryOptions), {
542
+ ...options,
543
+ ...queryOptions
544
+ }),
545
+ command: (sql, commandOptions) => executeInAmbientConnection((connection) => connection.execute.command(sql, commandOptions), {
546
+ ...options,
547
+ ...commandOptions
548
+ }),
549
+ batchCommand: (sqls, commandOptions) => executeInAmbientConnection((connection) => connection.execute.batchCommand(sqls, commandOptions), {
550
+ ...options,
551
+ ...commandOptions
552
+ })
229
553
  });
230
554
  const executeInNewDbClient = async (handle, options) => {
555
+ Abort.throwIfAborted(options);
231
556
  const { connect, close } = options;
232
- const client = await connect();
557
+ const client = await connect({ abort: Abort.from(options) });
233
558
  try {
234
559
  return await handle(client);
235
560
  } catch (error) {
@@ -238,7 +563,8 @@ const executeInNewDbClient = async (handle, options) => {
238
563
  }
239
564
  };
240
565
  const executeInNewConnection = async (handle, options) => {
241
- const connection = await options.connection();
566
+ Abort.throwIfAborted(options);
567
+ const connection = await options.connection({ abort: Abort.from(options) });
242
568
  try {
243
569
  return await handle(connection);
244
570
  } finally {
@@ -246,10 +572,8 @@ const executeInNewConnection = async (handle, options) => {
246
572
  }
247
573
  };
248
574
  const executeInAmbientConnection = async (handle, options) => {
249
- const connection = await options.connection();
250
- try {
251
- return await handle(connection);
252
- } finally {}
575
+ Abort.throwIfAborted(options);
576
+ return handle(await options.connection({ abort: Abort.from(options) }));
253
577
  };
254
578
 
255
579
  //#endregion
@@ -317,10 +641,10 @@ const toTransactionResult = (transactionResult) => transactionResult !== void 0
317
641
  success: true,
318
642
  result: transactionResult
319
643
  };
320
- const executeInTransaction = async (transaction, handle) => {
644
+ const executeInTransaction = async (transaction, handle, context = { abort: Abort.never }) => {
321
645
  await transaction.begin();
322
646
  try {
323
- const { success, result } = toTransactionResult(await handle(transaction));
647
+ const { success, result } = toTransactionResult(await handle(transaction, context));
324
648
  if (success) await transaction.commit();
325
649
  else await transaction.rollback();
326
650
  return result;
@@ -329,18 +653,32 @@ const executeInTransaction = async (transaction, handle) => {
329
653
  throw e;
330
654
  }
331
655
  };
656
+ const executeInNestedTransaction = async (transaction, handle, options, context) => {
657
+ Abort.throwIfAborted(options);
658
+ 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.");
659
+ return executeInTransaction(transaction, handle, context);
660
+ };
332
661
  const transactionFactoryWithDbClient = (connect, initTransaction) => {
333
662
  let currentTransaction = void 0;
334
- const getOrInitCurrentTransaction = (options) => currentTransaction ?? (currentTransaction = initTransaction(connect(), {
335
- close: () => {
336
- currentTransaction = void 0;
337
- return Promise.resolve();
338
- },
339
- ...options ?? {}
340
- }));
663
+ const getOrInitCurrentTransaction = (options) => {
664
+ Abort.throwIfAborted(options);
665
+ if (currentTransaction) return currentTransaction;
666
+ currentTransaction = initTransaction(connect({ abort: Abort.from(options) }), {
667
+ close: () => {
668
+ currentTransaction = void 0;
669
+ return Promise.resolve();
670
+ },
671
+ ...options ?? {}
672
+ });
673
+ return currentTransaction;
674
+ };
341
675
  return {
342
676
  transaction: getOrInitCurrentTransaction,
343
- withTransaction: (handle, options) => executeInTransaction(getOrInitCurrentTransaction(options), handle)
677
+ withTransaction: (handle, options) => {
678
+ const abortRejection = Abort.rejectIfAborted(options);
679
+ if (abortRejection) return abortRejection;
680
+ return executeInTransaction(getOrInitCurrentTransaction(options), handle, { abort: Abort.from(options) });
681
+ }
344
682
  };
345
683
  };
346
684
  const wrapInConnectionClosure = async (connection, handle) => {
@@ -352,7 +690,8 @@ const wrapInConnectionClosure = async (connection, handle) => {
352
690
  };
353
691
  const transactionFactoryWithNewConnection = (connect) => ({
354
692
  transaction: (options) => {
355
- const connection = connect();
693
+ Abort.throwIfAborted(options);
694
+ const connection = connect({ abort: Abort.from(options) });
356
695
  const transaction = connection.transaction(options);
357
696
  return {
358
697
  ...transaction,
@@ -361,7 +700,9 @@ const transactionFactoryWithNewConnection = (connect) => ({
361
700
  };
362
701
  },
363
702
  withTransaction: (handle, options) => {
364
- const connection = connect();
703
+ const abortRejection = Abort.rejectIfAborted(options);
704
+ if (abortRejection) return abortRejection;
705
+ const connection = connect({ abort: Abort.from(options) });
365
706
  const withTx = connection.withTransaction;
366
707
  return wrapInConnectionClosure(connection, () => withTx(handle, options));
367
708
  }
@@ -370,19 +711,21 @@ const transactionFactoryWithAsyncAmbientConnection = (driverType, connect, close
370
711
  close ??= () => Promise.resolve();
371
712
  return {
372
713
  transaction: (options) => {
714
+ Abort.throwIfAborted(options);
373
715
  let conn = null;
374
716
  let innerTx = null;
375
717
  let connectingPromise = null;
376
718
  const ensureConnection = async () => {
377
719
  if (conn) return innerTx;
378
720
  if (!connectingPromise) connectingPromise = (async () => {
379
- conn = await connect();
721
+ Abort.throwIfAborted(options);
722
+ conn = await connect({ abort: Abort.from(options) });
380
723
  innerTx = conn.transaction(options);
381
724
  })();
382
725
  await connectingPromise;
383
726
  return innerTx;
384
727
  };
385
- return {
728
+ const tx = {
386
729
  driverType,
387
730
  get connection() {
388
731
  if (!conn) throw new Error("Transaction not started - call begin() first");
@@ -424,11 +767,14 @@ const transactionFactoryWithAsyncAmbientConnection = (driverType, connect, close
424
767
  if (conn) await close(conn);
425
768
  }
426
769
  },
427
- _transactionOptions: void 0
770
+ withTransaction: (handle, options) => executeInNestedTransaction(tx, handle, options, { abort: Abort.from(options) }),
771
+ _transactionOptions: options ?? {}
428
772
  };
773
+ return tx;
429
774
  },
430
775
  withTransaction: async (handle, options) => {
431
- const conn = await connect();
776
+ Abort.throwIfAborted(options);
777
+ const conn = await connect({ abort: Abort.from(options) });
432
778
  try {
433
779
  const withTx = conn.withTransaction;
434
780
  return await withTx(handle, options);
@@ -445,7 +791,10 @@ const createAmbientConnection = (options) => {
445
791
  const { driverType, client, executor, initTransaction, serializer } = options;
446
792
  const clientPromise = Promise.resolve(client);
447
793
  const closePromise = Promise.resolve();
448
- const open = () => clientPromise;
794
+ const open = (context) => {
795
+ Abort.throwIfAborted(context);
796
+ return clientPromise;
797
+ };
449
798
  const close = () => closePromise;
450
799
  const typedConnection = {
451
800
  driverType,
@@ -461,9 +810,10 @@ const createConnection = (options) => {
461
810
  const { driverType, connect, close, initTransaction, executor, serializer } = options;
462
811
  let client = null;
463
812
  let connectPromise = null;
464
- const getClient = async () => {
813
+ const getClient = async (context) => {
814
+ Abort.throwIfAborted(context);
465
815
  if (client) return client;
466
- if (!connectPromise) connectPromise = connect().then((c) => {
816
+ if (!connectPromise) connectPromise = connect(context ?? { abort: Abort.never }).then((c) => {
467
817
  client = c;
468
818
  return c;
469
819
  });
@@ -493,7 +843,10 @@ const createAmbientConnectionPool = (options) => {
493
843
  getConnection: () => connection,
494
844
  execute: connection.execute,
495
845
  transaction: (options) => connection.transaction(options),
496
- withConnection: (handle, _options) => handle(connection),
846
+ withConnection: (handle, options) => {
847
+ Abort.throwIfAborted(options);
848
+ return handle(connection, { abort: Abort.from(options) });
849
+ },
497
850
  withTransaction: (handle, options) => {
498
851
  const withTx = connection.withTransaction;
499
852
  return withTx(handle, options);
@@ -504,48 +857,45 @@ const createSingletonConnectionPool = (options) => {
504
857
  const { driverType, getConnection } = options;
505
858
  let connectionPromise = null;
506
859
  let closed = false;
507
- const activeOperations = /* @__PURE__ */ new Set();
860
+ const operationGuard = guardConcurrentAccess();
508
861
  const closedError = () => /* @__PURE__ */ new Error("Singleton connection pool has been closed");
509
- const run = async (operation) => {
862
+ const executeIfOpen = async (operation, operationOptions) => {
510
863
  if (closed) throw closedError();
511
- const activeOperation = operation();
512
- activeOperations.add(activeOperation);
513
- try {
514
- return await activeOperation;
515
- } finally {
516
- activeOperations.delete(activeOperation);
517
- }
864
+ return operationGuard.execute(operation, operationOptions);
518
865
  };
519
- const getExistingOrNewConnection = () => {
520
- if (!connectionPromise) connectionPromise ??= Promise.resolve(getConnection());
866
+ const getExistingOrNewConnection = (context) => {
867
+ if (!connectionPromise) connectionPromise ??= Promise.resolve(getConnection(context));
521
868
  return connectionPromise;
522
869
  };
523
870
  const innerTransactionFactory = transactionFactoryWithAsyncAmbientConnection(options.driverType, getExistingOrNewConnection, options.closeConnection);
524
871
  return {
525
872
  driverType,
526
- connection: () => run(() => getExistingOrNewConnection().then((conn) => wrapPooledConnection(conn, () => Promise.resolve()))),
873
+ connection: (connectionOptions) => executeIfOpen((context) => getExistingOrNewConnection(context).then((conn) => wrapPooledConnection(conn, () => Promise.resolve())), connectionOptions),
527
874
  execute: (() => {
528
875
  const ambientExecutor = sqlExecutorInAmbientConnection({
529
876
  driverType,
530
877
  connection: getExistingOrNewConnection
531
878
  });
532
879
  return {
533
- query: (sql, opts) => run(() => ambientExecutor.query(sql, opts)),
534
- batchQuery: (sqls, opts) => run(() => ambientExecutor.batchQuery(sqls, opts)),
535
- command: (sql, opts) => run(() => ambientExecutor.command(sql, opts)),
536
- batchCommand: (sqls, opts) => run(() => ambientExecutor.batchCommand(sqls, opts))
880
+ query: (sql, opts) => executeIfOpen(() => ambientExecutor.query(sql, opts), opts),
881
+ batchQuery: (sqls, opts) => executeIfOpen(() => ambientExecutor.batchQuery(sqls, opts), opts),
882
+ command: (sql, opts) => executeIfOpen(() => ambientExecutor.command(sql, opts), opts),
883
+ batchCommand: (sqls, opts) => executeIfOpen(() => ambientExecutor.batchCommand(sqls, opts), opts)
537
884
  };
538
885
  })(),
539
- withConnection: (handle, _options) => run(() => executeInAmbientConnection(handle, { connection: getExistingOrNewConnection })),
886
+ withConnection: (handle, options) => executeIfOpen((context) => executeInAmbientConnection((connection) => handle(connection, context), {
887
+ connection: getExistingOrNewConnection,
888
+ ...options
889
+ }), options),
540
890
  transaction: (transactionOptions) => {
541
891
  if (closed) throw closedError();
542
892
  return innerTransactionFactory.transaction(transactionOptions);
543
893
  },
544
- withTransaction: (handle, transactionOptions) => run(() => innerTransactionFactory.withTransaction(handle, transactionOptions)),
894
+ withTransaction: (handle, transactionOptions) => executeIfOpen((context) => innerTransactionFactory.withTransaction((tx) => handle(tx, context), transactionOptions), transactionOptions),
545
895
  close: async (closeOptions) => {
546
896
  if (closed) return;
547
897
  closed = true;
548
- if (!closeOptions?.force) await Promise.allSettled([...activeOperations]);
898
+ await operationGuard.stop(closeOptions);
549
899
  if (!connectionPromise) return;
550
900
  const connection = await connectionPromise;
551
901
  connectionPromise = null;
@@ -557,16 +907,22 @@ const createAlwaysNewConnectionPool = (options) => {
557
907
  const { driverType, getConnection, connectionOptions } = options;
558
908
  return createConnectionPool({
559
909
  driverType,
560
- getConnection: () => connectionOptions ? getConnection(connectionOptions) : getConnection()
910
+ getConnection: (context) => connectionOptions ? getConnection(connectionOptions, context) : getConnection(context)
561
911
  });
562
912
  };
563
913
  const createConnectionPool = (pool) => {
564
914
  const { driverType, getConnection } = pool;
565
- const connection = "connection" in pool ? pool.connection : () => Promise.resolve(getConnection());
915
+ const connection = "connection" in pool ? pool.connection : (options) => {
916
+ Abort.throwIfAborted(options);
917
+ return Promise.resolve(getConnection({ abort: Abort.from(options) }));
918
+ };
566
919
  return {
567
920
  driverType,
568
921
  connection,
569
- withConnection: "withConnection" in pool ? pool.withConnection : (handle, _options) => executeInNewConnection(handle, { connection }),
922
+ withConnection: "withConnection" in pool ? pool.withConnection : (handle, options) => executeInNewConnection((connection) => handle(connection, { abort: Abort.from(options) }), {
923
+ connection,
924
+ ...options
925
+ }),
570
926
  close: "close" in pool ? pool.close : () => Promise.resolve(),
571
927
  execute: "execute" in pool ? pool.execute : sqlExecutorInNewConnection({
572
928
  driverType,
@@ -1901,9 +2257,9 @@ const sqliteSQLExecutor = (driverType, serializer, formatter, errorMapper) => ({
1901
2257
 
1902
2258
  //#endregion
1903
2259
  //#region src/storage/sqlite/core/transactions/index.ts
1904
- const sqliteTransaction = (driverType, connection, allowNestedTransactions, serializer, defaultTransactionMode) => (getClient, options) => {
1905
- allowNestedTransactions = options?.allowNestedTransactions ?? allowNestedTransactions;
1906
- const useSavepoints = options?.useSavepoints ?? false;
2260
+ const sqliteTransaction = (driverType, connection, defaultOptions, serializer, defaultTransactionMode) => (getClient, options) => {
2261
+ const defaultTransactionOptions = typeof defaultOptions === "boolean" ? { allowNestedTransactions: defaultOptions } : defaultOptions;
2262
+ const allowNestedTransactions = options?.allowNestedTransactions ?? defaultTransactionOptions.allowNestedTransactions ?? false;
1907
2263
  const tx = databaseTransaction({
1908
2264
  begin: async () => {
1909
2265
  const client = await getClient;
@@ -1931,23 +2287,28 @@ const sqliteTransaction = (driverType, connection, allowNestedTransactions, seri
1931
2287
  },
1932
2288
  releaseSavepoint: async (level) => {
1933
2289
  await (await getClient).command(SQL`RELEASE transaction${SQL.plain(level.toString())}`);
2290
+ },
2291
+ rollbackToSavepoint: async (level) => {
2292
+ await (await getClient).command(SQL`ROLLBACK TO transaction${SQL.plain(level.toString())}`);
1934
2293
  }
1935
2294
  }, {
1936
2295
  allowNestedTransactions,
1937
- useSavepoints
2296
+ useSavepoints: options?.useSavepoints ?? defaultTransactionOptions.useSavepoints ?? false
1938
2297
  });
1939
- return {
2298
+ const transaction = {
1940
2299
  connection: connection(),
1941
2300
  driverType,
1942
2301
  begin: tx.begin,
1943
2302
  commit: tx.commit,
1944
2303
  rollback: tx.rollback,
1945
2304
  execute: sqlExecutor(sqliteSQLExecutor(driverType, serializer), { connect: () => getClient }),
2305
+ withTransaction: (handle, options) => executeInNestedTransaction(transaction, handle, options),
1946
2306
  _transactionOptions: {
1947
2307
  ...options,
1948
2308
  allowNestedTransactions
1949
2309
  }
1950
2310
  };
2311
+ return transaction;
1951
2312
  };
1952
2313
 
1953
2314
  //#endregion
@@ -1992,7 +2353,7 @@ const sqliteAmbientClientConnection = (options) => {
1992
2353
  return createAmbientConnection({
1993
2354
  driverType,
1994
2355
  client,
1995
- initTransaction: initTransaction ?? ((connection) => sqliteTransaction(driverType, connection, allowNestedTransactions ?? false, serializer, defaultTransactionMode)),
2356
+ initTransaction: initTransaction ?? ((connection) => sqliteTransaction(driverType, connection, { allowNestedTransactions: allowNestedTransactions ?? false }, serializer, defaultTransactionMode)),
1996
2357
  executor: ({ serializer }) => sqliteSQLExecutor(driverType, serializer, void 0, errorMapper),
1997
2358
  serializer
1998
2359
  });
@@ -2017,7 +2378,7 @@ const sqliteClientConnection = (options) => {
2017
2378
  if (client && "close" in client && typeof client.close === "function") await client.close();
2018
2379
  else if (client && "release" in client && typeof client.release === "function") client.release();
2019
2380
  },
2020
- initTransaction: (connection) => sqliteTransaction(options.driverType, connection, connectionOptions.transactionOptions?.allowNestedTransactions ?? false, serializer, connectionOptions.defaultTransactionMode),
2381
+ initTransaction: (connection) => sqliteTransaction(options.driverType, connection, connectionOptions.transactionOptions ?? {}, serializer, connectionOptions.defaultTransactionMode),
2021
2382
  executor: ({ serializer }) => sqliteSQLExecutor(options.driverType, serializer),
2022
2383
  serializer
2023
2384
  });
@@ -2039,7 +2400,7 @@ const sqlitePoolClientConnection = (options) => {
2039
2400
  driverType: options.driverType,
2040
2401
  connect,
2041
2402
  close: () => client !== null ? Promise.resolve(client.release()) : Promise.resolve(),
2042
- initTransaction: (connection) => sqliteTransaction(options.driverType, connection, connectionOptions.transactionOptions?.allowNestedTransactions ?? false, serializer, connectionOptions.defaultTransactionMode),
2403
+ initTransaction: (connection) => sqliteTransaction(options.driverType, connection, connectionOptions.transactionOptions ?? {}, serializer, connectionOptions.defaultTransactionMode),
2043
2404
  executor: ({ serializer }) => sqliteSQLExecutor(options.driverType, serializer),
2044
2405
  serializer
2045
2406
  });