@hesed/mysql 0.2.1 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/README.md +107 -32
  2. package/dist/commands/mysql/auth/add.d.ts +2 -18
  3. package/dist/commands/mysql/auth/add.js +16 -57
  4. package/dist/commands/mysql/auth/delete.d.ts +2 -0
  5. package/dist/commands/mysql/auth/delete.js +2 -0
  6. package/dist/commands/mysql/auth/list.d.ts +2 -0
  7. package/dist/commands/mysql/auth/list.js +2 -0
  8. package/dist/commands/mysql/auth/profile.d.ts +2 -0
  9. package/dist/commands/mysql/auth/profile.js +2 -0
  10. package/dist/commands/mysql/auth/test.d.ts +2 -12
  11. package/dist/commands/mysql/auth/test.js +16 -41
  12. package/dist/commands/mysql/auth/update.d.ts +2 -18
  13. package/dist/commands/mysql/auth/update.js +16 -74
  14. package/dist/commands/mysql/databases.js +2 -10
  15. package/dist/commands/mysql/describe-table.js +2 -10
  16. package/dist/commands/mysql/explain-query.js +2 -10
  17. package/dist/commands/mysql/indexes.js +2 -10
  18. package/dist/commands/mysql/query.js +2 -10
  19. package/dist/commands/mysql/tables.js +2 -10
  20. package/dist/mysql/config-loader.d.ts +8 -17
  21. package/dist/mysql/config-loader.js +0 -7
  22. package/dist/mysql/database.d.ts +0 -31
  23. package/dist/mysql/database.js +0 -4
  24. package/dist/mysql/formatters.d.ts +5 -0
  25. package/dist/mysql/formatters.js +76 -0
  26. package/dist/mysql/index.d.ts +1 -3
  27. package/dist/mysql/index.js +1 -1
  28. package/dist/mysql/mysql-client.d.ts +8 -57
  29. package/dist/mysql/mysql-client.js +44 -101
  30. package/dist/mysql/mysql-utils.d.ts +2 -52
  31. package/dist/mysql/mysql-utils.js +31 -177
  32. package/dist/mysql/query-validator.d.ts +0 -19
  33. package/dist/mysql/query-validator.js +0 -19
  34. package/oclif.manifest.json +176 -59
  35. package/package.json +3 -2
  36. package/dist/config.d.ts +0 -13
  37. package/dist/config.js +0 -18
@@ -1,5 +1,5 @@
1
1
  import { Args, Command, Flags } from '@oclif/core';
