/** * SQLite 数据层(§4.1) * 表:settings / ignored_packages / logs */ import Database from 'better-sqlite3' import fs from 'node:fs' import path from 'node:path' import { fileURLToPath } from 'node:url' const __dirname = path.dirname(fileURLToPath(import.meta.url)) // 数据目录:环境变量 DATA_DIR 可覆盖(Docker 挂载 manager-data) const DATA_DIR = process.env.DATA_DIR || path.join(__dirname, 'data') fs.mkdirSync(DATA_DIR, { recursive: true }) const db = new Database(path.join(DATA_DIR, 'manager.db')) db.pragma('journal_mode = WAL') db.exec(` CREATE TABLE IF NOT EXISTS settings ( key TEXT PRIMARY KEY, value TEXT ); CREATE TABLE IF NOT EXISTS ignored_packages ( pkg_name TEXT PRIMARY KEY, ignored_at DATETIME DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE IF NOT EXISTS logs ( id INTEGER PRIMARY KEY AUTOINCREMENT, pkg_name TEXT, deleted_versions TEXT, deleted_count INTEGER, freed_space TEXT, created_at DATETIME DEFAULT CURRENT_TIMESTAMP ); `) // —— settings —— export function getSetting(key, def = null) { const row = db.prepare('SELECT value FROM settings WHERE key = ?').get(key) return row ? row.value : def } export function setSetting(key, value) { db.prepare( 'INSERT INTO settings (key, value) VALUES (?, ?) ON CONFLICT(key) DO UPDATE SET value = excluded.value', ).run(key, String(value)) } // —— ignored —— export function getIgnored() { return db.prepare('SELECT pkg_name FROM ignored_packages ORDER BY ignored_at DESC').all().map(r => r.pkg_name) } export function getIgnoredRows() { return db.prepare('SELECT pkg_name, ignored_at FROM ignored_packages ORDER BY ignored_at DESC').all() } export function isIgnored(pkgName) { return !!db.prepare('SELECT 1 FROM ignored_packages WHERE pkg_name = ?').get(pkgName) } export function addIgnored(pkgName) { db.prepare( 'INSERT INTO ignored_packages (pkg_name) VALUES (?) ON CONFLICT(pkg_name) DO NOTHING', ).run(pkgName) } export function removeIgnored(pkgName) { db.prepare('DELETE FROM ignored_packages WHERE pkg_name = ?').run(pkgName) } // —— logs —— export function addLog({ pkgName, deletedVersions, deletedCount, freedSpace }) { const info = db.prepare( 'INSERT INTO logs (pkg_name, deleted_versions, deleted_count, freed_space) VALUES (?, ?, ?, ?)', ).run(pkgName, deletedVersions, deletedCount, freedSpace) return info.lastInsertRowid } export function getLogs(limit = 50) { return db.prepare( 'SELECT * FROM logs ORDER BY id DESC LIMIT ?', ).all(limit) } export default db