92 lines
2.6 KiB
TypeScript
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;
|
|
}
|
|
}
|