@typed-sql/mysql 2.0.0 → 2.1.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.
- package/CHANGELOG.md +129 -0
- package/README.md +12 -0
- package/dist/packages/mysql/src/bulk.d.ts.map +1 -1
- package/dist/packages/mysql/src/bulk.js +9 -3
- package/dist/packages/mysql/src/bulk.js.map +1 -1
- package/dist/packages/mysql/src/capabilities.d.ts +30 -0
- package/dist/packages/mysql/src/capabilities.d.ts.map +1 -0
- package/dist/packages/mysql/src/capabilities.js +233 -0
- package/dist/packages/mysql/src/capabilities.js.map +1 -0
- package/dist/packages/mysql/src/catalog/generated/26.7.d.ts +4 -0
- package/dist/packages/mysql/src/catalog/generated/26.7.d.ts.map +1 -0
- package/dist/packages/mysql/src/catalog/generated/26.7.js +3 -0
- package/dist/packages/mysql/src/catalog/generated/26.7.js.map +1 -0
- package/dist/packages/mysql/src/catalog/generated/8.4.d.ts +4 -0
- package/dist/packages/mysql/src/catalog/generated/8.4.d.ts.map +1 -0
- package/dist/packages/mysql/src/catalog/generated/8.4.js +3 -0
- package/dist/packages/mysql/src/catalog/generated/8.4.js.map +1 -0
- package/dist/packages/mysql/src/catalog/generated/9.7.d.ts +4 -0
- package/dist/packages/mysql/src/catalog/generated/9.7.d.ts.map +1 -0
- package/dist/packages/mysql/src/catalog/generated/9.7.js +3 -0
- package/dist/packages/mysql/src/catalog/generated/9.7.js.map +1 -0
- package/dist/packages/mysql/src/catalog/index.d.ts +15 -0
- package/dist/packages/mysql/src/catalog/index.d.ts.map +1 -0
- package/dist/packages/mysql/src/catalog/index.js +129 -0
- package/dist/packages/mysql/src/catalog/index.js.map +1 -0
- package/dist/packages/mysql/src/catalog/types.d.ts +50 -0
- package/dist/packages/mysql/src/catalog/types.d.ts.map +1 -0
- package/dist/packages/mysql/src/catalog/types.js +2 -0
- package/dist/packages/mysql/src/catalog/types.js.map +1 -0
- package/dist/packages/mysql/src/index.d.ts +9 -1
- package/dist/packages/mysql/src/index.d.ts.map +1 -1
- package/dist/packages/mysql/src/index.js +37 -15
- package/dist/packages/mysql/src/index.js.map +1 -1
- package/dist/packages/mysql/src/mysql2.d.ts +9 -1
- package/dist/packages/mysql/src/mysql2.d.ts.map +1 -1
- package/dist/packages/mysql/src/mysql2.js +86 -3
- package/dist/packages/mysql/src/mysql2.js.map +1 -1
- package/dist/packages/mysql/src/parser/index.d.ts +8 -0
- package/dist/packages/mysql/src/parser/index.d.ts.map +1 -0
- package/dist/packages/mysql/src/parser/index.js +4 -0
- package/dist/packages/mysql/src/parser/index.js.map +1 -0
- package/dist/packages/mysql/src/parser/parser.d.ts +14 -0
- package/dist/packages/mysql/src/parser/parser.d.ts.map +1 -0
- package/dist/packages/mysql/src/parser/parser.js +1276 -0
- package/dist/packages/mysql/src/parser/parser.js.map +1 -0
- package/dist/packages/mysql/src/parser/tokenizer.d.ts +18 -0
- package/dist/packages/mysql/src/parser/tokenizer.d.ts.map +1 -0
- package/dist/packages/mysql/src/parser/tokenizer.js +385 -0
- package/dist/packages/mysql/src/parser/tokenizer.js.map +1 -0
- package/dist/packages/mysql/src/parser/types.d.ts +313 -0
- package/dist/packages/mysql/src/parser/types.d.ts.map +1 -0
- package/dist/packages/mysql/src/parser/types.js +9 -0
- package/dist/packages/mysql/src/parser/types.js.map +1 -0
- package/dist/packages/mysql/src/parser/walk.d.ts +13 -0
- package/dist/packages/mysql/src/parser/walk.d.ts.map +1 -0
- package/dist/packages/mysql/src/parser/walk.js +190 -0
- package/dist/packages/mysql/src/parser/walk.js.map +1 -0
- package/dist/packages/mysql/src/prepared.d.ts +6 -3
- package/dist/packages/mysql/src/prepared.d.ts.map +1 -1
- package/dist/packages/mysql/src/prepared.js +15 -14
- package/dist/packages/mysql/src/prepared.js.map +1 -1
- package/dist/packages/mysql/src/provider.d.ts +21 -5
- package/dist/packages/mysql/src/provider.d.ts.map +1 -1
- package/dist/packages/mysql/src/provider.js +647 -44
- package/dist/packages/mysql/src/provider.js.map +1 -1
- package/dist/packages/mysql/src/resolver.d.ts +5 -1
- package/dist/packages/mysql/src/resolver.d.ts.map +1 -1
- package/dist/packages/mysql/src/resolver.js +1207 -95
- package/dist/packages/mysql/src/resolver.js.map +1 -1
- package/dist/packages/mysql/src/routing.d.ts.map +1 -1
- package/dist/packages/mysql/src/routing.js +3 -2
- package/dist/packages/mysql/src/routing.js.map +1 -1
- package/dist/packages/mysql/src/runtime.d.ts +33 -0
- package/dist/packages/mysql/src/runtime.d.ts.map +1 -1
- package/dist/packages/mysql/src/runtime.js +166 -12
- package/dist/packages/mysql/src/runtime.js.map +1 -1
- package/dist/packages/mysql/src/semantics.d.ts +1 -1
- package/dist/packages/mysql/src/semantics.d.ts.map +1 -1
- package/dist/packages/mysql/src/semantics.js +27 -3
- package/dist/packages/mysql/src/semantics.js.map +1 -1
- package/dist/packages/mysql/src/support.d.ts +43 -0
- package/dist/packages/mysql/src/support.d.ts.map +1 -0
- package/dist/packages/mysql/src/support.js +102 -0
- package/dist/packages/mysql/src/support.js.map +1 -0
- package/dist/packages/mysql/src/type-policy.d.ts +2 -0
- package/dist/packages/mysql/src/type-policy.d.ts.map +1 -1
- package/dist/packages/mysql/src/type-policy.js +24 -50
- package/dist/packages/mysql/src/type-policy.js.map +1 -1
- package/package.json +8 -5
|
@@ -1,7 +1,22 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { defineSchemaSnapshotV2, fingerprintSchemaExpression, } from "@typed-sql/schema";
|
|
2
|
+
import { mySqlServerEvidence } from "./capabilities.js";
|
|
3
|
+
import { mySqlCoreCatalogForSchema } from "./catalog/index.js";
|
|
4
|
+
import { defaultMySqlTypePolicy, mapMySqlType, mySqlEnumValues, mySqlSetValues, } from "./type-policy.js";
|
|
5
|
+
import { MYSQL_DIALECT_VERSION } from "./version.js";
|
|
2
6
|
export const mysqlCatalogQueries = Object.freeze({
|
|
3
|
-
version: "SELECT VERSION() AS server_version",
|
|
7
|
+
version: "SELECT VERSION() AS server_version, @@version_comment AS version_comment, @@session.sql_mode AS sql_mode, @@global.character_set_server AS character_set_server, @@global.collation_server AS collation_server, @@session.character_set_connection AS character_set_connection, @@session.collation_connection AS collation_connection, @@session.time_zone AS time_zone, @@global.system_time_zone AS system_time_zone, @@global.lower_case_table_names AS lower_case_table_names",
|
|
4
8
|
database: "SELECT DATABASE() AS database_name",
|
|
9
|
+
schemas(schemaCount) {
|
|
10
|
+
return `
|
|
11
|
+
SELECT 'def' AS catalog_name,
|
|
12
|
+
SCHEMA_NAME AS schema_name,
|
|
13
|
+
DEFAULT_CHARACTER_SET_NAME AS default_character_set_name,
|
|
14
|
+
DEFAULT_COLLATION_NAME AS default_collation_name
|
|
15
|
+
FROM information_schema.SCHEMATA
|
|
16
|
+
WHERE SCHEMA_NAME IN (${Array.from({ length: schemaCount }, () => "?").join(", ")})
|
|
17
|
+
ORDER BY SCHEMA_NAME
|
|
18
|
+
`;
|
|
19
|
+
},
|
|
5
20
|
columns(schemaCount) {
|
|
6
21
|
return `
|
|
7
22
|
SELECT TABLE_SCHEMA AS schema_name,
|
|
@@ -9,8 +24,22 @@ export const mysqlCatalogQueries = Object.freeze({
|
|
|
9
24
|
COLUMN_NAME AS column_name,
|
|
10
25
|
COLUMN_TYPE AS database_type,
|
|
11
26
|
IS_NULLABLE AS is_nullable,
|
|
12
|
-
COLUMN_DEFAULT AS default_expression
|
|
27
|
+
COLUMN_DEFAULT AS default_expression,
|
|
28
|
+
ORDINAL_POSITION AS ordinal_position,
|
|
29
|
+
CHARACTER_SET_NAME AS character_set_name,
|
|
30
|
+
COLLATION_NAME AS collation_name,
|
|
31
|
+
EXTRA AS extra,
|
|
32
|
+
GENERATION_EXPRESSION AS generation_expression,
|
|
33
|
+
CHARACTER_MAXIMUM_LENGTH AS character_maximum_length,
|
|
34
|
+
NUMERIC_PRECISION AS numeric_precision,
|
|
35
|
+
NUMERIC_SCALE AS numeric_scale,
|
|
36
|
+
DATETIME_PRECISION AS datetime_precision,
|
|
37
|
+
SRS_ID AS spatial_reference_system_id,
|
|
38
|
+
t.TABLE_TYPE AS table_type,
|
|
39
|
+
v.IS_UPDATABLE AS view_updatable
|
|
13
40
|
FROM information_schema.COLUMNS
|
|
41
|
+
JOIN information_schema.TABLES AS t USING (TABLE_SCHEMA, TABLE_NAME)
|
|
42
|
+
LEFT JOIN information_schema.VIEWS AS v USING (TABLE_SCHEMA, TABLE_NAME)
|
|
14
43
|
WHERE TABLE_SCHEMA IN (${Array.from({ length: schemaCount }, () => "?").join(", ")})
|
|
15
44
|
ORDER BY TABLE_SCHEMA, TABLE_NAME, ORDINAL_POSITION
|
|
16
45
|
`;
|
|
@@ -19,16 +48,249 @@ export const mysqlCatalogQueries = Object.freeze({
|
|
|
19
48
|
return `
|
|
20
49
|
SELECT ROUTINE_SCHEMA AS schema_name,
|
|
21
50
|
ROUTINE_NAME AS function_name,
|
|
51
|
+
ROUTINE_TYPE AS routine_type,
|
|
22
52
|
DTD_IDENTIFIER AS database_return_type,
|
|
23
53
|
IS_DETERMINISTIC AS is_deterministic,
|
|
24
|
-
SQL_DATA_ACCESS AS sql_data_access
|
|
54
|
+
SQL_DATA_ACCESS AS sql_data_access,
|
|
55
|
+
CHARACTER_SET_NAME AS return_character_set,
|
|
56
|
+
COLLATION_NAME AS return_collation,
|
|
57
|
+
SECURITY_TYPE AS security_type,
|
|
58
|
+
SQL_MODE AS creation_sql_mode,
|
|
59
|
+
CHARACTER_SET_CLIENT AS creation_character_set,
|
|
60
|
+
COLLATION_CONNECTION AS creation_collation,
|
|
61
|
+
DATABASE_COLLATION AS database_collation
|
|
25
62
|
FROM information_schema.ROUTINES
|
|
26
|
-
WHERE
|
|
27
|
-
AND ROUTINE_SCHEMA IN (${Array.from({ length: schemaCount }, () => "?").join(", ")})
|
|
63
|
+
WHERE ROUTINE_SCHEMA IN (${Array.from({ length: schemaCount }, () => "?").join(", ")})
|
|
28
64
|
ORDER BY ROUTINE_SCHEMA, ROUTINE_NAME
|
|
29
65
|
`;
|
|
30
66
|
},
|
|
67
|
+
parameters(schemaCount) {
|
|
68
|
+
return `
|
|
69
|
+
SELECT SPECIFIC_SCHEMA AS schema_name, SPECIFIC_NAME AS routine_name,
|
|
70
|
+
ORDINAL_POSITION AS ordinal_position, PARAMETER_MODE AS parameter_mode,
|
|
71
|
+
PARAMETER_NAME AS parameter_name, DTD_IDENTIFIER AS database_type,
|
|
72
|
+
CHARACTER_SET_NAME AS character_set_name, COLLATION_NAME AS collation_name
|
|
73
|
+
FROM information_schema.PARAMETERS
|
|
74
|
+
WHERE SPECIFIC_SCHEMA IN (${Array.from({ length: schemaCount }, () => "?").join(", ")})
|
|
75
|
+
ORDER BY SPECIFIC_SCHEMA, SPECIFIC_NAME, ORDINAL_POSITION
|
|
76
|
+
`;
|
|
77
|
+
},
|
|
78
|
+
constraints(schemaCount) {
|
|
79
|
+
return `
|
|
80
|
+
SELECT tc.CONSTRAINT_SCHEMA AS schema_name, tc.TABLE_NAME AS table_name,
|
|
81
|
+
tc.CONSTRAINT_NAME AS constraint_name, tc.CONSTRAINT_TYPE AS constraint_type,
|
|
82
|
+
kcu.COLUMN_NAME AS column_name,
|
|
83
|
+
kcu.REFERENCED_TABLE_SCHEMA AS referenced_schema,
|
|
84
|
+
kcu.REFERENCED_TABLE_NAME AS referenced_table,
|
|
85
|
+
kcu.REFERENCED_COLUMN_NAME AS referenced_column_name,
|
|
86
|
+
rc.UPDATE_RULE AS update_rule, rc.DELETE_RULE AS delete_rule,
|
|
87
|
+
cc.CHECK_CLAUSE AS check_clause,
|
|
88
|
+
tc.ENFORCED AS enforced,
|
|
89
|
+
COALESCE(kcu.ORDINAL_POSITION, 0) AS ordinal_position
|
|
90
|
+
FROM information_schema.TABLE_CONSTRAINTS AS tc
|
|
91
|
+
LEFT JOIN information_schema.KEY_COLUMN_USAGE AS kcu
|
|
92
|
+
ON kcu.CONSTRAINT_SCHEMA = tc.CONSTRAINT_SCHEMA AND kcu.TABLE_NAME = tc.TABLE_NAME
|
|
93
|
+
AND kcu.CONSTRAINT_NAME = tc.CONSTRAINT_NAME
|
|
94
|
+
LEFT JOIN information_schema.REFERENTIAL_CONSTRAINTS AS rc
|
|
95
|
+
ON rc.CONSTRAINT_SCHEMA = tc.CONSTRAINT_SCHEMA AND rc.CONSTRAINT_NAME = tc.CONSTRAINT_NAME
|
|
96
|
+
LEFT JOIN information_schema.CHECK_CONSTRAINTS AS cc
|
|
97
|
+
ON cc.CONSTRAINT_SCHEMA = tc.CONSTRAINT_SCHEMA AND cc.CONSTRAINT_NAME = tc.CONSTRAINT_NAME
|
|
98
|
+
WHERE tc.CONSTRAINT_SCHEMA IN (${Array.from({ length: schemaCount }, () => "?").join(", ")})
|
|
99
|
+
ORDER BY tc.CONSTRAINT_SCHEMA, tc.TABLE_NAME, tc.CONSTRAINT_NAME, ordinal_position
|
|
100
|
+
`;
|
|
101
|
+
},
|
|
102
|
+
indexes(schemaCount) {
|
|
103
|
+
return `
|
|
104
|
+
SELECT s.TABLE_SCHEMA AS schema_name, s.TABLE_NAME AS table_name, s.INDEX_NAME AS index_name,
|
|
105
|
+
(s.NON_UNIQUE = 0) AS is_unique, s.INDEX_TYPE AS index_type,
|
|
106
|
+
s.COLUMN_NAME AS column_name, s.EXPRESSION AS expression,
|
|
107
|
+
COALESCE(s.COLLATION = 'D', 0) AS descending,
|
|
108
|
+
c.COLLATION_NAME AS column_collation,
|
|
109
|
+
s.SUB_PART AS prefix_length,
|
|
110
|
+
(s.IS_VISIBLE = 'YES') AS visible,
|
|
111
|
+
s.SEQ_IN_INDEX AS ordinal_position
|
|
112
|
+
FROM information_schema.STATISTICS AS s
|
|
113
|
+
LEFT JOIN information_schema.COLUMNS AS c
|
|
114
|
+
ON c.TABLE_SCHEMA = s.TABLE_SCHEMA AND c.TABLE_NAME = s.TABLE_NAME
|
|
115
|
+
AND c.COLUMN_NAME = s.COLUMN_NAME
|
|
116
|
+
WHERE s.TABLE_SCHEMA IN (${Array.from({ length: schemaCount }, () => "?").join(", ")})
|
|
117
|
+
ORDER BY s.TABLE_SCHEMA, s.TABLE_NAME, s.INDEX_NAME, s.SEQ_IN_INDEX
|
|
118
|
+
`;
|
|
119
|
+
},
|
|
31
120
|
});
|
|
121
|
+
function relationKey(schemas, schema, name) {
|
|
122
|
+
return schemas.length === 1 ? name : `${schema}.${name}`;
|
|
123
|
+
}
|
|
124
|
+
function foreignKeyAction(value) {
|
|
125
|
+
const normalized = value?.toUpperCase();
|
|
126
|
+
if (normalized === "RESTRICT")
|
|
127
|
+
return "restrict";
|
|
128
|
+
if (normalized === "CASCADE")
|
|
129
|
+
return "cascade";
|
|
130
|
+
if (normalized === "SET NULL")
|
|
131
|
+
return "set-null";
|
|
132
|
+
if (normalized === "SET DEFAULT")
|
|
133
|
+
return "set-default";
|
|
134
|
+
if (normalized === "NO ACTION")
|
|
135
|
+
return "no-action";
|
|
136
|
+
return "unknown";
|
|
137
|
+
}
|
|
138
|
+
function catalogArray(value, path) {
|
|
139
|
+
if (Array.isArray(value))
|
|
140
|
+
return value;
|
|
141
|
+
if (typeof value === "string") {
|
|
142
|
+
try {
|
|
143
|
+
const parsed = JSON.parse(value);
|
|
144
|
+
if (Array.isArray(parsed))
|
|
145
|
+
return parsed;
|
|
146
|
+
}
|
|
147
|
+
catch {
|
|
148
|
+
// The stable, redacted error below is more useful than a driver JSON failure.
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
throw new TypeError(`MySQL introspection ${path} must be a JSON array`);
|
|
152
|
+
}
|
|
153
|
+
function catalogBoolean(value, path) {
|
|
154
|
+
if (typeof value === "boolean")
|
|
155
|
+
return value;
|
|
156
|
+
if (value === 0 || value === "0")
|
|
157
|
+
return false;
|
|
158
|
+
if (value === 1 || value === "1")
|
|
159
|
+
return true;
|
|
160
|
+
throw new TypeError(`MySQL introspection ${path} must be boolean evidence`);
|
|
161
|
+
}
|
|
162
|
+
function optionalCatalogInteger(value, path) {
|
|
163
|
+
if (value === undefined || value === null)
|
|
164
|
+
return undefined;
|
|
165
|
+
const normalized = typeof value === "string" && /^\d+$/u.test(value.trim()) ? Number(value.trim()) : value;
|
|
166
|
+
if (!Number.isSafeInteger(normalized) || normalized < 0) {
|
|
167
|
+
throw new TypeError(`MySQL introspection ${path} must be non-negative integer evidence`);
|
|
168
|
+
}
|
|
169
|
+
return normalized;
|
|
170
|
+
}
|
|
171
|
+
function normalizeCatalogSqlMode(value) {
|
|
172
|
+
return [
|
|
173
|
+
...new Set(value
|
|
174
|
+
.split(",")
|
|
175
|
+
.map((mode) => mode.trim().toUpperCase())
|
|
176
|
+
.filter(Boolean)),
|
|
177
|
+
]
|
|
178
|
+
.sort()
|
|
179
|
+
.join(",");
|
|
180
|
+
}
|
|
181
|
+
function normalizeSchemas(values) {
|
|
182
|
+
const schemas = values.map((value) => {
|
|
183
|
+
if (typeof value !== "string" || value.trim().length === 0 || value.includes("\0")) {
|
|
184
|
+
throw new TypeError("MySQL introspection schema names must be non-empty strings without NUL bytes");
|
|
185
|
+
}
|
|
186
|
+
return value.trim();
|
|
187
|
+
});
|
|
188
|
+
return [...new Set(schemas)].sort();
|
|
189
|
+
}
|
|
190
|
+
function incompleteCatalogDiagnostic(catalog) {
|
|
191
|
+
return Object.freeze({
|
|
192
|
+
code: "TSQ406",
|
|
193
|
+
severity: "warning",
|
|
194
|
+
catalog,
|
|
195
|
+
message: `MySQL introspection could not read ${catalog} metadata; the snapshot contains incomplete evidence.`,
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
function compareCatalogIdentity(left, right) {
|
|
199
|
+
return (left.schema_name.localeCompare(right.schema_name) ||
|
|
200
|
+
left.table_name.localeCompare(right.table_name) ||
|
|
201
|
+
left.constraint_name.localeCompare(right.constraint_name));
|
|
202
|
+
}
|
|
203
|
+
function normalizeConstraintRows(rows) {
|
|
204
|
+
const groups = new Map();
|
|
205
|
+
for (const row of rows) {
|
|
206
|
+
const key = `${row.schema_name}\u0000${row.table_name}\u0000${row.constraint_name}`;
|
|
207
|
+
const group = groups.get(key);
|
|
208
|
+
if (group === undefined)
|
|
209
|
+
groups.set(key, [row]);
|
|
210
|
+
else
|
|
211
|
+
group.push(row);
|
|
212
|
+
}
|
|
213
|
+
return [...groups.values()]
|
|
214
|
+
.map((group) => {
|
|
215
|
+
const ordered = [...group].sort((left, right) => (left.ordinal_position ?? 0) - (right.ordinal_position ?? 0));
|
|
216
|
+
const first = ordered[0];
|
|
217
|
+
const referencedRow = ordered.find((row) => row.referenced_schema != null || row.referenced_table != null || row.referenced_column_name != null);
|
|
218
|
+
return {
|
|
219
|
+
...first,
|
|
220
|
+
referenced_schema: first.referenced_schema ?? referencedRow?.referenced_schema ?? null,
|
|
221
|
+
referenced_table: first.referenced_table ?? referencedRow?.referenced_table ?? null,
|
|
222
|
+
update_rule: first.update_rule ?? null,
|
|
223
|
+
delete_rule: first.delete_rule ?? null,
|
|
224
|
+
check_clause: first.check_clause ?? null,
|
|
225
|
+
columns: first.columns === undefined
|
|
226
|
+
? ordered.map(({ column_name }) => column_name).filter((column) => column != null)
|
|
227
|
+
: catalogArray(first.columns, "constraint columns"),
|
|
228
|
+
referenced_columns: first.referenced_columns === undefined
|
|
229
|
+
? ordered.map(({ referenced_column_name }) => referenced_column_name).filter((column) => column != null)
|
|
230
|
+
: first.referenced_columns === null
|
|
231
|
+
? []
|
|
232
|
+
: catalogArray(first.referenced_columns, "referenced constraint columns"),
|
|
233
|
+
};
|
|
234
|
+
})
|
|
235
|
+
.sort(compareCatalogIdentity);
|
|
236
|
+
}
|
|
237
|
+
function normalizeIndexRows(rows) {
|
|
238
|
+
const groups = new Map();
|
|
239
|
+
for (const row of rows) {
|
|
240
|
+
const key = `${row.schema_name}\u0000${row.table_name}\u0000${row.index_name}`;
|
|
241
|
+
const group = groups.get(key);
|
|
242
|
+
if (group === undefined)
|
|
243
|
+
groups.set(key, [row]);
|
|
244
|
+
else
|
|
245
|
+
group.push(row);
|
|
246
|
+
}
|
|
247
|
+
return [...groups.values()]
|
|
248
|
+
.map((group) => {
|
|
249
|
+
const ordered = [...group].sort((left, right) => (left.ordinal_position ?? 0) - (right.ordinal_position ?? 0));
|
|
250
|
+
const first = ordered[0];
|
|
251
|
+
return {
|
|
252
|
+
...first,
|
|
253
|
+
columns: first.columns === undefined
|
|
254
|
+
? ordered.map(({ column_name }) => column_name ?? null)
|
|
255
|
+
: catalogArray(first.columns, "index columns"),
|
|
256
|
+
expressions: first.expressions === undefined
|
|
257
|
+
? ordered.map(({ expression }) => expression ?? null)
|
|
258
|
+
: catalogArray(first.expressions, "index expressions"),
|
|
259
|
+
descending: first.descending === undefined || Array.isArray(first.descending)
|
|
260
|
+
? first.descending === undefined
|
|
261
|
+
? ordered.map(() => false)
|
|
262
|
+
: first.descending
|
|
263
|
+
: typeof first.descending === "string" && first.descending.startsWith("[")
|
|
264
|
+
? catalogArray(first.descending, "index ordering")
|
|
265
|
+
: ordered.map(({ descending }) => descending ?? false),
|
|
266
|
+
column_collations: first.column_collations === undefined
|
|
267
|
+
? ordered.map(({ column_collation }) => column_collation ?? null)
|
|
268
|
+
: catalogArray(first.column_collations, "index column collations"),
|
|
269
|
+
prefix_lengths: first.prefix_lengths === undefined
|
|
270
|
+
? ordered.map(({ prefix_length }) => prefix_length ?? null)
|
|
271
|
+
: catalogArray(first.prefix_lengths, "index prefix lengths"),
|
|
272
|
+
};
|
|
273
|
+
})
|
|
274
|
+
.sort((left, right) => left.schema_name.localeCompare(right.schema_name) ||
|
|
275
|
+
left.table_name.localeCompare(right.table_name) ||
|
|
276
|
+
left.index_name.localeCompare(right.index_name));
|
|
277
|
+
}
|
|
278
|
+
function routineDataAccess(value) {
|
|
279
|
+
if (value === "NO SQL")
|
|
280
|
+
return "none";
|
|
281
|
+
if (value === "CONTAINS SQL")
|
|
282
|
+
return "contains-sql";
|
|
283
|
+
if (value === "READS SQL DATA")
|
|
284
|
+
return "reads-sql";
|
|
285
|
+
return "modifies-sql";
|
|
286
|
+
}
|
|
287
|
+
function routineVolatility(row) {
|
|
288
|
+
if (row.sql_data_access === "MODIFIES SQL DATA" || row.is_deterministic === "NO")
|
|
289
|
+
return "volatile";
|
|
290
|
+
if (row.sql_data_access === "READS SQL DATA")
|
|
291
|
+
return "stable";
|
|
292
|
+
return "immutable";
|
|
293
|
+
}
|
|
32
294
|
export class MySqlSchemaProvider {
|
|
33
295
|
#client;
|
|
34
296
|
#schemas;
|
|
@@ -38,58 +300,399 @@ export class MySqlSchemaProvider {
|
|
|
38
300
|
this.#schemas = options.includeSchemas;
|
|
39
301
|
this.#policy = options.typePolicy ?? defaultMySqlTypePolicy;
|
|
40
302
|
}
|
|
41
|
-
async introspect(
|
|
42
|
-
|
|
303
|
+
async introspect(input) {
|
|
304
|
+
return (await this.introspectWithDiagnostics(input)).snapshot;
|
|
305
|
+
}
|
|
306
|
+
async introspectWithDiagnostics(_input) {
|
|
307
|
+
const client = this.#client;
|
|
308
|
+
if (client === undefined)
|
|
43
309
|
throw new TypeError("MySQL schema provider requires an injected client; use @typed-sql/mysql/mysql2 for a connection URI");
|
|
44
|
-
const
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
const
|
|
310
|
+
const versionRow = (await client.query(mysqlCatalogQueries.version)).rows[0];
|
|
311
|
+
if (versionRow === undefined)
|
|
312
|
+
throw new TypeError("MySQL introspection did not return a server version");
|
|
313
|
+
const version = versionRow.server_version;
|
|
314
|
+
const server = mySqlServerEvidence(version, {
|
|
315
|
+
...(versionRow.sql_mode === undefined ? {} : { sqlMode: versionRow.sql_mode }),
|
|
316
|
+
...(versionRow.version_comment === undefined ? {} : { versionComment: versionRow.version_comment }),
|
|
317
|
+
...(versionRow.character_set_server === undefined ? {} : { characterSetServer: versionRow.character_set_server }),
|
|
318
|
+
...(versionRow.collation_server === undefined ? {} : { collationServer: versionRow.collation_server }),
|
|
319
|
+
...(versionRow.character_set_connection === undefined
|
|
320
|
+
? {}
|
|
321
|
+
: { characterSetConnection: versionRow.character_set_connection }),
|
|
322
|
+
...(versionRow.collation_connection === undefined
|
|
323
|
+
? {}
|
|
324
|
+
: { collationConnection: versionRow.collation_connection }),
|
|
325
|
+
...(versionRow.time_zone === undefined ? {} : { timeZone: versionRow.time_zone }),
|
|
326
|
+
...(versionRow.system_time_zone === undefined ? {} : { systemTimeZone: versionRow.system_time_zone }),
|
|
327
|
+
...(versionRow.lower_case_table_names === undefined
|
|
328
|
+
? {}
|
|
329
|
+
: { lowerCaseTableNames: versionRow.lower_case_table_names }),
|
|
330
|
+
});
|
|
331
|
+
if (server.product !== "mysql") {
|
|
332
|
+
throw new TypeError(`MySQL introspection requires an Oracle MySQL server; detected ${server.product}`);
|
|
333
|
+
}
|
|
334
|
+
const typeContext = {
|
|
335
|
+
formatVersion: 1,
|
|
336
|
+
dialect: "mysql",
|
|
337
|
+
tables: {},
|
|
338
|
+
server,
|
|
339
|
+
};
|
|
340
|
+
const mapType = (databaseType) => mapMySqlType(databaseType, this.#policy, typeContext);
|
|
341
|
+
const currentDatabase = (await client.query(mysqlCatalogQueries.database)).rows[0]?.database_name;
|
|
342
|
+
const schemas = normalizeSchemas(this.#schemas ?? (currentDatabase === null || currentDatabase === undefined ? [] : [currentDatabase]));
|
|
48
343
|
if (schemas.length === 0)
|
|
49
344
|
throw new TypeError("MySQL introspection requires at least one database schema");
|
|
50
|
-
const
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
345
|
+
const diagnostics = [];
|
|
346
|
+
const catalogEvidence = new Map();
|
|
347
|
+
const queryCatalog = async (catalog, sql) => {
|
|
348
|
+
try {
|
|
349
|
+
const { rows } = await client.query(sql, schemas);
|
|
350
|
+
catalogEvidence.set(catalog, "complete");
|
|
351
|
+
return rows;
|
|
352
|
+
}
|
|
353
|
+
catch {
|
|
354
|
+
catalogEvidence.set(catalog, "incomplete");
|
|
355
|
+
diagnostics.push(incompleteCatalogDiagnostic(catalog));
|
|
356
|
+
return [];
|
|
357
|
+
}
|
|
358
|
+
};
|
|
359
|
+
const [schemaRows, columnRows, routineRows, parameterRows, constraintRows, indexRows] = await Promise.all([
|
|
360
|
+
queryCatalog("schemas", mysqlCatalogQueries.schemas(schemas.length)),
|
|
361
|
+
queryCatalog("columns", mysqlCatalogQueries.columns(schemas.length)),
|
|
362
|
+
queryCatalog("routines", mysqlCatalogQueries.routines(schemas.length)),
|
|
363
|
+
queryCatalog("parameters", mysqlCatalogQueries.parameters(schemas.length)),
|
|
364
|
+
queryCatalog("constraints", mysqlCatalogQueries.constraints(schemas.length)),
|
|
365
|
+
queryCatalog("indexes", mysqlCatalogQueries.indexes(schemas.length)),
|
|
366
|
+
]);
|
|
367
|
+
if (catalogEvidence.get("schemas") === "complete") {
|
|
368
|
+
const visibleSchemas = new Set(schemaRows.map(({ schema_name }) => schema_name));
|
|
369
|
+
if (schemas.some((schema) => !visibleSchemas.has(schema))) {
|
|
370
|
+
catalogEvidence.set("schemas", "incomplete");
|
|
371
|
+
diagnostics.push(incompleteCatalogDiagnostic("schemas"));
|
|
60
372
|
}
|
|
61
|
-
|
|
373
|
+
}
|
|
374
|
+
const relations = {};
|
|
375
|
+
const types = {};
|
|
376
|
+
const orderedColumnRows = [...columnRows].sort((left, right) => left.schema_name.localeCompare(right.schema_name) ||
|
|
377
|
+
left.table_name.localeCompare(right.table_name) ||
|
|
378
|
+
(left.ordinal_position ?? Number.MAX_SAFE_INTEGER) - (right.ordinal_position ?? Number.MAX_SAFE_INTEGER) ||
|
|
379
|
+
left.column_name.localeCompare(right.column_name));
|
|
380
|
+
for (const row of orderedColumnRows) {
|
|
381
|
+
const key = relationKey(schemas, row.schema_name, row.table_name);
|
|
382
|
+
const relation = relations[key];
|
|
383
|
+
const columns = relation === undefined ? {} : { ...relation.columns };
|
|
384
|
+
const generated = /(?:VIRTUAL|STORED) GENERATED/iu
|
|
385
|
+
.exec(row.extra ?? "")?.[0]
|
|
386
|
+
?.toUpperCase()
|
|
387
|
+
.startsWith("STORED")
|
|
388
|
+
? "stored"
|
|
389
|
+
: /GENERATED/iu.test(row.extra ?? "")
|
|
390
|
+
? "virtual"
|
|
391
|
+
: "none";
|
|
392
|
+
const isView = row.table_type === "VIEW" || row.table_type === "SYSTEM VIEW";
|
|
393
|
+
const invisible = /(?:^|\s)INVISIBLE(?:\s|$)/iu.test(row.extra ?? "");
|
|
394
|
+
const characterMaximumLength = optionalCatalogInteger(row.character_maximum_length, `${row.schema_name}.${row.table_name}.${row.column_name} character length`);
|
|
395
|
+
const numericPrecision = optionalCatalogInteger(row.numeric_precision, `${row.schema_name}.${row.table_name}.${row.column_name} numeric precision`);
|
|
396
|
+
const numericScale = optionalCatalogInteger(row.numeric_scale, `${row.schema_name}.${row.table_name}.${row.column_name} numeric scale`);
|
|
397
|
+
const datetimePrecision = optionalCatalogInteger(row.datetime_precision, `${row.schema_name}.${row.table_name}.${row.column_name} datetime precision`);
|
|
398
|
+
const spatialReferenceSystemId = optionalCatalogInteger(row.spatial_reference_system_id, `${row.schema_name}.${row.table_name}.${row.column_name} spatial reference system`);
|
|
399
|
+
columns[row.column_name] = {
|
|
62
400
|
name: row.column_name,
|
|
401
|
+
position: typeof row.ordinal_position !== "number"
|
|
402
|
+
? Math.max(-1, ...Object.values(columns).map(({ position }) => position)) + 1
|
|
403
|
+
: Math.max(0, row.ordinal_position - 1),
|
|
63
404
|
databaseType: row.database_type,
|
|
64
|
-
|
|
405
|
+
typeIdentity: `mysql:${row.database_type.toLowerCase()}`,
|
|
406
|
+
tsType: mapType(row.database_type),
|
|
65
407
|
nullable: row.is_nullable === "YES",
|
|
66
|
-
|
|
408
|
+
nullabilitySource: "declared",
|
|
409
|
+
default: row.default_expression === null ? "unknown" : "present",
|
|
410
|
+
...(row.default_expression === null
|
|
411
|
+
? {}
|
|
412
|
+
: { defaultExpressionHash: fingerprintSchemaExpression(row.default_expression) }),
|
|
413
|
+
generated,
|
|
414
|
+
...(generated === "none" || row.generation_expression === undefined || row.generation_expression === null
|
|
415
|
+
? {}
|
|
416
|
+
: { generatedExpressionHash: fingerprintSchemaExpression(row.generation_expression) }),
|
|
417
|
+
identity: /auto_increment/iu.test(row.extra ?? "") ? "by-default" : "none",
|
|
418
|
+
...(row.collation_name === undefined || row.collation_name === null ? {} : { collation: row.collation_name }),
|
|
419
|
+
...(row.character_set_name === undefined || row.character_set_name === null
|
|
420
|
+
? {}
|
|
421
|
+
: { characterSet: row.character_set_name }),
|
|
422
|
+
classification: invisible ? "hidden" : "normal",
|
|
423
|
+
insertable: generated === "none" && !isView,
|
|
424
|
+
updatable: generated === "none" && (!isView || row.view_updatable === "YES"),
|
|
425
|
+
extension: {
|
|
426
|
+
version: "1",
|
|
427
|
+
attributes: {
|
|
428
|
+
unsigned: /(?:^|\s)unsigned(?:\s|$)/iu.test(row.database_type),
|
|
429
|
+
zerofill: /(?:^|\s)zerofill(?:\s|$)/iu.test(row.database_type),
|
|
430
|
+
invisible,
|
|
431
|
+
...(characterMaximumLength === undefined ? {} : { characterMaximumLength }),
|
|
432
|
+
...(numericPrecision === undefined ? {} : { numericPrecision }),
|
|
433
|
+
...(numericScale === undefined ? {} : { numericScale }),
|
|
434
|
+
...(datetimePrecision === undefined ? {} : { datetimePrecision }),
|
|
435
|
+
...(spatialReferenceSystemId === undefined ? {} : { spatialReferenceSystemId }),
|
|
436
|
+
},
|
|
437
|
+
},
|
|
438
|
+
};
|
|
439
|
+
relations[key] = {
|
|
440
|
+
schema: row.schema_name,
|
|
441
|
+
name: row.table_name,
|
|
442
|
+
kind: isView ? "view" : "table",
|
|
443
|
+
columns,
|
|
444
|
+
constraints: relation?.constraints ?? [],
|
|
445
|
+
indexes: relation?.indexes ?? [],
|
|
446
|
+
capabilities: {
|
|
447
|
+
viewUpdatable: !isView || row.view_updatable === "YES",
|
|
448
|
+
constraintEvidence: catalogEvidence.get("constraints") === "complete",
|
|
449
|
+
indexEvidence: catalogEvidence.get("indexes") === "complete",
|
|
450
|
+
},
|
|
451
|
+
};
|
|
452
|
+
if (types[row.database_type] === undefined) {
|
|
453
|
+
const labels = mySqlEnumValues(row.database_type);
|
|
454
|
+
const setMembers = mySqlSetValues(row.database_type);
|
|
455
|
+
const common = {
|
|
456
|
+
name: row.database_type,
|
|
457
|
+
identity: `mysql:${row.database_type.toLowerCase()}`,
|
|
458
|
+
databaseType: row.database_type,
|
|
459
|
+
tsType: mapType(row.database_type),
|
|
460
|
+
};
|
|
461
|
+
types[row.database_type] =
|
|
462
|
+
labels === undefined
|
|
463
|
+
? common.tsType === this.#policy.unknown
|
|
464
|
+
? { kind: "opaque", ...common, reason: "The MySQL type has no configured type-policy mapping." }
|
|
465
|
+
: {
|
|
466
|
+
kind: /^set\(/iu.test(row.database_type) ? "collection" : "scalar",
|
|
467
|
+
...common,
|
|
468
|
+
...(/^set\(/iu.test(row.database_type)
|
|
469
|
+
? {
|
|
470
|
+
elementTypeIdentity: "mysql:string",
|
|
471
|
+
extension: {
|
|
472
|
+
version: "1",
|
|
473
|
+
attributes: { members: setMembers ?? [] },
|
|
474
|
+
},
|
|
475
|
+
}
|
|
476
|
+
: {}),
|
|
477
|
+
}
|
|
478
|
+
: { kind: "enum", ...common, labels };
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
for (const row of normalizeConstraintRows(constraintRows)) {
|
|
482
|
+
const key = relationKey(schemas, row.schema_name, row.table_name);
|
|
483
|
+
const relation = relations[key];
|
|
484
|
+
if (relation === undefined)
|
|
485
|
+
continue;
|
|
486
|
+
const columns = row.columns.filter((column) => typeof column === "string");
|
|
487
|
+
const referencedColumns = row.referenced_columns.filter((column) => typeof column === "string");
|
|
488
|
+
const base = {
|
|
489
|
+
name: row.constraint_name,
|
|
490
|
+
identity: `${row.schema_name}.${row.table_name}.${row.constraint_name}`,
|
|
491
|
+
columns,
|
|
492
|
+
partial: false,
|
|
493
|
+
expressionBased: false,
|
|
494
|
+
deferrable: false,
|
|
495
|
+
initiallyDeferred: false,
|
|
496
|
+
extension: {
|
|
497
|
+
version: "1",
|
|
498
|
+
attributes: { enforced: row.enforced === undefined ? "unknown" : row.enforced === "YES" },
|
|
499
|
+
},
|
|
67
500
|
};
|
|
501
|
+
const constraint = row.constraint_type === "PRIMARY KEY"
|
|
502
|
+
? { kind: "primary-key", ...base, nullsDistinct: false }
|
|
503
|
+
: row.constraint_type === "UNIQUE"
|
|
504
|
+
? { kind: "unique", ...base, nullsDistinct: true }
|
|
505
|
+
: row.constraint_type === "FOREIGN KEY"
|
|
506
|
+
? {
|
|
507
|
+
kind: "foreign-key",
|
|
508
|
+
...base,
|
|
509
|
+
referencedRelation: row.referenced_table === null
|
|
510
|
+
? "unknown"
|
|
511
|
+
: relationKey(schemas, row.referenced_schema ?? row.schema_name, row.referenced_table),
|
|
512
|
+
referencedColumns,
|
|
513
|
+
match: "simple",
|
|
514
|
+
onUpdate: foreignKeyAction(row.update_rule),
|
|
515
|
+
onDelete: foreignKeyAction(row.delete_rule),
|
|
516
|
+
}
|
|
517
|
+
: {
|
|
518
|
+
kind: "check",
|
|
519
|
+
...base,
|
|
520
|
+
expressionBased: true,
|
|
521
|
+
predicate: row.check_clause === null ? "unknown" : "present",
|
|
522
|
+
...(row.check_clause === null
|
|
523
|
+
? {}
|
|
524
|
+
: { predicateHash: fingerprintSchemaExpression(row.check_clause) }),
|
|
525
|
+
};
|
|
526
|
+
relations[key] = { ...relation, constraints: [...relation.constraints, constraint] };
|
|
68
527
|
}
|
|
69
|
-
const
|
|
70
|
-
|
|
71
|
-
|
|
528
|
+
for (const row of normalizeIndexRows(indexRows)) {
|
|
529
|
+
const key = relationKey(schemas, row.schema_name, row.table_name);
|
|
530
|
+
const relation = relations[key];
|
|
531
|
+
if (relation === undefined)
|
|
532
|
+
continue;
|
|
533
|
+
const { columns, expressions, descending, column_collations, prefix_lengths } = row;
|
|
534
|
+
const visible = catalogBoolean(row.visible, "index visibility");
|
|
535
|
+
relations[key] = {
|
|
536
|
+
...relation,
|
|
537
|
+
indexes: [
|
|
538
|
+
...relation.indexes,
|
|
539
|
+
{
|
|
540
|
+
name: row.index_name,
|
|
541
|
+
identity: `${row.schema_name}.${row.table_name}.${row.index_name}`,
|
|
542
|
+
unique: catalogBoolean(row.is_unique, "index uniqueness"),
|
|
543
|
+
method: row.index_type.toLowerCase(),
|
|
544
|
+
columns: columns.map((value, index) => {
|
|
545
|
+
const column = typeof value === "string" ? value : null;
|
|
546
|
+
const expression = expressions[index];
|
|
547
|
+
const collation = column_collations[index];
|
|
548
|
+
return {
|
|
549
|
+
...(column === null
|
|
550
|
+
? {
|
|
551
|
+
expressionHash: fingerprintSchemaExpression(typeof expression === "string" ? expression : `${row.index_name}:${index}`),
|
|
552
|
+
}
|
|
553
|
+
: { column }),
|
|
554
|
+
...(catalogBoolean(descending[index], "index column ordering") ? { descending: true } : {}),
|
|
555
|
+
...(typeof collation !== "string" ? {} : { collation }),
|
|
556
|
+
};
|
|
557
|
+
}),
|
|
558
|
+
predicate: "none",
|
|
559
|
+
valid: true,
|
|
560
|
+
extension: {
|
|
561
|
+
version: "1",
|
|
562
|
+
attributes: {
|
|
563
|
+
visible,
|
|
564
|
+
prefixLengths: prefix_lengths.map((value, index) => optionalCatalogInteger(value, `${row.index_name} prefix length ${index}`) ?? null),
|
|
565
|
+
},
|
|
566
|
+
},
|
|
567
|
+
},
|
|
568
|
+
],
|
|
569
|
+
};
|
|
570
|
+
}
|
|
571
|
+
const parameters = new Map();
|
|
572
|
+
for (const row of parameterRows) {
|
|
573
|
+
const key = `${row.schema_name}.${row.routine_name}`;
|
|
574
|
+
const rows = parameters.get(key);
|
|
575
|
+
if (rows === undefined)
|
|
576
|
+
parameters.set(key, [row]);
|
|
577
|
+
else
|
|
578
|
+
rows.push(row);
|
|
579
|
+
}
|
|
580
|
+
const routines = {};
|
|
581
|
+
for (const row of catalogEvidence.get("parameters") === "complete" ? routineRows : []) {
|
|
582
|
+
const name = `${row.schema_name}.${row.function_name}`;
|
|
583
|
+
const allParameters = (parameters.get(name) ?? []).sort((left, right) => left.ordinal_position - right.ordinal_position);
|
|
584
|
+
const inputParameters = allParameters.filter(({ ordinal_position }) => ordinal_position > 0);
|
|
585
|
+
const argumentsList = inputParameters.map((parameter) => ({
|
|
586
|
+
...(parameter.parameter_name === null ? {} : { name: parameter.parameter_name }),
|
|
587
|
+
mode: parameter.parameter_mode === "OUT"
|
|
588
|
+
? "out"
|
|
589
|
+
: parameter.parameter_mode === "INOUT"
|
|
590
|
+
? "inout"
|
|
591
|
+
: "in",
|
|
592
|
+
typeIdentity: `mysql:${parameter.database_type.toLowerCase()}`,
|
|
593
|
+
databaseType: parameter.database_type,
|
|
594
|
+
tsType: mapType(parameter.database_type),
|
|
595
|
+
default: "none",
|
|
596
|
+
}));
|
|
597
|
+
const kind = row.routine_type === "PROCEDURE" ? "procedure" : "function";
|
|
598
|
+
const routine = {
|
|
72
599
|
schema: row.schema_name,
|
|
73
600
|
name: row.function_name,
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
601
|
+
identity: `${name}(${argumentsList
|
|
602
|
+
.filter(({ mode }) => mode !== "out")
|
|
603
|
+
.map(({ databaseType }) => databaseType)
|
|
604
|
+
.join(",")})`,
|
|
605
|
+
kind,
|
|
606
|
+
arguments: argumentsList,
|
|
607
|
+
result: kind === "procedure"
|
|
608
|
+
? { kind: "command" }
|
|
609
|
+
: {
|
|
610
|
+
kind: "scalar",
|
|
611
|
+
typeIdentity: `mysql:${row.database_return_type.toLowerCase()}`,
|
|
612
|
+
databaseType: row.database_return_type,
|
|
613
|
+
tsType: mapType(row.database_return_type),
|
|
614
|
+
nullable: true,
|
|
615
|
+
},
|
|
616
|
+
volatility: routineVolatility(row),
|
|
617
|
+
deterministic: row.is_deterministic === "YES",
|
|
618
|
+
dataAccess: routineDataAccess(row.sql_data_access),
|
|
619
|
+
nullInput: "called",
|
|
620
|
+
extension: {
|
|
621
|
+
version: "1",
|
|
622
|
+
attributes: {
|
|
623
|
+
...(row.security_type === undefined ? {} : { securityType: row.security_type.toLowerCase() }),
|
|
624
|
+
...(row.creation_sql_mode === undefined
|
|
625
|
+
? {}
|
|
626
|
+
: { creationSqlMode: normalizeCatalogSqlMode(row.creation_sql_mode) }),
|
|
627
|
+
...(row.creation_character_set == null ? {} : { creationCharacterSet: row.creation_character_set }),
|
|
628
|
+
...(row.creation_collation == null ? {} : { creationCollation: row.creation_collation }),
|
|
629
|
+
...(row.database_collation == null ? {} : { databaseCollation: row.database_collation }),
|
|
630
|
+
...(row.return_character_set == null ? {} : { returnCharacterSet: row.return_character_set }),
|
|
631
|
+
...(row.return_collation == null ? {} : { returnCollation: row.return_collation }),
|
|
632
|
+
argumentCharacterSets: inputParameters.map(({ character_set_name }) => character_set_name ?? null),
|
|
633
|
+
argumentCollations: inputParameters.map(({ collation_name }) => collation_name ?? null),
|
|
634
|
+
},
|
|
635
|
+
},
|
|
83
636
|
};
|
|
637
|
+
const overloads = routines[name];
|
|
638
|
+
if (overloads === undefined)
|
|
639
|
+
routines[name] = [routine];
|
|
640
|
+
else
|
|
641
|
+
overloads.push(routine);
|
|
84
642
|
}
|
|
85
|
-
|
|
86
|
-
|
|
643
|
+
for (const overloads of Object.values(routines)) {
|
|
644
|
+
overloads.sort((left, right) => left.identity.localeCompare(right.identity) ||
|
|
645
|
+
left.volatility.localeCompare(right.volatility) ||
|
|
646
|
+
String(left.deterministic).localeCompare(String(right.deterministic)));
|
|
647
|
+
}
|
|
648
|
+
const schemaByName = new Map(schemaRows.map((row) => [row.schema_name, row]));
|
|
649
|
+
const namespaces = Object.fromEntries([
|
|
650
|
+
["def", { name: "def", kind: "catalog" }],
|
|
651
|
+
...schemas.map((name) => {
|
|
652
|
+
const row = schemaByName.get(name);
|
|
653
|
+
return [
|
|
654
|
+
name,
|
|
655
|
+
{
|
|
656
|
+
name,
|
|
657
|
+
kind: "database",
|
|
658
|
+
...(row === undefined
|
|
659
|
+
? {}
|
|
660
|
+
: {
|
|
661
|
+
extension: {
|
|
662
|
+
version: "1",
|
|
663
|
+
attributes: {
|
|
664
|
+
catalog: row.catalog_name,
|
|
665
|
+
characterSet: row.default_character_set_name,
|
|
666
|
+
collation: row.default_collation_name,
|
|
667
|
+
},
|
|
668
|
+
},
|
|
669
|
+
}),
|
|
670
|
+
},
|
|
671
|
+
];
|
|
672
|
+
}),
|
|
673
|
+
]);
|
|
674
|
+
const coreCatalog = mySqlCoreCatalogForSchema(typeContext);
|
|
675
|
+
const snapshot = defineSchemaSnapshotV2({
|
|
676
|
+
formatVersion: 2,
|
|
87
677
|
dialect: "mysql",
|
|
88
|
-
dialectVersion:
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
678
|
+
dialectVersion: MYSQL_DIALECT_VERSION,
|
|
679
|
+
server,
|
|
680
|
+
namespaces,
|
|
681
|
+
types,
|
|
682
|
+
relations,
|
|
683
|
+
routines,
|
|
684
|
+
extension: {
|
|
685
|
+
version: "1",
|
|
686
|
+
attributes: {
|
|
687
|
+
catalogRevision: coreCatalog?.revision ?? "unknown",
|
|
688
|
+
evidenceScope: "current-role",
|
|
689
|
+
catalogEvidence: Object.fromEntries([...catalogEvidence.entries()].sort(([left], [right]) => left.localeCompare(right))),
|
|
690
|
+
incompleteEvidence: diagnostics.length > 0,
|
|
691
|
+
temporaryTables: "not-captured",
|
|
692
|
+
},
|
|
693
|
+
},
|
|
694
|
+
});
|
|
695
|
+
return Object.freeze({ snapshot, diagnostics: Object.freeze([...diagnostics]) });
|
|
93
696
|
}
|
|
94
697
|
}
|
|
95
698
|
export async function introspectMySql(options) {
|