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

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 +216 -94
  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.21";
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) {
@@ -101793,6 +101793,16 @@ function safeJsonStringify(obj) {
101793
101793
  return val;
101794
101794
  });
101795
101795
  }
101796
+ var MAX_PUSH_SPREAD_ARGS = 8192;
101797
+ function appendToArray(target, source) {
101798
+ if (source.length <= MAX_PUSH_SPREAD_ARGS) {
101799
+ target.push(...source);
101800
+ return;
101801
+ }
101802
+ for (let i2 = 0; i2 < source.length; i2 += MAX_PUSH_SPREAD_ARGS) {
101803
+ target.push(...source.slice(i2, i2 + MAX_PUSH_SPREAD_ARGS));
101804
+ }
101805
+ }
101796
101806
  function normalizeJsonProtocolValues(result) {
101797
101807
  if (result === null) {
101798
101808
  return result;
@@ -101944,6 +101954,7 @@ function getErrorCode(err) {
101944
101954
  case "UniqueConstraintViolation":
101945
101955
  return "P2002";
101946
101956
  case "ForeignKeyConstraintViolation":
101957
+ case "RestrictViolation":
101947
101958
  return "P2003";
101948
101959
  case "InvalidInputValue":
101949
101960
  return "P2007";
@@ -102016,6 +102027,7 @@ function renderErrorMessage(err) {
102016
102027
  case "UniqueConstraintViolation":
102017
102028
  return `Unique constraint failed on the ${renderConstraint(err.cause.constraint)}`;
102018
102029
  case "ForeignKeyConstraintViolation":
102030
+ case "RestrictViolation":
102019
102031
  return `Foreign key constraint violated on the ${renderConstraint(err.cause.constraint)}`;
102020
102032
  case "UnsupportedNativeDataType":
102021
102033
  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\`.`;
@@ -102656,8 +102668,9 @@ function renderTemplateSql(fragments, placeholderFormat, params, argTypes) {
102656
102668
  if (fragment.type === "stringChunk") {
102657
102669
  continue;
102658
102670
  }
102659
- const length2 = flattenedParams.length;
102660
- const added = flattenedParams.push(...flattenedFragmentParams(fragment)) - length2;
102671
+ const fragmentParams = Array.from(flattenedFragmentParams(fragment));
102672
+ const added = fragmentParams.length;
102673
+ appendToArray(flattenedParams, fragmentParams);
102661
102674
  if (fragment.argType.arity === "tuple") {
102662
102675
  if (added % fragment.argType.elements.length !== 0) {
102663
102676
  throw new Error(
@@ -103199,7 +103212,7 @@ var QueryInterpreter = class _QueryInterpreter {
103199
103212
  if (results === void 0) {
103200
103213
  results = result;
103201
103214
  } else {
103202
- results.rows.push(...result.rows);
103215
+ appendToArray(results.rows, result.rows);
103203
103216
  results.lastInsertId = result.lastInsertId;
103204
103217
  }
103205
103218
  }
@@ -103579,6 +103592,14 @@ var InvalidTransactionIsolationLevelError = class extends TransactionManagerErro
103579
103592
  }
103580
103593
  };
103581
103594
  var MAX_CLOSED_TRANSACTIONS = 100;
103595
+ var CANCEL_ROLLBACK_GRACE_MS = 2e3;
103596
+ function trackStartingTransaction() {
103597
+ let markSettled;
103598
+ const settled = new Promise((resolve) => {
103599
+ markSettled = resolve;
103600
+ });
103601
+ return { abortController: new AbortController(), settled, markSettled };
103602
+ }
103582
103603
  var debug3 = Debug("prisma:client:transactionManager");
103583
103604
  var COMMIT_QUERY = () => ({ sql: "COMMIT", args: [], argTypes: [] });
103584
103605
  var ROLLBACK_QUERY = () => ({ sql: "ROLLBACK", args: [], argTypes: [] });
@@ -103598,6 +103619,9 @@ var TransactionManager = class {
103598
103619
  // List of last closed transactions. Max MAX_CLOSED_TRANSACTIONS entries.
103599
103620
  // Used to provide better error messages than a generic "transaction not found".
103600
103621
  closedTransactions = [];
103622
+ // Transactions that are still being started. Tracked separately so that
103623
+ // `cancelAllTransactions` can reach them: they are not in `transactions` yet.
103624
+ #startingTransactions = /* @__PURE__ */ new Set();
103601
103625
  driverAdapter;
103602
103626
  transactionOptions;
103603
103627
  tracingHelper;
@@ -103661,56 +103685,91 @@ var TransactionManager = class {
103661
103685
  return { id: existing.id };
103662
103686
  });
103663
103687
  }
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.");
103688
+ const starting = trackStartingTransaction();
103689
+ const { abortController } = starting;
103690
+ this.#startingTransactions.add(starting);
103691
+ let discarding;
103692
+ try {
103693
+ const transaction = {
103694
+ id: await randomUUID(),
103695
+ status: "waiting",
103696
+ timer: void 0,
103697
+ timeout: options.timeout,
103698
+ startedAt: Date.now(),
103699
+ transaction: void 0,
103700
+ operationQueue: Promise.resolve(),
103701
+ depth: 1,
103702
+ savepoints: [],
103703
+ savepointCounter: 0
103704
+ };
103705
+ if (abortController.signal.aborted) {
103706
+ throw new TransactionStartTimeoutError();
103707
+ }
103708
+ const startTimer = createTimeoutIfDefined(() => abortController.abort(), options.maxWait);
103709
+ startTimer?.unref?.();
103710
+ const startTransactionPromise = this.driverAdapter.startTransaction(options.isolationLevel).catch(rethrowAsUserFacing);
103711
+ transaction.transaction = await Promise.race([
103712
+ startTransactionPromise.finally(() => clearTimeout(startTimer)),
103713
+ once(abortController.signal, "abort").then(() => void 0)
103714
+ ]);
103715
+ this.transactions.set(transaction.id, transaction);
103716
+ switch (transaction.status) {
103717
+ case "waiting":
103718
+ if (abortController.signal.aborted) {
103719
+ transaction.transaction = void 0;
103720
+ discarding = this.#discardStartedTransaction(startTransactionPromise);
103721
+ await this.#closeTransaction(transaction, "timed_out");
103722
+ throw new TransactionStartTimeoutError();
103723
+ }
103724
+ transaction.status = "running";
103725
+ transaction.startedAt = Date.now();
103726
+ transaction.timer = this.#startTransactionTimeout(transaction.id, options.timeout);
103727
+ return { id: transaction.id };
103728
+ case "timed_out":
103729
+ case "running":
103730
+ case "committed":
103731
+ case "rolled_back":
103732
+ throw new TransactionInternalConsistencyError(
103733
+ `Transaction in invalid state ${transaction.status} although it just finished startup.`
103734
+ );
103735
+ default:
103736
+ return assertNever(transaction["status"], "Unknown transaction status.");
103737
+ }
103738
+ } finally {
103739
+ this.#startingTransactions.delete(starting);
103740
+ if (discarding) {
103741
+ void discarding.finally(starting.markSettled);
103742
+ } else {
103743
+ starting.markSettled();
103744
+ }
103745
+ }
103746
+ }
103747
+ /**
103748
+ * Rolls back a transaction whose start was abandoned, and releases its connection.
103749
+ *
103750
+ * The `startTransaction` promise may still be running in the background. If it eventually
103751
+ * succeeds, we need to roll back and release the connection to avoid leaking it and
103752
+ * exhausting the connection pool. For adapters that don't use phantom queries (e.g. pg/neon),
103753
+ * `rollback()` only releases the connection without sending SQL, so we send an explicit
103754
+ * ROLLBACK first; otherwise the connection returns to the pool mid-transaction because
103755
+ * `BEGIN` already ran on the wire during startup.
103756
+ *
103757
+ * Errors are only logged: the caller has already reported the failure that led here.
103758
+ */
103759
+ async #discardStartedTransaction(startTransactionPromise) {
103760
+ try {
103761
+ const tx = await startTransactionPromise;
103762
+ if (tx.options.usePhantomQuery) {
103763
+ await tx.rollback();
103764
+ } else {
103765
+ try {
103766
+ await tx.executeRaw(ROLLBACK_QUERY());
103767
+ } finally {
103768
+ await tx.rollback();
103769
+ }
103770
+ }
103771
+ } catch (e2) {
103772
+ debug3("error in discarded transaction:", e2);
103714
103773
  }
103715
103774
  }
103716
103775
  async commitTransaction(transactionId) {
@@ -103801,16 +103860,21 @@ var TransactionManager = class {
103801
103860
  return transaction;
103802
103861
  }
103803
103862
  async cancelAllTransactions() {
103804
- await Promise.allSettled(
103805
- [...this.transactions.values()].map(
103863
+ const starting = [...this.#startingTransactions];
103864
+ for (const { abortController } of starting) {
103865
+ abortController.abort();
103866
+ }
103867
+ await Promise.allSettled([
103868
+ ...[...this.transactions.values()].map(
103806
103869
  (tx) => this.#runSerialized(tx, async () => {
103807
103870
  const current = this.transactions.get(tx.id);
103808
103871
  if (current) {
103809
103872
  await this.#closeTransaction(current, "rolled_back");
103810
103873
  }
103811
103874
  })
103812
- )
103813
- );
103875
+ ),
103876
+ ...starting.map(({ settled }) => settleWithin(settled, CANCEL_ROLLBACK_GRACE_MS))
103877
+ ]);
103814
103878
  }
103815
103879
  #nextSavepointName(transaction) {
103816
103880
  return `prisma_sp_${transaction.savepointCounter++}`;
@@ -103963,6 +104027,14 @@ var TransactionManager = class {
103963
104027
  function createTimeoutIfDefined(cb, ms) {
103964
104028
  return ms !== void 0 ? setTimeout(cb, ms) : void 0;
103965
104029
  }
104030
+ function settleWithin(promise2, timeout) {
104031
+ let timer;
104032
+ const deadline = new Promise((resolve) => {
104033
+ timer = setTimeout(resolve, timeout);
104034
+ timer?.unref?.();
104035
+ });
104036
+ return Promise.race([promise2, deadline]).finally(() => clearTimeout(timer));
104037
+ }
103966
104038
 
103967
104039
  // ../../node_modules/.pnpm/hono@4.12.23/node_modules/hono/dist/compose.js
103968
104040
  var compose = (middleware, onError, onNotFound) => {
@@ -106465,7 +106537,7 @@ var MariaDbTransaction = class extends MariaDbQueryable {
106465
106537
  this.onError(err);
106466
106538
  } finally {
106467
106539
  this.cleanup?.();
106468
- await this.client.end();
106540
+ await releaseConnection(this.client);
106469
106541
  }
106470
106542
  }
106471
106543
  async rollback() {
@@ -106476,7 +106548,7 @@ var MariaDbTransaction = class extends MariaDbQueryable {
106476
106548
  this.onError(err);
106477
106549
  } finally {
106478
106550
  this.cleanup?.();
106479
- await this.client.end();
106551
+ await releaseConnection(this.client);
106480
106552
  }
106481
106553
  }
106482
106554
  async createSavepoint(name22) {
@@ -106490,10 +106562,11 @@ var MariaDbTransaction = class extends MariaDbQueryable {
106490
106562
  }
106491
106563
  };
106492
106564
  var PrismaMariaDbAdapter = class extends MariaDbQueryable {
106493
- constructor(client, capabilities, mariadbOptions) {
106565
+ constructor(client, capabilities, mariadbOptions, release) {
106494
106566
  super(client, mariadbOptions);
106495
106567
  this.capabilities = capabilities;
106496
106568
  this.mariadbOptions = mariadbOptions;
106569
+ this.release = release;
106497
106570
  }
106498
106571
  executeScript(_script) {
106499
106572
  throw new Error("Not implemented yet");
@@ -106517,7 +106590,7 @@ var PrismaMariaDbAdapter = class extends MariaDbQueryable {
106517
106590
  };
106518
106591
  conn.on("error", onError);
106519
106592
  const cleanup = () => {
106520
- conn.removeListener("error", onError);
106593
+ conn.off("error", onError);
106521
106594
  };
106522
106595
  try {
106523
106596
  const tx = new MariaDbTransaction(conn, this.mariadbOptions, options, cleanup);
@@ -106531,13 +106604,16 @@ var PrismaMariaDbAdapter = class extends MariaDbQueryable {
106531
106604
  await tx.conn.query({ sql: "BEGIN" }).catch(this.onError.bind(this));
106532
106605
  return tx;
106533
106606
  } catch (error44) {
106534
- await conn.end();
106535
- cleanup();
106607
+ try {
106608
+ cleanup();
106609
+ } finally {
106610
+ await releaseConnection(conn);
106611
+ }
106536
106612
  this.onError(error44);
106537
106613
  }
106538
106614
  }
106539
106615
  async dispose() {
106540
- await this.client.end();
106616
+ return this.release?.();
106541
106617
  }
106542
106618
  underlyingDriver() {
106543
106619
  return this.client;
@@ -106547,47 +106623,73 @@ var PrismaMariaDbAdapterFactory = class {
106547
106623
  provider = "mysql";
106548
106624
  adapterName = name;
106549
106625
  #capabilities;
106550
- #config;
106626
+ #poolOrConfig;
106551
106627
  #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
- }
106628
+ #externalPoolClaimed = false;
106629
+ /**
106630
+ * Accepts either connection settings for a pool the adapter creates and owns, or an existing
106631
+ * pool. Settings the adapter would normally apply to its own pool (such as defaulting
106632
+ * `prepareCacheLength` to 0) are not applied to an externally created pool.
106633
+ */
106634
+ constructor(poolOrConfig, options) {
106635
+ this.#poolOrConfig = isPool(poolOrConfig) ? { type: "pool", pool: poolOrConfig } : { type: "config", config: normalizeConfig(poolOrConfig) };
106571
106636
  this.#options = options;
106572
106637
  }
106573
106638
  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")) {
106639
+ const poolOrConfig = this.#poolOrConfig;
106640
+ const ownsPool = poolOrConfig.type === "config" || this.#options?.disposeExternalPool === true;
106641
+ if (poolOrConfig.type === "pool" && ownsPool) {
106642
+ if (this.#externalPoolClaimed) {
106579
106643
  throw new Error(
106580
- "error parsing connection string, format must be 'mariadb://[<user>[:<password>]@]<host>[:<port>]/[<db>[?<opt1>=<value1>[&<opt2>=<value2>]]]'"
106644
+ "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
106645
  );
106582
106646
  }
106583
- throw error44;
106647
+ this.#externalPoolClaimed = true;
106584
106648
  }
106649
+ const pool2 = poolOrConfig.type === "pool" ? poolOrConfig.pool : createPool2(poolOrConfig.config);
106585
106650
  if (this.#capabilities === void 0) {
106586
106651
  this.#capabilities = await getCapabilities(pool2);
106587
106652
  }
106588
- return new PrismaMariaDbAdapter(pool2, this.#capabilities, this.#options);
106653
+ return new PrismaMariaDbAdapter(pool2, this.#capabilities, this.#options, async () => {
106654
+ if (ownsPool) {
106655
+ await pool2.end();
106656
+ }
106657
+ });
106589
106658
  }
106590
106659
  };
106660
+ function isPool(poolOrConfig) {
106661
+ return typeof poolOrConfig === "object" && typeof poolOrConfig.getConnection === "function";
106662
+ }
106663
+ function normalizeConfig(config3) {
106664
+ if (typeof config3 === "string") {
106665
+ try {
106666
+ const url2 = new URL(config3);
106667
+ if (!url2.searchParams.has("prepareCacheLength")) {
106668
+ url2.searchParams.set("prepareCacheLength", "0");
106669
+ }
106670
+ return rewriteConnectionString(url2).toString();
106671
+ } catch {
106672
+ debug4("Failed to parse the connection string, passing it to the driver as-is");
106673
+ return config3;
106674
+ }
106675
+ }
106676
+ if (config3.prepareCacheLength === void 0) {
106677
+ return { ...config3, prepareCacheLength: 0 };
106678
+ }
106679
+ return config3;
106680
+ }
106681
+ function createPool2(config3) {
106682
+ try {
106683
+ return mariadb.createPool(config3);
106684
+ } catch (error44) {
106685
+ if (error44 instanceof Error && error44.message.startsWith("error parsing connection string")) {
106686
+ throw new Error(
106687
+ "error parsing connection string, format must be 'mariadb://[<user>[:<password>]@]<host>[:<port>]/[<db>[?<opt1>=<value1>[&<opt2>=<value2>]]]'"
106688
+ );
106689
+ }
106690
+ throw error44;
106691
+ }
106692
+ }
106591
106693
  async function getCapabilities(pool2) {
106592
106694
  const tag2 = "[js::getCapabilities]";
106593
106695
  try {
@@ -106624,6 +106726,14 @@ function rewriteConnectionString(url2) {
106624
106726
  }
106625
106727
  return url2;
106626
106728
  }
106729
+ async function releaseConnection(conn) {
106730
+ const poolConn = conn;
106731
+ if (typeof poolConn.release === "function") {
106732
+ await poolConn.release();
106733
+ } else {
106734
+ await conn.end();
106735
+ }
106736
+ }
106627
106737
 
106628
106738
  // ../../node_modules/.pnpm/async-mutex@0.5.0/node_modules/async-mutex/index.mjs
106629
106739
  var E_TIMEOUT = new Error("timeout while waiting for mutex to become available");
@@ -108079,6 +108189,18 @@ function mapDriverError3(error44) {
108079
108189
  constraint
108080
108190
  };
108081
108191
  }
108192
+ case "23001": {
108193
+ let constraint;
108194
+ if (error44.column) {
108195
+ constraint = { fields: [error44.column] };
108196
+ } else if (error44.constraint) {
108197
+ constraint = { index: error44.constraint };
108198
+ }
108199
+ return {
108200
+ kind: "RestrictViolation",
108201
+ constraint
108202
+ };
108203
+ }
108082
108204
  case "3D000":
108083
108205
  return {
108084
108206
  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.21",
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-pg": "7.10.0-dev.21",
23
+ "@prisma/adapter-mssql": "7.10.0-dev.21",
24
+ "@prisma/adapter-mariadb": "7.10.0-dev.21",
25
+ "@prisma/client-engine-runtime": "7.10.0-dev.21",
26
+ "@prisma/driver-adapter-utils": "7.10.0-dev.21"
27
27
  },
28
28
  "files": [
29
29
  "dist"