@prisma/client-engine-runtime 6.7.0-dev.3 → 6.7.0-dev.30
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 +40 -0
- package/dist/UserFacingError.d.ts +16 -0
- package/dist/index.d.mts +79 -2
- package/dist/index.d.ts +79 -2
- package/dist/index.js +394 -47
- package/dist/index.mjs +391 -46
- package/dist/interpreter/DataMapper.d.ts +3 -0
- package/dist/interpreter/QueryInterpreter.d.ts +3 -1
- package/dist/tracing.d.ts +11 -0
- package/dist/transactionManager/TransactionManager.d.ts +5 -1
- package/package.json +4 -3
package/dist/index.mjs
CHANGED
|
@@ -1,3 +1,267 @@
|
|
|
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
|
+
|
|
171
|
+
// src/interpreter/DataMapper.ts
|
|
172
|
+
function applyDataMap(data, structure) {
|
|
173
|
+
switch (structure.type) {
|
|
174
|
+
case "Object":
|
|
175
|
+
return mapArrayOrObject(data, structure.fields);
|
|
176
|
+
case "Value":
|
|
177
|
+
return mapValue(data, structure.resultType);
|
|
178
|
+
default:
|
|
179
|
+
assertNever(structure, `Invalid data mapping type: '${structure.type}'`);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
function mapArrayOrObject(data, fields) {
|
|
183
|
+
if (data === null) return null;
|
|
184
|
+
if (Array.isArray(data)) {
|
|
185
|
+
const rows = data;
|
|
186
|
+
return rows.map((row) => mapObject(row, fields));
|
|
187
|
+
}
|
|
188
|
+
if (typeof data === "object") {
|
|
189
|
+
const row = data;
|
|
190
|
+
return mapObject(row, fields);
|
|
191
|
+
}
|
|
192
|
+
throw new Error(`DataMapper: Expected an array or an object, got: ${typeof data}`);
|
|
193
|
+
}
|
|
194
|
+
function mapObject(data, fields) {
|
|
195
|
+
if (typeof data !== "object") {
|
|
196
|
+
throw new Error(`DataMapper: Expected an object, but got '${typeof data}'`);
|
|
197
|
+
}
|
|
198
|
+
const result = {};
|
|
199
|
+
for (const [name, node] of Object.entries(fields)) {
|
|
200
|
+
switch (node.type) {
|
|
201
|
+
case "Object":
|
|
202
|
+
if (Object.hasOwn(data, name)) {
|
|
203
|
+
result[name] = mapArrayOrObject(data[name], node.fields);
|
|
204
|
+
} else {
|
|
205
|
+
throw new Error(
|
|
206
|
+
`DataMapper: Missing data field (Object): '${name}'; node: ${JSON.stringify(node)}; data: ${JSON.stringify(data)}`
|
|
207
|
+
);
|
|
208
|
+
}
|
|
209
|
+
break;
|
|
210
|
+
case "Value":
|
|
211
|
+
{
|
|
212
|
+
const dbName = node.dbName;
|
|
213
|
+
if (Object.hasOwn(data, dbName)) {
|
|
214
|
+
result[name] = mapValue(data[dbName], node.resultType);
|
|
215
|
+
} else {
|
|
216
|
+
throw new Error(
|
|
217
|
+
`DataMapper: Missing data field (Value): '${dbName}'; node: ${JSON.stringify(node)}; data: ${JSON.stringify(data)}`
|
|
218
|
+
);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
break;
|
|
222
|
+
default:
|
|
223
|
+
assertNever(node, `DataMapper: Invalid data mapping node type: '${node.type}'`);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
return result;
|
|
227
|
+
}
|
|
228
|
+
function mapValue(value, resultType) {
|
|
229
|
+
if (value === null) return null;
|
|
230
|
+
switch (resultType.type) {
|
|
231
|
+
case "Any":
|
|
232
|
+
return value;
|
|
233
|
+
case "String":
|
|
234
|
+
return typeof value === "string" ? value : `${value}`;
|
|
235
|
+
case "Int":
|
|
236
|
+
return typeof value === "number" ? value : parseInt(`${value}`, 10);
|
|
237
|
+
case "BigInt":
|
|
238
|
+
return typeof value === "bigint" ? value : BigInt(`${value}`);
|
|
239
|
+
case "Float":
|
|
240
|
+
return typeof value === "number" ? value : parseFloat(`${value}`);
|
|
241
|
+
case "Boolean":
|
|
242
|
+
return typeof value === "boolean" ? value : value !== "0";
|
|
243
|
+
case "Decimal":
|
|
244
|
+
return typeof value === "number" ? value : parseFloat(`${value}`);
|
|
245
|
+
case "Date":
|
|
246
|
+
return value instanceof Date ? value : /* @__PURE__ */ new Date(`${value}`);
|
|
247
|
+
case "Array": {
|
|
248
|
+
const values = value;
|
|
249
|
+
return values.map((v) => {
|
|
250
|
+
mapValue(v, resultType.inner);
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
case "Object":
|
|
254
|
+
return typeof value === "object" ? value : { value };
|
|
255
|
+
case "Bytes":
|
|
256
|
+
if (typeof value !== "string") {
|
|
257
|
+
throw new Error(`DataMapper: Bytes data is not a string, got: ${typeof value}`);
|
|
258
|
+
}
|
|
259
|
+
return value;
|
|
260
|
+
default:
|
|
261
|
+
assertNever(resultType, `DataMapper: Unknown result type: ${resultType.type}`);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
1
265
|
// src/interpreter/generators.ts
|
|
2
266
|
import cuid1 from "@bugsnag/cuid";
|
|
3
267
|
import { createId as cuid2 } from "@paralleldrive/cuid2";
|
|
@@ -12,6 +276,7 @@ var GeneratorRegistry = class {
|
|
|
12
276
|
this.register("cuid", new CuidGenerator());
|
|
13
277
|
this.register("ulid", new UlidGenerator());
|
|
14
278
|
this.register("nanoid", new NanoIdGenerator());
|
|
279
|
+
this.register("product", new ProductGenerator());
|
|
15
280
|
}
|
|
16
281
|
/**
|
|
17
282
|
* Returns a snapshot of the generator registry. It's 'frozen' in time at the moment of this
|
|
@@ -74,6 +339,22 @@ var NanoIdGenerator = class {
|
|
|
74
339
|
}
|
|
75
340
|
}
|
|
76
341
|
};
|
|
342
|
+
var ProductGenerator = class {
|
|
343
|
+
generate(lhs, rhs) {
|
|
344
|
+
if (lhs === void 0 || rhs === void 0) {
|
|
345
|
+
throw new Error("Invalid Product generator arguments");
|
|
346
|
+
}
|
|
347
|
+
if (Array.isArray(lhs) && Array.isArray(rhs)) {
|
|
348
|
+
return lhs.flatMap((l) => rhs.map((r) => [l, r]));
|
|
349
|
+
} else if (Array.isArray(lhs)) {
|
|
350
|
+
return lhs.map((l) => [l, rhs]);
|
|
351
|
+
} else if (Array.isArray(rhs)) {
|
|
352
|
+
return rhs.map((r) => [lhs, r]);
|
|
353
|
+
} else {
|
|
354
|
+
return [[lhs, rhs]];
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
};
|
|
77
358
|
|
|
78
359
|
// src/QueryPlan.ts
|
|
79
360
|
function isPrismaValuePlaceholder(value) {
|
|
@@ -83,46 +364,49 @@ function isPrismaValueGenerator(value) {
|
|
|
83
364
|
return typeof value === "object" && value !== null && value["prisma__type"] === "generatorCall";
|
|
84
365
|
}
|
|
85
366
|
|
|
86
|
-
// src/utils.ts
|
|
87
|
-
function assertNever(_, message) {
|
|
88
|
-
throw new Error(message);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
367
|
// src/interpreter/renderQuery.ts
|
|
92
368
|
function renderQuery(dbQuery, scope, generators) {
|
|
93
369
|
const queryType = dbQuery.type;
|
|
94
370
|
switch (queryType) {
|
|
95
371
|
case "rawSql":
|
|
96
|
-
return renderRawSql(dbQuery.sql,
|
|
372
|
+
return renderRawSql(dbQuery.sql, evaluateParams(dbQuery.params, scope, generators));
|
|
97
373
|
case "templateSql":
|
|
98
374
|
return renderTemplateSql(
|
|
99
375
|
dbQuery.fragments,
|
|
100
376
|
dbQuery.placeholderFormat,
|
|
101
|
-
|
|
377
|
+
evaluateParams(dbQuery.params, scope, generators)
|
|
102
378
|
);
|
|
103
379
|
default:
|
|
104
380
|
assertNever(queryType, `Invalid query type`);
|
|
105
381
|
}
|
|
106
382
|
}
|
|
107
|
-
function
|
|
108
|
-
return params.map((param) =>
|
|
109
|
-
|
|
110
|
-
|
|
383
|
+
function evaluateParams(params, scope, generators) {
|
|
384
|
+
return params.map((param) => evaluateParam(param, scope, generators));
|
|
385
|
+
}
|
|
386
|
+
function evaluateParam(param, scope, generators) {
|
|
387
|
+
let value = param;
|
|
388
|
+
while (doesRequireEvaluation(value)) {
|
|
389
|
+
if (isPrismaValuePlaceholder(value)) {
|
|
390
|
+
const found = scope[value.prisma__value.name];
|
|
391
|
+
if (found === void 0) {
|
|
392
|
+
throw new Error(`Missing value for query variable ${value.prisma__value.name}`);
|
|
393
|
+
}
|
|
394
|
+
value = found;
|
|
395
|
+
} else if (isPrismaValueGenerator(value)) {
|
|
396
|
+
const { name, args } = value.prisma__value;
|
|
111
397
|
const generator = generators[name];
|
|
112
398
|
if (!generator) {
|
|
113
399
|
throw new Error(`Encountered an unknown generator '${name}'`);
|
|
114
400
|
}
|
|
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}`);
|
|
401
|
+
value = generator.generate(...args.map((arg) => evaluateParam(arg, scope, generators)));
|
|
402
|
+
} else {
|
|
403
|
+
assertNever(value, `Unexpected unevaluated value type: ${value}`);
|
|
123
404
|
}
|
|
124
|
-
|
|
125
|
-
|
|
405
|
+
}
|
|
406
|
+
if (Array.isArray(value)) {
|
|
407
|
+
value = value.map((el) => evaluateParam(el, scope, generators));
|
|
408
|
+
}
|
|
409
|
+
return value;
|
|
126
410
|
}
|
|
127
411
|
function renderTemplateSql(fragments, placeholderFormat, params) {
|
|
128
412
|
let paramIndex = 0;
|
|
@@ -151,6 +435,29 @@ function renderTemplateSql(fragments, placeholderFormat, params) {
|
|
|
151
435
|
}).join(",");
|
|
152
436
|
return `(${placeholders})`;
|
|
153
437
|
}
|
|
438
|
+
case "parameterTupleList": {
|
|
439
|
+
if (paramIndex >= params.length) {
|
|
440
|
+
throw new Error(`Malformed query template. Fragments attempt to read over ${params.length} parameters.`);
|
|
441
|
+
}
|
|
442
|
+
const paramValue = params[paramIndex++];
|
|
443
|
+
if (!Array.isArray(paramValue)) {
|
|
444
|
+
throw new Error(`Malformed query template. Tuple list expected.`);
|
|
445
|
+
}
|
|
446
|
+
if (paramValue.length === 0) {
|
|
447
|
+
throw new Error(`Malformed query template. Tuple list cannot be empty.`);
|
|
448
|
+
}
|
|
449
|
+
const tupleList = paramValue.map((tuple) => {
|
|
450
|
+
if (!Array.isArray(tuple)) {
|
|
451
|
+
throw new Error(`Malformed query template. Tuple expected.`);
|
|
452
|
+
}
|
|
453
|
+
const elements = tuple.map((value) => {
|
|
454
|
+
flattenedParams.push(value);
|
|
455
|
+
return formatPlaceholder(placeholderFormat, placeholderNumber++);
|
|
456
|
+
}).join(",");
|
|
457
|
+
return `(${elements})`;
|
|
458
|
+
}).join(",");
|
|
459
|
+
return tupleList;
|
|
460
|
+
}
|
|
154
461
|
default:
|
|
155
462
|
assertNever(fragmentType, "Invalid fragment type");
|
|
156
463
|
}
|
|
@@ -209,6 +516,9 @@ function placeholderTypeToArgType(type) {
|
|
|
209
516
|
}
|
|
210
517
|
return mappedType;
|
|
211
518
|
}
|
|
519
|
+
function doesRequireEvaluation(param) {
|
|
520
|
+
return isPrismaValuePlaceholder(param) || isPrismaValueGenerator(param);
|
|
521
|
+
}
|
|
212
522
|
|
|
213
523
|
// src/interpreter/serialize.ts
|
|
214
524
|
function serialize(resultSet) {
|
|
@@ -238,13 +548,17 @@ var QueryInterpreter = class {
|
|
|
238
548
|
#placeholderValues;
|
|
239
549
|
#onQuery;
|
|
240
550
|
#generators = new GeneratorRegistry();
|
|
241
|
-
|
|
551
|
+
#tracingHelper;
|
|
552
|
+
constructor({ transactionManager, placeholderValues, onQuery, tracingHelper }) {
|
|
242
553
|
this.#transactionManager = transactionManager;
|
|
243
554
|
this.#placeholderValues = placeholderValues;
|
|
244
555
|
this.#onQuery = onQuery;
|
|
556
|
+
this.#tracingHelper = tracingHelper;
|
|
245
557
|
}
|
|
246
558
|
async run(queryPlan, queryable) {
|
|
247
|
-
return this.interpretNode(queryPlan, queryable, this.#placeholderValues, this.#generators.snapshot())
|
|
559
|
+
return this.interpretNode(queryPlan, queryable, this.#placeholderValues, this.#generators.snapshot()).catch(
|
|
560
|
+
(e) => rethrowAsUserFacing(e)
|
|
561
|
+
);
|
|
248
562
|
}
|
|
249
563
|
async interpretNode(node, queryable, scope, generators) {
|
|
250
564
|
switch (node.type) {
|
|
@@ -283,13 +597,13 @@ var QueryInterpreter = class {
|
|
|
283
597
|
}
|
|
284
598
|
case "execute": {
|
|
285
599
|
const query = renderQuery(node.args, scope, generators);
|
|
286
|
-
return this.#withQueryEvent(query, async () => {
|
|
600
|
+
return this.#withQueryEvent(query, queryable, async () => {
|
|
287
601
|
return await queryable.executeRaw(query);
|
|
288
602
|
});
|
|
289
603
|
}
|
|
290
604
|
case "query": {
|
|
291
605
|
const query = renderQuery(node.args, scope, generators);
|
|
292
|
-
return this.#withQueryEvent(query, async () => {
|
|
606
|
+
return this.#withQueryEvent(query, queryable, async () => {
|
|
293
607
|
return serialize(await queryable.queryRaw(query));
|
|
294
608
|
});
|
|
295
609
|
}
|
|
@@ -350,24 +664,38 @@ var QueryInterpreter = class {
|
|
|
350
664
|
throw e;
|
|
351
665
|
}
|
|
352
666
|
}
|
|
353
|
-
|
|
354
|
-
node;
|
|
355
|
-
|
|
667
|
+
case "dataMap": {
|
|
668
|
+
const data = await this.interpretNode(node.args.expr, queryable, scope, generators);
|
|
669
|
+
return applyDataMap(data, node.args.structure);
|
|
356
670
|
}
|
|
671
|
+
default:
|
|
672
|
+
assertNever(node, `Unexpected node type: ${node.type}`);
|
|
357
673
|
}
|
|
358
674
|
}
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
675
|
+
#withQueryEvent(query, queryable, execute) {
|
|
676
|
+
return this.#tracingHelper.runInChildSpan(
|
|
677
|
+
{
|
|
678
|
+
name: "db_query",
|
|
679
|
+
kind: SpanKind.CLIENT,
|
|
680
|
+
attributes: {
|
|
681
|
+
"db.query.text": query.sql,
|
|
682
|
+
"db.system.name": providerToOtelSystem(queryable.provider)
|
|
683
|
+
}
|
|
684
|
+
},
|
|
685
|
+
async () => {
|
|
686
|
+
const timestamp = /* @__PURE__ */ new Date();
|
|
687
|
+
const startInstant = performance.now();
|
|
688
|
+
const result = await execute();
|
|
689
|
+
const endInstant = performance.now();
|
|
690
|
+
this.#onQuery?.({
|
|
691
|
+
timestamp,
|
|
692
|
+
duration: endInstant - startInstant,
|
|
693
|
+
query: query.sql,
|
|
694
|
+
params: query.args
|
|
695
|
+
});
|
|
696
|
+
return result;
|
|
697
|
+
}
|
|
698
|
+
);
|
|
371
699
|
}
|
|
372
700
|
};
|
|
373
701
|
function isEmpty(value) {
|
|
@@ -412,6 +740,8 @@ function attachChildrenToParent(parentRecord, children) {
|
|
|
412
740
|
function filterChildRecords(records, parentRecord, joinExpr) {
|
|
413
741
|
if (Array.isArray(records)) {
|
|
414
742
|
return records.filter((record) => childRecordMatchesParent(asRecord(record), parentRecord, joinExpr));
|
|
743
|
+
} else if (records === null) {
|
|
744
|
+
return null;
|
|
415
745
|
} else {
|
|
416
746
|
const record = asRecord(records);
|
|
417
747
|
return childRecordMatchesParent(record, parentRecord, joinExpr) ? record : null;
|
|
@@ -500,11 +830,20 @@ var TransactionManager = class {
|
|
|
500
830
|
closedTransactions = [];
|
|
501
831
|
driverAdapter;
|
|
502
832
|
transactionOptions;
|
|
503
|
-
|
|
833
|
+
tracingHelper;
|
|
834
|
+
constructor({
|
|
835
|
+
driverAdapter,
|
|
836
|
+
transactionOptions,
|
|
837
|
+
tracingHelper
|
|
838
|
+
}) {
|
|
504
839
|
this.driverAdapter = driverAdapter;
|
|
505
840
|
this.transactionOptions = transactionOptions;
|
|
841
|
+
this.tracingHelper = tracingHelper;
|
|
506
842
|
}
|
|
507
843
|
async startTransaction(options) {
|
|
844
|
+
return await this.tracingHelper.runInChildSpan("start_transaction", () => this.#startTransactionImpl(options));
|
|
845
|
+
}
|
|
846
|
+
async #startTransactionImpl(options) {
|
|
508
847
|
const validatedOptions = options !== void 0 ? this.validateOptions(options) : this.transactionOptions;
|
|
509
848
|
const transaction = {
|
|
510
849
|
id: await randomUUID(),
|
|
@@ -538,12 +877,16 @@ var TransactionManager = class {
|
|
|
538
877
|
}
|
|
539
878
|
}
|
|
540
879
|
async commitTransaction(transactionId) {
|
|
541
|
-
|
|
542
|
-
|
|
880
|
+
return await this.tracingHelper.runInChildSpan("commit_transaction", async () => {
|
|
881
|
+
const txw = this.getActiveTransaction(transactionId, "commit");
|
|
882
|
+
await this.closeTransaction(txw, "committed");
|
|
883
|
+
});
|
|
543
884
|
}
|
|
544
885
|
async rollbackTransaction(transactionId) {
|
|
545
|
-
|
|
546
|
-
|
|
886
|
+
return await this.tracingHelper.runInChildSpan("rollback_transaction", async () => {
|
|
887
|
+
const txw = this.getActiveTransaction(transactionId, "rollback");
|
|
888
|
+
await this.closeTransaction(txw, "rolled_back");
|
|
889
|
+
});
|
|
547
890
|
}
|
|
548
891
|
getTransaction(txInfo, operation) {
|
|
549
892
|
const tx = this.getActiveTransaction(txInfo.id, operation);
|
|
@@ -632,6 +975,8 @@ export {
|
|
|
632
975
|
QueryInterpreter,
|
|
633
976
|
TransactionManager,
|
|
634
977
|
TransactionManagerError,
|
|
978
|
+
UserFacingError,
|
|
635
979
|
isPrismaValueGenerator,
|
|
636
|
-
isPrismaValuePlaceholder
|
|
980
|
+
isPrismaValuePlaceholder,
|
|
981
|
+
noopTracingHelper
|
|
637
982
|
};
|
|
@@ -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>;
|
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.30",
|
|
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/
|
|
33
|
-
"@prisma/
|
|
33
|
+
"@prisma/debug": "6.7.0-dev.30",
|
|
34
|
+
"@prisma/driver-adapter-utils": "6.7.0-dev.30"
|
|
34
35
|
},
|
|
35
36
|
"devDependencies": {
|
|
36
37
|
"@types/jest": "29.5.14",
|