@prisma/client-engine-runtime 6.9.0-dev.9 → 6.9.0-integration-push-xtvzqtsrpwpk.3
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 +35 -1
- package/dist/UserFacingError.d.ts +3 -3
- package/dist/index.d.mts +67 -13
- package/dist/index.d.ts +67 -13
- package/dist/index.js +544 -199
- package/dist/index.mjs +539 -198
- 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 +11 -0
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -30,30 +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,
|
|
37
39
|
isDeepStrictEqual: () => isDeepStrictEqual,
|
|
40
|
+
isPrismaValueBigInt: () => isPrismaValueBigInt,
|
|
38
41
|
isPrismaValueBytes: () => isPrismaValueBytes,
|
|
39
42
|
isPrismaValueGenerator: () => isPrismaValueGenerator,
|
|
40
43
|
isPrismaValuePlaceholder: () => isPrismaValuePlaceholder,
|
|
41
|
-
noopTracingHelper: () => noopTracingHelper
|
|
44
|
+
noopTracingHelper: () => noopTracingHelper,
|
|
45
|
+
safeJsonStringify: () => safeJsonStringify
|
|
42
46
|
});
|
|
43
47
|
module.exports = __toCommonJS(index_exports);
|
|
44
48
|
|
|
45
|
-
// src/interpreter/
|
|
46
|
-
var
|
|
49
|
+
// src/interpreter/DataMapper.ts
|
|
50
|
+
var import_decimal2 = __toESM(require("decimal.js"));
|
|
47
51
|
|
|
48
52
|
// src/utils.ts
|
|
53
|
+
var import_decimal = __toESM(require("decimal.js"));
|
|
49
54
|
function assertNever(_, message) {
|
|
50
55
|
throw new Error(message);
|
|
51
56
|
}
|
|
52
57
|
function isDeepStrictEqual(a, b) {
|
|
53
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]));
|
|
54
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
|
+
}
|
|
55
298
|
|
|
56
299
|
// src/tracing.ts
|
|
300
|
+
var import_api = require("@opentelemetry/api");
|
|
57
301
|
var noopTracingHelper = {
|
|
58
302
|
runInChildSpan(_, callback) {
|
|
59
303
|
return callback();
|
|
@@ -71,6 +315,37 @@ function providerToOtelSystem(provider) {
|
|
|
71
315
|
assertNever(provider, `Unknown provider: ${provider}`);
|
|
72
316
|
}
|
|
73
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
|
+
}
|
|
74
349
|
|
|
75
350
|
// src/UserFacingError.ts
|
|
76
351
|
var import_driver_adapter_utils = require("@prisma/driver-adapter-utils");
|
|
@@ -81,7 +356,7 @@ var UserFacingError = class extends Error {
|
|
|
81
356
|
constructor(message, code, meta) {
|
|
82
357
|
super(message);
|
|
83
358
|
this.code = code;
|
|
84
|
-
this.meta = meta;
|
|
359
|
+
this.meta = meta ?? {};
|
|
85
360
|
}
|
|
86
361
|
toQueryResponseErrorObject() {
|
|
87
362
|
return {
|
|
@@ -104,7 +379,7 @@ function rethrowAsUserFacing(error) {
|
|
|
104
379
|
if (!code || !message) {
|
|
105
380
|
throw error;
|
|
106
381
|
}
|
|
107
|
-
throw new UserFacingError(message, code, error);
|
|
382
|
+
throw new UserFacingError(message, code, { driverAdapterError: error });
|
|
108
383
|
}
|
|
109
384
|
function getErrorCode(err) {
|
|
110
385
|
switch (err.cause.kind) {
|
|
@@ -215,101 +490,6 @@ function renderConstraint(constraint) {
|
|
|
215
490
|
return "(not available)";
|
|
216
491
|
}
|
|
217
492
|
|
|
218
|
-
// src/interpreter/DataMapper.ts
|
|
219
|
-
var import_decimal = __toESM(require("decimal.js"));
|
|
220
|
-
function applyDataMap(data, structure) {
|
|
221
|
-
switch (structure.type) {
|
|
222
|
-
case "Object":
|
|
223
|
-
return mapArrayOrObject(data, structure.fields);
|
|
224
|
-
case "Value":
|
|
225
|
-
return mapValue(data, structure.resultType);
|
|
226
|
-
default:
|
|
227
|
-
assertNever(structure, `Invalid data mapping type: '${structure.type}'`);
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
function mapArrayOrObject(data, fields) {
|
|
231
|
-
if (data === null) return null;
|
|
232
|
-
if (Array.isArray(data)) {
|
|
233
|
-
const rows = data;
|
|
234
|
-
return rows.map((row) => mapObject(row, fields));
|
|
235
|
-
}
|
|
236
|
-
if (typeof data === "object") {
|
|
237
|
-
const row = data;
|
|
238
|
-
return mapObject(row, fields);
|
|
239
|
-
}
|
|
240
|
-
throw new Error(`DataMapper: Expected an array or an object, got: ${typeof data}`);
|
|
241
|
-
}
|
|
242
|
-
function mapObject(data, fields) {
|
|
243
|
-
if (typeof data !== "object") {
|
|
244
|
-
throw new Error(`DataMapper: Expected an object, but got '${typeof data}'`);
|
|
245
|
-
}
|
|
246
|
-
const result = {};
|
|
247
|
-
for (const [name, node] of Object.entries(fields)) {
|
|
248
|
-
switch (node.type) {
|
|
249
|
-
case "Object": {
|
|
250
|
-
if (!node.flattened && !Object.hasOwn(data, name)) {
|
|
251
|
-
throw new Error(
|
|
252
|
-
`DataMapper: Missing data field (Object): '${name}'; node: ${JSON.stringify(node)}; data: ${JSON.stringify(data)}`
|
|
253
|
-
);
|
|
254
|
-
}
|
|
255
|
-
const target = node.flattened ? data : data[name];
|
|
256
|
-
result[name] = mapArrayOrObject(target, node.fields);
|
|
257
|
-
break;
|
|
258
|
-
}
|
|
259
|
-
case "Value":
|
|
260
|
-
{
|
|
261
|
-
const dbName = node.dbName;
|
|
262
|
-
if (Object.hasOwn(data, dbName)) {
|
|
263
|
-
result[name] = mapValue(data[dbName], node.resultType);
|
|
264
|
-
} else {
|
|
265
|
-
throw new Error(
|
|
266
|
-
`DataMapper: Missing data field (Value): '${dbName}'; node: ${JSON.stringify(node)}; data: ${JSON.stringify(data)}`
|
|
267
|
-
);
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
break;
|
|
271
|
-
default:
|
|
272
|
-
assertNever(node, `DataMapper: Invalid data mapping node type: '${node.type}'`);
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
return result;
|
|
276
|
-
}
|
|
277
|
-
function mapValue(value, resultType) {
|
|
278
|
-
if (value === null) return null;
|
|
279
|
-
switch (resultType.type) {
|
|
280
|
-
case "Any":
|
|
281
|
-
return value;
|
|
282
|
-
case "String":
|
|
283
|
-
return typeof value === "string" ? value : `${value}`;
|
|
284
|
-
case "Int":
|
|
285
|
-
return typeof value === "number" ? value : parseInt(`${value}`, 10);
|
|
286
|
-
case "BigInt":
|
|
287
|
-
return typeof value === "bigint" ? value : BigInt(`${value}`);
|
|
288
|
-
case "Float":
|
|
289
|
-
return typeof value === "number" ? value : parseFloat(`${value}`);
|
|
290
|
-
case "Boolean":
|
|
291
|
-
return typeof value === "boolean" ? value : value !== "0";
|
|
292
|
-
case "Decimal":
|
|
293
|
-
return typeof value === "number" ? new import_decimal.default(value) : new import_decimal.default(`${value}`);
|
|
294
|
-
case "Date":
|
|
295
|
-
return value instanceof Date ? value : /* @__PURE__ */ new Date(`${value}`);
|
|
296
|
-
case "Array": {
|
|
297
|
-
const values = value;
|
|
298
|
-
return values.map((v) => mapValue(v, resultType.inner));
|
|
299
|
-
}
|
|
300
|
-
case "Object":
|
|
301
|
-
return typeof value === "string" ? value : JSON.stringify(value);
|
|
302
|
-
case "Bytes": {
|
|
303
|
-
if (!Array.isArray(value)) {
|
|
304
|
-
throw new Error(`DataMapper: Bytes data is invalid, got: ${typeof value}`);
|
|
305
|
-
}
|
|
306
|
-
return new Uint8Array(value);
|
|
307
|
-
}
|
|
308
|
-
default:
|
|
309
|
-
assertNever(resultType, `DataMapper: Unknown result type: ${resultType.type}`);
|
|
310
|
-
}
|
|
311
|
-
}
|
|
312
|
-
|
|
313
493
|
// src/interpreter/generators.ts
|
|
314
494
|
var import_cuid = __toESM(require("@bugsnag/cuid"));
|
|
315
495
|
var import_cuid2 = require("@paralleldrive/cuid2");
|
|
@@ -319,7 +499,6 @@ var import_uuid = require("uuid");
|
|
|
319
499
|
var GeneratorRegistry = class {
|
|
320
500
|
#generators = {};
|
|
321
501
|
constructor() {
|
|
322
|
-
this.register("now", new NowGenerator());
|
|
323
502
|
this.register("uuid", new UuidGenerator());
|
|
324
503
|
this.register("cuid", new CuidGenerator());
|
|
325
504
|
this.register("ulid", new UlidGenerator());
|
|
@@ -331,9 +510,11 @@ var GeneratorRegistry = class {
|
|
|
331
510
|
* method being called, meaning that the built-in time-based generators will always return
|
|
332
511
|
* the same value on repeated calls as long as the same snapshot is used.
|
|
333
512
|
*/
|
|
334
|
-
snapshot() {
|
|
513
|
+
snapshot(provider) {
|
|
335
514
|
return Object.create(this.#generators, {
|
|
336
|
-
now: {
|
|
515
|
+
now: {
|
|
516
|
+
value: provider === "mysql" ? new MysqlNowGenerator() : new NowGenerator()
|
|
517
|
+
}
|
|
337
518
|
});
|
|
338
519
|
}
|
|
339
520
|
/**
|
|
@@ -349,6 +530,12 @@ var NowGenerator = class {
|
|
|
349
530
|
return this.#now.toISOString();
|
|
350
531
|
}
|
|
351
532
|
};
|
|
533
|
+
var MysqlNowGenerator = class {
|
|
534
|
+
#now = /* @__PURE__ */ new Date();
|
|
535
|
+
generate() {
|
|
536
|
+
return this.#now.toISOString().replace("T", " ").replace("Z", "");
|
|
537
|
+
}
|
|
538
|
+
};
|
|
352
539
|
var UuidGenerator = class {
|
|
353
540
|
generate(arg) {
|
|
354
541
|
if (arg === 4) {
|
|
@@ -414,6 +601,9 @@ function isPrismaValueGenerator(value) {
|
|
|
414
601
|
function isPrismaValueBytes(value) {
|
|
415
602
|
return typeof value === "object" && value !== null && value["prisma__type"] === "bytes";
|
|
416
603
|
}
|
|
604
|
+
function isPrismaValueBigInt(value) {
|
|
605
|
+
return typeof value === "object" && value !== null && value["prisma__type"] === "bigint";
|
|
606
|
+
}
|
|
417
607
|
|
|
418
608
|
// src/interpreter/renderQuery.ts
|
|
419
609
|
function renderQuery(dbQuery, scope, generators) {
|
|
@@ -456,9 +646,10 @@ function evaluateParam(param, scope, generators) {
|
|
|
456
646
|
}
|
|
457
647
|
if (Array.isArray(value)) {
|
|
458
648
|
value = value.map((el) => evaluateParam(el, scope, generators));
|
|
459
|
-
}
|
|
460
|
-
if (isPrismaValueBytes(value)) {
|
|
649
|
+
} else if (isPrismaValueBytes(value)) {
|
|
461
650
|
value = Buffer.from(value.prisma__value, "base64");
|
|
651
|
+
} else if (isPrismaValueBigInt(value)) {
|
|
652
|
+
value = BigInt(value.prisma__value);
|
|
462
653
|
}
|
|
463
654
|
return value;
|
|
464
655
|
}
|
|
@@ -552,6 +743,7 @@ function doesRequireEvaluation(param) {
|
|
|
552
743
|
}
|
|
553
744
|
|
|
554
745
|
// src/interpreter/serializeSql.ts
|
|
746
|
+
var import_driver_adapter_utils2 = require("@prisma/driver-adapter-utils");
|
|
555
747
|
function serializeSql(resultSet) {
|
|
556
748
|
return resultSet.rows.map(
|
|
557
749
|
(row) => row.reduce((acc, value, index) => {
|
|
@@ -572,6 +764,100 @@ function serializeSql(resultSet) {
|
|
|
572
764
|
}, {})
|
|
573
765
|
);
|
|
574
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
|
+
}
|
|
575
861
|
|
|
576
862
|
// src/interpreter/validation.ts
|
|
577
863
|
function performValidation(data, rules, error) {
|
|
@@ -599,6 +885,8 @@ function doesSatisfyRule(data, rule) {
|
|
|
599
885
|
return rule.args !== 0;
|
|
600
886
|
}
|
|
601
887
|
return rule.args !== 1;
|
|
888
|
+
case "affectedRowCountEq":
|
|
889
|
+
return data === rule.args;
|
|
602
890
|
case "never":
|
|
603
891
|
return false;
|
|
604
892
|
default:
|
|
@@ -616,7 +904,9 @@ function renderMessage(data, error) {
|
|
|
616
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}'.`;
|
|
617
905
|
}
|
|
618
906
|
case "INCOMPLETE_CONNECT_INPUT":
|
|
619
|
-
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}.`;
|
|
620
910
|
case "RECORDS_NOT_CONNECTED":
|
|
621
911
|
return `The records for relation \`${error.context.relation}\` between the \`${error.context.parent}\` and \`${error.context.child}\` models are not connected.`;
|
|
622
912
|
default:
|
|
@@ -629,6 +919,8 @@ function getErrorCode2(error) {
|
|
|
629
919
|
return "P2014";
|
|
630
920
|
case "RECORDS_NOT_CONNECTED":
|
|
631
921
|
return "P2017";
|
|
922
|
+
case "INCOMPLETE_CONNECT_OUTPUT":
|
|
923
|
+
return "P2018";
|
|
632
924
|
case "MISSING_RECORD":
|
|
633
925
|
case "MISSING_RELATED_RECORD":
|
|
634
926
|
case "INCOMPLETE_CONNECT_INPUT":
|
|
@@ -646,12 +938,21 @@ var QueryInterpreter = class _QueryInterpreter {
|
|
|
646
938
|
#generators = new GeneratorRegistry();
|
|
647
939
|
#tracingHelper;
|
|
648
940
|
#serializer;
|
|
649
|
-
|
|
941
|
+
#rawSerializer;
|
|
942
|
+
constructor({
|
|
943
|
+
transactionManager,
|
|
944
|
+
placeholderValues,
|
|
945
|
+
onQuery,
|
|
946
|
+
tracingHelper,
|
|
947
|
+
serializer,
|
|
948
|
+
rawSerializer
|
|
949
|
+
}) {
|
|
650
950
|
this.#transactionManager = transactionManager;
|
|
651
951
|
this.#placeholderValues = placeholderValues;
|
|
652
952
|
this.#onQuery = onQuery;
|
|
653
953
|
this.#tracingHelper = tracingHelper;
|
|
654
954
|
this.#serializer = serializer;
|
|
955
|
+
this.#rawSerializer = rawSerializer ?? serializer;
|
|
655
956
|
}
|
|
656
957
|
static forSql(options) {
|
|
657
958
|
return new _QueryInterpreter({
|
|
@@ -659,13 +960,18 @@ var QueryInterpreter = class _QueryInterpreter {
|
|
|
659
960
|
placeholderValues: options.placeholderValues,
|
|
660
961
|
onQuery: options.onQuery,
|
|
661
962
|
tracingHelper: options.tracingHelper,
|
|
662
|
-
serializer: serializeSql
|
|
963
|
+
serializer: serializeSql,
|
|
964
|
+
rawSerializer: serializeRawSql
|
|
663
965
|
});
|
|
664
966
|
}
|
|
665
967
|
async run(queryPlan, queryable) {
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
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;
|
|
669
975
|
}
|
|
670
976
|
async interpretNode(node, queryable, scope, generators) {
|
|
671
977
|
switch (node.type) {
|
|
@@ -674,15 +980,16 @@ var QueryInterpreter = class _QueryInterpreter {
|
|
|
674
980
|
for (const arg of node.args) {
|
|
675
981
|
result = await this.interpretNode(arg, queryable, scope, generators);
|
|
676
982
|
}
|
|
677
|
-
return result;
|
|
983
|
+
return result ?? { value: void 0 };
|
|
678
984
|
}
|
|
679
985
|
case "get": {
|
|
680
|
-
return scope[node.args.name];
|
|
986
|
+
return { value: scope[node.args.name] };
|
|
681
987
|
}
|
|
682
988
|
case "let": {
|
|
683
989
|
const nestedScope = Object.create(scope);
|
|
684
990
|
for (const binding of node.args.bindings) {
|
|
685
|
-
|
|
991
|
+
const { value } = await this.interpretNode(binding.expr, queryable, nestedScope, generators);
|
|
992
|
+
nestedScope[binding.name] = value;
|
|
686
993
|
}
|
|
687
994
|
return this.interpretNode(node.args.expr, queryable, nestedScope, generators);
|
|
688
995
|
}
|
|
@@ -690,71 +997,87 @@ var QueryInterpreter = class _QueryInterpreter {
|
|
|
690
997
|
for (const name of node.args.names) {
|
|
691
998
|
const value = scope[name];
|
|
692
999
|
if (!isEmpty(value)) {
|
|
693
|
-
return value;
|
|
1000
|
+
return { value };
|
|
694
1001
|
}
|
|
695
1002
|
}
|
|
696
|
-
return [];
|
|
1003
|
+
return { value: [] };
|
|
697
1004
|
}
|
|
698
1005
|
case "concat": {
|
|
699
|
-
const parts = await Promise.all(
|
|
700
|
-
|
|
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
|
+
};
|
|
701
1012
|
}
|
|
702
1013
|
case "sum": {
|
|
703
|
-
const parts = await Promise.all(
|
|
704
|
-
|
|
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
|
+
};
|
|
705
1020
|
}
|
|
706
1021
|
case "execute": {
|
|
707
1022
|
const query = renderQuery(node.args, scope, generators);
|
|
708
|
-
return this.#
|
|
709
|
-
return await queryable.executeRaw(query);
|
|
1023
|
+
return this.#withQuerySpanAndEvent(query, queryable, async () => {
|
|
1024
|
+
return { value: await queryable.executeRaw(query) };
|
|
710
1025
|
});
|
|
711
1026
|
}
|
|
712
1027
|
case "query": {
|
|
713
1028
|
const query = renderQuery(node.args, scope, generators);
|
|
714
|
-
return this.#
|
|
715
|
-
|
|
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
|
+
}
|
|
716
1036
|
});
|
|
717
1037
|
}
|
|
718
1038
|
case "reverse": {
|
|
719
|
-
const value = await this.interpretNode(node.args, queryable, scope, generators);
|
|
720
|
-
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 };
|
|
721
1041
|
}
|
|
722
1042
|
case "unique": {
|
|
723
|
-
const value = await this.interpretNode(node.args, queryable, scope, generators);
|
|
1043
|
+
const { value, lastInsertId } = await this.interpretNode(node.args, queryable, scope, generators);
|
|
724
1044
|
if (!Array.isArray(value)) {
|
|
725
|
-
return value;
|
|
1045
|
+
return { value, lastInsertId };
|
|
726
1046
|
}
|
|
727
1047
|
if (value.length > 1) {
|
|
728
1048
|
throw new Error(`Expected zero or one element, got ${value.length}`);
|
|
729
1049
|
}
|
|
730
|
-
return value[0] ?? null;
|
|
1050
|
+
return { value: value[0] ?? null, lastInsertId };
|
|
731
1051
|
}
|
|
732
1052
|
case "required": {
|
|
733
|
-
const value = await this.interpretNode(node.args, queryable, scope, generators);
|
|
1053
|
+
const { value, lastInsertId } = await this.interpretNode(node.args, queryable, scope, generators);
|
|
734
1054
|
if (isEmpty(value)) {
|
|
735
1055
|
throw new Error("Required value is empty");
|
|
736
1056
|
}
|
|
737
|
-
return value;
|
|
1057
|
+
return { value, lastInsertId };
|
|
738
1058
|
}
|
|
739
1059
|
case "mapField": {
|
|
740
|
-
const value = await this.interpretNode(node.args.records, queryable, scope, generators);
|
|
741
|
-
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 };
|
|
742
1062
|
}
|
|
743
1063
|
case "join": {
|
|
744
|
-
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
|
+
}
|
|
745
1068
|
const children = await Promise.all(
|
|
746
1069
|
node.args.children.map(async (joinExpr) => ({
|
|
747
1070
|
joinExpr,
|
|
748
|
-
childRecords: await this.interpretNode(joinExpr.child, queryable, scope, generators)
|
|
1071
|
+
childRecords: (await this.interpretNode(joinExpr.child, queryable, scope, generators)).value
|
|
749
1072
|
}))
|
|
750
1073
|
);
|
|
751
1074
|
if (Array.isArray(parent)) {
|
|
752
1075
|
for (const record of parent) {
|
|
753
1076
|
attachChildrenToParent(asRecord(record), children);
|
|
754
1077
|
}
|
|
755
|
-
return parent;
|
|
1078
|
+
return { value: parent, lastInsertId };
|
|
756
1079
|
}
|
|
757
|
-
return attachChildrenToParent(asRecord(parent), children);
|
|
1080
|
+
return { value: attachChildrenToParent(asRecord(parent), children), lastInsertId };
|
|
758
1081
|
}
|
|
759
1082
|
case "transaction": {
|
|
760
1083
|
if (!this.#transactionManager.enabled) {
|
|
@@ -773,16 +1096,16 @@ var QueryInterpreter = class _QueryInterpreter {
|
|
|
773
1096
|
}
|
|
774
1097
|
}
|
|
775
1098
|
case "dataMap": {
|
|
776
|
-
const
|
|
777
|
-
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 };
|
|
778
1101
|
}
|
|
779
1102
|
case "validate": {
|
|
780
|
-
const
|
|
781
|
-
performValidation(
|
|
782
|
-
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 };
|
|
783
1106
|
}
|
|
784
1107
|
case "if": {
|
|
785
|
-
const value = await this.interpretNode(node.args.value, queryable, scope, generators);
|
|
1108
|
+
const { value } = await this.interpretNode(node.args.value, queryable, scope, generators);
|
|
786
1109
|
if (doesSatisfyRule(value, node.args.rule)) {
|
|
787
1110
|
return await this.interpretNode(node.args.then, queryable, scope, generators);
|
|
788
1111
|
} else {
|
|
@@ -790,16 +1113,16 @@ var QueryInterpreter = class _QueryInterpreter {
|
|
|
790
1113
|
}
|
|
791
1114
|
}
|
|
792
1115
|
case "unit": {
|
|
793
|
-
return void 0;
|
|
1116
|
+
return { value: void 0 };
|
|
794
1117
|
}
|
|
795
1118
|
case "diff": {
|
|
796
|
-
const from = await this.interpretNode(node.args.from, queryable, scope, generators);
|
|
797
|
-
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);
|
|
798
1121
|
const toSet = new Set(asList(to));
|
|
799
|
-
return asList(from).filter((item) => !toSet.has(item));
|
|
1122
|
+
return { value: asList(from).filter((item) => !toSet.has(item)) };
|
|
800
1123
|
}
|
|
801
1124
|
case "distinctBy": {
|
|
802
|
-
const value = await this.interpretNode(node.args.expr, queryable, scope, generators);
|
|
1125
|
+
const { value, lastInsertId } = await this.interpretNode(node.args.expr, queryable, scope, generators);
|
|
803
1126
|
const seen = /* @__PURE__ */ new Set();
|
|
804
1127
|
const result = [];
|
|
805
1128
|
for (const item of asList(value)) {
|
|
@@ -809,10 +1132,10 @@ var QueryInterpreter = class _QueryInterpreter {
|
|
|
809
1132
|
result.push(item);
|
|
810
1133
|
}
|
|
811
1134
|
}
|
|
812
|
-
return result;
|
|
1135
|
+
return { value: result, lastInsertId };
|
|
813
1136
|
}
|
|
814
1137
|
case "paginate": {
|
|
815
|
-
const value = await this.interpretNode(node.args.expr, queryable, scope, generators);
|
|
1138
|
+
const { value, lastInsertId } = await this.interpretNode(node.args.expr, queryable, scope, generators);
|
|
816
1139
|
const list = asList(value);
|
|
817
1140
|
const linkingFields = node.args.pagination.linkingFields;
|
|
818
1141
|
if (linkingFields !== null) {
|
|
@@ -826,38 +1149,37 @@ var QueryInterpreter = class _QueryInterpreter {
|
|
|
826
1149
|
}
|
|
827
1150
|
const groupList = Array.from(groupedByParent.entries());
|
|
828
1151
|
groupList.sort(([aId], [bId]) => aId < bId ? -1 : aId > bId ? 1 : 0);
|
|
829
|
-
return
|
|
1152
|
+
return {
|
|
1153
|
+
value: groupList.flatMap(([, elems]) => paginate(elems, node.args.pagination)),
|
|
1154
|
+
lastInsertId
|
|
1155
|
+
};
|
|
830
1156
|
}
|
|
831
|
-
return paginate(list, node.args.pagination);
|
|
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 };
|
|
832
1170
|
}
|
|
833
1171
|
default:
|
|
834
1172
|
assertNever(node, `Unexpected node type: ${node.type}`);
|
|
835
1173
|
}
|
|
836
1174
|
}
|
|
837
|
-
#
|
|
838
|
-
return
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
}
|
|
846
|
-
},
|
|
847
|
-
async () => {
|
|
848
|
-
const timestamp = /* @__PURE__ */ new Date();
|
|
849
|
-
const startInstant = performance.now();
|
|
850
|
-
const result = await execute();
|
|
851
|
-
const endInstant = performance.now();
|
|
852
|
-
this.#onQuery?.({
|
|
853
|
-
timestamp,
|
|
854
|
-
duration: endInstant - startInstant,
|
|
855
|
-
query: query.sql,
|
|
856
|
-
params: query.args
|
|
857
|
-
});
|
|
858
|
-
return result;
|
|
859
|
-
}
|
|
860
|
-
);
|
|
1175
|
+
#withQuerySpanAndEvent(query, queryable, execute) {
|
|
1176
|
+
return withQuerySpanAndEvent({
|
|
1177
|
+
query,
|
|
1178
|
+
queryable,
|
|
1179
|
+
execute,
|
|
1180
|
+
tracingHelper: this.#tracingHelper,
|
|
1181
|
+
onQuery: this.#onQuery
|
|
1182
|
+
});
|
|
861
1183
|
}
|
|
862
1184
|
};
|
|
863
1185
|
function isEmpty(value) {
|
|
@@ -923,7 +1245,7 @@ function childRecordMatchesParent(childRecord, parentRecord, joinExpr) {
|
|
|
923
1245
|
return true;
|
|
924
1246
|
}
|
|
925
1247
|
function paginate(list, { cursor, skip, take }) {
|
|
926
|
-
const cursorIndex = cursor !== null ? list.findIndex((item) =>
|
|
1248
|
+
const cursorIndex = cursor !== null ? list.findIndex((item) => doKeysMatch(item, cursor)) : 0;
|
|
927
1249
|
if (cursorIndex === -1) {
|
|
928
1250
|
return [];
|
|
929
1251
|
}
|
|
@@ -934,14 +1256,6 @@ function paginate(list, { cursor, skip, take }) {
|
|
|
934
1256
|
function getRecordKey(record, fields) {
|
|
935
1257
|
return JSON.stringify(fields.map((field) => record[field]));
|
|
936
1258
|
}
|
|
937
|
-
function doesMatchCursor(item, cursor) {
|
|
938
|
-
return Object.keys(cursor).every((key) => {
|
|
939
|
-
if (typeof item[key] !== typeof cursor[key] && (typeof item[key] === "number" || typeof cursor[key] === "number")) {
|
|
940
|
-
return `${item[key]}` === `${cursor[key]}`;
|
|
941
|
-
}
|
|
942
|
-
return isDeepStrictEqual(cursor[key], item[key]);
|
|
943
|
-
});
|
|
944
|
-
}
|
|
945
1259
|
|
|
946
1260
|
// src/transactionManager/TransactionManager.ts
|
|
947
1261
|
var import_debug = require("@prisma/debug");
|
|
@@ -956,12 +1270,11 @@ async function randomUUID() {
|
|
|
956
1270
|
}
|
|
957
1271
|
|
|
958
1272
|
// src/transactionManager/TransactionManagerErrors.ts
|
|
959
|
-
var TransactionManagerError = class extends
|
|
1273
|
+
var TransactionManagerError = class extends UserFacingError {
|
|
1274
|
+
name = "TransactionManagerError";
|
|
960
1275
|
constructor(message, meta) {
|
|
961
|
-
super("Transaction API error: " + message);
|
|
962
|
-
this.meta = meta;
|
|
1276
|
+
super("Transaction API error: " + message, "P2028", meta);
|
|
963
1277
|
}
|
|
964
|
-
code = "P2028";
|
|
965
1278
|
};
|
|
966
1279
|
var TransactionNotFoundError = class extends TransactionManagerError {
|
|
967
1280
|
constructor() {
|
|
@@ -972,12 +1285,12 @@ var TransactionNotFoundError = class extends TransactionManagerError {
|
|
|
972
1285
|
};
|
|
973
1286
|
var TransactionClosedError = class extends TransactionManagerError {
|
|
974
1287
|
constructor(operation) {
|
|
975
|
-
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.`);
|
|
976
1289
|
}
|
|
977
1290
|
};
|
|
978
1291
|
var TransactionRolledBackError = class extends TransactionManagerError {
|
|
979
1292
|
constructor(operation) {
|
|
980
|
-
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.`);
|
|
981
1294
|
}
|
|
982
1295
|
};
|
|
983
1296
|
var TransactionStartTimeoutError = class extends TransactionManagerError {
|
|
@@ -1009,6 +1322,16 @@ var MAX_CLOSED_TRANSACTIONS = 100;
|
|
|
1009
1322
|
var debug = (0, import_debug.Debug)("prisma:client:transactionManager");
|
|
1010
1323
|
var COMMIT_QUERY = () => ({ sql: "COMMIT", args: [], argTypes: [] });
|
|
1011
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
|
+
});
|
|
1012
1335
|
var TransactionManager = class {
|
|
1013
1336
|
// The map of active transactions.
|
|
1014
1337
|
transactions = /* @__PURE__ */ new Map();
|
|
@@ -1018,14 +1341,17 @@ var TransactionManager = class {
|
|
|
1018
1341
|
driverAdapter;
|
|
1019
1342
|
transactionOptions;
|
|
1020
1343
|
tracingHelper;
|
|
1344
|
+
#onQuery;
|
|
1021
1345
|
constructor({
|
|
1022
1346
|
driverAdapter,
|
|
1023
1347
|
transactionOptions,
|
|
1024
|
-
tracingHelper
|
|
1348
|
+
tracingHelper,
|
|
1349
|
+
onQuery
|
|
1025
1350
|
}) {
|
|
1026
1351
|
this.driverAdapter = driverAdapter;
|
|
1027
1352
|
this.transactionOptions = transactionOptions;
|
|
1028
1353
|
this.tracingHelper = tracingHelper;
|
|
1354
|
+
this.#onQuery = onQuery;
|
|
1029
1355
|
}
|
|
1030
1356
|
async startTransaction(options) {
|
|
1031
1357
|
return await this.tracingHelper.runInChildSpan("start_transaction", () => this.#startTransactionImpl(options));
|
|
@@ -1129,14 +1455,20 @@ var TransactionManager = class {
|
|
|
1129
1455
|
debug("Closing transaction.", { transactionId: tx.id, status });
|
|
1130
1456
|
tx.status = status;
|
|
1131
1457
|
if (tx.transaction && status === "committed") {
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
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));
|
|
1135
1464
|
}
|
|
1136
1465
|
} else if (tx.transaction) {
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
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));
|
|
1140
1472
|
}
|
|
1141
1473
|
}
|
|
1142
1474
|
clearTimeout(tx.timer);
|
|
@@ -1157,16 +1489,29 @@ var TransactionManager = class {
|
|
|
1157
1489
|
maxWait: options.maxWait
|
|
1158
1490
|
};
|
|
1159
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
|
+
}
|
|
1160
1501
|
};
|
|
1161
1502
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1162
1503
|
0 && (module.exports = {
|
|
1504
|
+
DataMapperError,
|
|
1163
1505
|
QueryInterpreter,
|
|
1164
1506
|
TransactionManager,
|
|
1165
1507
|
TransactionManagerError,
|
|
1166
1508
|
UserFacingError,
|
|
1509
|
+
doKeysMatch,
|
|
1167
1510
|
isDeepStrictEqual,
|
|
1511
|
+
isPrismaValueBigInt,
|
|
1168
1512
|
isPrismaValueBytes,
|
|
1169
1513
|
isPrismaValueGenerator,
|
|
1170
1514
|
isPrismaValuePlaceholder,
|
|
1171
|
-
noopTracingHelper
|
|
1515
|
+
noopTracingHelper,
|
|
1516
|
+
safeJsonStringify
|
|
1172
1517
|
});
|