@prisma/client-engine-runtime 6.9.0-dev.4 → 6.9.0-dev.41
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 +50 -1
- package/dist/UserFacingError.d.ts +3 -3
- package/dist/index.d.mts +88 -13
- package/dist/index.d.ts +88 -13
- package/dist/index.js +586 -187
- package/dist/index.mjs +580 -186
- package/dist/interpreter/DataMapper.d.ts +3 -0
- 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,263 @@ 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) {
|
|
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);
|
|
103
|
+
case "Value":
|
|
104
|
+
return mapValue(data, "<result>", structure.resultType);
|
|
105
|
+
default:
|
|
106
|
+
assertNever(structure, `Invalid data mapping type: '${structure.type}'`);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
function mapArrayOrObject(data, fields) {
|
|
110
|
+
if (data === null) return null;
|
|
111
|
+
if (Array.isArray(data)) {
|
|
112
|
+
const rows = data;
|
|
113
|
+
return rows.map((row) => mapObject(row, fields));
|
|
114
|
+
}
|
|
115
|
+
if (typeof data === "object") {
|
|
116
|
+
const row = data;
|
|
117
|
+
return mapObject(row, fields);
|
|
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);
|
|
129
|
+
}
|
|
130
|
+
throw new DataMapperError(`Expected an array or an object, got: ${typeof data}`);
|
|
131
|
+
}
|
|
132
|
+
function mapObject(data, fields) {
|
|
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);
|
|
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);
|
|
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) {
|
|
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));
|
|
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
|
+
default:
|
|
273
|
+
assertNever(resultType, `DataMapper: Unknown result type: ${resultType.type}`);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
var TIMEZONE_PATTERN = /Z$|(?<!\d{4}-\d{2})[+-]\d{2}(:?\d{2})?$/;
|
|
277
|
+
function ensureTimezoneInIsoString(dt) {
|
|
278
|
+
const results = TIMEZONE_PATTERN.exec(dt);
|
|
279
|
+
if (results === null) {
|
|
280
|
+
return `${dt}Z`;
|
|
281
|
+
} else if (results[0] !== "Z" && results[1] === void 0) {
|
|
282
|
+
return `${dt}:00`;
|
|
283
|
+
} else {
|
|
284
|
+
return dt;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
51
287
|
|
|
52
288
|
// src/tracing.ts
|
|
289
|
+
var import_api = require("@opentelemetry/api");
|
|
53
290
|
var noopTracingHelper = {
|
|
54
291
|
runInChildSpan(_, callback) {
|
|
55
292
|
return callback();
|
|
@@ -67,6 +304,37 @@ function providerToOtelSystem(provider) {
|
|
|
67
304
|
assertNever(provider, `Unknown provider: ${provider}`);
|
|
68
305
|
}
|
|
69
306
|
}
|
|
307
|
+
async function withQuerySpanAndEvent({
|
|
308
|
+
query,
|
|
309
|
+
queryable,
|
|
310
|
+
tracingHelper,
|
|
311
|
+
onQuery,
|
|
312
|
+
execute
|
|
313
|
+
}) {
|
|
314
|
+
return await tracingHelper.runInChildSpan(
|
|
315
|
+
{
|
|
316
|
+
name: "db_query",
|
|
317
|
+
kind: import_api.SpanKind.CLIENT,
|
|
318
|
+
attributes: {
|
|
319
|
+
"db.query.text": query.sql,
|
|
320
|
+
"db.system.name": providerToOtelSystem(queryable.provider)
|
|
321
|
+
}
|
|
322
|
+
},
|
|
323
|
+
async () => {
|
|
324
|
+
const timestamp = /* @__PURE__ */ new Date();
|
|
325
|
+
const startInstant = performance.now();
|
|
326
|
+
const result = await execute();
|
|
327
|
+
const endInstant = performance.now();
|
|
328
|
+
onQuery?.({
|
|
329
|
+
timestamp,
|
|
330
|
+
duration: endInstant - startInstant,
|
|
331
|
+
query: query.sql,
|
|
332
|
+
params: query.args
|
|
333
|
+
});
|
|
334
|
+
return result;
|
|
335
|
+
}
|
|
336
|
+
);
|
|
337
|
+
}
|
|
70
338
|
|
|
71
339
|
// src/UserFacingError.ts
|
|
72
340
|
var import_driver_adapter_utils = require("@prisma/driver-adapter-utils");
|
|
@@ -77,7 +345,7 @@ var UserFacingError = class extends Error {
|
|
|
77
345
|
constructor(message, code, meta) {
|
|
78
346
|
super(message);
|
|
79
347
|
this.code = code;
|
|
80
|
-
this.meta = meta;
|
|
348
|
+
this.meta = meta ?? {};
|
|
81
349
|
}
|
|
82
350
|
toQueryResponseErrorObject() {
|
|
83
351
|
return {
|
|
@@ -100,7 +368,7 @@ function rethrowAsUserFacing(error) {
|
|
|
100
368
|
if (!code || !message) {
|
|
101
369
|
throw error;
|
|
102
370
|
}
|
|
103
|
-
throw new UserFacingError(message, code, error);
|
|
371
|
+
throw new UserFacingError(message, code, { driverAdapterError: error });
|
|
104
372
|
}
|
|
105
373
|
function getErrorCode(err) {
|
|
106
374
|
switch (err.cause.kind) {
|
|
@@ -211,101 +479,6 @@ function renderConstraint(constraint) {
|
|
|
211
479
|
return "(not available)";
|
|
212
480
|
}
|
|
213
481
|
|
|
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
482
|
// src/interpreter/generators.ts
|
|
310
483
|
var import_cuid = __toESM(require("@bugsnag/cuid"));
|
|
311
484
|
var import_cuid2 = require("@paralleldrive/cuid2");
|
|
@@ -315,7 +488,6 @@ var import_uuid = require("uuid");
|
|
|
315
488
|
var GeneratorRegistry = class {
|
|
316
489
|
#generators = {};
|
|
317
490
|
constructor() {
|
|
318
|
-
this.register("now", new NowGenerator());
|
|
319
491
|
this.register("uuid", new UuidGenerator());
|
|
320
492
|
this.register("cuid", new CuidGenerator());
|
|
321
493
|
this.register("ulid", new UlidGenerator());
|
|
@@ -327,9 +499,11 @@ var GeneratorRegistry = class {
|
|
|
327
499
|
* method being called, meaning that the built-in time-based generators will always return
|
|
328
500
|
* the same value on repeated calls as long as the same snapshot is used.
|
|
329
501
|
*/
|
|
330
|
-
snapshot() {
|
|
502
|
+
snapshot(provider) {
|
|
331
503
|
return Object.create(this.#generators, {
|
|
332
|
-
now: {
|
|
504
|
+
now: {
|
|
505
|
+
value: provider === "mysql" ? new MysqlNowGenerator() : new NowGenerator()
|
|
506
|
+
}
|
|
333
507
|
});
|
|
334
508
|
}
|
|
335
509
|
/**
|
|
@@ -345,6 +519,12 @@ var NowGenerator = class {
|
|
|
345
519
|
return this.#now.toISOString();
|
|
346
520
|
}
|
|
347
521
|
};
|
|
522
|
+
var MysqlNowGenerator = class {
|
|
523
|
+
#now = /* @__PURE__ */ new Date();
|
|
524
|
+
generate() {
|
|
525
|
+
return this.#now.toISOString().replace("T", " ").replace("Z", "");
|
|
526
|
+
}
|
|
527
|
+
};
|
|
348
528
|
var UuidGenerator = class {
|
|
349
529
|
generate(arg) {
|
|
350
530
|
if (arg === 4) {
|
|
@@ -410,6 +590,9 @@ function isPrismaValueGenerator(value) {
|
|
|
410
590
|
function isPrismaValueBytes(value) {
|
|
411
591
|
return typeof value === "object" && value !== null && value["prisma__type"] === "bytes";
|
|
412
592
|
}
|
|
593
|
+
function isPrismaValueBigInt(value) {
|
|
594
|
+
return typeof value === "object" && value !== null && value["prisma__type"] === "bigint";
|
|
595
|
+
}
|
|
413
596
|
|
|
414
597
|
// src/interpreter/renderQuery.ts
|
|
415
598
|
function renderQuery(dbQuery, scope, generators) {
|
|
@@ -452,9 +635,10 @@ function evaluateParam(param, scope, generators) {
|
|
|
452
635
|
}
|
|
453
636
|
if (Array.isArray(value)) {
|
|
454
637
|
value = value.map((el) => evaluateParam(el, scope, generators));
|
|
455
|
-
}
|
|
456
|
-
if (isPrismaValueBytes(value)) {
|
|
638
|
+
} else if (isPrismaValueBytes(value)) {
|
|
457
639
|
value = Buffer.from(value.prisma__value, "base64");
|
|
640
|
+
} else if (isPrismaValueBigInt(value)) {
|
|
641
|
+
value = BigInt(value.prisma__value);
|
|
458
642
|
}
|
|
459
643
|
return value;
|
|
460
644
|
}
|
|
@@ -548,6 +732,7 @@ function doesRequireEvaluation(param) {
|
|
|
548
732
|
}
|
|
549
733
|
|
|
550
734
|
// src/interpreter/serializeSql.ts
|
|
735
|
+
var import_driver_adapter_utils2 = require("@prisma/driver-adapter-utils");
|
|
551
736
|
function serializeSql(resultSet) {
|
|
552
737
|
return resultSet.rows.map(
|
|
553
738
|
(row) => row.reduce((acc, value, index) => {
|
|
@@ -568,6 +753,100 @@ function serializeSql(resultSet) {
|
|
|
568
753
|
}, {})
|
|
569
754
|
);
|
|
570
755
|
}
|
|
756
|
+
function serializeRawSql(resultSet) {
|
|
757
|
+
const types = resultSet.columnTypes.map((type) => serializeColumnType(type));
|
|
758
|
+
const mappers = types.map((type) => {
|
|
759
|
+
switch (type) {
|
|
760
|
+
case "int":
|
|
761
|
+
return (value) => value === null ? null : typeof value === "number" ? value : parseInt(`${value}`, 10);
|
|
762
|
+
case "bigint":
|
|
763
|
+
return (value) => value === null ? null : typeof value === "bigint" ? value : BigInt(`${value}`);
|
|
764
|
+
case "json":
|
|
765
|
+
return (value) => typeof value === "string" ? JSON.parse(value) : value;
|
|
766
|
+
case "bool":
|
|
767
|
+
return (value) => typeof value === "string" ? value === "true" || value === "1" : typeof value === "number" ? value === 1 : value;
|
|
768
|
+
default:
|
|
769
|
+
return (value) => value;
|
|
770
|
+
}
|
|
771
|
+
});
|
|
772
|
+
return {
|
|
773
|
+
columns: resultSet.columnNames,
|
|
774
|
+
types: resultSet.columnTypes.map((type) => serializeColumnType(type)),
|
|
775
|
+
rows: resultSet.rows.map((row) => row.map((value, index) => mappers[index](value)))
|
|
776
|
+
};
|
|
777
|
+
}
|
|
778
|
+
function serializeColumnType(columnType) {
|
|
779
|
+
switch (columnType) {
|
|
780
|
+
case import_driver_adapter_utils2.ColumnTypeEnum.Int32:
|
|
781
|
+
return "int";
|
|
782
|
+
case import_driver_adapter_utils2.ColumnTypeEnum.Int64:
|
|
783
|
+
return "bigint";
|
|
784
|
+
case import_driver_adapter_utils2.ColumnTypeEnum.Float:
|
|
785
|
+
return "float";
|
|
786
|
+
case import_driver_adapter_utils2.ColumnTypeEnum.Double:
|
|
787
|
+
return "double";
|
|
788
|
+
case import_driver_adapter_utils2.ColumnTypeEnum.Text:
|
|
789
|
+
return "string";
|
|
790
|
+
case import_driver_adapter_utils2.ColumnTypeEnum.Enum:
|
|
791
|
+
return "enum";
|
|
792
|
+
case import_driver_adapter_utils2.ColumnTypeEnum.Bytes:
|
|
793
|
+
return "bytes";
|
|
794
|
+
case import_driver_adapter_utils2.ColumnTypeEnum.Boolean:
|
|
795
|
+
return "bool";
|
|
796
|
+
case import_driver_adapter_utils2.ColumnTypeEnum.Character:
|
|
797
|
+
return "char";
|
|
798
|
+
case import_driver_adapter_utils2.ColumnTypeEnum.Numeric:
|
|
799
|
+
return "decimal";
|
|
800
|
+
case import_driver_adapter_utils2.ColumnTypeEnum.Json:
|
|
801
|
+
return "json";
|
|
802
|
+
case import_driver_adapter_utils2.ColumnTypeEnum.Uuid:
|
|
803
|
+
return "uuid";
|
|
804
|
+
case import_driver_adapter_utils2.ColumnTypeEnum.DateTime:
|
|
805
|
+
return "datetime";
|
|
806
|
+
case import_driver_adapter_utils2.ColumnTypeEnum.Date:
|
|
807
|
+
return "date";
|
|
808
|
+
case import_driver_adapter_utils2.ColumnTypeEnum.Time:
|
|
809
|
+
return "time";
|
|
810
|
+
case import_driver_adapter_utils2.ColumnTypeEnum.Int32Array:
|
|
811
|
+
return "int-array";
|
|
812
|
+
case import_driver_adapter_utils2.ColumnTypeEnum.Int64Array:
|
|
813
|
+
return "bigint-array";
|
|
814
|
+
case import_driver_adapter_utils2.ColumnTypeEnum.FloatArray:
|
|
815
|
+
return "float-array";
|
|
816
|
+
case import_driver_adapter_utils2.ColumnTypeEnum.DoubleArray:
|
|
817
|
+
return "double-array";
|
|
818
|
+
case import_driver_adapter_utils2.ColumnTypeEnum.TextArray:
|
|
819
|
+
return "string-array";
|
|
820
|
+
case import_driver_adapter_utils2.ColumnTypeEnum.EnumArray:
|
|
821
|
+
return "string-array";
|
|
822
|
+
case import_driver_adapter_utils2.ColumnTypeEnum.BytesArray:
|
|
823
|
+
return "bytes-array";
|
|
824
|
+
case import_driver_adapter_utils2.ColumnTypeEnum.BooleanArray:
|
|
825
|
+
return "bool-array";
|
|
826
|
+
case import_driver_adapter_utils2.ColumnTypeEnum.CharacterArray:
|
|
827
|
+
return "char-array";
|
|
828
|
+
case import_driver_adapter_utils2.ColumnTypeEnum.NumericArray:
|
|
829
|
+
return "decimal-array";
|
|
830
|
+
case import_driver_adapter_utils2.ColumnTypeEnum.JsonArray:
|
|
831
|
+
return "json-array";
|
|
832
|
+
case import_driver_adapter_utils2.ColumnTypeEnum.UuidArray:
|
|
833
|
+
return "uuid-array";
|
|
834
|
+
case import_driver_adapter_utils2.ColumnTypeEnum.DateTimeArray:
|
|
835
|
+
return "datetime-array";
|
|
836
|
+
case import_driver_adapter_utils2.ColumnTypeEnum.DateArray:
|
|
837
|
+
return "date-array";
|
|
838
|
+
case import_driver_adapter_utils2.ColumnTypeEnum.TimeArray:
|
|
839
|
+
return "time-array";
|
|
840
|
+
case import_driver_adapter_utils2.ColumnTypeEnum.UnknownNumber:
|
|
841
|
+
return "unknown";
|
|
842
|
+
/// The following PlanetScale type IDs are mapped into Set:
|
|
843
|
+
/// - SET (SET) -> e.g. `"foo,bar"` (String-encoded, comma-separated)
|
|
844
|
+
case import_driver_adapter_utils2.ColumnTypeEnum.Set:
|
|
845
|
+
return "string";
|
|
846
|
+
default:
|
|
847
|
+
assertNever(columnType, `Unexpected column type: ${columnType}`);
|
|
848
|
+
}
|
|
849
|
+
}
|
|
571
850
|
|
|
572
851
|
// src/interpreter/validation.ts
|
|
573
852
|
function performValidation(data, rules, error) {
|
|
@@ -595,6 +874,8 @@ function doesSatisfyRule(data, rule) {
|
|
|
595
874
|
return rule.args !== 0;
|
|
596
875
|
}
|
|
597
876
|
return rule.args !== 1;
|
|
877
|
+
case "affectedRowCountEq":
|
|
878
|
+
return data === rule.args;
|
|
598
879
|
case "never":
|
|
599
880
|
return false;
|
|
600
881
|
default:
|
|
@@ -612,7 +893,9 @@ function renderMessage(data, error) {
|
|
|
612
893
|
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
894
|
}
|
|
614
895
|
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 :
|
|
896
|
+
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}.`;
|
|
897
|
+
case "INCOMPLETE_CONNECT_OUTPUT":
|
|
898
|
+
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
899
|
case "RECORDS_NOT_CONNECTED":
|
|
617
900
|
return `The records for relation \`${error.context.relation}\` between the \`${error.context.parent}\` and \`${error.context.child}\` models are not connected.`;
|
|
618
901
|
default:
|
|
@@ -625,6 +908,8 @@ function getErrorCode2(error) {
|
|
|
625
908
|
return "P2014";
|
|
626
909
|
case "RECORDS_NOT_CONNECTED":
|
|
627
910
|
return "P2017";
|
|
911
|
+
case "INCOMPLETE_CONNECT_OUTPUT":
|
|
912
|
+
return "P2018";
|
|
628
913
|
case "MISSING_RECORD":
|
|
629
914
|
case "MISSING_RELATED_RECORD":
|
|
630
915
|
case "INCOMPLETE_CONNECT_INPUT":
|
|
@@ -642,12 +927,21 @@ var QueryInterpreter = class _QueryInterpreter {
|
|
|
642
927
|
#generators = new GeneratorRegistry();
|
|
643
928
|
#tracingHelper;
|
|
644
929
|
#serializer;
|
|
645
|
-
|
|
930
|
+
#rawSerializer;
|
|
931
|
+
constructor({
|
|
932
|
+
transactionManager,
|
|
933
|
+
placeholderValues,
|
|
934
|
+
onQuery,
|
|
935
|
+
tracingHelper,
|
|
936
|
+
serializer,
|
|
937
|
+
rawSerializer
|
|
938
|
+
}) {
|
|
646
939
|
this.#transactionManager = transactionManager;
|
|
647
940
|
this.#placeholderValues = placeholderValues;
|
|
648
941
|
this.#onQuery = onQuery;
|
|
649
942
|
this.#tracingHelper = tracingHelper;
|
|
650
943
|
this.#serializer = serializer;
|
|
944
|
+
this.#rawSerializer = rawSerializer ?? serializer;
|
|
651
945
|
}
|
|
652
946
|
static forSql(options) {
|
|
653
947
|
return new _QueryInterpreter({
|
|
@@ -655,27 +949,36 @@ var QueryInterpreter = class _QueryInterpreter {
|
|
|
655
949
|
placeholderValues: options.placeholderValues,
|
|
656
950
|
onQuery: options.onQuery,
|
|
657
951
|
tracingHelper: options.tracingHelper,
|
|
658
|
-
serializer: serializeSql
|
|
952
|
+
serializer: serializeSql,
|
|
953
|
+
rawSerializer: serializeRawSql
|
|
659
954
|
});
|
|
660
955
|
}
|
|
661
956
|
async run(queryPlan, queryable) {
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
957
|
+
const { value } = await this.interpretNode(
|
|
958
|
+
queryPlan,
|
|
959
|
+
queryable,
|
|
960
|
+
this.#placeholderValues,
|
|
961
|
+
this.#generators.snapshot(queryable.provider)
|
|
962
|
+
).catch((e) => rethrowAsUserFacing(e));
|
|
963
|
+
return value;
|
|
665
964
|
}
|
|
666
965
|
async interpretNode(node, queryable, scope, generators) {
|
|
667
966
|
switch (node.type) {
|
|
668
967
|
case "seq": {
|
|
669
|
-
|
|
670
|
-
|
|
968
|
+
let result;
|
|
969
|
+
for (const arg of node.args) {
|
|
970
|
+
result = await this.interpretNode(arg, queryable, scope, generators);
|
|
971
|
+
}
|
|
972
|
+
return result ?? { value: void 0 };
|
|
671
973
|
}
|
|
672
974
|
case "get": {
|
|
673
|
-
return scope[node.args.name];
|
|
975
|
+
return { value: scope[node.args.name] };
|
|
674
976
|
}
|
|
675
977
|
case "let": {
|
|
676
978
|
const nestedScope = Object.create(scope);
|
|
677
979
|
for (const binding of node.args.bindings) {
|
|
678
|
-
|
|
980
|
+
const { value } = await this.interpretNode(binding.expr, queryable, nestedScope, generators);
|
|
981
|
+
nestedScope[binding.name] = value;
|
|
679
982
|
}
|
|
680
983
|
return this.interpretNode(node.args.expr, queryable, nestedScope, generators);
|
|
681
984
|
}
|
|
@@ -683,71 +986,87 @@ var QueryInterpreter = class _QueryInterpreter {
|
|
|
683
986
|
for (const name of node.args.names) {
|
|
684
987
|
const value = scope[name];
|
|
685
988
|
if (!isEmpty(value)) {
|
|
686
|
-
return value;
|
|
989
|
+
return { value };
|
|
687
990
|
}
|
|
688
991
|
}
|
|
689
|
-
return [];
|
|
992
|
+
return { value: [] };
|
|
690
993
|
}
|
|
691
994
|
case "concat": {
|
|
692
|
-
const parts = await Promise.all(
|
|
693
|
-
|
|
995
|
+
const parts = await Promise.all(
|
|
996
|
+
node.args.map((arg) => this.interpretNode(arg, queryable, scope, generators).then((res) => res.value))
|
|
997
|
+
);
|
|
998
|
+
return {
|
|
999
|
+
value: parts.length > 0 ? parts.reduce((acc, part) => acc.concat(asList(part)), []) : []
|
|
1000
|
+
};
|
|
694
1001
|
}
|
|
695
1002
|
case "sum": {
|
|
696
|
-
const parts = await Promise.all(
|
|
697
|
-
|
|
1003
|
+
const parts = await Promise.all(
|
|
1004
|
+
node.args.map((arg) => this.interpretNode(arg, queryable, scope, generators).then((res) => res.value))
|
|
1005
|
+
);
|
|
1006
|
+
return {
|
|
1007
|
+
value: parts.length > 0 ? parts.reduce((acc, part) => asNumber(acc) + asNumber(part)) : 0
|
|
1008
|
+
};
|
|
698
1009
|
}
|
|
699
1010
|
case "execute": {
|
|
700
1011
|
const query = renderQuery(node.args, scope, generators);
|
|
701
|
-
return this.#
|
|
702
|
-
return await queryable.executeRaw(query);
|
|
1012
|
+
return this.#withQuerySpanAndEvent(query, queryable, async () => {
|
|
1013
|
+
return { value: await queryable.executeRaw(query) };
|
|
703
1014
|
});
|
|
704
1015
|
}
|
|
705
1016
|
case "query": {
|
|
706
1017
|
const query = renderQuery(node.args, scope, generators);
|
|
707
|
-
return this.#
|
|
708
|
-
|
|
1018
|
+
return this.#withQuerySpanAndEvent(query, queryable, async () => {
|
|
1019
|
+
const result = await queryable.queryRaw(query);
|
|
1020
|
+
if (node.args.type === "rawSql") {
|
|
1021
|
+
return { value: this.#rawSerializer(result), lastInsertId: result.lastInsertId };
|
|
1022
|
+
} else {
|
|
1023
|
+
return { value: this.#serializer(result), lastInsertId: result.lastInsertId };
|
|
1024
|
+
}
|
|
709
1025
|
});
|
|
710
1026
|
}
|
|
711
1027
|
case "reverse": {
|
|
712
|
-
const value = await this.interpretNode(node.args, queryable, scope, generators);
|
|
713
|
-
return Array.isArray(value) ? value.reverse() : value;
|
|
1028
|
+
const { value, lastInsertId } = await this.interpretNode(node.args, queryable, scope, generators);
|
|
1029
|
+
return { value: Array.isArray(value) ? value.reverse() : value, lastInsertId };
|
|
714
1030
|
}
|
|
715
1031
|
case "unique": {
|
|
716
|
-
const value = await this.interpretNode(node.args, queryable, scope, generators);
|
|
1032
|
+
const { value, lastInsertId } = await this.interpretNode(node.args, queryable, scope, generators);
|
|
717
1033
|
if (!Array.isArray(value)) {
|
|
718
|
-
return value;
|
|
1034
|
+
return { value, lastInsertId };
|
|
719
1035
|
}
|
|
720
1036
|
if (value.length > 1) {
|
|
721
1037
|
throw new Error(`Expected zero or one element, got ${value.length}`);
|
|
722
1038
|
}
|
|
723
|
-
return value[0] ?? null;
|
|
1039
|
+
return { value: value[0] ?? null, lastInsertId };
|
|
724
1040
|
}
|
|
725
1041
|
case "required": {
|
|
726
|
-
const value = await this.interpretNode(node.args, queryable, scope, generators);
|
|
1042
|
+
const { value, lastInsertId } = await this.interpretNode(node.args, queryable, scope, generators);
|
|
727
1043
|
if (isEmpty(value)) {
|
|
728
1044
|
throw new Error("Required value is empty");
|
|
729
1045
|
}
|
|
730
|
-
return value;
|
|
1046
|
+
return { value, lastInsertId };
|
|
731
1047
|
}
|
|
732
1048
|
case "mapField": {
|
|
733
|
-
const value = await this.interpretNode(node.args.records, queryable, scope, generators);
|
|
734
|
-
return mapField(value, node.args.field);
|
|
1049
|
+
const { value, lastInsertId } = await this.interpretNode(node.args.records, queryable, scope, generators);
|
|
1050
|
+
return { value: mapField(value, node.args.field), lastInsertId };
|
|
735
1051
|
}
|
|
736
1052
|
case "join": {
|
|
737
|
-
const parent = await this.interpretNode(node.args.parent, queryable, scope, generators);
|
|
1053
|
+
const { value: parent, lastInsertId } = await this.interpretNode(node.args.parent, queryable, scope, generators);
|
|
1054
|
+
if (parent === null) {
|
|
1055
|
+
return { value: null, lastInsertId };
|
|
1056
|
+
}
|
|
738
1057
|
const children = await Promise.all(
|
|
739
1058
|
node.args.children.map(async (joinExpr) => ({
|
|
740
1059
|
joinExpr,
|
|
741
|
-
childRecords: await this.interpretNode(joinExpr.child, queryable, scope, generators)
|
|
1060
|
+
childRecords: (await this.interpretNode(joinExpr.child, queryable, scope, generators)).value
|
|
742
1061
|
}))
|
|
743
1062
|
);
|
|
744
1063
|
if (Array.isArray(parent)) {
|
|
745
1064
|
for (const record of parent) {
|
|
746
1065
|
attachChildrenToParent(asRecord(record), children);
|
|
747
1066
|
}
|
|
748
|
-
return parent;
|
|
1067
|
+
return { value: parent, lastInsertId };
|
|
749
1068
|
}
|
|
750
|
-
return attachChildrenToParent(asRecord(parent), children);
|
|
1069
|
+
return { value: attachChildrenToParent(asRecord(parent), children), lastInsertId };
|
|
751
1070
|
}
|
|
752
1071
|
case "transaction": {
|
|
753
1072
|
if (!this.#transactionManager.enabled) {
|
|
@@ -766,16 +1085,16 @@ var QueryInterpreter = class _QueryInterpreter {
|
|
|
766
1085
|
}
|
|
767
1086
|
}
|
|
768
1087
|
case "dataMap": {
|
|
769
|
-
const
|
|
770
|
-
return applyDataMap(
|
|
1088
|
+
const { value, lastInsertId } = await this.interpretNode(node.args.expr, queryable, scope, generators);
|
|
1089
|
+
return { value: applyDataMap(value, node.args.structure), lastInsertId };
|
|
771
1090
|
}
|
|
772
1091
|
case "validate": {
|
|
773
|
-
const
|
|
774
|
-
performValidation(
|
|
775
|
-
return
|
|
1092
|
+
const { value, lastInsertId } = await this.interpretNode(node.args.expr, queryable, scope, generators);
|
|
1093
|
+
performValidation(value, node.args.rules, node.args);
|
|
1094
|
+
return { value, lastInsertId };
|
|
776
1095
|
}
|
|
777
1096
|
case "if": {
|
|
778
|
-
const value = await this.interpretNode(node.args.value, queryable, scope, generators);
|
|
1097
|
+
const { value } = await this.interpretNode(node.args.value, queryable, scope, generators);
|
|
779
1098
|
if (doesSatisfyRule(value, node.args.rule)) {
|
|
780
1099
|
return await this.interpretNode(node.args.then, queryable, scope, generators);
|
|
781
1100
|
} else {
|
|
@@ -783,42 +1102,73 @@ var QueryInterpreter = class _QueryInterpreter {
|
|
|
783
1102
|
}
|
|
784
1103
|
}
|
|
785
1104
|
case "unit": {
|
|
786
|
-
return void 0;
|
|
1105
|
+
return { value: void 0 };
|
|
787
1106
|
}
|
|
788
1107
|
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);
|
|
1108
|
+
const { value: from } = await this.interpretNode(node.args.from, queryable, scope, generators);
|
|
1109
|
+
const { value: to } = await this.interpretNode(node.args.to, queryable, scope, generators);
|
|
791
1110
|
const toSet = new Set(asList(to));
|
|
792
|
-
return asList(from).filter((item) => !toSet.has(item));
|
|
1111
|
+
return { value: asList(from).filter((item) => !toSet.has(item)) };
|
|
1112
|
+
}
|
|
1113
|
+
case "distinctBy": {
|
|
1114
|
+
const { value, lastInsertId } = await this.interpretNode(node.args.expr, queryable, scope, generators);
|
|
1115
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1116
|
+
const result = [];
|
|
1117
|
+
for (const item of asList(value)) {
|
|
1118
|
+
const key = getRecordKey(item, node.args.fields);
|
|
1119
|
+
if (!seen.has(key)) {
|
|
1120
|
+
seen.add(key);
|
|
1121
|
+
result.push(item);
|
|
1122
|
+
}
|
|
1123
|
+
}
|
|
1124
|
+
return { value: result, lastInsertId };
|
|
1125
|
+
}
|
|
1126
|
+
case "paginate": {
|
|
1127
|
+
const { value, lastInsertId } = await this.interpretNode(node.args.expr, queryable, scope, generators);
|
|
1128
|
+
const list = asList(value);
|
|
1129
|
+
const linkingFields = node.args.pagination.linkingFields;
|
|
1130
|
+
if (linkingFields !== null) {
|
|
1131
|
+
const groupedByParent = /* @__PURE__ */ new Map();
|
|
1132
|
+
for (const item of list) {
|
|
1133
|
+
const parentKey = getRecordKey(item, linkingFields);
|
|
1134
|
+
if (!groupedByParent.has(parentKey)) {
|
|
1135
|
+
groupedByParent.set(parentKey, []);
|
|
1136
|
+
}
|
|
1137
|
+
groupedByParent.get(parentKey).push(item);
|
|
1138
|
+
}
|
|
1139
|
+
const groupList = Array.from(groupedByParent.entries());
|
|
1140
|
+
groupList.sort(([aId], [bId]) => aId < bId ? -1 : aId > bId ? 1 : 0);
|
|
1141
|
+
return {
|
|
1142
|
+
value: groupList.flatMap(([, elems]) => paginate(elems, node.args.pagination)),
|
|
1143
|
+
lastInsertId
|
|
1144
|
+
};
|
|
1145
|
+
}
|
|
1146
|
+
return { value: paginate(list, node.args.pagination), lastInsertId };
|
|
1147
|
+
}
|
|
1148
|
+
case "extendRecord": {
|
|
1149
|
+
const { value, lastInsertId } = await this.interpretNode(node.args.expr, queryable, scope, generators);
|
|
1150
|
+
const record = value === null ? {} : asRecord(value);
|
|
1151
|
+
for (const [key, entry] of Object.entries(node.args.values)) {
|
|
1152
|
+
if (entry.type === "lastInsertId") {
|
|
1153
|
+
record[key] = lastInsertId;
|
|
1154
|
+
} else {
|
|
1155
|
+
record[key] = evaluateParam(entry.value, scope, generators);
|
|
1156
|
+
}
|
|
1157
|
+
}
|
|
1158
|
+
return { value: record, lastInsertId };
|
|
793
1159
|
}
|
|
794
1160
|
default:
|
|
795
1161
|
assertNever(node, `Unexpected node type: ${node.type}`);
|
|
796
1162
|
}
|
|
797
1163
|
}
|
|
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
|
-
);
|
|
1164
|
+
#withQuerySpanAndEvent(query, queryable, execute) {
|
|
1165
|
+
return withQuerySpanAndEvent({
|
|
1166
|
+
query,
|
|
1167
|
+
queryable,
|
|
1168
|
+
execute,
|
|
1169
|
+
tracingHelper: this.#tracingHelper,
|
|
1170
|
+
onQuery: this.#onQuery
|
|
1171
|
+
});
|
|
822
1172
|
}
|
|
823
1173
|
};
|
|
824
1174
|
function isEmpty(value) {
|
|
@@ -862,7 +1212,12 @@ function attachChildrenToParent(parentRecord, children) {
|
|
|
862
1212
|
}
|
|
863
1213
|
function filterChildRecords(records, parentRecord, joinExpr) {
|
|
864
1214
|
if (Array.isArray(records)) {
|
|
865
|
-
|
|
1215
|
+
const filtered = records.filter((record) => childRecordMatchesParent(asRecord(record), parentRecord, joinExpr));
|
|
1216
|
+
if (joinExpr.isRelationUnique) {
|
|
1217
|
+
return filtered.length > 0 ? filtered[0] : null;
|
|
1218
|
+
} else {
|
|
1219
|
+
return filtered;
|
|
1220
|
+
}
|
|
866
1221
|
} else if (records === null) {
|
|
867
1222
|
return null;
|
|
868
1223
|
} else {
|
|
@@ -878,6 +1233,18 @@ function childRecordMatchesParent(childRecord, parentRecord, joinExpr) {
|
|
|
878
1233
|
}
|
|
879
1234
|
return true;
|
|
880
1235
|
}
|
|
1236
|
+
function paginate(list, { cursor, skip, take }) {
|
|
1237
|
+
const cursorIndex = cursor !== null ? list.findIndex((item) => doKeysMatch(item, cursor)) : 0;
|
|
1238
|
+
if (cursorIndex === -1) {
|
|
1239
|
+
return [];
|
|
1240
|
+
}
|
|
1241
|
+
const start = cursorIndex + (skip ?? 0);
|
|
1242
|
+
const end = take !== null ? start + take : list.length;
|
|
1243
|
+
return list.slice(start, end);
|
|
1244
|
+
}
|
|
1245
|
+
function getRecordKey(record, fields) {
|
|
1246
|
+
return JSON.stringify(fields.map((field) => record[field]));
|
|
1247
|
+
}
|
|
881
1248
|
|
|
882
1249
|
// src/transactionManager/TransactionManager.ts
|
|
883
1250
|
var import_debug = require("@prisma/debug");
|
|
@@ -892,12 +1259,11 @@ async function randomUUID() {
|
|
|
892
1259
|
}
|
|
893
1260
|
|
|
894
1261
|
// src/transactionManager/TransactionManagerErrors.ts
|
|
895
|
-
var TransactionManagerError = class extends
|
|
1262
|
+
var TransactionManagerError = class extends UserFacingError {
|
|
1263
|
+
name = "TransactionManagerError";
|
|
896
1264
|
constructor(message, meta) {
|
|
897
|
-
super("Transaction API error: " + message);
|
|
898
|
-
this.meta = meta;
|
|
1265
|
+
super("Transaction API error: " + message, "P2028", meta);
|
|
899
1266
|
}
|
|
900
|
-
code = "P2028";
|
|
901
1267
|
};
|
|
902
1268
|
var TransactionNotFoundError = class extends TransactionManagerError {
|
|
903
1269
|
constructor() {
|
|
@@ -908,12 +1274,12 @@ var TransactionNotFoundError = class extends TransactionManagerError {
|
|
|
908
1274
|
};
|
|
909
1275
|
var TransactionClosedError = class extends TransactionManagerError {
|
|
910
1276
|
constructor(operation) {
|
|
911
|
-
super(`Transaction already closed: A ${operation} cannot be executed on a committed transaction
|
|
1277
|
+
super(`Transaction already closed: A ${operation} cannot be executed on a committed transaction.`);
|
|
912
1278
|
}
|
|
913
1279
|
};
|
|
914
1280
|
var TransactionRolledBackError = class extends TransactionManagerError {
|
|
915
1281
|
constructor(operation) {
|
|
916
|
-
super(`Transaction already closed: A ${operation} cannot be executed on a transaction that was rolled back
|
|
1282
|
+
super(`Transaction already closed: A ${operation} cannot be executed on a transaction that was rolled back.`);
|
|
917
1283
|
}
|
|
918
1284
|
};
|
|
919
1285
|
var TransactionStartTimeoutError = class extends TransactionManagerError {
|
|
@@ -945,6 +1311,16 @@ var MAX_CLOSED_TRANSACTIONS = 100;
|
|
|
945
1311
|
var debug = (0, import_debug.Debug)("prisma:client:transactionManager");
|
|
946
1312
|
var COMMIT_QUERY = () => ({ sql: "COMMIT", args: [], argTypes: [] });
|
|
947
1313
|
var ROLLBACK_QUERY = () => ({ sql: "ROLLBACK", args: [], argTypes: [] });
|
|
1314
|
+
var PHANTOM_COMMIT_QUERY = () => ({
|
|
1315
|
+
sql: '-- Implicit "COMMIT" query via underlying driver',
|
|
1316
|
+
args: [],
|
|
1317
|
+
argTypes: []
|
|
1318
|
+
});
|
|
1319
|
+
var PHANTOM_ROLLBACK_QUERY = () => ({
|
|
1320
|
+
sql: '-- Implicit "ROLLBACK" query via underlying driver',
|
|
1321
|
+
args: [],
|
|
1322
|
+
argTypes: []
|
|
1323
|
+
});
|
|
948
1324
|
var TransactionManager = class {
|
|
949
1325
|
// The map of active transactions.
|
|
950
1326
|
transactions = /* @__PURE__ */ new Map();
|
|
@@ -954,14 +1330,17 @@ var TransactionManager = class {
|
|
|
954
1330
|
driverAdapter;
|
|
955
1331
|
transactionOptions;
|
|
956
1332
|
tracingHelper;
|
|
1333
|
+
#onQuery;
|
|
957
1334
|
constructor({
|
|
958
1335
|
driverAdapter,
|
|
959
1336
|
transactionOptions,
|
|
960
|
-
tracingHelper
|
|
1337
|
+
tracingHelper,
|
|
1338
|
+
onQuery
|
|
961
1339
|
}) {
|
|
962
1340
|
this.driverAdapter = driverAdapter;
|
|
963
1341
|
this.transactionOptions = transactionOptions;
|
|
964
1342
|
this.tracingHelper = tracingHelper;
|
|
1343
|
+
this.#onQuery = onQuery;
|
|
965
1344
|
}
|
|
966
1345
|
async startTransaction(options) {
|
|
967
1346
|
return await this.tracingHelper.runInChildSpan("start_transaction", () => this.#startTransactionImpl(options));
|
|
@@ -1065,14 +1444,20 @@ var TransactionManager = class {
|
|
|
1065
1444
|
debug("Closing transaction.", { transactionId: tx.id, status });
|
|
1066
1445
|
tx.status = status;
|
|
1067
1446
|
if (tx.transaction && status === "committed") {
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1447
|
+
if (tx.transaction.options.usePhantomQuery) {
|
|
1448
|
+
await this.#withQuerySpanAndEvent(PHANTOM_COMMIT_QUERY(), tx.transaction, () => tx.transaction.commit());
|
|
1449
|
+
} else {
|
|
1450
|
+
await tx.transaction.commit();
|
|
1451
|
+
const query = COMMIT_QUERY();
|
|
1452
|
+
await this.#withQuerySpanAndEvent(query, tx.transaction, () => tx.transaction.executeRaw(query));
|
|
1071
1453
|
}
|
|
1072
1454
|
} else if (tx.transaction) {
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1455
|
+
if (tx.transaction.options.usePhantomQuery) {
|
|
1456
|
+
await this.#withQuerySpanAndEvent(PHANTOM_ROLLBACK_QUERY(), tx.transaction, () => tx.transaction.rollback());
|
|
1457
|
+
} else {
|
|
1458
|
+
await tx.transaction.rollback();
|
|
1459
|
+
const query = ROLLBACK_QUERY();
|
|
1460
|
+
await this.#withQuerySpanAndEvent(query, tx.transaction, () => tx.transaction.executeRaw(query));
|
|
1076
1461
|
}
|
|
1077
1462
|
}
|
|
1078
1463
|
clearTimeout(tx.timer);
|
|
@@ -1093,15 +1478,29 @@ var TransactionManager = class {
|
|
|
1093
1478
|
maxWait: options.maxWait
|
|
1094
1479
|
};
|
|
1095
1480
|
}
|
|
1481
|
+
#withQuerySpanAndEvent(query, queryable, execute) {
|
|
1482
|
+
return withQuerySpanAndEvent({
|
|
1483
|
+
query,
|
|
1484
|
+
queryable,
|
|
1485
|
+
execute,
|
|
1486
|
+
tracingHelper: this.tracingHelper,
|
|
1487
|
+
onQuery: this.#onQuery
|
|
1488
|
+
});
|
|
1489
|
+
}
|
|
1096
1490
|
};
|
|
1097
1491
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1098
1492
|
0 && (module.exports = {
|
|
1493
|
+
DataMapperError,
|
|
1099
1494
|
QueryInterpreter,
|
|
1100
1495
|
TransactionManager,
|
|
1101
1496
|
TransactionManagerError,
|
|
1102
1497
|
UserFacingError,
|
|
1498
|
+
doKeysMatch,
|
|
1499
|
+
isDeepStrictEqual,
|
|
1500
|
+
isPrismaValueBigInt,
|
|
1103
1501
|
isPrismaValueBytes,
|
|
1104
1502
|
isPrismaValueGenerator,
|
|
1105
1503
|
isPrismaValuePlaceholder,
|
|
1106
|
-
noopTracingHelper
|
|
1504
|
+
noopTracingHelper,
|
|
1505
|
+
safeJsonStringify
|
|
1107
1506
|
});
|