@adminiumjs/adapter-mysql 0.1.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/dist/errors.js ADDED
@@ -0,0 +1,94 @@
1
+ /**
2
+ * Driver error → typed `AdapterError` mapping — 05-introspection-engine.md §3.
3
+ * mysql2 errors carry a symbolic `code` (`ER_ACCESS_DENIED_ERROR`, …) plus
4
+ * `errno`/`sqlState`; socket-level failures carry Node errnos. The Studio
5
+ * wizard and the `diagnostics-readout` widget map `code` to remediation
6
+ * copy, so the mapping here is the whole UX for failure states.
7
+ */
8
+ import { AdapterError } from '@adminium/engine/adapter';
9
+ const AUTH_CODES = new Set([
10
+ 'ER_ACCESS_DENIED_ERROR',
11
+ 'ER_ACCESS_DENIED_NO_PASSWORD_ERROR',
12
+ 'ER_NOT_SUPPORTED_AUTH_MODE',
13
+ 'ER_BAD_DB_ERROR', // unknown database — same treatment as pg 3D000
14
+ 'ER_DBACCESS_DENIED_ERROR',
15
+ ]);
16
+ const PERMISSION_CODES = new Set([
17
+ 'ER_TABLEACCESS_DENIED_ERROR',
18
+ 'ER_COLUMNACCESS_DENIED_ERROR',
19
+ 'ER_SPECIFIC_ACCESS_DENIED_ERROR',
20
+ 'ER_PROCACCESS_DENIED_ERROR',
21
+ 'ER_OPTION_PREVENTS_STATEMENT', // --read-only server rejecting a write
22
+ ]);
23
+ const TIMEOUT_CODES = new Set([
24
+ 'ER_QUERY_TIMEOUT', // MySQL max_execution_time (3024) / MariaDB (1969)
25
+ 'ER_STATEMENT_TIMEOUT',
26
+ 'ER_LOCK_WAIT_TIMEOUT',
27
+ 'PROTOCOL_SEQUENCE_TIMEOUT',
28
+ 'ETIMEDOUT',
29
+ ]);
30
+ const DRIFT_CODES = new Set(['ER_NO_SUCH_TABLE', 'ER_BAD_FIELD_ERROR']);
31
+ const NETWORK_ERRNOS = new Set([
32
+ 'ECONNREFUSED',
33
+ 'ECONNRESET',
34
+ 'ENOTFOUND',
35
+ 'EHOSTUNREACH',
36
+ 'ENETUNREACH',
37
+ 'EPIPE',
38
+ 'EAI_AGAIN',
39
+ ]);
40
+ const TLS_CODES = new Set([
41
+ 'HANDSHAKE_SSL_ERROR',
42
+ 'HANDSHAKE_NO_SSL_SUPPORT',
43
+ 'SELF_SIGNED_CERT_IN_CHAIN',
44
+ 'UNABLE_TO_VERIFY_LEAF_SIGNATURE',
45
+ 'CERT_HAS_EXPIRED',
46
+ 'DEPTH_ZERO_SELF_SIGNED_CERT',
47
+ 'UNABLE_TO_GET_ISSUER_CERT_LOCALLY',
48
+ 'HOSTNAME_MISMATCH',
49
+ ]);
50
+ const HINTS = {
51
+ AUTH: 'check the username, password, and database name in the connection string',
52
+ HOST_UNREACHABLE: 'check the host/port and any firewall or IP allowlist — the database must accept connections from this server',
53
+ TLS: "check the ssl options in the DSN and the server's certificate chain",
54
+ PERMISSION: 'the connected user lacks the required privilege — grant it or use a different user',
55
+ TIMEOUT: 'the statement exceeded its time budget; retry or narrow the operation',
56
+ UNSUPPORTED: 'Adminium supports MySQL ≥ 8.0 and MariaDB ≥ 10.5 — upgrade the server to connect',
57
+ };
58
+ function messageOf(error) {
59
+ return error instanceof Error ? error.message : String(error);
60
+ }
61
+ /** Coerce any driver/socket failure into the one allowed error type. */
62
+ export function toAdapterError(error, context) {
63
+ if (error instanceof AdapterError)
64
+ return error;
65
+ const message = messageOf(error);
66
+ const code = typeof error === 'object' && error !== null && 'code' in error
67
+ ? String(error.code)
68
+ : '';
69
+ let mapped = 'UNKNOWN';
70
+ if (AUTH_CODES.has(code))
71
+ mapped = 'AUTH';
72
+ else if (PERMISSION_CODES.has(code))
73
+ mapped = 'PERMISSION';
74
+ else if (TIMEOUT_CODES.has(code))
75
+ mapped = 'TIMEOUT';
76
+ else if (DRIFT_CODES.has(code))
77
+ mapped = 'SCHEMA_DRIFT';
78
+ else if (NETWORK_ERRNOS.has(code))
79
+ mapped = 'HOST_UNREACHABLE';
80
+ else if (TLS_CODES.has(code) ||
81
+ code.startsWith('ERR_TLS') ||
82
+ /\b(ssl|tls|certificate)\b/i.test(message)) {
83
+ mapped = 'TLS';
84
+ }
85
+ const options = {
86
+ detail: code.length > 0 ? `${code}: ${message}` : message,
87
+ cause: error,
88
+ };
89
+ const hint = HINTS[mapped];
90
+ if (hint !== undefined)
91
+ options.hint = hint;
92
+ return new AdapterError(mapped, `${context}: ${message}`, options);
93
+ }
94
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,57 @@
1
+ import { type AdapterProvider, type AdapterRegistry, type CapabilityProbeResult, type CollectStatsOptions, type ColumnSampleOptions, type ConnectionConfig, type ConnectionRole, type DatabaseAdapter, type DatabaseModel, type Dialect, type FilterSpec, type IntrospectOptions, type MutationResult, type MutationSpec, type QueryResult, type QuerySpec, type Row, type SampleOptions, type StatsResult, type TableRef, type TestResult } from '@adminium/engine/adapter';
2
+ export declare class MysqlAdapter<Role extends ConnectionRole = ConnectionRole> implements DatabaseAdapter<Role> {
3
+ #private;
4
+ readonly dialect: Dialect;
5
+ readonly capabilities: {
6
+ hasEnums: boolean;
7
+ hasFKs: boolean;
8
+ hasSchemas: boolean;
9
+ hasComments: boolean;
10
+ hasChecks: boolean;
11
+ hasRLS: boolean;
12
+ hasMaterializedViews: boolean;
13
+ hasRowEstimates: boolean;
14
+ supportsStatementTimeout: boolean;
15
+ supportsReturning: boolean;
16
+ maxIdentifierLength: number;
17
+ };
18
+ readonly role: Role;
19
+ constructor(role: Role);
20
+ /** Lazy pool — no socket is opened until the first query. */
21
+ connect(config: ConnectionConfig<Role>): Promise<void>;
22
+ test(): Promise<TestResult>;
23
+ /** Runs on every connect/test; results persist on the connection row. */
24
+ probeCapabilities(): Promise<CapabilityProbeResult>;
25
+ /** SCHEMA ONLY — reads `information_schema` exclusively (05 §10). */
26
+ introspect(this: DatabaseAdapter<'introspect'>, opts?: IntrospectOptions): Promise<DatabaseModel>;
27
+ count(this: DatabaseAdapter<'data'>, _table: TableRef, _filter?: FilterSpec, _opts?: {
28
+ cap?: number;
29
+ }): Promise<{
30
+ value: number;
31
+ capped: boolean;
32
+ }>;
33
+ sample(this: DatabaseAdapter<'data'>, _table: TableRef, _opts: SampleOptions): Promise<Row[]>;
34
+ sampleColumn(this: DatabaseAdapter<'data'>, _table: TableRef, _column: string, _opts: ColumnSampleOptions): Promise<unknown[]>;
35
+ query(this: DatabaseAdapter<'data'>, _spec: QuerySpec): Promise<QueryResult>;
36
+ mutate(this: DatabaseAdapter<'data'>, _spec: MutationSpec): Promise<MutationResult>;
37
+ /** Aggregate statistics for LLM enrichment (06 §4.2); sample-free by default. */
38
+ collectTableStats(this: DatabaseAdapter<'data'>, table: TableRef, opts?: CollectStatsOptions): Promise<StatsResult>;
39
+ /** Release the pool; idempotent. */
40
+ close(): Promise<void>;
41
+ }
42
+ /** What the server registers at boot (01-architecture.md §2.3.1). */
43
+ export declare const mysqlAdapter: AdapterProvider;
44
+ /**
45
+ * Boot registration helper — `@adminium/server` calls `register()` once at
46
+ * startup; tests may pass their own registry instance.
47
+ */
48
+ export declare function register(registry?: AdapterRegistry<AdapterProvider>): void;
49
+ export { createQueryEngine } from './query-engine.js';
50
+ export { checkConstraintsSql, columnsSql, detectServerFlavor, foreignKeysSql, GRANTS_SQL, interpretGrants, interpretProbe, introspectionStatements, introspectMysql, MYSQL_CAPABILITIES, parseCheckEnum, PROBE_SQL, SSL_SQL, statisticsSql, tableConstraintsSql, tablesSql, type CatalogExecutor, type CatalogRow, type GrantsResult, type IntrospectContext, type ProbeResult, type ServerFlavor, } from './introspect.js';
51
+ export { collectMysqlStats, type StatsExecutor } from './stats.js';
52
+ export { classifyMysqlDefault, mapMysqlType, parseEnumValues, type MappedMysqlType, } from './type-map.js';
53
+ export { MYSQL_MAX_IDENTIFIER_LENGTH, mysqlSerializers, quoteIdentifier, } from './serialization.js';
54
+ export { toAdapterError } from './errors.js';
55
+ /** @deprecated M0 scaffold export; kept so early imports keep compiling. */
56
+ export declare const PACKAGE_NAME = "@adminium/adapter-mysql";
57
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js ADDED
@@ -0,0 +1,250 @@
1
+ /**
2
+ * @adminium/adapter-mysql — the `mysql2`-driver implementation of the
3
+ * `DatabaseAdapter` contract (05-introspection-engine.md §3/§4.2, M9/05-T13).
4
+ *
5
+ * Mirrors the postgres reference adapter: connect/test/probeCapabilities,
6
+ * `introspect()` (schema only — never rows, via `information_schema`), the
7
+ * Kysely query-engine factory, and the boot registration helper. The
8
+ * data-role methods (`query`/`mutate`/`sample`/`count`) follow the same
9
+ * 05-T05 pattern and currently reject with a typed `UNSUPPORTED` error after
10
+ * their role guard runs — CRUD goes through `createQueryEngine()`.
11
+ *
12
+ * Supported servers: MySQL ≥ 8.0, MariaDB ≥ 10.5 (feature-detected via
13
+ * `VERSION()`; older versions → `UNSUPPORTED` with an upgrade hint).
14
+ */
15
+ import { createPool } from 'mysql2/promise';
16
+ import { AdapterError, adapterRegistry, registerAdapter, } from '@adminium/engine/adapter';
17
+ import { toAdapterError } from './errors.js';
18
+ import { GRANTS_SQL, interpretGrants, interpretProbe, introspectMysql, MYSQL_CAPABILITIES, PROBE_SQL, SSL_SQL, } from './introspect.js';
19
+ import { createQueryEngine } from './query-engine.js';
20
+ import { collectMysqlStats } from './stats.js';
21
+ const INTROSPECT_POOL_MAX = 5;
22
+ const DATA_POOL_MAX = 10;
23
+ const DEFAULT_STATEMENT_TIMEOUT_MS = 15_000;
24
+ export class MysqlAdapter {
25
+ dialect = 'mysql';
26
+ capabilities = { ...MYSQL_CAPABILITIES };
27
+ role;
28
+ #pool = null;
29
+ #closed = false;
30
+ constructor(role) {
31
+ this.role = role;
32
+ }
33
+ /** Lazy pool — no socket is opened until the first query. */
34
+ async connect(config) {
35
+ if (config.role !== this.role) {
36
+ throw new AdapterError('PERMISSION', `connection config is branded "${config.role}" but this adapter instance is "${this.role}"`, { hint: 'the three logical connections are never interchangeable (01-architecture.md §3)' });
37
+ }
38
+ if (config.dsn === undefined || config.dsn.length === 0) {
39
+ throw new AdapterError('UNKNOWN', 'mysql connections require a DSN', {
40
+ hint: 'pass a mysql:// connection string naming the database to introspect',
41
+ });
42
+ }
43
+ const statementTimeoutMs = Math.floor(config.statementTimeoutMs ?? DEFAULT_STATEMENT_TIMEOUT_MS);
44
+ const pool = createPool({
45
+ uri: config.dsn,
46
+ connectionLimit: config.poolMax ?? (this.role === 'introspect' ? INTROSPECT_POOL_MAX : DATA_POOL_MAX),
47
+ });
48
+ // Session timeout setup on every new connection — 05 §4.2. MySQL takes
49
+ // milliseconds (max_execution_time); MariaDB takes seconds
50
+ // (max_statement_time) — feature-detected by trying both in order.
51
+ const mariadbSeconds = Math.max(1, Math.ceil(statementTimeoutMs / 1000));
52
+ pool.pool.on('connection', (connection) => {
53
+ const conn = connection;
54
+ conn.query(`SET SESSION max_execution_time = ${statementTimeoutMs}`, (error) => {
55
+ if (error !== null && error !== undefined) {
56
+ conn.query(`SET SESSION max_statement_time = ${mariadbSeconds}`, () => {
57
+ /* neither supported — introspection still bounded by timeoutMs */
58
+ });
59
+ }
60
+ });
61
+ });
62
+ this.#pool = pool;
63
+ this.#closed = false;
64
+ }
65
+ #requirePool() {
66
+ if (this.#pool === null || this.#closed) {
67
+ throw new AdapterError('UNKNOWN', 'adapter is not connected — call connect() first');
68
+ }
69
+ return this.#pool;
70
+ }
71
+ async #query(sql) {
72
+ const pool = this.#requirePool();
73
+ try {
74
+ // Same NodeNext mixin-typing workaround as the connection listener above.
75
+ const queryable = pool;
76
+ const [rows] = await queryable.query(sql);
77
+ return rows;
78
+ }
79
+ catch (error) {
80
+ throw toAdapterError(error, 'mysql query failed');
81
+ }
82
+ }
83
+ async #probe() {
84
+ const rows = await this.#query(PROBE_SQL);
85
+ const probe = interpretProbe(rows[0] ?? {});
86
+ if (!probe.flavor.supported) {
87
+ throw new AdapterError('UNSUPPORTED', `unsupported server version "${probe.serverVersion}"`, {
88
+ detail: `${probe.flavor.flavor} ${probe.flavor.major}.${probe.flavor.minor}`,
89
+ hint: 'Adminium supports MySQL ≥ 8.0 and MariaDB ≥ 10.5 — upgrade the server to connect',
90
+ });
91
+ }
92
+ return probe;
93
+ }
94
+ /** `SHOW GRANTS` refinement — guarded, degrades to server-level read_only. */
95
+ async #grants(databaseName) {
96
+ if (databaseName === null)
97
+ return null;
98
+ try {
99
+ return interpretGrants(await this.#query(GRANTS_SQL), databaseName);
100
+ }
101
+ catch {
102
+ return null;
103
+ }
104
+ }
105
+ async #ssl() {
106
+ try {
107
+ const rows = await this.#query(SSL_SQL);
108
+ const value = rows[0]?.['Value'];
109
+ return typeof value === 'string' && value.length > 0;
110
+ }
111
+ catch {
112
+ return false;
113
+ }
114
+ }
115
+ async test() {
116
+ const startedAt = Date.now();
117
+ try {
118
+ const probe = await this.#probe();
119
+ const grants = await this.#grants(probe.databaseName);
120
+ return {
121
+ ok: true,
122
+ latencyMs: Date.now() - startedAt,
123
+ serverVersion: probe.serverVersion,
124
+ currentUser: probe.roleName,
125
+ canWrite: !probe.readOnly && (grants?.canWrite ?? true),
126
+ ssl: await this.#ssl(),
127
+ };
128
+ }
129
+ catch (error) {
130
+ return {
131
+ ok: false,
132
+ latencyMs: Date.now() - startedAt,
133
+ serverVersion: null,
134
+ currentUser: null,
135
+ canWrite: false,
136
+ ssl: false,
137
+ error: toAdapterError(error, 'connection test failed'),
138
+ };
139
+ }
140
+ }
141
+ /** Runs on every connect/test; results persist on the connection row. */
142
+ async probeCapabilities() {
143
+ const probe = await this.#probe();
144
+ const grants = await this.#grants(probe.databaseName);
145
+ const canWrite = !probe.readOnly && (grants?.canWrite ?? true);
146
+ return {
147
+ capabilities: {
148
+ ...MYSQL_CAPABILITIES,
149
+ // MariaDB ≥ 10.5 supports INSERT/DELETE … RETURNING (05 §4.2).
150
+ supportsReturning: probe.flavor.flavor === 'mariadb',
151
+ },
152
+ privileges: {
153
+ canReadSchema: true,
154
+ canRead: grants?.canSelect ?? true,
155
+ canWrite,
156
+ canDDL: !probe.readOnly && (grants?.canDDL ?? false),
157
+ },
158
+ serverVersion: probe.serverVersion,
159
+ currentRole: { name: probe.roleName, readOnly: !canWrite },
160
+ };
161
+ }
162
+ /** SCHEMA ONLY — reads `information_schema` exclusively (05 §10). */
163
+ async introspect(opts) {
164
+ const self = this;
165
+ // Runtime guard behind the compile-time role brand (05 §3).
166
+ if (self.role !== 'introspect') {
167
+ throw new AdapterError('PERMISSION', 'introspect() is only available on the introspect-role instance');
168
+ }
169
+ const probe = await self.#probe();
170
+ if (probe.databaseName === null) {
171
+ throw new AdapterError('UNKNOWN', 'the DSN names no database to introspect', {
172
+ hint: 'add the database to the connection string path (mysql://host/db)',
173
+ });
174
+ }
175
+ return introspectMysql(async (sql) => self.#query(sql), { connectionId: probe.databaseName, databaseName: probe.databaseName }, opts);
176
+ }
177
+ #guardDataRole(method) {
178
+ if (this.role !== 'data') {
179
+ throw new AdapterError('PERMISSION', `${method}() is only available on the data-role instance`, { hint: 'row-touching methods never run on the introspect connection (05 §10)' });
180
+ }
181
+ throw new AdapterError('UNSUPPORTED', `${method}() lands with 05-T05 (dynamic Kysely CRUD)`, {
182
+ hint: 'use createQueryEngine() for the CRUD query port in the meantime',
183
+ });
184
+ }
185
+ /* eslint-disable @typescript-eslint/no-unused-vars -- 05-T05 stubs: the
186
+ parameter lists must match the DatabaseAdapter contract exactly. */
187
+ async count(_table, _filter, _opts) {
188
+ return this.#guardDataRole('count');
189
+ }
190
+ async sample(_table, _opts) {
191
+ return this.#guardDataRole('sample');
192
+ }
193
+ async sampleColumn(_table, _column, _opts) {
194
+ return this.#guardDataRole('sampleColumn');
195
+ }
196
+ async query(_spec) {
197
+ return this.#guardDataRole('query');
198
+ }
199
+ async mutate(_spec) {
200
+ return this.#guardDataRole('mutate');
201
+ }
202
+ /* eslint-enable @typescript-eslint/no-unused-vars */
203
+ /** Aggregate statistics for LLM enrichment (06 §4.2); sample-free by default. */
204
+ async collectTableStats(table, opts) {
205
+ const self = this;
206
+ if (self.role !== 'data') {
207
+ throw new AdapterError('PERMISSION', 'collectTableStats() is only available on the data-role instance', { hint: 'statistics touch user rows and never run on the introspect connection (05 §10)' });
208
+ }
209
+ return collectMysqlStats((sql) => self.#query(sql), table, opts);
210
+ }
211
+ /** Release the pool; idempotent. */
212
+ async close() {
213
+ if (this.#pool === null || this.#closed)
214
+ return;
215
+ this.#closed = true;
216
+ const pool = this.#pool;
217
+ this.#pool = null;
218
+ await pool.end();
219
+ }
220
+ }
221
+ /** What the server registers at boot (01-architecture.md §2.3.1). */
222
+ export const mysqlAdapter = {
223
+ dialect: 'mysql',
224
+ async create(config) {
225
+ const adapter = new MysqlAdapter(config.role);
226
+ await adapter.connect(config);
227
+ return adapter;
228
+ },
229
+ createQueryEngine,
230
+ };
231
+ /**
232
+ * Boot registration helper — `@adminium/server` calls `register()` once at
233
+ * startup; tests may pass their own registry instance.
234
+ */
235
+ export function register(registry = adapterRegistry) {
236
+ if (registry === adapterRegistry) {
237
+ registerAdapter(mysqlAdapter);
238
+ return;
239
+ }
240
+ registry.register(mysqlAdapter);
241
+ }
242
+ export { createQueryEngine } from './query-engine.js';
243
+ export { checkConstraintsSql, columnsSql, detectServerFlavor, foreignKeysSql, GRANTS_SQL, interpretGrants, interpretProbe, introspectionStatements, introspectMysql, MYSQL_CAPABILITIES, parseCheckEnum, PROBE_SQL, SSL_SQL, statisticsSql, tableConstraintsSql, tablesSql, } from './introspect.js';
244
+ export { collectMysqlStats } from './stats.js';
245
+ export { classifyMysqlDefault, mapMysqlType, parseEnumValues, } from './type-map.js';
246
+ export { MYSQL_MAX_IDENTIFIER_LENGTH, mysqlSerializers, quoteIdentifier, } from './serialization.js';
247
+ export { toAdapterError } from './errors.js';
248
+ /** @deprecated M0 scaffold export; kept so early imports keep compiling. */
249
+ export const PACKAGE_NAME = '@adminium/adapter-mysql';
250
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,92 @@
1
+ /**
2
+ * MySQL/MariaDB introspection — 05-introspection-engine.md §4.2.
3
+ *
4
+ * Reads `information_schema` scoped `WHERE TABLE_SCHEMA = <db>`: a FIXED set
5
+ * of set-based queries regardless of table count (≤ 10 statements — 05 §10),
6
+ * joined in memory. This module is executor-agnostic — `introspectMysql`
7
+ * takes a `CatalogExecutor` (any `sql → rows` function) so the assembly
8
+ * logic is testable without the `mysql2` driver; `src/index.ts` wires it to
9
+ * the pool. Mirrors the postgres reference adapter file for file.
10
+ *
11
+ * THE "SCHEMA ONLY" INVARIANT (05 §10): every statement here references
12
+ * `information_schema.*` exclusively — no user table is ever touched during
13
+ * setup (asserted offline by test/introspect.offline.test.ts).
14
+ */
15
+ import { type AdapterCapabilities, type DatabaseModel, type IntrospectOptions } from '@adminium/engine/adapter';
16
+ export type CatalogRow = Record<string, unknown>;
17
+ /** Any `sql → rows` runner (the mysql2 pool in production, canned rows in tests). */
18
+ export type CatalogExecutor = (sql: string) => Promise<CatalogRow[]>;
19
+ export interface IntrospectContext {
20
+ /** `adminium_connections` row id; falls back to the database name. */
21
+ connectionId: string;
22
+ /** `DATABASE()` — the one schema MySQL connections see (hasSchemas=false). */
23
+ databaseName: string;
24
+ }
25
+ /**
26
+ * Static dialect capabilities — 05 §2.1 (probe refines per-connection).
27
+ * Canonical values live in the engine's capability matrix (M9-T04) so the
28
+ * wizard's degradation copy and the adapter never disagree.
29
+ */
30
+ export declare const MYSQL_CAPABILITIES: AdapterCapabilities;
31
+ /**
32
+ * Session probe. `@@read_only` covers replica/`--read-only` servers; the
33
+ * grants probe (`SHOW GRANTS`) refines per-user write access — 05 §4.2.
34
+ */
35
+ export declare const PROBE_SQL = "\nSELECT VERSION() AS server_version,\n CURRENT_USER() AS role_name,\n DATABASE() AS database_name,\n @@read_only AS read_only";
36
+ /** Grants probe — parsed by {@link interpretGrants}. */
37
+ export declare const GRANTS_SQL = "SHOW GRANTS";
38
+ /** TLS probe (guarded — may be absent on stripped-down servers). */
39
+ export declare const SSL_SQL = "SHOW SESSION STATUS LIKE 'Ssl_cipher'";
40
+ export interface ServerFlavor {
41
+ flavor: 'mysql' | 'mariadb';
42
+ major: number;
43
+ minor: number;
44
+ /** MySQL ≥ 8.0, MariaDB ≥ 10.5 (05 §4.2); older → UNSUPPORTED. */
45
+ supported: boolean;
46
+ }
47
+ /**
48
+ * Feature-detect the server flavor and version from `VERSION()` output.
49
+ * Handles MariaDB's replication-compat prefix (`5.5.5-10.6.14-MariaDB`).
50
+ */
51
+ export declare function detectServerFlavor(version: string): ServerFlavor;
52
+ export interface ProbeResult {
53
+ serverVersion: string;
54
+ flavor: ServerFlavor;
55
+ roleName: string;
56
+ /** Null when the DSN names no database. */
57
+ databaseName: string | null;
58
+ /** `@@read_only` — server-level; grants refine per-user access. */
59
+ readOnly: boolean;
60
+ }
61
+ /** Interpret one {@link PROBE_SQL} row (executor-agnostic, pure). */
62
+ export declare function interpretProbe(row: CatalogRow): ProbeResult;
63
+ export interface GrantsResult {
64
+ canSelect: boolean;
65
+ canWrite: boolean;
66
+ canDDL: boolean;
67
+ }
68
+ /**
69
+ * Parse `SHOW GRANTS` rows (each row is one `GRANT … ON scope TO user`
70
+ * string) into privilege booleans for `databaseName` — pure, unit-testable.
71
+ */
72
+ export declare function interpretGrants(rows: CatalogRow[], databaseName: string): GrantsResult;
73
+ export declare function tablesSql(schema: string): string;
74
+ export declare function columnsSql(schema: string): string;
75
+ export declare function statisticsSql(schema: string): string;
76
+ export declare function foreignKeysSql(schema: string): string;
77
+ export declare function tableConstraintsSql(schema: string): string;
78
+ /** Guarded: the view exists on MySQL ≥ 8.0.16 / MariaDB ≥ 10.2 only. */
79
+ export declare function checkConstraintsSql(schema: string): string;
80
+ /** The fixed introspection statement set (6 + the probe = 7 — 05 §4.2). */
81
+ export declare function introspectionStatements(schema: string): string[];
82
+ /** Parse a `col IN ('a','b')` check shape into a synthesized enum. */
83
+ export declare function parseCheckEnum(clause: string): {
84
+ column: string;
85
+ values: string[];
86
+ } | null;
87
+ /**
88
+ * Run the fixed catalog query set through `exec` and assemble the
89
+ * `DatabaseModel`. Schema only — never touches user rows.
90
+ */
91
+ export declare function introspectMysql(exec: CatalogExecutor, ctx: IntrospectContext, opts?: IntrospectOptions): Promise<DatabaseModel>;
92
+ //# sourceMappingURL=introspect.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"introspect.d.ts","sourceRoot":"","sources":["../src/introspect.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,EAGL,KAAK,mBAAmB,EAExB,KAAK,aAAa,EAGlB,KAAK,iBAAiB,EAIvB,MAAM,0BAA0B,CAAC;AAQlC,MAAM,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAEjD,qFAAqF;AACrF,MAAM,MAAM,eAAe,GAAG,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC;AAErE,MAAM,WAAW,iBAAiB;IAChC,sEAAsE;IACtE,YAAY,EAAE,MAAM,CAAC;IACrB,8EAA8E;IAC9E,YAAY,EAAE,MAAM,CAAC;CACtB;AAED;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,EAAE,mBAEhC,CAAC;AAMF;;;GAGG;AACH,eAAO,MAAM,SAAS,qJAIU,CAAC;AAEjC,wDAAwD;AACxD,eAAO,MAAM,UAAU,gBAAgB,CAAC;AAExC,oEAAoE;AACpE,eAAO,MAAM,OAAO,0CAA0C,CAAC;AAE/D,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,OAAO,GAAG,SAAS,CAAC;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,kEAAkE;IAClE,SAAS,EAAE,OAAO,CAAC;CACpB;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,YAAY,CAShE;AAED,MAAM,WAAW,WAAW;IAC1B,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,YAAY,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,2CAA2C;IAC3C,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,mEAAmE;IACnE,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,qEAAqE;AACrE,wBAAgB,cAAc,CAAC,GAAG,EAAE,UAAU,GAAG,WAAW,CAU3D;AAED,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,EAAE,OAAO,CAAC;CACjB;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,UAAU,EAAE,EAAE,YAAY,EAAE,MAAM,GAAG,YAAY,CAgBtF;AAiBD,wBAAgB,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAWhD;AAED,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAiBjD;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAWpD;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAmBrD;AAED,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAQ1D;AAED,wEAAwE;AACxE,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAO1D;AAED,2EAA2E;AAC3E,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAShE;AA+BD,sEAAsE;AACtE,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,EAAE,CAAA;CAAE,GAAG,IAAI,CAS1F;AAiDD;;;GAGG;AACH,wBAAsB,eAAe,CACnC,IAAI,EAAE,eAAe,EACrB,GAAG,EAAE,iBAAiB,EACtB,IAAI,GAAE,iBAAsB,GAC3B,OAAO,CAAC,aAAa,CAAC,CA0WxB"}