@prisma/query-plan-executor 7.10.0-dev.2 → 7.10.0-dev.20

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 (2) hide show
  1. package/dist/index.js +202 -91
  2. package/package.json +6 -6
package/dist/index.js CHANGED
@@ -22009,7 +22009,7 @@ var require_promise = __commonJS({
22009
22009
  return Promise.reject(err);
22010
22010
  }
22011
22011
  };
22012
- module2.exports.createPool = function createPool2(opts) {
22012
+ module2.exports.createPool = function createPool3(opts) {
22013
22013
  const options = new PoolOptions(opts);
22014
22014
  const pool2 = new PoolPromise(options);
22015
22015
  pool2.on("error", (err) => {
@@ -93473,7 +93473,7 @@ __export(index_exports, {
93473
93473
  module.exports = __toCommonJS(index_exports);
93474
93474
 
93475
93475
  // package.json
93476
- var version = "7.10.0-dev.2";
93476
+ var version = "7.10.0-dev.20";
93477
93477
 
93478
93478
  // ../../node_modules/.pnpm/temporal-polyfill@0.3.0/node_modules/temporal-polyfill/chunks/internal.js
93479
93479
  function clampProp(e2, n2, t2, o2, r2) {
@@ -101944,6 +101944,7 @@ function getErrorCode(err) {
101944
101944
  case "UniqueConstraintViolation":
101945
101945
  return "P2002";
101946
101946
  case "ForeignKeyConstraintViolation":
101947
+ case "RestrictViolation":
101947
101948
  return "P2003";
101948
101949
  case "InvalidInputValue":
101949
101950
  return "P2007";
@@ -102016,6 +102017,7 @@ function renderErrorMessage(err) {
102016
102017
  case "UniqueConstraintViolation":
102017
102018
  return `Unique constraint failed on the ${renderConstraint(err.cause.constraint)}`;
102018
102019
  case "ForeignKeyConstraintViolation":
102020
+ case "RestrictViolation":
102019
102021
  return `Foreign key constraint violated on the ${renderConstraint(err.cause.constraint)}`;
102020
102022
  case "UnsupportedNativeDataType":
102021
102023
  return `Failed to deserialize column of type '${err.cause.type}'. If you're using $queryRaw and this column is explicitly marked as \`Unsupported\` in your Prisma schema, try casting this column to any supported Prisma type such as \`String\`.`;
@@ -103579,6 +103581,14 @@ var InvalidTransactionIsolationLevelError = class extends TransactionManagerErro
103579
103581
  }
103580
103582
  };
103581
103583
  var MAX_CLOSED_TRANSACTIONS = 100;
103584
+ var CANCEL_ROLLBACK_GRACE_MS = 2e3;
103585
+ function trackStartingTransaction() {
103586
+ let markSettled;
103587
+ const settled = new Promise((resolve) => {
103588
+ markSettled = resolve;
103589
+ });
103590
+ return { abortController: new AbortController(), settled, markSettled };
103591
+ }
103582
103592
  var debug3 = Debug("prisma:client:transactionManager");
103583
103593
  var COMMIT_QUERY = () => ({ sql: "COMMIT", args: [], argTypes: [] });
103584
103594
  var ROLLBACK_QUERY = () => ({ sql: "ROLLBACK", args: [], argTypes: [] });
@@ -103598,6 +103608,9 @@ var TransactionManager = class {
103598
103608
  // List of last closed transactions. Max MAX_CLOSED_TRANSACTIONS entries.
103599
103609
  // Used to provide better error messages than a generic "transaction not found".
103600
103610
  closedTransactions = [];
103611
+ // Transactions that are still being started. Tracked separately so that
103612
+ // `cancelAllTransactions` can reach them: they are not in `transactions` yet.
103613
+ #startingTransactions = /* @__PURE__ */ new Set();
103601
103614
  driverAdapter;
103602
103615
  transactionOptions;
103603
103616
  tracingHelper;
@@ -103661,56 +103674,91 @@ var TransactionManager = class {
103661
103674
  return { id: existing.id };
103662
103675
  });
103663
103676
  }
103664
- const transaction = {
103665
- id: await randomUUID(),
103666
- status: "waiting",
103667
- timer: void 0,
103668
- timeout: options.timeout,
103669
- startedAt: Date.now(),
103670
- transaction: void 0,
103671
- operationQueue: Promise.resolve(),
103672
- depth: 1,
103673
- savepoints: [],
103674
- savepointCounter: 0
103675
- };
103676
- const abortController = new AbortController();
103677
- const startTimer = createTimeoutIfDefined(() => abortController.abort(), options.maxWait);
103678
- startTimer?.unref?.();
103679
- const startTransactionPromise = this.driverAdapter.startTransaction(options.isolationLevel).catch(rethrowAsUserFacing);
103680
- transaction.transaction = await Promise.race([
103681
- startTransactionPromise.finally(() => clearTimeout(startTimer)),
103682
- once(abortController.signal, "abort").then(() => void 0)
103683
- ]);
103684
- this.transactions.set(transaction.id, transaction);
103685
- switch (transaction.status) {
103686
- case "waiting":
103687
- if (abortController.signal.aborted) {
103688
- void startTransactionPromise.then(async (tx) => {
103689
- if (tx.options.usePhantomQuery) {
103690
- await tx.rollback();
103691
- } else {
103692
- try {
103693
- await tx.executeRaw(ROLLBACK_QUERY());
103694
- } finally {
103695
- await tx.rollback();
103696
- }
103697
- }
103698
- }).catch((e2) => debug3("error in discarded transaction:", e2));
103699
- await this.#closeTransaction(transaction, "timed_out");
103700
- throw new TransactionStartTimeoutError();
103701
- }
103702
- transaction.status = "running";
103703
- transaction.timer = this.#startTransactionTimeout(transaction.id, options.timeout);
103704
- return { id: transaction.id };
103705
- case "timed_out":
103706
- case "running":
103707
- case "committed":
103708
- case "rolled_back":
103709
- throw new TransactionInternalConsistencyError(
103710
- `Transaction in invalid state ${transaction.status} although it just finished startup.`
103711
- );
103712
- default:
103713
- assertNever(transaction["status"], "Unknown transaction status.");
103677
+ const starting = trackStartingTransaction();
103678
+ const { abortController } = starting;
103679
+ this.#startingTransactions.add(starting);
103680
+ let discarding;
103681
+ try {
103682
+ const transaction = {
103683
+ id: await randomUUID(),
103684
+ status: "waiting",
103685
+ timer: void 0,
103686
+ timeout: options.timeout,
103687
+ startedAt: Date.now(),
103688
+ transaction: void 0,
103689
+ operationQueue: Promise.resolve(),
103690
+ depth: 1,
103691
+ savepoints: [],
103692
+ savepointCounter: 0
103693
+ };
103694
+ if (abortController.signal.aborted) {
103695
+ throw new TransactionStartTimeoutError();
103696
+ }
103697
+ const startTimer = createTimeoutIfDefined(() => abortController.abort(), options.maxWait);
103698
+ startTimer?.unref?.();
103699
+ const startTransactionPromise = this.driverAdapter.startTransaction(options.isolationLevel).catch(rethrowAsUserFacing);
103700
+ transaction.transaction = await Promise.race([
103701
+ startTransactionPromise.finally(() => clearTimeout(startTimer)),
103702
+ once(abortController.signal, "abort").then(() => void 0)
103703
+ ]);
103704
+ this.transactions.set(transaction.id, transaction);
103705
+ switch (transaction.status) {
103706
+ case "waiting":
103707
+ if (abortController.signal.aborted) {
103708
+ transaction.transaction = void 0;
103709
+ discarding = this.#discardStartedTransaction(startTransactionPromise);
103710
+ await this.#closeTransaction(transaction, "timed_out");
103711
+ throw new TransactionStartTimeoutError();
103712
+ }
103713
+ transaction.status = "running";
103714
+ transaction.startedAt = Date.now();
103715
+ transaction.timer = this.#startTransactionTimeout(transaction.id, options.timeout);
103716
+ return { id: transaction.id };
103717
+ case "timed_out":
103718
+ case "running":
103719
+ case "committed":
103720
+ case "rolled_back":
103721
+ throw new TransactionInternalConsistencyError(
103722
+ `Transaction in invalid state ${transaction.status} although it just finished startup.`
103723
+ );
103724
+ default:
103725
+ return assertNever(transaction["status"], "Unknown transaction status.");
103726
+ }
103727
+ } finally {
103728
+ this.#startingTransactions.delete(starting);
103729
+ if (discarding) {
103730
+ void discarding.finally(starting.markSettled);
103731
+ } else {
103732
+ starting.markSettled();
103733
+ }
103734
+ }
103735
+ }
103736
+ /**
103737
+ * Rolls back a transaction whose start was abandoned, and releases its connection.
103738
+ *
103739
+ * The `startTransaction` promise may still be running in the background. If it eventually
103740
+ * succeeds, we need to roll back and release the connection to avoid leaking it and
103741
+ * exhausting the connection pool. For adapters that don't use phantom queries (e.g. pg/neon),
103742
+ * `rollback()` only releases the connection without sending SQL, so we send an explicit
103743
+ * ROLLBACK first; otherwise the connection returns to the pool mid-transaction because
103744
+ * `BEGIN` already ran on the wire during startup.
103745
+ *
103746
+ * Errors are only logged: the caller has already reported the failure that led here.
103747
+ */
103748
+ async #discardStartedTransaction(startTransactionPromise) {
103749
+ try {
103750
+ const tx = await startTransactionPromise;
103751
+ if (tx.options.usePhantomQuery) {
103752
+ await tx.rollback();
103753
+ } else {
103754
+ try {
103755
+ await tx.executeRaw(ROLLBACK_QUERY());
103756
+ } finally {
103757
+ await tx.rollback();
103758
+ }
103759
+ }
103760
+ } catch (e2) {
103761
+ debug3("error in discarded transaction:", e2);
103714
103762
  }
103715
103763
  }
103716
103764
  async commitTransaction(transactionId) {
@@ -103801,16 +103849,21 @@ var TransactionManager = class {
103801
103849
  return transaction;
103802
103850
  }
103803
103851
  async cancelAllTransactions() {
103804
- await Promise.allSettled(
103805
- [...this.transactions.values()].map(
103852
+ const starting = [...this.#startingTransactions];
103853
+ for (const { abortController } of starting) {
103854
+ abortController.abort();
103855
+ }
103856
+ await Promise.allSettled([
103857
+ ...[...this.transactions.values()].map(
103806
103858
  (tx) => this.#runSerialized(tx, async () => {
103807
103859
  const current = this.transactions.get(tx.id);
103808
103860
  if (current) {
103809
103861
  await this.#closeTransaction(current, "rolled_back");
103810
103862
  }
103811
103863
  })
103812
- )
103813
- );
103864
+ ),
103865
+ ...starting.map(({ settled }) => settleWithin(settled, CANCEL_ROLLBACK_GRACE_MS))
103866
+ ]);
103814
103867
  }
103815
103868
  #nextSavepointName(transaction) {
103816
103869
  return `prisma_sp_${transaction.savepointCounter++}`;
@@ -103963,6 +104016,14 @@ var TransactionManager = class {
103963
104016
  function createTimeoutIfDefined(cb, ms) {
103964
104017
  return ms !== void 0 ? setTimeout(cb, ms) : void 0;
103965
104018
  }
104019
+ function settleWithin(promise2, timeout) {
104020
+ let timer;
104021
+ const deadline = new Promise((resolve) => {
104022
+ timer = setTimeout(resolve, timeout);
104023
+ timer?.unref?.();
104024
+ });
104025
+ return Promise.race([promise2, deadline]).finally(() => clearTimeout(timer));
104026
+ }
103966
104027
 
103967
104028
  // ../../node_modules/.pnpm/hono@4.12.23/node_modules/hono/dist/compose.js
103968
104029
  var compose = (middleware, onError, onNotFound) => {
@@ -106465,7 +106526,7 @@ var MariaDbTransaction = class extends MariaDbQueryable {
106465
106526
  this.onError(err);
106466
106527
  } finally {
106467
106528
  this.cleanup?.();
106468
- await this.client.end();
106529
+ await releaseConnection(this.client);
106469
106530
  }
106470
106531
  }
106471
106532
  async rollback() {
@@ -106476,7 +106537,7 @@ var MariaDbTransaction = class extends MariaDbQueryable {
106476
106537
  this.onError(err);
106477
106538
  } finally {
106478
106539
  this.cleanup?.();
106479
- await this.client.end();
106540
+ await releaseConnection(this.client);
106480
106541
  }
106481
106542
  }
106482
106543
  async createSavepoint(name22) {
@@ -106490,10 +106551,11 @@ var MariaDbTransaction = class extends MariaDbQueryable {
106490
106551
  }
106491
106552
  };
106492
106553
  var PrismaMariaDbAdapter = class extends MariaDbQueryable {
106493
- constructor(client, capabilities, mariadbOptions) {
106554
+ constructor(client, capabilities, mariadbOptions, release) {
106494
106555
  super(client, mariadbOptions);
106495
106556
  this.capabilities = capabilities;
106496
106557
  this.mariadbOptions = mariadbOptions;
106558
+ this.release = release;
106497
106559
  }
106498
106560
  executeScript(_script) {
106499
106561
  throw new Error("Not implemented yet");
@@ -106517,7 +106579,7 @@ var PrismaMariaDbAdapter = class extends MariaDbQueryable {
106517
106579
  };
106518
106580
  conn.on("error", onError);
106519
106581
  const cleanup = () => {
106520
- conn.removeListener("error", onError);
106582
+ conn.off("error", onError);
106521
106583
  };
106522
106584
  try {
106523
106585
  const tx = new MariaDbTransaction(conn, this.mariadbOptions, options, cleanup);
@@ -106531,13 +106593,16 @@ var PrismaMariaDbAdapter = class extends MariaDbQueryable {
106531
106593
  await tx.conn.query({ sql: "BEGIN" }).catch(this.onError.bind(this));
106532
106594
  return tx;
106533
106595
  } catch (error44) {
106534
- await conn.end();
106535
- cleanup();
106596
+ try {
106597
+ cleanup();
106598
+ } finally {
106599
+ await releaseConnection(conn);
106600
+ }
106536
106601
  this.onError(error44);
106537
106602
  }
106538
106603
  }
106539
106604
  async dispose() {
106540
- await this.client.end();
106605
+ return this.release?.();
106541
106606
  }
106542
106607
  underlyingDriver() {
106543
106608
  return this.client;
@@ -106547,47 +106612,73 @@ var PrismaMariaDbAdapterFactory = class {
106547
106612
  provider = "mysql";
106548
106613
  adapterName = name;
106549
106614
  #capabilities;
106550
- #config;
106615
+ #poolOrConfig;
106551
106616
  #options;
106552
- constructor(config3, options) {
106553
- if (typeof config3 === "string") {
106554
- try {
106555
- const url2 = new URL(config3);
106556
- if (!url2.searchParams.has("prepareCacheLength")) {
106557
- url2.searchParams.set("prepareCacheLength", "0");
106558
- }
106559
- this.#config = rewriteConnectionString(url2).toString();
106560
- } catch (error44) {
106561
- debug4("Error parsing connection string: %O", error44);
106562
- this.#config = config3;
106563
- }
106564
- } else {
106565
- if (config3.prepareCacheLength === void 0) {
106566
- this.#config = { ...config3, prepareCacheLength: 0 };
106567
- } else {
106568
- this.#config = config3;
106569
- }
106570
- }
106617
+ #externalPoolClaimed = false;
106618
+ /**
106619
+ * Accepts either connection settings for a pool the adapter creates and owns, or an existing
106620
+ * pool. Settings the adapter would normally apply to its own pool (such as defaulting
106621
+ * `prepareCacheLength` to 0) are not applied to an externally created pool.
106622
+ */
106623
+ constructor(poolOrConfig, options) {
106624
+ this.#poolOrConfig = isPool(poolOrConfig) ? { type: "pool", pool: poolOrConfig } : { type: "config", config: normalizeConfig(poolOrConfig) };
106571
106625
  this.#options = options;
106572
106626
  }
106573
106627
  async connect() {
106574
- let pool2;
106575
- try {
106576
- pool2 = mariadb.createPool(this.#config);
106577
- } catch (error44) {
106578
- if (error44 instanceof Error && error44.message.startsWith("error parsing connection string")) {
106628
+ const poolOrConfig = this.#poolOrConfig;
106629
+ const ownsPool = poolOrConfig.type === "config" || this.#options?.disposeExternalPool === true;
106630
+ if (poolOrConfig.type === "pool" && ownsPool) {
106631
+ if (this.#externalPoolClaimed) {
106579
106632
  throw new Error(
106580
- "error parsing connection string, format must be 'mariadb://[<user>[:<password>]@]<host>[:<port>]/[<db>[?<opt1>=<value1>[&<opt2>=<value2>]]]'"
106633
+ "connect() can only be called once when `disposeExternalPool` is true, because the adapter ends the pool it was given and cannot create a replacement from it. Either pass connection settings instead of a pool, or set `disposeExternalPool: false` and end the pool yourself once you no longer need the adapter."
106581
106634
  );
106582
106635
  }
106583
- throw error44;
106636
+ this.#externalPoolClaimed = true;
106584
106637
  }
106638
+ const pool2 = poolOrConfig.type === "pool" ? poolOrConfig.pool : createPool2(poolOrConfig.config);
106585
106639
  if (this.#capabilities === void 0) {
106586
106640
  this.#capabilities = await getCapabilities(pool2);
106587
106641
  }
106588
- return new PrismaMariaDbAdapter(pool2, this.#capabilities, this.#options);
106642
+ return new PrismaMariaDbAdapter(pool2, this.#capabilities, this.#options, async () => {
106643
+ if (ownsPool) {
106644
+ await pool2.end();
106645
+ }
106646
+ });
106589
106647
  }
106590
106648
  };
106649
+ function isPool(poolOrConfig) {
106650
+ return typeof poolOrConfig === "object" && typeof poolOrConfig.getConnection === "function";
106651
+ }
106652
+ function normalizeConfig(config3) {
106653
+ if (typeof config3 === "string") {
106654
+ try {
106655
+ const url2 = new URL(config3);
106656
+ if (!url2.searchParams.has("prepareCacheLength")) {
106657
+ url2.searchParams.set("prepareCacheLength", "0");
106658
+ }
106659
+ return rewriteConnectionString(url2).toString();
106660
+ } catch {
106661
+ debug4("Failed to parse the connection string, passing it to the driver as-is");
106662
+ return config3;
106663
+ }
106664
+ }
106665
+ if (config3.prepareCacheLength === void 0) {
106666
+ return { ...config3, prepareCacheLength: 0 };
106667
+ }
106668
+ return config3;
106669
+ }
106670
+ function createPool2(config3) {
106671
+ try {
106672
+ return mariadb.createPool(config3);
106673
+ } catch (error44) {
106674
+ if (error44 instanceof Error && error44.message.startsWith("error parsing connection string")) {
106675
+ throw new Error(
106676
+ "error parsing connection string, format must be 'mariadb://[<user>[:<password>]@]<host>[:<port>]/[<db>[?<opt1>=<value1>[&<opt2>=<value2>]]]'"
106677
+ );
106678
+ }
106679
+ throw error44;
106680
+ }
106681
+ }
106591
106682
  async function getCapabilities(pool2) {
106592
106683
  const tag2 = "[js::getCapabilities]";
106593
106684
  try {
@@ -106624,6 +106715,14 @@ function rewriteConnectionString(url2) {
106624
106715
  }
106625
106716
  return url2;
106626
106717
  }
106718
+ async function releaseConnection(conn) {
106719
+ const poolConn = conn;
106720
+ if (typeof poolConn.release === "function") {
106721
+ await poolConn.release();
106722
+ } else {
106723
+ await conn.end();
106724
+ }
106725
+ }
106627
106726
 
106628
106727
  // ../../node_modules/.pnpm/async-mutex@0.5.0/node_modules/async-mutex/index.mjs
106629
106728
  var E_TIMEOUT = new Error("timeout while waiting for mutex to become available");
@@ -108079,6 +108178,18 @@ function mapDriverError3(error44) {
108079
108178
  constraint
108080
108179
  };
108081
108180
  }
108181
+ case "23001": {
108182
+ let constraint;
108183
+ if (error44.column) {
108184
+ constraint = { fields: [error44.column] };
108185
+ } else if (error44.constraint) {
108186
+ constraint = { index: error44.constraint };
108187
+ }
108188
+ return {
108189
+ kind: "RestrictViolation",
108190
+ constraint
108191
+ };
108192
+ }
108082
108193
  case "3D000":
108083
108194
  return {
108084
108195
  kind: "DatabaseDoesNotExist",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@prisma/query-plan-executor",
3
- "version": "7.10.0-dev.2",
3
+ "version": "7.10.0-dev.20",
4
4
  "description": "This package is intended for Prisma's internal use",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -19,11 +19,11 @@
19
19
  "hono": "^4.12.23",
20
20
  "temporal-polyfill": "0.3.0",
21
21
  "zod": "4.1.3",
22
- "@prisma/adapter-pg": "7.10.0-dev.2",
23
- "@prisma/adapter-mariadb": "7.10.0-dev.2",
24
- "@prisma/adapter-mssql": "7.10.0-dev.2",
25
- "@prisma/client-engine-runtime": "7.10.0-dev.2",
26
- "@prisma/driver-adapter-utils": "7.10.0-dev.2"
22
+ "@prisma/adapter-mssql": "7.10.0-dev.20",
23
+ "@prisma/adapter-mariadb": "7.10.0-dev.20",
24
+ "@prisma/driver-adapter-utils": "7.10.0-dev.20",
25
+ "@prisma/client-engine-runtime": "7.10.0-dev.20",
26
+ "@prisma/adapter-pg": "7.10.0-dev.20"
27
27
  },
28
28
  "files": [
29
29
  "dist"