package rest import ( "git.nspix.com/golang/rest/v3/inflector" "gorm.io/gorm" "reflect" "strconv" "strings" ) type ( //Dynamic 实现动态结构体的操作 Dynamic struct { moduleName string tableName string schemas []*Schema fields []reflect.StructField } Dialector struct { gorm.Dialector tableName string } Migrator struct { gorm.Migrator tableName string } ) func (d *Dialector) Migrator(db *gorm.DB) gorm.Migrator { migrator := d.Dialector.Migrator(db) if db.Statement != nil { db.Statement.Table = d.tableName } return newDynamicMigrator(d.tableName, migrator) } func (m *Migrator) HasTable(dst interface{}) bool { return m.Migrator.HasTable(m.tableName) } func newDynamicDialector(tableName string, dialector gorm.Dialector) *Dialector { return &Dialector{dialector, tableName} } func newDynamicMigrator(tableName string, migrator gorm.Migrator) *Migrator { mig := &Migrator{migrator, tableName} return mig } //Interface 返回结构体的实体结构 func (d *Dynamic) Interface() interface{} { refValue := reflect.New(d.Type()) return refValue.Interface() } //Type 返回结构体类型 func (d *Dynamic) Type() reflect.Type { reflectType := reflect.StructOf(d.fields) return reflectType } //Slice 返回结构体slice类型 func (d *Dynamic) Slice() reflect.Type { return reflect.SliceOf(d.Type()) } //Reset 重置表结构 func (d *Dynamic) Reset(schemas []*Schema) { d.fields = make([]reflect.StructField, 0, 10) d.schemas = schemas d.buildField(schemas) } //ModuleName 模块名称 func (d *Dynamic) ModuleName() string { return d.moduleName } //TableName 表名称 func (d *Dynamic) TableName() string { return d.tableName } //typeOfSchema 通过schema生成结构体的类型 func (d *Dynamic) typeOfSchema(schema *Schema) reflect.Type { switch schema.Type { case TypeBoolean: return reflect.TypeOf(uint8(0)) case TypeInteger: return reflect.TypeOf(int64(0)) case TypeFloat: return reflect.TypeOf(float64(0)) default: return reflect.TypeOf("") } } //tagOfSchema 通过schema生成结构体的tag func (d *Dynamic) tagOfSchema(schema *Schema) reflect.StructTag { var sb strings.Builder var tags = make(map[string][]string) tags["json"] = []string{schema.Column} tags["yaml"] = []string{schema.Column} gormPairs := make([]string, 0, 5) if schema.IsPrimaryKey == 1 { gormPairs = append(gormPairs, "primaryKey") } switch schema.Type { case TypeInteger, TypeFloat: gormPairs = append(gormPairs, "not null") if schema.IsPrimaryKey == 0 { gormPairs = append(gormPairs, "default:0") } case TypeBoolean: gormPairs = append(gormPairs, "not null") case TypeString: if schema.Rule.Max > 0 { gormPairs = append(gormPairs, "size:"+strconv.Itoa(schema.Rule.Max*2)) } else { gormPairs = append(gormPairs, "size:1024") } gormPairs = append(gormPairs, "not null") gormPairs = append(gormPairs, "default:''") } if schema.Rule.Unique { gormPairs = append(gormPairs, "unique") } gormPairs = append(gormPairs, "comment:"+schema.Label) tags["gorm"] = gormPairs for tag, pairs := range tags { sb.WriteString(tag + ":\"") sb.WriteString(strings.Join(pairs, ";")) sb.WriteString("\" ") } return reflect.StructTag(sb.String()) } //buildField 通过schema构建字段 func (d *Dynamic) buildField(schemas []*Schema) { for _, schema := range schemas { d.moduleName = schema.ModuleName d.tableName = schema.TableName field := reflect.StructField{ Name: inflector.Camelize(schema.Column), Type: d.typeOfSchema(schema), Tag: d.tagOfSchema(schema), } d.fields = append(d.fields, field) } } func NewDynamic(schemas []*Schema) *Dynamic { model := &Dynamic{} model.Reset(schemas) return model }