@prisma/client-engine-runtime 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.
- package/dist/index.js +130 -60
- package/dist/index.mjs +130 -60
- package/dist/interpreter/query-interpreter.test.d.ts +1 -0
- package/dist/utils.d.ts +5 -0
- package/package.json +9 -9
package/dist/index.js
CHANGED
|
@@ -145,6 +145,16 @@ function safeJsonStringify(obj) {
|
|
|
145
145
|
return val;
|
|
146
146
|
});
|
|
147
147
|
}
|
|
148
|
+
var MAX_PUSH_SPREAD_ARGS = 8192;
|
|
149
|
+
function appendToArray(target, source) {
|
|
150
|
+
if (source.length <= MAX_PUSH_SPREAD_ARGS) {
|
|
151
|
+
target.push(...source);
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
for (let i = 0; i < source.length; i += MAX_PUSH_SPREAD_ARGS) {
|
|
155
|
+
target.push(...source.slice(i, i + MAX_PUSH_SPREAD_ARGS));
|
|
156
|
+
}
|
|
157
|
+
}
|
|
148
158
|
|
|
149
159
|
// src/json-protocol.ts
|
|
150
160
|
function normalizeJsonProtocolValues(result) {
|
|
@@ -226,10 +236,8 @@ function deserializeTaggedValue({ $type, value }) {
|
|
|
226
236
|
switch ($type) {
|
|
227
237
|
case "BigInt":
|
|
228
238
|
return BigInt(value);
|
|
229
|
-
case "Bytes":
|
|
230
|
-
|
|
231
|
-
return new Uint8Array(buffer, byteOffset, byteLength);
|
|
232
|
-
}
|
|
239
|
+
case "Bytes":
|
|
240
|
+
return new Uint8Array(Buffer.from(value, "base64"));
|
|
233
241
|
case "DateTime":
|
|
234
242
|
return new Date(value);
|
|
235
243
|
case "Decimal":
|
|
@@ -343,6 +351,7 @@ function getErrorCode(err) {
|
|
|
343
351
|
case "UniqueConstraintViolation":
|
|
344
352
|
return "P2002";
|
|
345
353
|
case "ForeignKeyConstraintViolation":
|
|
354
|
+
case "RestrictViolation":
|
|
346
355
|
return "P2003";
|
|
347
356
|
case "InvalidInputValue":
|
|
348
357
|
return "P2007";
|
|
@@ -415,6 +424,7 @@ function renderErrorMessage(err) {
|
|
|
415
424
|
case "UniqueConstraintViolation":
|
|
416
425
|
return `Unique constraint failed on the ${renderConstraint(err.cause.constraint)}`;
|
|
417
426
|
case "ForeignKeyConstraintViolation":
|
|
427
|
+
case "RestrictViolation":
|
|
418
428
|
return `Foreign key constraint violated on the ${renderConstraint(err.cause.constraint)}`;
|
|
419
429
|
case "UnsupportedNativeDataType":
|
|
420
430
|
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\`.`;
|
|
@@ -1148,8 +1158,9 @@ function renderTemplateSql(fragments, placeholderFormat, params, argTypes) {
|
|
|
1148
1158
|
if (fragment.type === "stringChunk") {
|
|
1149
1159
|
continue;
|
|
1150
1160
|
}
|
|
1151
|
-
const
|
|
1152
|
-
const added =
|
|
1161
|
+
const fragmentParams = Array.from(flattenedFragmentParams(fragment));
|
|
1162
|
+
const added = fragmentParams.length;
|
|
1163
|
+
appendToArray(flattenedParams, fragmentParams);
|
|
1153
1164
|
if (fragment.argType.arity === "tuple") {
|
|
1154
1165
|
if (added % fragment.argType.elements.length !== 0) {
|
|
1155
1166
|
throw new Error(
|
|
@@ -1698,7 +1709,7 @@ var QueryInterpreter = class _QueryInterpreter {
|
|
|
1698
1709
|
if (results === void 0) {
|
|
1699
1710
|
results = result;
|
|
1700
1711
|
} else {
|
|
1701
|
-
results.rows
|
|
1712
|
+
appendToArray(results.rows, result.rows);
|
|
1702
1713
|
results.lastInsertId = result.lastInsertId;
|
|
1703
1714
|
}
|
|
1704
1715
|
}
|
|
@@ -2553,6 +2564,14 @@ var InvalidTransactionIsolationLevelError = class extends TransactionManagerErro
|
|
|
2553
2564
|
|
|
2554
2565
|
// src/transaction-manager/transaction-manager.ts
|
|
2555
2566
|
var MAX_CLOSED_TRANSACTIONS = 100;
|
|
2567
|
+
var CANCEL_ROLLBACK_GRACE_MS = 2e3;
|
|
2568
|
+
function trackStartingTransaction() {
|
|
2569
|
+
let markSettled;
|
|
2570
|
+
const settled = new Promise((resolve) => {
|
|
2571
|
+
markSettled = resolve;
|
|
2572
|
+
});
|
|
2573
|
+
return { abortController: new AbortController(), settled, markSettled };
|
|
2574
|
+
}
|
|
2556
2575
|
var debug = (0, import_debug.Debug)("prisma:client:transactionManager");
|
|
2557
2576
|
var COMMIT_QUERY = () => ({ sql: "COMMIT", args: [], argTypes: [] });
|
|
2558
2577
|
var ROLLBACK_QUERY = () => ({ sql: "ROLLBACK", args: [], argTypes: [] });
|
|
@@ -2572,6 +2591,9 @@ var TransactionManager = class {
|
|
|
2572
2591
|
// List of last closed transactions. Max MAX_CLOSED_TRANSACTIONS entries.
|
|
2573
2592
|
// Used to provide better error messages than a generic "transaction not found".
|
|
2574
2593
|
closedTransactions = [];
|
|
2594
|
+
// Transactions that are still being started. Tracked separately so that
|
|
2595
|
+
// `cancelAllTransactions` can reach them: they are not in `transactions` yet.
|
|
2596
|
+
#startingTransactions = /* @__PURE__ */ new Set();
|
|
2575
2597
|
driverAdapter;
|
|
2576
2598
|
transactionOptions;
|
|
2577
2599
|
tracingHelper;
|
|
@@ -2635,56 +2657,91 @@ var TransactionManager = class {
|
|
|
2635
2657
|
return { id: existing.id };
|
|
2636
2658
|
});
|
|
2637
2659
|
}
|
|
2638
|
-
const
|
|
2639
|
-
|
|
2640
|
-
|
|
2641
|
-
|
|
2642
|
-
|
|
2643
|
-
|
|
2644
|
-
|
|
2645
|
-
|
|
2646
|
-
|
|
2647
|
-
|
|
2648
|
-
|
|
2649
|
-
|
|
2650
|
-
|
|
2651
|
-
|
|
2652
|
-
|
|
2653
|
-
|
|
2654
|
-
|
|
2655
|
-
|
|
2656
|
-
|
|
2657
|
-
|
|
2658
|
-
|
|
2659
|
-
|
|
2660
|
-
|
|
2661
|
-
|
|
2662
|
-
|
|
2663
|
-
|
|
2664
|
-
|
|
2665
|
-
|
|
2666
|
-
|
|
2667
|
-
|
|
2668
|
-
|
|
2669
|
-
|
|
2670
|
-
|
|
2671
|
-
|
|
2672
|
-
|
|
2673
|
-
|
|
2674
|
-
|
|
2660
|
+
const starting = trackStartingTransaction();
|
|
2661
|
+
const { abortController } = starting;
|
|
2662
|
+
this.#startingTransactions.add(starting);
|
|
2663
|
+
let discarding;
|
|
2664
|
+
try {
|
|
2665
|
+
const transaction = {
|
|
2666
|
+
id: await randomUUID(),
|
|
2667
|
+
status: "waiting",
|
|
2668
|
+
timer: void 0,
|
|
2669
|
+
timeout: options.timeout,
|
|
2670
|
+
startedAt: Date.now(),
|
|
2671
|
+
transaction: void 0,
|
|
2672
|
+
operationQueue: Promise.resolve(),
|
|
2673
|
+
depth: 1,
|
|
2674
|
+
savepoints: [],
|
|
2675
|
+
savepointCounter: 0
|
|
2676
|
+
};
|
|
2677
|
+
if (abortController.signal.aborted) {
|
|
2678
|
+
throw new TransactionStartTimeoutError();
|
|
2679
|
+
}
|
|
2680
|
+
const startTimer = createTimeoutIfDefined(() => abortController.abort(), options.maxWait);
|
|
2681
|
+
startTimer?.unref?.();
|
|
2682
|
+
const startTransactionPromise = this.driverAdapter.startTransaction(options.isolationLevel).catch(rethrowAsUserFacing);
|
|
2683
|
+
transaction.transaction = await Promise.race([
|
|
2684
|
+
startTransactionPromise.finally(() => clearTimeout(startTimer)),
|
|
2685
|
+
once(abortController.signal, "abort").then(() => void 0)
|
|
2686
|
+
]);
|
|
2687
|
+
this.transactions.set(transaction.id, transaction);
|
|
2688
|
+
switch (transaction.status) {
|
|
2689
|
+
case "waiting":
|
|
2690
|
+
if (abortController.signal.aborted) {
|
|
2691
|
+
transaction.transaction = void 0;
|
|
2692
|
+
discarding = this.#discardStartedTransaction(startTransactionPromise);
|
|
2693
|
+
await this.#closeTransaction(transaction, "timed_out");
|
|
2694
|
+
throw new TransactionStartTimeoutError();
|
|
2695
|
+
}
|
|
2696
|
+
transaction.status = "running";
|
|
2697
|
+
transaction.startedAt = Date.now();
|
|
2698
|
+
transaction.timer = this.#startTransactionTimeout(transaction.id, options.timeout);
|
|
2699
|
+
return { id: transaction.id };
|
|
2700
|
+
case "timed_out":
|
|
2701
|
+
case "running":
|
|
2702
|
+
case "committed":
|
|
2703
|
+
case "rolled_back":
|
|
2704
|
+
throw new TransactionInternalConsistencyError(
|
|
2705
|
+
`Transaction in invalid state ${transaction.status} although it just finished startup.`
|
|
2706
|
+
);
|
|
2707
|
+
default:
|
|
2708
|
+
return assertNever(transaction["status"], "Unknown transaction status.");
|
|
2709
|
+
}
|
|
2710
|
+
} finally {
|
|
2711
|
+
this.#startingTransactions.delete(starting);
|
|
2712
|
+
if (discarding) {
|
|
2713
|
+
void discarding.finally(starting.markSettled);
|
|
2714
|
+
} else {
|
|
2715
|
+
starting.markSettled();
|
|
2716
|
+
}
|
|
2717
|
+
}
|
|
2718
|
+
}
|
|
2719
|
+
/**
|
|
2720
|
+
* Rolls back a transaction whose start was abandoned, and releases its connection.
|
|
2721
|
+
*
|
|
2722
|
+
* The `startTransaction` promise may still be running in the background. If it eventually
|
|
2723
|
+
* succeeds, we need to roll back and release the connection to avoid leaking it and
|
|
2724
|
+
* exhausting the connection pool. For adapters that don't use phantom queries (e.g. pg/neon),
|
|
2725
|
+
* `rollback()` only releases the connection without sending SQL, so we send an explicit
|
|
2726
|
+
* ROLLBACK first; otherwise the connection returns to the pool mid-transaction because
|
|
2727
|
+
* `BEGIN` already ran on the wire during startup.
|
|
2728
|
+
*
|
|
2729
|
+
* Errors are only logged: the caller has already reported the failure that led here.
|
|
2730
|
+
*/
|
|
2731
|
+
async #discardStartedTransaction(startTransactionPromise) {
|
|
2732
|
+
try {
|
|
2733
|
+
const tx = await startTransactionPromise;
|
|
2734
|
+
if (tx.options.usePhantomQuery) {
|
|
2735
|
+
await tx.rollback();
|
|
2736
|
+
} else {
|
|
2737
|
+
try {
|
|
2738
|
+
await tx.executeRaw(ROLLBACK_QUERY());
|
|
2739
|
+
} finally {
|
|
2740
|
+
await tx.rollback();
|
|
2675
2741
|
}
|
|
2676
|
-
|
|
2677
|
-
|
|
2678
|
-
|
|
2679
|
-
case "timed_out":
|
|
2680
|
-
case "running":
|
|
2681
|
-
case "committed":
|
|
2682
|
-
case "rolled_back":
|
|
2683
|
-
throw new TransactionInternalConsistencyError(
|
|
2684
|
-
`Transaction in invalid state ${transaction.status} although it just finished startup.`
|
|
2685
|
-
);
|
|
2686
|
-
default:
|
|
2687
|
-
assertNever(transaction["status"], "Unknown transaction status.");
|
|
2742
|
+
}
|
|
2743
|
+
} catch (e) {
|
|
2744
|
+
debug("error in discarded transaction:", e);
|
|
2688
2745
|
}
|
|
2689
2746
|
}
|
|
2690
2747
|
async commitTransaction(transactionId) {
|
|
@@ -2775,16 +2832,21 @@ var TransactionManager = class {
|
|
|
2775
2832
|
return transaction;
|
|
2776
2833
|
}
|
|
2777
2834
|
async cancelAllTransactions() {
|
|
2778
|
-
|
|
2779
|
-
|
|
2835
|
+
const starting = [...this.#startingTransactions];
|
|
2836
|
+
for (const { abortController } of starting) {
|
|
2837
|
+
abortController.abort();
|
|
2838
|
+
}
|
|
2839
|
+
await Promise.allSettled([
|
|
2840
|
+
...[...this.transactions.values()].map(
|
|
2780
2841
|
(tx) => this.#runSerialized(tx, async () => {
|
|
2781
2842
|
const current = this.transactions.get(tx.id);
|
|
2782
2843
|
if (current) {
|
|
2783
2844
|
await this.#closeTransaction(current, "rolled_back");
|
|
2784
2845
|
}
|
|
2785
2846
|
})
|
|
2786
|
-
)
|
|
2787
|
-
|
|
2847
|
+
),
|
|
2848
|
+
...starting.map(({ settled }) => settleWithin(settled, CANCEL_ROLLBACK_GRACE_MS))
|
|
2849
|
+
]);
|
|
2788
2850
|
}
|
|
2789
2851
|
#nextSavepointName(transaction) {
|
|
2790
2852
|
return `prisma_sp_${transaction.savepointCounter++}`;
|
|
@@ -2937,6 +2999,14 @@ var TransactionManager = class {
|
|
|
2937
2999
|
function createTimeoutIfDefined(cb, ms) {
|
|
2938
3000
|
return ms !== void 0 ? setTimeout(cb, ms) : void 0;
|
|
2939
3001
|
}
|
|
3002
|
+
function settleWithin(promise, timeout) {
|
|
3003
|
+
let timer;
|
|
3004
|
+
const deadline = new Promise((resolve) => {
|
|
3005
|
+
timer = setTimeout(resolve, timeout);
|
|
3006
|
+
timer?.unref?.();
|
|
3007
|
+
});
|
|
3008
|
+
return Promise.race([promise, deadline]).finally(() => clearTimeout(timer));
|
|
3009
|
+
}
|
|
2940
3010
|
// Annotate the CommonJS export names for ESM import in node:
|
|
2941
3011
|
0 && (module.exports = {
|
|
2942
3012
|
DataMapperError,
|
package/dist/index.mjs
CHANGED
|
@@ -92,6 +92,16 @@ function safeJsonStringify(obj) {
|
|
|
92
92
|
return val;
|
|
93
93
|
});
|
|
94
94
|
}
|
|
95
|
+
var MAX_PUSH_SPREAD_ARGS = 8192;
|
|
96
|
+
function appendToArray(target, source) {
|
|
97
|
+
if (source.length <= MAX_PUSH_SPREAD_ARGS) {
|
|
98
|
+
target.push(...source);
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
for (let i = 0; i < source.length; i += MAX_PUSH_SPREAD_ARGS) {
|
|
102
|
+
target.push(...source.slice(i, i + MAX_PUSH_SPREAD_ARGS));
|
|
103
|
+
}
|
|
104
|
+
}
|
|
95
105
|
|
|
96
106
|
// src/json-protocol.ts
|
|
97
107
|
function normalizeJsonProtocolValues(result) {
|
|
@@ -173,10 +183,8 @@ function deserializeTaggedValue({ $type, value }) {
|
|
|
173
183
|
switch ($type) {
|
|
174
184
|
case "BigInt":
|
|
175
185
|
return BigInt(value);
|
|
176
|
-
case "Bytes":
|
|
177
|
-
|
|
178
|
-
return new Uint8Array(buffer, byteOffset, byteLength);
|
|
179
|
-
}
|
|
186
|
+
case "Bytes":
|
|
187
|
+
return new Uint8Array(Buffer.from(value, "base64"));
|
|
180
188
|
case "DateTime":
|
|
181
189
|
return new Date(value);
|
|
182
190
|
case "Decimal":
|
|
@@ -290,6 +298,7 @@ function getErrorCode(err) {
|
|
|
290
298
|
case "UniqueConstraintViolation":
|
|
291
299
|
return "P2002";
|
|
292
300
|
case "ForeignKeyConstraintViolation":
|
|
301
|
+
case "RestrictViolation":
|
|
293
302
|
return "P2003";
|
|
294
303
|
case "InvalidInputValue":
|
|
295
304
|
return "P2007";
|
|
@@ -362,6 +371,7 @@ function renderErrorMessage(err) {
|
|
|
362
371
|
case "UniqueConstraintViolation":
|
|
363
372
|
return `Unique constraint failed on the ${renderConstraint(err.cause.constraint)}`;
|
|
364
373
|
case "ForeignKeyConstraintViolation":
|
|
374
|
+
case "RestrictViolation":
|
|
365
375
|
return `Foreign key constraint violated on the ${renderConstraint(err.cause.constraint)}`;
|
|
366
376
|
case "UnsupportedNativeDataType":
|
|
367
377
|
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\`.`;
|
|
@@ -1095,8 +1105,9 @@ function renderTemplateSql(fragments, placeholderFormat, params, argTypes) {
|
|
|
1095
1105
|
if (fragment.type === "stringChunk") {
|
|
1096
1106
|
continue;
|
|
1097
1107
|
}
|
|
1098
|
-
const
|
|
1099
|
-
const added =
|
|
1108
|
+
const fragmentParams = Array.from(flattenedFragmentParams(fragment));
|
|
1109
|
+
const added = fragmentParams.length;
|
|
1110
|
+
appendToArray(flattenedParams, fragmentParams);
|
|
1100
1111
|
if (fragment.argType.arity === "tuple") {
|
|
1101
1112
|
if (added % fragment.argType.elements.length !== 0) {
|
|
1102
1113
|
throw new Error(
|
|
@@ -1645,7 +1656,7 @@ var QueryInterpreter = class _QueryInterpreter {
|
|
|
1645
1656
|
if (results === void 0) {
|
|
1646
1657
|
results = result;
|
|
1647
1658
|
} else {
|
|
1648
|
-
results.rows
|
|
1659
|
+
appendToArray(results.rows, result.rows);
|
|
1649
1660
|
results.lastInsertId = result.lastInsertId;
|
|
1650
1661
|
}
|
|
1651
1662
|
}
|
|
@@ -2500,6 +2511,14 @@ var InvalidTransactionIsolationLevelError = class extends TransactionManagerErro
|
|
|
2500
2511
|
|
|
2501
2512
|
// src/transaction-manager/transaction-manager.ts
|
|
2502
2513
|
var MAX_CLOSED_TRANSACTIONS = 100;
|
|
2514
|
+
var CANCEL_ROLLBACK_GRACE_MS = 2e3;
|
|
2515
|
+
function trackStartingTransaction() {
|
|
2516
|
+
let markSettled;
|
|
2517
|
+
const settled = new Promise((resolve) => {
|
|
2518
|
+
markSettled = resolve;
|
|
2519
|
+
});
|
|
2520
|
+
return { abortController: new AbortController(), settled, markSettled };
|
|
2521
|
+
}
|
|
2503
2522
|
var debug = Debug("prisma:client:transactionManager");
|
|
2504
2523
|
var COMMIT_QUERY = () => ({ sql: "COMMIT", args: [], argTypes: [] });
|
|
2505
2524
|
var ROLLBACK_QUERY = () => ({ sql: "ROLLBACK", args: [], argTypes: [] });
|
|
@@ -2519,6 +2538,9 @@ var TransactionManager = class {
|
|
|
2519
2538
|
// List of last closed transactions. Max MAX_CLOSED_TRANSACTIONS entries.
|
|
2520
2539
|
// Used to provide better error messages than a generic "transaction not found".
|
|
2521
2540
|
closedTransactions = [];
|
|
2541
|
+
// Transactions that are still being started. Tracked separately so that
|
|
2542
|
+
// `cancelAllTransactions` can reach them: they are not in `transactions` yet.
|
|
2543
|
+
#startingTransactions = /* @__PURE__ */ new Set();
|
|
2522
2544
|
driverAdapter;
|
|
2523
2545
|
transactionOptions;
|
|
2524
2546
|
tracingHelper;
|
|
@@ -2582,56 +2604,91 @@ var TransactionManager = class {
|
|
|
2582
2604
|
return { id: existing.id };
|
|
2583
2605
|
});
|
|
2584
2606
|
}
|
|
2585
|
-
const
|
|
2586
|
-
|
|
2587
|
-
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
|
|
2596
|
-
|
|
2597
|
-
|
|
2598
|
-
|
|
2599
|
-
|
|
2600
|
-
|
|
2601
|
-
|
|
2602
|
-
|
|
2603
|
-
|
|
2604
|
-
|
|
2605
|
-
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
|
|
2611
|
-
|
|
2612
|
-
|
|
2613
|
-
|
|
2614
|
-
|
|
2615
|
-
|
|
2616
|
-
|
|
2617
|
-
|
|
2618
|
-
|
|
2619
|
-
|
|
2620
|
-
|
|
2621
|
-
|
|
2607
|
+
const starting = trackStartingTransaction();
|
|
2608
|
+
const { abortController } = starting;
|
|
2609
|
+
this.#startingTransactions.add(starting);
|
|
2610
|
+
let discarding;
|
|
2611
|
+
try {
|
|
2612
|
+
const transaction = {
|
|
2613
|
+
id: await randomUUID(),
|
|
2614
|
+
status: "waiting",
|
|
2615
|
+
timer: void 0,
|
|
2616
|
+
timeout: options.timeout,
|
|
2617
|
+
startedAt: Date.now(),
|
|
2618
|
+
transaction: void 0,
|
|
2619
|
+
operationQueue: Promise.resolve(),
|
|
2620
|
+
depth: 1,
|
|
2621
|
+
savepoints: [],
|
|
2622
|
+
savepointCounter: 0
|
|
2623
|
+
};
|
|
2624
|
+
if (abortController.signal.aborted) {
|
|
2625
|
+
throw new TransactionStartTimeoutError();
|
|
2626
|
+
}
|
|
2627
|
+
const startTimer = createTimeoutIfDefined(() => abortController.abort(), options.maxWait);
|
|
2628
|
+
startTimer?.unref?.();
|
|
2629
|
+
const startTransactionPromise = this.driverAdapter.startTransaction(options.isolationLevel).catch(rethrowAsUserFacing);
|
|
2630
|
+
transaction.transaction = await Promise.race([
|
|
2631
|
+
startTransactionPromise.finally(() => clearTimeout(startTimer)),
|
|
2632
|
+
once(abortController.signal, "abort").then(() => void 0)
|
|
2633
|
+
]);
|
|
2634
|
+
this.transactions.set(transaction.id, transaction);
|
|
2635
|
+
switch (transaction.status) {
|
|
2636
|
+
case "waiting":
|
|
2637
|
+
if (abortController.signal.aborted) {
|
|
2638
|
+
transaction.transaction = void 0;
|
|
2639
|
+
discarding = this.#discardStartedTransaction(startTransactionPromise);
|
|
2640
|
+
await this.#closeTransaction(transaction, "timed_out");
|
|
2641
|
+
throw new TransactionStartTimeoutError();
|
|
2642
|
+
}
|
|
2643
|
+
transaction.status = "running";
|
|
2644
|
+
transaction.startedAt = Date.now();
|
|
2645
|
+
transaction.timer = this.#startTransactionTimeout(transaction.id, options.timeout);
|
|
2646
|
+
return { id: transaction.id };
|
|
2647
|
+
case "timed_out":
|
|
2648
|
+
case "running":
|
|
2649
|
+
case "committed":
|
|
2650
|
+
case "rolled_back":
|
|
2651
|
+
throw new TransactionInternalConsistencyError(
|
|
2652
|
+
`Transaction in invalid state ${transaction.status} although it just finished startup.`
|
|
2653
|
+
);
|
|
2654
|
+
default:
|
|
2655
|
+
return assertNever(transaction["status"], "Unknown transaction status.");
|
|
2656
|
+
}
|
|
2657
|
+
} finally {
|
|
2658
|
+
this.#startingTransactions.delete(starting);
|
|
2659
|
+
if (discarding) {
|
|
2660
|
+
void discarding.finally(starting.markSettled);
|
|
2661
|
+
} else {
|
|
2662
|
+
starting.markSettled();
|
|
2663
|
+
}
|
|
2664
|
+
}
|
|
2665
|
+
}
|
|
2666
|
+
/**
|
|
2667
|
+
* Rolls back a transaction whose start was abandoned, and releases its connection.
|
|
2668
|
+
*
|
|
2669
|
+
* The `startTransaction` promise may still be running in the background. If it eventually
|
|
2670
|
+
* succeeds, we need to roll back and release the connection to avoid leaking it and
|
|
2671
|
+
* exhausting the connection pool. For adapters that don't use phantom queries (e.g. pg/neon),
|
|
2672
|
+
* `rollback()` only releases the connection without sending SQL, so we send an explicit
|
|
2673
|
+
* ROLLBACK first; otherwise the connection returns to the pool mid-transaction because
|
|
2674
|
+
* `BEGIN` already ran on the wire during startup.
|
|
2675
|
+
*
|
|
2676
|
+
* Errors are only logged: the caller has already reported the failure that led here.
|
|
2677
|
+
*/
|
|
2678
|
+
async #discardStartedTransaction(startTransactionPromise) {
|
|
2679
|
+
try {
|
|
2680
|
+
const tx = await startTransactionPromise;
|
|
2681
|
+
if (tx.options.usePhantomQuery) {
|
|
2682
|
+
await tx.rollback();
|
|
2683
|
+
} else {
|
|
2684
|
+
try {
|
|
2685
|
+
await tx.executeRaw(ROLLBACK_QUERY());
|
|
2686
|
+
} finally {
|
|
2687
|
+
await tx.rollback();
|
|
2622
2688
|
}
|
|
2623
|
-
|
|
2624
|
-
|
|
2625
|
-
|
|
2626
|
-
case "timed_out":
|
|
2627
|
-
case "running":
|
|
2628
|
-
case "committed":
|
|
2629
|
-
case "rolled_back":
|
|
2630
|
-
throw new TransactionInternalConsistencyError(
|
|
2631
|
-
`Transaction in invalid state ${transaction.status} although it just finished startup.`
|
|
2632
|
-
);
|
|
2633
|
-
default:
|
|
2634
|
-
assertNever(transaction["status"], "Unknown transaction status.");
|
|
2689
|
+
}
|
|
2690
|
+
} catch (e) {
|
|
2691
|
+
debug("error in discarded transaction:", e);
|
|
2635
2692
|
}
|
|
2636
2693
|
}
|
|
2637
2694
|
async commitTransaction(transactionId) {
|
|
@@ -2722,16 +2779,21 @@ var TransactionManager = class {
|
|
|
2722
2779
|
return transaction;
|
|
2723
2780
|
}
|
|
2724
2781
|
async cancelAllTransactions() {
|
|
2725
|
-
|
|
2726
|
-
|
|
2782
|
+
const starting = [...this.#startingTransactions];
|
|
2783
|
+
for (const { abortController } of starting) {
|
|
2784
|
+
abortController.abort();
|
|
2785
|
+
}
|
|
2786
|
+
await Promise.allSettled([
|
|
2787
|
+
...[...this.transactions.values()].map(
|
|
2727
2788
|
(tx) => this.#runSerialized(tx, async () => {
|
|
2728
2789
|
const current = this.transactions.get(tx.id);
|
|
2729
2790
|
if (current) {
|
|
2730
2791
|
await this.#closeTransaction(current, "rolled_back");
|
|
2731
2792
|
}
|
|
2732
2793
|
})
|
|
2733
|
-
)
|
|
2734
|
-
|
|
2794
|
+
),
|
|
2795
|
+
...starting.map(({ settled }) => settleWithin(settled, CANCEL_ROLLBACK_GRACE_MS))
|
|
2796
|
+
]);
|
|
2735
2797
|
}
|
|
2736
2798
|
#nextSavepointName(transaction) {
|
|
2737
2799
|
return `prisma_sp_${transaction.savepointCounter++}`;
|
|
@@ -2884,6 +2946,14 @@ var TransactionManager = class {
|
|
|
2884
2946
|
function createTimeoutIfDefined(cb, ms) {
|
|
2885
2947
|
return ms !== void 0 ? setTimeout(cb, ms) : void 0;
|
|
2886
2948
|
}
|
|
2949
|
+
function settleWithin(promise, timeout) {
|
|
2950
|
+
let timer;
|
|
2951
|
+
const deadline = new Promise((resolve) => {
|
|
2952
|
+
timer = setTimeout(resolve, timeout);
|
|
2953
|
+
timer?.unref?.();
|
|
2954
|
+
});
|
|
2955
|
+
return Promise.race([promise, deadline]).finally(() => clearTimeout(timer));
|
|
2956
|
+
}
|
|
2887
2957
|
export {
|
|
2888
2958
|
DataMapperError,
|
|
2889
2959
|
QueryInterpreter,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/utils.d.ts
CHANGED
|
@@ -20,3 +20,8 @@ export declare function doKeysMatch(lhs: {}, rhs: {}): boolean;
|
|
|
20
20
|
* BigInt and Uint8Array values.
|
|
21
21
|
*/
|
|
22
22
|
export declare function safeJsonStringify(obj: unknown): string;
|
|
23
|
+
/**
|
|
24
|
+
* Appends all elements of `source` to `target` without spreading the whole
|
|
25
|
+
* array as call arguments, which overflows the stack for large arrays.
|
|
26
|
+
*/
|
|
27
|
+
export declare function appendToArray<T>(target: T[], source: readonly T[]): void;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@prisma/client-engine-runtime",
|
|
3
|
-
"version": "7.10.0-dev.
|
|
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
|
"module": "dist/index.mjs",
|
|
@@ -31,20 +31,20 @@
|
|
|
31
31
|
"nanoid": "5.1.5",
|
|
32
32
|
"ulid": "3.0.0",
|
|
33
33
|
"uuid": "14.0.0",
|
|
34
|
-
"@prisma/
|
|
35
|
-
"@prisma/
|
|
36
|
-
"@prisma/
|
|
37
|
-
"@prisma/
|
|
38
|
-
"@prisma/
|
|
39
|
-
"@prisma/json-protocol": "7.10.0-dev.
|
|
34
|
+
"@prisma/debug": "7.10.0-dev.21",
|
|
35
|
+
"@prisma/driver-adapter-utils": "7.10.0-dev.21",
|
|
36
|
+
"@prisma/sqlcommenter": "7.10.0-dev.21",
|
|
37
|
+
"@prisma/param-graph": "7.10.0-dev.21",
|
|
38
|
+
"@prisma/client-runtime-utils": "7.10.0-dev.21",
|
|
39
|
+
"@prisma/json-protocol": "7.10.0-dev.21"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
42
|
"@codspeed/benchmark.js-plugin": "4.0.0",
|
|
43
43
|
"@types/benchmark": "2.1.5",
|
|
44
44
|
"@types/node": "~20.19.24",
|
|
45
45
|
"benchmark": "2.1.4",
|
|
46
|
-
"@prisma/
|
|
47
|
-
"@prisma/
|
|
46
|
+
"@prisma/get-dmmf": "7.10.0-dev.21",
|
|
47
|
+
"@prisma/param-graph-builder": "7.10.0-dev.21"
|
|
48
48
|
},
|
|
49
49
|
"files": [
|
|
50
50
|
"dist"
|