/** * 一次性迁移脚本:旧 JSON data store → SQLite(R-008 / 迭代 06,D6) * * 用途: * - 独立执行(手动 / CI),逻辑与 DataStore 启动自动迁移共用(都调用 SqliteStore.migrateJson) * - 手动/CI 环境下可显式触发迁移,无需等插件启动 * * 用法: * node scripts/migrate-json-to-sqlite.mjs # 默认数据目录 ~/.dsh/one-divine-lot * ODL_TEST_DATA_DIR=/tmp/xxx node scripts/migrate-json-to-sqlite.mjs # 指定数据目录(测试隔离,技术约束-011) * * 行为(与启动自动迁移一致,幂等): * 1. 检测 SQLite 是否为空(strategy_holdings / market_quotes_cache 均无数据)——非空则跳过; * 2. store.json → strategy_holdings(策略为中心平铺,created_at=迁移时间戳); * 3. store.market.json → market_quotes_cache(抽取 lastPrice/lastClose 两列); * 4. 旧 allocations.json(若存在)→ strategy_holdings(code 为中心聚合,跳过重复); * 5. 迁移前备份 JSON 为 *.bak;迁移失败不破坏原文件。 */ import { SqliteStore } from '../lib/component/SqliteStore.js'; async function main() { const store = new SqliteStore({}); // dataDir 默认 ~/.dsh/one-divine-lot,或 ODL_TEST_DATA_DIR try { if (!store.isEmpty()) { console.log('[migrate] SQLite 已有数据,跳过迁移(幂等)'); return; } const result = await store.migrateJson(); console.log('[migrate] 迁移完成:', JSON.stringify(result)); if (result.holdings === 0 && result.quotes === 0) { console.log('[migrate] 无数据可迁移(store.json / store.market.json / allocations.json 均不存在或为空)'); } else { console.log('[migrate] 旧 JSON 已备份为 *.bak,可安全删除或保留'); } } catch (err) { console.error('[migrate] 迁移失败:', err.message); process.exitCode = 1; } finally { store.close(); } } main();