@prisma/client-engine-runtime 6.9.0-dev.5 → 6.9.0-dev.51
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 +54 -1
- package/dist/UserFacingError.d.ts +3 -3
- package/dist/index.d.mts +92 -13
- package/dist/index.d.ts +92 -13
- package/dist/index.js +597 -187
- package/dist/index.mjs +591 -186
- package/dist/interpreter/DataMapper.d.ts +4 -1
- package/dist/interpreter/QueryInterpreter.d.ts +2 -1
- package/dist/interpreter/generators.d.ts +2 -1
- package/dist/interpreter/renderQuery.d.ts +2 -1
- package/dist/interpreter/serializeSql.d.ts +2 -1
- package/dist/tracing.d.ts +10 -2
- package/dist/transactionManager/TransactionManager.d.ts +3 -1
- package/dist/transactionManager/TransactionManagerErrors.d.ts +4 -4
- package/dist/utils.d.ts +15 -0
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -30,26 +30,274 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
30
30
|
// src/index.ts
|
|
31
31
|
var index_exports = {};
|
|
32
32
|
__export(index_exports, {
|
|
33
|
+
DataMapperError: () => DataMapperError,
|
|
33
34
|
QueryInterpreter: () => QueryInterpreter,
|
|
34
35
|
TransactionManager: () => TransactionManager,
|
|
35
36
|
TransactionManagerError: () => TransactionManagerError,
|
|
36
37
|
UserFacingError: () => UserFacingError,
|
|
38
|
+
doKeysMatch: () => doKeysMatch,
|
|
39
|
+
isDeepStrictEqual: () => isDeepStrictEqual,
|
|
40
|
+
isPrismaValueBigInt: () => isPrismaValueBigInt,
|
|
37
41
|
isPrismaValueBytes: () => isPrismaValueBytes,
|
|
38
42
|
isPrismaValueGenerator: () => isPrismaValueGenerator,
|
|
39
43
|
isPrismaValuePlaceholder: () => isPrismaValuePlaceholder,
|
|
40
|
-
noopTracingHelper: () => noopTracingHelper
|
|
44
|
+
noopTracingHelper: () => noopTracingHelper,
|
|
45
|
+
safeJsonStringify: () => safeJsonStringify
|
|
41
46
|
});
|
|
42
47
|
module.exports = __toCommonJS(index_exports);
|
|
43
48
|
|
|
44
|
-
// src/interpreter/
|
|
45
|
-
var
|
|
49
|
+
// src/interpreter/DataMapper.ts
|
|
50
|
+
var import_decimal2 = __toESM(require("decimal.js"));
|
|
46
51
|
|
|
47
52
|
// src/utils.ts
|
|
53
|
+
var import_decimal = __toESM(require("decimal.js"));
|
|
48
54
|
function assertNever(_, message) {
|
|
49
55
|
throw new Error(message);
|
|
50
56
|
}
|
|
57
|
+
function isDeepStrictEqual(a, b) {
|
|
58
|
+
return a === b || a !== null && b !== null && typeof a === "object" && typeof b === "object" && Object.keys(a).length === Object.keys(b).length && Object.keys(a).every((key) => isDeepStrictEqual(a[key], b[key]));
|
|
59
|
+
}
|
|
60
|
+
function doKeysMatch(lhs, rhs) {
|
|
61
|
+
const lhsKeys = Object.keys(lhs);
|
|
62
|
+
const rhsKeys = Object.keys(rhs);
|
|
63
|
+
const smallerKeyList = lhsKeys.length < rhsKeys.length ? lhsKeys : rhsKeys;
|
|
64
|
+
return smallerKeyList.every((key) => {
|
|
65
|
+
if (typeof lhs[key] !== typeof rhs[key]) {
|
|
66
|
+
if (typeof lhs[key] === "number" || typeof rhs[key] === "number") {
|
|
67
|
+
return `${lhs[key]}` === `${rhs[key]}`;
|
|
68
|
+
} else if (typeof lhs[key] === "bigint" || typeof rhs[key] === "bigint") {
|
|
69
|
+
return BigInt(`${lhs[key]}`.replace(/n$/, "")) === BigInt(`${rhs[key]}`.replace(/n$/, ""));
|
|
70
|
+
} else if (lhs[key] instanceof Date || rhs[key] instanceof Date) {
|
|
71
|
+
return (/* @__PURE__ */ new Date(`${lhs[key]}`)).getTime() === (/* @__PURE__ */ new Date(`${rhs[key]}`)).getTime();
|
|
72
|
+
} else if (import_decimal.default.isDecimal(lhs[key]) || import_decimal.default.isDecimal(rhs[key])) {
|
|
73
|
+
return new import_decimal.default(`${lhs[key]}`).equals(new import_decimal.default(`${rhs[key]}`));
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return isDeepStrictEqual(lhs[key], rhs[key]);
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
function safeJsonStringify(obj) {
|
|
80
|
+
return JSON.stringify(obj, (_key, val) => {
|
|
81
|
+
if (typeof val === "bigint") {
|
|
82
|
+
return val.toString();
|
|
83
|
+
} else if (val instanceof Uint8Array) {
|
|
84
|
+
return Buffer.from(val).toString("base64");
|
|
85
|
+
}
|
|
86
|
+
return val;
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// src/interpreter/DataMapper.ts
|
|
91
|
+
var DataMapperError = class extends Error {
|
|
92
|
+
name = "DataMapperError";
|
|
93
|
+
};
|
|
94
|
+
function applyDataMap(data, structure, enums) {
|
|
95
|
+
switch (structure.type) {
|
|
96
|
+
case "AffectedRows":
|
|
97
|
+
if (typeof data !== "number") {
|
|
98
|
+
throw new DataMapperError(`Expected an affected rows count, got: ${typeof data} (${data})`);
|
|
99
|
+
}
|
|
100
|
+
return { count: data };
|
|
101
|
+
case "Object":
|
|
102
|
+
return mapArrayOrObject(data, structure.fields, enums);
|
|
103
|
+
case "Value":
|
|
104
|
+
return mapValue(data, "<result>", structure.resultType, enums);
|
|
105
|
+
default:
|
|
106
|
+
assertNever(structure, `Invalid data mapping type: '${structure.type}'`);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
function mapArrayOrObject(data, fields, enums) {
|
|
110
|
+
if (data === null) return null;
|
|
111
|
+
if (Array.isArray(data)) {
|
|
112
|
+
const rows = data;
|
|
113
|
+
return rows.map((row) => mapObject(row, fields, enums));
|
|
114
|
+
}
|
|
115
|
+
if (typeof data === "object") {
|
|
116
|
+
const row = data;
|
|
117
|
+
return mapObject(row, fields, enums);
|
|
118
|
+
}
|
|
119
|
+
if (typeof data === "string") {
|
|
120
|
+
let decodedData;
|
|
121
|
+
try {
|
|
122
|
+
decodedData = JSON.parse(data);
|
|
123
|
+
} catch (error) {
|
|
124
|
+
throw new DataMapperError(`Expected an array or object, got a string that is not valid JSON`, {
|
|
125
|
+
cause: error
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
return mapArrayOrObject(decodedData, fields, enums);
|
|
129
|
+
}
|
|
130
|
+
throw new DataMapperError(`Expected an array or an object, got: ${typeof data}`);
|
|
131
|
+
}
|
|
132
|
+
function mapObject(data, fields, enums) {
|
|
133
|
+
if (typeof data !== "object") {
|
|
134
|
+
throw new DataMapperError(`Expected an object, but got '${typeof data}'`);
|
|
135
|
+
}
|
|
136
|
+
const result = {};
|
|
137
|
+
for (const [name, node] of Object.entries(fields)) {
|
|
138
|
+
switch (node.type) {
|
|
139
|
+
case "AffectedRows": {
|
|
140
|
+
throw new DataMapperError(`Unexpected 'AffectedRows' node in data mapping for field '${name}'`);
|
|
141
|
+
}
|
|
142
|
+
case "Object": {
|
|
143
|
+
if (!node.flattened && !Object.hasOwn(data, name)) {
|
|
144
|
+
throw new DataMapperError(
|
|
145
|
+
`Missing data field (Object): '${name}'; node: ${JSON.stringify(node)}; data: ${JSON.stringify(data)}`
|
|
146
|
+
);
|
|
147
|
+
}
|
|
148
|
+
const target = node.flattened ? data : data[name];
|
|
149
|
+
result[name] = mapArrayOrObject(target, node.fields, enums);
|
|
150
|
+
break;
|
|
151
|
+
}
|
|
152
|
+
case "Value":
|
|
153
|
+
{
|
|
154
|
+
const dbName = node.dbName;
|
|
155
|
+
if (Object.hasOwn(data, dbName)) {
|
|
156
|
+
result[name] = mapValue(data[dbName], dbName, node.resultType, enums);
|
|
157
|
+
} else {
|
|
158
|
+
throw new DataMapperError(
|
|
159
|
+
`Missing data field (Value): '${dbName}'; node: ${JSON.stringify(node)}; data: ${JSON.stringify(data)}`
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
break;
|
|
164
|
+
default:
|
|
165
|
+
assertNever(node, `DataMapper: Invalid data mapping node type: '${node.type}'`);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
return result;
|
|
169
|
+
}
|
|
170
|
+
function mapValue(value, columnName, resultType, enums) {
|
|
171
|
+
if (value === null) {
|
|
172
|
+
return resultType.type === "Array" ? [] : null;
|
|
173
|
+
}
|
|
174
|
+
switch (resultType.type) {
|
|
175
|
+
case "Any":
|
|
176
|
+
return value;
|
|
177
|
+
case "String": {
|
|
178
|
+
if (typeof value !== "string") {
|
|
179
|
+
throw new DataMapperError(`Expected a string in column '${columnName}', got ${typeof value}: ${value}`);
|
|
180
|
+
}
|
|
181
|
+
return value;
|
|
182
|
+
}
|
|
183
|
+
case "Int": {
|
|
184
|
+
switch (typeof value) {
|
|
185
|
+
case "number": {
|
|
186
|
+
return Math.trunc(value);
|
|
187
|
+
}
|
|
188
|
+
case "string": {
|
|
189
|
+
const numberValue = Math.trunc(Number(value));
|
|
190
|
+
if (Number.isNaN(numberValue) || !Number.isFinite(numberValue)) {
|
|
191
|
+
throw new DataMapperError(`Expected an integer in column '${columnName}', got string: ${value}`);
|
|
192
|
+
}
|
|
193
|
+
if (!Number.isSafeInteger(numberValue)) {
|
|
194
|
+
throw new DataMapperError(
|
|
195
|
+
`Integer value in column '${columnName}' is too large to represent as a JavaScript number without loss of precision, got: ${value}. Consider using BigInt type.`
|
|
196
|
+
);
|
|
197
|
+
}
|
|
198
|
+
return numberValue;
|
|
199
|
+
}
|
|
200
|
+
default:
|
|
201
|
+
throw new DataMapperError(`Expected an integer in column '${columnName}', got ${typeof value}: ${value}`);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
case "BigInt": {
|
|
205
|
+
if (typeof value !== "number" && typeof value !== "string") {
|
|
206
|
+
throw new DataMapperError(`Expected a bigint in column '${columnName}', got ${typeof value}: ${value}`);
|
|
207
|
+
}
|
|
208
|
+
return { $type: "BigInt", value };
|
|
209
|
+
}
|
|
210
|
+
case "Float": {
|
|
211
|
+
if (typeof value === "number") return value;
|
|
212
|
+
if (typeof value === "string") {
|
|
213
|
+
const parsedValue = Number(value);
|
|
214
|
+
if (Number.isNaN(parsedValue) && !/^[-+]?nan$/.test(value.toLowerCase())) {
|
|
215
|
+
throw new DataMapperError(`Expected a float in column '${columnName}', got string: ${value}`);
|
|
216
|
+
}
|
|
217
|
+
return parsedValue;
|
|
218
|
+
}
|
|
219
|
+
throw new DataMapperError(`Expected a float in column '${columnName}', got ${typeof value}: ${value}`);
|
|
220
|
+
}
|
|
221
|
+
case "Boolean": {
|
|
222
|
+
if (typeof value === "boolean") return value;
|
|
223
|
+
if (typeof value === "number") return value === 1;
|
|
224
|
+
if (typeof value === "string") {
|
|
225
|
+
if (value === "true" || value === "TRUE" || value === "1") {
|
|
226
|
+
return true;
|
|
227
|
+
} else if (value === "false" || value === "FALSE" || value === "0") {
|
|
228
|
+
return false;
|
|
229
|
+
} else {
|
|
230
|
+
throw new DataMapperError(`Expected a boolean in column '${columnName}', got ${typeof value}: ${value}`);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
throw new DataMapperError(`Expected a boolean in column '${columnName}', got ${typeof value}: ${value}`);
|
|
234
|
+
}
|
|
235
|
+
case "Decimal":
|
|
236
|
+
if (typeof value !== "number" && typeof value !== "string" && !import_decimal2.default.isDecimal(value)) {
|
|
237
|
+
throw new DataMapperError(`Expected a decimal in column '${columnName}', got ${typeof value}: ${value}`);
|
|
238
|
+
}
|
|
239
|
+
return { $type: "Decimal", value };
|
|
240
|
+
case "Date": {
|
|
241
|
+
if (typeof value === "string") {
|
|
242
|
+
return { $type: "DateTime", value: ensureTimezoneInIsoString(value) };
|
|
243
|
+
}
|
|
244
|
+
if (typeof value === "number" || value instanceof Date) {
|
|
245
|
+
return { $type: "DateTime", value };
|
|
246
|
+
}
|
|
247
|
+
throw new DataMapperError(`Expected a date in column '${columnName}', got ${typeof value}: ${value}`);
|
|
248
|
+
}
|
|
249
|
+
case "Time": {
|
|
250
|
+
if (typeof value === "string") {
|
|
251
|
+
return { $type: "DateTime", value: `1970-01-01T${ensureTimezoneInIsoString(value)}` };
|
|
252
|
+
}
|
|
253
|
+
throw new DataMapperError(`Expected a time in column '${columnName}', got ${typeof value}: ${value}`);
|
|
254
|
+
}
|
|
255
|
+
case "Array": {
|
|
256
|
+
const values = value;
|
|
257
|
+
return values.map((v, i) => mapValue(v, `${columnName}[${i}]`, resultType.inner, enums));
|
|
258
|
+
}
|
|
259
|
+
case "Object": {
|
|
260
|
+
const jsonValue = typeof value === "string" ? value : safeJsonStringify(value);
|
|
261
|
+
return { $type: "Json", value: jsonValue };
|
|
262
|
+
}
|
|
263
|
+
case "Bytes": {
|
|
264
|
+
if (typeof value === "string" && value.startsWith("\\x")) {
|
|
265
|
+
return { $type: "Bytes", value: Buffer.from(value.slice(2), "hex").toString("base64") };
|
|
266
|
+
}
|
|
267
|
+
if (Array.isArray(value)) {
|
|
268
|
+
return { $type: "Bytes", value: Buffer.from(value).toString("base64") };
|
|
269
|
+
}
|
|
270
|
+
throw new DataMapperError(`Expected a byte array in column '${columnName}', got ${typeof value}: ${value}`);
|
|
271
|
+
}
|
|
272
|
+
case "Enum": {
|
|
273
|
+
const enumDef = enums[resultType.inner];
|
|
274
|
+
if (enumDef === void 0) {
|
|
275
|
+
throw new DataMapperError(`Unknown enum '${resultType.inner}'`);
|
|
276
|
+
}
|
|
277
|
+
const enumValue = enumDef[`${value}`];
|
|
278
|
+
if (enumValue === void 0) {
|
|
279
|
+
throw new DataMapperError(`Unknown enum value '${value}' for enum '${resultType.inner}'`);
|
|
280
|
+
}
|
|
281
|
+
return enumValue;
|
|
282
|
+
}
|
|
283
|
+
default:
|
|
284
|
+
assertNever(resultType, `DataMapper: Unknown result type: ${resultType.type}`);
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
var TIMEZONE_PATTERN = /Z$|(?<!\d{4}-\d{2})[+-]\d{2}(:?\d{2})?$/;
|
|
288
|
+
function ensureTimezoneInIsoString(dt) {
|
|
289
|
+
const results = TIMEZONE_PATTERN.exec(dt);
|
|
290
|
+
if (results === null) {
|
|
291
|
+
return `${dt}Z`;
|
|
292
|
+
} else if (results[0] !== "Z" && results[1] === void 0) {
|
|
293
|
+
return `${dt}:00`;
|
|
294
|
+
} else {
|
|
295
|
+
return dt;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
51
298
|
|
|
52
299
|
// src/tracing.ts
|
|
300
|
+
var import_api = require("@opentelemetry/api");
|
|
53
301
|
var noopTracingHelper = {
|
|
54
302
|
runInChildSpan(_, callback) {
|
|
55
303
|
return callback();
|
|
@@ -67,6 +315,37 @@ function providerToOtelSystem(provider) {
|
|
|
67
315
|
assertNever(provider, `Unknown provider: ${provider}`);
|
|
68
316
|
}
|
|
69
317
|
}
|
|
318
|
+
async function withQuerySpanAndEvent({
|
|
319
|
+
query,
|
|
320
|
+
queryable,
|
|
321
|
+
tracingHelper,
|
|
322
|
+
onQuery,
|
|
323
|
+
execute
|
|
324
|
+
}) {
|
|
325
|
+
return await tracingHelper.runInChildSpan(
|
|
326
|
+
{
|
|
327
|
+
name: "db_query",
|
|
328
|
+
kind: import_api.SpanKind.CLIENT,
|
|
329
|
+
attributes: {
|
|
330
|
+
"db.query.text": query.sql,
|
|
331
|
+
"db.system.name": providerToOtelSystem(queryable.provider)
|
|
332
|
+
}
|
|
333
|
+
},
|
|
334
|
+
async () => {
|
|
335
|
+
const timestamp = /* @__PURE__ */ new Date();
|
|
336
|
+
const startInstant = performance.now();
|
|
337
|
+
const result = await execute();
|
|
338
|
+
const endInstant = performance.now();
|
|
339
|
+
onQuery?.({
|
|
340
|
+
timestamp,
|
|
341
|
+
duration: endInstant - startInstant,
|
|
342
|
+
query: query.sql,
|
|
343
|
+
params: query.args
|
|
344
|
+
});
|
|
345
|
+
return result;
|
|
346
|
+
}
|
|
347
|
+
);
|
|
348
|
+
}
|
|
70
349
|
|
|
71
350
|
// src/UserFacingError.ts
|
|
72
351
|
var import_driver_adapter_utils = require("@prisma/driver-adapter-utils");
|
|
@@ -77,7 +356,7 @@ var UserFacingError = class extends Error {
|
|
|
77
356
|
constructor(message, code, meta) {
|
|
78
357
|
super(message);
|
|
79
358
|
this.code = code;
|
|
80
|
-
this.meta = meta;
|
|
359
|
+
this.meta = meta ?? {};
|
|
81
360
|
}
|
|
82
361
|
toQueryResponseErrorObject() {
|
|
83
362
|
return {
|
|
@@ -100,7 +379,7 @@ function rethrowAsUserFacing(error) {
|
|
|
100
379
|
if (!code || !message) {
|
|
101
380
|
throw error;
|
|
102
381
|
}
|
|
103
|
-
throw new UserFacingError(message, code, error);
|
|
382
|
+
throw new UserFacingError(message, code, { driverAdapterError: error });
|
|
104
383
|
}
|
|
105
384
|
function getErrorCode(err) {
|
|
106
385
|
switch (err.cause.kind) {
|
|
@@ -211,101 +490,6 @@ function renderConstraint(constraint) {
|
|
|
211
490
|
return "(not available)";
|
|
212
491
|
}
|
|
213
492
|
|
|
214
|
-
// src/interpreter/DataMapper.ts
|
|
215
|
-
var import_decimal = __toESM(require("decimal.js"));
|
|
216
|
-
function applyDataMap(data, structure) {
|
|
217
|
-
switch (structure.type) {
|
|
218
|
-
case "Object":
|
|
219
|
-
return mapArrayOrObject(data, structure.fields);
|
|
220
|
-
case "Value":
|
|
221
|
-
return mapValue(data, structure.resultType);
|
|
222
|
-
default:
|
|
223
|
-
assertNever(structure, `Invalid data mapping type: '${structure.type}'`);
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
function mapArrayOrObject(data, fields) {
|
|
227
|
-
if (data === null) return null;
|
|
228
|
-
if (Array.isArray(data)) {
|
|
229
|
-
const rows = data;
|
|
230
|
-
return rows.map((row) => mapObject(row, fields));
|
|
231
|
-
}
|
|
232
|
-
if (typeof data === "object") {
|
|
233
|
-
const row = data;
|
|
234
|
-
return mapObject(row, fields);
|
|
235
|
-
}
|
|
236
|
-
throw new Error(`DataMapper: Expected an array or an object, got: ${typeof data}`);
|
|
237
|
-
}
|
|
238
|
-
function mapObject(data, fields) {
|
|
239
|
-
if (typeof data !== "object") {
|
|
240
|
-
throw new Error(`DataMapper: Expected an object, but got '${typeof data}'`);
|
|
241
|
-
}
|
|
242
|
-
const result = {};
|
|
243
|
-
for (const [name, node] of Object.entries(fields)) {
|
|
244
|
-
switch (node.type) {
|
|
245
|
-
case "Object": {
|
|
246
|
-
if (!node.flattened && !Object.hasOwn(data, name)) {
|
|
247
|
-
throw new Error(
|
|
248
|
-
`DataMapper: Missing data field (Object): '${name}'; node: ${JSON.stringify(node)}; data: ${JSON.stringify(data)}`
|
|
249
|
-
);
|
|
250
|
-
}
|
|
251
|
-
const target = node.flattened ? data : data[name];
|
|
252
|
-
result[name] = mapArrayOrObject(target, node.fields);
|
|
253
|
-
break;
|
|
254
|
-
}
|
|
255
|
-
case "Value":
|
|
256
|
-
{
|
|
257
|
-
const dbName = node.dbName;
|
|
258
|
-
if (Object.hasOwn(data, dbName)) {
|
|
259
|
-
result[name] = mapValue(data[dbName], node.resultType);
|
|
260
|
-
} else {
|
|
261
|
-
throw new Error(
|
|
262
|
-
`DataMapper: Missing data field (Value): '${dbName}'; node: ${JSON.stringify(node)}; data: ${JSON.stringify(data)}`
|
|
263
|
-
);
|
|
264
|
-
}
|
|
265
|
-
}
|
|
266
|
-
break;
|
|
267
|
-
default:
|
|
268
|
-
assertNever(node, `DataMapper: Invalid data mapping node type: '${node.type}'`);
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
return result;
|
|
272
|
-
}
|
|
273
|
-
function mapValue(value, resultType) {
|
|
274
|
-
if (value === null) return null;
|
|
275
|
-
switch (resultType.type) {
|
|
276
|
-
case "Any":
|
|
277
|
-
return value;
|
|
278
|
-
case "String":
|
|
279
|
-
return typeof value === "string" ? value : `${value}`;
|
|
280
|
-
case "Int":
|
|
281
|
-
return typeof value === "number" ? value : parseInt(`${value}`, 10);
|
|
282
|
-
case "BigInt":
|
|
283
|
-
return typeof value === "bigint" ? value : BigInt(`${value}`);
|
|
284
|
-
case "Float":
|
|
285
|
-
return typeof value === "number" ? value : parseFloat(`${value}`);
|
|
286
|
-
case "Boolean":
|
|
287
|
-
return typeof value === "boolean" ? value : value !== "0";
|
|
288
|
-
case "Decimal":
|
|
289
|
-
return typeof value === "number" ? new import_decimal.default(value) : new import_decimal.default(`${value}`);
|
|
290
|
-
case "Date":
|
|
291
|
-
return value instanceof Date ? value : /* @__PURE__ */ new Date(`${value}`);
|
|
292
|
-
case "Array": {
|
|
293
|
-
const values = value;
|
|
294
|
-
return values.map((v) => mapValue(v, resultType.inner));
|
|
295
|
-
}
|
|
296
|
-
case "Object":
|
|
297
|
-
return typeof value === "string" ? value : JSON.stringify(value);
|
|
298
|
-
case "Bytes": {
|
|
299
|
-
if (!Array.isArray(value)) {
|
|
300
|
-
throw new Error(`DataMapper: Bytes data is invalid, got: ${typeof value}`);
|
|
301
|
-
}
|
|
302
|
-
return new Uint8Array(value);
|
|
303
|
-
}
|
|
304
|
-
default:
|
|
305
|
-
assertNever(resultType, `DataMapper: Unknown result type: ${resultType.type}`);
|
|
306
|
-
}
|
|
307
|
-
}
|
|
308
|
-
|
|
309
493
|
// src/interpreter/generators.ts
|
|
310
494
|
var import_cuid = __toESM(require("@bugsnag/cuid"));
|
|
311
495
|
var import_cuid2 = require("@paralleldrive/cuid2");
|
|
@@ -315,7 +499,6 @@ var import_uuid = require("uuid");
|
|
|
315
499
|
var GeneratorRegistry = class {
|
|
316
500
|
#generators = {};
|
|
317
501
|
constructor() {
|
|
318
|
-
this.register("now", new NowGenerator());
|
|
319
502
|
this.register("uuid", new UuidGenerator());
|
|
320
503
|
this.register("cuid", new CuidGenerator());
|
|
321
504
|
this.register("ulid", new UlidGenerator());
|
|
@@ -327,9 +510,11 @@ var GeneratorRegistry = class {
|
|
|
327
510
|
* method being called, meaning that the built-in time-based generators will always return
|
|
328
511
|
* the same value on repeated calls as long as the same snapshot is used.
|
|
329
512
|
*/
|
|
330
|
-
snapshot() {
|
|
513
|
+
snapshot(provider) {
|
|
331
514
|
return Object.create(this.#generators, {
|
|
332
|
-
now: {
|
|
515
|
+
now: {
|
|
516
|
+
value: provider === "mysql" ? new MysqlNowGenerator() : new NowGenerator()
|
|
517
|
+
}
|
|
333
518
|
});
|
|
334
519
|
}
|
|
335
520
|
/**
|
|
@@ -345,6 +530,12 @@ var NowGenerator = class {
|
|
|
345
530
|
return this.#now.toISOString();
|
|
346
531
|
}
|
|
347
532
|
};
|
|
533
|
+
var MysqlNowGenerator = class {
|
|
534
|
+
#now = /* @__PURE__ */ new Date();
|
|
535
|
+
generate() {
|
|
536
|
+
return this.#now.toISOString().replace("T", " ").replace("Z", "");
|
|
537
|
+
}
|
|
538
|
+
};
|
|
348
539
|
var UuidGenerator = class {
|
|
349
540
|
generate(arg) {
|
|
350
541
|
if (arg === 4) {
|
|
@@ -410,6 +601,9 @@ function isPrismaValueGenerator(value) {
|
|
|
410
601
|
function isPrismaValueBytes(value) {
|
|
411
602
|
return typeof value === "object" && value !== null && value["prisma__type"] === "bytes";
|
|
412
603
|
}
|
|
604
|
+
function isPrismaValueBigInt(value) {
|
|
605
|
+
return typeof value === "object" && value !== null && value["prisma__type"] === "bigint";
|
|
606
|
+
}
|
|
413
607
|
|
|
414
608
|
// src/interpreter/renderQuery.ts
|
|
415
609
|
function renderQuery(dbQuery, scope, generators) {
|
|
@@ -452,9 +646,10 @@ function evaluateParam(param, scope, generators) {
|
|
|
452
646
|
}
|
|
453
647
|
if (Array.isArray(value)) {
|
|
454
648
|
value = value.map((el) => evaluateParam(el, scope, generators));
|
|
455
|
-
}
|
|
456
|
-
if (isPrismaValueBytes(value)) {
|
|
649
|
+
} else if (isPrismaValueBytes(value)) {
|
|
457
650
|
value = Buffer.from(value.prisma__value, "base64");
|
|
651
|
+
} else if (isPrismaValueBigInt(value)) {
|
|
652
|
+
value = BigInt(value.prisma__value);
|
|
458
653
|
}
|
|
459
654
|
return value;
|
|
460
655
|
}
|
|
@@ -548,6 +743,7 @@ function doesRequireEvaluation(param) {
|
|
|
548
743
|
}
|
|
549
744
|
|
|
550
745
|
// src/interpreter/serializeSql.ts
|
|
746
|
+
var import_driver_adapter_utils2 = require("@prisma/driver-adapter-utils");
|
|
551
747
|
function serializeSql(resultSet) {
|
|
552
748
|
return resultSet.rows.map(
|
|
553
749
|
(row) => row.reduce((acc, value, index) => {
|
|
@@ -568,6 +764,100 @@ function serializeSql(resultSet) {
|
|
|
568
764
|
}, {})
|
|
569
765
|
);
|
|
570
766
|
}
|
|
767
|
+
function serializeRawSql(resultSet) {
|
|
768
|
+
const types = resultSet.columnTypes.map((type) => serializeColumnType(type));
|
|
769
|
+
const mappers = types.map((type) => {
|
|
770
|
+
switch (type) {
|
|
771
|
+
case "int":
|
|
772
|
+
return (value) => value === null ? null : typeof value === "number" ? value : parseInt(`${value}`, 10);
|
|
773
|
+
case "bigint":
|
|
774
|
+
return (value) => value === null ? null : typeof value === "bigint" ? value : BigInt(`${value}`);
|
|
775
|
+
case "json":
|
|
776
|
+
return (value) => typeof value === "string" ? JSON.parse(value) : value;
|
|
777
|
+
case "bool":
|
|
778
|
+
return (value) => typeof value === "string" ? value === "true" || value === "1" : typeof value === "number" ? value === 1 : value;
|
|
779
|
+
default:
|
|
780
|
+
return (value) => value;
|
|
781
|
+
}
|
|
782
|
+
});
|
|
783
|
+
return {
|
|
784
|
+
columns: resultSet.columnNames,
|
|
785
|
+
types: resultSet.columnTypes.map((type) => serializeColumnType(type)),
|
|
786
|
+
rows: resultSet.rows.map((row) => row.map((value, index) => mappers[index](value)))
|
|
787
|
+
};
|
|
788
|
+
}
|
|
789
|
+
function serializeColumnType(columnType) {
|
|
790
|
+
switch (columnType) {
|
|
791
|
+
case import_driver_adapter_utils2.ColumnTypeEnum.Int32:
|
|
792
|
+
return "int";
|
|
793
|
+
case import_driver_adapter_utils2.ColumnTypeEnum.Int64:
|
|
794
|
+
return "bigint";
|
|
795
|
+
case import_driver_adapter_utils2.ColumnTypeEnum.Float:
|
|
796
|
+
return "float";
|
|
797
|
+
case import_driver_adapter_utils2.ColumnTypeEnum.Double:
|
|
798
|
+
return "double";
|
|
799
|
+
case import_driver_adapter_utils2.ColumnTypeEnum.Text:
|
|
800
|
+
return "string";
|
|
801
|
+
case import_driver_adapter_utils2.ColumnTypeEnum.Enum:
|
|
802
|
+
return "enum";
|
|
803
|
+
case import_driver_adapter_utils2.ColumnTypeEnum.Bytes:
|
|
804
|
+
return "bytes";
|
|
805
|
+
case import_driver_adapter_utils2.ColumnTypeEnum.Boolean:
|
|
806
|
+
return "bool";
|
|
807
|
+
case import_driver_adapter_utils2.ColumnTypeEnum.Character:
|
|
808
|
+
return "char";
|
|
809
|
+
case import_driver_adapter_utils2.ColumnTypeEnum.Numeric:
|
|
810
|
+
return "decimal";
|
|
811
|
+
case import_driver_adapter_utils2.ColumnTypeEnum.Json:
|
|
812
|
+
return "json";
|
|
813
|
+
case import_driver_adapter_utils2.ColumnTypeEnum.Uuid:
|
|
814
|
+
return "uuid";
|
|
815
|
+
case import_driver_adapter_utils2.ColumnTypeEnum.DateTime:
|
|
816
|
+
return "datetime";
|
|
817
|
+
case import_driver_adapter_utils2.ColumnTypeEnum.Date:
|
|
818
|
+
return "date";
|
|
819
|
+
case import_driver_adapter_utils2.ColumnTypeEnum.Time:
|
|
820
|
+
return "time";
|
|
821
|
+
case import_driver_adapter_utils2.ColumnTypeEnum.Int32Array:
|
|
822
|
+
return "int-array";
|
|
823
|
+
case import_driver_adapter_utils2.ColumnTypeEnum.Int64Array:
|
|
824
|
+
return "bigint-array";
|
|
825
|
+
case import_driver_adapter_utils2.ColumnTypeEnum.FloatArray:
|
|
826
|
+
return "float-array";
|
|
827
|
+
case import_driver_adapter_utils2.ColumnTypeEnum.DoubleArray:
|
|
828
|
+
return "double-array";
|
|
829
|
+
case import_driver_adapter_utils2.ColumnTypeEnum.TextArray:
|
|
830
|
+
return "string-array";
|
|
831
|
+
case import_driver_adapter_utils2.ColumnTypeEnum.EnumArray:
|
|
832
|
+
return "string-array";
|
|
833
|
+
case import_driver_adapter_utils2.ColumnTypeEnum.BytesArray:
|
|
834
|
+
return "bytes-array";
|
|
835
|
+
case import_driver_adapter_utils2.ColumnTypeEnum.BooleanArray:
|
|
836
|
+
return "bool-array";
|
|
837
|
+
case import_driver_adapter_utils2.ColumnTypeEnum.CharacterArray:
|
|
838
|
+
return "char-array";
|
|
839
|
+
case import_driver_adapter_utils2.ColumnTypeEnum.NumericArray:
|
|
840
|
+
return "decimal-array";
|
|
841
|
+
case import_driver_adapter_utils2.ColumnTypeEnum.JsonArray:
|
|
842
|
+
return "json-array";
|
|
843
|
+
case import_driver_adapter_utils2.ColumnTypeEnum.UuidArray:
|
|
844
|
+
return "uuid-array";
|
|
845
|
+
case import_driver_adapter_utils2.ColumnTypeEnum.DateTimeArray:
|
|
846
|
+
return "datetime-array";
|
|
847
|
+
case import_driver_adapter_utils2.ColumnTypeEnum.DateArray:
|
|
848
|
+
return "date-array";
|
|
849
|
+
case import_driver_adapter_utils2.ColumnTypeEnum.TimeArray:
|
|
850
|
+
return "time-array";
|
|
851
|
+
case import_driver_adapter_utils2.ColumnTypeEnum.UnknownNumber:
|
|
852
|
+
return "unknown";
|
|
853
|
+
/// The following PlanetScale type IDs are mapped into Set:
|
|
854
|
+
/// - SET (SET) -> e.g. `"foo,bar"` (String-encoded, comma-separated)
|
|
855
|
+
case import_driver_adapter_utils2.ColumnTypeEnum.Set:
|
|
856
|
+
return "string";
|
|
857
|
+
default:
|
|
858
|
+
assertNever(columnType, `Unexpected column type: ${columnType}`);
|
|
859
|
+
}
|
|
860
|
+
}
|
|
571
861
|
|
|
572
862
|
// src/interpreter/validation.ts
|
|
573
863
|
function performValidation(data, rules, error) {
|
|
@@ -595,6 +885,8 @@ function doesSatisfyRule(data, rule) {
|
|
|
595
885
|
return rule.args !== 0;
|
|
596
886
|
}
|
|
597
887
|
return rule.args !== 1;
|
|
888
|
+
case "affectedRowCountEq":
|
|
889
|
+
return data === rule.args;
|
|
598
890
|
case "never":
|
|
599
891
|
return false;
|
|
600
892
|
default:
|
|
@@ -612,7 +904,9 @@ function renderMessage(data, error) {
|
|
|
612
904
|
return `An operation failed because it depends on one or more records that were required but not found. No '${error.context.model}' record${hint} was found for ${error.context.operation} on ${error.context.relationType} relation '${error.context.relation}'.`;
|
|
613
905
|
}
|
|
614
906
|
case "INCOMPLETE_CONNECT_INPUT":
|
|
615
|
-
return `An operation failed because it depends on one or more records that were required but not found. Expected ${error.context.expectedRows} records to be connected, found only ${Array.isArray(data) ? data.length :
|
|
907
|
+
return `An operation failed because it depends on one or more records that were required but not found. Expected ${error.context.expectedRows} records to be connected, found only ${Array.isArray(data) ? data.length : data}.`;
|
|
908
|
+
case "INCOMPLETE_CONNECT_OUTPUT":
|
|
909
|
+
return `The required connected records were not found. Expected ${error.context.expectedRows} records to be connected after connect operation on ${error.context.relationType} relation '${error.context.relation}', found ${Array.isArray(data) ? data.length : data}.`;
|
|
616
910
|
case "RECORDS_NOT_CONNECTED":
|
|
617
911
|
return `The records for relation \`${error.context.relation}\` between the \`${error.context.parent}\` and \`${error.context.child}\` models are not connected.`;
|
|
618
912
|
default:
|
|
@@ -625,6 +919,8 @@ function getErrorCode2(error) {
|
|
|
625
919
|
return "P2014";
|
|
626
920
|
case "RECORDS_NOT_CONNECTED":
|
|
627
921
|
return "P2017";
|
|
922
|
+
case "INCOMPLETE_CONNECT_OUTPUT":
|
|
923
|
+
return "P2018";
|
|
628
924
|
case "MISSING_RECORD":
|
|
629
925
|
case "MISSING_RELATED_RECORD":
|
|
630
926
|
case "INCOMPLETE_CONNECT_INPUT":
|
|
@@ -642,12 +938,21 @@ var QueryInterpreter = class _QueryInterpreter {
|
|
|
642
938
|
#generators = new GeneratorRegistry();
|
|
643
939
|
#tracingHelper;
|
|
644
940
|
#serializer;
|
|
645
|
-
|
|
941
|
+
#rawSerializer;
|
|
942
|
+
constructor({
|
|
943
|
+
transactionManager,
|
|
944
|
+
placeholderValues,
|
|
945
|
+
onQuery,
|
|
946
|
+
tracingHelper,
|
|
947
|
+
serializer,
|
|
948
|
+
rawSerializer
|
|
949
|
+
}) {
|
|
646
950
|
this.#transactionManager = transactionManager;
|
|
647
951
|
this.#placeholderValues = placeholderValues;
|
|
648
952
|
this.#onQuery = onQuery;
|
|
649
953
|
this.#tracingHelper = tracingHelper;
|
|
650
954
|
this.#serializer = serializer;
|
|
955
|
+
this.#rawSerializer = rawSerializer ?? serializer;
|
|
651
956
|
}
|
|
652
957
|
static forSql(options) {
|
|
653
958
|
return new _QueryInterpreter({
|
|
@@ -655,27 +960,36 @@ var QueryInterpreter = class _QueryInterpreter {
|
|
|
655
960
|
placeholderValues: options.placeholderValues,
|
|
656
961
|
onQuery: options.onQuery,
|
|
657
962
|
tracingHelper: options.tracingHelper,
|
|
658
|
-
serializer: serializeSql
|
|
963
|
+
serializer: serializeSql,
|
|
964
|
+
rawSerializer: serializeRawSql
|
|
659
965
|
});
|
|
660
966
|
}
|
|
661
967
|
async run(queryPlan, queryable) {
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
968
|
+
const { value } = await this.interpretNode(
|
|
969
|
+
queryPlan,
|
|
970
|
+
queryable,
|
|
971
|
+
this.#placeholderValues,
|
|
972
|
+
this.#generators.snapshot(queryable.provider)
|
|
973
|
+
).catch((e) => rethrowAsUserFacing(e));
|
|
974
|
+
return value;
|
|
665
975
|
}
|
|
666
976
|
async interpretNode(node, queryable, scope, generators) {
|
|
667
977
|
switch (node.type) {
|
|
668
978
|
case "seq": {
|
|
669
|
-
|
|
670
|
-
|
|
979
|
+
let result;
|
|
980
|
+
for (const arg of node.args) {
|
|
981
|
+
result = await this.interpretNode(arg, queryable, scope, generators);
|
|
982
|
+
}
|
|
983
|
+
return result ?? { value: void 0 };
|
|
671
984
|
}
|
|
672
985
|
case "get": {
|
|
673
|
-
return scope[node.args.name];
|
|
986
|
+
return { value: scope[node.args.name] };
|
|
674
987
|
}
|
|
675
988
|
case "let": {
|
|
676
989
|
const nestedScope = Object.create(scope);
|
|
677
990
|
for (const binding of node.args.bindings) {
|
|
678
|
-
|
|
991
|
+
const { value } = await this.interpretNode(binding.expr, queryable, nestedScope, generators);
|
|
992
|
+
nestedScope[binding.name] = value;
|
|
679
993
|
}
|
|
680
994
|
return this.interpretNode(node.args.expr, queryable, nestedScope, generators);
|
|
681
995
|
}
|
|
@@ -683,71 +997,87 @@ var QueryInterpreter = class _QueryInterpreter {
|
|
|
683
997
|
for (const name of node.args.names) {
|
|
684
998
|
const value = scope[name];
|
|
685
999
|
if (!isEmpty(value)) {
|
|
686
|
-
return value;
|
|
1000
|
+
return { value };
|
|
687
1001
|
}
|
|
688
1002
|
}
|
|
689
|
-
return [];
|
|
1003
|
+
return { value: [] };
|
|
690
1004
|
}
|
|
691
1005
|
case "concat": {
|
|
692
|
-
const parts = await Promise.all(
|
|
693
|
-
|
|
1006
|
+
const parts = await Promise.all(
|
|
1007
|
+
node.args.map((arg) => this.interpretNode(arg, queryable, scope, generators).then((res) => res.value))
|
|
1008
|
+
);
|
|
1009
|
+
return {
|
|
1010
|
+
value: parts.length > 0 ? parts.reduce((acc, part) => acc.concat(asList(part)), []) : []
|
|
1011
|
+
};
|
|
694
1012
|
}
|
|
695
1013
|
case "sum": {
|
|
696
|
-
const parts = await Promise.all(
|
|
697
|
-
|
|
1014
|
+
const parts = await Promise.all(
|
|
1015
|
+
node.args.map((arg) => this.interpretNode(arg, queryable, scope, generators).then((res) => res.value))
|
|
1016
|
+
);
|
|
1017
|
+
return {
|
|
1018
|
+
value: parts.length > 0 ? parts.reduce((acc, part) => asNumber(acc) + asNumber(part)) : 0
|
|
1019
|
+
};
|
|
698
1020
|
}
|
|
699
1021
|
case "execute": {
|
|
700
1022
|
const query = renderQuery(node.args, scope, generators);
|
|
701
|
-
return this.#
|
|
702
|
-
return await queryable.executeRaw(query);
|
|
1023
|
+
return this.#withQuerySpanAndEvent(query, queryable, async () => {
|
|
1024
|
+
return { value: await queryable.executeRaw(query) };
|
|
703
1025
|
});
|
|
704
1026
|
}
|
|
705
1027
|
case "query": {
|
|
706
1028
|
const query = renderQuery(node.args, scope, generators);
|
|
707
|
-
return this.#
|
|
708
|
-
|
|
1029
|
+
return this.#withQuerySpanAndEvent(query, queryable, async () => {
|
|
1030
|
+
const result = await queryable.queryRaw(query);
|
|
1031
|
+
if (node.args.type === "rawSql") {
|
|
1032
|
+
return { value: this.#rawSerializer(result), lastInsertId: result.lastInsertId };
|
|
1033
|
+
} else {
|
|
1034
|
+
return { value: this.#serializer(result), lastInsertId: result.lastInsertId };
|
|
1035
|
+
}
|
|
709
1036
|
});
|
|
710
1037
|
}
|
|
711
1038
|
case "reverse": {
|
|
712
|
-
const value = await this.interpretNode(node.args, queryable, scope, generators);
|
|
713
|
-
return Array.isArray(value) ? value.reverse() : value;
|
|
1039
|
+
const { value, lastInsertId } = await this.interpretNode(node.args, queryable, scope, generators);
|
|
1040
|
+
return { value: Array.isArray(value) ? value.reverse() : value, lastInsertId };
|
|
714
1041
|
}
|
|
715
1042
|
case "unique": {
|
|
716
|
-
const value = await this.interpretNode(node.args, queryable, scope, generators);
|
|
1043
|
+
const { value, lastInsertId } = await this.interpretNode(node.args, queryable, scope, generators);
|
|
717
1044
|
if (!Array.isArray(value)) {
|
|
718
|
-
return value;
|
|
1045
|
+
return { value, lastInsertId };
|
|
719
1046
|
}
|
|
720
1047
|
if (value.length > 1) {
|
|
721
1048
|
throw new Error(`Expected zero or one element, got ${value.length}`);
|
|
722
1049
|
}
|
|
723
|
-
return value[0] ?? null;
|
|
1050
|
+
return { value: value[0] ?? null, lastInsertId };
|
|
724
1051
|
}
|
|
725
1052
|
case "required": {
|
|
726
|
-
const value = await this.interpretNode(node.args, queryable, scope, generators);
|
|
1053
|
+
const { value, lastInsertId } = await this.interpretNode(node.args, queryable, scope, generators);
|
|
727
1054
|
if (isEmpty(value)) {
|
|
728
1055
|
throw new Error("Required value is empty");
|
|
729
1056
|
}
|
|
730
|
-
return value;
|
|
1057
|
+
return { value, lastInsertId };
|
|
731
1058
|
}
|
|
732
1059
|
case "mapField": {
|
|
733
|
-
const value = await this.interpretNode(node.args.records, queryable, scope, generators);
|
|
734
|
-
return mapField(value, node.args.field);
|
|
1060
|
+
const { value, lastInsertId } = await this.interpretNode(node.args.records, queryable, scope, generators);
|
|
1061
|
+
return { value: mapField(value, node.args.field), lastInsertId };
|
|
735
1062
|
}
|
|
736
1063
|
case "join": {
|
|
737
|
-
const parent = await this.interpretNode(node.args.parent, queryable, scope, generators);
|
|
1064
|
+
const { value: parent, lastInsertId } = await this.interpretNode(node.args.parent, queryable, scope, generators);
|
|
1065
|
+
if (parent === null) {
|
|
1066
|
+
return { value: null, lastInsertId };
|
|
1067
|
+
}
|
|
738
1068
|
const children = await Promise.all(
|
|
739
1069
|
node.args.children.map(async (joinExpr) => ({
|
|
740
1070
|
joinExpr,
|
|
741
|
-
childRecords: await this.interpretNode(joinExpr.child, queryable, scope, generators)
|
|
1071
|
+
childRecords: (await this.interpretNode(joinExpr.child, queryable, scope, generators)).value
|
|
742
1072
|
}))
|
|
743
1073
|
);
|
|
744
1074
|
if (Array.isArray(parent)) {
|
|
745
1075
|
for (const record of parent) {
|
|
746
1076
|
attachChildrenToParent(asRecord(record), children);
|
|
747
1077
|
}
|
|
748
|
-
return parent;
|
|
1078
|
+
return { value: parent, lastInsertId };
|
|
749
1079
|
}
|
|
750
|
-
return attachChildrenToParent(asRecord(parent), children);
|
|
1080
|
+
return { value: attachChildrenToParent(asRecord(parent), children), lastInsertId };
|
|
751
1081
|
}
|
|
752
1082
|
case "transaction": {
|
|
753
1083
|
if (!this.#transactionManager.enabled) {
|
|
@@ -766,16 +1096,16 @@ var QueryInterpreter = class _QueryInterpreter {
|
|
|
766
1096
|
}
|
|
767
1097
|
}
|
|
768
1098
|
case "dataMap": {
|
|
769
|
-
const
|
|
770
|
-
return applyDataMap(
|
|
1099
|
+
const { value, lastInsertId } = await this.interpretNode(node.args.expr, queryable, scope, generators);
|
|
1100
|
+
return { value: applyDataMap(value, node.args.structure, node.args.enums), lastInsertId };
|
|
771
1101
|
}
|
|
772
1102
|
case "validate": {
|
|
773
|
-
const
|
|
774
|
-
performValidation(
|
|
775
|
-
return
|
|
1103
|
+
const { value, lastInsertId } = await this.interpretNode(node.args.expr, queryable, scope, generators);
|
|
1104
|
+
performValidation(value, node.args.rules, node.args);
|
|
1105
|
+
return { value, lastInsertId };
|
|
776
1106
|
}
|
|
777
1107
|
case "if": {
|
|
778
|
-
const value = await this.interpretNode(node.args.value, queryable, scope, generators);
|
|
1108
|
+
const { value } = await this.interpretNode(node.args.value, queryable, scope, generators);
|
|
779
1109
|
if (doesSatisfyRule(value, node.args.rule)) {
|
|
780
1110
|
return await this.interpretNode(node.args.then, queryable, scope, generators);
|
|
781
1111
|
} else {
|
|
@@ -783,42 +1113,73 @@ var QueryInterpreter = class _QueryInterpreter {
|
|
|
783
1113
|
}
|
|
784
1114
|
}
|
|
785
1115
|
case "unit": {
|
|
786
|
-
return void 0;
|
|
1116
|
+
return { value: void 0 };
|
|
787
1117
|
}
|
|
788
1118
|
case "diff": {
|
|
789
|
-
const from = await this.interpretNode(node.args.from, queryable, scope, generators);
|
|
790
|
-
const to = await this.interpretNode(node.args.to, queryable, scope, generators);
|
|
1119
|
+
const { value: from } = await this.interpretNode(node.args.from, queryable, scope, generators);
|
|
1120
|
+
const { value: to } = await this.interpretNode(node.args.to, queryable, scope, generators);
|
|
791
1121
|
const toSet = new Set(asList(to));
|
|
792
|
-
return asList(from).filter((item) => !toSet.has(item));
|
|
1122
|
+
return { value: asList(from).filter((item) => !toSet.has(item)) };
|
|
1123
|
+
}
|
|
1124
|
+
case "distinctBy": {
|
|
1125
|
+
const { value, lastInsertId } = await this.interpretNode(node.args.expr, queryable, scope, generators);
|
|
1126
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1127
|
+
const result = [];
|
|
1128
|
+
for (const item of asList(value)) {
|
|
1129
|
+
const key = getRecordKey(item, node.args.fields);
|
|
1130
|
+
if (!seen.has(key)) {
|
|
1131
|
+
seen.add(key);
|
|
1132
|
+
result.push(item);
|
|
1133
|
+
}
|
|
1134
|
+
}
|
|
1135
|
+
return { value: result, lastInsertId };
|
|
1136
|
+
}
|
|
1137
|
+
case "paginate": {
|
|
1138
|
+
const { value, lastInsertId } = await this.interpretNode(node.args.expr, queryable, scope, generators);
|
|
1139
|
+
const list = asList(value);
|
|
1140
|
+
const linkingFields = node.args.pagination.linkingFields;
|
|
1141
|
+
if (linkingFields !== null) {
|
|
1142
|
+
const groupedByParent = /* @__PURE__ */ new Map();
|
|
1143
|
+
for (const item of list) {
|
|
1144
|
+
const parentKey = getRecordKey(item, linkingFields);
|
|
1145
|
+
if (!groupedByParent.has(parentKey)) {
|
|
1146
|
+
groupedByParent.set(parentKey, []);
|
|
1147
|
+
}
|
|
1148
|
+
groupedByParent.get(parentKey).push(item);
|
|
1149
|
+
}
|
|
1150
|
+
const groupList = Array.from(groupedByParent.entries());
|
|
1151
|
+
groupList.sort(([aId], [bId]) => aId < bId ? -1 : aId > bId ? 1 : 0);
|
|
1152
|
+
return {
|
|
1153
|
+
value: groupList.flatMap(([, elems]) => paginate(elems, node.args.pagination)),
|
|
1154
|
+
lastInsertId
|
|
1155
|
+
};
|
|
1156
|
+
}
|
|
1157
|
+
return { value: paginate(list, node.args.pagination), lastInsertId };
|
|
1158
|
+
}
|
|
1159
|
+
case "extendRecord": {
|
|
1160
|
+
const { value, lastInsertId } = await this.interpretNode(node.args.expr, queryable, scope, generators);
|
|
1161
|
+
const record = value === null ? {} : asRecord(value);
|
|
1162
|
+
for (const [key, entry] of Object.entries(node.args.values)) {
|
|
1163
|
+
if (entry.type === "lastInsertId") {
|
|
1164
|
+
record[key] = lastInsertId;
|
|
1165
|
+
} else {
|
|
1166
|
+
record[key] = evaluateParam(entry.value, scope, generators);
|
|
1167
|
+
}
|
|
1168
|
+
}
|
|
1169
|
+
return { value: record, lastInsertId };
|
|
793
1170
|
}
|
|
794
1171
|
default:
|
|
795
1172
|
assertNever(node, `Unexpected node type: ${node.type}`);
|
|
796
1173
|
}
|
|
797
1174
|
}
|
|
798
|
-
#
|
|
799
|
-
return
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
}
|
|
807
|
-
},
|
|
808
|
-
async () => {
|
|
809
|
-
const timestamp = /* @__PURE__ */ new Date();
|
|
810
|
-
const startInstant = performance.now();
|
|
811
|
-
const result = await execute();
|
|
812
|
-
const endInstant = performance.now();
|
|
813
|
-
this.#onQuery?.({
|
|
814
|
-
timestamp,
|
|
815
|
-
duration: endInstant - startInstant,
|
|
816
|
-
query: query.sql,
|
|
817
|
-
params: query.args
|
|
818
|
-
});
|
|
819
|
-
return result;
|
|
820
|
-
}
|
|
821
|
-
);
|
|
1175
|
+
#withQuerySpanAndEvent(query, queryable, execute) {
|
|
1176
|
+
return withQuerySpanAndEvent({
|
|
1177
|
+
query,
|
|
1178
|
+
queryable,
|
|
1179
|
+
execute,
|
|
1180
|
+
tracingHelper: this.#tracingHelper,
|
|
1181
|
+
onQuery: this.#onQuery
|
|
1182
|
+
});
|
|
822
1183
|
}
|
|
823
1184
|
};
|
|
824
1185
|
function isEmpty(value) {
|
|
@@ -862,7 +1223,12 @@ function attachChildrenToParent(parentRecord, children) {
|
|
|
862
1223
|
}
|
|
863
1224
|
function filterChildRecords(records, parentRecord, joinExpr) {
|
|
864
1225
|
if (Array.isArray(records)) {
|
|
865
|
-
|
|
1226
|
+
const filtered = records.filter((record) => childRecordMatchesParent(asRecord(record), parentRecord, joinExpr));
|
|
1227
|
+
if (joinExpr.isRelationUnique) {
|
|
1228
|
+
return filtered.length > 0 ? filtered[0] : null;
|
|
1229
|
+
} else {
|
|
1230
|
+
return filtered;
|
|
1231
|
+
}
|
|
866
1232
|
} else if (records === null) {
|
|
867
1233
|
return null;
|
|
868
1234
|
} else {
|
|
@@ -878,6 +1244,18 @@ function childRecordMatchesParent(childRecord, parentRecord, joinExpr) {
|
|
|
878
1244
|
}
|
|
879
1245
|
return true;
|
|
880
1246
|
}
|
|
1247
|
+
function paginate(list, { cursor, skip, take }) {
|
|
1248
|
+
const cursorIndex = cursor !== null ? list.findIndex((item) => doKeysMatch(item, cursor)) : 0;
|
|
1249
|
+
if (cursorIndex === -1) {
|
|
1250
|
+
return [];
|
|
1251
|
+
}
|
|
1252
|
+
const start = cursorIndex + (skip ?? 0);
|
|
1253
|
+
const end = take !== null ? start + take : list.length;
|
|
1254
|
+
return list.slice(start, end);
|
|
1255
|
+
}
|
|
1256
|
+
function getRecordKey(record, fields) {
|
|
1257
|
+
return JSON.stringify(fields.map((field) => record[field]));
|
|
1258
|
+
}
|
|
881
1259
|
|
|
882
1260
|
// src/transactionManager/TransactionManager.ts
|
|
883
1261
|
var import_debug = require("@prisma/debug");
|
|
@@ -892,12 +1270,11 @@ async function randomUUID() {
|
|
|
892
1270
|
}
|
|
893
1271
|
|
|
894
1272
|
// src/transactionManager/TransactionManagerErrors.ts
|
|
895
|
-
var TransactionManagerError = class extends
|
|
1273
|
+
var TransactionManagerError = class extends UserFacingError {
|
|
1274
|
+
name = "TransactionManagerError";
|
|
896
1275
|
constructor(message, meta) {
|
|
897
|
-
super("Transaction API error: " + message);
|
|
898
|
-
this.meta = meta;
|
|
1276
|
+
super("Transaction API error: " + message, "P2028", meta);
|
|
899
1277
|
}
|
|
900
|
-
code = "P2028";
|
|
901
1278
|
};
|
|
902
1279
|
var TransactionNotFoundError = class extends TransactionManagerError {
|
|
903
1280
|
constructor() {
|
|
@@ -908,12 +1285,12 @@ var TransactionNotFoundError = class extends TransactionManagerError {
|
|
|
908
1285
|
};
|
|
909
1286
|
var TransactionClosedError = class extends TransactionManagerError {
|
|
910
1287
|
constructor(operation) {
|
|
911
|
-
super(`Transaction already closed: A ${operation} cannot be executed on a committed transaction
|
|
1288
|
+
super(`Transaction already closed: A ${operation} cannot be executed on a committed transaction.`);
|
|
912
1289
|
}
|
|
913
1290
|
};
|
|
914
1291
|
var TransactionRolledBackError = class extends TransactionManagerError {
|
|
915
1292
|
constructor(operation) {
|
|
916
|
-
super(`Transaction already closed: A ${operation} cannot be executed on a transaction that was rolled back
|
|
1293
|
+
super(`Transaction already closed: A ${operation} cannot be executed on a transaction that was rolled back.`);
|
|
917
1294
|
}
|
|
918
1295
|
};
|
|
919
1296
|
var TransactionStartTimeoutError = class extends TransactionManagerError {
|
|
@@ -945,6 +1322,16 @@ var MAX_CLOSED_TRANSACTIONS = 100;
|
|
|
945
1322
|
var debug = (0, import_debug.Debug)("prisma:client:transactionManager");
|
|
946
1323
|
var COMMIT_QUERY = () => ({ sql: "COMMIT", args: [], argTypes: [] });
|
|
947
1324
|
var ROLLBACK_QUERY = () => ({ sql: "ROLLBACK", args: [], argTypes: [] });
|
|
1325
|
+
var PHANTOM_COMMIT_QUERY = () => ({
|
|
1326
|
+
sql: '-- Implicit "COMMIT" query via underlying driver',
|
|
1327
|
+
args: [],
|
|
1328
|
+
argTypes: []
|
|
1329
|
+
});
|
|
1330
|
+
var PHANTOM_ROLLBACK_QUERY = () => ({
|
|
1331
|
+
sql: '-- Implicit "ROLLBACK" query via underlying driver',
|
|
1332
|
+
args: [],
|
|
1333
|
+
argTypes: []
|
|
1334
|
+
});
|
|
948
1335
|
var TransactionManager = class {
|
|
949
1336
|
// The map of active transactions.
|
|
950
1337
|
transactions = /* @__PURE__ */ new Map();
|
|
@@ -954,14 +1341,17 @@ var TransactionManager = class {
|
|
|
954
1341
|
driverAdapter;
|
|
955
1342
|
transactionOptions;
|
|
956
1343
|
tracingHelper;
|
|
1344
|
+
#onQuery;
|
|
957
1345
|
constructor({
|
|
958
1346
|
driverAdapter,
|
|
959
1347
|
transactionOptions,
|
|
960
|
-
tracingHelper
|
|
1348
|
+
tracingHelper,
|
|
1349
|
+
onQuery
|
|
961
1350
|
}) {
|
|
962
1351
|
this.driverAdapter = driverAdapter;
|
|
963
1352
|
this.transactionOptions = transactionOptions;
|
|
964
1353
|
this.tracingHelper = tracingHelper;
|
|
1354
|
+
this.#onQuery = onQuery;
|
|
965
1355
|
}
|
|
966
1356
|
async startTransaction(options) {
|
|
967
1357
|
return await this.tracingHelper.runInChildSpan("start_transaction", () => this.#startTransactionImpl(options));
|
|
@@ -1065,14 +1455,20 @@ var TransactionManager = class {
|
|
|
1065
1455
|
debug("Closing transaction.", { transactionId: tx.id, status });
|
|
1066
1456
|
tx.status = status;
|
|
1067
1457
|
if (tx.transaction && status === "committed") {
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1458
|
+
if (tx.transaction.options.usePhantomQuery) {
|
|
1459
|
+
await this.#withQuerySpanAndEvent(PHANTOM_COMMIT_QUERY(), tx.transaction, () => tx.transaction.commit());
|
|
1460
|
+
} else {
|
|
1461
|
+
await tx.transaction.commit();
|
|
1462
|
+
const query = COMMIT_QUERY();
|
|
1463
|
+
await this.#withQuerySpanAndEvent(query, tx.transaction, () => tx.transaction.executeRaw(query));
|
|
1071
1464
|
}
|
|
1072
1465
|
} else if (tx.transaction) {
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1466
|
+
if (tx.transaction.options.usePhantomQuery) {
|
|
1467
|
+
await this.#withQuerySpanAndEvent(PHANTOM_ROLLBACK_QUERY(), tx.transaction, () => tx.transaction.rollback());
|
|
1468
|
+
} else {
|
|
1469
|
+
await tx.transaction.rollback();
|
|
1470
|
+
const query = ROLLBACK_QUERY();
|
|
1471
|
+
await this.#withQuerySpanAndEvent(query, tx.transaction, () => tx.transaction.executeRaw(query));
|
|
1076
1472
|
}
|
|
1077
1473
|
}
|
|
1078
1474
|
clearTimeout(tx.timer);
|
|
@@ -1093,15 +1489,29 @@ var TransactionManager = class {
|
|
|
1093
1489
|
maxWait: options.maxWait
|
|
1094
1490
|
};
|
|
1095
1491
|
}
|
|
1492
|
+
#withQuerySpanAndEvent(query, queryable, execute) {
|
|
1493
|
+
return withQuerySpanAndEvent({
|
|
1494
|
+
query,
|
|
1495
|
+
queryable,
|
|
1496
|
+
execute,
|
|
1497
|
+
tracingHelper: this.tracingHelper,
|
|
1498
|
+
onQuery: this.#onQuery
|
|
1499
|
+
});
|
|
1500
|
+
}
|
|
1096
1501
|
};
|
|
1097
1502
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1098
1503
|
0 && (module.exports = {
|
|
1504
|
+
DataMapperError,
|
|
1099
1505
|
QueryInterpreter,
|
|
1100
1506
|
TransactionManager,
|
|
1101
1507
|
TransactionManagerError,
|
|
1102
1508
|
UserFacingError,
|
|
1509
|
+
doKeysMatch,
|
|
1510
|
+
isDeepStrictEqual,
|
|
1511
|
+
isPrismaValueBigInt,
|
|
1103
1512
|
isPrismaValueBytes,
|
|
1104
1513
|
isPrismaValueGenerator,
|
|
1105
1514
|
isPrismaValuePlaceholder,
|
|
1106
|
-
noopTracingHelper
|
|
1515
|
+
noopTracingHelper,
|
|
1516
|
+
safeJsonStringify
|
|
1107
1517
|
});
|