package base import ( "encoding/json" "fmt" "reflect" "strconv" "strings" "git.fsdpf.net/go/db" "git.fsdpf.net/go/db/schema" "git.fsdpf.net/go/req" "github.com/spf13/cast" ) // ResField 资源字段 type ResField struct { Uuid string `db:"uuid" json:"uuid"` Name string `db:"name" json:"name"` Code string `db:"code" json:"code"` CodeResource string `db:"codeResource" json:"codeResource"` DataType req.ResDataType `db:"data_type" json:"data_type"` Length string `db:"length" json:"length"` Comment string `db:"comment" json:"comment"` Default string `db:"default" json:"default"` Virtual bool `db:"virtual" json:"virtual"` VirtualExpr string `db:"virtual_expr" json:"virtual_expr"` } func (this ResField) ToStructField(tags ...string) reflect.StructField { var typ reflect.Type fCode := this.Code fTag := `db:"` + fCode + `" json:"` + fCode + `"` if len(tags) > 0 { fTag = strings.Join(tags, " ") + " " + fTag } switch this.DataType { case req.ResString, req.ResText, req.ResEnum, req.ResTimestamp, req.ResDate, req.ResDatetime: typ = reflect.TypeOf(string("")) case req.ResInteger, req.ResSmallInteger: typ = reflect.TypeOf(int64(0)) case req.ResDecimal: typ = reflect.TypeOf(float64(0)) case req.ResBoolean: typ = reflect.TypeOf(true) case req.ResJson: if this.Default != "" && this.Default[0:1] == "[" { typ = reflect.TypeOf([]any{}) } else { typ = reflect.TypeOf(map[string]any{}) } } return reflect.StructField{ Name: strings.ToUpper(fCode[:1]) + fCode[1:], Tag: reflect.StructTag(fTag), Type: typ, } } func (this ResField) IsVirtual() bool { return this.Virtual } func (this ResField) GetCode() string { return this.Code } func (this ResField) GetCodeResource() string { return this.CodeResource } func (this ResField) GetName() string { return this.Name } func (this ResField) GetDataType() req.ResDataType { return this.DataType } func (this ResField) GetQueryDataType() req.RouteParamType { switch this.GetDataType() { case req.ResEnum, req.ResTimestamp, req.ResDate, req.ResDatetime, req.ResString, req.ResText: return req.ReqString case req.ResInteger, req.ResSmallInteger: return req.ReqInteger case req.ResDecimal: return req.ReqFloat case req.ResBoolean: return req.ReqBool case req.ResJson: if this.Default != "" && this.Default[0:1] == "[" { return req.ReqArray } return req.ReqJson } return req.ReqString } func (this ResField) ToValue(v any) any { if this.DataType == req.ResJson { if v == nil { if this.Default != "" && this.Default[0:1] == "[" { return db.V("[]") } else if this.Default != "" && this.Default[0:1] == "{" { return db.V("{}") } else if this.Default == "" { return db.V("{}") } return this.GetRawDefault() } if str, ok := v.(string); ok { return str } else if raw, ok := v.(db.Expression); ok { return raw } else if b, err := json.Marshal(v); err == nil { return string(b) } else { panic(fmt.Sprintf("%s, 类型转换错误, %s", this.Code, err)) } } return v } func (this ResField) GetRawDefault() db.Expression { if this.DataType == req.ResJson { if this.Default != "" && this.Default[0:1] == "[" { return db.V("[]") } else if this.Default != "" && this.Default[0:1] == "{" { return db.V("{}") } else if this.Default == "" { return db.V("{}") } } else if this.DataType == req.ResBoolean { if v, _ := strconv.ParseBool(this.Default); v { return db.V(true) } return db.V(false) } if len(this.Default) > 4 && strings.ToLower(this.Default[0:4]) == "sql:" { return db.L(this.Default[4:]) } if this.Default == "" { if this.GetDataType() == req.ResDate || this.GetDataType() == req.ResDatetime { return db.V(nil) } return db.V("") } if strings.ToUpper(this.Default) == "CURRENT_TIMESTAMP" { return db.L(this.Default) } return db.V(this.Default) } func (this ResField) ToBlueprint(table *schema.Blueprint) (temp *schema.ColumnDefinition) { switch this.Code { case "id": return table.BigIncrements("id").AutoIncrement().Comment("ID") case "enabled": return table.Boolean("enabled").Default("1").Comment("是否有效") case "created_user": return table.Char("created_user", 36).Default("00000000-0000-0000-0000-000000000000").Comment("创建者") case "owned_user": return table.Char("owned_user", 36).Default("00000000-0000-0000-0000-000000000000").Comment("拥有者") case "created_at": return table.Timestamp("created_at").UseCurrent().Comment("创建时间") case "updated_at": return table.Timestamp("updated_at").UseCurrent().Default(db.L("ON UPDATE CURRENT_TIMESTAMP")).Comment("更新时间") case "deleted_at": return table.DateTime("deleted_at").Nullable().Comment("删除时间") } isNull := false comment := this.Name def := any(this.Default) if this.Comment != "" { comment += " [ " + strings.Trim(this.Comment, `' "`) + " ]" } switch this.DataType { case "string": len := 255 if v, err := strconv.Atoi(strings.Trim(this.Length, `' "`)); err == nil { len = v } temp = table.String(this.Code, len) case "smallInteger": // integer 默认长度 4 temp = table.SmallInteger(this.Code) case "boolean": // integer 默认长度 1 temp = table.Boolean(this.Code) case "integer": // integer 默认长度 11 temp = table.Integer(this.Code) case "date", "dateTime", "timestamp": if this.DataType == "date" { temp = table.Date(this.Code) } else { temp = table.DateTime(this.Code) } if strings.ToUpper(this.Default) == "SQL:CURRENT_TIMESTAMP" { def = db.L("CURRENT_TIMESTAMP") } else if def == "" { isNull = true } case "decimal": allowed := strings.SplitN(this.Length, ",", 2) total := 8 places := 2 if v, err := strconv.Atoi(strings.Trim(allowed[0], `' "`)); err == nil { total = v } if v, err := strconv.Atoi(strings.Trim(allowed[1], `' "`)); err == nil { places = v } temp = table.Decimal(this.Code, total, places) case "enum": allowed := []string{} for _, v := range strings.Split(this.Length, ",") { allowed = append(allowed, strings.Trim(v, `' "`)) } temp = table.Enum(this.Code, allowed) case "json": temp = table.Json(this.Code) isNull = true case "text": temp = table.Text(this.Code) isNull = true case "vector": temp = table.Vector(this.Code, cast.ToInt(this.Length)) isNull = false default: panic(fmt.Sprintf("Unknown type: %s", this.DataType)) } if this.IsVirtual() { temp.VirtualAs(this.VirtualExpr) } if isNull { temp.Nullable() } else { temp.Default(def) } temp.Comment(comment) return temp } func (this ResField) ToQueryField(t req.RouteParamType, alias string, options byte) req.QueryField { o := &QueryField{ ResField: this, typ: t, alias: alias, } return o.SetOptions(options) }