@typed-sql/mysql 1.0.0 → 2.0.0-rc.1
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/CHANGELOG.md +60 -0
- package/README.md +22 -4
- package/dist/packages/mysql/src/bulk.d.ts +22 -0
- package/dist/packages/mysql/src/bulk.d.ts.map +1 -0
- package/dist/packages/mysql/src/bulk.js +205 -0
- package/dist/packages/mysql/src/bulk.js.map +1 -0
- package/dist/packages/mysql/src/index.d.ts +5 -1
- package/dist/packages/mysql/src/index.d.ts.map +1 -1
- package/dist/packages/mysql/src/index.js +16 -3
- package/dist/packages/mysql/src/index.js.map +1 -1
- package/dist/packages/mysql/src/mysql2.d.ts +60 -1
- package/dist/packages/mysql/src/mysql2.d.ts.map +1 -1
- package/dist/packages/mysql/src/mysql2.js +296 -0
- package/dist/packages/mysql/src/mysql2.js.map +1 -1
- package/dist/packages/mysql/src/provider.d.ts.map +1 -1
- package/dist/packages/mysql/src/provider.js +8 -1
- package/dist/packages/mysql/src/provider.js.map +1 -1
- package/dist/packages/mysql/src/resolver.d.ts.map +1 -1
- package/dist/packages/mysql/src/resolver.js +20 -1
- package/dist/packages/mysql/src/resolver.js.map +1 -1
- package/dist/packages/mysql/src/routing.d.ts +22 -0
- package/dist/packages/mysql/src/routing.d.ts.map +1 -0
- package/dist/packages/mysql/src/routing.js +72 -0
- package/dist/packages/mysql/src/routing.js.map +1 -0
- package/dist/packages/mysql/src/runtime.d.ts +6 -1
- package/dist/packages/mysql/src/runtime.d.ts.map +1 -1
- package/dist/packages/mysql/src/runtime.js +311 -25
- package/dist/packages/mysql/src/runtime.js.map +1 -1
- package/dist/packages/mysql/src/semantics.d.ts +5 -0
- package/dist/packages/mysql/src/semantics.d.ts.map +1 -0
- package/dist/packages/mysql/src/semantics.js +203 -0
- package/dist/packages/mysql/src/semantics.js.map +1 -0
- package/dist/packages/mysql/src/version.d.ts +2 -0
- package/dist/packages/mysql/src/version.d.ts.map +1 -0
- package/dist/packages/mysql/src/version.js +2 -0
- package/dist/packages/mysql/src/version.js.map +1 -0
- 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":"
|
|
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 {
|
|
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
|
-
|
|
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
|
|
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 =
|
|
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(
|
|
134
|
-
if (this.#transactionState?.active ===
|
|
310
|
+
this.#streams?.delete(exposedStream);
|
|
311
|
+
if (this.#transactionState?.active === exposedStream)
|
|
135
312
|
this.#transactionState.active = undefined;
|
|
136
313
|
},
|
|
137
314
|
});
|
|
138
|
-
|
|
139
|
-
|
|
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
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
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
|