@prisma/client-engine-runtime 7.5.0-dev.5 → 7.5.0-dev.50

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.mjs CHANGED
@@ -119,7 +119,10 @@ function normalizeJsonProtocolValues(result) {
119
119
  function isTaggedValue(value) {
120
120
  return value !== null && typeof value == "object" && typeof value["$type"] === "string";
121
121
  }
122
- function normalizeTaggedValue({ $type, value }) {
122
+ function normalizeTaggedValue({
123
+ $type,
124
+ value
125
+ }) {
123
126
  switch ($type) {
124
127
  case "BigInt":
125
128
  return { $type, value: String(value) };
@@ -131,6 +134,12 @@ function normalizeTaggedValue({ $type, value }) {
131
134
  return { $type, value: String(new Decimal2(value)) };
132
135
  case "Json":
133
136
  return { $type, value: JSON.stringify(JSON.parse(value)) };
137
+ case "Raw":
138
+ return { $type, value };
139
+ case "FieldRef":
140
+ return { $type, value };
141
+ case "Enum":
142
+ return { $type, value };
134
143
  default:
135
144
  assertNever(value, "Unknown tagged value");
136
145
  }
@@ -142,12 +151,12 @@ function mapObjectValues(object, mapper) {
142
151
  }
143
152
  return result;
144
153
  }
145
- function deserializeJsonResponse(result) {
154
+ function deserializeJsonObject(result) {
146
155
  if (result === null) {
147
156
  return result;
148
157
  }
149
158
  if (Array.isArray(result)) {
150
- return result.map(deserializeJsonResponse);
159
+ return result.map(deserializeJsonObject);
151
160
  }
152
161
  if (typeof result === "object") {
153
162
  if (isTaggedValue(result)) {
@@ -156,7 +165,7 @@ function deserializeJsonResponse(result) {
156
165
  if (result.constructor !== null && result.constructor.name !== "Object") {
157
166
  return result;
158
167
  }
159
- return mapObjectValues(result, deserializeJsonResponse);
168
+ return mapObjectValues(result, deserializeJsonObject);
160
169
  }
161
170
  return result;
162
171
  }
@@ -174,6 +183,12 @@ function deserializeTaggedValue({ $type, value }) {
174
183
  return new Decimal2(value);
175
184
  case "Json":
176
185
  return JSON.parse(value);
186
+ case "Raw":
187
+ return value;
188
+ case "FieldRef":
189
+ throw new Error("FieldRef tagged values cannot be deserialized to JavaScript values");
190
+ case "Enum":
191
+ return value;
177
192
  default:
178
193
  assertNever(value, "Unknown tagged value");
179
194
  }
@@ -405,7 +420,7 @@ function resolveArgPlaceholders(args, placeholderValues) {
405
420
  function convertCompactedRows(rows, compiledBatch, placeholderValues = {}) {
406
421
  const keysPerRow = rows.map(
407
422
  (item) => compiledBatch.keys.reduce((acc, key) => {
408
- acc[key] = deserializeJsonResponse(item[key]);
423
+ acc[key] = deserializeJsonObject(item[key]);
409
424
  return acc;
410
425
  }, {})
411
426
  );
@@ -691,6 +706,9 @@ function normalizeDateTime(dt) {
691
706
  return dtWithTz;
692
707
  }
693
708
 
709
+ // src/interpreter/query-interpreter.ts
710
+ import { klona as klona2 } from "klona";
711
+
694
712
  // src/sql-commenter.ts
695
713
  import { klona } from "klona";
696
714
  function formatSqlComment(tags) {
@@ -974,8 +992,11 @@ function paginateSingleList(list, { cursor, skip, take }) {
974
992
  const end = take !== null ? start + take : list.length;
975
993
  return list.slice(start, end);
976
994
  }
977
- function getRecordKey(record, fields) {
978
- return JSON.stringify(fields.map((field) => record[field]));
995
+ function getRecordKey(record, fields, mappers) {
996
+ const array = fields.map(
997
+ (field, index) => mappers?.[index] ? record[field] !== null ? mappers[index](record[field]) : null : record[field]
998
+ );
999
+ return JSON.stringify(array);
979
1000
  }
980
1001
 
981
1002
  // src/query-plan.ts
@@ -1012,7 +1033,11 @@ function evaluateArg(arg, scope, generators) {
1012
1033
  if (found === void 0) {
1013
1034
  throw new Error(`Missing value for query variable ${arg.prisma__value.name}`);
1014
1035
  }
1015
- arg = found;
1036
+ if (arg.prisma__value.type === "DateTime" && typeof found === "string") {
1037
+ arg = new Date(found);
1038
+ } else {
1039
+ arg = found;
1040
+ }
1016
1041
  } else if (isPrismaValueGenerator(arg)) {
1017
1042
  const { name, args } = arg.prisma__value;
1018
1043
  const generator = generators[name];
@@ -1070,7 +1095,10 @@ function renderFragment(fragment, placeholderFormat, ctx) {
1070
1095
  case "stringChunk":
1071
1096
  return fragment.chunk;
1072
1097
  case "parameterTuple": {
1073
- const placeholders = fragment.value.length == 0 ? "NULL" : fragment.value.map(() => formatPlaceholder(placeholderFormat, ctx.placeholderNumber++)).join(",");
1098
+ const placeholders = fragment.value.length == 0 ? "NULL" : fragment.value.map(() => {
1099
+ const item = formatPlaceholder(placeholderFormat, ctx.placeholderNumber++);
1100
+ return `${fragment.itemPrefix}${item}${fragment.itemSuffix}`;
1101
+ }).join(fragment.itemSeparator);
1074
1102
  return `(${placeholders})`;
1075
1103
  }
1076
1104
  case "parameterTupleList": {
@@ -1429,7 +1457,7 @@ function doesSatisfyRule(data, rule) {
1429
1457
  }
1430
1458
  }
1431
1459
  function renderMessage(data, error) {
1432
- switch (error.error_identifier) {
1460
+ switch (error.errorIdentifier) {
1433
1461
  case "RELATION_VIOLATION":
1434
1462
  return `The change you are trying to make would violate the required relation '${error.context.relation}' between the \`${error.context.modelA}\` and \`${error.context.modelB}\` models.`;
1435
1463
  case "MISSING_RECORD":
@@ -1449,7 +1477,7 @@ function renderMessage(data, error) {
1449
1477
  }
1450
1478
  }
1451
1479
  function getErrorCode2(error) {
1452
- switch (error.error_identifier) {
1480
+ switch (error.errorIdentifier) {
1453
1481
  case "RELATION_VIOLATION":
1454
1482
  return "P2014";
1455
1483
  case "RECORDS_NOT_CONNECTED":
@@ -1564,7 +1592,7 @@ var QueryInterpreter = class _QueryInterpreter {
1564
1592
  sum += await this.#withQuerySpanAndEvent(
1565
1593
  commentedQuery,
1566
1594
  context.queryable,
1567
- () => context.queryable.executeRaw(commentedQuery).catch(
1595
+ () => context.queryable.executeRaw(cloneObject(commentedQuery)).catch(
1568
1596
  (err) => node.args.type === "rawSql" ? rethrowAsUserFacingRawError(err) : rethrowAsUserFacing(err)
1569
1597
  )
1570
1598
  );
@@ -1579,7 +1607,7 @@ var QueryInterpreter = class _QueryInterpreter {
1579
1607
  const result = await this.#withQuerySpanAndEvent(
1580
1608
  commentedQuery,
1581
1609
  context.queryable,
1582
- () => context.queryable.queryRaw(commentedQuery).catch(
1610
+ () => context.queryable.queryRaw(cloneObject(commentedQuery)).catch(
1583
1611
  (err) => node.args.type === "rawSql" ? rethrowAsUserFacingRawError(err) : rethrowAsUserFacing(err)
1584
1612
  )
1585
1613
  );
@@ -1631,7 +1659,7 @@ var QueryInterpreter = class _QueryInterpreter {
1631
1659
  childRecords: (await this.interpretNode(joinExpr.child, context)).value
1632
1660
  }))
1633
1661
  );
1634
- return { value: attachChildrenToParents(parent, children), lastInsertId };
1662
+ return { value: attachChildrenToParents(parent, children, node.args.canAssumeStrictEquality), lastInsertId };
1635
1663
  }
1636
1664
  case "transaction": {
1637
1665
  if (!context.transactionManager.enabled) {
@@ -1678,8 +1706,9 @@ var QueryInterpreter = class _QueryInterpreter {
1678
1706
  }
1679
1707
  case "process": {
1680
1708
  const { value, lastInsertId } = await this.interpretNode(node.args.expr, context);
1681
- evaluateProcessingParameters(node.args.operations, context.scope, context.generators);
1682
- return { value: processRecords(value, node.args.operations), lastInsertId };
1709
+ const ops = cloneObject(node.args.operations);
1710
+ evaluateProcessingParameters(ops, context.scope, context.generators);
1711
+ return { value: processRecords(value, ops), lastInsertId };
1683
1712
  }
1684
1713
  case "initializeRecord": {
1685
1714
  const { lastInsertId } = await this.interpretNode(node.args.expr, context);
@@ -1772,12 +1801,13 @@ function mapField2(value, field) {
1772
1801
  }
1773
1802
  return value;
1774
1803
  }
1775
- function attachChildrenToParents(parentRecords, children) {
1804
+ function attachChildrenToParents(parentRecords, children, canAssumeStrictEquality) {
1776
1805
  for (const { joinExpr, childRecords } of children) {
1777
1806
  const parentKeys = joinExpr.on.map(([k]) => k);
1778
1807
  const childKeys = joinExpr.on.map(([, k]) => k);
1779
1808
  const parentMap = {};
1780
- for (const parent of Array.isArray(parentRecords) ? parentRecords : [parentRecords]) {
1809
+ const parentArray = Array.isArray(parentRecords) ? parentRecords : [parentRecords];
1810
+ for (const parent of parentArray) {
1781
1811
  const parentRecord = asRecord(parent);
1782
1812
  const key = getRecordKey(parentRecord, parentKeys);
1783
1813
  if (!parentMap[key]) {
@@ -1790,11 +1820,12 @@ function attachChildrenToParents(parentRecords, children) {
1790
1820
  parentRecord[joinExpr.parentField] = [];
1791
1821
  }
1792
1822
  }
1823
+ const mappers = canAssumeStrictEquality ? void 0 : inferKeyCasts(parentArray, parentKeys);
1793
1824
  for (const childRecord of Array.isArray(childRecords) ? childRecords : [childRecords]) {
1794
1825
  if (childRecord === null) {
1795
1826
  continue;
1796
1827
  }
1797
- const key = getRecordKey(asRecord(childRecord), childKeys);
1828
+ const key = getRecordKey(asRecord(childRecord), childKeys, mappers);
1798
1829
  for (const parentRecord of parentMap[key] ?? []) {
1799
1830
  if (joinExpr.isRelationUnique) {
1800
1831
  parentRecord[joinExpr.parentField] = childRecord;
@@ -1806,6 +1837,40 @@ function attachChildrenToParents(parentRecords, children) {
1806
1837
  }
1807
1838
  return parentRecords;
1808
1839
  }
1840
+ function inferKeyCasts(rows, keys) {
1841
+ function getKeyCast(type) {
1842
+ switch (type) {
1843
+ case "number":
1844
+ return Number;
1845
+ case "string":
1846
+ return String;
1847
+ case "boolean":
1848
+ return Boolean;
1849
+ case "bigint":
1850
+ return BigInt;
1851
+ default:
1852
+ return;
1853
+ }
1854
+ }
1855
+ const keyCasts = Array.from({ length: keys.length });
1856
+ let keysFound = 0;
1857
+ for (const parent of rows) {
1858
+ const parentRecord = asRecord(parent);
1859
+ for (const [i, key] of keys.entries()) {
1860
+ if (parentRecord[key] !== null && keyCasts[i] === void 0) {
1861
+ const keyCast = getKeyCast(typeof parentRecord[key]);
1862
+ if (keyCast !== void 0) {
1863
+ keyCasts[i] = keyCast;
1864
+ }
1865
+ keysFound++;
1866
+ }
1867
+ }
1868
+ if (keysFound === keys.length) {
1869
+ break;
1870
+ }
1871
+ }
1872
+ return keyCasts;
1873
+ }
1809
1874
  function evalFieldInitializer(initializer, lastInsertId, scope, generators) {
1810
1875
  switch (initializer.type) {
1811
1876
  case "value":
@@ -1865,6 +1930,9 @@ function evaluateProcessingParameters(ops, scope, generators) {
1865
1930
  evaluateProcessingParameters(nested, scope, generators);
1866
1931
  }
1867
1932
  }
1933
+ function cloneObject(value) {
1934
+ return klona2(value);
1935
+ }
1868
1936
 
1869
1937
  // src/raw-json-protocol.ts
1870
1938
  import { Decimal as Decimal4 } from "@prisma/client-runtime-utils";
@@ -2021,13 +2089,42 @@ var TransactionManager = class {
2021
2089
  );
2022
2090
  }
2023
2091
  async #startTransactionImpl(options) {
2092
+ if (options.newTxId) {
2093
+ return await this.#withActiveTransactionLock(options.newTxId, "start", async (existing) => {
2094
+ if (existing.status !== "running") {
2095
+ throw new TransactionInternalConsistencyError(
2096
+ `Transaction in invalid state ${existing.status} when starting a nested transaction.`
2097
+ );
2098
+ }
2099
+ if (!existing.transaction) {
2100
+ throw new TransactionInternalConsistencyError(
2101
+ `Transaction missing underlying driver transaction when starting a nested transaction.`
2102
+ );
2103
+ }
2104
+ existing.depth += 1;
2105
+ const savepointName = this.#nextSavepointName(existing);
2106
+ existing.savepoints.push(savepointName);
2107
+ try {
2108
+ await this.#requiredCreateSavepoint(existing.transaction)(savepointName);
2109
+ } catch (e) {
2110
+ existing.depth -= 1;
2111
+ existing.savepoints.pop();
2112
+ throw e;
2113
+ }
2114
+ return { id: existing.id };
2115
+ });
2116
+ }
2024
2117
  const transaction = {
2025
2118
  id: await randomUUID(),
2026
2119
  status: "waiting",
2027
2120
  timer: void 0,
2028
2121
  timeout: options.timeout,
2029
2122
  startedAt: Date.now(),
2030
- transaction: void 0
2123
+ transaction: void 0,
2124
+ operationQueue: Promise.resolve(),
2125
+ depth: 1,
2126
+ savepoints: [],
2127
+ savepointCounter: 0
2031
2128
  };
2032
2129
  const abortController = new AbortController();
2033
2130
  const startTimer = createTimeoutIfDefined(() => abortController.abort(), options.maxWait);
@@ -2061,14 +2158,49 @@ var TransactionManager = class {
2061
2158
  }
2062
2159
  async commitTransaction(transactionId) {
2063
2160
  return await this.tracingHelper.runInChildSpan("commit_transaction", async () => {
2064
- const txw = this.#getActiveOrClosingTransaction(transactionId, "commit");
2065
- await this.#closeTransaction(txw, "committed");
2161
+ await this.#withActiveTransactionLock(transactionId, "commit", async (txw) => {
2162
+ if (txw.depth > 1) {
2163
+ if (!txw.transaction) throw new TransactionNotFoundError();
2164
+ const savepointName = txw.savepoints.at(-1);
2165
+ if (!savepointName) {
2166
+ throw new TransactionInternalConsistencyError(
2167
+ `Missing savepoint for nested commit. Depth: ${txw.depth}, transactionId: ${txw.id}`
2168
+ );
2169
+ }
2170
+ try {
2171
+ await this.#releaseSavepoint(txw.transaction, savepointName);
2172
+ } finally {
2173
+ txw.savepoints.pop();
2174
+ txw.depth -= 1;
2175
+ }
2176
+ return;
2177
+ }
2178
+ await this.#closeTransaction(txw, "committed");
2179
+ });
2066
2180
  });
2067
2181
  }
2068
2182
  async rollbackTransaction(transactionId) {
2069
2183
  return await this.tracingHelper.runInChildSpan("rollback_transaction", async () => {
2070
- const txw = this.#getActiveOrClosingTransaction(transactionId, "rollback");
2071
- await this.#closeTransaction(txw, "rolled_back");
2184
+ await this.#withActiveTransactionLock(transactionId, "rollback", async (txw) => {
2185
+ if (txw.depth > 1) {
2186
+ if (!txw.transaction) throw new TransactionNotFoundError();
2187
+ const savepointName = txw.savepoints.at(-1);
2188
+ if (!savepointName) {
2189
+ throw new TransactionInternalConsistencyError(
2190
+ `Missing savepoint for nested rollback. Depth: ${txw.depth}, transactionId: ${txw.id}`
2191
+ );
2192
+ }
2193
+ try {
2194
+ await this.#requiredRollbackToSavepoint(txw.transaction)(savepointName);
2195
+ await this.#releaseSavepoint(txw.transaction, savepointName);
2196
+ } finally {
2197
+ txw.savepoints.pop();
2198
+ txw.depth -= 1;
2199
+ }
2200
+ return;
2201
+ }
2202
+ await this.#closeTransaction(txw, "rolled_back");
2203
+ });
2072
2204
  });
2073
2205
  }
2074
2206
  async getTransaction(txInfo, operation) {
@@ -2112,22 +2244,90 @@ var TransactionManager = class {
2112
2244
  return transaction;
2113
2245
  }
2114
2246
  async cancelAllTransactions() {
2115
- await Promise.allSettled([...this.transactions.values()].map((tx) => this.#closeTransaction(tx, "rolled_back")));
2247
+ await Promise.allSettled(
2248
+ [...this.transactions.values()].map(
2249
+ (tx) => this.#runSerialized(tx, async () => {
2250
+ const current = this.transactions.get(tx.id);
2251
+ if (current) {
2252
+ await this.#closeTransaction(current, "rolled_back");
2253
+ }
2254
+ })
2255
+ )
2256
+ );
2257
+ }
2258
+ #nextSavepointName(transaction) {
2259
+ return `prisma_sp_${transaction.savepointCounter++}`;
2260
+ }
2261
+ #requiredCreateSavepoint(transaction) {
2262
+ if (transaction.createSavepoint) {
2263
+ return transaction.createSavepoint.bind(transaction);
2264
+ }
2265
+ throw new TransactionManagerError(
2266
+ `Nested transactions are not supported by adapter "${transaction.adapterName}" (${transaction.provider}): createSavepoint is not implemented.`
2267
+ );
2268
+ }
2269
+ #requiredRollbackToSavepoint(transaction) {
2270
+ if (transaction.rollbackToSavepoint) {
2271
+ return transaction.rollbackToSavepoint.bind(transaction);
2272
+ }
2273
+ throw new TransactionManagerError(
2274
+ `Nested transactions are not supported by adapter "${transaction.adapterName}" (${transaction.provider}): rollbackToSavepoint is not implemented.`
2275
+ );
2276
+ }
2277
+ async #releaseSavepoint(transaction, name) {
2278
+ if (transaction.releaseSavepoint) {
2279
+ await transaction.releaseSavepoint(name);
2280
+ }
2281
+ }
2282
+ #debugTransactionAlreadyClosedOnTimeout(transactionId) {
2283
+ debug("Transaction already committed or rolled back when timeout happened.", transactionId);
2116
2284
  }
2117
2285
  #startTransactionTimeout(transactionId, timeout) {
2118
2286
  const timeoutStartedAt = Date.now();
2119
2287
  const timer = createTimeoutIfDefined(async () => {
2120
2288
  debug("Transaction timed out.", { transactionId, timeoutStartedAt, timeout });
2121
2289
  const tx = this.transactions.get(transactionId);
2122
- if (tx && ["running", "waiting"].includes(tx.status)) {
2123
- await this.#closeTransaction(tx, "timed_out");
2124
- } else {
2125
- debug("Transaction already committed or rolled back when timeout happened.", transactionId);
2126
- }
2290
+ if (!tx) {
2291
+ this.#debugTransactionAlreadyClosedOnTimeout(transactionId);
2292
+ return;
2293
+ }
2294
+ await this.#runSerialized(tx, async () => {
2295
+ const current = this.transactions.get(transactionId);
2296
+ if (current && ["running", "waiting"].includes(current.status)) {
2297
+ await this.#closeTransaction(current, "timed_out");
2298
+ } else {
2299
+ this.#debugTransactionAlreadyClosedOnTimeout(transactionId);
2300
+ }
2301
+ });
2127
2302
  }, timeout);
2128
2303
  timer?.unref?.();
2129
2304
  return timer;
2130
2305
  }
2306
+ // Any operation that mutates or closes a transaction must run through this lock so
2307
+ // status/savepoint/depth checks and updates happen against a stable view of state.
2308
+ async #withActiveTransactionLock(transactionId, operation, callback) {
2309
+ const tx = this.#getActiveOrClosingTransaction(transactionId, operation);
2310
+ return await this.#runSerialized(tx, async () => {
2311
+ const current = this.#getActiveOrClosingTransaction(transactionId, operation);
2312
+ return await callback(current);
2313
+ });
2314
+ }
2315
+ // Serializes operations per transaction id to prevent interleaving across awaits.
2316
+ // This avoids races where one operation mutates savepoint/depth state while another
2317
+ // operation is suspended, which could otherwise corrupt cleanup logic.
2318
+ async #runSerialized(tx, callback) {
2319
+ const previousOperation = tx.operationQueue;
2320
+ let releaseOperationLock;
2321
+ tx.operationQueue = new Promise((resolve) => {
2322
+ releaseOperationLock = resolve;
2323
+ });
2324
+ await previousOperation;
2325
+ try {
2326
+ return await callback();
2327
+ } finally {
2328
+ releaseOperationLock();
2329
+ }
2330
+ }
2131
2331
  async #closeTransaction(tx, status) {
2132
2332
  const createClosingPromise = async () => {
2133
2333
  debug("Closing transaction.", { transactionId: tx.id, status });
@@ -2214,7 +2414,7 @@ export {
2214
2414
  UserFacingError,
2215
2415
  applySqlCommenters,
2216
2416
  convertCompactedRows,
2217
- deserializeJsonResponse,
2417
+ deserializeJsonObject,
2218
2418
  doKeysMatch,
2219
2419
  isDeepStrictEqual,
2220
2420
  isPrismaValueGenerator,
@@ -1,3 +1,3 @@
1
1
  import { InMemoryOps } from '../query-plan';
2
2
  export declare function processRecords(value: unknown, ops: InMemoryOps): unknown;
3
- export declare function getRecordKey(record: {}, fields: string[]): string;
3
+ export declare function getRecordKey(record: {}, fields: readonly string[], mappers?: ((value: unknown) => unknown)[]): string;
@@ -5,6 +5,7 @@ import { QueryPlanNode } from '../query-plan';
5
5
  import { type SchemaProvider } from '../schema';
6
6
  import { type TracingHelper } from '../tracing';
7
7
  import { type TransactionManager } from '../transaction-manager/transaction-manager';
8
+ import { DeepReadonly } from '../utils';
8
9
  import { Value } from './scope';
9
10
  export type QueryInterpreterTransactionManager = {
10
11
  enabled: true;
@@ -39,6 +40,6 @@ export declare class QueryInterpreter {
39
40
  provider?: SchemaProvider;
40
41
  connectionInfo?: ConnectionInfo;
41
42
  }): QueryInterpreter;
42
- run(queryPlan: QueryPlanNode, options: QueryRuntimeOptions): Promise<unknown>;
43
+ run(queryPlan: DeepReadonly<QueryPlanNode>, options: QueryRuntimeOptions): Promise<unknown>;
43
44
  private interpretNode;
44
45
  }
@@ -1,6 +1,7 @@
1
1
  import { SqlQuery } from '@prisma/driver-adapter-utils';
2
2
  import { type QueryPlanDbQuery } from '../query-plan';
3
+ import { DeepReadonly } from '../utils';
3
4
  import { GeneratorRegistrySnapshot } from './generators';
4
5
  import { ScopeBindings } from './scope';
5
- export declare function renderQuery(dbQuery: QueryPlanDbQuery, scope: ScopeBindings, generators: GeneratorRegistrySnapshot, maxChunkSize?: number): SqlQuery[];
6
+ export declare function renderQuery(dbQuery: DeepReadonly<QueryPlanDbQuery>, scope: ScopeBindings, generators: GeneratorRegistrySnapshot, maxChunkSize?: number): DeepReadonly<SqlQuery>[];
6
7
  export declare function evaluateArg(arg: unknown, scope: ScopeBindings, generators: GeneratorRegistrySnapshot): unknown;
@@ -1,3 +1,4 @@
1
1
  import { DataRule, ValidationError } from '../query-plan';
2
- export declare function performValidation(data: unknown, rules: DataRule[], error: ValidationError): void;
2
+ import { DeepReadonly } from '../utils';
3
+ export declare function performValidation(data: unknown, rules: DeepReadonly<DataRule[]>, error: ValidationError): void;
3
4
  export declare function doesSatisfyRule(data: unknown, rule: DataRule): boolean;
@@ -29,10 +29,14 @@ export type JsonTaggedValue = {
29
29
  $type: 'Json';
30
30
  value: string;
31
31
  };
32
- export type JsonInputTaggedValue = DateTaggedValue | DecimalTaggedValue | BytesTaggedValue | BigIntTaggedValue | FieldRefTaggedValue | JsonTaggedValue | EnumTaggedValue;
32
+ export type RawTaggedValue = {
33
+ $type: 'Raw';
34
+ value: unknown;
35
+ };
36
+ export type JsonInputTaggedValue = DateTaggedValue | DecimalTaggedValue | BytesTaggedValue | BigIntTaggedValue | FieldRefTaggedValue | JsonTaggedValue | EnumTaggedValue | RawTaggedValue;
33
37
  export type JsonOutputTaggedValue = DateTaggedValue | DecimalTaggedValue | BytesTaggedValue | BigIntTaggedValue | JsonTaggedValue;
34
38
  export type JsOutputValue = null | string | number | boolean | bigint | Uint8Array | Date | Decimal | JsOutputValue[] | {
35
39
  [key: string]: JsOutputValue;
36
40
  };
37
41
  export declare function normalizeJsonProtocolValues(result: unknown): unknown;
38
- export declare function deserializeJsonResponse(result: unknown): unknown;
42
+ export declare function deserializeJsonObject(result: unknown): unknown;
@@ -56,6 +56,9 @@ export type Fragment = {
56
56
  type: 'parameter';
57
57
  } | {
58
58
  type: 'parameterTuple';
59
+ itemPrefix: string;
60
+ itemSeparator: string;
61
+ itemSuffix: string;
59
62
  } | {
60
63
  type: 'parameterTupleList';
61
64
  itemPrefix: string;
@@ -121,6 +124,7 @@ export type QueryPlanNode = {
121
124
  args: {
122
125
  parent: QueryPlanNode;
123
126
  children: JoinExpression[];
127
+ canAssumeStrictEquality: boolean;
124
128
  };
125
129
  } | {
126
130
  type: 'mapField';
@@ -227,14 +231,14 @@ export type DataRule = {
227
231
  type: 'never';
228
232
  };
229
233
  export type ValidationError = {
230
- error_identifier: 'RELATION_VIOLATION';
234
+ errorIdentifier: 'RELATION_VIOLATION';
231
235
  context: {
232
236
  relation: string;
233
237
  modelA: string;
234
238
  modelB: string;
235
239
  };
236
240
  } | {
237
- error_identifier: 'MISSING_RELATED_RECORD';
241
+ errorIdentifier: 'MISSING_RELATED_RECORD';
238
242
  context: {
239
243
  model: string;
240
244
  relation: string;
@@ -243,24 +247,24 @@ export type ValidationError = {
243
247
  neededFor?: string;
244
248
  };
245
249
  } | {
246
- error_identifier: 'MISSING_RECORD';
250
+ errorIdentifier: 'MISSING_RECORD';
247
251
  context: {
248
252
  operation: string;
249
253
  };
250
254
  } | {
251
- error_identifier: 'INCOMPLETE_CONNECT_INPUT';
255
+ errorIdentifier: 'INCOMPLETE_CONNECT_INPUT';
252
256
  context: {
253
257
  expectedRows: number;
254
258
  };
255
259
  } | {
256
- error_identifier: 'INCOMPLETE_CONNECT_OUTPUT';
260
+ errorIdentifier: 'INCOMPLETE_CONNECT_OUTPUT';
257
261
  context: {
258
262
  expectedRows: number;
259
263
  relation: string;
260
264
  relationType: string;
261
265
  };
262
266
  } | {
263
- error_identifier: 'RECORDS_NOT_CONNECTED';
267
+ errorIdentifier: 'RECORDS_NOT_CONNECTED';
264
268
  context: {
265
269
  relation: string;
266
270
  parent: string;
package/dist/tracing.d.ts CHANGED
@@ -2,6 +2,7 @@ import { type Context, type Span, type SpanOptions } from '@opentelemetry/api';
2
2
  import type { SqlQuery } from '@prisma/driver-adapter-utils';
3
3
  import { QueryEvent } from './events';
4
4
  import type { SchemaProvider } from './schema';
5
+ import { DeepReadonly } from './utils';
5
6
  export type SpanCallback<R> = (span?: Span, context?: Context) => R;
6
7
  export type ExtendedSpanOptions = SpanOptions & {
7
8
  name: string;
@@ -13,7 +14,7 @@ export interface TracingHelper {
13
14
  export declare const noopTracingHelper: TracingHelper;
14
15
  export declare function providerToOtelSystem(provider: SchemaProvider): string;
15
16
  export declare function withQuerySpanAndEvent<T>({ query, tracingHelper, provider, onQuery, execute, }: {
16
- query: SqlQuery;
17
+ query: DeepReadonly<SqlQuery>;
17
18
  tracingHelper: TracingHelper;
18
19
  provider: SchemaProvider;
19
20
  onQuery?: (event: QueryEvent) => void;
@@ -3,6 +3,7 @@ export type Options = {
3
3
  maxWait?: number;
4
4
  timeout?: number;
5
5
  isolationLevel?: IsolationLevel;
6
+ newTxId?: string;
6
7
  };
7
8
  export type TransactionInfo = {
8
9
  id: string;
package/dist/utils.d.ts CHANGED
@@ -1,3 +1,9 @@
1
+ export type DeepReadonly<T> = T extends undefined | null | boolean | string | number | symbol | Function | Date ? T : T extends Array<infer U> ? ReadonlyArray<DeepReadonly<U>> : unknown extends T ? unknown : {
2
+ readonly [K in keyof T]: DeepReadonly<T[K]>;
3
+ };
4
+ export type DeepUnreadonly<T> = T extends undefined | null | boolean | string | number | symbol | Function | Date ? T : T extends ReadonlyArray<infer U> ? Array<DeepUnreadonly<U>> : unknown extends T ? unknown : {
5
+ -readonly [K in keyof T]: DeepUnreadonly<T[K]>;
6
+ };
1
7
  export declare function assertNever(_: never, message: string): never;
2
8
  /**
3
9
  * Checks if two objects are deeply equal, recursively checking all properties for strict equality.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@prisma/client-engine-runtime",
3
- "version": "7.5.0-dev.5",
3
+ "version": "7.5.0-dev.50",
4
4
  "description": "This package is intended for Prisma's internal use",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -31,19 +31,16 @@
31
31
  "nanoid": "5.1.5",
32
32
  "ulid": "3.0.0",
33
33
  "uuid": "11.1.0",
34
- "@prisma/client-runtime-utils": "7.5.0-dev.5",
35
- "@prisma/driver-adapter-utils": "7.5.0-dev.5",
36
- "@prisma/sqlcommenter": "7.5.0-dev.5",
37
- "@prisma/debug": "7.5.0-dev.5"
34
+ "@prisma/client-runtime-utils": "7.5.0-dev.50",
35
+ "@prisma/debug": "7.5.0-dev.50",
36
+ "@prisma/driver-adapter-utils": "7.5.0-dev.50",
37
+ "@prisma/sqlcommenter": "7.5.0-dev.50"
38
38
  },
39
39
  "devDependencies": {
40
40
  "@codspeed/benchmark.js-plugin": "4.0.0",
41
41
  "@types/benchmark": "2.1.5",
42
- "@types/jest": "29.5.14",
43
42
  "@types/node": "~20.19.24",
44
- "benchmark": "2.1.4",
45
- "jest": "29.7.0",
46
- "jest-junit": "16.0.0"
43
+ "benchmark": "2.1.4"
47
44
  },
48
45
  "files": [
49
46
  "dist"
@@ -52,6 +49,6 @@
52
49
  "scripts": {
53
50
  "dev": "DEV=true tsx helpers/build.ts",
54
51
  "build": "tsx helpers/build.ts",
55
- "test": "jest"
52
+ "test": "vitest run"
56
53
  }
57
54
  }