fix(store): 补 checks/auto_approve_* 列的 ensureColumn 迁移(旧 DB 缺列 bug)
线上实测复现:既有 DB 的 projects 表早于这三列创建,schema.sql 的 CREATE TABLE IF NOT EXISTS 对已存在表是 no-op,故必须靠 ensureColumn 补列, 否则 createProject 的 INSERT 引用不存在的列报错「table projects has no column named checks」。 上个会话加列时漏了迁移,:memory: 测试走全新建表没暴露。 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,51 @@
|
||||
import { test } from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import Database from 'better-sqlite3';
|
||||
import { mkdtempSync, rmSync } from 'node:fs';
|
||||
import { tmpdir } from 'node:os';
|
||||
import { join } from 'node:path';
|
||||
import { openDb } from '../src/store/db.js';
|
||||
import { Store } from '../src/store/index.js';
|
||||
|
||||
/**
|
||||
* 回归:旧 DB 的 projects 表早于 checks、auto_approve_x、budget、agent_rules 等列创建,
|
||||
* schema.sql 的 CREATE TABLE IF NOT EXISTS 对已存在的表是 no-op → 这些列必须靠 ensureColumn 迁移补上。
|
||||
* 漏迁移会导致 createProject 的 INSERT 引用不存在的列而报错(线上实测复现)。
|
||||
*/
|
||||
test('迁移:旧 projects 表缺新列 → openDb 补齐 + createProject 不报错', () => {
|
||||
const dir = mkdtempSync(join(tmpdir(), 'maestro-mig-'));
|
||||
const file = join(dir, 'old.db');
|
||||
try {
|
||||
// 造一个"旧版" projects 表(只有最早期那批列,缺 checks/auto_approve_*/budget/agent_rules…)
|
||||
const raw = new Database(file);
|
||||
raw.exec(`CREATE TABLE projects (
|
||||
id TEXT PRIMARY KEY, name TEXT NOT NULL, repo_path TEXT NOT NULL UNIQUE,
|
||||
default_branch TEXT NOT NULL DEFAULT 'main', verify_cmd TEXT,
|
||||
autonomy TEXT NOT NULL DEFAULT 'manual', model TEXT,
|
||||
concurrency INTEGER NOT NULL DEFAULT 1, status TEXT NOT NULL DEFAULT 'active',
|
||||
created_at TEXT NOT NULL
|
||||
)`);
|
||||
raw.close();
|
||||
|
||||
// openDb 跑迁移:应补齐所有后加列
|
||||
const db = openDb(file);
|
||||
const cols = (db.prepare(`PRAGMA table_info(projects)`).all() as Array<{ name: string }>).map((c) => c.name);
|
||||
for (const c of [
|
||||
'checks', 'auto_approve_plan', 'auto_approve_exec', 'agent_rules',
|
||||
'budget_usd', 'budget_period', 'max_retries', 'timeout_ms', 'last_sync_at', 'logo', 'sort_order',
|
||||
]) {
|
||||
assert.ok(cols.includes(c), `应补列 ${c}`);
|
||||
}
|
||||
db.close();
|
||||
|
||||
// Store 在该旧库上建项目(INSERT 引用 checks/auto_approve_* 列)应成功
|
||||
const s = new Store(file);
|
||||
const p = s.createProject({ name: 'mig', repoPath: '/tmp/mig-' + Math.random() });
|
||||
assert.equal(p.autoApprovePlan, false);
|
||||
assert.equal(p.autoApproveExec, false);
|
||||
assert.equal(p.checks, null);
|
||||
s.close();
|
||||
} finally {
|
||||
rmSync(dir, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user