diff --git a/src/resultStore.js b/src/resultStore.js index 628587c..2065b83 100644 --- a/src/resultStore.js +++ b/src/resultStore.js @@ -1,15 +1,23 @@ import Database from 'better-sqlite3'; -import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs'; +import { + copyFileSync, + existsSync, + mkdirSync, + readFileSync, + renameSync, + unlinkSync, + writeFileSync, +} from 'fs'; import { fileURLToPath } from 'url'; import { dirname, join } from 'path'; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); -const DB_PATH = - process.env.APP_DB_PATH || - process.env.RESULTS_DB_PATH || - join(__dirname, '..', 'data', 'results.sqlite'); +const DEFAULT_DB_DIR = join(__dirname, '..', 'data'); +const DEFAULT_DB_PATH = join(DEFAULT_DB_DIR, 'results.db'); +const LEGACY_DB_PATH = join(DEFAULT_DB_DIR, 'results.sqlite'); +const DB_PATH = resolveDbPath(); const CONFIG_PATH = join(__dirname, '..', 'config.json'); const MAX_RESULT_RECORDS = 500; const DEFAULT_TASK_MODE = 'qwen3.5-plus'; @@ -22,6 +30,55 @@ function clone(value) { return JSON.parse(JSON.stringify(value)); } +function removeFileIfExists(filePath) { + if (!existsSync(filePath)) return; + unlinkSync(filePath); +} + +function migrateLegacyDbIfNeeded(nextPath, legacyPath) { + if (existsSync(nextPath) || !existsSync(legacyPath)) return nextPath; + + const legacyDb = new Database(legacyPath); + + try { + legacyDb.pragma('wal_checkpoint(TRUNCATE)'); + } catch (_error) { + // Ignore checkpoint failures and still attempt to switch to single-file mode. + } + + legacyDb.pragma('journal_mode = DELETE'); + legacyDb.close(); + + try { + renameSync(legacyPath, nextPath); + } catch (_error) { + copyFileSync(legacyPath, nextPath); + } + + removeFileIfExists(`${legacyPath}-shm`); + removeFileIfExists(`${legacyPath}-wal`); + + return nextPath; +} + +function resolveDbPath() { + const explicitPath = process.env.APP_DB_PATH || process.env.RESULTS_DB_PATH; + if (explicitPath) return explicitPath; + + mkdirSync(DEFAULT_DB_DIR, { recursive: true }); + + try { + return migrateLegacyDbIfNeeded(DEFAULT_DB_PATH, LEGACY_DB_PATH); + } catch (error) { + if (existsSync(LEGACY_DB_PATH)) { + console.warn(`[resultStore] Legacy database migration skipped: ${error.message}`); + return LEGACY_DB_PATH; + } + + throw error; + } +} + function generateResultId() { return `result-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`; } @@ -141,7 +198,13 @@ function getDb() { mkdirSync(dirname(DB_PATH), { recursive: true }); db = new Database(DB_PATH); - db.pragma('journal_mode = WAL'); + + try { + db.pragma('journal_mode = DELETE'); + } catch (error) { + console.warn(`[resultStore] Database journal mode unchanged: ${error.message}`); + } + return db; }