import { DatabaseConnector, ConnectionConfig, QueryResult } from '../interfaces/DatabaseConnector'; import { ConnectionTestResult, TableInfo } from '../types/externalDbTypes'; import * as mysql from 'mysql2/promise'; export class MariaDBConnector implements DatabaseConnector { private connection: mysql.Connection | null = null; private config: ConnectionConfig; constructor(config: ConnectionConfig) { this.config = config; } async connect(): Promise { if (!this.connection) { this.connection = await mysql.createConnection({ host: this.config.host, port: this.config.port, user: this.config.user, password: this.config.password, database: this.config.database, connectTimeout: this.config.connectionTimeoutMillis, ssl: typeof this.config.ssl === 'boolean' ? undefined : this.config.ssl, }); } } async disconnect(): Promise { if (this.connection) { await this.connection.end(); this.connection = null; } } async testConnection(): Promise { const startTime = Date.now(); try { await this.connect(); const [rows] = await this.connection!.query("SELECT VERSION() as version"); const version = (rows as any[])[0]?.version || "Unknown"; const responseTime = Date.now() - startTime; await this.disconnect(); return { success: true, message: "MariaDB/MySQL 연결이 성공했습니다.", details: { response_time: responseTime, server_version: version, }, }; } catch (error: any) { await this.disconnect(); return { success: false, message: "MariaDB/MySQL 연결에 실패했습니다.", error: { code: "CONNECTION_FAILED", details: error.message || "알 수 없는 오류", }, }; } } async executeQuery(query: string): Promise { try { await this.connect(); const [rows, fields] = await this.connection!.query(query); await this.disconnect(); return { rows: rows as any[], fields: fields as any[], }; } catch (error: any) { await this.disconnect(); throw new Error(`쿼리 실행 실패: ${error.message}`); } } async getTables(): Promise { try { await this.connect(); const [rows] = await this.connection!.query(` SELECT TABLE_NAME as table_name, TABLE_COMMENT as description FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() ORDER BY TABLE_NAME; `); const tables: TableInfo[] = []; for (const row of rows as any[]) { const columns = await this.getColumns(row.table_name); tables.push({ table_name: row.table_name, description: row.description || null, columns: columns, }); } await this.disconnect(); return tables; } catch (error: any) { await this.disconnect(); throw new Error(`테이블 목록 조회 실패: ${error.message}`); } } async getColumns(tableName: string): Promise { try { await this.connect(); const [rows] = await this.connection!.query(` SELECT COLUMN_NAME as column_name, DATA_TYPE as data_type, IS_NULLABLE as is_nullable, COLUMN_DEFAULT as column_default FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = ? ORDER BY ORDINAL_POSITION; `, [tableName]); await this.disconnect(); return rows as any[]; } catch (error: any) { await this.disconnect(); throw new Error(`컬럼 정보 조회 실패: ${error.message}`); } } }