@prisma/client-engine-runtime 6.7.0-integration-push-sunrovnkrkpv.1 → 6.7.0
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 +92 -2
- package/dist/index.d.ts +92 -2
- package/dist/index.js +416 -82
- package/dist/index.mjs +413 -81
- package/dist/interpreter/DataMapper.d.ts +3 -0
- package/dist/interpreter/QueryInterpreter.d.ts +12 -2
- package/dist/interpreter/serializeSql.d.ts +2 -0
- 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/interpreter/serialize.d.ts +0 -2
- /package/dist/interpreter/{serialize.test.d.ts → serializeSql.test.d.ts} +0 -0
package/dist/index.js
CHANGED
|
@@ -33,11 +33,277 @@ __export(index_exports, {
|
|
|
33
33
|
QueryInterpreter: () => QueryInterpreter,
|
|
34
34
|
TransactionManager: () => TransactionManager,
|
|
35
35
|
TransactionManagerError: () => TransactionManagerError,
|
|
36
|
+
UserFacingError: () => UserFacingError,
|
|
36
37
|
isPrismaValueGenerator: () => isPrismaValueGenerator,
|
|
37
|
-
isPrismaValuePlaceholder: () => isPrismaValuePlaceholder
|
|
38
|
+
isPrismaValuePlaceholder: () => isPrismaValuePlaceholder,
|
|
39
|
+
noopTracingHelper: () => noopTracingHelper
|
|
38
40
|
});
|
|
39
41
|
module.exports = __toCommonJS(index_exports);
|
|
40
42
|
|
|
43
|
+
// src/interpreter/QueryInterpreter.ts
|
|
44
|
+
var import_api = require("@opentelemetry/api");
|
|
45
|
+
|
|
46
|
+
// src/utils.ts
|
|
47
|
+
function assertNever(_, message) {
|
|
48
|
+
throw new Error(message);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// src/tracing.ts
|
|
52
|
+
var noopTracingHelper = {
|
|
53
|
+
runInChildSpan(_, callback) {
|
|
54
|
+
return callback();
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
function providerToOtelSystem(provider) {
|
|
58
|
+
switch (provider) {
|
|
59
|
+
case "postgres":
|
|
60
|
+
return "postgresql";
|
|
61
|
+
case "mysql":
|
|
62
|
+
return "mysql";
|
|
63
|
+
case "sqlite":
|
|
64
|
+
return "sqlite";
|
|
65
|
+
default:
|
|
66
|
+
assertNever(provider, `Unknown provider: ${provider}`);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// src/UserFacingError.ts
|
|
71
|
+
var import_driver_adapter_utils = require("@prisma/driver-adapter-utils");
|
|
72
|
+
var UserFacingError = class extends Error {
|
|
73
|
+
name = "UserFacingError";
|
|
74
|
+
code;
|
|
75
|
+
meta;
|
|
76
|
+
constructor(message, code, meta) {
|
|
77
|
+
super(message);
|
|
78
|
+
this.code = code;
|
|
79
|
+
this.meta = meta;
|
|
80
|
+
}
|
|
81
|
+
toQueryResponseErrorObject() {
|
|
82
|
+
return {
|
|
83
|
+
error: this.message,
|
|
84
|
+
user_facing_error: {
|
|
85
|
+
is_panic: false,
|
|
86
|
+
message: this.message,
|
|
87
|
+
meta: this.meta,
|
|
88
|
+
error_code: this.code
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
function rethrowAsUserFacing(error) {
|
|
94
|
+
if (!(0, import_driver_adapter_utils.isDriverAdapterError)(error)) {
|
|
95
|
+
throw error;
|
|
96
|
+
}
|
|
97
|
+
const code = getErrorCode(error);
|
|
98
|
+
const message = renderErrorMessage(error);
|
|
99
|
+
if (!code || !message) {
|
|
100
|
+
throw error;
|
|
101
|
+
}
|
|
102
|
+
throw new UserFacingError(message, code, error);
|
|
103
|
+
}
|
|
104
|
+
function getErrorCode(err) {
|
|
105
|
+
switch (err.cause.kind) {
|
|
106
|
+
case "AuthenticationFailed":
|
|
107
|
+
return "P1000";
|
|
108
|
+
case "DatabaseDoesNotExist":
|
|
109
|
+
return "P1003";
|
|
110
|
+
case "SocketTimeout":
|
|
111
|
+
return "P1008";
|
|
112
|
+
case "DatabaseAlreadyExists":
|
|
113
|
+
return "P1009";
|
|
114
|
+
case "DatabaseAccessDenied":
|
|
115
|
+
return "P1010";
|
|
116
|
+
case "LengthMismatch":
|
|
117
|
+
return "P2000";
|
|
118
|
+
case "UniqueConstraintViolation":
|
|
119
|
+
return "P2002";
|
|
120
|
+
case "ForeignKeyConstraintViolation":
|
|
121
|
+
return "P2003";
|
|
122
|
+
case "UnsupportedNativeDataType":
|
|
123
|
+
return "P2010";
|
|
124
|
+
case "NullConstraintViolation":
|
|
125
|
+
return "P2011";
|
|
126
|
+
case "TableDoesNotExist":
|
|
127
|
+
return "P2021";
|
|
128
|
+
case "ColumnNotFound":
|
|
129
|
+
return "P2022";
|
|
130
|
+
case "InvalidIsolationLevel":
|
|
131
|
+
return "P2023";
|
|
132
|
+
case "TransactionWriteConflict":
|
|
133
|
+
return "P2034";
|
|
134
|
+
case "GenericJs":
|
|
135
|
+
return "P2036";
|
|
136
|
+
case "TooManyConnections":
|
|
137
|
+
return "P2037";
|
|
138
|
+
case "postgres":
|
|
139
|
+
case "sqlite":
|
|
140
|
+
case "mysql":
|
|
141
|
+
return;
|
|
142
|
+
default:
|
|
143
|
+
assertNever(err.cause, `Unknown error: ${err.cause}`);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
function renderErrorMessage(err) {
|
|
147
|
+
switch (err.cause.kind) {
|
|
148
|
+
case "AuthenticationFailed": {
|
|
149
|
+
const user = err.cause.user ?? "(not available)";
|
|
150
|
+
return `Authentication failed against the database server, the provided database credentials for \`${user}\` are not valid`;
|
|
151
|
+
}
|
|
152
|
+
case "DatabaseDoesNotExist": {
|
|
153
|
+
const db = err.cause.db ?? "(not available)";
|
|
154
|
+
return `Database \`${db}\` does not exist on the database server`;
|
|
155
|
+
}
|
|
156
|
+
case "SocketTimeout":
|
|
157
|
+
return `Operation has timed out`;
|
|
158
|
+
case "DatabaseAlreadyExists": {
|
|
159
|
+
const db = err.cause.db ?? "(not available)";
|
|
160
|
+
return `Database \`${db}\` already exists on the database server`;
|
|
161
|
+
}
|
|
162
|
+
case "DatabaseAccessDenied": {
|
|
163
|
+
const db = err.cause.db ?? "(not available)";
|
|
164
|
+
return `User was denied access on the database \`${db}\``;
|
|
165
|
+
}
|
|
166
|
+
case "LengthMismatch": {
|
|
167
|
+
const column = err.cause.column ?? "(not available)";
|
|
168
|
+
return `The provided value for the column is too long for the column's type. Column: ${column}`;
|
|
169
|
+
}
|
|
170
|
+
case "UniqueConstraintViolation":
|
|
171
|
+
return `Unique constraint failed on the ${renderConstraint({ fields: err.cause.fields })}`;
|
|
172
|
+
case "ForeignKeyConstraintViolation":
|
|
173
|
+
return `Foreign key constraint violated on the ${renderConstraint(err.cause.constraint)}`;
|
|
174
|
+
case "UnsupportedNativeDataType":
|
|
175
|
+
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\`.`;
|
|
176
|
+
case "NullConstraintViolation":
|
|
177
|
+
return `Null constraint violation on the ${renderConstraint({ fields: err.cause.fields })}`;
|
|
178
|
+
case "TableDoesNotExist": {
|
|
179
|
+
const table = err.cause.table ?? "(not available)";
|
|
180
|
+
return `The table \`${table}\` does not exist in the current database.`;
|
|
181
|
+
}
|
|
182
|
+
case "ColumnNotFound": {
|
|
183
|
+
const column = err.cause.column ?? "(not available)";
|
|
184
|
+
return `The column \`${column}\` does not exist in the current database.`;
|
|
185
|
+
}
|
|
186
|
+
case "InvalidIsolationLevel":
|
|
187
|
+
return `Invalid isolation level \`${err.cause.level}\``;
|
|
188
|
+
case "TransactionWriteConflict":
|
|
189
|
+
return `Transaction failed due to a write conflict or a deadlock. Please retry your transaction`;
|
|
190
|
+
case "GenericJs":
|
|
191
|
+
return `Error in external connector (id ${err.cause.id})`;
|
|
192
|
+
case "TooManyConnections":
|
|
193
|
+
return `Too many database connections opened: ${err.cause.cause}`;
|
|
194
|
+
case "sqlite":
|
|
195
|
+
case "postgres":
|
|
196
|
+
case "mysql":
|
|
197
|
+
return;
|
|
198
|
+
default:
|
|
199
|
+
assertNever(err.cause, `Unknown error: ${err.cause}`);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
function renderConstraint(constraint) {
|
|
203
|
+
if (constraint && "fields" in constraint) {
|
|
204
|
+
return `fields: (${constraint.fields.map((field) => `\`${field}\``).join(", ")})`;
|
|
205
|
+
} else if (constraint && "index" in constraint) {
|
|
206
|
+
return `constraint: \`${constraint.index}\``;
|
|
207
|
+
} else if (constraint && "foreignKey" in constraint) {
|
|
208
|
+
return `foreign key`;
|
|
209
|
+
}
|
|
210
|
+
return "(not available)";
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// src/interpreter/DataMapper.ts
|
|
214
|
+
function applyDataMap(data, structure) {
|
|
215
|
+
switch (structure.type) {
|
|
216
|
+
case "Object":
|
|
217
|
+
return mapArrayOrObject(data, structure.fields);
|
|
218
|
+
case "Value":
|
|
219
|
+
return mapValue(data, structure.resultType);
|
|
220
|
+
default:
|
|
221
|
+
assertNever(structure, `Invalid data mapping type: '${structure.type}'`);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
function mapArrayOrObject(data, fields) {
|
|
225
|
+
if (data === null) return null;
|
|
226
|
+
if (Array.isArray(data)) {
|
|
227
|
+
const rows = data;
|
|
228
|
+
return rows.map((row) => mapObject(row, fields));
|
|
229
|
+
}
|
|
230
|
+
if (typeof data === "object") {
|
|
231
|
+
const row = data;
|
|
232
|
+
return mapObject(row, fields);
|
|
233
|
+
}
|
|
234
|
+
throw new Error(`DataMapper: Expected an array or an object, got: ${typeof data}`);
|
|
235
|
+
}
|
|
236
|
+
function mapObject(data, fields) {
|
|
237
|
+
if (typeof data !== "object") {
|
|
238
|
+
throw new Error(`DataMapper: Expected an object, but got '${typeof data}'`);
|
|
239
|
+
}
|
|
240
|
+
const result = {};
|
|
241
|
+
for (const [name, node] of Object.entries(fields)) {
|
|
242
|
+
switch (node.type) {
|
|
243
|
+
case "Object":
|
|
244
|
+
if (Object.hasOwn(data, name)) {
|
|
245
|
+
result[name] = mapArrayOrObject(data[name], node.fields);
|
|
246
|
+
} else {
|
|
247
|
+
throw new Error(
|
|
248
|
+
`DataMapper: Missing data field (Object): '${name}'; node: ${JSON.stringify(node)}; data: ${JSON.stringify(data)}`
|
|
249
|
+
);
|
|
250
|
+
}
|
|
251
|
+
break;
|
|
252
|
+
case "Value":
|
|
253
|
+
{
|
|
254
|
+
const dbName = node.dbName;
|
|
255
|
+
if (Object.hasOwn(data, dbName)) {
|
|
256
|
+
result[name] = mapValue(data[dbName], node.resultType);
|
|
257
|
+
} else {
|
|
258
|
+
throw new Error(
|
|
259
|
+
`DataMapper: Missing data field (Value): '${dbName}'; node: ${JSON.stringify(node)}; data: ${JSON.stringify(data)}`
|
|
260
|
+
);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
break;
|
|
264
|
+
default:
|
|
265
|
+
assertNever(node, `DataMapper: Invalid data mapping node type: '${node.type}'`);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
return result;
|
|
269
|
+
}
|
|
270
|
+
function mapValue(value, resultType) {
|
|
271
|
+
if (value === null) return null;
|
|
272
|
+
switch (resultType.type) {
|
|
273
|
+
case "Any":
|
|
274
|
+
return value;
|
|
275
|
+
case "String":
|
|
276
|
+
return typeof value === "string" ? value : `${value}`;
|
|
277
|
+
case "Int":
|
|
278
|
+
return typeof value === "number" ? value : parseInt(`${value}`, 10);
|
|
279
|
+
case "BigInt":
|
|
280
|
+
return typeof value === "bigint" ? value : BigInt(`${value}`);
|
|
281
|
+
case "Float":
|
|
282
|
+
return typeof value === "number" ? value : parseFloat(`${value}`);
|
|
283
|
+
case "Boolean":
|
|
284
|
+
return typeof value === "boolean" ? value : value !== "0";
|
|
285
|
+
case "Decimal":
|
|
286
|
+
return typeof value === "number" ? value : parseFloat(`${value}`);
|
|
287
|
+
case "Date":
|
|
288
|
+
return value instanceof Date ? value : /* @__PURE__ */ new Date(`${value}`);
|
|
289
|
+
case "Array": {
|
|
290
|
+
const values = value;
|
|
291
|
+
return values.map((v) => {
|
|
292
|
+
mapValue(v, resultType.inner);
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
case "Object":
|
|
296
|
+
return typeof value === "object" ? value : { value };
|
|
297
|
+
case "Bytes":
|
|
298
|
+
if (typeof value !== "string") {
|
|
299
|
+
throw new Error(`DataMapper: Bytes data is not a string, got: ${typeof value}`);
|
|
300
|
+
}
|
|
301
|
+
return value;
|
|
302
|
+
default:
|
|
303
|
+
assertNever(resultType, `DataMapper: Unknown result type: ${resultType.type}`);
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
41
307
|
// src/interpreter/generators.ts
|
|
42
308
|
var import_cuid = __toESM(require("@bugsnag/cuid"));
|
|
43
309
|
var import_cuid2 = require("@paralleldrive/cuid2");
|
|
@@ -52,6 +318,7 @@ var GeneratorRegistry = class {
|
|
|
52
318
|
this.register("cuid", new CuidGenerator());
|
|
53
319
|
this.register("ulid", new UlidGenerator());
|
|
54
320
|
this.register("nanoid", new NanoIdGenerator());
|
|
321
|
+
this.register("product", new ProductGenerator());
|
|
55
322
|
}
|
|
56
323
|
/**
|
|
57
324
|
* Returns a snapshot of the generator registry. It's 'frozen' in time at the moment of this
|
|
@@ -114,6 +381,22 @@ var NanoIdGenerator = class {
|
|
|
114
381
|
}
|
|
115
382
|
}
|
|
116
383
|
};
|
|
384
|
+
var ProductGenerator = class {
|
|
385
|
+
generate(lhs, rhs) {
|
|
386
|
+
if (lhs === void 0 || rhs === void 0) {
|
|
387
|
+
throw new Error("Invalid Product generator arguments");
|
|
388
|
+
}
|
|
389
|
+
if (Array.isArray(lhs) && Array.isArray(rhs)) {
|
|
390
|
+
return lhs.flatMap((l) => rhs.map((r) => [l, r]));
|
|
391
|
+
} else if (Array.isArray(lhs)) {
|
|
392
|
+
return lhs.map((l) => [l, rhs]);
|
|
393
|
+
} else if (Array.isArray(rhs)) {
|
|
394
|
+
return rhs.map((r) => [lhs, r]);
|
|
395
|
+
} else {
|
|
396
|
+
return [[lhs, rhs]];
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
};
|
|
117
400
|
|
|
118
401
|
// src/QueryPlan.ts
|
|
119
402
|
function isPrismaValuePlaceholder(value) {
|
|
@@ -123,46 +406,49 @@ function isPrismaValueGenerator(value) {
|
|
|
123
406
|
return typeof value === "object" && value !== null && value["prisma__type"] === "generatorCall";
|
|
124
407
|
}
|
|
125
408
|
|
|
126
|
-
// src/utils.ts
|
|
127
|
-
function assertNever(_, message) {
|
|
128
|
-
throw new Error(message);
|
|
129
|
-
}
|
|
130
|
-
|
|
131
409
|
// src/interpreter/renderQuery.ts
|
|
132
410
|
function renderQuery(dbQuery, scope, generators) {
|
|
133
411
|
const queryType = dbQuery.type;
|
|
134
412
|
switch (queryType) {
|
|
135
413
|
case "rawSql":
|
|
136
|
-
return renderRawSql(dbQuery.sql,
|
|
414
|
+
return renderRawSql(dbQuery.sql, evaluateParams(dbQuery.params, scope, generators));
|
|
137
415
|
case "templateSql":
|
|
138
416
|
return renderTemplateSql(
|
|
139
417
|
dbQuery.fragments,
|
|
140
418
|
dbQuery.placeholderFormat,
|
|
141
|
-
|
|
419
|
+
evaluateParams(dbQuery.params, scope, generators)
|
|
142
420
|
);
|
|
143
421
|
default:
|
|
144
422
|
assertNever(queryType, `Invalid query type`);
|
|
145
423
|
}
|
|
146
424
|
}
|
|
147
|
-
function
|
|
148
|
-
return params.map((param) =>
|
|
149
|
-
|
|
150
|
-
|
|
425
|
+
function evaluateParams(params, scope, generators) {
|
|
426
|
+
return params.map((param) => evaluateParam(param, scope, generators));
|
|
427
|
+
}
|
|
428
|
+
function evaluateParam(param, scope, generators) {
|
|
429
|
+
let value = param;
|
|
430
|
+
while (doesRequireEvaluation(value)) {
|
|
431
|
+
if (isPrismaValuePlaceholder(value)) {
|
|
432
|
+
const found = scope[value.prisma__value.name];
|
|
433
|
+
if (found === void 0) {
|
|
434
|
+
throw new Error(`Missing value for query variable ${value.prisma__value.name}`);
|
|
435
|
+
}
|
|
436
|
+
value = found;
|
|
437
|
+
} else if (isPrismaValueGenerator(value)) {
|
|
438
|
+
const { name, args } = value.prisma__value;
|
|
151
439
|
const generator = generators[name];
|
|
152
440
|
if (!generator) {
|
|
153
441
|
throw new Error(`Encountered an unknown generator '${name}'`);
|
|
154
442
|
}
|
|
155
|
-
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
return param;
|
|
159
|
-
}
|
|
160
|
-
const value = scope[param.prisma__value.name];
|
|
161
|
-
if (value === void 0) {
|
|
162
|
-
throw new Error(`Missing value for query variable ${param.prisma__value.name}`);
|
|
443
|
+
value = generator.generate(...args.map((arg) => evaluateParam(arg, scope, generators)));
|
|
444
|
+
} else {
|
|
445
|
+
assertNever(value, `Unexpected unevaluated value type: ${value}`);
|
|
163
446
|
}
|
|
164
|
-
|
|
165
|
-
|
|
447
|
+
}
|
|
448
|
+
if (Array.isArray(value)) {
|
|
449
|
+
value = value.map((el) => evaluateParam(el, scope, generators));
|
|
450
|
+
}
|
|
451
|
+
return value;
|
|
166
452
|
}
|
|
167
453
|
function renderTemplateSql(fragments, placeholderFormat, params) {
|
|
168
454
|
let paramIndex = 0;
|
|
@@ -191,6 +477,29 @@ function renderTemplateSql(fragments, placeholderFormat, params) {
|
|
|
191
477
|
}).join(",");
|
|
192
478
|
return `(${placeholders})`;
|
|
193
479
|
}
|
|
480
|
+
case "parameterTupleList": {
|
|
481
|
+
if (paramIndex >= params.length) {
|
|
482
|
+
throw new Error(`Malformed query template. Fragments attempt to read over ${params.length} parameters.`);
|
|
483
|
+
}
|
|
484
|
+
const paramValue = params[paramIndex++];
|
|
485
|
+
if (!Array.isArray(paramValue)) {
|
|
486
|
+
throw new Error(`Malformed query template. Tuple list expected.`);
|
|
487
|
+
}
|
|
488
|
+
if (paramValue.length === 0) {
|
|
489
|
+
throw new Error(`Malformed query template. Tuple list cannot be empty.`);
|
|
490
|
+
}
|
|
491
|
+
const tupleList = paramValue.map((tuple) => {
|
|
492
|
+
if (!Array.isArray(tuple)) {
|
|
493
|
+
throw new Error(`Malformed query template. Tuple expected.`);
|
|
494
|
+
}
|
|
495
|
+
const elements = tuple.map((value) => {
|
|
496
|
+
flattenedParams.push(value);
|
|
497
|
+
return formatPlaceholder(placeholderFormat, placeholderNumber++);
|
|
498
|
+
}).join(",");
|
|
499
|
+
return `(${elements})`;
|
|
500
|
+
}).join(",");
|
|
501
|
+
return tupleList;
|
|
502
|
+
}
|
|
194
503
|
default:
|
|
195
504
|
assertNever(fragmentType, "Invalid fragment type");
|
|
196
505
|
}
|
|
@@ -249,9 +558,12 @@ function placeholderTypeToArgType(type) {
|
|
|
249
558
|
}
|
|
250
559
|
return mappedType;
|
|
251
560
|
}
|
|
561
|
+
function doesRequireEvaluation(param) {
|
|
562
|
+
return isPrismaValuePlaceholder(param) || isPrismaValueGenerator(param);
|
|
563
|
+
}
|
|
252
564
|
|
|
253
|
-
// src/interpreter/
|
|
254
|
-
function
|
|
565
|
+
// src/interpreter/serializeSql.ts
|
|
566
|
+
function serializeSql(resultSet) {
|
|
255
567
|
return resultSet.rows.map(
|
|
256
568
|
(row) => row.reduce((acc, value, index) => {
|
|
257
569
|
const splitByDot = resultSet.columnNames[index].split(".");
|
|
@@ -273,18 +585,33 @@ function serialize(resultSet) {
|
|
|
273
585
|
}
|
|
274
586
|
|
|
275
587
|
// src/interpreter/QueryInterpreter.ts
|
|
276
|
-
var QueryInterpreter = class {
|
|
588
|
+
var QueryInterpreter = class _QueryInterpreter {
|
|
277
589
|
#transactionManager;
|
|
278
590
|
#placeholderValues;
|
|
279
591
|
#onQuery;
|
|
280
592
|
#generators = new GeneratorRegistry();
|
|
281
|
-
|
|
593
|
+
#tracingHelper;
|
|
594
|
+
#serializer;
|
|
595
|
+
constructor({ transactionManager, placeholderValues, onQuery, tracingHelper, serializer }) {
|
|
282
596
|
this.#transactionManager = transactionManager;
|
|
283
597
|
this.#placeholderValues = placeholderValues;
|
|
284
598
|
this.#onQuery = onQuery;
|
|
599
|
+
this.#tracingHelper = tracingHelper;
|
|
600
|
+
this.#serializer = serializer;
|
|
601
|
+
}
|
|
602
|
+
static forSql(options) {
|
|
603
|
+
return new _QueryInterpreter({
|
|
604
|
+
transactionManager: options.transactionManager,
|
|
605
|
+
placeholderValues: options.placeholderValues,
|
|
606
|
+
onQuery: options.onQuery,
|
|
607
|
+
tracingHelper: options.tracingHelper,
|
|
608
|
+
serializer: serializeSql
|
|
609
|
+
});
|
|
285
610
|
}
|
|
286
611
|
async run(queryPlan, queryable) {
|
|
287
|
-
return this.interpretNode(queryPlan, queryable, this.#placeholderValues, this.#generators.snapshot())
|
|
612
|
+
return this.interpretNode(queryPlan, queryable, this.#placeholderValues, this.#generators.snapshot()).catch(
|
|
613
|
+
(e) => rethrowAsUserFacing(e)
|
|
614
|
+
);
|
|
288
615
|
}
|
|
289
616
|
async interpretNode(node, queryable, scope, generators) {
|
|
290
617
|
switch (node.type) {
|
|
@@ -323,14 +650,14 @@ var QueryInterpreter = class {
|
|
|
323
650
|
}
|
|
324
651
|
case "execute": {
|
|
325
652
|
const query = renderQuery(node.args, scope, generators);
|
|
326
|
-
return this.#withQueryEvent(query, async () => {
|
|
653
|
+
return this.#withQueryEvent(query, queryable, async () => {
|
|
327
654
|
return await queryable.executeRaw(query);
|
|
328
655
|
});
|
|
329
656
|
}
|
|
330
657
|
case "query": {
|
|
331
658
|
const query = renderQuery(node.args, scope, generators);
|
|
332
|
-
return this.#withQueryEvent(query, async () => {
|
|
333
|
-
return
|
|
659
|
+
return this.#withQueryEvent(query, queryable, async () => {
|
|
660
|
+
return this.#serializer(await queryable.queryRaw(query));
|
|
334
661
|
});
|
|
335
662
|
}
|
|
336
663
|
case "reverse": {
|
|
@@ -380,7 +707,7 @@ var QueryInterpreter = class {
|
|
|
380
707
|
}
|
|
381
708
|
const transactionManager = this.#transactionManager.manager;
|
|
382
709
|
const transactionInfo = await transactionManager.startTransaction();
|
|
383
|
-
const transaction = transactionManager.getTransaction(transactionInfo, "
|
|
710
|
+
const transaction = transactionManager.getTransaction(transactionInfo, "query");
|
|
384
711
|
try {
|
|
385
712
|
const value = await this.interpretNode(node.args, transaction, scope, generators);
|
|
386
713
|
await transactionManager.commitTransaction(transactionInfo.id);
|
|
@@ -390,24 +717,38 @@ var QueryInterpreter = class {
|
|
|
390
717
|
throw e;
|
|
391
718
|
}
|
|
392
719
|
}
|
|
393
|
-
|
|
394
|
-
node;
|
|
395
|
-
|
|
720
|
+
case "dataMap": {
|
|
721
|
+
const data = await this.interpretNode(node.args.expr, queryable, scope, generators);
|
|
722
|
+
return applyDataMap(data, node.args.structure);
|
|
396
723
|
}
|
|
724
|
+
default:
|
|
725
|
+
assertNever(node, `Unexpected node type: ${node.type}`);
|
|
397
726
|
}
|
|
398
727
|
}
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
728
|
+
#withQueryEvent(query, queryable, execute) {
|
|
729
|
+
return this.#tracingHelper.runInChildSpan(
|
|
730
|
+
{
|
|
731
|
+
name: "db_query",
|
|
732
|
+
kind: import_api.SpanKind.CLIENT,
|
|
733
|
+
attributes: {
|
|
734
|
+
"db.query.text": query.sql,
|
|
735
|
+
"db.system.name": providerToOtelSystem(queryable.provider)
|
|
736
|
+
}
|
|
737
|
+
},
|
|
738
|
+
async () => {
|
|
739
|
+
const timestamp = /* @__PURE__ */ new Date();
|
|
740
|
+
const startInstant = performance.now();
|
|
741
|
+
const result = await execute();
|
|
742
|
+
const endInstant = performance.now();
|
|
743
|
+
this.#onQuery?.({
|
|
744
|
+
timestamp,
|
|
745
|
+
duration: endInstant - startInstant,
|
|
746
|
+
query: query.sql,
|
|
747
|
+
params: query.args
|
|
748
|
+
});
|
|
749
|
+
return result;
|
|
750
|
+
}
|
|
751
|
+
);
|
|
411
752
|
}
|
|
412
753
|
};
|
|
413
754
|
function isEmpty(value) {
|
|
@@ -452,6 +793,8 @@ function attachChildrenToParent(parentRecord, children) {
|
|
|
452
793
|
function filterChildRecords(records, parentRecord, joinExpr) {
|
|
453
794
|
if (Array.isArray(records)) {
|
|
454
795
|
return records.filter((record) => childRecordMatchesParent(asRecord(record), parentRecord, joinExpr));
|
|
796
|
+
} else if (records === null) {
|
|
797
|
+
return null;
|
|
455
798
|
} else {
|
|
456
799
|
const record = asRecord(records);
|
|
457
800
|
return childRecordMatchesParent(record, parentRecord, joinExpr) ? record : null;
|
|
@@ -486,11 +829,6 @@ var TransactionManagerError = class extends Error {
|
|
|
486
829
|
}
|
|
487
830
|
code = "P2028";
|
|
488
831
|
};
|
|
489
|
-
var TransactionDriverAdapterError = class extends TransactionManagerError {
|
|
490
|
-
constructor(message, errorParams) {
|
|
491
|
-
super(`Error from Driver Adapter: ${message}`, { ...errorParams.driverAdapterError });
|
|
492
|
-
}
|
|
493
|
-
};
|
|
494
832
|
var TransactionNotFoundError = class extends TransactionManagerError {
|
|
495
833
|
constructor() {
|
|
496
834
|
super(
|
|
@@ -505,10 +843,10 @@ var TransactionClosedError = class extends TransactionManagerError {
|
|
|
505
843
|
};
|
|
506
844
|
var TransactionRolledBackError = class extends TransactionManagerError {
|
|
507
845
|
constructor(operation) {
|
|
508
|
-
super(`Transaction already closed: A ${operation} cannot be executed on a
|
|
846
|
+
super(`Transaction already closed: A ${operation} cannot be executed on a transaction that was rolled back`);
|
|
509
847
|
}
|
|
510
848
|
};
|
|
511
|
-
var
|
|
849
|
+
var TransactionStartTimeoutError = class extends TransactionManagerError {
|
|
512
850
|
constructor() {
|
|
513
851
|
super("Unable to start a transaction in the given time.");
|
|
514
852
|
}
|
|
@@ -545,11 +883,20 @@ var TransactionManager = class {
|
|
|
545
883
|
closedTransactions = [];
|
|
546
884
|
driverAdapter;
|
|
547
885
|
transactionOptions;
|
|
548
|
-
|
|
886
|
+
tracingHelper;
|
|
887
|
+
constructor({
|
|
888
|
+
driverAdapter,
|
|
889
|
+
transactionOptions,
|
|
890
|
+
tracingHelper
|
|
891
|
+
}) {
|
|
549
892
|
this.driverAdapter = driverAdapter;
|
|
550
893
|
this.transactionOptions = transactionOptions;
|
|
894
|
+
this.tracingHelper = tracingHelper;
|
|
551
895
|
}
|
|
552
896
|
async startTransaction(options) {
|
|
897
|
+
return await this.tracingHelper.runInChildSpan("start_transaction", () => this.#startTransactionImpl(options));
|
|
898
|
+
}
|
|
899
|
+
async #startTransactionImpl(options) {
|
|
553
900
|
const validatedOptions = options !== void 0 ? this.validateOptions(options) : this.transactionOptions;
|
|
554
901
|
const transaction = {
|
|
555
902
|
id: await randomUUID(),
|
|
@@ -561,14 +908,7 @@ var TransactionManager = class {
|
|
|
561
908
|
};
|
|
562
909
|
this.transactions.set(transaction.id, transaction);
|
|
563
910
|
transaction.timer = this.startTransactionTimeout(transaction.id, validatedOptions.maxWait);
|
|
564
|
-
|
|
565
|
-
try {
|
|
566
|
-
startedTransaction = await this.driverAdapter.startTransaction(validatedOptions.isolationLevel);
|
|
567
|
-
} catch (error) {
|
|
568
|
-
throw new TransactionDriverAdapterError("Failed to start transaction.", {
|
|
569
|
-
driverAdapterError: error
|
|
570
|
-
});
|
|
571
|
-
}
|
|
911
|
+
const startedTransaction = await this.driverAdapter.startTransaction(validatedOptions.isolationLevel);
|
|
572
912
|
switch (transaction.status) {
|
|
573
913
|
case "waiting":
|
|
574
914
|
transaction.transaction = startedTransaction;
|
|
@@ -578,7 +918,7 @@ var TransactionManager = class {
|
|
|
578
918
|
transaction.timer = this.startTransactionTimeout(transaction.id, validatedOptions.timeout);
|
|
579
919
|
return { id: transaction.id };
|
|
580
920
|
case "timed_out":
|
|
581
|
-
throw new
|
|
921
|
+
throw new TransactionStartTimeoutError();
|
|
582
922
|
case "running":
|
|
583
923
|
case "committed":
|
|
584
924
|
case "rolled_back":
|
|
@@ -590,12 +930,16 @@ var TransactionManager = class {
|
|
|
590
930
|
}
|
|
591
931
|
}
|
|
592
932
|
async commitTransaction(transactionId) {
|
|
593
|
-
|
|
594
|
-
|
|
933
|
+
return await this.tracingHelper.runInChildSpan("commit_transaction", async () => {
|
|
934
|
+
const txw = this.getActiveTransaction(transactionId, "commit");
|
|
935
|
+
await this.closeTransaction(txw, "committed");
|
|
936
|
+
});
|
|
595
937
|
}
|
|
596
938
|
async rollbackTransaction(transactionId) {
|
|
597
|
-
|
|
598
|
-
|
|
939
|
+
return await this.tracingHelper.runInChildSpan("rollback_transaction", async () => {
|
|
940
|
+
const txw = this.getActiveTransaction(transactionId, "rollback");
|
|
941
|
+
await this.closeTransaction(txw, "rolled_back");
|
|
942
|
+
});
|
|
599
943
|
}
|
|
600
944
|
getTransaction(txInfo, operation) {
|
|
601
945
|
const tx = this.getActiveTransaction(txInfo.id, operation);
|
|
@@ -651,24 +995,12 @@ var TransactionManager = class {
|
|
|
651
995
|
debug("Closing transaction.", { transactionId: tx.id, status });
|
|
652
996
|
tx.status = status;
|
|
653
997
|
if (tx.transaction && status === "committed") {
|
|
654
|
-
|
|
655
|
-
await tx.transaction.commit();
|
|
656
|
-
} catch (error) {
|
|
657
|
-
throw new TransactionDriverAdapterError("Failed to commit transaction.", {
|
|
658
|
-
driverAdapterError: error
|
|
659
|
-
});
|
|
660
|
-
}
|
|
998
|
+
await tx.transaction.commit();
|
|
661
999
|
if (!tx.transaction.options.usePhantomQuery) {
|
|
662
1000
|
await tx.transaction.executeRaw(COMMIT_QUERY());
|
|
663
1001
|
}
|
|
664
1002
|
} else if (tx.transaction) {
|
|
665
|
-
|
|
666
|
-
await tx.transaction.rollback();
|
|
667
|
-
} catch (error) {
|
|
668
|
-
throw new TransactionDriverAdapterError("Failed to rollback transaction.", {
|
|
669
|
-
driverAdapterError: error
|
|
670
|
-
});
|
|
671
|
-
}
|
|
1003
|
+
await tx.transaction.rollback();
|
|
672
1004
|
if (!tx.transaction.options.usePhantomQuery) {
|
|
673
1005
|
await tx.transaction.executeRaw(ROLLBACK_QUERY());
|
|
674
1006
|
}
|
|
@@ -697,6 +1029,8 @@ var TransactionManager = class {
|
|
|
697
1029
|
QueryInterpreter,
|
|
698
1030
|
TransactionManager,
|
|
699
1031
|
TransactionManagerError,
|
|
1032
|
+
UserFacingError,
|
|
700
1033
|
isPrismaValueGenerator,
|
|
701
|
-
isPrismaValuePlaceholder
|
|
1034
|
+
isPrismaValuePlaceholder,
|
|
1035
|
+
noopTracingHelper
|
|
702
1036
|
});
|