@prisma/client-engine-runtime 6.7.0-dev.1 → 6.7.0-dev.10
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/UserFacingError.d.ts +16 -0
- package/dist/index.d.mts +37 -2
- package/dist/index.d.ts +37 -2
- package/dist/index.js +233 -61
- package/dist/index.mjs +230 -60
- package/dist/interpreter/QueryInterpreter.d.ts +3 -1
- package/dist/tracing.d.ts +11 -0
- package/dist/transactionManager/TransactionManager.d.ts +5 -1
- package/dist/transactionManager/TransactionManagerErrors.d.ts +1 -7
- package/package.json +4 -3
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export declare class UserFacingError extends Error {
|
|
2
|
+
name: string;
|
|
3
|
+
code: string;
|
|
4
|
+
meta: unknown;
|
|
5
|
+
constructor(message: string, code: string, meta?: unknown);
|
|
6
|
+
toQueryResponseErrorObject(): {
|
|
7
|
+
error: string;
|
|
8
|
+
user_facing_error: {
|
|
9
|
+
is_panic: boolean;
|
|
10
|
+
message: string;
|
|
11
|
+
meta: unknown;
|
|
12
|
+
error_code: string;
|
|
13
|
+
};
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
export declare function rethrowAsUserFacing(error: any): never;
|
package/dist/index.d.mts
CHANGED
|
@@ -1,8 +1,15 @@
|
|
|
1
|
+
import type { Context } from '@opentelemetry/api';
|
|
1
2
|
import type { IsolationLevel } from '@prisma/driver-adapter-utils';
|
|
3
|
+
import type { Span } from '@opentelemetry/api';
|
|
4
|
+
import type { SpanOptions } from '@opentelemetry/api';
|
|
2
5
|
import { SqlDriverAdapter } from '@prisma/driver-adapter-utils';
|
|
3
6
|
import { SqlQueryable } from '@prisma/driver-adapter-utils';
|
|
4
7
|
import { Transaction } from '@prisma/driver-adapter-utils';
|
|
5
8
|
|
|
9
|
+
declare type ExtendedSpanOptions = SpanOptions & {
|
|
10
|
+
name: string;
|
|
11
|
+
};
|
|
12
|
+
|
|
6
13
|
export declare type Fragment = {
|
|
7
14
|
type: 'stringChunk';
|
|
8
15
|
value: string;
|
|
@@ -22,6 +29,8 @@ export declare type JoinExpression = {
|
|
|
22
29
|
parentField: string;
|
|
23
30
|
};
|
|
24
31
|
|
|
32
|
+
export declare const noopTracingHelper: TracingHelper;
|
|
33
|
+
|
|
25
34
|
export declare interface PlaceholderFormat {
|
|
26
35
|
prefix: string;
|
|
27
36
|
hasNumbering: boolean;
|
|
@@ -54,7 +63,7 @@ export declare type QueryEvent = {
|
|
|
54
63
|
|
|
55
64
|
export declare class QueryInterpreter {
|
|
56
65
|
#private;
|
|
57
|
-
constructor({ transactionManager, placeholderValues, onQuery }: QueryInterpreterOptions);
|
|
66
|
+
constructor({ transactionManager, placeholderValues, onQuery, tracingHelper }: QueryInterpreterOptions);
|
|
58
67
|
run(queryPlan: QueryPlanNode, queryable: SqlQueryable): Promise<unknown>;
|
|
59
68
|
private interpretNode;
|
|
60
69
|
}
|
|
@@ -63,6 +72,7 @@ export declare type QueryInterpreterOptions = {
|
|
|
63
72
|
transactionManager: QueryInterpreterTransactionManager;
|
|
64
73
|
placeholderValues: Record<string, unknown>;
|
|
65
74
|
onQuery?: (event: QueryEvent) => void;
|
|
75
|
+
tracingHelper: TracingHelper;
|
|
66
76
|
};
|
|
67
77
|
|
|
68
78
|
export declare type QueryInterpreterTransactionManager = {
|
|
@@ -145,18 +155,27 @@ export declare type QueryPlanNode = {
|
|
|
145
155
|
args: QueryPlanNode;
|
|
146
156
|
};
|
|
147
157
|
|
|
158
|
+
declare type SpanCallback<R> = (span?: Span, context?: Context) => R;
|
|
159
|
+
|
|
160
|
+
export declare interface TracingHelper {
|
|
161
|
+
runInChildSpan<R>(nameOrOptions: string | ExtendedSpanOptions, callback: SpanCallback<R>): R;
|
|
162
|
+
}
|
|
163
|
+
|
|
148
164
|
export declare type TransactionInfo = {
|
|
149
165
|
id: string;
|
|
150
166
|
};
|
|
151
167
|
|
|
152
168
|
export declare class TransactionManager {
|
|
169
|
+
#private;
|
|
153
170
|
private transactions;
|
|
154
171
|
private closedTransactions;
|
|
155
172
|
private readonly driverAdapter;
|
|
156
173
|
private readonly transactionOptions;
|
|
157
|
-
|
|
174
|
+
private readonly tracingHelper;
|
|
175
|
+
constructor({ driverAdapter, transactionOptions, tracingHelper, }: {
|
|
158
176
|
driverAdapter: SqlDriverAdapter;
|
|
159
177
|
transactionOptions: TransactionOptions;
|
|
178
|
+
tracingHelper: TracingHelper;
|
|
160
179
|
});
|
|
161
180
|
startTransaction(options?: TransactionOptions): Promise<TransactionInfo>;
|
|
162
181
|
commitTransaction(transactionId: string): Promise<void>;
|
|
@@ -181,4 +200,20 @@ export declare type TransactionOptions = {
|
|
|
181
200
|
isolationLevel?: IsolationLevel;
|
|
182
201
|
};
|
|
183
202
|
|
|
203
|
+
export declare class UserFacingError extends Error {
|
|
204
|
+
name: string;
|
|
205
|
+
code: string;
|
|
206
|
+
meta: unknown;
|
|
207
|
+
constructor(message: string, code: string, meta?: unknown);
|
|
208
|
+
toQueryResponseErrorObject(): {
|
|
209
|
+
error: string;
|
|
210
|
+
user_facing_error: {
|
|
211
|
+
is_panic: boolean;
|
|
212
|
+
message: string;
|
|
213
|
+
meta: unknown;
|
|
214
|
+
error_code: string;
|
|
215
|
+
};
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
|
|
184
219
|
export { }
|
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,15 @@
|
|
|
1
|
+
import type { Context } from '@opentelemetry/api';
|
|
1
2
|
import type { IsolationLevel } from '@prisma/driver-adapter-utils';
|
|
3
|
+
import type { Span } from '@opentelemetry/api';
|
|
4
|
+
import type { SpanOptions } from '@opentelemetry/api';
|
|
2
5
|
import { SqlDriverAdapter } from '@prisma/driver-adapter-utils';
|
|
3
6
|
import { SqlQueryable } from '@prisma/driver-adapter-utils';
|
|
4
7
|
import { Transaction } from '@prisma/driver-adapter-utils';
|
|
5
8
|
|
|
9
|
+
declare type ExtendedSpanOptions = SpanOptions & {
|
|
10
|
+
name: string;
|
|
11
|
+
};
|
|
12
|
+
|
|
6
13
|
export declare type Fragment = {
|
|
7
14
|
type: 'stringChunk';
|
|
8
15
|
value: string;
|
|
@@ -22,6 +29,8 @@ export declare type JoinExpression = {
|
|
|
22
29
|
parentField: string;
|
|
23
30
|
};
|
|
24
31
|
|
|
32
|
+
export declare const noopTracingHelper: TracingHelper;
|
|
33
|
+
|
|
25
34
|
export declare interface PlaceholderFormat {
|
|
26
35
|
prefix: string;
|
|
27
36
|
hasNumbering: boolean;
|
|
@@ -54,7 +63,7 @@ export declare type QueryEvent = {
|
|
|
54
63
|
|
|
55
64
|
export declare class QueryInterpreter {
|
|
56
65
|
#private;
|
|
57
|
-
constructor({ transactionManager, placeholderValues, onQuery }: QueryInterpreterOptions);
|
|
66
|
+
constructor({ transactionManager, placeholderValues, onQuery, tracingHelper }: QueryInterpreterOptions);
|
|
58
67
|
run(queryPlan: QueryPlanNode, queryable: SqlQueryable): Promise<unknown>;
|
|
59
68
|
private interpretNode;
|
|
60
69
|
}
|
|
@@ -63,6 +72,7 @@ export declare type QueryInterpreterOptions = {
|
|
|
63
72
|
transactionManager: QueryInterpreterTransactionManager;
|
|
64
73
|
placeholderValues: Record<string, unknown>;
|
|
65
74
|
onQuery?: (event: QueryEvent) => void;
|
|
75
|
+
tracingHelper: TracingHelper;
|
|
66
76
|
};
|
|
67
77
|
|
|
68
78
|
export declare type QueryInterpreterTransactionManager = {
|
|
@@ -145,18 +155,27 @@ export declare type QueryPlanNode = {
|
|
|
145
155
|
args: QueryPlanNode;
|
|
146
156
|
};
|
|
147
157
|
|
|
158
|
+
declare type SpanCallback<R> = (span?: Span, context?: Context) => R;
|
|
159
|
+
|
|
160
|
+
export declare interface TracingHelper {
|
|
161
|
+
runInChildSpan<R>(nameOrOptions: string | ExtendedSpanOptions, callback: SpanCallback<R>): R;
|
|
162
|
+
}
|
|
163
|
+
|
|
148
164
|
export declare type TransactionInfo = {
|
|
149
165
|
id: string;
|
|
150
166
|
};
|
|
151
167
|
|
|
152
168
|
export declare class TransactionManager {
|
|
169
|
+
#private;
|
|
153
170
|
private transactions;
|
|
154
171
|
private closedTransactions;
|
|
155
172
|
private readonly driverAdapter;
|
|
156
173
|
private readonly transactionOptions;
|
|
157
|
-
|
|
174
|
+
private readonly tracingHelper;
|
|
175
|
+
constructor({ driverAdapter, transactionOptions, tracingHelper, }: {
|
|
158
176
|
driverAdapter: SqlDriverAdapter;
|
|
159
177
|
transactionOptions: TransactionOptions;
|
|
178
|
+
tracingHelper: TracingHelper;
|
|
160
179
|
});
|
|
161
180
|
startTransaction(options?: TransactionOptions): Promise<TransactionInfo>;
|
|
162
181
|
commitTransaction(transactionId: string): Promise<void>;
|
|
@@ -181,4 +200,20 @@ export declare type TransactionOptions = {
|
|
|
181
200
|
isolationLevel?: IsolationLevel;
|
|
182
201
|
};
|
|
183
202
|
|
|
203
|
+
export declare class UserFacingError extends Error {
|
|
204
|
+
name: string;
|
|
205
|
+
code: string;
|
|
206
|
+
meta: unknown;
|
|
207
|
+
constructor(message: string, code: string, meta?: unknown);
|
|
208
|
+
toQueryResponseErrorObject(): {
|
|
209
|
+
error: string;
|
|
210
|
+
user_facing_error: {
|
|
211
|
+
is_panic: boolean;
|
|
212
|
+
message: string;
|
|
213
|
+
meta: unknown;
|
|
214
|
+
error_code: string;
|
|
215
|
+
};
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
|
|
184
219
|
export { }
|
package/dist/index.js
CHANGED
|
@@ -33,11 +33,183 @@ __export(index_exports, {
|
|
|
33
33
|
QueryInterpreter: () => QueryInterpreter,
|
|
34
34
|
TransactionManager: () => TransactionManager,
|
|
35
35
|
TransactionManagerError: () => TransactionManagerError,
|
|
36
|
+
UserFacingError: () => UserFacingError,
|
|
36
37
|
isPrismaValueGenerator: () => isPrismaValueGenerator,
|
|
37
|
-
isPrismaValuePlaceholder: () => isPrismaValuePlaceholder
|
|
38
|
+
isPrismaValuePlaceholder: () => isPrismaValuePlaceholder,
|
|
39
|
+
noopTracingHelper: () => noopTracingHelper
|
|
38
40
|
});
|
|
39
41
|
module.exports = __toCommonJS(index_exports);
|
|
40
42
|
|
|
43
|
+
// src/interpreter/QueryInterpreter.ts
|
|
44
|
+
var import_api = require("@opentelemetry/api");
|
|
45
|
+
|
|
46
|
+
// src/utils.ts
|
|
47
|
+
function assertNever(_, message) {
|
|
48
|
+
throw new Error(message);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// src/tracing.ts
|
|
52
|
+
var noopTracingHelper = {
|
|
53
|
+
runInChildSpan(_, callback) {
|
|
54
|
+
return callback();
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
function providerToOtelSystem(provider) {
|
|
58
|
+
switch (provider) {
|
|
59
|
+
case "postgres":
|
|
60
|
+
return "postgresql";
|
|
61
|
+
case "mysql":
|
|
62
|
+
return "mysql";
|
|
63
|
+
case "sqlite":
|
|
64
|
+
return "sqlite";
|
|
65
|
+
default:
|
|
66
|
+
assertNever(provider, `Unknown provider: ${provider}`);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// src/UserFacingError.ts
|
|
71
|
+
var import_driver_adapter_utils = require("@prisma/driver-adapter-utils");
|
|
72
|
+
var UserFacingError = class extends Error {
|
|
73
|
+
name = "UserFacingError";
|
|
74
|
+
code;
|
|
75
|
+
meta;
|
|
76
|
+
constructor(message, code, meta) {
|
|
77
|
+
super(message);
|
|
78
|
+
this.code = code;
|
|
79
|
+
this.meta = meta;
|
|
80
|
+
}
|
|
81
|
+
toQueryResponseErrorObject() {
|
|
82
|
+
return {
|
|
83
|
+
error: this.message,
|
|
84
|
+
user_facing_error: {
|
|
85
|
+
is_panic: false,
|
|
86
|
+
message: this.message,
|
|
87
|
+
meta: this.meta,
|
|
88
|
+
error_code: this.code
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
function rethrowAsUserFacing(error) {
|
|
94
|
+
if (!(0, import_driver_adapter_utils.isDriverAdapterError)(error)) {
|
|
95
|
+
throw error;
|
|
96
|
+
}
|
|
97
|
+
const code = getErrorCode(error);
|
|
98
|
+
const message = renderErrorMessage(error);
|
|
99
|
+
if (!code || !message) {
|
|
100
|
+
throw error;
|
|
101
|
+
}
|
|
102
|
+
throw new UserFacingError(message, code, error);
|
|
103
|
+
}
|
|
104
|
+
function getErrorCode(err) {
|
|
105
|
+
switch (err.cause.kind) {
|
|
106
|
+
case "AuthenticationFailed":
|
|
107
|
+
return "P1000";
|
|
108
|
+
case "DatabaseDoesNotExist":
|
|
109
|
+
return "P1003";
|
|
110
|
+
case "SocketTimeout":
|
|
111
|
+
return "P1008";
|
|
112
|
+
case "DatabaseAlreadyExists":
|
|
113
|
+
return "P1009";
|
|
114
|
+
case "DatabaseAccessDenied":
|
|
115
|
+
return "P1010";
|
|
116
|
+
case "LengthMismatch":
|
|
117
|
+
return "P2000";
|
|
118
|
+
case "UniqueConstraintViolation":
|
|
119
|
+
return "P2002";
|
|
120
|
+
case "ForeignKeyConstraintViolation":
|
|
121
|
+
return "P2003";
|
|
122
|
+
case "UnsupportedNativeDataType":
|
|
123
|
+
return "P2010";
|
|
124
|
+
case "NullConstraintViolation":
|
|
125
|
+
return "P2011";
|
|
126
|
+
case "TableDoesNotExist":
|
|
127
|
+
return "P2021";
|
|
128
|
+
case "ColumnNotFound":
|
|
129
|
+
return "P2022";
|
|
130
|
+
case "InvalidIsolationLevel":
|
|
131
|
+
return "P2023";
|
|
132
|
+
case "TransactionWriteConflict":
|
|
133
|
+
return "P2034";
|
|
134
|
+
case "GenericJs":
|
|
135
|
+
return "P2036";
|
|
136
|
+
case "TooManyConnections":
|
|
137
|
+
return "P2037";
|
|
138
|
+
case "postgres":
|
|
139
|
+
case "sqlite":
|
|
140
|
+
case "mysql":
|
|
141
|
+
return;
|
|
142
|
+
default:
|
|
143
|
+
assertNever(err.cause, `Unknown error: ${err.cause}`);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
function renderErrorMessage(err) {
|
|
147
|
+
switch (err.cause.kind) {
|
|
148
|
+
case "AuthenticationFailed": {
|
|
149
|
+
const user = err.cause.user ?? "(not available)";
|
|
150
|
+
return `Authentication failed against the database server, the provided database credentials for \`${user}\` are not valid`;
|
|
151
|
+
}
|
|
152
|
+
case "DatabaseDoesNotExist": {
|
|
153
|
+
const db = err.cause.db ?? "(not available)";
|
|
154
|
+
return `Database \`${db}\` does not exist on the database server`;
|
|
155
|
+
}
|
|
156
|
+
case "SocketTimeout":
|
|
157
|
+
return `Operation has timed out`;
|
|
158
|
+
case "DatabaseAlreadyExists": {
|
|
159
|
+
const db = err.cause.db ?? "(not available)";
|
|
160
|
+
return `Database \`${db}\` already exists on the database server`;
|
|
161
|
+
}
|
|
162
|
+
case "DatabaseAccessDenied": {
|
|
163
|
+
const db = err.cause.db ?? "(not available)";
|
|
164
|
+
return `User was denied access on the database \`${db}\``;
|
|
165
|
+
}
|
|
166
|
+
case "LengthMismatch": {
|
|
167
|
+
const column = err.cause.column ?? "(not available)";
|
|
168
|
+
return `The provided value for the column is too long for the column's type. Column: ${column}`;
|
|
169
|
+
}
|
|
170
|
+
case "UniqueConstraintViolation":
|
|
171
|
+
return `Unique constraint failed on the ${renderConstraint({ fields: err.cause.fields })}`;
|
|
172
|
+
case "ForeignKeyConstraintViolation":
|
|
173
|
+
return `Foreign key constraint violated on the ${renderConstraint(err.cause.constraint)}`;
|
|
174
|
+
case "UnsupportedNativeDataType":
|
|
175
|
+
return `Failed to deserialize column of type '${err.cause.type}'. If you're using $queryRaw and this column is explicitly marked as \`Unsupported\` in your Prisma schema, try casting this column to any supported Prisma type such as \`String\`.`;
|
|
176
|
+
case "NullConstraintViolation":
|
|
177
|
+
return `Null constraint violation on the ${renderConstraint({ fields: err.cause.fields })}`;
|
|
178
|
+
case "TableDoesNotExist": {
|
|
179
|
+
const table = err.cause.table ?? "(not available)";
|
|
180
|
+
return `The table \`${table}\` does not exist in the current database.`;
|
|
181
|
+
}
|
|
182
|
+
case "ColumnNotFound": {
|
|
183
|
+
const column = err.cause.column ?? "(not available)";
|
|
184
|
+
return `The column \`${column}\` does not exist in the current database.`;
|
|
185
|
+
}
|
|
186
|
+
case "InvalidIsolationLevel":
|
|
187
|
+
return `Invalid isolation level \`${err.cause.level}\``;
|
|
188
|
+
case "TransactionWriteConflict":
|
|
189
|
+
return `Transaction failed due to a write conflict or a deadlock. Please retry your transaction`;
|
|
190
|
+
case "GenericJs":
|
|
191
|
+
return `Error in external connector (id ${err.cause.id})`;
|
|
192
|
+
case "TooManyConnections":
|
|
193
|
+
return `Too many database connections opened: ${err.cause.cause}`;
|
|
194
|
+
case "sqlite":
|
|
195
|
+
case "postgres":
|
|
196
|
+
case "mysql":
|
|
197
|
+
return;
|
|
198
|
+
default:
|
|
199
|
+
assertNever(err.cause, `Unknown error: ${err.cause}`);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
function renderConstraint(constraint) {
|
|
203
|
+
if (constraint && "fields" in constraint) {
|
|
204
|
+
return `fields: (${constraint.fields.map((field) => `\`${field}\``).join(", ")})`;
|
|
205
|
+
} else if (constraint && "index" in constraint) {
|
|
206
|
+
return `constraint: \`${constraint.index}\``;
|
|
207
|
+
} else if (constraint && "foreignKey" in constraint) {
|
|
208
|
+
return `foreign key`;
|
|
209
|
+
}
|
|
210
|
+
return "(not available)";
|
|
211
|
+
}
|
|
212
|
+
|
|
41
213
|
// src/interpreter/generators.ts
|
|
42
214
|
var import_cuid = __toESM(require("@bugsnag/cuid"));
|
|
43
215
|
var import_cuid2 = require("@paralleldrive/cuid2");
|
|
@@ -123,11 +295,6 @@ function isPrismaValueGenerator(value) {
|
|
|
123
295
|
return typeof value === "object" && value !== null && value["prisma__type"] === "generatorCall";
|
|
124
296
|
}
|
|
125
297
|
|
|
126
|
-
// src/utils.ts
|
|
127
|
-
function assertNever(_, message) {
|
|
128
|
-
throw new Error(message);
|
|
129
|
-
}
|
|
130
|
-
|
|
131
298
|
// src/interpreter/renderQuery.ts
|
|
132
299
|
function renderQuery(dbQuery, scope, generators) {
|
|
133
300
|
const queryType = dbQuery.type;
|
|
@@ -278,13 +445,17 @@ var QueryInterpreter = class {
|
|
|
278
445
|
#placeholderValues;
|
|
279
446
|
#onQuery;
|
|
280
447
|
#generators = new GeneratorRegistry();
|
|
281
|
-
|
|
448
|
+
#tracingHelper;
|
|
449
|
+
constructor({ transactionManager, placeholderValues, onQuery, tracingHelper }) {
|
|
282
450
|
this.#transactionManager = transactionManager;
|
|
283
451
|
this.#placeholderValues = placeholderValues;
|
|
284
452
|
this.#onQuery = onQuery;
|
|
453
|
+
this.#tracingHelper = tracingHelper;
|
|
285
454
|
}
|
|
286
455
|
async run(queryPlan, queryable) {
|
|
287
|
-
return this.interpretNode(queryPlan, queryable, this.#placeholderValues, this.#generators.snapshot())
|
|
456
|
+
return this.interpretNode(queryPlan, queryable, this.#placeholderValues, this.#generators.snapshot()).catch(
|
|
457
|
+
(e) => rethrowAsUserFacing(e)
|
|
458
|
+
);
|
|
288
459
|
}
|
|
289
460
|
async interpretNode(node, queryable, scope, generators) {
|
|
290
461
|
switch (node.type) {
|
|
@@ -323,13 +494,13 @@ var QueryInterpreter = class {
|
|
|
323
494
|
}
|
|
324
495
|
case "execute": {
|
|
325
496
|
const query = renderQuery(node.args, scope, generators);
|
|
326
|
-
return this.#withQueryEvent(query, async () => {
|
|
497
|
+
return this.#withQueryEvent(query, queryable, async () => {
|
|
327
498
|
return await queryable.executeRaw(query);
|
|
328
499
|
});
|
|
329
500
|
}
|
|
330
501
|
case "query": {
|
|
331
502
|
const query = renderQuery(node.args, scope, generators);
|
|
332
|
-
return this.#withQueryEvent(query, async () => {
|
|
503
|
+
return this.#withQueryEvent(query, queryable, async () => {
|
|
333
504
|
return serialize(await queryable.queryRaw(query));
|
|
334
505
|
});
|
|
335
506
|
}
|
|
@@ -390,24 +561,34 @@ var QueryInterpreter = class {
|
|
|
390
561
|
throw e;
|
|
391
562
|
}
|
|
392
563
|
}
|
|
393
|
-
default:
|
|
394
|
-
node;
|
|
395
|
-
throw new Error(`Unexpected node type: ${node.type}`);
|
|
396
|
-
}
|
|
564
|
+
default:
|
|
565
|
+
assertNever(node, `Unexpected node type: ${node.type}`);
|
|
397
566
|
}
|
|
398
567
|
}
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
568
|
+
#withQueryEvent(query, queryable, execute) {
|
|
569
|
+
return this.#tracingHelper.runInChildSpan(
|
|
570
|
+
{
|
|
571
|
+
name: "db_query",
|
|
572
|
+
kind: import_api.SpanKind.CLIENT,
|
|
573
|
+
attributes: {
|
|
574
|
+
"db.query.text": query.sql,
|
|
575
|
+
"db.system.name": providerToOtelSystem(queryable.provider)
|
|
576
|
+
}
|
|
577
|
+
},
|
|
578
|
+
async () => {
|
|
579
|
+
const timestamp = /* @__PURE__ */ new Date();
|
|
580
|
+
const startInstant = performance.now();
|
|
581
|
+
const result = await execute();
|
|
582
|
+
const endInstant = performance.now();
|
|
583
|
+
this.#onQuery?.({
|
|
584
|
+
timestamp,
|
|
585
|
+
duration: endInstant - startInstant,
|
|
586
|
+
query: query.sql,
|
|
587
|
+
params: query.args
|
|
588
|
+
});
|
|
589
|
+
return result;
|
|
590
|
+
}
|
|
591
|
+
);
|
|
411
592
|
}
|
|
412
593
|
};
|
|
413
594
|
function isEmpty(value) {
|
|
@@ -486,11 +667,6 @@ var TransactionManagerError = class extends Error {
|
|
|
486
667
|
}
|
|
487
668
|
code = "P2028";
|
|
488
669
|
};
|
|
489
|
-
var TransactionDriverAdapterError = class extends TransactionManagerError {
|
|
490
|
-
constructor(message, errorParams) {
|
|
491
|
-
super(`Error from Driver Adapter: ${message}`, { ...errorParams.driverAdapterError });
|
|
492
|
-
}
|
|
493
|
-
};
|
|
494
670
|
var TransactionNotFoundError = class extends TransactionManagerError {
|
|
495
671
|
constructor() {
|
|
496
672
|
super(
|
|
@@ -508,7 +684,7 @@ var TransactionRolledBackError = class extends TransactionManagerError {
|
|
|
508
684
|
super(`Transaction already closed: A ${operation} cannot be executed on a committed transaction`);
|
|
509
685
|
}
|
|
510
686
|
};
|
|
511
|
-
var
|
|
687
|
+
var TransactionStartTimeoutError = class extends TransactionManagerError {
|
|
512
688
|
constructor() {
|
|
513
689
|
super("Unable to start a transaction in the given time.");
|
|
514
690
|
}
|
|
@@ -545,11 +721,20 @@ var TransactionManager = class {
|
|
|
545
721
|
closedTransactions = [];
|
|
546
722
|
driverAdapter;
|
|
547
723
|
transactionOptions;
|
|
548
|
-
|
|
724
|
+
tracingHelper;
|
|
725
|
+
constructor({
|
|
726
|
+
driverAdapter,
|
|
727
|
+
transactionOptions,
|
|
728
|
+
tracingHelper
|
|
729
|
+
}) {
|
|
549
730
|
this.driverAdapter = driverAdapter;
|
|
550
731
|
this.transactionOptions = transactionOptions;
|
|
732
|
+
this.tracingHelper = tracingHelper;
|
|
551
733
|
}
|
|
552
734
|
async startTransaction(options) {
|
|
735
|
+
return await this.tracingHelper.runInChildSpan("start_transaction", () => this.#startTransactionImpl(options));
|
|
736
|
+
}
|
|
737
|
+
async #startTransactionImpl(options) {
|
|
553
738
|
const validatedOptions = options !== void 0 ? this.validateOptions(options) : this.transactionOptions;
|
|
554
739
|
const transaction = {
|
|
555
740
|
id: await randomUUID(),
|
|
@@ -561,14 +746,7 @@ var TransactionManager = class {
|
|
|
561
746
|
};
|
|
562
747
|
this.transactions.set(transaction.id, transaction);
|
|
563
748
|
transaction.timer = this.startTransactionTimeout(transaction.id, validatedOptions.maxWait);
|
|
564
|
-
|
|
565
|
-
try {
|
|
566
|
-
startedTransaction = await this.driverAdapter.startTransaction(validatedOptions.isolationLevel);
|
|
567
|
-
} catch (error) {
|
|
568
|
-
throw new TransactionDriverAdapterError("Failed to start transaction.", {
|
|
569
|
-
driverAdapterError: error
|
|
570
|
-
});
|
|
571
|
-
}
|
|
749
|
+
const startedTransaction = await this.driverAdapter.startTransaction(validatedOptions.isolationLevel);
|
|
572
750
|
switch (transaction.status) {
|
|
573
751
|
case "waiting":
|
|
574
752
|
transaction.transaction = startedTransaction;
|
|
@@ -578,7 +756,7 @@ var TransactionManager = class {
|
|
|
578
756
|
transaction.timer = this.startTransactionTimeout(transaction.id, validatedOptions.timeout);
|
|
579
757
|
return { id: transaction.id };
|
|
580
758
|
case "timed_out":
|
|
581
|
-
throw new
|
|
759
|
+
throw new TransactionStartTimeoutError();
|
|
582
760
|
case "running":
|
|
583
761
|
case "committed":
|
|
584
762
|
case "rolled_back":
|
|
@@ -590,12 +768,16 @@ var TransactionManager = class {
|
|
|
590
768
|
}
|
|
591
769
|
}
|
|
592
770
|
async commitTransaction(transactionId) {
|
|
593
|
-
|
|
594
|
-
|
|
771
|
+
return await this.tracingHelper.runInChildSpan("commit_transaction", async () => {
|
|
772
|
+
const txw = this.getActiveTransaction(transactionId, "commit");
|
|
773
|
+
await this.closeTransaction(txw, "committed");
|
|
774
|
+
});
|
|
595
775
|
}
|
|
596
776
|
async rollbackTransaction(transactionId) {
|
|
597
|
-
|
|
598
|
-
|
|
777
|
+
return await this.tracingHelper.runInChildSpan("rollback_transaction", async () => {
|
|
778
|
+
const txw = this.getActiveTransaction(transactionId, "rollback");
|
|
779
|
+
await this.closeTransaction(txw, "rolled_back");
|
|
780
|
+
});
|
|
599
781
|
}
|
|
600
782
|
getTransaction(txInfo, operation) {
|
|
601
783
|
const tx = this.getActiveTransaction(txInfo.id, operation);
|
|
@@ -651,24 +833,12 @@ var TransactionManager = class {
|
|
|
651
833
|
debug("Closing transaction.", { transactionId: tx.id, status });
|
|
652
834
|
tx.status = status;
|
|
653
835
|
if (tx.transaction && status === "committed") {
|
|
654
|
-
|
|
655
|
-
await tx.transaction.commit();
|
|
656
|
-
} catch (error) {
|
|
657
|
-
throw new TransactionDriverAdapterError("Failed to commit transaction.", {
|
|
658
|
-
driverAdapterError: error
|
|
659
|
-
});
|
|
660
|
-
}
|
|
836
|
+
await tx.transaction.commit();
|
|
661
837
|
if (!tx.transaction.options.usePhantomQuery) {
|
|
662
838
|
await tx.transaction.executeRaw(COMMIT_QUERY());
|
|
663
839
|
}
|
|
664
840
|
} else if (tx.transaction) {
|
|
665
|
-
|
|
666
|
-
await tx.transaction.rollback();
|
|
667
|
-
} catch (error) {
|
|
668
|
-
throw new TransactionDriverAdapterError("Failed to rollback transaction.", {
|
|
669
|
-
driverAdapterError: error
|
|
670
|
-
});
|
|
671
|
-
}
|
|
841
|
+
await tx.transaction.rollback();
|
|
672
842
|
if (!tx.transaction.options.usePhantomQuery) {
|
|
673
843
|
await tx.transaction.executeRaw(ROLLBACK_QUERY());
|
|
674
844
|
}
|
|
@@ -697,6 +867,8 @@ var TransactionManager = class {
|
|
|
697
867
|
QueryInterpreter,
|
|
698
868
|
TransactionManager,
|
|
699
869
|
TransactionManagerError,
|
|
870
|
+
UserFacingError,
|
|
700
871
|
isPrismaValueGenerator,
|
|
701
|
-
isPrismaValuePlaceholder
|
|
872
|
+
isPrismaValuePlaceholder,
|
|
873
|
+
noopTracingHelper
|
|
702
874
|
});
|
package/dist/index.mjs
CHANGED
|
@@ -1,3 +1,173 @@
|
|
|
1
|
+
// src/interpreter/QueryInterpreter.ts
|
|
2
|
+
import { SpanKind } from "@opentelemetry/api";
|
|
3
|
+
|
|
4
|
+
// src/utils.ts
|
|
5
|
+
function assertNever(_, message) {
|
|
6
|
+
throw new Error(message);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
// src/tracing.ts
|
|
10
|
+
var noopTracingHelper = {
|
|
11
|
+
runInChildSpan(_, callback) {
|
|
12
|
+
return callback();
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
function providerToOtelSystem(provider) {
|
|
16
|
+
switch (provider) {
|
|
17
|
+
case "postgres":
|
|
18
|
+
return "postgresql";
|
|
19
|
+
case "mysql":
|
|
20
|
+
return "mysql";
|
|
21
|
+
case "sqlite":
|
|
22
|
+
return "sqlite";
|
|
23
|
+
default:
|
|
24
|
+
assertNever(provider, `Unknown provider: ${provider}`);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// src/UserFacingError.ts
|
|
29
|
+
import { isDriverAdapterError } from "@prisma/driver-adapter-utils";
|
|
30
|
+
var UserFacingError = class extends Error {
|
|
31
|
+
name = "UserFacingError";
|
|
32
|
+
code;
|
|
33
|
+
meta;
|
|
34
|
+
constructor(message, code, meta) {
|
|
35
|
+
super(message);
|
|
36
|
+
this.code = code;
|
|
37
|
+
this.meta = meta;
|
|
38
|
+
}
|
|
39
|
+
toQueryResponseErrorObject() {
|
|
40
|
+
return {
|
|
41
|
+
error: this.message,
|
|
42
|
+
user_facing_error: {
|
|
43
|
+
is_panic: false,
|
|
44
|
+
message: this.message,
|
|
45
|
+
meta: this.meta,
|
|
46
|
+
error_code: this.code
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
function rethrowAsUserFacing(error) {
|
|
52
|
+
if (!isDriverAdapterError(error)) {
|
|
53
|
+
throw error;
|
|
54
|
+
}
|
|
55
|
+
const code = getErrorCode(error);
|
|
56
|
+
const message = renderErrorMessage(error);
|
|
57
|
+
if (!code || !message) {
|
|
58
|
+
throw error;
|
|
59
|
+
}
|
|
60
|
+
throw new UserFacingError(message, code, error);
|
|
61
|
+
}
|
|
62
|
+
function getErrorCode(err) {
|
|
63
|
+
switch (err.cause.kind) {
|
|
64
|
+
case "AuthenticationFailed":
|
|
65
|
+
return "P1000";
|
|
66
|
+
case "DatabaseDoesNotExist":
|
|
67
|
+
return "P1003";
|
|
68
|
+
case "SocketTimeout":
|
|
69
|
+
return "P1008";
|
|
70
|
+
case "DatabaseAlreadyExists":
|
|
71
|
+
return "P1009";
|
|
72
|
+
case "DatabaseAccessDenied":
|
|
73
|
+
return "P1010";
|
|
74
|
+
case "LengthMismatch":
|
|
75
|
+
return "P2000";
|
|
76
|
+
case "UniqueConstraintViolation":
|
|
77
|
+
return "P2002";
|
|
78
|
+
case "ForeignKeyConstraintViolation":
|
|
79
|
+
return "P2003";
|
|
80
|
+
case "UnsupportedNativeDataType":
|
|
81
|
+
return "P2010";
|
|
82
|
+
case "NullConstraintViolation":
|
|
83
|
+
return "P2011";
|
|
84
|
+
case "TableDoesNotExist":
|
|
85
|
+
return "P2021";
|
|
86
|
+
case "ColumnNotFound":
|
|
87
|
+
return "P2022";
|
|
88
|
+
case "InvalidIsolationLevel":
|
|
89
|
+
return "P2023";
|
|
90
|
+
case "TransactionWriteConflict":
|
|
91
|
+
return "P2034";
|
|
92
|
+
case "GenericJs":
|
|
93
|
+
return "P2036";
|
|
94
|
+
case "TooManyConnections":
|
|
95
|
+
return "P2037";
|
|
96
|
+
case "postgres":
|
|
97
|
+
case "sqlite":
|
|
98
|
+
case "mysql":
|
|
99
|
+
return;
|
|
100
|
+
default:
|
|
101
|
+
assertNever(err.cause, `Unknown error: ${err.cause}`);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
function renderErrorMessage(err) {
|
|
105
|
+
switch (err.cause.kind) {
|
|
106
|
+
case "AuthenticationFailed": {
|
|
107
|
+
const user = err.cause.user ?? "(not available)";
|
|
108
|
+
return `Authentication failed against the database server, the provided database credentials for \`${user}\` are not valid`;
|
|
109
|
+
}
|
|
110
|
+
case "DatabaseDoesNotExist": {
|
|
111
|
+
const db = err.cause.db ?? "(not available)";
|
|
112
|
+
return `Database \`${db}\` does not exist on the database server`;
|
|
113
|
+
}
|
|
114
|
+
case "SocketTimeout":
|
|
115
|
+
return `Operation has timed out`;
|
|
116
|
+
case "DatabaseAlreadyExists": {
|
|
117
|
+
const db = err.cause.db ?? "(not available)";
|
|
118
|
+
return `Database \`${db}\` already exists on the database server`;
|
|
119
|
+
}
|
|
120
|
+
case "DatabaseAccessDenied": {
|
|
121
|
+
const db = err.cause.db ?? "(not available)";
|
|
122
|
+
return `User was denied access on the database \`${db}\``;
|
|
123
|
+
}
|
|
124
|
+
case "LengthMismatch": {
|
|
125
|
+
const column = err.cause.column ?? "(not available)";
|
|
126
|
+
return `The provided value for the column is too long for the column's type. Column: ${column}`;
|
|
127
|
+
}
|
|
128
|
+
case "UniqueConstraintViolation":
|
|
129
|
+
return `Unique constraint failed on the ${renderConstraint({ fields: err.cause.fields })}`;
|
|
130
|
+
case "ForeignKeyConstraintViolation":
|
|
131
|
+
return `Foreign key constraint violated on the ${renderConstraint(err.cause.constraint)}`;
|
|
132
|
+
case "UnsupportedNativeDataType":
|
|
133
|
+
return `Failed to deserialize column of type '${err.cause.type}'. If you're using $queryRaw and this column is explicitly marked as \`Unsupported\` in your Prisma schema, try casting this column to any supported Prisma type such as \`String\`.`;
|
|
134
|
+
case "NullConstraintViolation":
|
|
135
|
+
return `Null constraint violation on the ${renderConstraint({ fields: err.cause.fields })}`;
|
|
136
|
+
case "TableDoesNotExist": {
|
|
137
|
+
const table = err.cause.table ?? "(not available)";
|
|
138
|
+
return `The table \`${table}\` does not exist in the current database.`;
|
|
139
|
+
}
|
|
140
|
+
case "ColumnNotFound": {
|
|
141
|
+
const column = err.cause.column ?? "(not available)";
|
|
142
|
+
return `The column \`${column}\` does not exist in the current database.`;
|
|
143
|
+
}
|
|
144
|
+
case "InvalidIsolationLevel":
|
|
145
|
+
return `Invalid isolation level \`${err.cause.level}\``;
|
|
146
|
+
case "TransactionWriteConflict":
|
|
147
|
+
return `Transaction failed due to a write conflict or a deadlock. Please retry your transaction`;
|
|
148
|
+
case "GenericJs":
|
|
149
|
+
return `Error in external connector (id ${err.cause.id})`;
|
|
150
|
+
case "TooManyConnections":
|
|
151
|
+
return `Too many database connections opened: ${err.cause.cause}`;
|
|
152
|
+
case "sqlite":
|
|
153
|
+
case "postgres":
|
|
154
|
+
case "mysql":
|
|
155
|
+
return;
|
|
156
|
+
default:
|
|
157
|
+
assertNever(err.cause, `Unknown error: ${err.cause}`);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
function renderConstraint(constraint) {
|
|
161
|
+
if (constraint && "fields" in constraint) {
|
|
162
|
+
return `fields: (${constraint.fields.map((field) => `\`${field}\``).join(", ")})`;
|
|
163
|
+
} else if (constraint && "index" in constraint) {
|
|
164
|
+
return `constraint: \`${constraint.index}\``;
|
|
165
|
+
} else if (constraint && "foreignKey" in constraint) {
|
|
166
|
+
return `foreign key`;
|
|
167
|
+
}
|
|
168
|
+
return "(not available)";
|
|
169
|
+
}
|
|
170
|
+
|
|
1
171
|
// src/interpreter/generators.ts
|
|
2
172
|
import cuid1 from "@bugsnag/cuid";
|
|
3
173
|
import { createId as cuid2 } from "@paralleldrive/cuid2";
|
|
@@ -83,11 +253,6 @@ function isPrismaValueGenerator(value) {
|
|
|
83
253
|
return typeof value === "object" && value !== null && value["prisma__type"] === "generatorCall";
|
|
84
254
|
}
|
|
85
255
|
|
|
86
|
-
// src/utils.ts
|
|
87
|
-
function assertNever(_, message) {
|
|
88
|
-
throw new Error(message);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
256
|
// src/interpreter/renderQuery.ts
|
|
92
257
|
function renderQuery(dbQuery, scope, generators) {
|
|
93
258
|
const queryType = dbQuery.type;
|
|
@@ -238,13 +403,17 @@ var QueryInterpreter = class {
|
|
|
238
403
|
#placeholderValues;
|
|
239
404
|
#onQuery;
|
|
240
405
|
#generators = new GeneratorRegistry();
|
|
241
|
-
|
|
406
|
+
#tracingHelper;
|
|
407
|
+
constructor({ transactionManager, placeholderValues, onQuery, tracingHelper }) {
|
|
242
408
|
this.#transactionManager = transactionManager;
|
|
243
409
|
this.#placeholderValues = placeholderValues;
|
|
244
410
|
this.#onQuery = onQuery;
|
|
411
|
+
this.#tracingHelper = tracingHelper;
|
|
245
412
|
}
|
|
246
413
|
async run(queryPlan, queryable) {
|
|
247
|
-
return this.interpretNode(queryPlan, queryable, this.#placeholderValues, this.#generators.snapshot())
|
|
414
|
+
return this.interpretNode(queryPlan, queryable, this.#placeholderValues, this.#generators.snapshot()).catch(
|
|
415
|
+
(e) => rethrowAsUserFacing(e)
|
|
416
|
+
);
|
|
248
417
|
}
|
|
249
418
|
async interpretNode(node, queryable, scope, generators) {
|
|
250
419
|
switch (node.type) {
|
|
@@ -283,13 +452,13 @@ var QueryInterpreter = class {
|
|
|
283
452
|
}
|
|
284
453
|
case "execute": {
|
|
285
454
|
const query = renderQuery(node.args, scope, generators);
|
|
286
|
-
return this.#withQueryEvent(query, async () => {
|
|
455
|
+
return this.#withQueryEvent(query, queryable, async () => {
|
|
287
456
|
return await queryable.executeRaw(query);
|
|
288
457
|
});
|
|
289
458
|
}
|
|
290
459
|
case "query": {
|
|
291
460
|
const query = renderQuery(node.args, scope, generators);
|
|
292
|
-
return this.#withQueryEvent(query, async () => {
|
|
461
|
+
return this.#withQueryEvent(query, queryable, async () => {
|
|
293
462
|
return serialize(await queryable.queryRaw(query));
|
|
294
463
|
});
|
|
295
464
|
}
|
|
@@ -350,24 +519,34 @@ var QueryInterpreter = class {
|
|
|
350
519
|
throw e;
|
|
351
520
|
}
|
|
352
521
|
}
|
|
353
|
-
default:
|
|
354
|
-
node;
|
|
355
|
-
throw new Error(`Unexpected node type: ${node.type}`);
|
|
356
|
-
}
|
|
522
|
+
default:
|
|
523
|
+
assertNever(node, `Unexpected node type: ${node.type}`);
|
|
357
524
|
}
|
|
358
525
|
}
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
526
|
+
#withQueryEvent(query, queryable, execute) {
|
|
527
|
+
return this.#tracingHelper.runInChildSpan(
|
|
528
|
+
{
|
|
529
|
+
name: "db_query",
|
|
530
|
+
kind: SpanKind.CLIENT,
|
|
531
|
+
attributes: {
|
|
532
|
+
"db.query.text": query.sql,
|
|
533
|
+
"db.system.name": providerToOtelSystem(queryable.provider)
|
|
534
|
+
}
|
|
535
|
+
},
|
|
536
|
+
async () => {
|
|
537
|
+
const timestamp = /* @__PURE__ */ new Date();
|
|
538
|
+
const startInstant = performance.now();
|
|
539
|
+
const result = await execute();
|
|
540
|
+
const endInstant = performance.now();
|
|
541
|
+
this.#onQuery?.({
|
|
542
|
+
timestamp,
|
|
543
|
+
duration: endInstant - startInstant,
|
|
544
|
+
query: query.sql,
|
|
545
|
+
params: query.args
|
|
546
|
+
});
|
|
547
|
+
return result;
|
|
548
|
+
}
|
|
549
|
+
);
|
|
371
550
|
}
|
|
372
551
|
};
|
|
373
552
|
function isEmpty(value) {
|
|
@@ -446,11 +625,6 @@ var TransactionManagerError = class extends Error {
|
|
|
446
625
|
}
|
|
447
626
|
code = "P2028";
|
|
448
627
|
};
|
|
449
|
-
var TransactionDriverAdapterError = class extends TransactionManagerError {
|
|
450
|
-
constructor(message, errorParams) {
|
|
451
|
-
super(`Error from Driver Adapter: ${message}`, { ...errorParams.driverAdapterError });
|
|
452
|
-
}
|
|
453
|
-
};
|
|
454
628
|
var TransactionNotFoundError = class extends TransactionManagerError {
|
|
455
629
|
constructor() {
|
|
456
630
|
super(
|
|
@@ -468,7 +642,7 @@ var TransactionRolledBackError = class extends TransactionManagerError {
|
|
|
468
642
|
super(`Transaction already closed: A ${operation} cannot be executed on a committed transaction`);
|
|
469
643
|
}
|
|
470
644
|
};
|
|
471
|
-
var
|
|
645
|
+
var TransactionStartTimeoutError = class extends TransactionManagerError {
|
|
472
646
|
constructor() {
|
|
473
647
|
super("Unable to start a transaction in the given time.");
|
|
474
648
|
}
|
|
@@ -505,11 +679,20 @@ var TransactionManager = class {
|
|
|
505
679
|
closedTransactions = [];
|
|
506
680
|
driverAdapter;
|
|
507
681
|
transactionOptions;
|
|
508
|
-
|
|
682
|
+
tracingHelper;
|
|
683
|
+
constructor({
|
|
684
|
+
driverAdapter,
|
|
685
|
+
transactionOptions,
|
|
686
|
+
tracingHelper
|
|
687
|
+
}) {
|
|
509
688
|
this.driverAdapter = driverAdapter;
|
|
510
689
|
this.transactionOptions = transactionOptions;
|
|
690
|
+
this.tracingHelper = tracingHelper;
|
|
511
691
|
}
|
|
512
692
|
async startTransaction(options) {
|
|
693
|
+
return await this.tracingHelper.runInChildSpan("start_transaction", () => this.#startTransactionImpl(options));
|
|
694
|
+
}
|
|
695
|
+
async #startTransactionImpl(options) {
|
|
513
696
|
const validatedOptions = options !== void 0 ? this.validateOptions(options) : this.transactionOptions;
|
|
514
697
|
const transaction = {
|
|
515
698
|
id: await randomUUID(),
|
|
@@ -521,14 +704,7 @@ var TransactionManager = class {
|
|
|
521
704
|
};
|
|
522
705
|
this.transactions.set(transaction.id, transaction);
|
|
523
706
|
transaction.timer = this.startTransactionTimeout(transaction.id, validatedOptions.maxWait);
|
|
524
|
-
|
|
525
|
-
try {
|
|
526
|
-
startedTransaction = await this.driverAdapter.startTransaction(validatedOptions.isolationLevel);
|
|
527
|
-
} catch (error) {
|
|
528
|
-
throw new TransactionDriverAdapterError("Failed to start transaction.", {
|
|
529
|
-
driverAdapterError: error
|
|
530
|
-
});
|
|
531
|
-
}
|
|
707
|
+
const startedTransaction = await this.driverAdapter.startTransaction(validatedOptions.isolationLevel);
|
|
532
708
|
switch (transaction.status) {
|
|
533
709
|
case "waiting":
|
|
534
710
|
transaction.transaction = startedTransaction;
|
|
@@ -538,7 +714,7 @@ var TransactionManager = class {
|
|
|
538
714
|
transaction.timer = this.startTransactionTimeout(transaction.id, validatedOptions.timeout);
|
|
539
715
|
return { id: transaction.id };
|
|
540
716
|
case "timed_out":
|
|
541
|
-
throw new
|
|
717
|
+
throw new TransactionStartTimeoutError();
|
|
542
718
|
case "running":
|
|
543
719
|
case "committed":
|
|
544
720
|
case "rolled_back":
|
|
@@ -550,12 +726,16 @@ var TransactionManager = class {
|
|
|
550
726
|
}
|
|
551
727
|
}
|
|
552
728
|
async commitTransaction(transactionId) {
|
|
553
|
-
|
|
554
|
-
|
|
729
|
+
return await this.tracingHelper.runInChildSpan("commit_transaction", async () => {
|
|
730
|
+
const txw = this.getActiveTransaction(transactionId, "commit");
|
|
731
|
+
await this.closeTransaction(txw, "committed");
|
|
732
|
+
});
|
|
555
733
|
}
|
|
556
734
|
async rollbackTransaction(transactionId) {
|
|
557
|
-
|
|
558
|
-
|
|
735
|
+
return await this.tracingHelper.runInChildSpan("rollback_transaction", async () => {
|
|
736
|
+
const txw = this.getActiveTransaction(transactionId, "rollback");
|
|
737
|
+
await this.closeTransaction(txw, "rolled_back");
|
|
738
|
+
});
|
|
559
739
|
}
|
|
560
740
|
getTransaction(txInfo, operation) {
|
|
561
741
|
const tx = this.getActiveTransaction(txInfo.id, operation);
|
|
@@ -611,24 +791,12 @@ var TransactionManager = class {
|
|
|
611
791
|
debug("Closing transaction.", { transactionId: tx.id, status });
|
|
612
792
|
tx.status = status;
|
|
613
793
|
if (tx.transaction && status === "committed") {
|
|
614
|
-
|
|
615
|
-
await tx.transaction.commit();
|
|
616
|
-
} catch (error) {
|
|
617
|
-
throw new TransactionDriverAdapterError("Failed to commit transaction.", {
|
|
618
|
-
driverAdapterError: error
|
|
619
|
-
});
|
|
620
|
-
}
|
|
794
|
+
await tx.transaction.commit();
|
|
621
795
|
if (!tx.transaction.options.usePhantomQuery) {
|
|
622
796
|
await tx.transaction.executeRaw(COMMIT_QUERY());
|
|
623
797
|
}
|
|
624
798
|
} else if (tx.transaction) {
|
|
625
|
-
|
|
626
|
-
await tx.transaction.rollback();
|
|
627
|
-
} catch (error) {
|
|
628
|
-
throw new TransactionDriverAdapterError("Failed to rollback transaction.", {
|
|
629
|
-
driverAdapterError: error
|
|
630
|
-
});
|
|
631
|
-
}
|
|
799
|
+
await tx.transaction.rollback();
|
|
632
800
|
if (!tx.transaction.options.usePhantomQuery) {
|
|
633
801
|
await tx.transaction.executeRaw(ROLLBACK_QUERY());
|
|
634
802
|
}
|
|
@@ -656,6 +824,8 @@ export {
|
|
|
656
824
|
QueryInterpreter,
|
|
657
825
|
TransactionManager,
|
|
658
826
|
TransactionManagerError,
|
|
827
|
+
UserFacingError,
|
|
659
828
|
isPrismaValueGenerator,
|
|
660
|
-
isPrismaValuePlaceholder
|
|
829
|
+
isPrismaValuePlaceholder,
|
|
830
|
+
noopTracingHelper
|
|
661
831
|
};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { SqlQueryable } from '@prisma/driver-adapter-utils';
|
|
2
2
|
import { QueryEvent } from '../events';
|
|
3
3
|
import { QueryPlanNode } from '../QueryPlan';
|
|
4
|
+
import { type TracingHelper } from '../tracing';
|
|
4
5
|
import { type TransactionManager } from '../transactionManager/TransactionManager';
|
|
5
6
|
export type QueryInterpreterTransactionManager = {
|
|
6
7
|
enabled: true;
|
|
@@ -12,10 +13,11 @@ export type QueryInterpreterOptions = {
|
|
|
12
13
|
transactionManager: QueryInterpreterTransactionManager;
|
|
13
14
|
placeholderValues: Record<string, unknown>;
|
|
14
15
|
onQuery?: (event: QueryEvent) => void;
|
|
16
|
+
tracingHelper: TracingHelper;
|
|
15
17
|
};
|
|
16
18
|
export declare class QueryInterpreter {
|
|
17
19
|
#private;
|
|
18
|
-
constructor({ transactionManager, placeholderValues, onQuery }: QueryInterpreterOptions);
|
|
20
|
+
constructor({ transactionManager, placeholderValues, onQuery, tracingHelper }: QueryInterpreterOptions);
|
|
19
21
|
run(queryPlan: QueryPlanNode, queryable: SqlQueryable): Promise<unknown>;
|
|
20
22
|
private interpretNode;
|
|
21
23
|
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Context, Span, SpanOptions } from '@opentelemetry/api';
|
|
2
|
+
import type { Provider } from '@prisma/driver-adapter-utils';
|
|
3
|
+
export type SpanCallback<R> = (span?: Span, context?: Context) => R;
|
|
4
|
+
export type ExtendedSpanOptions = SpanOptions & {
|
|
5
|
+
name: string;
|
|
6
|
+
};
|
|
7
|
+
export interface TracingHelper {
|
|
8
|
+
runInChildSpan<R>(nameOrOptions: string | ExtendedSpanOptions, callback: SpanCallback<R>): R;
|
|
9
|
+
}
|
|
10
|
+
export declare const noopTracingHelper: TracingHelper;
|
|
11
|
+
export declare function providerToOtelSystem(provider: Provider): string;
|
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
import { SqlDriverAdapter, Transaction } from '@prisma/driver-adapter-utils';
|
|
2
|
+
import { TracingHelper } from '../tracing';
|
|
2
3
|
import { Options, TransactionInfo } from './Transaction';
|
|
3
4
|
export declare class TransactionManager {
|
|
5
|
+
#private;
|
|
4
6
|
private transactions;
|
|
5
7
|
private closedTransactions;
|
|
6
8
|
private readonly driverAdapter;
|
|
7
9
|
private readonly transactionOptions;
|
|
8
|
-
|
|
10
|
+
private readonly tracingHelper;
|
|
11
|
+
constructor({ driverAdapter, transactionOptions, tracingHelper, }: {
|
|
9
12
|
driverAdapter: SqlDriverAdapter;
|
|
10
13
|
transactionOptions: Options;
|
|
14
|
+
tracingHelper: TracingHelper;
|
|
11
15
|
});
|
|
12
16
|
startTransaction(options?: Options): Promise<TransactionInfo>;
|
|
13
17
|
commitTransaction(transactionId: string): Promise<void>;
|
|
@@ -1,14 +1,8 @@
|
|
|
1
|
-
import { Error as DriverAdapterError } from '@prisma/driver-adapter-utils';
|
|
2
1
|
export declare class TransactionManagerError extends Error {
|
|
3
2
|
meta?: Record<string, unknown> | undefined;
|
|
4
3
|
code: string;
|
|
5
4
|
constructor(message: string, meta?: Record<string, unknown> | undefined);
|
|
6
5
|
}
|
|
7
|
-
export declare class TransactionDriverAdapterError extends TransactionManagerError {
|
|
8
|
-
constructor(message: string, errorParams: {
|
|
9
|
-
driverAdapterError: DriverAdapterError;
|
|
10
|
-
});
|
|
11
|
-
}
|
|
12
6
|
export declare class TransactionNotFoundError extends TransactionManagerError {
|
|
13
7
|
constructor();
|
|
14
8
|
}
|
|
@@ -18,7 +12,7 @@ export declare class TransactionClosedError extends TransactionManagerError {
|
|
|
18
12
|
export declare class TransactionRolledBackError extends TransactionManagerError {
|
|
19
13
|
constructor(operation: string);
|
|
20
14
|
}
|
|
21
|
-
export declare class
|
|
15
|
+
export declare class TransactionStartTimeoutError extends TransactionManagerError {
|
|
22
16
|
constructor();
|
|
23
17
|
}
|
|
24
18
|
export declare class TransactionExecutionTimeoutError extends TransactionManagerError {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@prisma/client-engine-runtime",
|
|
3
|
-
"version": "6.7.0-dev.
|
|
3
|
+
"version": "6.7.0-dev.10",
|
|
4
4
|
"description": "This package is intended for Prisma's internal use",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
@@ -25,12 +25,13 @@
|
|
|
25
25
|
"license": "Apache-2.0",
|
|
26
26
|
"dependencies": {
|
|
27
27
|
"@bugsnag/cuid": "3.2.1",
|
|
28
|
+
"@opentelemetry/api": "1.9.0",
|
|
28
29
|
"@paralleldrive/cuid2": "2.2.2",
|
|
29
30
|
"nanoid": "5.1.5",
|
|
30
31
|
"ulid": "3.0.0",
|
|
31
32
|
"uuid": "11.1.0",
|
|
32
|
-
"@prisma/debug": "6.7.0-dev.
|
|
33
|
-
"@prisma/driver-adapter-utils": "6.7.0-dev.
|
|
33
|
+
"@prisma/debug": "6.7.0-dev.10",
|
|
34
|
+
"@prisma/driver-adapter-utils": "6.7.0-dev.10"
|
|
34
35
|
},
|
|
35
36
|
"devDependencies": {
|
|
36
37
|
"@types/jest": "29.5.14",
|