@prisma/client-engine-runtime 6.7.0-dev.2 → 6.7.0-dev.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/QueryPlan.d.ts +2 -0
- package/dist/UserFacingError.d.ts +16 -0
- package/dist/index.d.mts +39 -2
- package/dist/index.d.ts +39 -2
- package/dist/index.js +302 -77
- package/dist/index.mjs +299 -76
- package/dist/interpreter/QueryInterpreter.d.ts +3 -1
- package/dist/tracing.d.ts +11 -0
- package/dist/transactionManager/TransactionManager.d.ts +5 -1
- package/dist/transactionManager/TransactionManagerErrors.d.ts +1 -7
- package/package.json +4 -3
package/dist/index.mjs
CHANGED
|
@@ -1,3 +1,173 @@
|
|
|
1
|
+
// src/interpreter/QueryInterpreter.ts
|
|
2
|
+
import { SpanKind } from "@opentelemetry/api";
|
|
3
|
+
|
|
4
|
+
// src/utils.ts
|
|
5
|
+
function assertNever(_, message) {
|
|
6
|
+
throw new Error(message);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
// src/tracing.ts
|
|
10
|
+
var noopTracingHelper = {
|
|
11
|
+
runInChildSpan(_, callback) {
|
|
12
|
+
return callback();
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
function providerToOtelSystem(provider) {
|
|
16
|
+
switch (provider) {
|
|
17
|
+
case "postgres":
|
|
18
|
+
return "postgresql";
|
|
19
|
+
case "mysql":
|
|
20
|
+
return "mysql";
|
|
21
|
+
case "sqlite":
|
|
22
|
+
return "sqlite";
|
|
23
|
+
default:
|
|
24
|
+
assertNever(provider, `Unknown provider: ${provider}`);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// src/UserFacingError.ts
|
|
29
|
+
import { isDriverAdapterError } from "@prisma/driver-adapter-utils";
|
|
30
|
+
var UserFacingError = class extends Error {
|
|
31
|
+
name = "UserFacingError";
|
|
32
|
+
code;
|
|
33
|
+
meta;
|
|
34
|
+
constructor(message, code, meta) {
|
|
35
|
+
super(message);
|
|
36
|
+
this.code = code;
|
|
37
|
+
this.meta = meta;
|
|
38
|
+
}
|
|
39
|
+
toQueryResponseErrorObject() {
|
|
40
|
+
return {
|
|
41
|
+
error: this.message,
|
|
42
|
+
user_facing_error: {
|
|
43
|
+
is_panic: false,
|
|
44
|
+
message: this.message,
|
|
45
|
+
meta: this.meta,
|
|
46
|
+
error_code: this.code
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
function rethrowAsUserFacing(error) {
|
|
52
|
+
if (!isDriverAdapterError(error)) {
|
|
53
|
+
throw error;
|
|
54
|
+
}
|
|
55
|
+
const code = getErrorCode(error);
|
|
56
|
+
const message = renderErrorMessage(error);
|
|
57
|
+
if (!code || !message) {
|
|
58
|
+
throw error;
|
|
59
|
+
}
|
|
60
|
+
throw new UserFacingError(message, code, error);
|
|
61
|
+
}
|
|
62
|
+
function getErrorCode(err) {
|
|
63
|
+
switch (err.cause.kind) {
|
|
64
|
+
case "AuthenticationFailed":
|
|
65
|
+
return "P1000";
|
|
66
|
+
case "DatabaseDoesNotExist":
|
|
67
|
+
return "P1003";
|
|
68
|
+
case "SocketTimeout":
|
|
69
|
+
return "P1008";
|
|
70
|
+
case "DatabaseAlreadyExists":
|
|
71
|
+
return "P1009";
|
|
72
|
+
case "DatabaseAccessDenied":
|
|
73
|
+
return "P1010";
|
|
74
|
+
case "LengthMismatch":
|
|
75
|
+
return "P2000";
|
|
76
|
+
case "UniqueConstraintViolation":
|
|
77
|
+
return "P2002";
|
|
78
|
+
case "ForeignKeyConstraintViolation":
|
|
79
|
+
return "P2003";
|
|
80
|
+
case "UnsupportedNativeDataType":
|
|
81
|
+
return "P2010";
|
|
82
|
+
case "NullConstraintViolation":
|
|
83
|
+
return "P2011";
|
|
84
|
+
case "TableDoesNotExist":
|
|
85
|
+
return "P2021";
|
|
86
|
+
case "ColumnNotFound":
|
|
87
|
+
return "P2022";
|
|
88
|
+
case "InvalidIsolationLevel":
|
|
89
|
+
return "P2023";
|
|
90
|
+
case "TransactionWriteConflict":
|
|
91
|
+
return "P2034";
|
|
92
|
+
case "GenericJs":
|
|
93
|
+
return "P2036";
|
|
94
|
+
case "TooManyConnections":
|
|
95
|
+
return "P2037";
|
|
96
|
+
case "postgres":
|
|
97
|
+
case "sqlite":
|
|
98
|
+
case "mysql":
|
|
99
|
+
return;
|
|
100
|
+
default:
|
|
101
|
+
assertNever(err.cause, `Unknown error: ${err.cause}`);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
function renderErrorMessage(err) {
|
|
105
|
+
switch (err.cause.kind) {
|
|
106
|
+
case "AuthenticationFailed": {
|
|
107
|
+
const user = err.cause.user ?? "(not available)";
|
|
108
|
+
return `Authentication failed against the database server, the provided database credentials for \`${user}\` are not valid`;
|
|
109
|
+
}
|
|
110
|
+
case "DatabaseDoesNotExist": {
|
|
111
|
+
const db = err.cause.db ?? "(not available)";
|
|
112
|
+
return `Database \`${db}\` does not exist on the database server`;
|
|
113
|
+
}
|
|
114
|
+
case "SocketTimeout":
|
|
115
|
+
return `Operation has timed out`;
|
|
116
|
+
case "DatabaseAlreadyExists": {
|
|
117
|
+
const db = err.cause.db ?? "(not available)";
|
|
118
|
+
return `Database \`${db}\` already exists on the database server`;
|
|
119
|
+
}
|
|
120
|
+
case "DatabaseAccessDenied": {
|
|
121
|
+
const db = err.cause.db ?? "(not available)";
|
|
122
|
+
return `User was denied access on the database \`${db}\``;
|
|
123
|
+
}
|
|
124
|
+
case "LengthMismatch": {
|
|
125
|
+
const column = err.cause.column ?? "(not available)";
|
|
126
|
+
return `The provided value for the column is too long for the column's type. Column: ${column}`;
|
|
127
|
+
}
|
|
128
|
+
case "UniqueConstraintViolation":
|
|
129
|
+
return `Unique constraint failed on the ${renderConstraint({ fields: err.cause.fields })}`;
|
|
130
|
+
case "ForeignKeyConstraintViolation":
|
|
131
|
+
return `Foreign key constraint violated on the ${renderConstraint(err.cause.constraint)}`;
|
|
132
|
+
case "UnsupportedNativeDataType":
|
|
133
|
+
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\`.`;
|
|
134
|
+
case "NullConstraintViolation":
|
|
135
|
+
return `Null constraint violation on the ${renderConstraint({ fields: err.cause.fields })}`;
|
|
136
|
+
case "TableDoesNotExist": {
|
|
137
|
+
const table = err.cause.table ?? "(not available)";
|
|
138
|
+
return `The table \`${table}\` does not exist in the current database.`;
|
|
139
|
+
}
|
|
140
|
+
case "ColumnNotFound": {
|
|
141
|
+
const column = err.cause.column ?? "(not available)";
|
|
142
|
+
return `The column \`${column}\` does not exist in the current database.`;
|
|
143
|
+
}
|
|
144
|
+
case "InvalidIsolationLevel":
|
|
145
|
+
return `Invalid isolation level \`${err.cause.level}\``;
|
|
146
|
+
case "TransactionWriteConflict":
|
|
147
|
+
return `Transaction failed due to a write conflict or a deadlock. Please retry your transaction`;
|
|
148
|
+
case "GenericJs":
|
|
149
|
+
return `Error in external connector (id ${err.cause.id})`;
|
|
150
|
+
case "TooManyConnections":
|
|
151
|
+
return `Too many database connections opened: ${err.cause.cause}`;
|
|
152
|
+
case "sqlite":
|
|
153
|
+
case "postgres":
|
|
154
|
+
case "mysql":
|
|
155
|
+
return;
|
|
156
|
+
default:
|
|
157
|
+
assertNever(err.cause, `Unknown error: ${err.cause}`);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
function renderConstraint(constraint) {
|
|
161
|
+
if (constraint && "fields" in constraint) {
|
|
162
|
+
return `fields: (${constraint.fields.map((field) => `\`${field}\``).join(", ")})`;
|
|
163
|
+
} else if (constraint && "index" in constraint) {
|
|
164
|
+
return `constraint: \`${constraint.index}\``;
|
|
165
|
+
} else if (constraint && "foreignKey" in constraint) {
|
|
166
|
+
return `foreign key`;
|
|
167
|
+
}
|
|
168
|
+
return "(not available)";
|
|
169
|
+
}
|
|
170
|
+
|
|
1
171
|
// src/interpreter/generators.ts
|
|
2
172
|
import cuid1 from "@bugsnag/cuid";
|
|
3
173
|
import { createId as cuid2 } from "@paralleldrive/cuid2";
|
|
@@ -12,6 +182,7 @@ var GeneratorRegistry = class {
|
|
|
12
182
|
this.register("cuid", new CuidGenerator());
|
|
13
183
|
this.register("ulid", new UlidGenerator());
|
|
14
184
|
this.register("nanoid", new NanoIdGenerator());
|
|
185
|
+
this.register("product", new ProductGenerator());
|
|
15
186
|
}
|
|
16
187
|
/**
|
|
17
188
|
* Returns a snapshot of the generator registry. It's 'frozen' in time at the moment of this
|
|
@@ -74,6 +245,22 @@ var NanoIdGenerator = class {
|
|
|
74
245
|
}
|
|
75
246
|
}
|
|
76
247
|
};
|
|
248
|
+
var ProductGenerator = class {
|
|
249
|
+
generate(lhs, rhs) {
|
|
250
|
+
if (lhs === void 0 || rhs === void 0) {
|
|
251
|
+
throw new Error("Invalid Product generator arguments");
|
|
252
|
+
}
|
|
253
|
+
if (Array.isArray(lhs) && Array.isArray(rhs)) {
|
|
254
|
+
return lhs.flatMap((l) => rhs.map((r) => [l, r]));
|
|
255
|
+
} else if (Array.isArray(lhs)) {
|
|
256
|
+
return lhs.map((l) => [l, rhs]);
|
|
257
|
+
} else if (Array.isArray(rhs)) {
|
|
258
|
+
return rhs.map((r) => [lhs, r]);
|
|
259
|
+
} else {
|
|
260
|
+
return [[lhs, rhs]];
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
};
|
|
77
264
|
|
|
78
265
|
// src/QueryPlan.ts
|
|
79
266
|
function isPrismaValuePlaceholder(value) {
|
|
@@ -83,46 +270,49 @@ function isPrismaValueGenerator(value) {
|
|
|
83
270
|
return typeof value === "object" && value !== null && value["prisma__type"] === "generatorCall";
|
|
84
271
|
}
|
|
85
272
|
|
|
86
|
-
// src/utils.ts
|
|
87
|
-
function assertNever(_, message) {
|
|
88
|
-
throw new Error(message);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
273
|
// src/interpreter/renderQuery.ts
|
|
92
274
|
function renderQuery(dbQuery, scope, generators) {
|
|
93
275
|
const queryType = dbQuery.type;
|
|
94
276
|
switch (queryType) {
|
|
95
277
|
case "rawSql":
|
|
96
|
-
return renderRawSql(dbQuery.sql,
|
|
278
|
+
return renderRawSql(dbQuery.sql, evaluateParams(dbQuery.params, scope, generators));
|
|
97
279
|
case "templateSql":
|
|
98
280
|
return renderTemplateSql(
|
|
99
281
|
dbQuery.fragments,
|
|
100
282
|
dbQuery.placeholderFormat,
|
|
101
|
-
|
|
283
|
+
evaluateParams(dbQuery.params, scope, generators)
|
|
102
284
|
);
|
|
103
285
|
default:
|
|
104
286
|
assertNever(queryType, `Invalid query type`);
|
|
105
287
|
}
|
|
106
288
|
}
|
|
107
|
-
function
|
|
108
|
-
return params.map((param) =>
|
|
109
|
-
|
|
110
|
-
|
|
289
|
+
function evaluateParams(params, scope, generators) {
|
|
290
|
+
return params.map((param) => evaluateParam(param, scope, generators));
|
|
291
|
+
}
|
|
292
|
+
function evaluateParam(param, scope, generators) {
|
|
293
|
+
let value = param;
|
|
294
|
+
while (doesRequireEvaluation(value)) {
|
|
295
|
+
if (isPrismaValuePlaceholder(value)) {
|
|
296
|
+
const found = scope[value.prisma__value.name];
|
|
297
|
+
if (found === void 0) {
|
|
298
|
+
throw new Error(`Missing value for query variable ${value.prisma__value.name}`);
|
|
299
|
+
}
|
|
300
|
+
value = found;
|
|
301
|
+
} else if (isPrismaValueGenerator(value)) {
|
|
302
|
+
const { name, args } = value.prisma__value;
|
|
111
303
|
const generator = generators[name];
|
|
112
304
|
if (!generator) {
|
|
113
305
|
throw new Error(`Encountered an unknown generator '${name}'`);
|
|
114
306
|
}
|
|
115
|
-
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
return param;
|
|
119
|
-
}
|
|
120
|
-
const value = scope[param.prisma__value.name];
|
|
121
|
-
if (value === void 0) {
|
|
122
|
-
throw new Error(`Missing value for query variable ${param.prisma__value.name}`);
|
|
307
|
+
value = generator.generate(...args.map((arg) => evaluateParam(arg, scope, generators)));
|
|
308
|
+
} else {
|
|
309
|
+
assertNever(value, `Unexpected unevaluated value type: ${value}`);
|
|
123
310
|
}
|
|
124
|
-
|
|
125
|
-
|
|
311
|
+
}
|
|
312
|
+
if (Array.isArray(value)) {
|
|
313
|
+
value = value.map((el) => evaluateParam(el, scope, generators));
|
|
314
|
+
}
|
|
315
|
+
return value;
|
|
126
316
|
}
|
|
127
317
|
function renderTemplateSql(fragments, placeholderFormat, params) {
|
|
128
318
|
let paramIndex = 0;
|
|
@@ -151,6 +341,29 @@ function renderTemplateSql(fragments, placeholderFormat, params) {
|
|
|
151
341
|
}).join(",");
|
|
152
342
|
return `(${placeholders})`;
|
|
153
343
|
}
|
|
344
|
+
case "parameterTupleList": {
|
|
345
|
+
if (paramIndex >= params.length) {
|
|
346
|
+
throw new Error(`Malformed query template. Fragments attempt to read over ${params.length} parameters.`);
|
|
347
|
+
}
|
|
348
|
+
const paramValue = params[paramIndex++];
|
|
349
|
+
if (!Array.isArray(paramValue)) {
|
|
350
|
+
throw new Error(`Malformed query template. Tuple list expected.`);
|
|
351
|
+
}
|
|
352
|
+
if (paramValue.length === 0) {
|
|
353
|
+
throw new Error(`Malformed query template. Tuple list cannot be empty.`);
|
|
354
|
+
}
|
|
355
|
+
const tupleList = paramValue.map((tuple) => {
|
|
356
|
+
if (!Array.isArray(tuple)) {
|
|
357
|
+
throw new Error(`Malformed query template. Tuple expected.`);
|
|
358
|
+
}
|
|
359
|
+
const elements = tuple.map((value) => {
|
|
360
|
+
flattenedParams.push(value);
|
|
361
|
+
return formatPlaceholder(placeholderFormat, placeholderNumber++);
|
|
362
|
+
}).join(",");
|
|
363
|
+
return `(${elements})`;
|
|
364
|
+
}).join(",");
|
|
365
|
+
return tupleList;
|
|
366
|
+
}
|
|
154
367
|
default:
|
|
155
368
|
assertNever(fragmentType, "Invalid fragment type");
|
|
156
369
|
}
|
|
@@ -209,6 +422,9 @@ function placeholderTypeToArgType(type) {
|
|
|
209
422
|
}
|
|
210
423
|
return mappedType;
|
|
211
424
|
}
|
|
425
|
+
function doesRequireEvaluation(param) {
|
|
426
|
+
return isPrismaValuePlaceholder(param) || isPrismaValueGenerator(param);
|
|
427
|
+
}
|
|
212
428
|
|
|
213
429
|
// src/interpreter/serialize.ts
|
|
214
430
|
function serialize(resultSet) {
|
|
@@ -238,13 +454,17 @@ var QueryInterpreter = class {
|
|
|
238
454
|
#placeholderValues;
|
|
239
455
|
#onQuery;
|
|
240
456
|
#generators = new GeneratorRegistry();
|
|
241
|
-
|
|
457
|
+
#tracingHelper;
|
|
458
|
+
constructor({ transactionManager, placeholderValues, onQuery, tracingHelper }) {
|
|
242
459
|
this.#transactionManager = transactionManager;
|
|
243
460
|
this.#placeholderValues = placeholderValues;
|
|
244
461
|
this.#onQuery = onQuery;
|
|
462
|
+
this.#tracingHelper = tracingHelper;
|
|
245
463
|
}
|
|
246
464
|
async run(queryPlan, queryable) {
|
|
247
|
-
return this.interpretNode(queryPlan, queryable, this.#placeholderValues, this.#generators.snapshot())
|
|
465
|
+
return this.interpretNode(queryPlan, queryable, this.#placeholderValues, this.#generators.snapshot()).catch(
|
|
466
|
+
(e) => rethrowAsUserFacing(e)
|
|
467
|
+
);
|
|
248
468
|
}
|
|
249
469
|
async interpretNode(node, queryable, scope, generators) {
|
|
250
470
|
switch (node.type) {
|
|
@@ -283,13 +503,13 @@ var QueryInterpreter = class {
|
|
|
283
503
|
}
|
|
284
504
|
case "execute": {
|
|
285
505
|
const query = renderQuery(node.args, scope, generators);
|
|
286
|
-
return this.#withQueryEvent(query, async () => {
|
|
506
|
+
return this.#withQueryEvent(query, queryable, async () => {
|
|
287
507
|
return await queryable.executeRaw(query);
|
|
288
508
|
});
|
|
289
509
|
}
|
|
290
510
|
case "query": {
|
|
291
511
|
const query = renderQuery(node.args, scope, generators);
|
|
292
|
-
return this.#withQueryEvent(query, async () => {
|
|
512
|
+
return this.#withQueryEvent(query, queryable, async () => {
|
|
293
513
|
return serialize(await queryable.queryRaw(query));
|
|
294
514
|
});
|
|
295
515
|
}
|
|
@@ -350,24 +570,34 @@ var QueryInterpreter = class {
|
|
|
350
570
|
throw e;
|
|
351
571
|
}
|
|
352
572
|
}
|
|
353
|
-
default:
|
|
354
|
-
node;
|
|
355
|
-
throw new Error(`Unexpected node type: ${node.type}`);
|
|
356
|
-
}
|
|
573
|
+
default:
|
|
574
|
+
assertNever(node, `Unexpected node type: ${node.type}`);
|
|
357
575
|
}
|
|
358
576
|
}
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
577
|
+
#withQueryEvent(query, queryable, execute) {
|
|
578
|
+
return this.#tracingHelper.runInChildSpan(
|
|
579
|
+
{
|
|
580
|
+
name: "db_query",
|
|
581
|
+
kind: SpanKind.CLIENT,
|
|
582
|
+
attributes: {
|
|
583
|
+
"db.query.text": query.sql,
|
|
584
|
+
"db.system.name": providerToOtelSystem(queryable.provider)
|
|
585
|
+
}
|
|
586
|
+
},
|
|
587
|
+
async () => {
|
|
588
|
+
const timestamp = /* @__PURE__ */ new Date();
|
|
589
|
+
const startInstant = performance.now();
|
|
590
|
+
const result = await execute();
|
|
591
|
+
const endInstant = performance.now();
|
|
592
|
+
this.#onQuery?.({
|
|
593
|
+
timestamp,
|
|
594
|
+
duration: endInstant - startInstant,
|
|
595
|
+
query: query.sql,
|
|
596
|
+
params: query.args
|
|
597
|
+
});
|
|
598
|
+
return result;
|
|
599
|
+
}
|
|
600
|
+
);
|
|
371
601
|
}
|
|
372
602
|
};
|
|
373
603
|
function isEmpty(value) {
|
|
@@ -412,6 +642,8 @@ function attachChildrenToParent(parentRecord, children) {
|
|
|
412
642
|
function filterChildRecords(records, parentRecord, joinExpr) {
|
|
413
643
|
if (Array.isArray(records)) {
|
|
414
644
|
return records.filter((record) => childRecordMatchesParent(asRecord(record), parentRecord, joinExpr));
|
|
645
|
+
} else if (records === null) {
|
|
646
|
+
return null;
|
|
415
647
|
} else {
|
|
416
648
|
const record = asRecord(records);
|
|
417
649
|
return childRecordMatchesParent(record, parentRecord, joinExpr) ? record : null;
|
|
@@ -446,11 +678,6 @@ var TransactionManagerError = class extends Error {
|
|
|
446
678
|
}
|
|
447
679
|
code = "P2028";
|
|
448
680
|
};
|
|
449
|
-
var TransactionDriverAdapterError = class extends TransactionManagerError {
|
|
450
|
-
constructor(message, errorParams) {
|
|
451
|
-
super(`Error from Driver Adapter: ${message}`, { ...errorParams.driverAdapterError });
|
|
452
|
-
}
|
|
453
|
-
};
|
|
454
681
|
var TransactionNotFoundError = class extends TransactionManagerError {
|
|
455
682
|
constructor() {
|
|
456
683
|
super(
|
|
@@ -468,7 +695,7 @@ var TransactionRolledBackError = class extends TransactionManagerError {
|
|
|
468
695
|
super(`Transaction already closed: A ${operation} cannot be executed on a committed transaction`);
|
|
469
696
|
}
|
|
470
697
|
};
|
|
471
|
-
var
|
|
698
|
+
var TransactionStartTimeoutError = class extends TransactionManagerError {
|
|
472
699
|
constructor() {
|
|
473
700
|
super("Unable to start a transaction in the given time.");
|
|
474
701
|
}
|
|
@@ -505,11 +732,20 @@ var TransactionManager = class {
|
|
|
505
732
|
closedTransactions = [];
|
|
506
733
|
driverAdapter;
|
|
507
734
|
transactionOptions;
|
|
508
|
-
|
|
735
|
+
tracingHelper;
|
|
736
|
+
constructor({
|
|
737
|
+
driverAdapter,
|
|
738
|
+
transactionOptions,
|
|
739
|
+
tracingHelper
|
|
740
|
+
}) {
|
|
509
741
|
this.driverAdapter = driverAdapter;
|
|
510
742
|
this.transactionOptions = transactionOptions;
|
|
743
|
+
this.tracingHelper = tracingHelper;
|
|
511
744
|
}
|
|
512
745
|
async startTransaction(options) {
|
|
746
|
+
return await this.tracingHelper.runInChildSpan("start_transaction", () => this.#startTransactionImpl(options));
|
|
747
|
+
}
|
|
748
|
+
async #startTransactionImpl(options) {
|
|
513
749
|
const validatedOptions = options !== void 0 ? this.validateOptions(options) : this.transactionOptions;
|
|
514
750
|
const transaction = {
|
|
515
751
|
id: await randomUUID(),
|
|
@@ -521,14 +757,7 @@ var TransactionManager = class {
|
|
|
521
757
|
};
|
|
522
758
|
this.transactions.set(transaction.id, transaction);
|
|
523
759
|
transaction.timer = this.startTransactionTimeout(transaction.id, validatedOptions.maxWait);
|
|
524
|
-
|
|
525
|
-
try {
|
|
526
|
-
startedTransaction = await this.driverAdapter.startTransaction(validatedOptions.isolationLevel);
|
|
527
|
-
} catch (error) {
|
|
528
|
-
throw new TransactionDriverAdapterError("Failed to start transaction.", {
|
|
529
|
-
driverAdapterError: error
|
|
530
|
-
});
|
|
531
|
-
}
|
|
760
|
+
const startedTransaction = await this.driverAdapter.startTransaction(validatedOptions.isolationLevel);
|
|
532
761
|
switch (transaction.status) {
|
|
533
762
|
case "waiting":
|
|
534
763
|
transaction.transaction = startedTransaction;
|
|
@@ -538,7 +767,7 @@ var TransactionManager = class {
|
|
|
538
767
|
transaction.timer = this.startTransactionTimeout(transaction.id, validatedOptions.timeout);
|
|
539
768
|
return { id: transaction.id };
|
|
540
769
|
case "timed_out":
|
|
541
|
-
throw new
|
|
770
|
+
throw new TransactionStartTimeoutError();
|
|
542
771
|
case "running":
|
|
543
772
|
case "committed":
|
|
544
773
|
case "rolled_back":
|
|
@@ -550,12 +779,16 @@ var TransactionManager = class {
|
|
|
550
779
|
}
|
|
551
780
|
}
|
|
552
781
|
async commitTransaction(transactionId) {
|
|
553
|
-
|
|
554
|
-
|
|
782
|
+
return await this.tracingHelper.runInChildSpan("commit_transaction", async () => {
|
|
783
|
+
const txw = this.getActiveTransaction(transactionId, "commit");
|
|
784
|
+
await this.closeTransaction(txw, "committed");
|
|
785
|
+
});
|
|
555
786
|
}
|
|
556
787
|
async rollbackTransaction(transactionId) {
|
|
557
|
-
|
|
558
|
-
|
|
788
|
+
return await this.tracingHelper.runInChildSpan("rollback_transaction", async () => {
|
|
789
|
+
const txw = this.getActiveTransaction(transactionId, "rollback");
|
|
790
|
+
await this.closeTransaction(txw, "rolled_back");
|
|
791
|
+
});
|
|
559
792
|
}
|
|
560
793
|
getTransaction(txInfo, operation) {
|
|
561
794
|
const tx = this.getActiveTransaction(txInfo.id, operation);
|
|
@@ -611,24 +844,12 @@ var TransactionManager = class {
|
|
|
611
844
|
debug("Closing transaction.", { transactionId: tx.id, status });
|
|
612
845
|
tx.status = status;
|
|
613
846
|
if (tx.transaction && status === "committed") {
|
|
614
|
-
|
|
615
|
-
await tx.transaction.commit();
|
|
616
|
-
} catch (error) {
|
|
617
|
-
throw new TransactionDriverAdapterError("Failed to commit transaction.", {
|
|
618
|
-
driverAdapterError: error
|
|
619
|
-
});
|
|
620
|
-
}
|
|
847
|
+
await tx.transaction.commit();
|
|
621
848
|
if (!tx.transaction.options.usePhantomQuery) {
|
|
622
849
|
await tx.transaction.executeRaw(COMMIT_QUERY());
|
|
623
850
|
}
|
|
624
851
|
} else if (tx.transaction) {
|
|
625
|
-
|
|
626
|
-
await tx.transaction.rollback();
|
|
627
|
-
} catch (error) {
|
|
628
|
-
throw new TransactionDriverAdapterError("Failed to rollback transaction.", {
|
|
629
|
-
driverAdapterError: error
|
|
630
|
-
});
|
|
631
|
-
}
|
|
852
|
+
await tx.transaction.rollback();
|
|
632
853
|
if (!tx.transaction.options.usePhantomQuery) {
|
|
633
854
|
await tx.transaction.executeRaw(ROLLBACK_QUERY());
|
|
634
855
|
}
|
|
@@ -656,6 +877,8 @@ export {
|
|
|
656
877
|
QueryInterpreter,
|
|
657
878
|
TransactionManager,
|
|
658
879
|
TransactionManagerError,
|
|
880
|
+
UserFacingError,
|
|
659
881
|
isPrismaValueGenerator,
|
|
660
|
-
isPrismaValuePlaceholder
|
|
882
|
+
isPrismaValuePlaceholder,
|
|
883
|
+
noopTracingHelper
|
|
661
884
|
};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { SqlQueryable } from '@prisma/driver-adapter-utils';
|
|
2
2
|
import { QueryEvent } from '../events';
|
|
3
3
|
import { QueryPlanNode } from '../QueryPlan';
|
|
4
|
+
import { type TracingHelper } from '../tracing';
|
|
4
5
|
import { type TransactionManager } from '../transactionManager/TransactionManager';
|
|
5
6
|
export type QueryInterpreterTransactionManager = {
|
|
6
7
|
enabled: true;
|
|
@@ -12,10 +13,11 @@ export type QueryInterpreterOptions = {
|
|
|
12
13
|
transactionManager: QueryInterpreterTransactionManager;
|
|
13
14
|
placeholderValues: Record<string, unknown>;
|
|
14
15
|
onQuery?: (event: QueryEvent) => void;
|
|
16
|
+
tracingHelper: TracingHelper;
|
|
15
17
|
};
|
|
16
18
|
export declare class QueryInterpreter {
|
|
17
19
|
#private;
|
|
18
|
-
constructor({ transactionManager, placeholderValues, onQuery }: QueryInterpreterOptions);
|
|
20
|
+
constructor({ transactionManager, placeholderValues, onQuery, tracingHelper }: QueryInterpreterOptions);
|
|
19
21
|
run(queryPlan: QueryPlanNode, queryable: SqlQueryable): Promise<unknown>;
|
|
20
22
|
private interpretNode;
|
|
21
23
|
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Context, Span, SpanOptions } from '@opentelemetry/api';
|
|
2
|
+
import type { Provider } from '@prisma/driver-adapter-utils';
|
|
3
|
+
export type SpanCallback<R> = (span?: Span, context?: Context) => R;
|
|
4
|
+
export type ExtendedSpanOptions = SpanOptions & {
|
|
5
|
+
name: string;
|
|
6
|
+
};
|
|
7
|
+
export interface TracingHelper {
|
|
8
|
+
runInChildSpan<R>(nameOrOptions: string | ExtendedSpanOptions, callback: SpanCallback<R>): R;
|
|
9
|
+
}
|
|
10
|
+
export declare const noopTracingHelper: TracingHelper;
|
|
11
|
+
export declare function providerToOtelSystem(provider: Provider): string;
|
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
import { SqlDriverAdapter, Transaction } from '@prisma/driver-adapter-utils';
|
|
2
|
+
import { TracingHelper } from '../tracing';
|
|
2
3
|
import { Options, TransactionInfo } from './Transaction';
|
|
3
4
|
export declare class TransactionManager {
|
|
5
|
+
#private;
|
|
4
6
|
private transactions;
|
|
5
7
|
private closedTransactions;
|
|
6
8
|
private readonly driverAdapter;
|
|
7
9
|
private readonly transactionOptions;
|
|
8
|
-
|
|
10
|
+
private readonly tracingHelper;
|
|
11
|
+
constructor({ driverAdapter, transactionOptions, tracingHelper, }: {
|
|
9
12
|
driverAdapter: SqlDriverAdapter;
|
|
10
13
|
transactionOptions: Options;
|
|
14
|
+
tracingHelper: TracingHelper;
|
|
11
15
|
});
|
|
12
16
|
startTransaction(options?: Options): Promise<TransactionInfo>;
|
|
13
17
|
commitTransaction(transactionId: string): Promise<void>;
|
|
@@ -1,14 +1,8 @@
|
|
|
1
|
-
import { Error as DriverAdapterError } from '@prisma/driver-adapter-utils';
|
|
2
1
|
export declare class TransactionManagerError extends Error {
|
|
3
2
|
meta?: Record<string, unknown> | undefined;
|
|
4
3
|
code: string;
|
|
5
4
|
constructor(message: string, meta?: Record<string, unknown> | undefined);
|
|
6
5
|
}
|
|
7
|
-
export declare class TransactionDriverAdapterError extends TransactionManagerError {
|
|
8
|
-
constructor(message: string, errorParams: {
|
|
9
|
-
driverAdapterError: DriverAdapterError;
|
|
10
|
-
});
|
|
11
|
-
}
|
|
12
6
|
export declare class TransactionNotFoundError extends TransactionManagerError {
|
|
13
7
|
constructor();
|
|
14
8
|
}
|
|
@@ -18,7 +12,7 @@ export declare class TransactionClosedError extends TransactionManagerError {
|
|
|
18
12
|
export declare class TransactionRolledBackError extends TransactionManagerError {
|
|
19
13
|
constructor(operation: string);
|
|
20
14
|
}
|
|
21
|
-
export declare class
|
|
15
|
+
export declare class TransactionStartTimeoutError extends TransactionManagerError {
|
|
22
16
|
constructor();
|
|
23
17
|
}
|
|
24
18
|
export declare class TransactionExecutionTimeoutError extends TransactionManagerError {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@prisma/client-engine-runtime",
|
|
3
|
-
"version": "6.7.0-dev.
|
|
3
|
+
"version": "6.7.0-dev.20",
|
|
4
4
|
"description": "This package is intended for Prisma's internal use",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
@@ -25,12 +25,13 @@
|
|
|
25
25
|
"license": "Apache-2.0",
|
|
26
26
|
"dependencies": {
|
|
27
27
|
"@bugsnag/cuid": "3.2.1",
|
|
28
|
+
"@opentelemetry/api": "1.9.0",
|
|
28
29
|
"@paralleldrive/cuid2": "2.2.2",
|
|
29
30
|
"nanoid": "5.1.5",
|
|
30
31
|
"ulid": "3.0.0",
|
|
31
32
|
"uuid": "11.1.0",
|
|
32
|
-
"@prisma/debug": "6.7.0-dev.
|
|
33
|
-
"@prisma/driver-adapter-utils": "6.7.0-dev.
|
|
33
|
+
"@prisma/debug": "6.7.0-dev.20",
|
|
34
|
+
"@prisma/driver-adapter-utils": "6.7.0-dev.20"
|
|
34
35
|
},
|
|
35
36
|
"devDependencies": {
|
|
36
37
|
"@types/jest": "29.5.14",
|