mirror of
https://github.com/go-admin-team/go-admin.git
synced 2026-09-23 02:40:56 +00:00
uk_sys_menu_app_seed_code_del covers (app_code, seed_code, deleted_at) and is created by 1786700008000 with explicit SQL. The struct tag named the same index on SeedCode alone, and a named uniqueIndex tag collects only the fields carrying that name - so AutoMigrate on this model would build a unique index on seed_code by itself: stricter than the real one, and forbidding two applications from both having a "dir" node, which the composite key exists to allow. Worse than being stricter, it would win. The migration only creates its index when HasIndex says the name is free, so a schema built by AutoMigrate first keeps the wrong index and the migration steps over it without a word. The tag cannot express the real index: deleted_at comes from the ModelTime embed shared by every table, which no single model can add a tag to. So the tag goes and the migration is the only thing that creates it. No database is affected. The initial table migration AutoMigrates a frozen snapshot of this model that has neither app_code nor seed_code, and nothing else in the repository AutoMigrates the live one - which is why this stayed invisible until a test built the schema from the live model and seeded two applications, and got a unique-constraint failure on a seed code they are supposed to be able to share.
50 lines
2.0 KiB
Go
50 lines
2.0 KiB
Go
package models
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/glebarez/sqlite"
|
|
"gorm.io/gorm"
|
|
"gorm.io/gorm/logger"
|
|
)
|
|
|
|
func ptr(s string) *string { return &s }
|
|
|
|
// uk_sys_menu_app_seed_code_del covers (app_code, seed_code, deleted_at) and
|
|
// is created by 1786700008000, not from a struct tag. It cannot come from a
|
|
// tag: a named uniqueIndex collects every field carrying that name, and
|
|
// deleted_at lives in the shared ModelTime embed that no single model can tag.
|
|
//
|
|
// Naming it on SeedCode alone anyway produced a unique index on seed_code by
|
|
// itself under the same name - stricter than the real one - and AutoMigrate
|
|
// here would create that one, after which the migration's HasIndex guard
|
|
// finds the name taken and leaves the wrong index in place. Nothing in
|
|
// production AutoMigrates this model (the initial table migration uses a
|
|
// frozen snapshot that has neither column), which is why this never showed up
|
|
// as a broken database; it showed up the first time a test built the schema
|
|
// from the live model and seeded two applications.
|
|
func TestSysMenuDeclaresNoSeedCodeIndexOfItsOwn(t *testing.T) {
|
|
db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{
|
|
Logger: logger.Default.LogMode(logger.Silent),
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("open: %v", err)
|
|
}
|
|
if err := db.AutoMigrate(&SysMenu{}); err != nil {
|
|
t.Fatalf("automigrate: %v", err)
|
|
}
|
|
if db.Migrator().HasIndex(&SysMenu{}, "uk_sys_menu_app_seed_code_del") {
|
|
t.Error("AutoMigrate created uk_sys_menu_app_seed_code_del from a tag; " +
|
|
"the migration's HasIndex guard will now skip the composite index it should create")
|
|
}
|
|
|
|
// Two applications, the same seed code. The real index allows it because
|
|
// app_code is part of the key; an index on seed_code alone does not.
|
|
for _, app := range []string{"order", "crm"} {
|
|
row := SysMenu{MenuName: app + "Dir", AppCode: app, SeedCode: ptr("dir")}
|
|
if err := db.Create(&row).Error; err != nil {
|
|
t.Fatalf("%s could not use the seed code \"dir\": %v", app, err)
|
|
}
|
|
}
|
|
}
|