@prisma/client-engine-runtime 7.10.0-dev.9 → 7.10.0-integration-prisma7-project-closeout.8

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.
package/dist/index.js CHANGED
@@ -56,6 +56,12 @@ var import_client_runtime_utils2 = require("@prisma/client-runtime-utils");
56
56
 
57
57
  // src/utils.ts
58
58
  var import_client_runtime_utils = require("@prisma/client-runtime-utils");
59
+ function isUint8Array(value) {
60
+ return ArrayBuffer.isView(value) && Object.prototype.toString.call(value) === "[object Uint8Array]";
61
+ }
62
+ function isDate(value) {
63
+ return Object.prototype.toString.call(value) === "[object Date]";
64
+ }
59
65
  function assertNever(_, message) {
60
66
  throw new Error(message);
61
67
  }
@@ -74,11 +80,11 @@ function doKeysMatch(lhs, rhs) {
74
80
  const lhsDecimal = asDecimal(lhs[key]);
75
81
  const rhsDecimal = asDecimal(rhs[key]);
76
82
  return lhsDecimal && rhsDecimal && lhsDecimal.equals(rhsDecimal);
77
- } else if (lhs[key] instanceof Uint8Array || rhs[key] instanceof Uint8Array) {
83
+ } else if (isUint8Array(lhs[key]) || isUint8Array(rhs[key])) {
78
84
  const lhsBuffer = asBuffer(lhs[key]);
79
85
  const rhsBuffer = asBuffer(rhs[key]);
80
86
  return lhsBuffer && rhsBuffer && lhsBuffer.equals(rhsBuffer);
81
- } else if (lhs[key] instanceof Date || rhs[key] instanceof Date) {
87
+ } else if (isDate(lhs[key]) || isDate(rhs[key])) {
82
88
  return asDate(lhs[key])?.getTime() === asDate(rhs[key])?.getTime();
83
89
  } else if (typeof lhs[key] === "bigint" || typeof rhs[key] === "bigint") {
84
90
  return asBigInt(lhs[key]) === asBigInt(rhs[key]);
@@ -100,7 +106,7 @@ function asDecimal(value) {
100
106
  function asBuffer(value) {
101
107
  if (Buffer.isBuffer(value)) {
102
108
  return value;
103
- } else if (value instanceof Uint8Array) {
109
+ } else if (isUint8Array(value)) {
104
110
  return Buffer.from(value.buffer, value.byteOffset, value.byteLength);
105
111
  } else if (typeof value === "string") {
106
112
  return Buffer.from(value, "base64");
@@ -109,7 +115,7 @@ function asBuffer(value) {
109
115
  }
110
116
  }
111
117
  function asDate(value) {
112
- if (value instanceof Date) {
118
+ if (isDate(value)) {
113
119
  return value;
114
120
  } else if (typeof value === "string" || typeof value === "number") {
115
121
  return new Date(value);
@@ -145,6 +151,16 @@ function safeJsonStringify(obj) {
145
151
  return val;
146
152
  });
147
153
  }
154
+ var MAX_PUSH_SPREAD_ARGS = 8192;
155
+ function appendToArray(target, source) {
156
+ if (source.length <= MAX_PUSH_SPREAD_ARGS) {
157
+ target.push(...source);
158
+ return;
159
+ }
160
+ for (let i = 0; i < source.length; i += MAX_PUSH_SPREAD_ARGS) {
161
+ target.push(...source.slice(i, i + MAX_PUSH_SPREAD_ARGS));
162
+ }
163
+ }
148
164
 
149
165
  // src/json-protocol.ts
150
166
  function normalizeJsonProtocolValues(result) {
@@ -226,10 +242,8 @@ function deserializeTaggedValue({ $type, value }) {
226
242
  switch ($type) {
227
243
  case "BigInt":
228
244
  return BigInt(value);
229
- case "Bytes": {
230
- const { buffer, byteOffset, byteLength } = Buffer.from(value, "base64");
231
- return new Uint8Array(buffer, byteOffset, byteLength);
232
- }
245
+ case "Bytes":
246
+ return new Uint8Array(Buffer.from(value, "base64"));
233
247
  case "DateTime":
234
248
  return new Date(value);
235
249
  case "Decimal":
@@ -277,7 +291,11 @@ function rethrowAsUserFacing(error) {
277
291
  const code = getErrorCode(error);
278
292
  const message = renderErrorMessage(error);
279
293
  if (code !== void 0 && message !== void 0) {
280
- throw new UserFacingError(message, code, { driverAdapterError: error });
294
+ const meta = { driverAdapterError: error };
295
+ if (error.cause.kind === "UniqueConstraintViolation" && error.cause.table) {
296
+ meta.table = error.cause.table;
297
+ }
298
+ throw new UserFacingError(message, code, meta);
281
299
  }
282
300
  if (isGenericDatabaseErrorKind(error.cause.kind)) {
283
301
  throw buildUnmappedDatabaseUserFacingError(error);
@@ -343,6 +361,7 @@ function getErrorCode(err) {
343
361
  case "UniqueConstraintViolation":
344
362
  return "P2002";
345
363
  case "ForeignKeyConstraintViolation":
364
+ case "RestrictViolation":
346
365
  return "P2003";
347
366
  case "InvalidInputValue":
348
367
  return "P2007";
@@ -415,6 +434,7 @@ function renderErrorMessage(err) {
415
434
  case "UniqueConstraintViolation":
416
435
  return `Unique constraint failed on the ${renderConstraint(err.cause.constraint)}`;
417
436
  case "ForeignKeyConstraintViolation":
437
+ case "RestrictViolation":
418
438
  return `Foreign key constraint violated on the ${renderConstraint(err.cause.constraint)}`;
419
439
  case "UnsupportedNativeDataType":
420
440
  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\`.`;
@@ -691,7 +711,7 @@ function mapValue(value, columnName, scalarType, enums) {
691
711
  throw new DataMapperError(`Expected a boolean in column '${columnName}', got ${typeof value}: ${value}`);
692
712
  }
693
713
  }
694
- if (Array.isArray(value) || value instanceof Uint8Array) {
714
+ if (Array.isArray(value) || isUint8Array(value)) {
695
715
  for (const byte of value) {
696
716
  if (byte !== 0) return true;
697
717
  }
@@ -708,7 +728,7 @@ function mapValue(value, columnName, scalarType, enums) {
708
728
  if (typeof value === "string") {
709
729
  return { $type: "DateTime", value: normalizeDateTime(value) };
710
730
  }
711
- if (typeof value === "number" || value instanceof Date) {
731
+ if (typeof value === "number" || isDate(value)) {
712
732
  return { $type: "DateTime", value };
713
733
  }
714
734
  throw new DataMapperError(`Expected a date in column '${columnName}', got ${typeof value}: ${value}`);
@@ -739,7 +759,7 @@ function mapValue(value, columnName, scalarType, enums) {
739
759
  if (Array.isArray(value)) {
740
760
  return { $type: "Bytes", value: Buffer.from(value).toString("base64") };
741
761
  }
742
- if (value instanceof Uint8Array) {
762
+ if (isUint8Array(value)) {
743
763
  return { $type: "Bytes", value: Buffer.from(value).toString("base64") };
744
764
  }
745
765
  throw new DataMapperError(`Expected a byte array in column '${columnName}', got ${typeof value}: ${value}`);
@@ -787,6 +807,7 @@ function normalizeDateTime(dt) {
787
807
  }
788
808
 
789
809
  // src/interpreter/query-interpreter.ts
810
+ var import_debug = require("@prisma/debug");
790
811
  var import_klona2 = require("klona");
791
812
 
792
813
  // src/sql-commenter.ts
@@ -1148,8 +1169,9 @@ function renderTemplateSql(fragments, placeholderFormat, params, argTypes) {
1148
1169
  if (fragment.type === "stringChunk") {
1149
1170
  continue;
1150
1171
  }
1151
- const length = flattenedParams.length;
1152
- const added = flattenedParams.push(...flattenedFragmentParams(fragment)) - length;
1172
+ const fragmentParams = Array.from(flattenedFragmentParams(fragment));
1173
+ const added = fragmentParams.length;
1174
+ appendToArray(flattenedParams, fragmentParams);
1153
1175
  if (fragment.argType.arity === "tuple") {
1154
1176
  if (added % fragment.argType.elements.length !== 0) {
1155
1177
  throw new Error(
@@ -1578,6 +1600,7 @@ function getErrorCode2(error) {
1578
1600
  }
1579
1601
 
1580
1602
  // src/interpreter/query-interpreter.ts
1603
+ var debug = (0, import_debug.Debug)("prisma:client:queryInterpreter");
1581
1604
  var QueryInterpreter = class _QueryInterpreter {
1582
1605
  #onQuery;
1583
1606
  #generators = new GeneratorRegistry();
@@ -1612,17 +1635,27 @@ var QueryInterpreter = class _QueryInterpreter {
1612
1635
  });
1613
1636
  }
1614
1637
  async run(queryPlan, options) {
1615
- const { value } = await this.interpretNode(queryPlan, {
1616
- ...options,
1617
- generators: this.#generators.snapshot()
1618
- }).catch((e) => rethrowAsUserFacing(e));
1638
+ const generators = this.#generators.snapshot();
1639
+ const context = { ...options, generators };
1640
+ const purified = purifyQueryPlan(queryPlan, (node) => this.interpretNode(node, context))?.catch(
1641
+ (e) => rethrowAsUserFacing(e)
1642
+ );
1643
+ if (purified) {
1644
+ try {
1645
+ return this.#interpretPureNode(await purified, context.scope, generators).value;
1646
+ } catch (e) {
1647
+ rethrowAsUserFacing(e);
1648
+ }
1649
+ }
1650
+ const { value } = await this.interpretNode(queryPlan, context).catch((e) => rethrowAsUserFacing(e));
1619
1651
  return value;
1620
1652
  }
1621
1653
  async interpretNode(node, context) {
1622
1654
  switch (node.type) {
1623
1655
  case "value": {
1624
1656
  return {
1625
- value: evaluateArg(node.args, context.scope, context.generators)
1657
+ value: evaluateArg(node.args, context.scope, context.generators),
1658
+ lastInsertId: node.lastInsertId
1626
1659
  };
1627
1660
  }
1628
1661
  case "seq": {
@@ -1632,9 +1665,6 @@ var QueryInterpreter = class _QueryInterpreter {
1632
1665
  }
1633
1666
  return result ?? { value: void 0 };
1634
1667
  }
1635
- case "get": {
1636
- return { value: context.scope[node.args.name] };
1637
- }
1638
1668
  case "let": {
1639
1669
  const nestedScope = Object.create(context.scope);
1640
1670
  for (const binding of node.args.bindings) {
@@ -1643,15 +1673,6 @@ var QueryInterpreter = class _QueryInterpreter {
1643
1673
  }
1644
1674
  return this.interpretNode(node.args.expr, { ...context, scope: nestedScope });
1645
1675
  }
1646
- case "getFirstNonEmpty": {
1647
- for (const name of node.args.names) {
1648
- const value = context.scope[name];
1649
- if (!isEmpty(value)) {
1650
- return { value };
1651
- }
1652
- }
1653
- return { value: [] };
1654
- }
1655
1676
  case "concat": {
1656
1677
  const parts = await Promise.all(
1657
1678
  node.args.map((arg) => this.interpretNode(arg, context).then((res) => res.value))
@@ -1670,42 +1691,46 @@ var QueryInterpreter = class _QueryInterpreter {
1670
1691
  }
1671
1692
  case "execute": {
1672
1693
  const queries = renderQuery(node.args, context.scope, context.generators, this.#maxChunkSize());
1673
- let sum = 0;
1674
- for (const query of queries) {
1675
- const commentedQuery = applyComments(query, context.sqlCommenter);
1676
- sum += await this.#withQuerySpanAndEvent(
1677
- commentedQuery,
1678
- context.queryable,
1679
- () => context.queryable.executeRaw(cloneObject(commentedQuery)).catch(
1680
- (err) => node.args.type === "rawSql" ? rethrowAsUserFacingRawError(err) : rethrowAsUserFacing(err)
1681
- )
1682
- );
1683
- }
1684
- return { value: sum };
1694
+ return this.#withChunkTransaction(queries.length, context, async (context2) => {
1695
+ let sum = 0;
1696
+ for (const query of queries) {
1697
+ const commentedQuery = applyComments(query, context2.sqlCommenter);
1698
+ sum += await this.#withQuerySpanAndEvent(
1699
+ commentedQuery,
1700
+ context2.queryable,
1701
+ () => context2.queryable.executeRaw(cloneObject(commentedQuery)).catch(
1702
+ (err) => node.args.type === "rawSql" ? rethrowAsUserFacingRawError(err) : rethrowAsUserFacing(err)
1703
+ )
1704
+ );
1705
+ }
1706
+ return { value: sum };
1707
+ });
1685
1708
  }
1686
1709
  case "query": {
1687
1710
  const queries = renderQuery(node.args, context.scope, context.generators, this.#maxChunkSize());
1688
- let results;
1689
- for (const query of queries) {
1690
- const commentedQuery = applyComments(query, context.sqlCommenter);
1691
- const result = await this.#withQuerySpanAndEvent(
1692
- commentedQuery,
1693
- context.queryable,
1694
- () => context.queryable.queryRaw(cloneObject(commentedQuery)).catch(
1695
- (err) => node.args.type === "rawSql" ? rethrowAsUserFacingRawError(err) : rethrowAsUserFacing(err)
1696
- )
1697
- );
1698
- if (results === void 0) {
1699
- results = result;
1700
- } else {
1701
- results.rows.push(...result.rows);
1702
- results.lastInsertId = result.lastInsertId;
1711
+ return this.#withChunkTransaction(queries.length, context, async (context2) => {
1712
+ let results;
1713
+ for (const query of queries) {
1714
+ const commentedQuery = applyComments(query, context2.sqlCommenter);
1715
+ const result = await this.#withQuerySpanAndEvent(
1716
+ commentedQuery,
1717
+ context2.queryable,
1718
+ () => context2.queryable.queryRaw(cloneObject(commentedQuery)).catch(
1719
+ (err) => node.args.type === "rawSql" ? rethrowAsUserFacingRawError(err) : rethrowAsUserFacing(err)
1720
+ )
1721
+ );
1722
+ if (results === void 0) {
1723
+ results = result;
1724
+ } else {
1725
+ appendToArray(results.rows, result.rows);
1726
+ results.lastInsertId = result.lastInsertId;
1727
+ }
1703
1728
  }
1704
- }
1705
- return {
1706
- value: node.args.type === "rawSql" ? this.#rawSerializer(results) : this.#serializer(results),
1707
- lastInsertId: results?.lastInsertId
1708
- };
1729
+ return {
1730
+ value: node.args.type === "rawSql" ? this.#rawSerializer(results) : this.#serializer(results),
1731
+ lastInsertId: results?.lastInsertId
1732
+ };
1733
+ });
1709
1734
  }
1710
1735
  case "reverse": {
1711
1736
  const { value, lastInsertId } = await this.interpretNode(node.args, context);
@@ -1746,20 +1771,7 @@ var QueryInterpreter = class _QueryInterpreter {
1746
1771
  return { value: attachChildrenToParents(parent, children, node.args.canAssumeStrictEquality), lastInsertId };
1747
1772
  }
1748
1773
  case "transaction": {
1749
- if (!context.transactionManager.enabled) {
1750
- return this.interpretNode(node.args, context);
1751
- }
1752
- const transactionManager = context.transactionManager.manager;
1753
- const transactionInfo = await transactionManager.startInternalTransaction();
1754
- const transaction = await transactionManager.getTransaction(transactionInfo, "query");
1755
- try {
1756
- const value = await this.interpretNode(node.args, { ...context, queryable: transaction });
1757
- await transactionManager.commitTransaction(transactionInfo.id);
1758
- return value;
1759
- } catch (e) {
1760
- await transactionManager.rollbackTransaction(transactionInfo.id);
1761
- throw e;
1762
- }
1774
+ return this.#withInternalTransaction(context, (context2) => this.interpretNode(node.args, context2));
1763
1775
  }
1764
1776
  case "dataMap": {
1765
1777
  const { value, lastInsertId } = await this.interpretNode(node.args.expr, context);
@@ -1778,9 +1790,6 @@ var QueryInterpreter = class _QueryInterpreter {
1778
1790
  return await this.interpretNode(node.args.else, context);
1779
1791
  }
1780
1792
  }
1781
- case "unit": {
1782
- return { value: void 0 };
1783
- }
1784
1793
  case "diff": {
1785
1794
  const { value: from } = await this.interpretNode(node.args.from, context);
1786
1795
  const { value: to } = await this.interpretNode(node.args.to, context);
@@ -1810,10 +1819,185 @@ var QueryInterpreter = class _QueryInterpreter {
1810
1819
  }
1811
1820
  return { value: record, lastInsertId };
1812
1821
  }
1822
+ default:
1823
+ return this.#interpretPureNode(node, context.scope, context.generators);
1824
+ }
1825
+ }
1826
+ #interpretPureNode(node, scope, generators) {
1827
+ switch (node.type) {
1828
+ case "value": {
1829
+ return { value: evaluateArg(node.args, scope, generators), lastInsertId: node.lastInsertId };
1830
+ }
1831
+ case "seq": {
1832
+ let result;
1833
+ for (const arg of node.args) {
1834
+ result = this.#interpretPureNode(arg, scope, generators);
1835
+ }
1836
+ return result ?? { value: void 0 };
1837
+ }
1838
+ case "get": {
1839
+ return { value: scope[node.args.name] };
1840
+ }
1841
+ case "let": {
1842
+ const nestedScope = Object.create(scope);
1843
+ for (const binding of node.args.bindings) {
1844
+ const { value } = this.#interpretPureNode(binding.expr, nestedScope, generators);
1845
+ nestedScope[binding.name] = value;
1846
+ }
1847
+ return this.#interpretPureNode(node.args.expr, nestedScope, generators);
1848
+ }
1849
+ case "getFirstNonEmpty": {
1850
+ for (const name of node.args.names) {
1851
+ const value = scope[name];
1852
+ if (!isEmpty(value)) {
1853
+ return { value };
1854
+ }
1855
+ }
1856
+ return { value: [] };
1857
+ }
1858
+ case "concat": {
1859
+ const parts = node.args.map((arg) => this.#interpretPureNode(arg, scope, generators).value);
1860
+ return {
1861
+ value: parts.length > 0 ? parts.reduce((acc, part) => acc.concat(asList(part)), []) : []
1862
+ };
1863
+ }
1864
+ case "sum": {
1865
+ const parts = node.args.map((arg) => this.#interpretPureNode(arg, scope, generators).value);
1866
+ return {
1867
+ value: parts.length > 0 ? parts.reduce((acc, part) => asNumber2(acc) + asNumber2(part)) : 0
1868
+ };
1869
+ }
1870
+ case "reverse": {
1871
+ const { value, lastInsertId } = this.#interpretPureNode(node.args, scope, generators);
1872
+ return { value: Array.isArray(value) ? value.reverse() : value, lastInsertId };
1873
+ }
1874
+ case "unique": {
1875
+ const { value, lastInsertId } = this.#interpretPureNode(node.args, scope, generators);
1876
+ if (!Array.isArray(value)) {
1877
+ return { value, lastInsertId };
1878
+ }
1879
+ if (value.length > 1) {
1880
+ throw new Error(`Expected zero or one element, got ${value.length}`);
1881
+ }
1882
+ return { value: value[0] ?? null, lastInsertId };
1883
+ }
1884
+ case "required": {
1885
+ const { value, lastInsertId } = this.#interpretPureNode(node.args, scope, generators);
1886
+ if (isEmpty(value)) {
1887
+ throw new Error("Required value is empty");
1888
+ }
1889
+ return { value, lastInsertId };
1890
+ }
1891
+ case "mapField": {
1892
+ const { value, lastInsertId } = this.#interpretPureNode(node.args.records, scope, generators);
1893
+ return { value: mapField2(value, node.args.field), lastInsertId };
1894
+ }
1895
+ case "join": {
1896
+ const { value: parent, lastInsertId } = this.#interpretPureNode(node.args.parent, scope, generators);
1897
+ if (parent === null) {
1898
+ return { value: null, lastInsertId };
1899
+ }
1900
+ const children = node.args.children.map((joinExpr) => ({
1901
+ joinExpr,
1902
+ childRecords: this.#interpretPureNode(joinExpr.child, scope, generators).value
1903
+ }));
1904
+ return { value: attachChildrenToParents(parent, children, node.args.canAssumeStrictEquality), lastInsertId };
1905
+ }
1906
+ case "dataMap": {
1907
+ const { value, lastInsertId } = this.#interpretPureNode(node.args.expr, scope, generators);
1908
+ return { value: applyDataMap(value, node.args.structure, node.args.enums), lastInsertId };
1909
+ }
1910
+ case "validate": {
1911
+ const { value, lastInsertId } = this.#interpretPureNode(node.args.expr, scope, generators);
1912
+ performValidation(value, node.args.rules, node.args);
1913
+ return { value, lastInsertId };
1914
+ }
1915
+ case "if": {
1916
+ const { value } = this.#interpretPureNode(node.args.value, scope, generators);
1917
+ if (doesSatisfyRule(value, node.args.rule)) {
1918
+ return this.#interpretPureNode(node.args.then, scope, generators);
1919
+ } else {
1920
+ return this.#interpretPureNode(node.args.else, scope, generators);
1921
+ }
1922
+ }
1923
+ case "unit": {
1924
+ return { value: void 0 };
1925
+ }
1926
+ case "diff": {
1927
+ const { value: from } = this.#interpretPureNode(node.args.from, scope, generators);
1928
+ const { value: to } = this.#interpretPureNode(node.args.to, scope, generators);
1929
+ const keyGetter = (item) => item !== null ? getRecordKey(asRecord(item), node.args.fields) : null;
1930
+ const toSet = new Set(asList(to).map(keyGetter));
1931
+ return { value: asList(from).filter((item) => !toSet.has(keyGetter(item))) };
1932
+ }
1933
+ case "process": {
1934
+ const { value, lastInsertId } = this.#interpretPureNode(node.args.expr, scope, generators);
1935
+ const ops = cloneObject(node.args.operations);
1936
+ evaluateProcessingParameters(ops, scope, generators);
1937
+ return { value: processRecords(value, ops), lastInsertId };
1938
+ }
1939
+ case "initializeRecord": {
1940
+ const { lastInsertId } = this.#interpretPureNode(node.args.expr, scope, generators);
1941
+ const record = {};
1942
+ for (const [key, initializer] of Object.entries(node.args.fields)) {
1943
+ record[key] = evalFieldInitializer(initializer, lastInsertId, scope, generators);
1944
+ }
1945
+ return { value: record, lastInsertId };
1946
+ }
1947
+ case "mapRecord": {
1948
+ const { value, lastInsertId } = this.#interpretPureNode(node.args.expr, scope, generators);
1949
+ const record = value === null ? {} : asRecord(value);
1950
+ for (const [key, entry] of Object.entries(node.args.fields)) {
1951
+ record[key] = evalFieldOperation(entry, record[key], scope, generators);
1952
+ }
1953
+ return { value: record, lastInsertId };
1954
+ }
1813
1955
  default:
1814
1956
  assertNever(node, `Unexpected node type: ${node.type}`);
1815
1957
  }
1816
1958
  }
1959
+ /**
1960
+ * Runs the statements of a `query` or `execute` node via `fn`, wrapping them in a
1961
+ * transaction when a chunkable statement was split into multiple queries at render time,
1962
+ * so that a partially applied write cannot be observed or left behind if a later chunk
1963
+ * fails. A single statement is atomic on its own, so it runs on the current context.
1964
+ */
1965
+ #withChunkTransaction(statementCount, context, fn) {
1966
+ if (statementCount <= 1) {
1967
+ return fn(context);
1968
+ }
1969
+ return this.#withInternalTransaction(context, fn);
1970
+ }
1971
+ /**
1972
+ * Runs `fn` with a context whose queryable is guaranteed to be a transaction, starting a
1973
+ * new internal transaction and committing or rolling it back around the call.
1974
+ *
1975
+ * A disabled transaction manager means the queryable already is a transaction: executors
1976
+ * pass `{ enabled: false }` when the plan runs inside an interactive transaction, and the
1977
+ * context handed to `fn` carries it for the duration of an internal transaction. In that
1978
+ * case `fn` runs on the current context, since the statements it issues are already
1979
+ * covered by the surrounding transaction.
1980
+ */
1981
+ async #withInternalTransaction(context, fn) {
1982
+ if (!context.transactionManager.enabled) {
1983
+ return fn(context);
1984
+ }
1985
+ const transactionManager = context.transactionManager.manager;
1986
+ const transactionInfo = await transactionManager.startInternalTransaction();
1987
+ const transaction = await transactionManager.getTransaction(transactionInfo, "query");
1988
+ try {
1989
+ const result = await fn({ ...context, queryable: transaction, transactionManager: { enabled: false } });
1990
+ await transactionManager.commitTransaction(transactionInfo.id);
1991
+ return result;
1992
+ } catch (e) {
1993
+ try {
1994
+ await transactionManager.rollbackTransaction(transactionInfo.id);
1995
+ } catch (rollbackError) {
1996
+ debug("failed to roll back an internal transaction", rollbackError);
1997
+ }
1998
+ throw e;
1999
+ }
2000
+ }
1817
2001
  #maxChunkSize() {
1818
2002
  if (this.#connectionInfo?.maxBindValues !== void 0) {
1819
2003
  return this.#connectionInfo.maxBindValues;
@@ -1987,6 +2171,112 @@ function evalFieldOperation(op, value, scope, generators) {
1987
2171
  assertNever(op, `Unexpected field operation type: ${op["type"]}`);
1988
2172
  }
1989
2173
  }
2174
+ function purifyQueryPlan(node, evalNode) {
2175
+ const impureNode = findUniqueUnconditionalImpureNode(node);
2176
+ if (!impureNode) {
2177
+ return void 0;
2178
+ }
2179
+ return evalNode(impureNode).then((result) => {
2180
+ const evaluated = {
2181
+ type: "value",
2182
+ args: result.value,
2183
+ lastInsertId: result.lastInsertId
2184
+ };
2185
+ const purified = replaceImpureNode(node, impureNode, evaluated);
2186
+ if (!purified) {
2187
+ throw new Error("Could not substitute the evaluated impure node into the query plan");
2188
+ }
2189
+ return purified;
2190
+ });
2191
+ }
2192
+ function replaceImpureNode(node, target, replacement) {
2193
+ if (node === target) {
2194
+ return replacement;
2195
+ }
2196
+ switch (node.type) {
2197
+ case "seq":
2198
+ case "sum":
2199
+ case "concat": {
2200
+ for (let i = 0; i < node.args.length; i++) {
2201
+ const child = replaceImpureNode(node.args[i], target, replacement);
2202
+ if (child) {
2203
+ return { ...node, args: node.args.map((arg, j) => j === i ? child : arg) };
2204
+ }
2205
+ }
2206
+ return void 0;
2207
+ }
2208
+ case "dataMap":
2209
+ case "validate":
2210
+ case "initializeRecord":
2211
+ case "mapRecord":
2212
+ case "process": {
2213
+ const expr = replaceImpureNode(node.args.expr, target, replacement);
2214
+ return expr && { ...node, args: { ...node.args, expr } };
2215
+ }
2216
+ case "mapField": {
2217
+ const records = replaceImpureNode(node.args.records, target, replacement);
2218
+ return records && { ...node, args: { ...node.args, records } };
2219
+ }
2220
+ case "reverse":
2221
+ case "unique":
2222
+ case "required": {
2223
+ const args = replaceImpureNode(node.args, target, replacement);
2224
+ return args && { ...node, args };
2225
+ }
2226
+ default:
2227
+ return void 0;
2228
+ }
2229
+ }
2230
+ function findUniqueUnconditionalImpureNode(node) {
2231
+ switch (node.type) {
2232
+ case "query":
2233
+ case "execute":
2234
+ return node;
2235
+ case "seq":
2236
+ case "sum":
2237
+ case "concat": {
2238
+ let found = void 0;
2239
+ for (const child of node.args) {
2240
+ const childFound = findUniqueUnconditionalImpureNode(child);
2241
+ if (childFound === null) {
2242
+ return null;
2243
+ }
2244
+ if (childFound) {
2245
+ if (found) {
2246
+ return null;
2247
+ }
2248
+ found = childFound;
2249
+ }
2250
+ }
2251
+ return found;
2252
+ }
2253
+ case "dataMap":
2254
+ case "validate":
2255
+ case "initializeRecord":
2256
+ case "mapRecord":
2257
+ case "process":
2258
+ return findUniqueUnconditionalImpureNode(node.args.expr);
2259
+ case "mapField":
2260
+ return findUniqueUnconditionalImpureNode(node.args.records);
2261
+ case "reverse":
2262
+ case "unique":
2263
+ case "required":
2264
+ return findUniqueUnconditionalImpureNode(node.args);
2265
+ case "let":
2266
+ case "join":
2267
+ case "diff":
2268
+ case "if":
2269
+ case "transaction":
2270
+ return null;
2271
+ case "value":
2272
+ case "get":
2273
+ case "getFirstNonEmpty":
2274
+ case "unit":
2275
+ return void 0;
2276
+ default:
2277
+ assertNever(node, `Unexpected node type: ${node.type}`);
2278
+ }
2279
+ }
1990
2280
  function applyComments(query, sqlCommenter) {
1991
2281
  if (!sqlCommenter || sqlCommenter.plugins.length === 0) {
1992
2282
  return query;
@@ -2485,7 +2775,7 @@ function normalizeValue(type, value) {
2485
2775
  }
2486
2776
 
2487
2777
  // src/transaction-manager/transaction-manager.ts
2488
- var import_debug = require("@prisma/debug");
2778
+ var import_debug2 = require("@prisma/debug");
2489
2779
 
2490
2780
  // src/crypto.ts
2491
2781
  async function getCrypto() {
@@ -2561,7 +2851,7 @@ function trackStartingTransaction() {
2561
2851
  });
2562
2852
  return { abortController: new AbortController(), settled, markSettled };
2563
2853
  }
2564
- var debug = (0, import_debug.Debug)("prisma:client:transactionManager");
2854
+ var debug2 = (0, import_debug2.Debug)("prisma:client:transactionManager");
2565
2855
  var COMMIT_QUERY = () => ({ sql: "COMMIT", args: [], argTypes: [] });
2566
2856
  var ROLLBACK_QUERY = () => ({ sql: "ROLLBACK", args: [], argTypes: [] });
2567
2857
  var PHANTOM_COMMIT_QUERY = () => ({
@@ -2730,7 +3020,7 @@ var TransactionManager = class {
2730
3020
  }
2731
3021
  }
2732
3022
  } catch (e) {
2733
- debug("error in discarded transaction:", e);
3023
+ debug2("error in discarded transaction:", e);
2734
3024
  }
2735
3025
  }
2736
3026
  async commitTransaction(transactionId) {
@@ -2794,7 +3084,7 @@ var TransactionManager = class {
2794
3084
  if (!transaction) {
2795
3085
  const closedTransaction = this.closedTransactions.find((tx) => tx.id === transactionId);
2796
3086
  if (closedTransaction) {
2797
- debug("Transaction already closed.", { transactionId, status: closedTransaction.status });
3087
+ debug2("Transaction already closed.", { transactionId, status: closedTransaction.status });
2798
3088
  switch (closedTransaction.status) {
2799
3089
  case "closing":
2800
3090
  case "waiting":
@@ -2811,7 +3101,7 @@ var TransactionManager = class {
2811
3101
  });
2812
3102
  }
2813
3103
  } else {
2814
- debug(`Transaction not found.`, transactionId);
3104
+ debug2(`Transaction not found.`, transactionId);
2815
3105
  throw new TransactionNotFoundError();
2816
3106
  }
2817
3107
  }
@@ -2862,25 +3152,29 @@ var TransactionManager = class {
2862
3152
  }
2863
3153
  }
2864
3154
  #debugTransactionAlreadyClosedOnTimeout(transactionId) {
2865
- debug("Transaction already committed or rolled back when timeout happened.", transactionId);
3155
+ debug2("Transaction already committed or rolled back when timeout happened.", transactionId);
2866
3156
  }
2867
3157
  #startTransactionTimeout(transactionId, timeout) {
2868
3158
  const timeoutStartedAt = Date.now();
2869
3159
  const timer = createTimeoutIfDefined(async () => {
2870
- debug("Transaction timed out.", { transactionId, timeoutStartedAt, timeout });
2871
- const tx = this.transactions.get(transactionId);
2872
- if (!tx) {
2873
- this.#debugTransactionAlreadyClosedOnTimeout(transactionId);
2874
- return;
2875
- }
2876
- await this.#runSerialized(tx, async () => {
2877
- const current = this.transactions.get(transactionId);
2878
- if (current && ["running", "waiting"].includes(current.status)) {
2879
- await this.#closeTransaction(current, "timed_out");
2880
- } else {
3160
+ try {
3161
+ debug2("Transaction timed out.", { transactionId, timeoutStartedAt, timeout });
3162
+ const tx = this.transactions.get(transactionId);
3163
+ if (!tx) {
2881
3164
  this.#debugTransactionAlreadyClosedOnTimeout(transactionId);
3165
+ return;
2882
3166
  }
2883
- });
3167
+ await this.#runSerialized(tx, async () => {
3168
+ const current = this.transactions.get(transactionId);
3169
+ if (current && ["running", "waiting"].includes(current.status)) {
3170
+ await this.#closeTransaction(current, "timed_out");
3171
+ } else {
3172
+ this.#debugTransactionAlreadyClosedOnTimeout(transactionId);
3173
+ }
3174
+ });
3175
+ } catch (error) {
3176
+ debug2("Error while closing timed-out transaction.", { transactionId, error });
3177
+ }
2884
3178
  }, timeout);
2885
3179
  timer?.unref?.();
2886
3180
  return timer;
@@ -2912,7 +3206,7 @@ var TransactionManager = class {
2912
3206
  }
2913
3207
  async #closeTransaction(tx, status) {
2914
3208
  const createClosingPromise = async () => {
2915
- debug("Closing transaction.", { transactionId: tx.id, status });
3209
+ debug2("Closing transaction.", { transactionId: tx.id, status });
2916
3210
  try {
2917
3211
  if (tx.transaction && status === "committed") {
2918
3212
  if (tx.transaction.options.usePhantomQuery) {