@typed-sql/mysql 1.0.0 → 2.0.0

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.
Files changed (37) hide show
  1. package/CHANGELOG.md +119 -0
  2. package/README.md +22 -4
  3. package/dist/packages/mysql/src/bulk.d.ts +22 -0
  4. package/dist/packages/mysql/src/bulk.d.ts.map +1 -0
  5. package/dist/packages/mysql/src/bulk.js +205 -0
  6. package/dist/packages/mysql/src/bulk.js.map +1 -0
  7. package/dist/packages/mysql/src/index.d.ts +5 -1
  8. package/dist/packages/mysql/src/index.d.ts.map +1 -1
  9. package/dist/packages/mysql/src/index.js +16 -3
  10. package/dist/packages/mysql/src/index.js.map +1 -1
  11. package/dist/packages/mysql/src/mysql2.d.ts +60 -1
  12. package/dist/packages/mysql/src/mysql2.d.ts.map +1 -1
  13. package/dist/packages/mysql/src/mysql2.js +296 -0
  14. package/dist/packages/mysql/src/mysql2.js.map +1 -1
  15. package/dist/packages/mysql/src/provider.d.ts.map +1 -1
  16. package/dist/packages/mysql/src/provider.js +8 -1
  17. package/dist/packages/mysql/src/provider.js.map +1 -1
  18. package/dist/packages/mysql/src/resolver.d.ts.map +1 -1
  19. package/dist/packages/mysql/src/resolver.js +20 -1
  20. package/dist/packages/mysql/src/resolver.js.map +1 -1
  21. package/dist/packages/mysql/src/routing.d.ts +22 -0
  22. package/dist/packages/mysql/src/routing.d.ts.map +1 -0
  23. package/dist/packages/mysql/src/routing.js +72 -0
  24. package/dist/packages/mysql/src/routing.js.map +1 -0
  25. package/dist/packages/mysql/src/runtime.d.ts +6 -1
  26. package/dist/packages/mysql/src/runtime.d.ts.map +1 -1
  27. package/dist/packages/mysql/src/runtime.js +311 -25
  28. package/dist/packages/mysql/src/runtime.js.map +1 -1
  29. package/dist/packages/mysql/src/semantics.d.ts +5 -0
  30. package/dist/packages/mysql/src/semantics.d.ts.map +1 -0
  31. package/dist/packages/mysql/src/semantics.js +203 -0
  32. package/dist/packages/mysql/src/semantics.js.map +1 -0
  33. package/dist/packages/mysql/src/version.d.ts +2 -0
  34. package/dist/packages/mysql/src/version.d.ts.map +1 -0
  35. package/dist/packages/mysql/src/version.js +2 -0
  36. package/dist/packages/mysql/src/version.js.map +1 -0
  37. package/package.json +4 -4
