UNPKG

@bhagat-surya-dev/dashchat-database-manager

Version:

AI-powered database schema analysis and management library

185 lines 7.68 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.SqliteHandler = void 0; // SQLite specific handler const typeorm_1 = require("typeorm"); // import { SqlDatabase } from "langchain/sql_db"; const perf_hooks_1 = require("perf_hooks"); const path_1 = __importDefault(require("path")); const fs_1 = __importDefault(require("fs")); const base_handler_1 = require("./base-handler"); class SqliteHandler extends base_handler_1.BaseDatabaseHandler { getDatabaseType() { return 'sqlite'; } // Parse the SQLite connection string to get the file path getSqliteFilePath(databaseUrl) { // Handle different URL formats if (databaseUrl.startsWith('sqlite:///')) { // Absolute path: sqlite:///path/to/database.db return databaseUrl.substring(10); } else if (databaseUrl.startsWith('sqlite://')) { // Relative path: sqlite://./database.db or sqlite://database.db const relativePath = databaseUrl.substring(9); return path_1.default.resolve(process.cwd(), relativePath); } else if (databaseUrl.endsWith('.db') || databaseUrl.endsWith('.sqlite')) { // Direct file path (not a URL) return path_1.default.resolve(databaseUrl); } throw new Error('Invalid SQLite connection string format'); } // Create TypeORM DataSource options for SQLite createDataSourceOptions(databaseUrl) { const filePath = this.getSqliteFilePath(databaseUrl); return { type: 'sqlite', database: filePath, entities: [], // Not used for schema inference synchronize: false, logging: false }; } // Validates if SQLite file exists and is accessible validateSqliteFile(databaseUrl) { try { const filePath = this.getSqliteFilePath(databaseUrl); return fs_1.default.existsSync(filePath); } catch { // Ignore the error and return false return false; } } // Quotes identifiers safely for SQLite getQuotedIdentifier(identifier) { return `"${identifier.replace(/"/g, '""')}"`; } // Get table column metadata and sample data async getTableInfo(datasource, tableName) { const method = 'getTableInfo'; // SQLite's pragma table_info is better for getting column info than information_schema const columnsQuery = `PRAGMA table_info(${this.getQuotedIdentifier(tableName)})`; const sampleDataQuery = `SELECT * FROM ${this.getQuotedIdentifier(tableName)} LIMIT ${this.maxSampleSize}`; try { const [columnsResult, sampleData] = await Promise.all([ datasource.query(columnsQuery), datasource.query(sampleDataQuery) ]); // Convert PRAGMA table_info results to our common format const columns = columnsResult.map((col) => ({ column_name: col.name, data_type: col.type, is_nullable: col.notnull === 0 ? 'YES' : 'NO' // SQLite uses 0 for nullable, 1 for NOT NULL })); return { name: tableName, columns, sampleData }; } catch (error) { this.logError(method, error instanceof Error ? error : new Error(String(error)), { tableName }); throw error; } } // Test if connection is valid async testConnection(databaseUrl) { const method = 'testConnection'; const start = perf_hooks_1.performance.now(); if (!databaseUrl) { this.logError(method, new Error('Database URL is required')); return false; } // First check if the file exists if (!this.validateSqliteFile(databaseUrl)) { this.logError(method, new Error('SQLite database file does not exist or is not accessible')); return false; } const datasource = new typeorm_1.DataSource(this.createDataSourceOptions(databaseUrl)); try { await this.withTimeout(datasource.initialize(), this.timeout, 'Connection timed out'); this.logInfo(method, 'Successfully connected to SQLite database'); return true; } catch (error) { this.logError(method, error, { databaseUrl }); return false; } finally { if (datasource.isInitialized) { await datasource.destroy(); } const duration = perf_hooks_1.performance.now() - start; this.log(base_handler_1.LogLevel.DEBUG, { method, action: 'performance_measurement', duration, metadata: { durationMs: duration.toFixed(2) } }, 'Connection test completed'); } } // Main method to get schema info async getSchemaInfo(databaseUrl) { const method = 'getSchemaInfo'; const start = perf_hooks_1.performance.now(); if (!databaseUrl) { this.log(base_handler_1.LogLevel.ERROR, { method, action: 'validation' }, 'Database URL is required.'); throw new Error('Please provide a valid database URL'); } // Validate file existence if (!this.validateSqliteFile(databaseUrl)) { throw new Error('SQLite database file does not exist or is not accessible'); } this.logInfo(method, 'Starting schema extraction for SQLite', { databaseUrl }); const datasource = new typeorm_1.DataSource(this.createDataSourceOptions(databaseUrl)); try { await datasource.initialize(); try { // Get all table names from SQLite const tableQuery = ` SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%' ORDER BY name; `; const tables = await datasource.query(tableQuery); const tableInfoPromises = tables.map((table) => this.getTableInfo(datasource, table.name)); const rawTablesInfo = await Promise.all(tableInfoPromises); return { databaseType: this.getDatabaseType(), tables: rawTablesInfo.map((table) => ({ name: table.name, columns: table.columns.map((col) => ({ name: col.column_name, type: col.data_type, nullable: col.is_nullable === 'YES' })), sampleData: table.sampleData })) }; } finally { if (datasource.isInitialized) await datasource.destroy(); } } catch (error) { this.logError(method, error, { databaseUrl }); throw error; // Re-throw after logging } finally { const duration = perf_hooks_1.performance.now() - start; this.log(base_handler_1.LogLevel.DEBUG, { method, action: 'performance_measurement', duration, metadata: { durationMs: duration.toFixed(2) } }, 'Schema extraction completed'); } } } exports.SqliteHandler = SqliteHandler; //# sourceMappingURL=sqlite-handler.js.map