Files
zclaw_openfang/src/db/database.ts
2026-03-12 00:23:42 +08:00

92 lines
2.6 KiB
TypeScript

// ZCLAW 数据库管理
import Database from 'better-sqlite3';
import { existsSync, mkdirSync } from 'fs';
import { dirname } from 'path';
import { SCHEMA_SQL } from './schema';
import { createLogger } from '../utils/logger';
const log = createLogger('Database');
let _db: Database.Database | null = null;
export function initDatabase(dbPath: string): Database.Database {
// 确保目录存在
const dir = dirname(dbPath);
if (!existsSync(dir)) {
mkdirSync(dir, { recursive: true });
}
_db = new Database(dbPath);
// 启用 WAL 模式提升性能
_db.pragma('journal_mode = WAL');
_db.pragma('foreign_keys = ON');
// 创建表
_db.exec(SCHEMA_SQL);
log.info(`Database initialized at ${dbPath}`);
return _db;
}
export function getDatabase(): Database.Database {
if (!_db) {
throw new Error('Database not initialized. Call initDatabase() first.');
}
return _db;
}
export function closeDatabase(): void {
if (_db) {
_db.close();
_db = null;
log.info('Database closed');
}
}
// 通用 CRUD 辅助
export class BaseDAO<T extends Record<string, any>> {
constructor(
protected tableName: string,
protected db: Database.Database = getDatabase()
) {}
findById(id: string): T | undefined {
return this.db.prepare(`SELECT * FROM ${this.tableName} WHERE id = ?`).get(id) as T | undefined;
}
findAll(where?: string, params?: any[]): T[] {
const sql = where
? `SELECT * FROM ${this.tableName} WHERE ${where}`
: `SELECT * FROM ${this.tableName}`;
return (params ? this.db.prepare(sql).all(...params) : this.db.prepare(sql).all()) as T[];
}
insert(data: Partial<T>): void {
const keys = Object.keys(data);
const placeholders = keys.map(() => '?').join(', ');
const sql = `INSERT OR REPLACE INTO ${this.tableName} (${keys.join(', ')}) VALUES (${placeholders})`;
this.db.prepare(sql).run(...Object.values(data));
}
update(id: string, data: Partial<T>): void {
const sets = Object.keys(data).map(k => `${k} = ?`).join(', ');
const sql = `UPDATE ${this.tableName} SET ${sets} WHERE id = ?`;
this.db.prepare(sql).run(...Object.values(data), id);
}
delete(id: string): void {
this.db.prepare(`DELETE FROM ${this.tableName} WHERE id = ?`).run(id);
}
count(where?: string, params?: any[]): number {
const sql = where
? `SELECT COUNT(*) as count FROM ${this.tableName} WHERE ${where}`
: `SELECT COUNT(*) as count FROM ${this.tableName}`;
const result = params
? this.db.prepare(sql).get(...params) as { count: number }
: this.db.prepare(sql).get() as { count: number };
return result.count;
}
}