@prisma/client-engine-runtime 6.6.0-dev.8 → 6.6.0-dev.80
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 +28 -2
- package/dist/crypto.d.ts +1 -0
- package/dist/index.d.mts +39 -17
- package/dist/index.d.ts +39 -17
- package/dist/index.js +222 -232
- package/dist/index.mjs +219 -231
- package/dist/interpreter/QueryInterpreter.d.ts +2 -2
- package/dist/interpreter/generators.d.ts +21 -0
- package/dist/interpreter/renderQuery.d.ts +3 -2
- package/dist/interpreter/renderQuery.test.d.ts +1 -0
- package/dist/transactionManager/Transaction.d.ts +1 -7
- package/dist/transactionManager/TransactionManager.d.ts +3 -4
- package/package.json +9 -4
- package/dist/interpreter/renderQueryTemplate.d.ts +0 -10
- /package/dist/interpreter/{renderQueryTemplate.test.d.ts → generators.test.d.ts} +0 -0
package/dist/index.mjs
CHANGED
|
@@ -1,121 +1,119 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
// src/interpreter/generators.ts
|
|
2
|
+
import cuid1 from "@bugsnag/cuid";
|
|
3
|
+
import { createId as cuid2 } from "@paralleldrive/cuid2";
|
|
4
|
+
import { nanoid } from "nanoid";
|
|
5
|
+
import { ulid } from "ulid";
|
|
6
|
+
import { v4 as uuidv4, v7 as uuidv7 } from "uuid";
|
|
7
|
+
var GeneratorRegistry = class {
|
|
8
|
+
#generators = {};
|
|
9
|
+
constructor() {
|
|
10
|
+
this.register("now", new NowGenerator());
|
|
11
|
+
this.register("uuid", new UuidGenerator());
|
|
12
|
+
this.register("cuid", new CuidGenerator());
|
|
13
|
+
this.register("ulid", new UlidGenerator());
|
|
14
|
+
this.register("nanoid", new NanoIdGenerator());
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Returns a snapshot of the generator registry. It's 'frozen' in time at the moment of this
|
|
18
|
+
* method being called, meaning that the built-in time-based generators will always return
|
|
19
|
+
* the same value on repeated calls as long as the same snapshot is used.
|
|
20
|
+
*/
|
|
21
|
+
snapshot() {
|
|
22
|
+
return Object.create(this.#generators, {
|
|
23
|
+
now: { value: new NowGenerator() }
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Registers a new generator with the given name.
|
|
28
|
+
*/
|
|
29
|
+
register(name, generator) {
|
|
30
|
+
this.#generators[name] = generator;
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
var NowGenerator = class {
|
|
34
|
+
#now = /* @__PURE__ */ new Date();
|
|
35
|
+
generate() {
|
|
36
|
+
return this.#now.toISOString();
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
var UuidGenerator = class {
|
|
40
|
+
generate(arg) {
|
|
41
|
+
if (arg === 4) {
|
|
42
|
+
return uuidv4();
|
|
43
|
+
} else if (arg === 7) {
|
|
44
|
+
return uuidv7();
|
|
45
|
+
} else {
|
|
46
|
+
throw new Error("Invalid UUID generator arguments");
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
var CuidGenerator = class {
|
|
51
|
+
generate(arg) {
|
|
52
|
+
if (arg === 1) {
|
|
53
|
+
return cuid1();
|
|
54
|
+
} else if (arg === 2) {
|
|
55
|
+
return cuid2();
|
|
56
|
+
} else {
|
|
57
|
+
throw new Error("Invalid CUID generator arguments");
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
var UlidGenerator = class {
|
|
62
|
+
generate() {
|
|
63
|
+
return ulid();
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
var NanoIdGenerator = class {
|
|
67
|
+
generate(arg) {
|
|
68
|
+
if (typeof arg === "number") {
|
|
69
|
+
return nanoid(arg);
|
|
70
|
+
} else if (arg === void 0) {
|
|
71
|
+
return nanoid();
|
|
72
|
+
} else {
|
|
73
|
+
throw new Error("Invalid Nanoid generator arguments");
|
|
74
|
+
}
|
|
75
|
+
}
|
|
4
76
|
};
|
|
5
|
-
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
6
|
-
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
7
|
-
var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg);
|
|
8
|
-
var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
|
|
9
|
-
var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
|
|
10
|
-
var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value);
|
|
11
|
-
var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method);
|
|
12
77
|
|
|
13
78
|
// src/QueryPlan.ts
|
|
14
79
|
function isPrismaValuePlaceholder(value) {
|
|
15
80
|
return typeof value === "object" && value !== null && value["prisma__type"] === "param";
|
|
16
81
|
}
|
|
82
|
+
function isPrismaValueGenerator(value) {
|
|
83
|
+
return typeof value === "object" && value !== null && value["prisma__type"] === "generatorCall";
|
|
84
|
+
}
|
|
17
85
|
|
|
18
|
-
// src/
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
function renderQueryTemplate({
|
|
22
|
-
query,
|
|
23
|
-
params
|
|
24
|
-
}) {
|
|
25
|
-
if (!query.includes(BEGIN_REPEAT)) {
|
|
26
|
-
return { query, params };
|
|
27
|
-
}
|
|
28
|
-
const flattenedParams = [];
|
|
29
|
-
let lastParamId = 1;
|
|
30
|
-
let result = "";
|
|
31
|
-
let templatePos = 0;
|
|
32
|
-
let state = 0 /* Normal */;
|
|
33
|
-
let stateBeforeQuote = 0 /* Normal */;
|
|
34
|
-
while (templatePos < query.length) {
|
|
35
|
-
const nextChar = query[templatePos];
|
|
36
|
-
if (state === 1 /* Quoted */ && nextChar !== '"') {
|
|
37
|
-
result += nextChar;
|
|
38
|
-
templatePos++;
|
|
39
|
-
continue;
|
|
40
|
-
}
|
|
41
|
-
if (nextChar === '"') {
|
|
42
|
-
if (state === 1 /* Quoted */) {
|
|
43
|
-
state = stateBeforeQuote;
|
|
44
|
-
} else {
|
|
45
|
-
stateBeforeQuote = state;
|
|
46
|
-
state = 1 /* Quoted */;
|
|
47
|
-
}
|
|
48
|
-
result += nextChar;
|
|
49
|
-
templatePos++;
|
|
50
|
-
continue;
|
|
51
|
-
}
|
|
52
|
-
if (query.slice(templatePos, templatePos + BEGIN_REPEAT.length) === BEGIN_REPEAT) {
|
|
53
|
-
if (state === 2 /* Repeating */) {
|
|
54
|
-
throw new Error("Nested repetition is not allowed");
|
|
55
|
-
}
|
|
56
|
-
state = 2 /* Repeating */;
|
|
57
|
-
templatePos += BEGIN_REPEAT.length;
|
|
58
|
-
result += "(";
|
|
59
|
-
continue;
|
|
60
|
-
}
|
|
61
|
-
if (query.slice(templatePos, templatePos + END_REPEAT.length) === END_REPEAT) {
|
|
62
|
-
if (state === 0 /* Normal */) {
|
|
63
|
-
throw new Error("Unmatched repetition end");
|
|
64
|
-
}
|
|
65
|
-
state = 0 /* Normal */;
|
|
66
|
-
templatePos += END_REPEAT.length;
|
|
67
|
-
result += ")";
|
|
68
|
-
continue;
|
|
69
|
-
}
|
|
70
|
-
if (nextChar === "$") {
|
|
71
|
-
const paramMatch = query.slice(templatePos + 1).match(/^\d+/);
|
|
72
|
-
if (!paramMatch) {
|
|
73
|
-
result += "$";
|
|
74
|
-
templatePos++;
|
|
75
|
-
continue;
|
|
76
|
-
}
|
|
77
|
-
templatePos += paramMatch[0].length + 1;
|
|
78
|
-
const originalParamIdx = parseInt(paramMatch[0]);
|
|
79
|
-
const paramValue = params[originalParamIdx - 1];
|
|
80
|
-
switch (state) {
|
|
81
|
-
case 0 /* Normal */: {
|
|
82
|
-
flattenedParams.push(paramValue);
|
|
83
|
-
result += `$${lastParamId++}`;
|
|
84
|
-
break;
|
|
85
|
-
}
|
|
86
|
-
case 2 /* Repeating */: {
|
|
87
|
-
const paramArray = Array.isArray(paramValue) ? paramValue : [paramValue];
|
|
88
|
-
if (paramArray.length === 0) {
|
|
89
|
-
result += "NULL";
|
|
90
|
-
break;
|
|
91
|
-
}
|
|
92
|
-
paramArray.forEach((value, idx) => {
|
|
93
|
-
flattenedParams.push(value);
|
|
94
|
-
result += `$${lastParamId++}`;
|
|
95
|
-
if (idx !== paramArray.length - 1) {
|
|
96
|
-
result += ", ";
|
|
97
|
-
}
|
|
98
|
-
});
|
|
99
|
-
break;
|
|
100
|
-
}
|
|
101
|
-
default: {
|
|
102
|
-
throw new Error(`Unexpected state: ${state}`);
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
continue;
|
|
106
|
-
}
|
|
107
|
-
result += nextChar;
|
|
108
|
-
templatePos++;
|
|
109
|
-
}
|
|
110
|
-
return {
|
|
111
|
-
query: result,
|
|
112
|
-
params: flattenedParams
|
|
113
|
-
};
|
|
86
|
+
// src/utils.ts
|
|
87
|
+
function assertNever(_, message) {
|
|
88
|
+
throw new Error(message);
|
|
114
89
|
}
|
|
115
90
|
|
|
116
91
|
// src/interpreter/renderQuery.ts
|
|
117
|
-
function renderQuery(
|
|
118
|
-
const
|
|
92
|
+
function renderQuery(dbQuery, scope, generators) {
|
|
93
|
+
const queryType = dbQuery.type;
|
|
94
|
+
switch (queryType) {
|
|
95
|
+
case "rawSql":
|
|
96
|
+
return renderRawSql(dbQuery.sql, substituteParams(dbQuery.params, scope, generators));
|
|
97
|
+
case "templateSql":
|
|
98
|
+
return renderTemplateSql(
|
|
99
|
+
dbQuery.fragments,
|
|
100
|
+
dbQuery.placeholderFormat,
|
|
101
|
+
substituteParams(dbQuery.params, scope, generators)
|
|
102
|
+
);
|
|
103
|
+
default:
|
|
104
|
+
assertNever(queryType, `Invalid query type`);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
function substituteParams(params, scope, generators) {
|
|
108
|
+
return params.map((param) => {
|
|
109
|
+
if (isPrismaValueGenerator(param)) {
|
|
110
|
+
const { name, args } = param.prisma__value;
|
|
111
|
+
const generator = generators[name];
|
|
112
|
+
if (!generator) {
|
|
113
|
+
throw new Error(`Encountered an unknown generator '${name}'`);
|
|
114
|
+
}
|
|
115
|
+
return generator.generate(...args);
|
|
116
|
+
}
|
|
119
117
|
if (!isPrismaValuePlaceholder(param)) {
|
|
120
118
|
return param;
|
|
121
119
|
}
|
|
@@ -125,11 +123,48 @@ function renderQuery({ query, params }, scope) {
|
|
|
125
123
|
}
|
|
126
124
|
return value;
|
|
127
125
|
});
|
|
128
|
-
|
|
129
|
-
|
|
126
|
+
}
|
|
127
|
+
function renderTemplateSql(fragments, placeholderFormat, params) {
|
|
128
|
+
let paramIndex = 0;
|
|
129
|
+
let placeholderNumber = 1;
|
|
130
|
+
const flattenedParams = [];
|
|
131
|
+
const sql = fragments.map((fragment) => {
|
|
132
|
+
const fragmentType = fragment.type;
|
|
133
|
+
switch (fragmentType) {
|
|
134
|
+
case "parameter":
|
|
135
|
+
if (paramIndex >= params.length) {
|
|
136
|
+
throw new Error(`Malformed query template. Fragments attempt to read over ${params.length} parameters.`);
|
|
137
|
+
}
|
|
138
|
+
flattenedParams.push(params[paramIndex++]);
|
|
139
|
+
return formatPlaceholder(placeholderFormat, placeholderNumber++);
|
|
140
|
+
case "stringChunk":
|
|
141
|
+
return fragment.value;
|
|
142
|
+
case "parameterTuple": {
|
|
143
|
+
if (paramIndex >= params.length) {
|
|
144
|
+
throw new Error(`Malformed query template. Fragments attempt to read over ${params.length} parameters.`);
|
|
145
|
+
}
|
|
146
|
+
const paramValue = params[paramIndex++];
|
|
147
|
+
const paramArray = Array.isArray(paramValue) ? paramValue : [paramValue];
|
|
148
|
+
const placeholders = paramArray.length == 0 ? "NULL" : paramArray.map((value) => {
|
|
149
|
+
flattenedParams.push(value);
|
|
150
|
+
return formatPlaceholder(placeholderFormat, placeholderNumber++);
|
|
151
|
+
}).join(",");
|
|
152
|
+
return `(${placeholders})`;
|
|
153
|
+
}
|
|
154
|
+
default:
|
|
155
|
+
assertNever(fragmentType, "Invalid fragment type");
|
|
156
|
+
}
|
|
157
|
+
}).join("");
|
|
158
|
+
return renderRawSql(sql, flattenedParams);
|
|
159
|
+
}
|
|
160
|
+
function formatPlaceholder(placeholderFormat, placeholderNumber) {
|
|
161
|
+
return placeholderFormat.hasNumbering ? `${placeholderFormat.prefix}${placeholderNumber}` : placeholderFormat.prefix;
|
|
162
|
+
}
|
|
163
|
+
function renderRawSql(sql, params) {
|
|
164
|
+
const argTypes = params.map((param) => toArgType(param));
|
|
130
165
|
return {
|
|
131
|
-
sql
|
|
132
|
-
args:
|
|
166
|
+
sql,
|
|
167
|
+
args: params,
|
|
133
168
|
argTypes
|
|
134
169
|
};
|
|
135
170
|
}
|
|
@@ -198,24 +233,23 @@ function serialize(resultSet) {
|
|
|
198
233
|
}
|
|
199
234
|
|
|
200
235
|
// src/interpreter/QueryInterpreter.ts
|
|
201
|
-
var _queryable, _placeholderValues, _onQuery, _QueryInterpreter_instances, withQueryEvent_fn;
|
|
202
236
|
var QueryInterpreter = class {
|
|
237
|
+
#queryable;
|
|
238
|
+
#placeholderValues;
|
|
239
|
+
#onQuery;
|
|
240
|
+
#generators = new GeneratorRegistry();
|
|
203
241
|
constructor({ queryable, placeholderValues, onQuery }) {
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
__privateAdd(this, _onQuery);
|
|
208
|
-
__privateSet(this, _queryable, queryable);
|
|
209
|
-
__privateSet(this, _placeholderValues, placeholderValues);
|
|
210
|
-
__privateSet(this, _onQuery, onQuery);
|
|
242
|
+
this.#queryable = queryable;
|
|
243
|
+
this.#placeholderValues = placeholderValues;
|
|
244
|
+
this.#onQuery = onQuery;
|
|
211
245
|
}
|
|
212
246
|
async run(queryPlan) {
|
|
213
|
-
return this.interpretNode(queryPlan,
|
|
247
|
+
return this.interpretNode(queryPlan, this.#placeholderValues, this.#generators.snapshot());
|
|
214
248
|
}
|
|
215
|
-
async interpretNode(node, scope) {
|
|
249
|
+
async interpretNode(node, scope, generators) {
|
|
216
250
|
switch (node.type) {
|
|
217
251
|
case "seq": {
|
|
218
|
-
const results = await Promise.all(node.args.map((arg) => this.interpretNode(arg, scope)));
|
|
252
|
+
const results = await Promise.all(node.args.map((arg) => this.interpretNode(arg, scope, generators)));
|
|
219
253
|
return results[results.length - 1];
|
|
220
254
|
}
|
|
221
255
|
case "get": {
|
|
@@ -225,10 +259,10 @@ var QueryInterpreter = class {
|
|
|
225
259
|
const nestedScope = Object.create(scope);
|
|
226
260
|
await Promise.all(
|
|
227
261
|
node.args.bindings.map(async (binding) => {
|
|
228
|
-
nestedScope[binding.name] = await this.interpretNode(binding.expr, scope);
|
|
262
|
+
nestedScope[binding.name] = await this.interpretNode(binding.expr, scope, generators);
|
|
229
263
|
})
|
|
230
264
|
);
|
|
231
|
-
return this.interpretNode(node.args.expr, nestedScope);
|
|
265
|
+
return this.interpretNode(node.args.expr, nestedScope, generators);
|
|
232
266
|
}
|
|
233
267
|
case "getFirstNonEmpty": {
|
|
234
268
|
for (const name of node.args.names) {
|
|
@@ -240,41 +274,31 @@ var QueryInterpreter = class {
|
|
|
240
274
|
return [];
|
|
241
275
|
}
|
|
242
276
|
case "concat": {
|
|
243
|
-
const parts = await Promise.all(node.args.map((arg) => this.interpretNode(arg, scope)));
|
|
277
|
+
const parts = await Promise.all(node.args.map((arg) => this.interpretNode(arg, scope, generators)));
|
|
244
278
|
return parts.reduce((acc, part) => acc.concat(asList(part)), []);
|
|
245
279
|
}
|
|
246
280
|
case "sum": {
|
|
247
|
-
const parts = await Promise.all(node.args.map((arg) => this.interpretNode(arg, scope)));
|
|
281
|
+
const parts = await Promise.all(node.args.map((arg) => this.interpretNode(arg, scope, generators)));
|
|
248
282
|
return parts.reduce((acc, part) => asNumber(acc) + asNumber(part));
|
|
249
283
|
}
|
|
250
284
|
case "execute": {
|
|
251
|
-
const query = renderQuery(node.args, scope);
|
|
252
|
-
return
|
|
253
|
-
|
|
254
|
-
if (result.ok) {
|
|
255
|
-
return result.value;
|
|
256
|
-
} else {
|
|
257
|
-
throw result.error;
|
|
258
|
-
}
|
|
285
|
+
const query = renderQuery(node.args, scope, generators);
|
|
286
|
+
return this.#withQueryEvent(query, async () => {
|
|
287
|
+
return await this.#queryable.executeRaw(query);
|
|
259
288
|
});
|
|
260
289
|
}
|
|
261
290
|
case "query": {
|
|
262
|
-
const query = renderQuery(node.args, scope);
|
|
263
|
-
return
|
|
264
|
-
|
|
265
|
-
if (result.ok) {
|
|
266
|
-
return serialize(result.value);
|
|
267
|
-
} else {
|
|
268
|
-
throw result.error;
|
|
269
|
-
}
|
|
291
|
+
const query = renderQuery(node.args, scope, generators);
|
|
292
|
+
return this.#withQueryEvent(query, async () => {
|
|
293
|
+
return serialize(await this.#queryable.queryRaw(query));
|
|
270
294
|
});
|
|
271
295
|
}
|
|
272
296
|
case "reverse": {
|
|
273
|
-
const value = await this.interpretNode(node.args, scope);
|
|
297
|
+
const value = await this.interpretNode(node.args, scope, generators);
|
|
274
298
|
return Array.isArray(value) ? value.reverse() : value;
|
|
275
299
|
}
|
|
276
300
|
case "unique": {
|
|
277
|
-
const value = await this.interpretNode(node.args, scope);
|
|
301
|
+
const value = await this.interpretNode(node.args, scope, generators);
|
|
278
302
|
if (!Array.isArray(value)) {
|
|
279
303
|
return value;
|
|
280
304
|
}
|
|
@@ -284,22 +308,22 @@ var QueryInterpreter = class {
|
|
|
284
308
|
return value[0] ?? null;
|
|
285
309
|
}
|
|
286
310
|
case "required": {
|
|
287
|
-
const value = await this.interpretNode(node.args, scope);
|
|
311
|
+
const value = await this.interpretNode(node.args, scope, generators);
|
|
288
312
|
if (isEmpty(value)) {
|
|
289
313
|
throw new Error("Required value is empty");
|
|
290
314
|
}
|
|
291
315
|
return value;
|
|
292
316
|
}
|
|
293
317
|
case "mapField": {
|
|
294
|
-
const value = await this.interpretNode(node.args.records, scope);
|
|
318
|
+
const value = await this.interpretNode(node.args.records, scope, generators);
|
|
295
319
|
return mapField(value, node.args.field);
|
|
296
320
|
}
|
|
297
321
|
case "join": {
|
|
298
|
-
const parent = await this.interpretNode(node.args.parent, scope);
|
|
322
|
+
const parent = await this.interpretNode(node.args.parent, scope, generators);
|
|
299
323
|
const children = await Promise.all(
|
|
300
324
|
node.args.children.map(async (joinExpr) => ({
|
|
301
325
|
joinExpr,
|
|
302
|
-
childRecords: await this.interpretNode(joinExpr.child, scope)
|
|
326
|
+
childRecords: await this.interpretNode(joinExpr.child, scope, generators)
|
|
303
327
|
}))
|
|
304
328
|
);
|
|
305
329
|
if (Array.isArray(parent)) {
|
|
@@ -316,24 +340,19 @@ var QueryInterpreter = class {
|
|
|
316
340
|
}
|
|
317
341
|
}
|
|
318
342
|
}
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
duration: endInstant - startInstant,
|
|
333
|
-
query: query.sql,
|
|
334
|
-
params: query.args
|
|
335
|
-
});
|
|
336
|
-
return result;
|
|
343
|
+
async #withQueryEvent(query, execute) {
|
|
344
|
+
const timestamp = /* @__PURE__ */ new Date();
|
|
345
|
+
const startInstant = performance.now();
|
|
346
|
+
const result = await execute();
|
|
347
|
+
const endInstant = performance.now();
|
|
348
|
+
this.#onQuery?.({
|
|
349
|
+
timestamp,
|
|
350
|
+
duration: endInstant - startInstant,
|
|
351
|
+
query: query.sql,
|
|
352
|
+
params: query.args
|
|
353
|
+
});
|
|
354
|
+
return result;
|
|
355
|
+
}
|
|
337
356
|
};
|
|
338
357
|
function isEmpty(value) {
|
|
339
358
|
if (Array.isArray(value)) {
|
|
@@ -391,22 +410,16 @@ function childRecordMatchesParent(childRecord, parentRecord, joinExpr) {
|
|
|
391
410
|
return true;
|
|
392
411
|
}
|
|
393
412
|
|
|
394
|
-
// src/transactionManager/Transaction.ts
|
|
395
|
-
var IsolationLevel = /* @__PURE__ */ ((IsolationLevel2) => {
|
|
396
|
-
IsolationLevel2["ReadUncommitted"] = "ReadUncommitted";
|
|
397
|
-
IsolationLevel2["ReadCommitted"] = "ReadCommitted";
|
|
398
|
-
IsolationLevel2["RepeatableRead"] = "RepeatableRead";
|
|
399
|
-
IsolationLevel2["Snapshot"] = "Snapshot";
|
|
400
|
-
IsolationLevel2["Serializable"] = "Serializable";
|
|
401
|
-
return IsolationLevel2;
|
|
402
|
-
})(IsolationLevel || {});
|
|
403
|
-
|
|
404
413
|
// src/transactionManager/TransactionManager.ts
|
|
405
414
|
import Debug from "@prisma/debug";
|
|
406
415
|
|
|
407
|
-
// src/
|
|
408
|
-
function
|
|
409
|
-
|
|
416
|
+
// src/crypto.ts
|
|
417
|
+
async function getCrypto() {
|
|
418
|
+
return globalThis.crypto ?? await import("node:crypto");
|
|
419
|
+
}
|
|
420
|
+
async function randomUUID() {
|
|
421
|
+
const crypto = await getCrypto();
|
|
422
|
+
return crypto.randomUUID();
|
|
410
423
|
}
|
|
411
424
|
|
|
412
425
|
// src/transactionManager/TransactionManagerErrors.ts
|
|
@@ -414,8 +427,8 @@ var TransactionManagerError = class extends Error {
|
|
|
414
427
|
constructor(message, meta) {
|
|
415
428
|
super("Transaction API error: " + message);
|
|
416
429
|
this.meta = meta;
|
|
417
|
-
__publicField(this, "code", "P2028");
|
|
418
430
|
}
|
|
431
|
+
code = "P2028";
|
|
419
432
|
};
|
|
420
433
|
var TransactionDriverAdapterError = class extends TransactionManagerError {
|
|
421
434
|
constructor(message, errorParams) {
|
|
@@ -465,35 +478,23 @@ var InvalidTransactionIsolationLevelError = class extends TransactionManagerErro
|
|
|
465
478
|
|
|
466
479
|
// src/transactionManager/TransactionManager.ts
|
|
467
480
|
var MAX_CLOSED_TRANSACTIONS = 100;
|
|
468
|
-
var isolationLevelMap = {
|
|
469
|
-
ReadUncommitted: "READ UNCOMMITTED",
|
|
470
|
-
ReadCommitted: "READ COMMITTED",
|
|
471
|
-
RepeatableRead: "REPEATABLE READ",
|
|
472
|
-
Snapshot: "SNAPSHOT",
|
|
473
|
-
Serializable: "SERIALIZABLE"
|
|
474
|
-
};
|
|
475
481
|
var debug = Debug("prisma:client:transactionManager");
|
|
476
482
|
var COMMIT_QUERY = () => ({ sql: "COMMIT", args: [], argTypes: [] });
|
|
477
483
|
var ROLLBACK_QUERY = () => ({ sql: "ROLLBACK", args: [], argTypes: [] });
|
|
478
|
-
var ISOLATION_LEVEL_QUERY = (isolationLevel) => ({
|
|
479
|
-
sql: "SET TRANSACTION ISOLATION LEVEL " + isolationLevelMap[isolationLevel],
|
|
480
|
-
args: [],
|
|
481
|
-
argTypes: []
|
|
482
|
-
});
|
|
483
484
|
var TransactionManager = class {
|
|
485
|
+
// The map of active transactions.
|
|
486
|
+
transactions = /* @__PURE__ */ new Map();
|
|
487
|
+
// List of last closed transactions. Max MAX_CLOSED_TRANSACTIONS entries.
|
|
488
|
+
// Used to provide better error messages than a generic "transaction not found".
|
|
489
|
+
closedTransactions = [];
|
|
490
|
+
driverAdapter;
|
|
484
491
|
constructor({ driverAdapter }) {
|
|
485
|
-
// The map of active transactions.
|
|
486
|
-
__publicField(this, "transactions", /* @__PURE__ */ new Map());
|
|
487
|
-
// List of last closed transactions. Max MAX_CLOSED_TRANSACTIONS entries.
|
|
488
|
-
// Used to provide better error messages than a generic "transaction not found".
|
|
489
|
-
__publicField(this, "closedTransactions", []);
|
|
490
|
-
__publicField(this, "driverAdapter");
|
|
491
492
|
this.driverAdapter = driverAdapter;
|
|
492
493
|
}
|
|
493
494
|
async startTransaction(options) {
|
|
494
495
|
const validatedOptions = this.validateOptions(options);
|
|
495
496
|
const transaction = {
|
|
496
|
-
id:
|
|
497
|
+
id: await randomUUID(),
|
|
497
498
|
status: "waiting",
|
|
498
499
|
timer: void 0,
|
|
499
500
|
timeout: validatedOptions.timeout,
|
|
@@ -502,28 +503,17 @@ var TransactionManager = class {
|
|
|
502
503
|
};
|
|
503
504
|
this.transactions.set(transaction.id, transaction);
|
|
504
505
|
transaction.timer = this.startTransactionTimeout(transaction.id, validatedOptions.maxWait);
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
});
|
|
510
|
-
if (this.requiresSettingIsolationLevelFirst() && validatedOptions.isolationLevel) {
|
|
511
|
-
await txContext.value.executeRaw(ISOLATION_LEVEL_QUERY(validatedOptions.isolationLevel));
|
|
512
|
-
}
|
|
513
|
-
const startedTransaction = await txContext.value.startTransaction();
|
|
514
|
-
if (!startedTransaction.ok)
|
|
506
|
+
let startedTransaction;
|
|
507
|
+
try {
|
|
508
|
+
startedTransaction = await this.driverAdapter.startTransaction(validatedOptions.isolationLevel);
|
|
509
|
+
} catch (error) {
|
|
515
510
|
throw new TransactionDriverAdapterError("Failed to start transaction.", {
|
|
516
|
-
driverAdapterError:
|
|
511
|
+
driverAdapterError: error
|
|
517
512
|
});
|
|
518
|
-
if (!startedTransaction.value.options.usePhantomQuery) {
|
|
519
|
-
await startedTransaction.value.executeRaw({ sql: "BEGIN", args: [], argTypes: [] });
|
|
520
|
-
if (!this.requiresSettingIsolationLevelFirst() && validatedOptions.isolationLevel) {
|
|
521
|
-
await txContext.value.executeRaw(ISOLATION_LEVEL_QUERY(validatedOptions.isolationLevel));
|
|
522
|
-
}
|
|
523
513
|
}
|
|
524
514
|
switch (transaction.status) {
|
|
525
515
|
case "waiting":
|
|
526
|
-
transaction.transaction = startedTransaction
|
|
516
|
+
transaction.transaction = startedTransaction;
|
|
527
517
|
clearTimeout(transaction.timer);
|
|
528
518
|
transaction.timer = void 0;
|
|
529
519
|
transaction.status = "running";
|
|
@@ -603,20 +593,24 @@ var TransactionManager = class {
|
|
|
603
593
|
debug("Closing transaction.", { transactionId: tx.id, status });
|
|
604
594
|
tx.status = status;
|
|
605
595
|
if (tx.transaction && status === "committed") {
|
|
606
|
-
|
|
607
|
-
|
|
596
|
+
try {
|
|
597
|
+
await tx.transaction.commit();
|
|
598
|
+
} catch (error) {
|
|
608
599
|
throw new TransactionDriverAdapterError("Failed to commit transaction.", {
|
|
609
|
-
driverAdapterError:
|
|
600
|
+
driverAdapterError: error
|
|
610
601
|
});
|
|
602
|
+
}
|
|
611
603
|
if (!tx.transaction.options.usePhantomQuery) {
|
|
612
604
|
await tx.transaction.executeRaw(COMMIT_QUERY());
|
|
613
605
|
}
|
|
614
606
|
} else if (tx.transaction) {
|
|
615
|
-
|
|
616
|
-
|
|
607
|
+
try {
|
|
608
|
+
await tx.transaction.rollback();
|
|
609
|
+
} catch (error) {
|
|
617
610
|
throw new TransactionDriverAdapterError("Failed to rollback transaction.", {
|
|
618
|
-
driverAdapterError:
|
|
611
|
+
driverAdapterError: error
|
|
619
612
|
});
|
|
613
|
+
}
|
|
620
614
|
if (!tx.transaction.options.usePhantomQuery) {
|
|
621
615
|
await tx.transaction.executeRaw(ROLLBACK_QUERY());
|
|
622
616
|
}
|
|
@@ -632,24 +626,18 @@ var TransactionManager = class {
|
|
|
632
626
|
validateOptions(options) {
|
|
633
627
|
if (!options.timeout) throw new TransactionManagerError("timeout is required");
|
|
634
628
|
if (!options.maxWait) throw new TransactionManagerError("maxWait is required");
|
|
635
|
-
if (options.isolationLevel === "
|
|
636
|
-
throw new InvalidTransactionIsolationLevelError(options.isolationLevel);
|
|
637
|
-
if (this.driverAdapter.provider === "sqlite" && options.isolationLevel && options.isolationLevel !== "Serializable" /* Serializable */)
|
|
638
|
-
throw new InvalidTransactionIsolationLevelError(options.isolationLevel);
|
|
629
|
+
if (options.isolationLevel === "SNAPSHOT") throw new InvalidTransactionIsolationLevelError(options.isolationLevel);
|
|
639
630
|
return {
|
|
640
631
|
...options,
|
|
641
632
|
timeout: options.timeout,
|
|
642
633
|
maxWait: options.maxWait
|
|
643
634
|
};
|
|
644
635
|
}
|
|
645
|
-
requiresSettingIsolationLevelFirst() {
|
|
646
|
-
return this.driverAdapter.provider === "mysql";
|
|
647
|
-
}
|
|
648
636
|
};
|
|
649
637
|
export {
|
|
650
|
-
IsolationLevel,
|
|
651
638
|
QueryInterpreter,
|
|
652
639
|
TransactionManager,
|
|
653
640
|
TransactionManagerError,
|
|
641
|
+
isPrismaValueGenerator,
|
|
654
642
|
isPrismaValuePlaceholder
|
|
655
643
|
};
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { SqlQueryable } from '@prisma/driver-adapter-utils';
|
|
2
2
|
import { QueryEvent } from '../events';
|
|
3
3
|
import { QueryPlanNode } from '../QueryPlan';
|
|
4
4
|
export type QueryInterpreterOptions = {
|
|
5
|
-
queryable:
|
|
5
|
+
queryable: SqlQueryable;
|
|
6
6
|
placeholderValues: Record<string, unknown>;
|
|
7
7
|
onQuery?: (event: QueryEvent) => void;
|
|
8
8
|
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { PrismaValue } from '../QueryPlan';
|
|
2
|
+
export declare class GeneratorRegistry {
|
|
3
|
+
#private;
|
|
4
|
+
constructor();
|
|
5
|
+
/**
|
|
6
|
+
* Returns a snapshot of the generator registry. It's 'frozen' in time at the moment of this
|
|
7
|
+
* method being called, meaning that the built-in time-based generators will always return
|
|
8
|
+
* the same value on repeated calls as long as the same snapshot is used.
|
|
9
|
+
*/
|
|
10
|
+
snapshot(): Readonly<GeneratorRegistrySnapshot>;
|
|
11
|
+
/**
|
|
12
|
+
* Registers a new generator with the given name.
|
|
13
|
+
*/
|
|
14
|
+
register(name: string, generator: ValueGenerator): void;
|
|
15
|
+
}
|
|
16
|
+
export interface GeneratorRegistrySnapshot {
|
|
17
|
+
[key: string]: ValueGenerator;
|
|
18
|
+
}
|
|
19
|
+
export interface ValueGenerator {
|
|
20
|
+
generate(...args: PrismaValue[]): PrismaValue;
|
|
21
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { SqlQuery } from '@prisma/driver-adapter-utils';
|
|
2
|
-
import { QueryPlanDbQuery } from '../QueryPlan';
|
|
2
|
+
import type { QueryPlanDbQuery } from '../QueryPlan';
|
|
3
|
+
import { GeneratorRegistrySnapshot } from './generators';
|
|
3
4
|
import { ScopeBindings } from './scope';
|
|
4
|
-
export declare function renderQuery(
|
|
5
|
+
export declare function renderQuery(dbQuery: QueryPlanDbQuery, scope: ScopeBindings, generators: GeneratorRegistrySnapshot): SqlQuery;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,10 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
ReadUncommitted = "ReadUncommitted",
|
|
3
|
-
ReadCommitted = "ReadCommitted",
|
|
4
|
-
RepeatableRead = "RepeatableRead",
|
|
5
|
-
Snapshot = "Snapshot",
|
|
6
|
-
Serializable = "Serializable"
|
|
7
|
-
}
|
|
1
|
+
import type { IsolationLevel } from '@prisma/driver-adapter-utils';
|
|
8
2
|
export type Options = {
|
|
9
3
|
maxWait?: number;
|
|
10
4
|
timeout?: number;
|