@event-driven-io/dumbo 0.13.0-beta.43 → 0.13.0-beta.45

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.
@@ -240,6 +240,65 @@ const executeInAmbientConnection = async (handle, options) => {
240
240
 
241
241
  //#endregion
242
242
  //#region src/core/connections/transaction.ts
243
+ const transactionNestingCounter = () => {
244
+ let transactionLevel = 0;
245
+ return {
246
+ reset: () => {
247
+ transactionLevel = 0;
248
+ },
249
+ increment: () => {
250
+ transactionLevel++;
251
+ },
252
+ decrement: () => {
253
+ transactionLevel--;
254
+ if (transactionLevel < 0) throw new Error("Transaction level is out of bounds");
255
+ },
256
+ get level() {
257
+ return transactionLevel;
258
+ }
259
+ };
260
+ };
261
+ const databaseTransaction = (backend, options) => {
262
+ const allowNestedTransactions = options?.allowNestedTransactions ?? false;
263
+ const useSavepoints = options?.useSavepoints ?? false;
264
+ const counter = transactionNestingCounter();
265
+ let hasBegun = false;
266
+ return {
267
+ begin: async () => {
268
+ if (!allowNestedTransactions && hasBegun) throw new InvalidOperationError("Cannot start a nested transaction: allowNestedTransactions is false. Set transactionOptions: { allowNestedTransactions: true } on your pool or connection.");
269
+ if (allowNestedTransactions) {
270
+ if (counter.level >= 1) {
271
+ counter.increment();
272
+ if (useSavepoints && backend.savepoint) await backend.savepoint(counter.level);
273
+ return;
274
+ }
275
+ counter.increment();
276
+ }
277
+ hasBegun = true;
278
+ await backend.begin();
279
+ },
280
+ commit: async () => {
281
+ if (allowNestedTransactions && counter.level > 1) {
282
+ if (useSavepoints && backend.releaseSavepoint) await backend.releaseSavepoint(counter.level);
283
+ counter.decrement();
284
+ return;
285
+ }
286
+ if (allowNestedTransactions) counter.reset();
287
+ hasBegun = false;
288
+ await backend.commit();
289
+ },
290
+ rollback: async (error) => {
291
+ if (allowNestedTransactions && counter.level > 1) {
292
+ if (useSavepoints && backend.rollbackToSavepoint) await backend.rollbackToSavepoint(counter.level);
293
+ counter.decrement();
294
+ return;
295
+ }
296
+ if (allowNestedTransactions) counter.reset();
297
+ hasBegun = false;
298
+ await backend.rollback(error);
299
+ }
300
+ };
301
+ };
243
302
  const toTransactionResult = (transactionResult) => transactionResult !== void 0 && transactionResult !== null && typeof transactionResult === "object" && "success" in transactionResult ? transactionResult : {
244
303
  success: true,
245
304
  result: transactionResult
@@ -430,22 +489,53 @@ const createAmbientConnectionPool = (options) => {
430
489
  const createSingletonConnectionPool = (options) => {
431
490
  const { driverType, getConnection } = options;
432
491
  let connectionPromise = null;
492
+ let closed = false;
493
+ const activeOperations = /* @__PURE__ */ new Set();
494
+ const closedError = () => /* @__PURE__ */ new Error("Singleton connection pool has been closed");
495
+ const run = async (operation) => {
496
+ if (closed) throw closedError();
497
+ const activeOperation = operation();
498
+ activeOperations.add(activeOperation);
499
+ try {
500
+ return await activeOperation;
501
+ } finally {
502
+ activeOperations.delete(activeOperation);
503
+ }
504
+ };
433
505
  const getExistingOrNewConnection = () => {
434
506
  if (!connectionPromise) connectionPromise ??= Promise.resolve(getConnection());
435
507
  return connectionPromise;
436
508
  };
509
+ const innerTransactionFactory = transactionFactoryWithAsyncAmbientConnection(options.driverType, getExistingOrNewConnection, options.closeConnection);
437
510
  return {
438
511
  driverType,
439
- connection: () => getExistingOrNewConnection().then((conn) => wrapPooledConnection(conn, () => Promise.resolve())),
440
- execute: sqlExecutorInAmbientConnection({
441
- driverType,
442
- connection: getExistingOrNewConnection
443
- }),
444
- withConnection: (handle, _options) => executeInAmbientConnection(handle, { connection: getExistingOrNewConnection }),
445
- ...transactionFactoryWithAsyncAmbientConnection(options.driverType, getExistingOrNewConnection, options.closeConnection),
446
- close: async () => {
512
+ connection: () => run(() => getExistingOrNewConnection().then((conn) => wrapPooledConnection(conn, () => Promise.resolve()))),
513
+ execute: (() => {
514
+ const ambientExecutor = sqlExecutorInAmbientConnection({
515
+ driverType,
516
+ connection: getExistingOrNewConnection
517
+ });
518
+ return {
519
+ query: (sql, opts) => run(() => ambientExecutor.query(sql, opts)),
520
+ batchQuery: (sqls, opts) => run(() => ambientExecutor.batchQuery(sqls, opts)),
521
+ command: (sql, opts) => run(() => ambientExecutor.command(sql, opts)),
522
+ batchCommand: (sqls, opts) => run(() => ambientExecutor.batchCommand(sqls, opts))
523
+ };
524
+ })(),
525
+ withConnection: (handle, _options) => run(() => executeInAmbientConnection(handle, { connection: getExistingOrNewConnection })),
526
+ transaction: (transactionOptions) => {
527
+ if (closed) throw closedError();
528
+ return innerTransactionFactory.transaction(transactionOptions);
529
+ },
530
+ withTransaction: (handle, transactionOptions) => run(() => innerTransactionFactory.withTransaction(handle, transactionOptions)),
531
+ close: async (closeOptions) => {
532
+ if (closed) return;
533
+ closed = true;
534
+ if (!closeOptions?.force) await Promise.allSettled([...activeOperations]);
447
535
  if (!connectionPromise) return;
448
- await (await connectionPromise).close();
536
+ const connection = await connectionPromise;
537
+ connectionPromise = null;
538
+ await connection.close();
449
539
  }
450
540
  };
451
541
  };
@@ -1798,54 +1888,46 @@ const sqliteSQLExecutor = (driverType, serializer, formatter, errorMapper) => ({
1798
1888
  //#endregion
1799
1889
  //#region src/storage/sqlite/core/transactions/index.ts
1800
1890
  const sqliteTransaction = (driverType, connection, allowNestedTransactions, serializer, defaultTransactionMode) => (getClient, options) => {
1801
- const transactionCounter = transactionNestingCounter();
1802
1891
  allowNestedTransactions = options?.allowNestedTransactions ?? allowNestedTransactions;
1803
- let hasBegun = false;
1804
- return {
1805
- connection: connection(),
1806
- driverType,
1807
- begin: async function() {
1892
+ const useSavepoints = options?.useSavepoints ?? false;
1893
+ const tx = databaseTransaction({
1894
+ begin: async () => {
1808
1895
  const client = await getClient;
1809
- if (allowNestedTransactions) {
1810
- if (transactionCounter.level >= 1) {
1811
- transactionCounter.increment();
1812
- if (options?.useSavepoints) await client.command(SQL`SAVEPOINT transaction${SQL.plain(transactionCounter.level.toString())}`);
1813
- return;
1814
- }
1815
- transactionCounter.increment();
1816
- } else if (hasBegun) throw new InvalidOperationError("Cannot start a nested transaction: allowNestedTransactions is false. Set transactionOptions: { allowNestedTransactions: true } on your pool or connection.");
1817
- hasBegun = true;
1818
1896
  const mode = options?.mode ?? defaultTransactionMode ?? "IMMEDIATE";
1819
1897
  await client.command(SQL`BEGIN ${SQL.plain(mode)} TRANSACTION`);
1820
1898
  },
1821
- commit: async function() {
1899
+ commit: async () => {
1822
1900
  const client = await getClient;
1823
- if (allowNestedTransactions && transactionCounter.level > 1) {
1824
- if (options?.useSavepoints) await client.command(SQL`RELEASE transaction${SQL.plain(transactionCounter.level.toString())}`);
1825
- transactionCounter.decrement();
1826
- return;
1827
- }
1828
1901
  try {
1829
- if (allowNestedTransactions) transactionCounter.reset();
1830
- hasBegun = false;
1831
1902
  await client.command(SQL`COMMIT`);
1832
1903
  } finally {
1833
- if (options?.close) await options?.close(client);
1904
+ if (options?.close) await options.close(client);
1834
1905
  }
1835
1906
  },
1836
- rollback: async function(error) {
1907
+ rollback: async (error) => {
1837
1908
  const client = await getClient;
1838
- if (allowNestedTransactions && transactionCounter.level > 1) {
1839
- transactionCounter.decrement();
1840
- return;
1841
- }
1842
1909
  try {
1843
- hasBegun = false;
1844
1910
  await client.command(SQL`ROLLBACK`);
1845
1911
  } finally {
1846
- if (options?.close) await options?.close(client, error);
1912
+ if (options?.close) await options.close(client, error);
1847
1913
  }
1848
1914
  },
1915
+ savepoint: async (level) => {
1916
+ await (await getClient).command(SQL`SAVEPOINT transaction${SQL.plain(level.toString())}`);
1917
+ },
1918
+ releaseSavepoint: async (level) => {
1919
+ await (await getClient).command(SQL`RELEASE transaction${SQL.plain(level.toString())}`);
1920
+ }
1921
+ }, {
1922
+ allowNestedTransactions,
1923
+ useSavepoints
1924
+ });
1925
+ return {
1926
+ connection: connection(),
1927
+ driverType,
1928
+ begin: tx.begin,
1929
+ commit: tx.commit,
1930
+ rollback: tx.rollback,
1849
1931
  execute: sqlExecutor(sqliteSQLExecutor(driverType, serializer), { connect: () => getClient }),
1850
1932
  _transactionOptions: {
1851
1933
  ...options,
@@ -1891,24 +1973,6 @@ const isSQLiteError = (error) => {
1891
1973
  if (error instanceof Error && "code" in error) return true;
1892
1974
  return false;
1893
1975
  };
1894
- const transactionNestingCounter = () => {
1895
- let transactionLevel = 0;
1896
- return {
1897
- reset: () => {
1898
- transactionLevel = 0;
1899
- },
1900
- increment: () => {
1901
- transactionLevel++;
1902
- },
1903
- decrement: () => {
1904
- transactionLevel--;
1905
- if (transactionLevel < 0) throw new Error("Transaction level is out of bounds");
1906
- },
1907
- get level() {
1908
- return transactionLevel;
1909
- }
1910
- };
1911
- };
1912
1976
  const sqliteAmbientClientConnection = (options) => {
1913
1977
  const { client, driverType, initTransaction, allowNestedTransactions, defaultTransactionMode, serializer, errorMapper } = options;
1914
1978
  return createAmbientConnection({
@@ -2436,5 +2500,5 @@ const useD1DumboDriver = () => {
2436
2500
  useD1DumboDriver();
2437
2501
 
2438
2502
  //#endregion
2439
- export { D1DriverType, D1TransactionNotSupportedError, DEFAULT_SQLITE_PRAGMA_OPTIONS, DefaultSQLiteMigratorOptions, InMemorySQLiteDatabase, SQLiteConnectionString, SQLiteDatabaseName, SQLiteJSON, d1Client, d1Connection, d1DumboDriver, d1Pool, d1SQLExecutor, d1Transaction, defaultSQLiteDatabase, isInMemoryDatabase, isSQLiteError, mapD1Error, mapSqliteError, parsePragmasFromConnectionString, sqliteAlwaysNewConnectionPool, sqliteAmbientClientConnection, sqliteAmbientConnectionPool, sqliteClientConnection, sqliteConnection, sqliteExecute, sqliteFormatter, sqliteMetadata, sqlitePool, sqlitePoolClientConnection, sqliteSQLExecutor, sqliteSingletonConnectionPool, sqliteTransaction, tableExists, toSqlitePoolOptions, transactionNestingCounter, useD1DumboDriver };
2503
+ export { D1DriverType, D1TransactionNotSupportedError, DEFAULT_SQLITE_PRAGMA_OPTIONS, DefaultSQLiteMigratorOptions, InMemorySQLiteDatabase, SQLiteConnectionString, SQLiteDatabaseName, SQLiteJSON, d1Client, d1Connection, d1DumboDriver, d1Pool, d1SQLExecutor, d1Transaction, defaultSQLiteDatabase, isInMemoryDatabase, isSQLiteError, mapD1Error, mapSqliteError, parsePragmasFromConnectionString, sqliteAlwaysNewConnectionPool, sqliteAmbientClientConnection, sqliteAmbientConnectionPool, sqliteClientConnection, sqliteConnection, sqliteExecute, sqliteFormatter, sqliteMetadata, sqlitePool, sqlitePoolClientConnection, sqliteSQLExecutor, sqliteSingletonConnectionPool, sqliteTransaction, tableExists, toSqlitePoolOptions, useD1DumboDriver };
2440
2504
  //# sourceMappingURL=cloudflare.js.map