/** * metona-sqlark Core — 数据库主类 * @module core * * 管理数据库生命周期、引擎调度、表操作、SQL 查询、事务和插件。 */ import type { IStorageEngine } from './engine/interface'; import type { DatabaseConfig, ColumnDef } from './constants'; import { DB_DEFAULTS, DatabaseError } from './constants'; import { MemoryEngine } from './engine/memory'; import { IndexedDBEngine } from './engine/indexeddb'; import { OPFSEngine } from './engine/opfs'; import { AriaEngine } from './engine/aria/index'; import { HybridEngine } from './hybrid/index'; import { Table } from './table/table'; import { createSchema } from './table/schema'; import { QueryExecutor } from './query/executor'; import { parse } from './sql/parser'; import { TransactionManager } from './transaction/index'; import { PluginManager } from './plugin/index'; import type { Statement } from './query/ast'; // --------------------------------------------------------------------------- // MetonaSqlark // --------------------------------------------------------------------------- export class MetonaSqlark { /** 数据库名称 */ readonly name: string; /** 存储模式 */ readonly mode: string; /** 版本号 */ private _version: number; /** 获取版本号 */ get version(): number { return this._version; } private engine!: IStorageEngine; private executor!: QueryExecutor; private transactionManager!: TransactionManager; private pluginManager: PluginManager; private config: DatabaseConfig; private ready = false; private tableCache: Map = new Map(); /** 查询结果行数上限 */ get maxRowsPerQuery(): number { return this.config.maxRowsPerQuery ?? 0; } /** 调试模式 */ get debug(): boolean { return this.config.debug ?? false; } constructor(config: DatabaseConfig) { this.config = config; this.name = config.name ?? DB_DEFAULTS.name; this.mode = config.mode ?? DB_DEFAULTS.mode; this._version = config.version ?? DB_DEFAULTS.version; this.pluginManager = new PluginManager(); } // ---- 初始化 ---- /** 初始化数据库(创建引擎、打开连接) */ async init(): Promise { // 创建引擎 this.engine = this.createEngine(); // 打开连接 await this.engine.open(this.name, this.version); // 初始化执行器和事务管理器 this.executor = new QueryExecutor(this.engine); this.transactionManager = new TransactionManager(this.engine); // 注册插件 if (this.config.plugins) { for (const plugin of this.config.plugins) { this.pluginManager.register(plugin); } } this.ready = true; // 回调 if (this.config.onReady) { this.config.onReady(this); } } /** 检查是否就绪 */ isReady(): boolean { return this.ready; } // ---- 表管理 ---- /** 创建表 */ async defineTable(name: string, columns: Record): Promise { this.ensureReady(); const schema = createSchema(name, columns); await this.pluginManager.trigger('beforeCreateTable', schema); await this.engine.createTable(schema); await this.pluginManager.trigger('afterCreateTable', schema); // 清除缓存 this.tableCache.delete(name); } /** 获取表操作对象 */ table(name: string): Table { this.ensureReady(); let t = this.tableCache.get(name); if (!t) { t = new Table(this.engine, name, this.executor); this.tableCache.set(name, t); } return t; } /** 删除表 */ async dropTable(name: string): Promise { this.ensureReady(); await this.pluginManager.trigger('beforeDropTable', name); await this.engine.dropTable(name); await this.pluginManager.trigger('afterDropTable', name); this.tableCache.delete(name); } /** 获取所有表名 */ async getTableNames(): Promise { this.ensureReady(); return this.engine.getTableNames(); } // ---- SQL 查询 ---- /** 执行 SQL 字符串查询 */ async query(sql: string): Promise { this.ensureReady(); const startTime = this.debug ? Date.now() : 0; await this.pluginManager.trigger('beforeQuery', sql); const stmt: Statement = parse(sql); const result = await this.executor.execute(stmt); await this.pluginManager.trigger('afterQuery', sql, result); if (this.debug) { const elapsed = Date.now() - startTime; const rows = Array.isArray(result) ? (result as any[]).length : 0; this._debug(`query [${elapsed}ms] ${rows} rows: ${sql.slice(0, 100)}`); } return result; } // ---- 事务 ---- /** 执行事务 */ async transaction(fn: (trx: import('./transaction/index').Transaction) => Promise): Promise { this.ensureReady(); await this.pluginManager.trigger('beforeTransaction'); const result = await this.transactionManager.execute(fn); await this.pluginManager.trigger('afterTransaction'); return result; } // ---- 导入导出 ---- /** 导出表数据为 JSON */ async exportTable(tableName: string): Promise[]> { this.ensureReady(); return this.engine.find(tableName, { table: tableName }); } /** 导入 JSON 数据到表 */ async importTable(tableName: string, data: Record[]): Promise { this.ensureReady(); return this.engine.insert(tableName, data); } /** 导出整个数据库为 JSON */ async exportAll(): Promise[]>> { this.ensureReady(); const result: Record[]> = {}; const names = await this.engine.getTableNames(); for (const name of names) { result[name] = await this.engine.find(name, { table: name }); } return result; } // ---- 发布订阅 ---- private listeners: Map void>> = new Map(); /** 订阅表变更 */ subscribe(tableName: string, callback: (event: { type: string; row?: unknown }) => void): () => void { const key = `change:${tableName}`; if (!this.listeners.has(key)) this.listeners.set(key, new Set()); this.listeners.get(key)!.add(callback as (data: unknown) => void); return () => this.listeners.get(key)?.delete(callback as (data: unknown) => void); } /** 触发变更事件 */ emit(tableName: string, event: { type: string; row?: unknown }): void { const key = `change:${tableName}`; this.listeners.get(key)?.forEach((cb) => cb(event)); } // ---- 迁移 ---- private migrations: Map Promise> = new Map(); /** 注册迁移 */ addMigration(version: number, up: (db: MetonaSqlark) => Promise): void { this.migrations.set(version, up); } /** 执行迁移到指定版本 */ async migrateTo(targetVersion: number): Promise { this.ensureReady(); for (const [version, up] of [...this.migrations.entries()].sort((a, b) => a[0] - b[0])) { if (version <= targetVersion && version > this.version) { await up(this); this._version = version; } } } // ---- 插件 ---- /** 获取插件管理器 */ getPluginManager(): PluginManager { return this.pluginManager; } /** 注册钩子 */ on(hook: import('./constants').HookName, callback: import('./plugin/index').HookCallback): void { this.pluginManager.on(hook, callback); } // ---- 生命周期 ---- /** 关闭数据库 */ async close(): Promise { this.pluginManager.destroy(); await this.engine.close(); this.tableCache.clear(); this.ready = false; } /** 获取底层引擎 */ getEngine(): IStorageEngine { return this.engine; } // ---- 内部 ---- private createEngine(): IStorageEngine { const mode = this.mode; const diskEngine = this.config.diskEngine ?? 'indexeddb'; switch (mode) { case 'memory': return new MemoryEngine(); case 'disk': return diskEngine === 'opfs' ? new OPFSEngine() : new IndexedDBEngine(); case 'aria': return new AriaEngine({ storageBackend: diskEngine === 'opfs' ? 'memory' : 'indexeddb' }); case 'hybrid': return new HybridEngine(diskEngine); default: throw new DatabaseError(`Unknown storage mode: ${mode}`, 'CONFIG_ERROR'); } } private ensureReady(): void { if (!this.ready) { throw new DatabaseError('Database not initialized. Call await db.init() first.', 'DB_NOT_READY'); } } /** 错误回调分发 */ private _onError(error: Error): void { if (this.config.onError) { try { this.config.onError(error); } catch { /* 避免回调自身异常影响主流程 */ } } } /** 调试日志 */ private _debug(msg: string, ...args: unknown[]): void { if (this.debug) { console.debug(`[MetonaSqlark:${this.name}] ${msg}`, ...args); } } }