mcp-dbs
by cuongtl1992
Verified
import sqlite3 from 'sqlite3';
import { Database, SchemaInfo, TableSchema, ColumnInfo } from '../interfaces/database.js';
import { promisify } from 'util';
/**
* Configuration for SQLite database connection
*/
export interface SQLiteConfig {
/**
* Path to the SQLite database file
*/
filename: string;
/**
* Whether to create the database if it doesn't exist
*/
createIfNotExists?: boolean;
/**
* Whether to use read-only mode
*/
readOnly?: boolean;
}
/**
* SQLite database implementation
*/
export class SQLiteDatabase implements Database {
private db: sqlite3.Database | null = null;
private config: SQLiteConfig;
/**
* Create a new SQLite database connection
* @param config Connection configuration
*/
constructor(config: SQLiteConfig) {
this.config = config;
}
/**
* Connect to the SQLite database
*/
async connect(): Promise<void> {
return new Promise((resolve, reject) => {
let mode = sqlite3.OPEN_READWRITE;
if (this.config.createIfNotExists) {
mode |= sqlite3.OPEN_CREATE;
}
if (this.config.readOnly) {
mode = sqlite3.OPEN_READONLY;
}
this.db = new sqlite3.Database(this.config.filename, mode, (err) => {
if (err) {
reject(err);
} else {
resolve();
}
});
});
}
/**
* Disconnect from the SQLite database
*/
async disconnect(): Promise<void> {
if (!this.db) {
return;
}
return new Promise((resolve, reject) => {
this.db!.close((err) => {
if (err) {
reject(err);
} else {
this.db = null;
resolve();
}
});
});
}
/**
* Execute a query and return results
* @param query SQL query to execute
* @param params Parameters for the query
*/
async query(query: string, params: any[] = []): Promise<any> {
this.ensureConnected();
return new Promise((resolve, reject) => {
this.db!.all(query, params, (err, rows) => {
if (err) {
reject(err);
} else {
resolve(rows);
}
});
});
}
/**
* Execute a query that doesn't return results
* @param query SQL query to execute
* @param params Parameters for the query
*/
async execute(query: string, params: any[] = []): Promise<void> {
this.ensureConnected();
return new Promise((resolve, reject) => {
this.db!.run(query, params, function(err) {
if (err) {
reject(err);
} else {
resolve();
}
});
});
}
/**
* Get all table names
*/
async getTables(): Promise<string[]> {
this.ensureConnected();
const rows = await this.query(
"SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%'",
[]
);
return rows.map((row: any) => row.name);
}
/**
* Get column information for a specific table
* @param tableName Name of the table
*/
async getTableSchema(tableName: string): Promise<TableSchema> {
this.ensureConnected();
const pragmaResult = await this.query(`PRAGMA table_info(${tableName})`, []);
const columns: ColumnInfo[] = pragmaResult.map((row: any) => {
return {
name: row.name,
type: row.type,
nullable: row.notnull === 0,
isPrimaryKey: row.pk === 1,
defaultValue: row.dflt_value
};
});
return {
tableName,
columns
};
}
/**
* Get database schema information
*/
async getSchema(): Promise<SchemaInfo> {
const tables = await this.getTables();
const tableSchemas = await Promise.all(
tables.map(tableName => this.getTableSchema(tableName))
);
return {
databaseName: this.config.filename,
tables: tableSchemas
};
}
/**
* Ensure the database connection is established
* @throws Error if not connected
*/
private ensureConnected(): void {
if (!this.db) {
throw new Error('Database not connected. Call connect() first.');
}
}
}