fix(app): guard force-column migration against downgrade-then-reupgrade
Review hardening for Task 8 (test-server workflow: testers install older APKs over a newer DB): - Old APK opening a v2 database hits drift's downgrade path, which leaves the force column in place but writes user_version back to 1. Reinstalling the new APK then re-runs onUpgrade(1,2) and addColumn crashes with "duplicate column name: force", failing the DB open. - onUpgrade now checks PRAGMA table_info(upload_tasks) and only adds the force column when absent; the normal v1 -> v2 path is unchanged. - Migration test simulates the downgrade-reupgrade cycle on a file-backed database (v2 open -> user_version forced back to 1 -> re-upgrade), asserting the open succeeds, legacy rows survive, and the column stays writable. RED before the guard (SqliteException: duplicate column name). Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
@@ -141,7 +141,20 @@ class UploadTaskDb extends _$UploadTaskDb {
|
||||
MigrationStrategy get migration => MigrationStrategy(
|
||||
onUpgrade: (m, from, to) async {
|
||||
if (from == 1) {
|
||||
await m.addColumn(uploadTasks, uploadTasks.force);
|
||||
// 降级-重升级防护:旧 APK 覆盖安装打开 v2 库时,drift 降级
|
||||
// 路径不改表、只把 user_version 写回 1(force 列留存);随后
|
||||
// 新 APK 重升级再次走到这里——无条件 addColumn 会撞
|
||||
// 「duplicate column name: force」致库打开失败。先探测列
|
||||
// 存在性,缺列才补(正常 v1 → v2 路径列必缺省,行为不变)。
|
||||
final columns = await m.database
|
||||
.customSelect('PRAGMA table_info(upload_tasks)')
|
||||
.get();
|
||||
final forceExists = columns.any(
|
||||
(row) => row.read<String>('name') == 'force',
|
||||
);
|
||||
if (!forceExists) {
|
||||
await m.addColumn(uploadTasks, uploadTasks.force);
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user