2
- import { closeConnections, getMySQLConfig, setConfigDir, showIndexes } from '../../mysql/index.js';
2
+ import { closeConnections, showIndexes } from '../../mysql/index.js';
3
3
  export default class MySQLIndexes extends Command {
4
4
  static args = {
5
5
  table: Args.string({ description: 'Table name to show indexes for', required: true }),
@@ -19,15 +19,7 @@ export default class MySQLIndexes extends Command {
19
19
  };
20
20
  async run() {
21
21
  const { args, flags } = await this.parse(MySQLIndexes);
22
- setConfigDir(this.config.configDir);
23
- let profile;
24
- try {
25
- profile = flags.profile ?? (await getMySQLConfig()).defaultProfile;
26
- }
27
- catch (error) {
28
- this.error(error instanceof Error ? error.message : String(error));
29
- }
30
- const result = await showIndexes(profile, args.table, flags.format);
22
+ const result = await showIndexes(this.config, args.table, flags.profile, flags.format);
31
23
  await closeConnections();
32
24
  if (result.success) {
33
25
  this.log(result.result ?? '');
@@ -1,5 +1,5 @@
1
1
  import { Args, Command, Flags } from '@oclif/core';
2
- import { closeConnections, executeQuery, getMySQLConfig, setConfigDir } from '../../mysql/index.js';
2
+ import { closeConnections, executeQuery } from '../../mysql/index.js';
3
3
  export default class MySQLQuery extends Command {
4
4
  static args = {
5
5
  query: Args.string({ description: 'SQL query to execute', required: true }),
@@ -24,15 +24,7 @@ export default class MySQLQuery extends Command {
24
24
  };
25
25
  async run() {
26
26
  const { args, flags } = await this.parse(MySQLQuery);
27
- setConfigDir(this.config.configDir);
28
- let profile;
29
- try {
30
- profile = flags.profile ?? (await getMySQLConfig()).defaultProfile;
31
- }
32
- catch (error) {
33
- this.error(error instanceof Error ? error.message : String(error));
34
- }
35
- const result = await executeQuery(args.query, profile, flags.format, flags['skip-confirmation']);
27
+ const result = await executeQuery(this.config, args.query, flags.profile, flags.format, flags['skip-confirmation']);
36
28
  await closeConnections();
37
29
  if (result.success) {
38
30
  this.log(result.result ?? '');
@@ -1,5 +1,5 @@
1
1
  import { Command, Flags } from '@oclif/core';
2
- import { closeConnections, getMySQLConfig, listTables, setConfigDir } from '../../mysql/index.js';
2
+ import { closeConnections, listTables } from '../../mysql/index.js';
3
3
  export default class MySQLTables extends Command {
4
4
  static description = 'List all tables in the current MySQL database';
5
5
  static examples = [
@@ -11,15 +11,7 @@ export default class MySQLTables extends Command {
11
11
  };
12
12
  async run() {
13
13
  const { flags } = await this.parse(MySQLTables);
14
- setConfigDir(this.config.configDir);
15
- let profile;
16
- try {
17
- profile = flags.profile ?? (await getMySQLConfig()).defaultProfile;
18
- }
19
- catch (error) {
20
- this.error(error instanceof Error ? error.message : String(error));
21
- }
22
- const result = await listTables(profile);
14
+ const result = await listTables(this.config, flags.profile);
23
15
  await closeConnections();
24
16
  if (result.success) {
25
17
  this.logJson(result.tables);
@@ -1,32 +1,23 @@
1
1
  import type { ConnectionOptions as MySQL2ConnectionOptions } from 'mysql2/promise';
2
- import type { DatabaseProfile } from '../config.js';
3
- /**
4
- * Safety configuration for query execution
5
- */
2
+ export interface DatabaseProfile {
3
+ database: string;
4
+ host: string;
5
+ password: string;
6
+ port: number;
7
+ ssl?: boolean;
8
+ user: string;
9
+ }
6
10
  interface SafetyConfig {
7
11
  blacklistedOperations: string[];
8
12
  defaultLimit: number;
9
13
  requireConfirmationFor: string[];
10
14
  }
11
- /**
12
- * Main configuration structure
13
- */
14
15
  export interface MySQLConfig {
15
16
  defaultFormat: 'csv' | 'json' | 'table' | 'toon';
16
17
  defaultProfile: string;
17
18
  profiles: Record<string, DatabaseProfile>;
18
19
  safety: SafetyConfig;
19
20
  }
20
- /**
21
- * MySQL connection options for mysql2 driver
22
- */
23
21
  type MySQLConnectionOptions = Pick<MySQL2ConnectionOptions, 'connectTimeout' | 'database' | 'host' | 'multipleStatements' | 'password' | 'port' | 'ssl' | 'user'>;
24
- /**
25
- * Get MySQL connection options for a specific profile
26
- *
27
- * @param config - Configuration object
28
- * @param profileName - Profile name
29
- * @returns MySQL connection options
30
- */
31
22
  export declare function getMySQLConnectionOptions(config: MySQLConfig, profileName: string): MySQLConnectionOptions;
32
23
  export {};
@@ -1,10 +1,3 @@
1
- /**
2
- * Get MySQL connection options for a specific profile
3
- *
4
- * @param config - Configuration object
5
- * @param profileName - Profile name
6
- * @returns MySQL connection options
7
- */
8
1
  export function getMySQLConnectionOptions(config, profileName) {
9
2
  const profile = config.profiles[profileName];
10
3
  if (!profile) {
@@ -1,10 +1,3 @@
1
- /**
2
- * Database abstraction interface
3
- * Defines the contract for the MySQL utility implementation
4
- */
5
- /**
6
- * Query execution result for SELECT/SHOW/DESCRIBE/EXPLAIN queries
7
- */
8
1
  export interface QueryResult {
9
2
  error?: string;
10
3
  message?: string;
@@ -12,54 +5,36 @@ export interface QueryResult {
12
5
  result?: string;
13
6
  success: boolean;
14
7
  }
15
- /**
16
- * Database list result
17
- */
18
8
  export interface DatabaseListResult {
19
9
  databases?: string[];
20
10
  error?: string;
21
11
  result?: string;
22
12
  success: boolean;
23
13
  }
24
- /**
25
- * Table list result
26
- */
27
14
  export interface TableListResult {
28
15
  error?: string;
29
16
  result?: string;
30
17
  success: boolean;
31
18
  tables?: string[];
32
19
  }
33
- /**
34
- * Table structure result
35
- */
36
20
  export interface TableStructureResult {
37
21
  error?: string;
38
22
  result?: string;
39
23
  structure?: Record<string, unknown>[];
40
24
  success: boolean;
41
25
  }
42
- /**
43
- * Index information result
44
- */
45
26
  export interface IndexResult {
46
27
  error?: string;
47
28
  indexes?: Record<string, unknown>[];
48
29
  result?: string;
49
30
  success: boolean;
50
31
  }
51
- /**
52
- * Query plan result
53
- */
54
32
  export interface ExplainResult {
55
33
  error?: string;
56
34
  plan?: Record<string, unknown>[];
57
35
  result?: string;
58
36
  success: boolean;
59
37
  }
60
- /**
61
- * Connection test result
62
- */
63
38
  export interface ConnectionTestResult {
64
39
  database?: string;
65
40
  error?: string;
@@ -67,13 +42,7 @@ export interface ConnectionTestResult {
67
42
  success: boolean;
68
43
  version?: string;
69
44
  }
70
- /**
71
- * Output format type
72
- */
73
45
  export type OutputFormat = 'csv' | 'json' | 'table' | 'toon';
74
- /**
75
- * Database utility interface
76
- */
77
46
  export interface DatabaseUtil {
78
47
  closeAll(): Promise<void>;
79
48
  describeTable(profileName: string, table: string, format?: OutputFormat): Promise<TableStructureResult>;
@@ -1,5 +1 @@
1
- /**
2
- * Database abstraction interface
3
- * Defines the contract for the MySQL utility implementation
4
- */
5
1
  export {};
@@ -0,0 +1,5 @@
1
+ import type { FieldPacket, RowDataPacket } from 'mysql2/promise';
2
+ import type { OutputFormat } from './database.js';
3
+ type Formatter = (rows: RowDataPacket[], fields: FieldPacket[]) => string;
4
+ export declare const FORMATTERS: Record<OutputFormat, Formatter>;
5
+ export {};
@@ -0,0 +1,76 @@
1
+ import { encode } from '@toon-format/toon';
2
+ function formatAsCsv(rows, fields) {
3
+ if (!rows || rows.length === 0) {
4
+ return '';
5
+ }
6
+ const columnNames = fields.map((f) => f.name);
7
+ let csv = columnNames.join(',') + '\n';
8
+ for (const row of rows) {
9
+ const values = columnNames.map((name) => {
10
+ const value = row[name] ?? '';
11
+ const str = String(value);
12
+ if (str.includes(',') || str.includes('"') || str.includes('\n')) {
13
+ return '"' + str.replaceAll('"', '""') + '"';
14
+ }
15
+ return str;
16
+ });
17
+ csv += values.join(',') + '\n';
18
+ }
19
+ return csv;
20
+ }
21
+ function formatAsJson(rows) {
22
+ return JSON.stringify(rows, null, 2);
23
+ }
24
+ function formatAsTable(rows, fields) {
25
+ if (!rows || rows.length === 0) {
26
+ return 'No results';
27
+ }
28
+ const columnNames = fields.map((f) => f.name);
29
+ const columnWidths = columnNames.map((name) => {
30
+ const dataWidth = Math.max(...rows.map((row) => String(row[name] ?? '').length));
31
+ return Math.max(name.length, dataWidth, 3);
32
+ });
33
+ let table = '┌' + columnWidths.map((w) => '─'.repeat(w + 2)).join('┬') + '┐\n';
34
+ table += '│ ' + columnNames.map((name, i) => name.padEnd(columnWidths[i])).join(' │ ') + ' │\n';
35
+ table += '├' + columnWidths.map((w) => '─'.repeat(w + 2)).join('┼') + '┤\n';
36
+ for (const row of rows) {
37
+ table +=
38
+ '│ ' +
39
+ columnNames
40
+ .map((name, i) => {
41
+ const value = row[name] ?? 'NULL';
42
+ return String(value).padEnd(columnWidths[i]);
43
+ })
44
+ .join(' │ ') +
45
+ ' │\n';
46
+ }
47
+ table += '└' + columnWidths.map((w) => '─'.repeat(w + 2)).join('┴') + '┘';
48
+ return table;
49
+ }
50
+ function formatAsToon(rows) {
51
+ if (!rows || rows.length === 0) {
52
+ return '';
53
+ }
54
+ const serializedRows = rows.map((row) => {
55
+ const serialized = {};
56
+ for (const [key, value] of Object.entries(row)) {
57
+ if (value instanceof Date) {
58
+ serialized[key] = Number.isNaN(value.getTime()) ? null : value.toISOString();
59
+ }
60
+ else if (Buffer.isBuffer(value)) {
61
+ serialized[key] = value.toString('base64');
62
+ }
63
+ else {
64
+ serialized[key] = value;
65
+ }
66
+ }
67
+ return serialized;
68
+ });
69
+ return encode(serializedRows);
70
+ }
71
+ export const FORMATTERS = {
72
+ csv: formatAsCsv,
73
+ json: formatAsJson,
74
+ table: formatAsTable,
75
+ toon: formatAsToon,
76
+ };
@@ -1,3 +1 @@
1
- export type { MySQLJsonConfig } from '../config.js';
2
- export type { ConnectionTestResult } from './database.js';
3
- export { closeConnections, describeTable, executeQuery, explainQuery, getMySQLConfig, listDatabases, listTables, setConfigDir, showIndexes, testDirectConnection, } from './mysql-client.js';
1
+ export { closeConnections, describeTable, executeQuery, explainQuery, listDatabases, listTables, showIndexes, testDirectConnection, } from './mysql-client.js';
@@ -1 +1 @@
1
- export { closeConnections, describeTable, executeQuery, explainQuery, getMySQLConfig, listDatabases, listTables, setConfigDir, showIndexes, testDirectConnection, } from './mysql-client.js';
1
+ export { closeConnections, describeTable, executeQuery, explainQuery, listDatabases, listTables, showIndexes, testDirectConnection, } from './mysql-client.js';
@@ -1,60 +1,11 @@
1
- import type { DatabaseProfile } from '../config.js';
2
- import type { MySQLConfig } from './config-loader.js';
1
+ import type { Config } from '@oclif/core';
2
+ import type { DatabaseProfile } from './config-loader.js';
3
3
  import type { ConnectionTestResult, DatabaseListResult, ExplainResult, IndexResult, OutputFormat, QueryResult, TableListResult, TableStructureResult } from './database.js';
4
- /**
5
- * Set the config directory for the singleton client
6
- * @param dir - Oclif config directory path
7
- */
8
- export declare function setConfigDir(dir: string): void;
9
- /**
10
- * Get the loaded MySQL config, initializing if needed
11
- */
12
- export declare function getMySQLConfig(): Promise<MySQLConfig>;
13
- /**
14
- * Execute SQL query
15
- * @param query - SQL query to execute
16
- * @param profile - Database profile name
17
- * @param format - Output format
18
- * @param skipConfirmation - Skip confirmation for destructive operations
19
- */
20
- export declare function executeQuery(query: string, profile: string, format?: OutputFormat, skipConfirmation?: boolean): Promise<QueryResult>;
21
- /**
22
- * List all databases
23
- * @param profile - Database profile name
24
- */
25
- export declare function listDatabases(profile: string): Promise<DatabaseListResult>;
26
- /**
27
- * List all tables in current database
28
- * @param profile - Database profile name
29
- */
30
- export declare function listTables(profile: string): Promise<TableListResult>;
31
- /**
32
- * Describe table structure
33
- * @param profile - Database profile name
34
- * @param table - Table name
35
- * @param format - Output format
36
- */
37
- export declare function describeTable(profile: string, table: string, format?: 'json' | 'table' | 'toon'): Promise<TableStructureResult>;
38
- /**
39
- * Show table indexes
40
- * @param profile - Database profile name
41
- * @param table - Table name
42
- * @param format - Output format
43
- */
44
- export declare function showIndexes(profile: string, table: string, format?: 'json' | 'table' | 'toon'): Promise<IndexResult>;
45
- /**
46
- * Explain query execution plan
47
- * @param profile - Database profile name
48
- * @param query - SQL query to explain
49
- * @param format - Output format
50
- */
51
- export declare function explainQuery(profile: string, query: string, format?: 'json' | 'table' | 'toon'): Promise<ExplainResult>;
52
- /**
53
- * Test a connection directly with profile options (without loading JSON config)
54
- * @param profile - Database connection profile options
55
- */
4
+ export declare function executeQuery(config: Config, query: string, profile?: string, format?: OutputFormat, skipConfirmation?: boolean): Promise<QueryResult>;
5
+ export declare function listDatabases(config: Config, profile?: string): Promise<DatabaseListResult>;
6
+ export declare function listTables(config: Config, profile?: string): Promise<TableListResult>;
7
+ export declare function describeTable(config: Config, table: string, profile?: string, format?: 'json' | 'table' | 'toon'): Promise<TableStructureResult>;
8
+ export declare function showIndexes(config: Config, table: string, profile?: string, format?: 'json' | 'table' | 'toon'): Promise<IndexResult>;
9
+ export declare function explainQuery(config: Config, query: string, profile?: string, format?: 'json' | 'table' | 'toon'): Promise<ExplainResult>;
56
10
  export declare function testDirectConnection(profile: DatabaseProfile): Promise<ConnectionTestResult>;
57
- /**
58
- * Close all connections
59
- */
60
11
  export declare function closeConnections(): Promise<void>;
@@ -1,127 +1,70 @@
1
- import { readConfig } from '../config.js';
1
+ import { createProfileManager } from '@hesed/plugin-lib';
2
2
  import { MySQLUtil } from './mysql-utils.js';
3
3
  let mysqlUtil = null;
4
4
  let cachedConfig = null;
5
- let cachedConfigDir;
6
- /**
7
- * Set the config directory for the singleton client
8
- * @param dir - Oclif config directory path
9
- */
10
- export function setConfigDir(dir) {
11
- cachedConfigDir = dir;
12
- }
13
- /**
14
- * Initialize (or return cached) MySQLUtil
15
- */
16
- async function initMySQL() {
5
+ const DEFAULT_SAFETY_CONFIG = {
6
+ blacklistedOperations: ['DROP DATABASE'],
7
+ defaultLimit: 100,
8
+ requireConfirmationFor: ['DELETE', 'UPDATE', 'DROP', 'TRUNCATE', 'ALTER'],
9
+ };
10
+ async function initMySQL(config) {
17
11
  if (mysqlUtil)
18
12
  return mysqlUtil;
19
- if (!cachedConfigDir) {
20
- throw new Error('MySQL client not initialized. Call setConfigDir() before running commands.');
13
+ const pm = createProfileManager(config);
14
+ const profiles = await pm.readProfiles();
15
+ if (!profiles) {
16
+ throw new Error(`No profile found.`);
21
17
  }
22
- const jsonConfig = await readConfig(cachedConfigDir, console.error);
23
- if (!jsonConfig) {
24
- throw new Error('Missing connection config. Run "mq mysql auth add" to create a config.');
18
+ const defaultProfile = await pm.getDefaultProfile();
19
+ if (!defaultProfile) {
20
+ throw new Error(`Missing default profile.`);
25
21
  }
26
22
  cachedConfig = {
27
23
  defaultFormat: 'table',
28
- defaultProfile: jsonConfig.defaultProfile,
29
- profiles: jsonConfig.profiles,
30
- safety: {
31
- blacklistedOperations: ['DROP DATABASE'],
32
- defaultLimit: 100,
33
- requireConfirmationFor: ['DELETE', 'UPDATE', 'DROP', 'TRUNCATE', 'ALTER'],
34
- },
24
+ defaultProfile,
25
+ profiles,
26
+ safety: DEFAULT_SAFETY_CONFIG,
35
27
  };
36
28
  mysqlUtil = new MySQLUtil(cachedConfig);
37
29
  return mysqlUtil;
38
30
  }
39
- /**
40
- * Get the loaded MySQL config, initializing if needed
41
- */
42
- export async function getMySQLConfig() {
43
- if (!cachedConfig) {
44
- await initMySQL();
45
- }
46
- return cachedConfig;
47
- }
48
- /**
49
- * Execute SQL query
50
- * @param query - SQL query to execute
51
- * @param profile - Database profile name
52
- * @param format - Output format
53
- * @param skipConfirmation - Skip confirmation for destructive operations
54
- */
55
- export async function executeQuery(query, profile, format = 'table', skipConfirmation = false) {
56
- return (await initMySQL()).executeQuery(profile, query, format, skipConfirmation);
31
+ // eslint-disable-next-line max-params
32
+ export async function executeQuery(config, query, profile, format = 'table', skipConfirmation = false) {
33
+ const profileName = profile ?? cachedConfig?.defaultProfile ?? 'default';
34
+ return (await initMySQL(config)).executeQuery(profileName, query, format, skipConfirmation);
57
35
  }
58
- /**
59
- * List all databases
60
- * @param profile - Database profile name
61
- */
62
- export async function listDatabases(profile) {
63
- return (await initMySQL()).listDatabases(profile);
36
+ export async function listDatabases(config, profile) {
37
+ const profileName = profile ?? cachedConfig?.defaultProfile ?? 'default';
38
+ return (await initMySQL(config)).listDatabases(profileName);
64
39
  }
65
- /**
66
- * List all tables in current database
67
- * @param profile - Database profile name
68
- */
69
- export async function listTables(profile) {
70
- return (await initMySQL()).listTables(profile);
40
+ export async function listTables(config, profile) {
41
+ const profileName = profile ?? cachedConfig?.defaultProfile ?? 'default';
42
+ return (await initMySQL(config)).listTables(profileName);
71
43
  }
72
- /**
73
- * Describe table structure
74
- * @param profile - Database profile name
75
- * @param table - Table name
76
- * @param format - Output format
77
- */
78
- export async function describeTable(profile, table, format = 'table') {
79
- return (await initMySQL()).describeTable(profile, table, format);
44
+ export async function describeTable(config, table, profile, format = 'table') {
45
+ const profileName = profile ?? cachedConfig?.defaultProfile ?? 'default';
46
+ return (await initMySQL(config)).describeTable(profileName, table, format);
80
47
  }
81
- /**
82
- * Show table indexes
83
- * @param profile - Database profile name
84
- * @param table - Table name
85
- * @param format - Output format
86
- */
87
- export async function showIndexes(profile, table, format = 'table') {
88
- return (await initMySQL()).showIndexes(profile, table, format);
48
+ export async function showIndexes(config, table, profile, format = 'table') {
49
+ const profileName = profile ?? cachedConfig?.defaultProfile ?? 'default';
50
+ return (await initMySQL(config)).showIndexes(profileName, table, format);
89
51
  }
90
- /**
91
- * Explain query execution plan
92
- * @param profile - Database profile name
93
- * @param query - SQL query to explain
94
- * @param format - Output format
95
- */
96
- export async function explainQuery(profile, query, format = 'table') {
97
- return (await initMySQL()).explainQuery(profile, query, format);
52
+ export async function explainQuery(config, query, profile, format = 'table') {
53
+ const profileName = profile ?? cachedConfig?.defaultProfile ?? 'default';
54
+ return (await initMySQL(config)).explainQuery(profileName, query, format);
98
55
  }
99
- /**
100
- * Test a connection directly with profile options (without loading JSON config)
101
- * @param profile - Database connection profile options
102
- */
103
56
  export async function testDirectConnection(profile) {
104
- const tempConfig = {
57
+ const testConfig = {
105
58
  defaultFormat: 'table',
106
- defaultProfile: '_auth',
107
- profiles: { _auth: profile },
108
- safety: {
109
- blacklistedOperations: [],
110
- defaultLimit: 100,
111
- requireConfirmationFor: [],
112
- },
59
+ defaultProfile: 'default',
60
+ profiles: { default: profile },
61
+ safety: DEFAULT_SAFETY_CONFIG,
113
62
  };
114
- const tempUtil = new MySQLUtil(tempConfig);
115
- try {
116
- return await tempUtil.testConnection('_auth');
117
- }
118
- finally {
119
- await tempUtil.closeAll();
120
- }
63
+ const util = new MySQLUtil(testConfig);
64
+ const result = await util.testConnection('default');
65
+ await util.closeAll();
66
+ return result;
121
67
  }
122
- /**
123
- * Close all connections
124
- */
125
68
  export async function closeConnections() {
126
69
  if (mysqlUtil) {
127
70
  await mysqlUtil.closeAll();
@@ -1,68 +1,18 @@
1
- import type { FieldPacket, RowDataPacket } from 'mysql2/promise';
2
1
  import type { MySQLConfig } from './config-loader.js';
3
2
  import type { ConnectionTestResult, DatabaseListResult, DatabaseUtil, ExplainResult, IndexResult, OutputFormat, QueryResult, TableListResult, TableStructureResult } from './database.js';
4
- /**
5
- * MySQL Database Utility
6
- * Provides core database operations with safety validation and formatting
7
- */
8
3
  export declare class MySQLUtil implements DatabaseUtil {
9
4
  private config;
10
- private connectionPool;
5
+ private connections;
11
6
  constructor(config: MySQLConfig);
12
- /**
13
- * Close all connections
14
- */
15
7
  closeAll(): Promise<void>;
16
- /**
17
- * Describe table structure
18
- */
19
8
  describeTable(profileName: string, table: string, format?: 'json' | 'table' | 'toon'): Promise<TableStructureResult>;
20
- /**
21
- * Validate and execute a SQL query
22
- */
23
9
  executeQuery(profileName: string, query: string, format?: OutputFormat, skipConfirmation?: boolean): Promise<QueryResult>;
24
- /**
25
- * Explain query execution plan
26
- */
27
10
  explainQuery(profileName: string, query: string, format?: 'json' | 'table' | 'toon'): Promise<ExplainResult>;
28
- /**
29
- * Format query results as CSV
30
- */
31
- formatAsCsv(rows: RowDataPacket[], fields: FieldPacket[]): string;
32
- /**
33
- * Format query results as JSON
34
- */
35
- formatAsJson(rows: RowDataPacket[]): string;
36
- /**
37
- * Format query results as table
38
- */
39
- formatAsTable(rows: RowDataPacket[], fields: FieldPacket[]): string;
40
- /**
41
- * Format query results as TOON
42
- */
43
- formatAsToon(rows: RowDataPacket[]): string;
44
- /**
45
- * List all databases
46
- */
47
11
  listDatabases(profileName: string): Promise<DatabaseListResult>;
48
- /**
49
- * List all tables in current database
50
- */
51
12
  listTables(profileName: string): Promise<TableListResult>;
52
- /**
53
- * Show table indexes
54
- */
55
13
  showIndexes(profileName: string, table: string, format?: 'json' | 'table' | 'toon'): Promise<IndexResult>;
56
- /**
57
- * Test database connection
58
- */
59
14
  testConnection(profileName: string): Promise<ConnectionTestResult>;
60
- /**
61
- * Format rows for SELECT/SHOW/DESCRIBE/EXPLAIN query result
62
- */
15
+ private formatRows;
63
16
  private formatSelectResult;
64
- /**
65
- * Get or create MySQL connection for a profile
66
- */
67
17
  private getConnection;
68
18
  }