@prisma/client-engine-runtime 6.14.0-dev.4 → 6.14.0-dev.40
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/batch.d.ts +19 -0
- package/dist/index.d.mts +59 -14
- package/dist/index.d.ts +59 -14
- package/dist/index.js +784 -394
- package/dist/index.mjs +781 -394
- package/dist/interpreter/{DataMapper.d.ts → data-mapper.d.ts} +1 -1
- package/dist/interpreter/in-memory-processing.d.ts +3 -0
- package/dist/interpreter/{QueryInterpreter.d.ts → query-interpreter.d.ts} +6 -4
- package/dist/interpreter/{renderQuery.d.ts → render-query.d.ts} +2 -2
- package/dist/interpreter/validation.d.ts +1 -1
- package/dist/json-protocol.d.ts +5 -0
- package/dist/{QueryPlan.d.ts → query-plan.d.ts} +16 -12
- package/dist/raw-json-protocol.d.ts +6 -0
- package/dist/{transactionManager/TransactionManagerErrors.d.ts → transaction-manager/transaction-manager-error.d.ts} +1 -1
- package/dist/{transactionManager/TransactionManager.d.ts → transaction-manager/transaction-manager.d.ts} +1 -1
- package/dist/transaction-manager/transaction-manager.test.d.ts +1 -0
- package/dist/{UserFacingError.d.ts → user-facing-error.d.ts} +1 -0
- package/package.json +3 -3
- /package/dist/interpreter/{renderQuery.test.d.ts → render-query.test.d.ts} +0 -0
- /package/dist/interpreter/{serializeSql.d.ts → serialize-sql.d.ts} +0 -0
- /package/dist/interpreter/{serializeSql.test.d.ts → serialize-sql.test.d.ts} +0 -0
- /package/dist/{transactionManager/TransactionManager.test.d.ts → json-protocol.test.d.ts} +0 -0
- /package/dist/{transactionManager/Transaction.d.ts → transaction-manager/transaction.d.ts} +0 -0
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
// src/
|
|
2
|
-
import Decimal2 from "decimal.js";
|
|
1
|
+
// src/json-protocol.ts
|
|
2
|
+
import { Decimal as Decimal2 } from "decimal.js";
|
|
3
3
|
|
|
4
4
|
// src/utils.ts
|
|
5
5
|
import Decimal from "decimal.js";
|
|
@@ -93,7 +93,303 @@ function safeJsonStringify(obj) {
|
|
|
93
93
|
});
|
|
94
94
|
}
|
|
95
95
|
|
|
96
|
-
// src/
|
|
96
|
+
// src/json-protocol.ts
|
|
97
|
+
function normalizeJsonProtocolValues(result) {
|
|
98
|
+
if (result === null) {
|
|
99
|
+
return result;
|
|
100
|
+
}
|
|
101
|
+
if (Array.isArray(result)) {
|
|
102
|
+
return result.map(normalizeJsonProtocolValues);
|
|
103
|
+
}
|
|
104
|
+
if (typeof result === "object") {
|
|
105
|
+
if (isTaggedValue(result)) {
|
|
106
|
+
return normalizeTaggedValue(result);
|
|
107
|
+
}
|
|
108
|
+
if (result.constructor !== null && result.constructor.name !== "Object") {
|
|
109
|
+
return result;
|
|
110
|
+
}
|
|
111
|
+
return mapObjectValues(result, normalizeJsonProtocolValues);
|
|
112
|
+
}
|
|
113
|
+
return result;
|
|
114
|
+
}
|
|
115
|
+
function isTaggedValue(value) {
|
|
116
|
+
return value !== null && typeof value == "object" && typeof value["$type"] === "string";
|
|
117
|
+
}
|
|
118
|
+
function normalizeTaggedValue({ $type, value }) {
|
|
119
|
+
switch ($type) {
|
|
120
|
+
case "BigInt":
|
|
121
|
+
return { $type, value: String(value) };
|
|
122
|
+
case "Bytes":
|
|
123
|
+
return { $type, value };
|
|
124
|
+
case "DateTime":
|
|
125
|
+
return { $type, value: new Date(value).toISOString() };
|
|
126
|
+
case "Decimal":
|
|
127
|
+
return { $type, value: String(new Decimal2(value)) };
|
|
128
|
+
case "Json":
|
|
129
|
+
return { $type, value: JSON.stringify(JSON.parse(value)) };
|
|
130
|
+
default:
|
|
131
|
+
assertNever(value, "Unknown tagged value");
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
function mapObjectValues(object, mapper) {
|
|
135
|
+
const result = {};
|
|
136
|
+
for (const key of Object.keys(object)) {
|
|
137
|
+
result[key] = mapper(object[key], key);
|
|
138
|
+
}
|
|
139
|
+
return result;
|
|
140
|
+
}
|
|
141
|
+
function deserializeJsonResponse(result) {
|
|
142
|
+
if (result === null) {
|
|
143
|
+
return result;
|
|
144
|
+
}
|
|
145
|
+
if (Array.isArray(result)) {
|
|
146
|
+
return result.map(deserializeJsonResponse);
|
|
147
|
+
}
|
|
148
|
+
if (typeof result === "object") {
|
|
149
|
+
if (isTaggedValue(result)) {
|
|
150
|
+
return deserializeTaggedValue(result);
|
|
151
|
+
}
|
|
152
|
+
if (result.constructor !== null && result.constructor.name !== "Object") {
|
|
153
|
+
return result;
|
|
154
|
+
}
|
|
155
|
+
return mapObjectValues(result, deserializeJsonResponse);
|
|
156
|
+
}
|
|
157
|
+
return result;
|
|
158
|
+
}
|
|
159
|
+
function deserializeTaggedValue({ $type, value }) {
|
|
160
|
+
switch ($type) {
|
|
161
|
+
case "BigInt":
|
|
162
|
+
return BigInt(value);
|
|
163
|
+
case "Bytes": {
|
|
164
|
+
const { buffer, byteOffset, byteLength } = Buffer.from(value, "base64");
|
|
165
|
+
return new Uint8Array(buffer, byteOffset, byteLength);
|
|
166
|
+
}
|
|
167
|
+
case "DateTime":
|
|
168
|
+
return new Date(value);
|
|
169
|
+
case "Decimal":
|
|
170
|
+
return new Decimal2(value);
|
|
171
|
+
case "Json":
|
|
172
|
+
return JSON.parse(value);
|
|
173
|
+
default:
|
|
174
|
+
assertNever(value, "Unknown tagged value");
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// src/user-facing-error.ts
|
|
179
|
+
import { isDriverAdapterError } from "@prisma/driver-adapter-utils";
|
|
180
|
+
var UserFacingError = class extends Error {
|
|
181
|
+
name = "UserFacingError";
|
|
182
|
+
code;
|
|
183
|
+
meta;
|
|
184
|
+
constructor(message, code, meta) {
|
|
185
|
+
super(message);
|
|
186
|
+
this.code = code;
|
|
187
|
+
this.meta = meta ?? {};
|
|
188
|
+
}
|
|
189
|
+
toQueryResponseErrorObject() {
|
|
190
|
+
return {
|
|
191
|
+
error: this.message,
|
|
192
|
+
user_facing_error: {
|
|
193
|
+
is_panic: false,
|
|
194
|
+
message: this.message,
|
|
195
|
+
meta: this.meta,
|
|
196
|
+
error_code: this.code
|
|
197
|
+
}
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
};
|
|
201
|
+
function rethrowAsUserFacing(error) {
|
|
202
|
+
if (!isDriverAdapterError(error)) {
|
|
203
|
+
throw error;
|
|
204
|
+
}
|
|
205
|
+
const code = getErrorCode(error);
|
|
206
|
+
const message = renderErrorMessage(error);
|
|
207
|
+
if (!code || !message) {
|
|
208
|
+
throw error;
|
|
209
|
+
}
|
|
210
|
+
throw new UserFacingError(message, code, { driverAdapterError: error });
|
|
211
|
+
}
|
|
212
|
+
function rethrowAsUserFacingRawError(error) {
|
|
213
|
+
if (!isDriverAdapterError(error)) {
|
|
214
|
+
throw error;
|
|
215
|
+
}
|
|
216
|
+
throw new UserFacingError(
|
|
217
|
+
`Raw query failed. Code: \`${error.cause.originalCode ?? "N/A"}\`. Message: \`${error.cause.originalMessage ?? renderErrorMessage(error)}\``,
|
|
218
|
+
"P2010",
|
|
219
|
+
{ driverAdapterError: error }
|
|
220
|
+
);
|
|
221
|
+
}
|
|
222
|
+
function getErrorCode(err) {
|
|
223
|
+
switch (err.cause.kind) {
|
|
224
|
+
case "AuthenticationFailed":
|
|
225
|
+
return "P1000";
|
|
226
|
+
case "DatabaseNotReachable":
|
|
227
|
+
return "P1001";
|
|
228
|
+
case "DatabaseDoesNotExist":
|
|
229
|
+
return "P1003";
|
|
230
|
+
case "SocketTimeout":
|
|
231
|
+
return "P1008";
|
|
232
|
+
case "DatabaseAlreadyExists":
|
|
233
|
+
return "P1009";
|
|
234
|
+
case "DatabaseAccessDenied":
|
|
235
|
+
return "P1010";
|
|
236
|
+
case "TlsConnectionError":
|
|
237
|
+
return "P1011";
|
|
238
|
+
case "ConnectionClosed":
|
|
239
|
+
return "P1017";
|
|
240
|
+
case "TransactionAlreadyClosed":
|
|
241
|
+
return "P1018";
|
|
242
|
+
case "LengthMismatch":
|
|
243
|
+
return "P2000";
|
|
244
|
+
case "UniqueConstraintViolation":
|
|
245
|
+
return "P2002";
|
|
246
|
+
case "ForeignKeyConstraintViolation":
|
|
247
|
+
return "P2003";
|
|
248
|
+
case "UnsupportedNativeDataType":
|
|
249
|
+
return "P2010";
|
|
250
|
+
case "NullConstraintViolation":
|
|
251
|
+
return "P2011";
|
|
252
|
+
case "ValueOutOfRange":
|
|
253
|
+
return "P2020";
|
|
254
|
+
case "TableDoesNotExist":
|
|
255
|
+
return "P2021";
|
|
256
|
+
case "ColumnNotFound":
|
|
257
|
+
return "P2022";
|
|
258
|
+
case "InvalidIsolationLevel":
|
|
259
|
+
case "InconsistentColumnData":
|
|
260
|
+
return "P2023";
|
|
261
|
+
case "MissingFullTextSearchIndex":
|
|
262
|
+
return "P2030";
|
|
263
|
+
case "TransactionWriteConflict":
|
|
264
|
+
return "P2034";
|
|
265
|
+
case "GenericJs":
|
|
266
|
+
return "P2036";
|
|
267
|
+
case "TooManyConnections":
|
|
268
|
+
return "P2037";
|
|
269
|
+
case "postgres":
|
|
270
|
+
case "sqlite":
|
|
271
|
+
case "mysql":
|
|
272
|
+
case "mssql":
|
|
273
|
+
return;
|
|
274
|
+
default:
|
|
275
|
+
assertNever(err.cause, `Unknown error: ${err.cause}`);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
function renderErrorMessage(err) {
|
|
279
|
+
switch (err.cause.kind) {
|
|
280
|
+
case "AuthenticationFailed": {
|
|
281
|
+
const user = err.cause.user ?? "(not available)";
|
|
282
|
+
return `Authentication failed against the database server, the provided database credentials for \`${user}\` are not valid`;
|
|
283
|
+
}
|
|
284
|
+
case "DatabaseNotReachable": {
|
|
285
|
+
const address = err.cause.host && err.cause.port ? `${err.cause.host}:${err.cause.port}` : err.cause.host;
|
|
286
|
+
return `Can't reach database server${address ? ` at ${address}` : ""}`;
|
|
287
|
+
}
|
|
288
|
+
case "DatabaseDoesNotExist": {
|
|
289
|
+
const db = err.cause.db ?? "(not available)";
|
|
290
|
+
return `Database \`${db}\` does not exist on the database server`;
|
|
291
|
+
}
|
|
292
|
+
case "SocketTimeout":
|
|
293
|
+
return `Operation has timed out`;
|
|
294
|
+
case "DatabaseAlreadyExists": {
|
|
295
|
+
const db = err.cause.db ?? "(not available)";
|
|
296
|
+
return `Database \`${db}\` already exists on the database server`;
|
|
297
|
+
}
|
|
298
|
+
case "DatabaseAccessDenied": {
|
|
299
|
+
const db = err.cause.db ?? "(not available)";
|
|
300
|
+
return `User was denied access on the database \`${db}\``;
|
|
301
|
+
}
|
|
302
|
+
case "TlsConnectionError": {
|
|
303
|
+
return `Error opening a TLS connection: ${err.cause.reason}`;
|
|
304
|
+
}
|
|
305
|
+
case "ConnectionClosed": {
|
|
306
|
+
return "Server has closed the connection.";
|
|
307
|
+
}
|
|
308
|
+
case "TransactionAlreadyClosed":
|
|
309
|
+
return err.cause.cause;
|
|
310
|
+
case "LengthMismatch": {
|
|
311
|
+
const column = err.cause.column ?? "(not available)";
|
|
312
|
+
return `The provided value for the column is too long for the column's type. Column: ${column}`;
|
|
313
|
+
}
|
|
314
|
+
case "UniqueConstraintViolation":
|
|
315
|
+
return `Unique constraint failed on the ${renderConstraint(err.cause.constraint)}`;
|
|
316
|
+
case "ForeignKeyConstraintViolation":
|
|
317
|
+
return `Foreign key constraint violated on the ${renderConstraint(err.cause.constraint)}`;
|
|
318
|
+
case "UnsupportedNativeDataType":
|
|
319
|
+
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\`.`;
|
|
320
|
+
case "NullConstraintViolation":
|
|
321
|
+
return `Null constraint violation on the ${renderConstraint(err.cause.constraint)}`;
|
|
322
|
+
case "ValueOutOfRange":
|
|
323
|
+
return `Value out of range for the type: ${err.cause.cause}`;
|
|
324
|
+
case "TableDoesNotExist": {
|
|
325
|
+
const table = err.cause.table ?? "(not available)";
|
|
326
|
+
return `The table \`${table}\` does not exist in the current database.`;
|
|
327
|
+
}
|
|
328
|
+
case "ColumnNotFound": {
|
|
329
|
+
const column = err.cause.column ?? "(not available)";
|
|
330
|
+
return `The column \`${column}\` does not exist in the current database.`;
|
|
331
|
+
}
|
|
332
|
+
case "InvalidIsolationLevel":
|
|
333
|
+
return `Error in connector: Conversion error: ${err.cause.level}`;
|
|
334
|
+
case "InconsistentColumnData":
|
|
335
|
+
return `Inconsistent column data: ${err.cause.cause}`;
|
|
336
|
+
case "MissingFullTextSearchIndex":
|
|
337
|
+
return "Cannot find a fulltext index to use for the native search, try adding a @@fulltext([Fields...]) to your schema";
|
|
338
|
+
case "TransactionWriteConflict":
|
|
339
|
+
return `Transaction failed due to a write conflict or a deadlock. Please retry your transaction`;
|
|
340
|
+
case "GenericJs":
|
|
341
|
+
return `Error in external connector (id ${err.cause.id})`;
|
|
342
|
+
case "TooManyConnections":
|
|
343
|
+
return `Too many database connections opened: ${err.cause.cause}`;
|
|
344
|
+
case "sqlite":
|
|
345
|
+
case "postgres":
|
|
346
|
+
case "mysql":
|
|
347
|
+
case "mssql":
|
|
348
|
+
return;
|
|
349
|
+
default:
|
|
350
|
+
assertNever(err.cause, `Unknown error: ${err.cause}`);
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
function renderConstraint(constraint) {
|
|
354
|
+
if (constraint && "fields" in constraint) {
|
|
355
|
+
return `fields: (${constraint.fields.map((field) => `\`${field}\``).join(", ")})`;
|
|
356
|
+
} else if (constraint && "index" in constraint) {
|
|
357
|
+
return `constraint: \`${constraint.index}\``;
|
|
358
|
+
} else if (constraint && "foreignKey" in constraint) {
|
|
359
|
+
return `foreign key`;
|
|
360
|
+
}
|
|
361
|
+
return "(not available)";
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
// src/batch.ts
|
|
365
|
+
function convertCompactedRows(rows, compiledBatch) {
|
|
366
|
+
const keysPerRow = rows.map(
|
|
367
|
+
(item) => compiledBatch.keys.reduce((acc, key) => {
|
|
368
|
+
acc[key] = deserializeJsonResponse(item[key]);
|
|
369
|
+
return acc;
|
|
370
|
+
}, {})
|
|
371
|
+
);
|
|
372
|
+
const selection = new Set(compiledBatch.nestedSelection);
|
|
373
|
+
return compiledBatch.arguments.map((args) => {
|
|
374
|
+
const rowIndex = keysPerRow.findIndex((rowKeys) => doKeysMatch(rowKeys, args));
|
|
375
|
+
if (rowIndex === -1) {
|
|
376
|
+
if (compiledBatch.expectNonEmpty) {
|
|
377
|
+
return new UserFacingError(
|
|
378
|
+
"An operation failed because it depends on one or more records that were required but not found",
|
|
379
|
+
"P2025"
|
|
380
|
+
);
|
|
381
|
+
} else {
|
|
382
|
+
return null;
|
|
383
|
+
}
|
|
384
|
+
} else {
|
|
385
|
+
const selected = Object.entries(rows[rowIndex]).filter(([k]) => selection.has(k));
|
|
386
|
+
return Object.fromEntries(selected);
|
|
387
|
+
}
|
|
388
|
+
});
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
// src/interpreter/data-mapper.ts
|
|
392
|
+
import Decimal3 from "decimal.js";
|
|
97
393
|
var DataMapperError = class extends Error {
|
|
98
394
|
name = "DataMapperError";
|
|
99
395
|
};
|
|
@@ -105,17 +401,20 @@ function applyDataMap(data, structure, enums) {
|
|
|
105
401
|
}
|
|
106
402
|
return { count: data };
|
|
107
403
|
case "Object":
|
|
108
|
-
return mapArrayOrObject(data, structure.fields, enums);
|
|
404
|
+
return mapArrayOrObject(data, structure.fields, enums, structure.skipNulls);
|
|
109
405
|
case "Value":
|
|
110
406
|
return mapValue(data, "<result>", structure.resultType, enums);
|
|
111
407
|
default:
|
|
112
408
|
assertNever(structure, `Invalid data mapping type: '${structure.type}'`);
|
|
113
409
|
}
|
|
114
410
|
}
|
|
115
|
-
function mapArrayOrObject(data, fields, enums) {
|
|
411
|
+
function mapArrayOrObject(data, fields, enums, skipNulls) {
|
|
116
412
|
if (data === null) return null;
|
|
117
413
|
if (Array.isArray(data)) {
|
|
118
|
-
|
|
414
|
+
let rows = data;
|
|
415
|
+
if (skipNulls) {
|
|
416
|
+
rows = rows.filter((row) => row !== null);
|
|
417
|
+
}
|
|
119
418
|
return rows.map((row) => mapObject(row, fields, enums));
|
|
120
419
|
}
|
|
121
420
|
if (typeof data === "object") {
|
|
@@ -131,7 +430,7 @@ function mapArrayOrObject(data, fields, enums) {
|
|
|
131
430
|
cause: error
|
|
132
431
|
});
|
|
133
432
|
}
|
|
134
|
-
return mapArrayOrObject(decodedData, fields, enums);
|
|
433
|
+
return mapArrayOrObject(decodedData, fields, enums, skipNulls);
|
|
135
434
|
}
|
|
136
435
|
throw new DataMapperError(`Expected an array or an object, got: ${typeof data}`);
|
|
137
436
|
}
|
|
@@ -152,7 +451,7 @@ function mapObject(data, fields, enums) {
|
|
|
152
451
|
);
|
|
153
452
|
}
|
|
154
453
|
const target = node.serializedName !== null ? data[node.serializedName] : data;
|
|
155
|
-
result[name] = mapArrayOrObject(target, node.fields, enums);
|
|
454
|
+
result[name] = mapArrayOrObject(target, node.fields, enums, node.skipNulls);
|
|
156
455
|
break;
|
|
157
456
|
}
|
|
158
457
|
case "Value":
|
|
@@ -245,7 +544,7 @@ function mapValue(value, columnName, resultType, enums) {
|
|
|
245
544
|
throw new DataMapperError(`Expected a boolean in column '${columnName}', got ${typeof value}: ${value}`);
|
|
246
545
|
}
|
|
247
546
|
case "Decimal":
|
|
248
|
-
if (typeof value !== "number" && typeof value !== "string" && !
|
|
547
|
+
if (typeof value !== "number" && typeof value !== "string" && !Decimal3.isDecimal(value)) {
|
|
249
548
|
throw new DataMapperError(`Expected a decimal in column '${columnName}', got ${typeof value}: ${value}`);
|
|
250
549
|
}
|
|
251
550
|
return { $type: "Decimal", value };
|
|
@@ -269,8 +568,10 @@ function mapValue(value, columnName, resultType, enums) {
|
|
|
269
568
|
return values.map((v, i) => mapValue(v, `${columnName}[${i}]`, resultType.inner, enums));
|
|
270
569
|
}
|
|
271
570
|
case "Object": {
|
|
272
|
-
|
|
273
|
-
|
|
571
|
+
return { $type: "Json", value: safeJsonStringify(value) };
|
|
572
|
+
}
|
|
573
|
+
case "Json": {
|
|
574
|
+
return { $type: "Json", value: `${value}` };
|
|
274
575
|
}
|
|
275
576
|
case "Bytes": {
|
|
276
577
|
if (typeof value === "string" && value.startsWith("\\x")) {
|
|
@@ -291,7 +592,7 @@ function mapValue(value, columnName, resultType, enums) {
|
|
|
291
592
|
}
|
|
292
593
|
const enumValue = enumDef[`${value}`];
|
|
293
594
|
if (enumValue === void 0) {
|
|
294
|
-
throw new DataMapperError(`
|
|
595
|
+
throw new DataMapperError(`Value '${value}' not found in enum '${resultType.inner}'`);
|
|
295
596
|
}
|
|
296
597
|
return enumValue;
|
|
297
598
|
}
|
|
@@ -346,201 +647,25 @@ async function withQuerySpanAndEvent({
|
|
|
346
647
|
{
|
|
347
648
|
name: "db_query",
|
|
348
649
|
kind: SpanKind.CLIENT,
|
|
349
|
-
attributes: {
|
|
350
|
-
"db.query.text": query.sql,
|
|
351
|
-
"db.system.name": providerToOtelSystem(provider)
|
|
352
|
-
}
|
|
353
|
-
},
|
|
354
|
-
async () => {
|
|
355
|
-
const timestamp = /* @__PURE__ */ new Date();
|
|
356
|
-
const startInstant = performance.now();
|
|
357
|
-
const result = await execute();
|
|
358
|
-
const endInstant = performance.now();
|
|
359
|
-
onQuery?.({
|
|
360
|
-
timestamp,
|
|
361
|
-
duration: endInstant - startInstant,
|
|
362
|
-
query: query.sql,
|
|
363
|
-
params: query.args
|
|
364
|
-
});
|
|
365
|
-
return result;
|
|
366
|
-
}
|
|
367
|
-
);
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
// src/UserFacingError.ts
|
|
371
|
-
import { isDriverAdapterError } from "@prisma/driver-adapter-utils";
|
|
372
|
-
var UserFacingError = class extends Error {
|
|
373
|
-
name = "UserFacingError";
|
|
374
|
-
code;
|
|
375
|
-
meta;
|
|
376
|
-
constructor(message, code, meta) {
|
|
377
|
-
super(message);
|
|
378
|
-
this.code = code;
|
|
379
|
-
this.meta = meta ?? {};
|
|
380
|
-
}
|
|
381
|
-
toQueryResponseErrorObject() {
|
|
382
|
-
return {
|
|
383
|
-
error: this.message,
|
|
384
|
-
user_facing_error: {
|
|
385
|
-
is_panic: false,
|
|
386
|
-
message: this.message,
|
|
387
|
-
meta: this.meta,
|
|
388
|
-
error_code: this.code
|
|
389
|
-
}
|
|
390
|
-
};
|
|
391
|
-
}
|
|
392
|
-
};
|
|
393
|
-
function rethrowAsUserFacing(error) {
|
|
394
|
-
if (!isDriverAdapterError(error)) {
|
|
395
|
-
throw error;
|
|
396
|
-
}
|
|
397
|
-
const code = getErrorCode(error);
|
|
398
|
-
const message = renderErrorMessage(error);
|
|
399
|
-
if (!code || !message) {
|
|
400
|
-
throw error;
|
|
401
|
-
}
|
|
402
|
-
throw new UserFacingError(message, code, { driverAdapterError: error });
|
|
403
|
-
}
|
|
404
|
-
function getErrorCode(err) {
|
|
405
|
-
switch (err.cause.kind) {
|
|
406
|
-
case "AuthenticationFailed":
|
|
407
|
-
return "P1000";
|
|
408
|
-
case "DatabaseNotReachable":
|
|
409
|
-
return "P1001";
|
|
410
|
-
case "DatabaseDoesNotExist":
|
|
411
|
-
return "P1003";
|
|
412
|
-
case "SocketTimeout":
|
|
413
|
-
return "P1008";
|
|
414
|
-
case "DatabaseAlreadyExists":
|
|
415
|
-
return "P1009";
|
|
416
|
-
case "DatabaseAccessDenied":
|
|
417
|
-
return "P1010";
|
|
418
|
-
case "TlsConnectionError":
|
|
419
|
-
return "P1011";
|
|
420
|
-
case "ConnectionClosed":
|
|
421
|
-
return "P1017";
|
|
422
|
-
case "TransactionAlreadyClosed":
|
|
423
|
-
return "P1018";
|
|
424
|
-
case "LengthMismatch":
|
|
425
|
-
return "P2000";
|
|
426
|
-
case "UniqueConstraintViolation":
|
|
427
|
-
return "P2002";
|
|
428
|
-
case "ForeignKeyConstraintViolation":
|
|
429
|
-
return "P2003";
|
|
430
|
-
case "UnsupportedNativeDataType":
|
|
431
|
-
return "P2010";
|
|
432
|
-
case "NullConstraintViolation":
|
|
433
|
-
return "P2011";
|
|
434
|
-
case "ValueOutOfRange":
|
|
435
|
-
return "P2020";
|
|
436
|
-
case "TableDoesNotExist":
|
|
437
|
-
return "P2021";
|
|
438
|
-
case "ColumnNotFound":
|
|
439
|
-
return "P2022";
|
|
440
|
-
case "InvalidIsolationLevel":
|
|
441
|
-
case "InconsistentColumnData":
|
|
442
|
-
return "P2023";
|
|
443
|
-
case "MissingFullTextSearchIndex":
|
|
444
|
-
return "P2030";
|
|
445
|
-
case "TransactionWriteConflict":
|
|
446
|
-
return "P2034";
|
|
447
|
-
case "GenericJs":
|
|
448
|
-
return "P2036";
|
|
449
|
-
case "TooManyConnections":
|
|
450
|
-
return "P2037";
|
|
451
|
-
case "postgres":
|
|
452
|
-
case "sqlite":
|
|
453
|
-
case "mysql":
|
|
454
|
-
case "mssql":
|
|
455
|
-
return;
|
|
456
|
-
default:
|
|
457
|
-
assertNever(err.cause, `Unknown error: ${err.cause}`);
|
|
458
|
-
}
|
|
459
|
-
}
|
|
460
|
-
function renderErrorMessage(err) {
|
|
461
|
-
switch (err.cause.kind) {
|
|
462
|
-
case "AuthenticationFailed": {
|
|
463
|
-
const user = err.cause.user ?? "(not available)";
|
|
464
|
-
return `Authentication failed against the database server, the provided database credentials for \`${user}\` are not valid`;
|
|
465
|
-
}
|
|
466
|
-
case "DatabaseNotReachable": {
|
|
467
|
-
const address = err.cause.host && err.cause.port ? `${err.cause.host}:${err.cause.port}` : err.cause.host;
|
|
468
|
-
return `Can't reach database server${address ? ` at ${address}` : ""}`;
|
|
469
|
-
}
|
|
470
|
-
case "DatabaseDoesNotExist": {
|
|
471
|
-
const db = err.cause.db ?? "(not available)";
|
|
472
|
-
return `Database \`${db}\` does not exist on the database server`;
|
|
473
|
-
}
|
|
474
|
-
case "SocketTimeout":
|
|
475
|
-
return `Operation has timed out`;
|
|
476
|
-
case "DatabaseAlreadyExists": {
|
|
477
|
-
const db = err.cause.db ?? "(not available)";
|
|
478
|
-
return `Database \`${db}\` already exists on the database server`;
|
|
479
|
-
}
|
|
480
|
-
case "DatabaseAccessDenied": {
|
|
481
|
-
const db = err.cause.db ?? "(not available)";
|
|
482
|
-
return `User was denied access on the database \`${db}\``;
|
|
483
|
-
}
|
|
484
|
-
case "TlsConnectionError": {
|
|
485
|
-
return `Error opening a TLS connection: ${err.cause.reason}`;
|
|
486
|
-
}
|
|
487
|
-
case "ConnectionClosed": {
|
|
488
|
-
return "Server has closed the connection.";
|
|
489
|
-
}
|
|
490
|
-
case "TransactionAlreadyClosed":
|
|
491
|
-
return err.cause.cause;
|
|
492
|
-
case "LengthMismatch": {
|
|
493
|
-
const column = err.cause.column ?? "(not available)";
|
|
494
|
-
return `The provided value for the column is too long for the column's type. Column: ${column}`;
|
|
495
|
-
}
|
|
496
|
-
case "UniqueConstraintViolation":
|
|
497
|
-
return `Unique constraint failed on the ${renderConstraint(err.cause.constraint)}`;
|
|
498
|
-
case "ForeignKeyConstraintViolation":
|
|
499
|
-
return `Foreign key constraint violated on the ${renderConstraint(err.cause.constraint)}`;
|
|
500
|
-
case "UnsupportedNativeDataType":
|
|
501
|
-
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\`.`;
|
|
502
|
-
case "NullConstraintViolation":
|
|
503
|
-
return `Null constraint violation on the ${renderConstraint(err.cause.constraint)}`;
|
|
504
|
-
case "ValueOutOfRange":
|
|
505
|
-
return `Value out of range for the type: ${err.cause.cause}`;
|
|
506
|
-
case "TableDoesNotExist": {
|
|
507
|
-
const table = err.cause.table ?? "(not available)";
|
|
508
|
-
return `The table \`${table}\` does not exist in the current database.`;
|
|
509
|
-
}
|
|
510
|
-
case "ColumnNotFound": {
|
|
511
|
-
const column = err.cause.column ?? "(not available)";
|
|
512
|
-
return `The column \`${column}\` does not exist in the current database.`;
|
|
513
|
-
}
|
|
514
|
-
case "InvalidIsolationLevel":
|
|
515
|
-
return `Invalid isolation level \`${err.cause.level}\``;
|
|
516
|
-
case "InconsistentColumnData":
|
|
517
|
-
return `Inconsistent column data: ${err.cause.cause}`;
|
|
518
|
-
case "MissingFullTextSearchIndex":
|
|
519
|
-
return "Cannot find a fulltext index to use for the native search, try adding a @@fulltext([Fields...]) to your schema";
|
|
520
|
-
case "TransactionWriteConflict":
|
|
521
|
-
return `Transaction failed due to a write conflict or a deadlock. Please retry your transaction`;
|
|
522
|
-
case "GenericJs":
|
|
523
|
-
return `Error in external connector (id ${err.cause.id})`;
|
|
524
|
-
case "TooManyConnections":
|
|
525
|
-
return `Too many database connections opened: ${err.cause.cause}`;
|
|
526
|
-
case "sqlite":
|
|
527
|
-
case "postgres":
|
|
528
|
-
case "mysql":
|
|
529
|
-
case "mssql":
|
|
530
|
-
return;
|
|
531
|
-
default:
|
|
532
|
-
assertNever(err.cause, `Unknown error: ${err.cause}`);
|
|
533
|
-
}
|
|
534
|
-
}
|
|
535
|
-
function renderConstraint(constraint) {
|
|
536
|
-
if (constraint && "fields" in constraint) {
|
|
537
|
-
return `fields: (${constraint.fields.map((field) => `\`${field}\``).join(", ")})`;
|
|
538
|
-
} else if (constraint && "index" in constraint) {
|
|
539
|
-
return `constraint: \`${constraint.index}\``;
|
|
540
|
-
} else if (constraint && "foreignKey" in constraint) {
|
|
541
|
-
return `foreign key`;
|
|
542
|
-
}
|
|
543
|
-
return "(not available)";
|
|
650
|
+
attributes: {
|
|
651
|
+
"db.query.text": query.sql,
|
|
652
|
+
"db.system.name": providerToOtelSystem(provider)
|
|
653
|
+
}
|
|
654
|
+
},
|
|
655
|
+
async () => {
|
|
656
|
+
const timestamp = /* @__PURE__ */ new Date();
|
|
657
|
+
const startInstant = performance.now();
|
|
658
|
+
const result = await execute();
|
|
659
|
+
const endInstant = performance.now();
|
|
660
|
+
onQuery?.({
|
|
661
|
+
timestamp,
|
|
662
|
+
duration: endInstant - startInstant,
|
|
663
|
+
query: query.sql,
|
|
664
|
+
params: query.args
|
|
665
|
+
});
|
|
666
|
+
return result;
|
|
667
|
+
}
|
|
668
|
+
);
|
|
544
669
|
}
|
|
545
670
|
|
|
546
671
|
// src/interpreter/generators.ts
|
|
@@ -644,7 +769,98 @@ var ProductGenerator = class {
|
|
|
644
769
|
}
|
|
645
770
|
};
|
|
646
771
|
|
|
647
|
-
// src/
|
|
772
|
+
// src/interpreter/in-memory-processing.ts
|
|
773
|
+
function processRecords(value, ops) {
|
|
774
|
+
if (value == null) {
|
|
775
|
+
return value;
|
|
776
|
+
}
|
|
777
|
+
if (typeof value === "string") {
|
|
778
|
+
return processRecords(JSON.parse(value), ops);
|
|
779
|
+
}
|
|
780
|
+
if (Array.isArray(value)) {
|
|
781
|
+
return processManyRecords(value, ops);
|
|
782
|
+
}
|
|
783
|
+
return processOneRecord(value, ops);
|
|
784
|
+
}
|
|
785
|
+
function processOneRecord(record, ops) {
|
|
786
|
+
if (ops.pagination) {
|
|
787
|
+
const { skip, take, cursor } = ops.pagination;
|
|
788
|
+
if (skip !== null && skip > 0) {
|
|
789
|
+
return null;
|
|
790
|
+
}
|
|
791
|
+
if (take === 0) {
|
|
792
|
+
return null;
|
|
793
|
+
}
|
|
794
|
+
if (cursor !== null && !doKeysMatch(record, cursor)) {
|
|
795
|
+
return null;
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
return processNestedRecords(record, ops.nested);
|
|
799
|
+
}
|
|
800
|
+
function processNestedRecords(record, opsMap) {
|
|
801
|
+
for (const [key, ops] of Object.entries(opsMap)) {
|
|
802
|
+
record[key] = processRecords(record[key], ops);
|
|
803
|
+
}
|
|
804
|
+
return record;
|
|
805
|
+
}
|
|
806
|
+
function processManyRecords(records, ops) {
|
|
807
|
+
if (ops.distinct !== null) {
|
|
808
|
+
const fields = ops.linkingFields !== null ? [...ops.distinct, ...ops.linkingFields] : ops.distinct;
|
|
809
|
+
records = distinctBy(records, fields);
|
|
810
|
+
}
|
|
811
|
+
if (ops.pagination) {
|
|
812
|
+
records = paginate(records, ops.pagination, ops.linkingFields);
|
|
813
|
+
}
|
|
814
|
+
if (ops.reverse) {
|
|
815
|
+
records.reverse();
|
|
816
|
+
}
|
|
817
|
+
if (Object.keys(ops.nested).length === 0) {
|
|
818
|
+
return records;
|
|
819
|
+
}
|
|
820
|
+
return records.map((record) => processNestedRecords(record, ops.nested));
|
|
821
|
+
}
|
|
822
|
+
function distinctBy(records, fields) {
|
|
823
|
+
const seen = /* @__PURE__ */ new Set();
|
|
824
|
+
const result = [];
|
|
825
|
+
for (const record of records) {
|
|
826
|
+
const key = getRecordKey(record, fields);
|
|
827
|
+
if (!seen.has(key)) {
|
|
828
|
+
seen.add(key);
|
|
829
|
+
result.push(record);
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
return result;
|
|
833
|
+
}
|
|
834
|
+
function paginate(records, pagination, linkingFields) {
|
|
835
|
+
if (linkingFields === null) {
|
|
836
|
+
return paginateSingleList(records, pagination);
|
|
837
|
+
}
|
|
838
|
+
const groupedByParent = /* @__PURE__ */ new Map();
|
|
839
|
+
for (const record of records) {
|
|
840
|
+
const parentKey = getRecordKey(record, linkingFields);
|
|
841
|
+
if (!groupedByParent.has(parentKey)) {
|
|
842
|
+
groupedByParent.set(parentKey, []);
|
|
843
|
+
}
|
|
844
|
+
groupedByParent.get(parentKey).push(record);
|
|
845
|
+
}
|
|
846
|
+
const groupList = Array.from(groupedByParent.entries());
|
|
847
|
+
groupList.sort(([aId], [bId]) => aId < bId ? -1 : aId > bId ? 1 : 0);
|
|
848
|
+
return groupList.flatMap(([, elems]) => paginateSingleList(elems, pagination));
|
|
849
|
+
}
|
|
850
|
+
function paginateSingleList(list, { cursor, skip, take }) {
|
|
851
|
+
const cursorIndex = cursor !== null ? list.findIndex((item) => doKeysMatch(item, cursor)) : 0;
|
|
852
|
+
if (cursorIndex === -1) {
|
|
853
|
+
return [];
|
|
854
|
+
}
|
|
855
|
+
const start = cursorIndex + (skip ?? 0);
|
|
856
|
+
const end = take !== null ? start + take : list.length;
|
|
857
|
+
return list.slice(start, end);
|
|
858
|
+
}
|
|
859
|
+
function getRecordKey(record, fields) {
|
|
860
|
+
return JSON.stringify(fields.map((field) => record[field]));
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
// src/query-plan.ts
|
|
648
864
|
function isPrismaValuePlaceholder(value) {
|
|
649
865
|
return typeof value === "object" && value !== null && value["prisma__type"] === "param";
|
|
650
866
|
}
|
|
@@ -658,18 +874,22 @@ function isPrismaValueBigInt(value) {
|
|
|
658
874
|
return typeof value === "object" && value !== null && value["prisma__type"] === "bigint";
|
|
659
875
|
}
|
|
660
876
|
|
|
661
|
-
// src/interpreter/
|
|
662
|
-
function renderQuery(dbQuery, scope, generators) {
|
|
877
|
+
// src/interpreter/render-query.ts
|
|
878
|
+
function renderQuery(dbQuery, scope, generators, maxChunkSize) {
|
|
663
879
|
const queryType = dbQuery.type;
|
|
880
|
+
const params = evaluateParams(dbQuery.params, scope, generators);
|
|
664
881
|
switch (queryType) {
|
|
665
882
|
case "rawSql":
|
|
666
|
-
return renderRawSql(dbQuery.sql, evaluateParams(dbQuery.params, scope, generators));
|
|
667
|
-
case "templateSql":
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
883
|
+
return [renderRawSql(dbQuery.sql, evaluateParams(dbQuery.params, scope, generators))];
|
|
884
|
+
case "templateSql": {
|
|
885
|
+
const chunks = dbQuery.chunkable ? chunkParams(dbQuery.fragments, params, maxChunkSize) : [params];
|
|
886
|
+
return chunks.map((params2) => {
|
|
887
|
+
if (maxChunkSize !== void 0 && params2.length > maxChunkSize) {
|
|
888
|
+
throw new UserFacingError("The query parameter limit supported by your database is exceeded.", "P2029");
|
|
889
|
+
}
|
|
890
|
+
return renderTemplateSql(dbQuery.fragments, dbQuery.placeholderFormat, params2);
|
|
891
|
+
});
|
|
892
|
+
}
|
|
673
893
|
default:
|
|
674
894
|
assertNever(queryType, `Invalid query type`);
|
|
675
895
|
}
|
|
@@ -707,61 +927,36 @@ function evaluateParam(param, scope, generators) {
|
|
|
707
927
|
return value;
|
|
708
928
|
}
|
|
709
929
|
function renderTemplateSql(fragments, placeholderFormat, params) {
|
|
710
|
-
let
|
|
711
|
-
|
|
930
|
+
let sql = "";
|
|
931
|
+
const ctx = { placeholderNumber: 1 };
|
|
712
932
|
const flattenedParams = [];
|
|
713
|
-
const
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
if (paramIndex >= params.length) {
|
|
718
|
-
throw new Error(`Malformed query template. Fragments attempt to read over ${params.length} parameters.`);
|
|
719
|
-
}
|
|
720
|
-
flattenedParams.push(params[paramIndex++]);
|
|
721
|
-
return formatPlaceholder(placeholderFormat, placeholderNumber++);
|
|
722
|
-
case "stringChunk":
|
|
723
|
-
return fragment.chunk;
|
|
724
|
-
case "parameterTuple": {
|
|
725
|
-
if (paramIndex >= params.length) {
|
|
726
|
-
throw new Error(`Malformed query template. Fragments attempt to read over ${params.length} parameters.`);
|
|
727
|
-
}
|
|
728
|
-
const paramValue = params[paramIndex++];
|
|
729
|
-
const paramArray = Array.isArray(paramValue) ? paramValue : [paramValue];
|
|
730
|
-
const placeholders = paramArray.length == 0 ? "NULL" : paramArray.map((value) => {
|
|
731
|
-
flattenedParams.push(value);
|
|
732
|
-
return formatPlaceholder(placeholderFormat, placeholderNumber++);
|
|
733
|
-
}).join(",");
|
|
734
|
-
return `(${placeholders})`;
|
|
735
|
-
}
|
|
736
|
-
case "parameterTupleList": {
|
|
737
|
-
if (paramIndex >= params.length) {
|
|
738
|
-
throw new Error(`Malformed query template. Fragments attempt to read over ${params.length} parameters.`);
|
|
739
|
-
}
|
|
740
|
-
const paramValue = params[paramIndex++];
|
|
741
|
-
if (!Array.isArray(paramValue)) {
|
|
742
|
-
throw new Error(`Malformed query template. Tuple list expected.`);
|
|
743
|
-
}
|
|
744
|
-
if (paramValue.length === 0) {
|
|
745
|
-
throw new Error(`Malformed query template. Tuple list cannot be empty.`);
|
|
746
|
-
}
|
|
747
|
-
const tupleList = paramValue.map((tuple) => {
|
|
748
|
-
if (!Array.isArray(tuple)) {
|
|
749
|
-
throw new Error(`Malformed query template. Tuple expected.`);
|
|
750
|
-
}
|
|
751
|
-
const elements = tuple.map((value) => {
|
|
752
|
-
flattenedParams.push(value);
|
|
753
|
-
return formatPlaceholder(placeholderFormat, placeholderNumber++);
|
|
754
|
-
}).join(fragment.itemSeparator);
|
|
755
|
-
return `${fragment.itemPrefix}${elements}${fragment.itemSuffix}`;
|
|
756
|
-
}).join(fragment.groupSeparator);
|
|
757
|
-
return tupleList;
|
|
758
|
-
}
|
|
759
|
-
default:
|
|
760
|
-
assertNever(fragmentType, "Invalid fragment type");
|
|
761
|
-
}
|
|
762
|
-
}).join("");
|
|
933
|
+
for (const fragment of pairFragmentsWithParams(fragments, params)) {
|
|
934
|
+
flattenedParams.push(...flattenedFragmentParams(fragment));
|
|
935
|
+
sql += renderFragment(fragment, placeholderFormat, ctx);
|
|
936
|
+
}
|
|
763
937
|
return renderRawSql(sql, flattenedParams);
|
|
764
938
|
}
|
|
939
|
+
function renderFragment(fragment, placeholderFormat, ctx) {
|
|
940
|
+
const fragmentType = fragment.type;
|
|
941
|
+
switch (fragmentType) {
|
|
942
|
+
case "parameter":
|
|
943
|
+
return formatPlaceholder(placeholderFormat, ctx.placeholderNumber++);
|
|
944
|
+
case "stringChunk":
|
|
945
|
+
return fragment.chunk;
|
|
946
|
+
case "parameterTuple": {
|
|
947
|
+
const placeholders = fragment.value.length == 0 ? "NULL" : fragment.value.map(() => formatPlaceholder(placeholderFormat, ctx.placeholderNumber++)).join(",");
|
|
948
|
+
return `(${placeholders})`;
|
|
949
|
+
}
|
|
950
|
+
case "parameterTupleList": {
|
|
951
|
+
return fragment.value.map((tuple) => {
|
|
952
|
+
const elements = tuple.map(() => formatPlaceholder(placeholderFormat, ctx.placeholderNumber++)).join(fragment.itemSeparator);
|
|
953
|
+
return `${fragment.itemPrefix}${elements}${fragment.itemSuffix}`;
|
|
954
|
+
}).join(fragment.groupSeparator);
|
|
955
|
+
}
|
|
956
|
+
default:
|
|
957
|
+
assertNever(fragmentType, "Invalid fragment type");
|
|
958
|
+
}
|
|
959
|
+
}
|
|
765
960
|
function formatPlaceholder(placeholderFormat, placeholderNumber) {
|
|
766
961
|
return placeholderFormat.hasNumbering ? `${placeholderFormat.prefix}${placeholderNumber}` : placeholderFormat.prefix;
|
|
767
962
|
}
|
|
@@ -794,8 +989,145 @@ function toArgType(value) {
|
|
|
794
989
|
function doesRequireEvaluation(param) {
|
|
795
990
|
return isPrismaValuePlaceholder(param) || isPrismaValueGenerator(param);
|
|
796
991
|
}
|
|
992
|
+
function* pairFragmentsWithParams(fragments, params) {
|
|
993
|
+
let index = 0;
|
|
994
|
+
for (const fragment of fragments) {
|
|
995
|
+
switch (fragment.type) {
|
|
996
|
+
case "parameter": {
|
|
997
|
+
if (index >= params.length) {
|
|
998
|
+
throw new Error(`Malformed query template. Fragments attempt to read over ${params.length} parameters.`);
|
|
999
|
+
}
|
|
1000
|
+
yield { ...fragment, value: params[index++] };
|
|
1001
|
+
break;
|
|
1002
|
+
}
|
|
1003
|
+
case "stringChunk": {
|
|
1004
|
+
yield fragment;
|
|
1005
|
+
break;
|
|
1006
|
+
}
|
|
1007
|
+
case "parameterTuple": {
|
|
1008
|
+
if (index >= params.length) {
|
|
1009
|
+
throw new Error(`Malformed query template. Fragments attempt to read over ${params.length} parameters.`);
|
|
1010
|
+
}
|
|
1011
|
+
const value = params[index++];
|
|
1012
|
+
yield { ...fragment, value: Array.isArray(value) ? value : [value] };
|
|
1013
|
+
break;
|
|
1014
|
+
}
|
|
1015
|
+
case "parameterTupleList": {
|
|
1016
|
+
if (index >= params.length) {
|
|
1017
|
+
throw new Error(`Malformed query template. Fragments attempt to read over ${params.length} parameters.`);
|
|
1018
|
+
}
|
|
1019
|
+
const value = params[index++];
|
|
1020
|
+
if (!Array.isArray(value)) {
|
|
1021
|
+
throw new Error(`Malformed query template. Tuple list expected.`);
|
|
1022
|
+
}
|
|
1023
|
+
if (value.length === 0) {
|
|
1024
|
+
throw new Error(`Malformed query template. Tuple list cannot be empty.`);
|
|
1025
|
+
}
|
|
1026
|
+
for (const tuple of value) {
|
|
1027
|
+
if (!Array.isArray(tuple)) {
|
|
1028
|
+
throw new Error(`Malformed query template. Tuple expected.`);
|
|
1029
|
+
}
|
|
1030
|
+
}
|
|
1031
|
+
yield { ...fragment, value };
|
|
1032
|
+
break;
|
|
1033
|
+
}
|
|
1034
|
+
}
|
|
1035
|
+
}
|
|
1036
|
+
}
|
|
1037
|
+
function* flattenedFragmentParams(fragment) {
|
|
1038
|
+
switch (fragment.type) {
|
|
1039
|
+
case "parameter":
|
|
1040
|
+
yield fragment.value;
|
|
1041
|
+
break;
|
|
1042
|
+
case "stringChunk":
|
|
1043
|
+
break;
|
|
1044
|
+
case "parameterTuple":
|
|
1045
|
+
yield* fragment.value;
|
|
1046
|
+
break;
|
|
1047
|
+
case "parameterTupleList":
|
|
1048
|
+
for (const tuple of fragment.value) {
|
|
1049
|
+
yield* tuple;
|
|
1050
|
+
}
|
|
1051
|
+
break;
|
|
1052
|
+
}
|
|
1053
|
+
}
|
|
1054
|
+
function chunkParams(fragments, params, maxChunkSize) {
|
|
1055
|
+
let totalParamCount = 0;
|
|
1056
|
+
let maxParamsPerFragment = 0;
|
|
1057
|
+
for (const fragment of pairFragmentsWithParams(fragments, params)) {
|
|
1058
|
+
let paramSize = 0;
|
|
1059
|
+
for (const _ of flattenedFragmentParams(fragment)) {
|
|
1060
|
+
void _;
|
|
1061
|
+
paramSize++;
|
|
1062
|
+
}
|
|
1063
|
+
maxParamsPerFragment = Math.max(maxParamsPerFragment, paramSize);
|
|
1064
|
+
totalParamCount += paramSize;
|
|
1065
|
+
}
|
|
1066
|
+
let chunkedParams = [[]];
|
|
1067
|
+
for (const fragment of pairFragmentsWithParams(fragments, params)) {
|
|
1068
|
+
switch (fragment.type) {
|
|
1069
|
+
case "parameter": {
|
|
1070
|
+
for (const params2 of chunkedParams) {
|
|
1071
|
+
params2.push(fragment.value);
|
|
1072
|
+
}
|
|
1073
|
+
break;
|
|
1074
|
+
}
|
|
1075
|
+
case "stringChunk": {
|
|
1076
|
+
break;
|
|
1077
|
+
}
|
|
1078
|
+
case "parameterTuple": {
|
|
1079
|
+
const thisParamCount = fragment.value.length;
|
|
1080
|
+
let chunks = [];
|
|
1081
|
+
if (maxChunkSize && // Have we split the parameters into chunks already?
|
|
1082
|
+
chunkedParams.length === 1 && // Is this the fragment that has the most parameters?
|
|
1083
|
+
thisParamCount === maxParamsPerFragment && // Do we need chunking to fit the parameters?
|
|
1084
|
+
totalParamCount > maxChunkSize && // Would chunking enable us to fit the parameters?
|
|
1085
|
+
totalParamCount - thisParamCount < maxChunkSize) {
|
|
1086
|
+
const availableSize = maxChunkSize - (totalParamCount - thisParamCount);
|
|
1087
|
+
chunks = chunkArray(fragment.value, availableSize);
|
|
1088
|
+
} else {
|
|
1089
|
+
chunks = [fragment.value];
|
|
1090
|
+
}
|
|
1091
|
+
chunkedParams = chunkedParams.flatMap((params2) => chunks.map((chunk) => [...params2, chunk]));
|
|
1092
|
+
break;
|
|
1093
|
+
}
|
|
1094
|
+
case "parameterTupleList": {
|
|
1095
|
+
const thisParamCount = fragment.value.reduce((acc, tuple) => acc + tuple.length, 0);
|
|
1096
|
+
const completeChunks = [];
|
|
1097
|
+
let currentChunk = [];
|
|
1098
|
+
let currentChunkParamCount = 0;
|
|
1099
|
+
for (const tuple of fragment.value) {
|
|
1100
|
+
if (maxChunkSize && // Have we split the parameters into chunks already?
|
|
1101
|
+
chunkedParams.length === 1 && // Is this the fragment that has the most parameters?
|
|
1102
|
+
thisParamCount === maxParamsPerFragment && // Is there anything in the current chunk?
|
|
1103
|
+
currentChunk.length > 0 && // Will adding this tuple exceed the max chunk size?
|
|
1104
|
+
totalParamCount - thisParamCount + currentChunkParamCount + tuple.length > maxChunkSize) {
|
|
1105
|
+
completeChunks.push(currentChunk);
|
|
1106
|
+
currentChunk = [];
|
|
1107
|
+
currentChunkParamCount = 0;
|
|
1108
|
+
}
|
|
1109
|
+
currentChunk.push(tuple);
|
|
1110
|
+
currentChunkParamCount += tuple.length;
|
|
1111
|
+
}
|
|
1112
|
+
if (currentChunk.length > 0) {
|
|
1113
|
+
completeChunks.push(currentChunk);
|
|
1114
|
+
}
|
|
1115
|
+
chunkedParams = chunkedParams.flatMap((params2) => completeChunks.map((chunk) => [...params2, chunk]));
|
|
1116
|
+
break;
|
|
1117
|
+
}
|
|
1118
|
+
}
|
|
1119
|
+
}
|
|
1120
|
+
return chunkedParams;
|
|
1121
|
+
}
|
|
1122
|
+
function chunkArray(array, chunkSize) {
|
|
1123
|
+
const result = [];
|
|
1124
|
+
for (let i = 0; i < array.length; i += chunkSize) {
|
|
1125
|
+
result.push(array.slice(i, i + chunkSize));
|
|
1126
|
+
}
|
|
1127
|
+
return result;
|
|
1128
|
+
}
|
|
797
1129
|
|
|
798
|
-
// src/interpreter/
|
|
1130
|
+
// src/interpreter/serialize-sql.ts
|
|
799
1131
|
import { ColumnTypeEnum } from "@prisma/driver-adapter-utils";
|
|
800
1132
|
function serializeSql(resultSet) {
|
|
801
1133
|
const mappers = resultSet.columnTypes.map((type) => {
|
|
@@ -826,29 +1158,90 @@ function serializeSql(resultSet) {
|
|
|
826
1158
|
);
|
|
827
1159
|
}
|
|
828
1160
|
function serializeRawSql(resultSet) {
|
|
829
|
-
const types = resultSet.columnTypes.map((type) => serializeColumnType(type));
|
|
830
|
-
const mappers = types.map((type) => {
|
|
831
|
-
switch (type) {
|
|
832
|
-
case "bytes":
|
|
833
|
-
return (value) => Array.isArray(value) ? new Uint8Array(value) : value;
|
|
834
|
-
case "int":
|
|
835
|
-
return (value) => value === null ? null : typeof value === "number" ? value : parseInt(`${value}`, 10);
|
|
836
|
-
case "bigint":
|
|
837
|
-
return (value) => value === null ? null : typeof value === "bigint" ? value : BigInt(`${value}`);
|
|
838
|
-
case "json":
|
|
839
|
-
return (value) => typeof value === "string" ? JSON.parse(value) : value;
|
|
840
|
-
case "bool":
|
|
841
|
-
return (value) => typeof value === "string" ? value === "true" || value === "1" : typeof value === "number" ? value === 1 : value;
|
|
842
|
-
default:
|
|
843
|
-
return (value) => value;
|
|
844
|
-
}
|
|
845
|
-
});
|
|
846
1161
|
return {
|
|
847
1162
|
columns: resultSet.columnNames,
|
|
848
1163
|
types: resultSet.columnTypes.map((type) => serializeColumnType(type)),
|
|
849
|
-
rows: resultSet.rows.map(
|
|
1164
|
+
rows: resultSet.rows.map(
|
|
1165
|
+
(row) => row.map((value, index) => serializeRawValue(value, resultSet.columnTypes[index]))
|
|
1166
|
+
)
|
|
850
1167
|
};
|
|
851
1168
|
}
|
|
1169
|
+
function serializeRawValue(value, type) {
|
|
1170
|
+
if (value === null) {
|
|
1171
|
+
return null;
|
|
1172
|
+
}
|
|
1173
|
+
switch (type) {
|
|
1174
|
+
case ColumnTypeEnum.Int32:
|
|
1175
|
+
switch (typeof value) {
|
|
1176
|
+
case "number":
|
|
1177
|
+
return Math.trunc(value);
|
|
1178
|
+
case "string":
|
|
1179
|
+
return Math.trunc(Number(value));
|
|
1180
|
+
default:
|
|
1181
|
+
throw new Error(`Cannot serialize value of type ${typeof value} as Int32`);
|
|
1182
|
+
}
|
|
1183
|
+
case ColumnTypeEnum.Int32Array:
|
|
1184
|
+
if (!Array.isArray(value)) {
|
|
1185
|
+
throw new Error(`Cannot serialize value of type ${typeof value} as Int32Array`);
|
|
1186
|
+
}
|
|
1187
|
+
return value.map((v) => serializeRawValue(v, ColumnTypeEnum.Int32));
|
|
1188
|
+
case ColumnTypeEnum.Int64:
|
|
1189
|
+
switch (typeof value) {
|
|
1190
|
+
case "number":
|
|
1191
|
+
return BigInt(Math.trunc(value));
|
|
1192
|
+
case "string":
|
|
1193
|
+
return value;
|
|
1194
|
+
default:
|
|
1195
|
+
throw new Error(`Cannot serialize value of type ${typeof value} as Int64`);
|
|
1196
|
+
}
|
|
1197
|
+
case ColumnTypeEnum.Int64Array:
|
|
1198
|
+
if (!Array.isArray(value)) {
|
|
1199
|
+
throw new Error(`Cannot serialize value of type ${typeof value} as Int64Array`);
|
|
1200
|
+
}
|
|
1201
|
+
return value.map((v) => serializeRawValue(v, ColumnTypeEnum.Int64));
|
|
1202
|
+
case ColumnTypeEnum.Json:
|
|
1203
|
+
switch (typeof value) {
|
|
1204
|
+
case "string":
|
|
1205
|
+
return JSON.parse(value);
|
|
1206
|
+
default:
|
|
1207
|
+
throw new Error(`Cannot serialize value of type ${typeof value} as Json`);
|
|
1208
|
+
}
|
|
1209
|
+
case ColumnTypeEnum.JsonArray:
|
|
1210
|
+
if (!Array.isArray(value)) {
|
|
1211
|
+
throw new Error(`Cannot serialize value of type ${typeof value} as JsonArray`);
|
|
1212
|
+
}
|
|
1213
|
+
return value.map((v) => serializeRawValue(v, ColumnTypeEnum.Json));
|
|
1214
|
+
case ColumnTypeEnum.Bytes:
|
|
1215
|
+
if (Array.isArray(value)) {
|
|
1216
|
+
return new Uint8Array(value);
|
|
1217
|
+
} else {
|
|
1218
|
+
throw new Error(`Cannot serialize value of type ${typeof value} as Bytes`);
|
|
1219
|
+
}
|
|
1220
|
+
case ColumnTypeEnum.BytesArray:
|
|
1221
|
+
if (!Array.isArray(value)) {
|
|
1222
|
+
throw new Error(`Cannot serialize value of type ${typeof value} as BytesArray`);
|
|
1223
|
+
}
|
|
1224
|
+
return value.map((v) => serializeRawValue(v, ColumnTypeEnum.Bytes));
|
|
1225
|
+
case ColumnTypeEnum.Boolean:
|
|
1226
|
+
switch (typeof value) {
|
|
1227
|
+
case "boolean":
|
|
1228
|
+
return value;
|
|
1229
|
+
case "string":
|
|
1230
|
+
return value === "true" || value === "1";
|
|
1231
|
+
case "number":
|
|
1232
|
+
return value === 1;
|
|
1233
|
+
default:
|
|
1234
|
+
throw new Error(`Cannot serialize value of type ${typeof value} as Boolean`);
|
|
1235
|
+
}
|
|
1236
|
+
case ColumnTypeEnum.BooleanArray:
|
|
1237
|
+
if (!Array.isArray(value)) {
|
|
1238
|
+
throw new Error(`Cannot serialize value of type ${typeof value} as BooleanArray`);
|
|
1239
|
+
}
|
|
1240
|
+
return value.map((v) => serializeRawValue(v, ColumnTypeEnum.Boolean));
|
|
1241
|
+
default:
|
|
1242
|
+
return value;
|
|
1243
|
+
}
|
|
1244
|
+
}
|
|
852
1245
|
function serializeColumnType(columnType) {
|
|
853
1246
|
switch (columnType) {
|
|
854
1247
|
case ColumnTypeEnum.Int32:
|
|
@@ -993,7 +1386,7 @@ function getErrorCode2(error) {
|
|
|
993
1386
|
}
|
|
994
1387
|
}
|
|
995
1388
|
|
|
996
|
-
// src/interpreter/
|
|
1389
|
+
// src/interpreter/query-interpreter.ts
|
|
997
1390
|
var QueryInterpreter = class _QueryInterpreter {
|
|
998
1391
|
#transactionManager;
|
|
999
1392
|
#placeholderValues;
|
|
@@ -1003,6 +1396,7 @@ var QueryInterpreter = class _QueryInterpreter {
|
|
|
1003
1396
|
#serializer;
|
|
1004
1397
|
#rawSerializer;
|
|
1005
1398
|
#provider;
|
|
1399
|
+
#connectioInfo;
|
|
1006
1400
|
constructor({
|
|
1007
1401
|
transactionManager,
|
|
1008
1402
|
placeholderValues,
|
|
@@ -1010,7 +1404,8 @@ var QueryInterpreter = class _QueryInterpreter {
|
|
|
1010
1404
|
tracingHelper,
|
|
1011
1405
|
serializer,
|
|
1012
1406
|
rawSerializer,
|
|
1013
|
-
provider
|
|
1407
|
+
provider,
|
|
1408
|
+
connectionInfo
|
|
1014
1409
|
}) {
|
|
1015
1410
|
this.#transactionManager = transactionManager;
|
|
1016
1411
|
this.#placeholderValues = placeholderValues;
|
|
@@ -1019,6 +1414,7 @@ var QueryInterpreter = class _QueryInterpreter {
|
|
|
1019
1414
|
this.#serializer = serializer;
|
|
1020
1415
|
this.#rawSerializer = rawSerializer ?? serializer;
|
|
1021
1416
|
this.#provider = provider;
|
|
1417
|
+
this.#connectioInfo = connectionInfo;
|
|
1022
1418
|
}
|
|
1023
1419
|
static forSql(options) {
|
|
1024
1420
|
return new _QueryInterpreter({
|
|
@@ -1028,7 +1424,8 @@ var QueryInterpreter = class _QueryInterpreter {
|
|
|
1028
1424
|
tracingHelper: options.tracingHelper,
|
|
1029
1425
|
serializer: serializeSql,
|
|
1030
1426
|
rawSerializer: serializeRawSql,
|
|
1031
|
-
provider: options.provider
|
|
1427
|
+
provider: options.provider,
|
|
1428
|
+
connectionInfo: options.connectionInfo
|
|
1032
1429
|
});
|
|
1033
1430
|
}
|
|
1034
1431
|
async run(queryPlan, queryable) {
|
|
@@ -1089,21 +1486,41 @@ var QueryInterpreter = class _QueryInterpreter {
|
|
|
1089
1486
|
};
|
|
1090
1487
|
}
|
|
1091
1488
|
case "execute": {
|
|
1092
|
-
const
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1489
|
+
const queries = renderQuery(node.args, scope, generators, this.#maxChunkSize());
|
|
1490
|
+
let sum = 0;
|
|
1491
|
+
for (const query of queries) {
|
|
1492
|
+
sum += await this.#withQuerySpanAndEvent(
|
|
1493
|
+
query,
|
|
1494
|
+
queryable,
|
|
1495
|
+
() => queryable.executeRaw(query).catch(
|
|
1496
|
+
(err) => node.args.type === "rawSql" ? rethrowAsUserFacingRawError(err) : rethrowAsUserFacing(err)
|
|
1497
|
+
)
|
|
1498
|
+
);
|
|
1499
|
+
}
|
|
1500
|
+
return { value: sum };
|
|
1096
1501
|
}
|
|
1097
1502
|
case "query": {
|
|
1098
|
-
const
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1503
|
+
const queries = renderQuery(node.args, scope, generators, this.#maxChunkSize());
|
|
1504
|
+
let results;
|
|
1505
|
+
for (const query of queries) {
|
|
1506
|
+
const result = await this.#withQuerySpanAndEvent(
|
|
1507
|
+
query,
|
|
1508
|
+
queryable,
|
|
1509
|
+
() => queryable.queryRaw(query).catch(
|
|
1510
|
+
(err) => node.args.type === "rawSql" ? rethrowAsUserFacingRawError(err) : rethrowAsUserFacing(err)
|
|
1511
|
+
)
|
|
1512
|
+
);
|
|
1513
|
+
if (results === void 0) {
|
|
1514
|
+
results = result;
|
|
1103
1515
|
} else {
|
|
1104
|
-
|
|
1516
|
+
results.rows.push(...result.rows);
|
|
1517
|
+
results.lastInsertId = result.lastInsertId;
|
|
1105
1518
|
}
|
|
1106
|
-
}
|
|
1519
|
+
}
|
|
1520
|
+
return {
|
|
1521
|
+
value: node.args.type === "rawSql" ? this.#rawSerializer(results) : this.#serializer(results),
|
|
1522
|
+
lastInsertId: results?.lastInsertId
|
|
1523
|
+
};
|
|
1107
1524
|
}
|
|
1108
1525
|
case "reverse": {
|
|
1109
1526
|
const { value, lastInsertId } = await this.interpretNode(node.args, queryable, scope, generators);
|
|
@@ -1182,43 +1599,12 @@ var QueryInterpreter = class _QueryInterpreter {
|
|
|
1182
1599
|
case "diff": {
|
|
1183
1600
|
const { value: from } = await this.interpretNode(node.args.from, queryable, scope, generators);
|
|
1184
1601
|
const { value: to } = await this.interpretNode(node.args.to, queryable, scope, generators);
|
|
1185
|
-
const toSet = new Set(asList(to));
|
|
1186
|
-
return { value: asList(from).filter((item) => !toSet.has(item)) };
|
|
1187
|
-
}
|
|
1188
|
-
case "distinctBy": {
|
|
1189
|
-
const { value, lastInsertId } = await this.interpretNode(node.args.expr, queryable, scope, generators);
|
|
1190
|
-
const seen = /* @__PURE__ */ new Set();
|
|
1191
|
-
const result = [];
|
|
1192
|
-
for (const item of asList(value)) {
|
|
1193
|
-
const key = getRecordKey(item, node.args.fields);
|
|
1194
|
-
if (!seen.has(key)) {
|
|
1195
|
-
seen.add(key);
|
|
1196
|
-
result.push(item);
|
|
1197
|
-
}
|
|
1198
|
-
}
|
|
1199
|
-
return { value: result, lastInsertId };
|
|
1602
|
+
const toSet = new Set(asList(to).map((item) => JSON.stringify(item)));
|
|
1603
|
+
return { value: asList(from).filter((item) => !toSet.has(JSON.stringify(item))) };
|
|
1200
1604
|
}
|
|
1201
|
-
case "
|
|
1605
|
+
case "process": {
|
|
1202
1606
|
const { value, lastInsertId } = await this.interpretNode(node.args.expr, queryable, scope, generators);
|
|
1203
|
-
|
|
1204
|
-
const linkingFields = node.args.pagination.linkingFields;
|
|
1205
|
-
if (linkingFields !== null) {
|
|
1206
|
-
const groupedByParent = /* @__PURE__ */ new Map();
|
|
1207
|
-
for (const item of list) {
|
|
1208
|
-
const parentKey = getRecordKey(item, linkingFields);
|
|
1209
|
-
if (!groupedByParent.has(parentKey)) {
|
|
1210
|
-
groupedByParent.set(parentKey, []);
|
|
1211
|
-
}
|
|
1212
|
-
groupedByParent.get(parentKey).push(item);
|
|
1213
|
-
}
|
|
1214
|
-
const groupList = Array.from(groupedByParent.entries());
|
|
1215
|
-
groupList.sort(([aId], [bId]) => aId < bId ? -1 : aId > bId ? 1 : 0);
|
|
1216
|
-
return {
|
|
1217
|
-
value: groupList.flatMap(([, elems]) => paginate(elems, node.args.pagination)),
|
|
1218
|
-
lastInsertId
|
|
1219
|
-
};
|
|
1220
|
-
}
|
|
1221
|
-
return { value: paginate(list, node.args.pagination), lastInsertId };
|
|
1607
|
+
return { value: processRecords(value, node.args.operations), lastInsertId };
|
|
1222
1608
|
}
|
|
1223
1609
|
case "initializeRecord": {
|
|
1224
1610
|
const { lastInsertId } = await this.interpretNode(node.args.expr, queryable, scope, generators);
|
|
@@ -1240,6 +1626,34 @@ var QueryInterpreter = class _QueryInterpreter {
|
|
|
1240
1626
|
assertNever(node, `Unexpected node type: ${node.type}`);
|
|
1241
1627
|
}
|
|
1242
1628
|
}
|
|
1629
|
+
#maxChunkSize() {
|
|
1630
|
+
if (this.#connectioInfo?.maxBindValues !== void 0) {
|
|
1631
|
+
return this.#connectioInfo.maxBindValues;
|
|
1632
|
+
}
|
|
1633
|
+
return this.#providerMaxChunkSize();
|
|
1634
|
+
}
|
|
1635
|
+
#providerMaxChunkSize() {
|
|
1636
|
+
if (this.#provider === void 0) {
|
|
1637
|
+
return void 0;
|
|
1638
|
+
}
|
|
1639
|
+
switch (this.#provider) {
|
|
1640
|
+
case "cockroachdb":
|
|
1641
|
+
case "postgres":
|
|
1642
|
+
case "postgresql":
|
|
1643
|
+
case "prisma+postgres":
|
|
1644
|
+
return 32766;
|
|
1645
|
+
case "mysql":
|
|
1646
|
+
return 65535;
|
|
1647
|
+
case "sqlite":
|
|
1648
|
+
return 999;
|
|
1649
|
+
case "sqlserver":
|
|
1650
|
+
return 2098;
|
|
1651
|
+
case "mongodb":
|
|
1652
|
+
return void 0;
|
|
1653
|
+
default:
|
|
1654
|
+
assertNever(this.#provider, `Unexpected provider: ${this.#provider}`);
|
|
1655
|
+
}
|
|
1656
|
+
}
|
|
1243
1657
|
#withQuerySpanAndEvent(query, queryable, execute) {
|
|
1244
1658
|
return withQuerySpanAndEvent({
|
|
1245
1659
|
query,
|
|
@@ -1317,18 +1731,6 @@ function attachChildrenToParents(parentRecords, children) {
|
|
|
1317
1731
|
}
|
|
1318
1732
|
return parentRecords;
|
|
1319
1733
|
}
|
|
1320
|
-
function paginate(list, { cursor, skip, take }) {
|
|
1321
|
-
const cursorIndex = cursor !== null ? list.findIndex((item) => doKeysMatch(item, cursor)) : 0;
|
|
1322
|
-
if (cursorIndex === -1) {
|
|
1323
|
-
return [];
|
|
1324
|
-
}
|
|
1325
|
-
const start = cursorIndex + (skip ?? 0);
|
|
1326
|
-
const end = take !== null ? start + take : list.length;
|
|
1327
|
-
return list.slice(start, end);
|
|
1328
|
-
}
|
|
1329
|
-
function getRecordKey(record, fields) {
|
|
1330
|
-
return JSON.stringify(fields.map((field) => record[field]));
|
|
1331
|
-
}
|
|
1332
1734
|
function evalFieldInitializer(initializer, lastInsertId, scope, generators) {
|
|
1333
1735
|
switch (initializer.type) {
|
|
1334
1736
|
case "value":
|
|
@@ -1362,54 +1764,36 @@ function evalFieldOperation(op, value, scope, generators) {
|
|
|
1362
1764
|
}
|
|
1363
1765
|
}
|
|
1364
1766
|
|
|
1365
|
-
// src/json-protocol.ts
|
|
1366
|
-
import
|
|
1367
|
-
function
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
return result.map(normalizeJsonProtocolValues);
|
|
1373
|
-
}
|
|
1374
|
-
if (typeof result === "object") {
|
|
1375
|
-
if (isTaggedValue(result)) {
|
|
1376
|
-
return normalizeTaggedValue(result);
|
|
1377
|
-
}
|
|
1378
|
-
if (result.constructor !== null && result.constructor.name !== "Object") {
|
|
1379
|
-
return result;
|
|
1767
|
+
// src/raw-json-protocol.ts
|
|
1768
|
+
import Decimal4 from "decimal.js";
|
|
1769
|
+
function normalizeRawJsonProtocolResponse(response) {
|
|
1770
|
+
for (let i = 0; i < response.rows.length; i++) {
|
|
1771
|
+
const row = response.rows[i];
|
|
1772
|
+
for (let j = 0; j < row.length; j++) {
|
|
1773
|
+
row[j] = normalizeValue(response.types[j], row[j]);
|
|
1380
1774
|
}
|
|
1381
|
-
return mapObjectValues(result, normalizeJsonProtocolValues);
|
|
1382
1775
|
}
|
|
1383
|
-
return
|
|
1384
|
-
}
|
|
1385
|
-
function isTaggedValue(value) {
|
|
1386
|
-
return value !== null && typeof value == "object" && typeof value["$type"] === "string";
|
|
1776
|
+
return response;
|
|
1387
1777
|
}
|
|
1388
|
-
function
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
return { $type, value: String(value) };
|
|
1392
|
-
case "Bytes":
|
|
1393
|
-
return { $type, value };
|
|
1394
|
-
case "DateTime":
|
|
1395
|
-
return { $type, value: new Date(value).toISOString() };
|
|
1396
|
-
case "Decimal":
|
|
1397
|
-
return { $type, value: String(new Decimal3(value)) };
|
|
1398
|
-
case "Json":
|
|
1399
|
-
return { $type, value: JSON.stringify(JSON.parse(value)) };
|
|
1400
|
-
default:
|
|
1401
|
-
assertNever(value, "Unknown tagged value");
|
|
1778
|
+
function normalizeValue(type, value) {
|
|
1779
|
+
if (value === null) {
|
|
1780
|
+
return value;
|
|
1402
1781
|
}
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1782
|
+
switch (type) {
|
|
1783
|
+
case "bigint":
|
|
1784
|
+
return String(BigInt(value));
|
|
1785
|
+
case "decimal":
|
|
1786
|
+
return String(new Decimal4(value));
|
|
1787
|
+
case "bigint-array":
|
|
1788
|
+
return value.map((v) => normalizeValue("bigint", v));
|
|
1789
|
+
case "decimal-array":
|
|
1790
|
+
return value.map((v) => normalizeValue("decimal", v));
|
|
1791
|
+
default:
|
|
1792
|
+
return value;
|
|
1408
1793
|
}
|
|
1409
|
-
return result;
|
|
1410
1794
|
}
|
|
1411
1795
|
|
|
1412
|
-
// src/
|
|
1796
|
+
// src/transaction-manager/transaction-manager.ts
|
|
1413
1797
|
import { Debug } from "@prisma/debug";
|
|
1414
1798
|
|
|
1415
1799
|
// src/crypto.ts
|
|
@@ -1421,7 +1805,7 @@ async function randomUUID() {
|
|
|
1421
1805
|
return crypto.randomUUID();
|
|
1422
1806
|
}
|
|
1423
1807
|
|
|
1424
|
-
// src/
|
|
1808
|
+
// src/transaction-manager/transaction-manager-error.ts
|
|
1425
1809
|
var TransactionManagerError = class extends UserFacingError {
|
|
1426
1810
|
name = "TransactionManagerError";
|
|
1427
1811
|
constructor(message, meta) {
|
|
@@ -1458,7 +1842,7 @@ var TransactionStartTimeoutError = class extends TransactionManagerError {
|
|
|
1458
1842
|
var TransactionExecutionTimeoutError = class extends TransactionManagerError {
|
|
1459
1843
|
constructor(operation, { timeout, timeTaken }) {
|
|
1460
1844
|
super(
|
|
1461
|
-
`A ${operation} cannot be executed on an expired transaction. The timeout for this transaction was ${timeout} ms, however ${timeTaken} ms passed since the start of the transaction. Consider increasing the interactive transaction timeout or doing less work in the transaction
|
|
1845
|
+
`A ${operation} cannot be executed on an expired transaction. The timeout for this transaction was ${timeout} ms, however ${timeTaken} ms passed since the start of the transaction. Consider increasing the interactive transaction timeout or doing less work in the transaction.`,
|
|
1462
1846
|
{ operation, timeout, timeTaken }
|
|
1463
1847
|
);
|
|
1464
1848
|
}
|
|
@@ -1474,7 +1858,7 @@ var InvalidTransactionIsolationLevelError = class extends TransactionManagerErro
|
|
|
1474
1858
|
}
|
|
1475
1859
|
};
|
|
1476
1860
|
|
|
1477
|
-
// src/
|
|
1861
|
+
// src/transaction-manager/transaction-manager.ts
|
|
1478
1862
|
var MAX_CLOSED_TRANSACTIONS = 100;
|
|
1479
1863
|
var debug = Debug("prisma:client:transactionManager");
|
|
1480
1864
|
var COMMIT_QUERY = () => ({ sql: "COMMIT", args: [], argTypes: [] });
|
|
@@ -1529,7 +1913,7 @@ var TransactionManager = class {
|
|
|
1529
1913
|
this.transactions.set(transaction.id, transaction);
|
|
1530
1914
|
let hasTimedOut = false;
|
|
1531
1915
|
const startTimer = setTimeout(() => hasTimedOut = true, validatedOptions.maxWait);
|
|
1532
|
-
transaction.transaction = await this.driverAdapter.startTransaction(validatedOptions.isolationLevel);
|
|
1916
|
+
transaction.transaction = await this.driverAdapter.startTransaction(validatedOptions.isolationLevel).catch(rethrowAsUserFacing);
|
|
1533
1917
|
clearTimeout(startTimer);
|
|
1534
1918
|
switch (transaction.status) {
|
|
1535
1919
|
case "waiting":
|
|
@@ -1676,6 +2060,8 @@ export {
|
|
|
1676
2060
|
TransactionManager,
|
|
1677
2061
|
TransactionManagerError,
|
|
1678
2062
|
UserFacingError,
|
|
2063
|
+
convertCompactedRows,
|
|
2064
|
+
deserializeJsonResponse,
|
|
1679
2065
|
doKeysMatch,
|
|
1680
2066
|
isDeepStrictEqual,
|
|
1681
2067
|
isPrismaValueBigInt,
|
|
@@ -1684,5 +2070,6 @@ export {
|
|
|
1684
2070
|
isPrismaValuePlaceholder,
|
|
1685
2071
|
noopTracingHelper,
|
|
1686
2072
|
normalizeJsonProtocolValues,
|
|
2073
|
+
normalizeRawJsonProtocolResponse,
|
|
1687
2074
|
safeJsonStringify
|
|
1688
2075
|
};
|