mirror of
https://github.com/go-admin-team/go-admin.git
synced 2026-09-20 17:57:54 +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.
81 lines
3.8 KiB
Go
81 lines
3.8 KiB
Go
package models
|
|
|
|
import "go-admin/common/models"
|
|
|
|
type SysMenu struct {
|
|
MenuId int `json:"menuId" gorm:"primaryKey;autoIncrement"`
|
|
MenuName string `json:"menuName" gorm:"size:128;"`
|
|
Title string `json:"title" gorm:"size:128;"`
|
|
Icon string `json:"icon" gorm:"size:128;"`
|
|
Path string `json:"path" gorm:"size:128;"`
|
|
Paths string `json:"paths" gorm:"size:128;"`
|
|
MenuType string `json:"menuType" gorm:"size:1;"`
|
|
Action string `json:"action" gorm:"size:16;"`
|
|
Permission string `json:"permission" gorm:"size:255;"`
|
|
ParentId int `json:"parentId" gorm:"size:11;"`
|
|
NoCache bool `json:"noCache" gorm:"size:8;"`
|
|
Breadcrumb string `json:"breadcrumb" gorm:"size:255;"`
|
|
Component string `json:"component" gorm:"size:255;"`
|
|
Sort int `json:"sort" gorm:"size:4;"`
|
|
Visible string `json:"visible" gorm:"size:1;"`
|
|
IsFrame string `json:"isFrame" gorm:"size:1;DEFAULT:0;"`
|
|
SysApi []SysApi `json:"sysApi" gorm:"many2many:sys_menu_api_rule"`
|
|
Apis []int `json:"apis" gorm:"-"`
|
|
DataScope string `json:"dataScope" gorm:"-"`
|
|
Params string `json:"params" gorm:"-"`
|
|
RoleId int `gorm:"-"`
|
|
Children []SysMenu `json:"children,omitempty" gorm:"-"`
|
|
IsSelect bool `json:"is_select" gorm:"-"`
|
|
// AppCode identifies which application's seed.SeedMenus call wrote this
|
|
// row; empty for the host's own built-in menus. NOT NULL DEFAULT '' for
|
|
// the same reason sys_migration.app_code is (see contract/models.Migration):
|
|
// AutoMigrate adding this column to an existing table leaves every
|
|
// pre-existing row reading back as "" rather than NULL.
|
|
AppCode string `json:"appCode" gorm:"type:varchar(64);not null;default:'';index:idx_sys_menu_app_code;comment:AppCode"`
|
|
// SeedCode is the raw seed.MenuSpec.Code this row was created from, kept
|
|
// so seedMenuTree can ask "did I already write this node" without
|
|
// relying on MenuName's PascalCase concatenation, which is not
|
|
// injective (see design doc §1.6). Nullable, unlike AppCode: every row
|
|
// seed.SeedMenus writes sets a real value, but every pre-existing row -
|
|
// the host's own hand-placed menus, and every app-seeded row written
|
|
// before this column existed - has none, and there is no way to
|
|
// backfill one that means anything. NULL is what lets an unbounded
|
|
// number of those coexist under the same app_code without tripping the
|
|
// unique index below: the database never treats two NULLs as equal, so
|
|
// only rows that do carry a real code participate in the uniqueness
|
|
// check at all.
|
|
// uk_sys_menu_app_seed_code_del is created by the migration, not from
|
|
// this tag, and deliberately: it covers (app_code, seed_code,
|
|
// deleted_at), and this struct cannot say so. A named uniqueIndex tag
|
|
// puts every field carrying that name into one index, and deleted_at
|
|
// comes from the shared ModelTime embed, which no single model can add a
|
|
// tag to. Naming it here anyway declared a unique index on seed_code
|
|
// alone under the same name - stricter than the real one, forbidding two
|
|
// applications from both having a "dir" node - and AutoMigrate on this
|
|
// model would have created that one first, after which the migration's
|
|
// HasIndex guard finds the name taken and leaves the wrong index in
|
|
// place.
|
|
SeedCode *string `json:"seedCode" gorm:"size:64;comment:raw MenuSpec.Code, null for rows not written through SeedMenus"`
|
|
models.ControlBy
|
|
models.ModelTime
|
|
}
|
|
|
|
type SysMenuSlice []SysMenu
|
|
|
|
func (x SysMenuSlice) Len() int { return len(x) }
|
|
func (x SysMenuSlice) Less(i, j int) bool { return x[i].Sort < x[j].Sort }
|
|
func (x SysMenuSlice) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
|
|
|
|
func (*SysMenu) TableName() string {
|
|
return "sys_menu"
|
|
}
|
|
|
|
func (e *SysMenu) Generate() models.ActiveRecord {
|
|
o := *e
|
|
return &o
|
|
}
|
|
|
|
func (e *SysMenu) GetId() interface{} {
|
|
return e.MenuId
|
|
}
|