fix(#48): add the missing version-local migration for syb_session
Adding SYBSession to migrations.Migrate was not enough. Schema reaches an
existing database only through a version-local file; with the previous
version already recorded in sys_migration, Migrate never re-ran and the
table simply never appeared. The unit tests build a fresh database every
time, so they stayed green while the real database was missing a table —
which surfaced as "Error 1146: Table 'goauto.syb_session' doesn't exist"
on the first import attempt.
server/.gitignore was hiding these files. go-admin ignores version-local
because it is where generated local migrations land, but every GoAuto
migration belongs in version control; the existing ones had been forced
in with `git add -f`. Un-ignoring *.go there also recovers four migrations
that were never committed at all — 1786700000000 through 1786700300000,
covering the base schema, device registration, heartbeat and collection
execution. A fresh clone could not have built a working database.
Guard the class of mistake rather than just this instance:
- migrations.VerifyTables checks every model's table after migrating and
names what is missing along with the fix.
- The migrate command runs it, so the failure lands at migrate time
instead of at the first request that needs the table.
- initDB no longer discards migrateModel's error. Upstream had
`_ = migrateModel()` followed by an unconditional "初始化成功", so a
failed migration reported success and the launcher believed it.
Also records the two-step rule in Common-Changes: a new model needs both
the model registration and a new version file.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -376,3 +376,29 @@ func TestEveryModelDeclaresSingularTableName(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestVerifyTablesPassesAfterMigrate(t *testing.T) {
|
||||
db := openDatabase(t)
|
||||
if err := migrations.VerifyTables(db); err != nil {
|
||||
t.Fatalf("迁移后不应有缺表: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// 缺表时必须报出表名,并说清楚该怎么修——这正是漏建 version-local 迁移文件
|
||||
// 时的现场,之前它只会在运行时变成一句 "Error 1146"。
|
||||
func TestVerifyTablesNamesMissingTablesAndTheFix(t *testing.T) {
|
||||
db := openDatabase(t)
|
||||
if err := db.Migrator().DropTable("syb_session"); err != nil {
|
||||
t.Fatalf("删表失败: %v", err)
|
||||
}
|
||||
err := migrations.VerifyTables(db)
|
||||
if err == nil {
|
||||
t.Fatal("缺表时应报错")
|
||||
}
|
||||
if !strings.Contains(err.Error(), "syb_session") {
|
||||
t.Fatalf("错误信息应指出缺哪张表: %v", err)
|
||||
}
|
||||
if !strings.Contains(err.Error(), "version-local") {
|
||||
t.Fatalf("错误信息应说明修法: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// VerifyTables reports which tables in the GoAuto schema are missing.
|
||||
//
|
||||
// `[必须]` This exists because adding a model to Migrate is not enough on its
|
||||
// own. Schema changes reach an existing database only through a new
|
||||
// version-local migration file; without one, the already-recorded version is
|
||||
// skipped, Migrate never runs again, and the new table simply never appears.
|
||||
// Nothing fails at migrate time — the gap surfaces much later as a bare
|
||||
// "Error 1146: Table ... doesn't exist" from whatever feature needed it.
|
||||
//
|
||||
// Running this right after the migrations turns that into an immediate,
|
||||
// named failure.
|
||||
func VerifyTables(db *gorm.DB) error {
|
||||
type tableNamer interface{ TableName() string }
|
||||
|
||||
missing := make([]string, 0)
|
||||
for _, model := range MigratedModels() {
|
||||
namer, ok := model.(tableNamer)
|
||||
if !ok {
|
||||
return fmt.Errorf("模型 %T 没有声明 TableName()", model)
|
||||
}
|
||||
if !db.Migrator().HasTable(namer.TableName()) {
|
||||
missing = append(missing, namer.TableName())
|
||||
}
|
||||
}
|
||||
if len(missing) == 0 {
|
||||
return nil
|
||||
}
|
||||
sort.Strings(missing)
|
||||
return fmt.Errorf(
|
||||
"迁移后仍缺少表:%s。新增模型必须同时在 cmd/migrate/migration/version-local/ "+
|
||||
"下新建一个版本文件;只把模型加进 migrations.Migrate 对已有数据库无效,"+
|
||||
"因为旧版本号已记录在 sys_migration 中,不会再次执行",
|
||||
strings.Join(missing, "、"))
|
||||
}
|
||||
Reference in New Issue
Block a user