@@ -0,0 +1,22 @@
1
+ import { type Database, type QueryRoutingObserver, type QuerySemanticResolver, type ReplicaSelector, type RoutedDatabase } from "@typed-sql/core";
2
+ import type { SchemaSnapshot } from "@typed-sql/schema";
3
+ import { type MySqlTypePolicy } from "./type-policy.js";
4
+ export interface MySqlQuerySemanticResolverOptions {
5
+ readonly schema: SchemaSnapshot & {
6
+ readonly dialect: "mysql";
7
+ };
8
+ readonly typePolicy?: MySqlTypePolicy;
9
+ }
10
+ export interface MySqlRoutedDatabaseOptions extends MySqlQuerySemanticResolverOptions {
11
+ readonly primary: Database;
12
+ readonly replicas?: readonly Database[];
13
+ readonly selectReplica?: ReplicaSelector;
14
+ readonly observer?: QueryRoutingObserver;
15
+ }
16
+ /** Resolves runtime query identity with the same MySQL parser and semantic pass as the compiler. */
17
+ export declare function createMySqlQuerySemanticResolver(options: MySqlQuerySemanticResolverOptions): QuerySemanticResolver;
18
+ /** Composes application-owned MySQL databases into a conservative routed database. */
19
+ export declare function createMySqlRoutedDatabase(options: MySqlRoutedDatabaseOptions): RoutedDatabase;
20
+ /** MySQL explicitly instructs applications to retry complete transactions after an InnoDB deadlock. */
21
+ export declare function isMySqlRetryableTransactionError(error: unknown): boolean;
22
+ //# sourceMappingURL=routing.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routing.d.ts","sourceRoot":"","sources":["../../../../src/routing.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,KAAK,QAAQ,EAEb,KAAK,oBAAoB,EACzB,KAAK,qBAAqB,EAE1B,KAAK,eAAe,EACpB,KAAK,cAAc,EAEpB,MAAM,iBAAiB,CAAC;AACzB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAGxD,OAAO,EAA0B,KAAK,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAEhF,MAAM,WAAW,iCAAiC;IAChD,QAAQ,CAAC,MAAM,EAAE,cAAc,GAAG;QAAE,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;KAAE,CAAC;IAChE,QAAQ,CAAC,UAAU,CAAC,EAAE,eAAe,CAAC;CACvC;AAED,MAAM,WAAW,0BAA2B,SAAQ,iCAAiC;IACnF,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC;IAC3B,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,QAAQ,EAAE,CAAC;IACxC,QAAQ,CAAC,aAAa,CAAC,EAAE,eAAe,CAAC;IACzC,QAAQ,CAAC,QAAQ,CAAC,EAAE,oBAAoB,CAAC;CAC1C;AAED,oGAAoG;AACpG,wBAAgB,gCAAgC,CAAC,OAAO,EAAE,iCAAiC,GAAG,qBAAqB,CA+BlH;AAYD,sFAAsF;AACtF,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,0BAA0B,GAAG,cAAc,CAQ7F;AAED,uGAAuG;AACvG,wBAAgB,gCAAgC,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAIxE"}
@@ -0,0 +1,72 @@
1
+ import { parseStatement, SqlParseError } from "@typed-sql/ast";
2
+ import { createRoutedDatabase, unknownQuerySemantics, } from "@typed-sql/core";
3
+ import { resolveMySqlStatement } from "./resolver.js";
4
+ import { analyzeMySqlSemantics } from "./semantics.js";
5
+ import { defaultMySqlTypePolicy } from "./type-policy.js";
6
+ /** Resolves runtime query identity with the same MySQL parser and semantic pass as the compiler. */
7
+ export function createMySqlQuerySemanticResolver(options) {
8
+ const cache = new WeakMap();
9
+ const shapes = new Map();
10
+ const policy = options.typePolicy ?? defaultMySqlTypePolicy;
11
+ return Object.freeze({
12
+ resolve(query) {
13
+ const cached = cache.get(query);
14
+ if (cached !== undefined)
15
+ return cached;
16
+ const source = mysqlRendererQuery(query);
17
+ const shape = shapes.get(source);
18
+ if (shape !== undefined) {
19
+ cache.set(query, shape);
20
+ return shape;
21
+ }
22
+ let semantics;
23
+ try {
24
+ const statement = parseStatement(source, { syntax: "mysql" });
25
+ const resolved = resolveMySqlStatement(statement, options.schema, { typePolicy: policy });
26
+ semantics = resolved.diagnostics.some(({ severity }) => severity === "error")
27
+ ? unknownQuerySemantics(statement.range, "MySQL runtime semantic analysis reported an error.")
28
+ : analyzeMySqlSemantics(statement, options.schema);
29
+ }
30
+ catch (error) {
31
+ if (!(error instanceof SqlParseError))
32
+ throw error;
33
+ semantics = unknownQuerySemantics(error.range, "The runtime SQL could not be parsed by the MySQL grammar.");
34
+ }
35
+ if (shapes.size >= 1_024)
36
+ shapes.delete(shapes.keys().next().value);
37
+ shapes.set(source, semantics);
38
+ cache.set(query, semantics);
39
+ return semantics;
40
+ },
41
+ });
42
+ }
43
+ function mysqlRendererQuery(query) {
44
+ const chunks = [];
45
+ for (const segment of query.segments) {
46
+ if (segment.kind === "text")
47
+ chunks.push(segment.text);
48
+ else if (segment.kind === "identifier")
49
+ chunks.push(`\`${segment.name.replaceAll("`", "``")}\``);
50
+ else
51
+ chunks.push("?");
52
+ }
53
+ return chunks.join("");
54
+ }
55
+ /** Composes application-owned MySQL databases into a conservative routed database. */
56
+ export function createMySqlRoutedDatabase(options) {
57
+ return createRoutedDatabase({
58
+ primary: options.primary,
59
+ ...(options.replicas === undefined ? {} : { replicas: options.replicas }),
60
+ semantics: createMySqlQuerySemanticResolver(options),
61
+ ...(options.selectReplica === undefined ? {} : { selectReplica: options.selectReplica }),
62
+ ...(options.observer === undefined ? {} : { observer: options.observer }),
63
+ });
64
+ }
65
+ /** MySQL explicitly instructs applications to retry complete transactions after an InnoDB deadlock. */
66
+ export function isMySqlRetryableTransactionError(error) {
67
+ if (typeof error !== "object" || error === null)
68
+ return false;
69
+ const value = error;
70
+ return value.code === "ER_LOCK_DEADLOCK" || value.errno === 1213 || value.sqlState === "40001";
71
+ }
72
+ //# sourceMappingURL=routing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routing.js","sourceRoot":"","sources":["../../../../src/routing.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { type Database, type Query, type QueryBatch, type QueryResults, type QueryStream, type SqlRenderer, type StreamOptions } from "@typed-sql/core";
1
+ import { type Database, type DatabaseObserver, type ExecutionCapabilities, type Query, type QueryBatch, type QueryResults, type QueryStream, type SqlRenderer, type StreamOptions } from "@typed-sql/core";
2
2
  import { type MySqlFieldLike } from "./decoding.js";
3
3
  import { type MySqlPreparedQueryFactory } from "./prepared.js";
4
4
  import { type MySqlStreamingConnection } from "./stream.js";
@@ -13,12 +13,16 @@ export interface MySqlExecutionResult {
13
13
  export interface MySqlConnectionLike extends MySqlStreamingConnection {
14
14
  execute(sql: string, values?: readonly unknown[]): Promise<MySqlExecutionResult>;
15
15
  query(sql: string): Promise<MySqlExecutionResult>;
16
+ loadData?(statement: string, chunks: AsyncIterable<Uint8Array>): Promise<void>;
16
17
  beginTransaction(): Promise<void>;
17
18
  commit(): Promise<void>;
18
19
  rollback(): Promise<void>;
20
+ destroy?(): void;
19
21
  release(): void;
20
22
  }
21
23
  export interface MySqlPoolLike {
24
+ readonly executionCapabilities?: ExecutionCapabilities;
25
+ readonly bulkLoad?: boolean;
22
26
  execute(sql: string, values?: readonly unknown[]): Promise<MySqlExecutionResult>;
23
27
  getConnection(): Promise<MySqlConnectionLike>;
24
28
  end(): Promise<void>;
@@ -39,6 +43,7 @@ export interface MySqlDatabaseOptions {
39
43
  readonly ownsPool?: boolean;
40
44
  readonly typePolicy?: Pick<MySqlTypePolicy, "bigint" | "decimal" | "date" | "json" | "tinyint1">;
41
45
  readonly decimal?: (value: string) => unknown;
46
+ readonly observer?: DatabaseObserver;
42
47
  }
43
48
  export declare const mysqlRenderer: SqlRenderer;
44
49
  export declare function createMySqlDatabase(options: MySqlDatabaseOptions): MySqlDatabase;
@@ -1 +1 @@
1
- {"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../../../src/runtime.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../../../src/runtime.ts"],"names":[],"mappings":"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"}
@@ -1,11 +1,27 @@
1
1
  var _a;
2
- import { renderQuery, } from "@typed-sql/core";
2
+ import { createHash } from "node:crypto";
3
+ import { adapterCapabilities, assertExecutionCapabilities, createAdapterCapabilityResolver, databaseErrorCompletion, hasQueryResultValidator, observeQueryStream, QueryCardinalityError, queryResultValidationSource, renderQuery, runControlledExecution, startDatabaseObservation, UnsupportedExecutionCapabilityError, validateQueryResultRows, validateQueryResultStream, } from "@typed-sql/core";
4
+ import { createMySqlBulkCapability, mysqlBulk } from "./bulk.js";
3
5
  import { decodeMySqlRows, encodeMySqlValue, MySqlDecoderPlanCache, } from "./decoding.js";
4
6
  import { createMySqlPreparedQueryState, prepareMySqlQuery, } from "./prepared.js";
5
7
  import { createMySqlQueryStream, validateMySqlStreamBatchSize } from "./stream.js";
6
8
  import { defaultMySqlTypePolicy } from "./type-policy.js";
9
+ import { MYSQL_DIALECT_VERSION } from "./version.js";
7
10
  const defaultRuntimeTypePolicy = defaultMySqlTypePolicy;
8
11
  const emptyBatchResults = Object.freeze([]);
12
+ function createMySqlObservationState(observer) {
13
+ return { observer, fingerprints: observer === undefined ? undefined : new WeakMap() };
14
+ }
15
+ function mysqlQueryFingerprint(state, query) {
16
+ const key = query;
17
+ const cached = state.fingerprints?.get(key);
18
+ if (cached !== undefined)
19
+ return cached;
20
+ const text = renderQuery(query, mysqlRenderer).text;
21
+ const fingerprint = `sha256:${createHash("sha256").update(`mysql\0${MYSQL_DIALECT_VERSION}\0${text}`).digest("hex")}`;
22
+ state.fingerprints?.set(key, fingerprint);
23
+ return fingerprint;
24
+ }
9
25
  export const mysqlRenderer = Object.freeze({
10
26
  placeholder: () => "?",
11
27
  quoteIdentifier: (identifier) => `\`${identifier.replaceAll("`", "``")}\``,
@@ -23,23 +39,41 @@ class MySqlDatabaseImplementation {
23
39
  #ownsPool;
24
40
  #depth;
25
41
  #prepared;
42
+ #observation;
26
43
  #decoderPlans;
27
44
  #executes;
28
45
  #streams;
29
46
  #transactionState;
30
47
  #scopeOpen = true;
31
- constructor(pool, connection, ownsPool, depth, prepared, decoderPlans, transactionState) {
48
+ executionCapabilities;
49
+ [adapterCapabilities];
50
+ constructor(pool, connection, ownsPool, depth, prepared, decoderPlans, observation, transactionState) {
32
51
  this.#pool = pool;
33
52
  this.#connection = connection;
34
53
  this.#ownsPool = ownsPool;
35
54
  this.#depth = depth;
36
55
  this.#prepared = prepared;
37
56
  this.#decoderPlans = decoderPlans;
57
+ this.#observation = observation;
38
58
  this.#executes = connection === undefined ? undefined : new Set();
39
59
  this.#streams = connection === undefined ? undefined : new Set();
40
60
  this.#transactionState = transactionState;
61
+ this.executionCapabilities = Object.freeze({
62
+ cancellation: pool.executionCapabilities?.cancellation ?? false,
63
+ deadlines: pool.executionCapabilities?.deadlines ?? false,
64
+ });
65
+ const bulkTransport = {
66
+ loadData: (statement, chunks, options) => this.#loadData(statement, chunks, options),
67
+ };
68
+ this[adapterCapabilities] = createAdapterCapabilityResolver(pool.bulkLoad === true ? [[mysqlBulk, createMySqlBulkCapability(bulkTransport)]] : []);
41
69
  }
42
70
  async execute(query) {
71
+ if (this.#observation.observer === undefined) {
72
+ return this.#validateRows(query, await this.#executeUnobserved(query));
73
+ }
74
+ return this.#observeQuery(query, "many", async () => this.#validateRows(query, await this.#executeUnobserved(query)));
75
+ }
76
+ async #executeUnobserved(query) {
43
77
  this.#assertScopeOpen();
44
78
  this.#assertConnectionAvailable("execute a query");
45
79
  if (this.#connection === undefined)
@@ -57,8 +91,119 @@ class MySqlDatabaseImplementation {
57
91
  operation.finish();
58
92
  }
59
93
  }
94
+ async all(query, options) {
95
+ if (this.#observation.observer === undefined) {
96
+ return this.#validateRows(query, await this.#allUnobserved(query, options));
97
+ }
98
+ return this.#observeQuery(query, "many", async () => this.#validateRows(query, await this.#allUnobserved(query, options)));
99
+ }
100
+ async #allUnobserved(query, options) {
101
+ if (options === undefined || (options.signal === undefined && options.deadline === undefined))
102
+ return this.#executeUnobserved(query);
103
+ assertExecutionCapabilities(this.executionCapabilities, options);
104
+ this.#assertScopeOpen();
105
+ this.#assertConnectionAvailable("execute a query");
106
+ if (options.signal?.aborted || (options.deadline !== undefined && Number(options.deadline) <= Date.now())) {
107
+ return runControlledExecution(options, async () => [], () => undefined);
108
+ }
109
+ if (this.#connection === undefined) {
110
+ const connection = await this.#pool.getConnection();
111
+ if (connection.destroy === undefined) {
112
+ connection.release();
113
+ throw new UnsupportedExecutionCapabilityError(options.signal === undefined ? "deadlines" : "cancellation");
114
+ }
115
+ let discarded = false;
116
+ try {
117
+ return await this.#executeControlledOn(connection, query, options, () => {
118
+ connection.destroy();
119
+ discarded = true;
120
+ });
121
+ }
122
+ finally {
123
+ if (!discarded)
124
+ connection.release();
125
+ }
126
+ }
127
+ const connection = this.#connection;
128
+ if (connection.destroy === undefined) {
129
+ throw new UnsupportedExecutionCapabilityError(options.signal === undefined ? "deadlines" : "cancellation");
130
+ }
131
+ const operationState = createMySqlConnectionOperation();
132
+ this.#executes.add(operationState);
133
+ this.#transactionState.execute = operationState;
134
+ try {
135
+ return await this.#executeControlledOn(connection, query, options, () => {
136
+ this.#transactionState.usable = false;
137
+ connection.destroy();
138
+ this.#transactionState.discarded = true;
139
+ });
140
+ }
141
+ finally {
142
+ this.#executes.delete(operationState);
143
+ if (this.#transactionState?.execute === operationState)
144
+ this.#transactionState.execute = undefined;
145
+ operationState.finish();
146
+ }
147
+ }
148
+ async #executeControlledOn(connection, query, options, cancel) {
149
+ return runControlledExecution(options, () => this.#executeOn(connection, query), cancel);
150
+ }
151
+ async one(query, options) {
152
+ if (this.#observation.observer === undefined) {
153
+ const rows = await this.#validateRows(query, await this.#allUnobserved(query, options));
154
+ if (rows.length !== 1)
155
+ throw new QueryCardinalityError("one", rows.length);
156
+ return rows[0];
157
+ }
158
+ const rows = await this.#observeQuery(query, "one", async () => {
159
+ const result = await this.#validateRows(query, await this.#allUnobserved(query, options));
160
+ if (result.length !== 1)
161
+ throw new QueryCardinalityError("one", result.length);
162
+ return result;
163
+ });
164
+ return rows[0];
165
+ }
166
+ async maybeOne(query, options) {
167
+ if (this.#observation.observer === undefined) {
168
+ const rows = await this.#validateRows(query, await this.#allUnobserved(query, options));
169
+ if (rows.length > 1)
170
+ throw new QueryCardinalityError("maybeOne", rows.length);
171
+ return rows[0];
172
+ }
173
+ const rows = await this.#observeQuery(query, "maybeOne", async () => {
174
+ const result = await this.#validateRows(query, await this.#allUnobserved(query, options));
175
+ if (result.length > 1)
176
+ throw new QueryCardinalityError("maybeOne", result.length);
177
+ return result;
178
+ });
179
+ return rows[0];
180
+ }
181
+ async #observeQuery(query, cardinality, operation) {
182
+ if (this.#observation.observer === undefined)
183
+ return operation();
184
+ const observation = startDatabaseObservation(this.#observation.observer, {
185
+ kind: "query",
186
+ dialect: "mysql",
187
+ grammarVersion: MYSQL_DIALECT_VERSION,
188
+ transactionDepth: this.#depth,
189
+ fingerprint: mysqlQueryFingerprint(this.#observation, query),
190
+ cardinality,
191
+ prepared: this.#prepared.queries.has(queryResultValidationSource(query)),
192
+ });
193
+ if (observation === undefined)
194
+ return operation();
195
+ try {
196
+ const rows = await observation.run(operation);
197
+ observation.end({ status: "success", rowCount: rows.length });
198
+ return rows;
199
+ }
200
+ catch (error) {
201
+ observation.end(databaseErrorCompletion(error), error);
202
+ throw error;
203
+ }
204
+ }
60
205
  async #executeOn(executor, query) {
