/** * metona-sqlark Connection Manager — 数据库实例连接池 * @module connection-manager * * v0.1.13: 避免重复创建同名数据库实例,通过 connect() 复用已有连接。 * 管理实例生命周期,防止重复 open IndexedDB。 */ import { MetonaSqlark } from './core'; import type { DatabaseConfig } from './constants'; // --------------------------------------------------------------------------- // ConnectionManager // --------------------------------------------------------------------------- class ConnectionManager { /** 活跃连接:dbName → MetonaSqlark */ private connections = new Map(); /** 连接引用计数:dbName → count */ private refCount = new Map(); /** * 获取或创建数据库实例 * * 如果同名数据库已打开,复用已有实例并增加引用计数。 * 否则创建新实例。 * * @example * ```ts * const db = await MetonaSqlark.connect({ name: 'my-app', mode: 'hybrid' }); * // ... use db * await db.disconnect(); // 引用计数 -1,归零时自动关闭 * ``` */ async connect(config: DatabaseConfig): Promise { const name = config.name; // 已有连接 → 复用 const existing = this.connections.get(name); if (existing && existing.isReady()) { const count = (this.refCount.get(name) ?? 0) + 1; this.refCount.set(name, count); return existing; } // 创建新连接 const db = new MetonaSqlark(config); await db.init(); this.connections.set(name, db); this.refCount.set(name, 1); // 注入 disconnect 方法 (db as MetonaSqlark & { disconnect: () => Promise }).disconnect = async () => { await this.release(name); }; return db; } /** * 释放连接引用。引用计数归零时自动关闭数据库。 */ async release(dbName: string): Promise { const count = (this.refCount.get(dbName) ?? 1) - 1; if (count <= 0) { const db = this.connections.get(dbName); if (db) { await db.close(); this.connections.delete(dbName); } this.refCount.delete(dbName); } else { this.refCount.set(dbName, count); } } /** * 强制关闭指定数据库(忽略引用计数) */ async forceClose(dbName: string): Promise { const db = this.connections.get(dbName); if (db) { await db.close(); this.connections.delete(dbName); } this.refCount.delete(dbName); } /** * 强制关闭所有连接 */ async closeAll(): Promise { for (const [, db] of this.connections) { try { await db.close(); } catch { /* ignore */ } } this.connections.clear(); this.refCount.clear(); } /** * 获取所有活跃连接名 */ getActiveConnections(): string[] { return Array.from(this.connections.keys()); } /** * 获取连接的引用计数 */ getRefCount(dbName: string): number { return this.refCount.get(dbName) ?? 0; } } // --------------------------------------------------------------------------- // 全局单例 // --------------------------------------------------------------------------- const manager = new ConnectionManager(); // 挂载到 MetonaSqlark 静态方法(通过 any 绕过 TS 类型检查) const M = MetonaSqlark as unknown as Record; M.connect = (config: DatabaseConfig) => manager.connect(config); M.disconnect = (dbName: string) => manager.release(dbName); M.disconnectAll = () => manager.closeAll(); M.getActiveConnections = () => manager.getActiveConnections(); export { manager as connectionManager }; export default manager;