@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.
- package/README.md +107 -32
- package/dist/commands/mysql/auth/add.d.ts +2 -18
- package/dist/commands/mysql/auth/add.js +16 -57
- package/dist/commands/mysql/auth/delete.d.ts +2 -0
- package/dist/commands/mysql/auth/delete.js +2 -0
- package/dist/commands/mysql/auth/list.d.ts +2 -0
- package/dist/commands/mysql/auth/list.js +2 -0
- package/dist/commands/mysql/auth/profile.d.ts +2 -0
- package/dist/commands/mysql/auth/profile.js +2 -0
- package/dist/commands/mysql/auth/test.d.ts +2 -12
- package/dist/commands/mysql/auth/test.js +16 -41
- package/dist/commands/mysql/auth/update.d.ts +2 -18
- package/dist/commands/mysql/auth/update.js +16 -74
- package/dist/commands/mysql/databases.js +2 -10
- package/dist/commands/mysql/describe-table.js +2 -10
- package/dist/commands/mysql/explain-query.js +2 -10
- package/dist/commands/mysql/indexes.js +2 -10
- package/dist/commands/mysql/query.js +2 -10
- package/dist/commands/mysql/tables.js +2 -10
- package/dist/mysql/config-loader.d.ts +8 -17
- package/dist/mysql/config-loader.js +0 -7
- package/dist/mysql/database.d.ts +0 -31
- package/dist/mysql/database.js +0 -4
- package/dist/mysql/formatters.d.ts +5 -0
- package/dist/mysql/formatters.js +76 -0
- package/dist/mysql/index.d.ts +1 -3
- package/dist/mysql/index.js +1 -1
- package/dist/mysql/mysql-client.d.ts +8 -57
- package/dist/mysql/mysql-client.js +44 -101
- package/dist/mysql/mysql-utils.d.ts +2 -52
- package/dist/mysql/mysql-utils.js +31 -177
- package/dist/mysql/query-validator.d.ts +0 -19
- package/dist/mysql/query-validator.js +0 -19
- package/oclif.manifest.json +176 -59
- package/package.json +3 -2
- package/dist/config.d.ts +0 -13
- package/dist/config.js +0 -18
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Args, Command, Flags } from '@oclif/core';
|
|
2
|
-
import { closeConnections,
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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,
|
|
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
|
-
|
|
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
|
-
|
|
3
|
-
|
|
4
|
-
|
|
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) {
|
package/dist/mysql/database.d.ts
CHANGED
|
@@ -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>;
|
package/dist/mysql/database.js
CHANGED
|
@@ -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
|
+
};
|
package/dist/mysql/index.d.ts
CHANGED
|
@@ -1,3 +1 @@
|
|
|
1
|
-
export
|
|
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';
|
package/dist/mysql/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { closeConnections, describeTable, executeQuery, explainQuery,
|
|
1
|
+
export { closeConnections, describeTable, executeQuery, explainQuery, listDatabases, listTables, showIndexes, testDirectConnection, } from './mysql-client.js';
|
|
@@ -1,60 +1,11 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type {
|
|
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
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
export declare function
|
|
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 {
|
|
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
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
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
|
-
|
|
20
|
-
|
|
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
|
|
23
|
-
if (!
|
|
24
|
-
throw new Error(
|
|
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
|
|
29
|
-
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
|
-
|
|
41
|
-
|
|
42
|
-
|
|
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
|
-
|
|
60
|
-
|
|
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
|
-
|
|
67
|
-
|
|
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
|
-
|
|
74
|
-
|
|
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
|
-
|
|
83
|
-
|
|
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
|
-
|
|
92
|
-
|
|
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
|
|
57
|
+
const testConfig = {
|
|
105
58
|
defaultFormat: 'table',
|
|
106
|
-
defaultProfile: '
|
|
107
|
-
profiles: {
|
|
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
|
|
115
|
-
|
|
116
|
-
|
|
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
|
|
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
|
}
|