61
- const prepared = this.#prepared.queries.get(query);
206
+ const prepared = this.#prepared.queries.get(queryResultValidationSource(query));
62
207
  const rendered = prepared?.rendered ?? renderQuery(query, mysqlRenderer);
63
208
  const result = await executor.execute(rendered.text, rendered.values.map(encodeMySqlValue));
64
209
  if (!Array.isArray(result.rows))
@@ -67,6 +212,14 @@ class MySqlDatabaseImplementation {
67
212
  return decodeMySqlRows(result.rows, decoders);
68
213
  }
69
214
  async batch(queries) {
215
+ if (queries.length === 0)
216
+ return emptyBatchResults;
217
+ if (this.#observation.observer === undefined) {
218
+ return this.#validateBatch(queries, await this.#batchUnobserved(queries));
219
+ }
220
+ return this.#observeBatch(queries, async () => this.#validateBatch(queries, await this.#batchUnobserved(queries)));
221
+ }
222
+ async #batchUnobserved(queries) {
70
223
  this.#assertScopeOpen();
71
224
  this.#assertConnectionAvailable("execute a batch");
72
225
  if (queries.length === 0)
@@ -101,6 +254,30 @@ class MySqlDatabaseImplementation {
101
254
  connection.release();
102
255
  return results;
103
256
  }
