From 4f7f3a612ad01c22fea4353fcfd57ded13b8c03f Mon Sep 17 00:00:00 2001 From: QiuSW <105186638@qq.com> Date: Thu, 20 Aug 2026 09:00:58 +0800 Subject: [PATCH] fix(#48): give SYBSession an explicit singular table name MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Every other GoAuto model declares TableName(); SYBSession did not, so gorm silently created syb_sessions while the rest of the schema is singular. Migration succeeds either way, which is what makes it easy to miss — it only surfaces when someone queries the conventional name. Caught by running a real import, before the MySQL migration had been run anywhere. Migrate now takes its model list from MigratedModels(), so the new convention test asserts over exactly the set that Migrate creates instead of a hand-copied list that would drift. Mutation-checked: dropping the TableName method again makes the test fail. Co-Authored-By: Claude Opus 5 --- server/app/goauto/migrations/migrate.go | 13 ++++++++++--- server/app/goauto/migrations/migrate_test.go | 17 +++++++++++++++++ server/app/goauto/models/schema.go | 2 ++ 3 files changed, 29 insertions(+), 3 deletions(-) diff --git a/server/app/goauto/migrations/migrate.go b/server/app/goauto/migrations/migrate.go index e18f18d..254c3a1 100644 --- a/server/app/goauto/migrations/migrate.go +++ b/server/app/goauto/migrations/migrate.go @@ -8,8 +8,11 @@ import ( // Migrate creates the complete GoAuto MVP schema. AutoMigrate is intentionally // kept behind this package so the CLI migration and tests use the same model set. -func Migrate(db *gorm.DB) error { - return db.AutoMigrate( +// MigratedModels is the single source of truth for which models make up the +// schema, so tests can assert repo-wide conventions over exactly the set that +// Migrate creates rather than a hand-maintained copy that drifts. +func MigratedModels() []any { + return []any{ &models.AgentDevice{}, &models.PDDProduct{}, &models.ShopeeProduct{}, @@ -22,5 +25,9 @@ func Migrate(db *gorm.DB) error { &models.CollectionColorPrice{}, &models.CollectionSKU{}, &models.CollectionSKUValue{}, - ) + } +} + +func Migrate(db *gorm.DB) error { + return db.AutoMigrate(MigratedModels()...) } diff --git a/server/app/goauto/migrations/migrate_test.go b/server/app/goauto/migrations/migrate_test.go index 3fc8570..8de548d 100644 --- a/server/app/goauto/migrations/migrate_test.go +++ b/server/app/goauto/migrations/migrate_test.go @@ -359,3 +359,20 @@ func TestMySQLTextJSONBlobColumnsHaveNoLiteralDefault(t *testing.T) { } } } + +// 仓库约定:所有 GoAuto 模型显式声明单数表名。漏写 TableName() 时 gorm 会 +// 悄悄用复数(syb_session -> syb_sessions),迁移照样成功,直到有人按约定的 +// 名字写查询才会发现。这里对迁移清单里的每个模型逐一核对。 +func TestEveryModelDeclaresSingularTableName(t *testing.T) { + type tableNamer interface{ TableName() string } + for _, model := range migrations.MigratedModels() { + namer, ok := model.(tableNamer) + if !ok { + t.Fatalf("%T 没有声明 TableName(),gorm 会用复数表名", model) + } + name := namer.TableName() + if strings.HasSuffix(name, "s") && !strings.HasSuffix(name, "ss") { + t.Fatalf("%T 的表名 %q 像复数,仓库约定用单数", model, name) + } + } +} diff --git a/server/app/goauto/models/schema.go b/server/app/goauto/models/schema.go index 06aecbc..962a00c 100644 --- a/server/app/goauto/models/schema.go +++ b/server/app/goauto/models/schema.go @@ -380,6 +380,8 @@ type SYBProduct struct { func (SYBProduct) TableName() string { return "syb_product" } +func (SYBSession) TableName() string { return "syb_session" } + func (product *SYBProduct) BeforeCreate(_ *gorm.DB) error { if product.RawJSON == "" { product.RawJSON = "{}"