fix(#48): give SYBSession an explicit singular table name
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 <noreply@anthropic.com>
This commit is contained in:
@@ -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()...)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 = "{}"
|
||||
|
||||
Reference in New Issue
Block a user