257
+ async #observeBatch(queries, operation) {
258
+ if (this.#observation.observer === undefined)
259
+ return operation();
260
+ const fingerprints = Object.freeze([...queries].map((query) => mysqlQueryFingerprint(this.#observation, query)));
261
+ const observation = startDatabaseObservation(this.#observation.observer, {
262
+ kind: "batch",
263
+ dialect: "mysql",
264
+ grammarVersion: MYSQL_DIALECT_VERSION,
265
+ transactionDepth: this.#depth,
266
+ fingerprints,
267
+ size: queries.length,
268
+ });
269
+ if (observation === undefined)
270
+ return operation();
271
+ try {
272
+ const results = await observation.run(operation);
273
+ observation.end({ status: "success" });
274
+ return results;
275
+ }
276
+ catch (error) {
277
+ observation.end(databaseErrorCompletion(error), error);
278
+ throw error;
279
+ }
280
+ }
104
281
  async #executeBatchOn(connection, queries, beforeEach) {
105
282
  const results = [];
106
283
  for (const query of queries) {
@@ -111,16 +288,16 @@ class MySqlDatabaseImplementation {
111
288
  }
112
289
  stream(query, options = {}) {
113
290
  this.#assertScopeOpen();
114
- const prepared = this.#prepared.queries.get(query);
291
+ const prepared = this.#prepared.queries.get(queryResultValidationSource(query));
115
292
  const rendered = prepared?.rendered ?? renderQuery(query, mysqlRenderer);
116
293
  const batchSize = validateMySqlStreamBatchSize(options.batchSize);
117
- let queryStream;
118
- queryStream = createMySqlQueryStream({
294
+ let exposedStream;
295
+ const queryStream = createMySqlQueryStream({
119
296
  openConnection: async () => {
120
297
  if (this.#connection !== undefined) {
121
298
  this.#assertScopeOpen();
122
299
  this.#assertConnectionAvailable("start another query stream");
123
- this.#transactionState.active = queryStream;
300
+ this.#transactionState.active = exposedStream;
124
301
  return { connection: this.#connection, release: false };
125
302
  }
126
303
  return { connection: await this.#pool.getConnection(), release: true };
@@ -130,19 +307,113 @@ class MySqlDatabaseImplementation {
130
307
  batchSize,
131
308
  decoderPlans: this.#decoderPlans,
132
309
  onClose: () => {
133
- this.#streams?.delete(queryStream);
134
- if (this.#transactionState?.active === queryStream)
310
+ this.#streams?.delete(exposedStream);
311
+ if (this.#transactionState?.active === exposedStream)
135
312
  this.#transactionState.active = undefined;
136
313
  },
137
314
  });
138
- this.#streams?.add(queryStream);
139
- return queryStream;
315
+ const validatedStream = hasQueryResultValidator(query)
316
+ ? validateQueryResultStream(query, queryStream, mysqlQueryFingerprint(this.#observation, query))
317
+ : queryStream;
318
+ exposedStream =
319
+ this.#observation.observer === undefined
320
+ ? validatedStream
321
+ : observeQueryStream(validatedStream, this.#observation.observer, {
322
+ kind: "stream",
323
+ dialect: "mysql",
324
+ grammarVersion: MYSQL_DIALECT_VERSION,
325
+ transactionDepth: this.#depth,
326
+ fingerprint: mysqlQueryFingerprint(this.#observation, query),
327
+ prepared: prepared !== undefined,
328
+ });
329
+ this.#streams?.add(exposedStream);
330
+ return exposedStream;
331
+ }
332
+ async #validateRows(query, rows) {
333
+ if (!hasQueryResultValidator(query))
334
+ return rows;
335
+ return validateQueryResultRows(query, rows, mysqlQueryFingerprint(this.#observation, query));
336
+ }
337
+ async #validateBatch(queries, results) {
338
+ let validated;
339
+ const queryList = queries;
340
+ const resultList = results;
341
+ for (let index = 0; index < queryList.length; index += 1) {
342
+ const query = queryList[index];
343
+ if (!hasQueryResultValidator(query))
344
+ continue;
345
+ validated ??= [...resultList];
346
+ validated[index] = await validateQueryResultRows(query, resultList[index], mysqlQueryFingerprint(this.#observation, query));
347
+ }
348
+ return (validated ?? results);
349
+ }
350
+ async #loadData(statement, chunks, options) {
351
+ assertExecutionCapabilities(this.executionCapabilities, options);
352
+ this.#assertScopeOpen();
353
+ this.#assertConnectionAvailable("start LOAD DATA");
354
+ const connection = this.#connection ?? (await this.#pool.getConnection());
355
+ if (connection.loadData === undefined) {
356
+ if (this.#connection === undefined)
357
+ connection.release();
358
+ throw new Error("MySQL LOAD DATA requires an adapter with an application-owned local infile stream implementation");
359
+ }
360
+ const state = createMySqlConnectionOperation();
361
+ if (this.#connection !== undefined)
362
+ this.#transactionState.bulk = state;
363
+ let discarded = false;
364
+ const discard = () => {
365
+ if (discarded || connection.destroy === undefined)
366
+ return;
367
+ discarded = true;
368
+ connection.destroy();
369
+ if (this.#transactionState !== undefined) {
370
+ this.#transactionState.usable = false;
371
+ this.#transactionState.discarded = true;
372
+ }
373
+ };
374
+ try {
375
+ await runControlledExecution(options, () => connection.loadData(statement, chunks), discard);
376
+ if (this.#connection === undefined)
377
+ connection.release();
378
+ }
379
+ catch (error) {
380
+ discard();
381
+ if (!discarded && this.#connection === undefined)
382
+ connection.release();
383
+ throw error;
384
+ }
385
+ finally {
386
+ if (this.#transactionState?.bulk === state)
387
+ this.#transactionState.bulk = undefined;
388
+ state.finish();
389
+ }
140
390
  }
141
391
  prepare(statementName, factory) {
142
392
  this.#assertScopeOpen();
143
393
  return prepareMySqlQuery(this.#prepared, mysqlRenderer, statementName, factory);
144
394
  }
145
395
  async transaction(fn) {
396
+ if (this.#observation.observer === undefined)
397
+ return this.#transactionUnobserved(fn);
398
+ const observation = startDatabaseObservation(this.#observation.observer, {
399
+ kind: "transaction",
400
+ dialect: "mysql",
401
+ grammarVersion: MYSQL_DIALECT_VERSION,
402
+ transactionDepth: this.#depth + 1,
403
+ });
404
+ if (observation === undefined)
405
+ return this.#transactionUnobserved(fn);
406
+ try {
407
+ const result = await observation.run(() => this.#transactionUnobserved(fn));
408
+ observation.end({ status: "success" });
409
+ return result;
410
+ }
411
+ catch (error) {
412
+ observation.end(databaseErrorCompletion(error), error);
413
+ throw error;
414
+ }
415
+ }
416
+ async #transactionUnobserved(fn) {
146
417
  this.#assertScopeOpen();
147
418
  if (this.#connection !== undefined)
148
419
  return this.#nested(fn);
@@ -151,7 +422,7 @@ class MySqlDatabaseImplementation {
151
422
  let result;
152
423
  try {
153
424
  await connection.beginTransaction();
154
- transaction = new _a(this.#pool, connection, false, 1, this.#prepared, this.#decoderPlans, { active: undefined, batch: undefined, execute: undefined, usable: true });
425
+ transaction = new _a(this.#pool, connection, false, 1, this.#prepared, this.#decoderPlans, this.#observation, { active: undefined, batch: undefined, bulk: undefined, execute: undefined, discarded: false, usable: true });
155
426
  result = await fn(transaction);
156
427
  transaction.#scopeOpen = false;
157
428
  transaction.#transactionState.usable = false;
@@ -164,17 +435,19 @@ class MySqlDatabaseImplementation {
164
435
  transaction.#transactionState.usable = false;
165
436
  await transaction.#invalidateScope();
166
437
  }
167
- try {
168
- await connection.rollback();
169
- }
170
- catch {
171
- /* Preserve the original failure. */
172
- }
173
- try {
174
- connection.release();
175
- }
176
- catch {
177
- /* Preserve the original failure. */
438
+ if (transaction === undefined || transaction.#transactionState?.discarded !== true) {
439
+ try {
440
+ await connection.rollback();
441
+ }
442
+ catch {
443
+ /* Preserve the original failure. */
444
+ }
445
+ try {
446
+ connection.release();
447
+ }
448
+ catch {
449
+ /* Preserve the original failure. */
450
+ }
178
451
  }
179
452
  throw error;
180
453
  }
@@ -190,7 +463,7 @@ class MySqlDatabaseImplementation {
190
463
  await connection.query(`SAVEPOINT ${savepoint}`);
191
464
  let transaction;
192
465
  try {
193
- transaction = new _a(this.#pool, connection, false, depth, this.#prepared, this.#decoderPlans, this.#transactionState);
466
+ transaction = new _a(this.#pool, connection, false, depth, this.#prepared, this.#decoderPlans, this.#observation, this.#transactionState);
194
467
  const result = await fn(transaction);
195
468
  transaction.#scopeOpen = false;
196
469
  await transaction.#assertTransactionReadyForFinalize();
@@ -231,12 +504,14 @@ class MySqlDatabaseImplementation {
231
504
  await this.#closeStreams();
232
505
  await this.#settleExecutes();
233
506
  await this.#settleBatch();
507
+ await this.#settleBulk();
234
508
  }
235
509
  async #assertTransactionReadyForFinalize(connectionFinalizing = false) {
236
510
  const leakedExecutes = new Set(this.#executes);
237
511
  if (this.#transactionState?.execute !== undefined)
238
512
  leakedExecutes.add(this.#transactionState.execute);
239
513
  const leakedBatch = this.#transactionState?.batch;
514
+ const leakedBulk = this.#transactionState?.bulk;
240
515
  await this.#rejectActiveStreams();
241
516
  const active = this.#transactionState?.active;
242
517
  if (active !== undefined) {
@@ -251,6 +526,10 @@ class MySqlDatabaseImplementation {
251
526
  await leakedBatch.completion;
252
527
  throw new Error("MySQL transaction callback returned while an ordered batch owned its connection; await the batch before returning");
253
528
  }
529
+ if (leakedBulk !== undefined) {
530
+ await leakedBulk.completion;
531
+ throw new Error("MySQL transaction callback returned while LOAD DATA owned its connection; await LOAD DATA before returning");
532
+ }
254
533
  if (!connectionFinalizing && this.#transactionState?.usable === false)
255
534
  throw new Error("This MySQL transaction connection is no longer active");
256
535
  }
@@ -259,6 +538,8 @@ class MySqlDatabaseImplementation {
259
538
  throw new Error(`Cannot ${action} while a MySQL query stream owns the transaction connection`);
260
539
  if (this.#transactionState?.batch !== undefined)
261
540
  throw new Error(`Cannot ${action} while a MySQL ordered batch owns the transaction connection`);
541
+ if (this.#transactionState?.bulk !== undefined)
542
+ throw new Error(`Cannot ${action} while MySQL LOAD DATA owns the transaction connection`);
262
543
  if (this.#transactionState?.execute !== undefined)
263
544
  throw new Error(`Cannot ${action} while a MySQL execute operation owns the transaction connection`);
264
545
  }
@@ -272,6 +553,11 @@ class MySqlDatabaseImplementation {
272
553
  if (batch !== undefined)
273
554
  await batch.completion;
274
555
  }
556
+ async #settleBulk() {
557
+ const bulk = this.#transactionState?.bulk;
558
+ if (bulk !== undefined)
559
+ await bulk.completion;
560
+ }
275
561
  async #settleExecutes() {
276
562
  const operations = new Set(this.#executes);
277
563
  if (this.#transactionState?.execute !== undefined)
@@ -299,6 +585,6 @@ export function createMySqlDatabase(options) {
299
585
  const typePolicy = { ...defaultRuntimeTypePolicy, ...options.typePolicy };
300
586
  if (typePolicy.decimal === "Decimal" && options.decimal === undefined)
301
587
  throw new TypeError("decimal=Decimal requires a decimal(value) codec");
302
- return new MySqlDatabaseImplementation(options.pool, undefined, options.ownsPool ?? false, 0, createMySqlPreparedQueryState(), new MySqlDecoderPlanCache(typePolicy, options.decimal));
588
+ return new MySqlDatabaseImplementation(options.pool, undefined, options.ownsPool ?? false, 0, createMySqlPreparedQueryState(), new MySqlDecoderPlanCache(typePolicy, options.decimal), createMySqlObservationState(options.observer));
303
589
  }
304
590
  //# sourceMappingURL=runtime.js.map