contracts/base/res_field.go

267 lines
6.9 KiB
Go

package base
import (
"encoding/json"
"fmt"
"reflect"
"strconv"
"strings"
"git.fsdpf.net/go/contracts"
"git.fsdpf.net/go/contracts/res_type"
"git.fsdpf.net/go/db"
"git.fsdpf.net/go/db/schema"
"github.com/google/uuid"
"github.com/spf13/cast"
)
// 资源字段
type ResField struct {
Uuid string `db:"uuid"`
Name string `db:"name"`
Code string `db:"code"`
CodeResource string `db:"codeResource"`
DataType contracts.ResDataType `db:"table_type"`
Length string `db:"length"`
Comment string `db:"comment"`
Default string `db:"default"`
}
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 contracts.ResDataType_String, contracts.ResDataType_Text, contracts.ResDataType_Enum,
contracts.ResDataType_Timestamp, contracts.ResDataType_Date, contracts.ResDataType_Datetime:
typ = reflect.TypeOf(string(""))
case contracts.ResDataType_Integer, contracts.ResDataType_SmallInteger:
typ = reflect.TypeOf(res_type.ResFieldByInteger(0))
case contracts.ResDataType_Decimal:
typ = reflect.TypeOf(float64(0))
case contracts.ResDataType_Boolean:
typ = reflect.TypeOf(true)
case contracts.ResDataType_Json:
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) 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() contracts.ResDataType {
return this.DataType
}
func (this ResField) GetQueryDataType() contracts.QueryDataType {
switch this.GetDataType() {
case contracts.ResDataType_Enum,
contracts.ResDataType_Timestamp, contracts.ResDataType_Date,
contracts.ResDataType_Datetime, contracts.ResDataType_String,
contracts.ResDataType_Text:
return contracts.QueryDataType_String
case contracts.ResDataType_Integer, contracts.ResDataType_SmallInteger:
return contracts.QueryDataType_Integer
case contracts.ResDataType_Decimal:
return contracts.QueryDataType_Float
case contracts.ResDataType_Boolean:
return contracts.QueryDataType_Bool
case contracts.ResDataType_Json:
if this.Default != "" && this.Default[0:1] == "[" {
return contracts.QueryDataType_Array
}
return contracts.QueryDataType_Json
}
return contracts.QueryDataType_String
}
func (this ResField) ToValue(v any) any {
switch this.DataType {
case contracts.ResDataType_String, contracts.ResDataType_Text, contracts.ResDataType_Enum,
contracts.ResDataType_Timestamp, contracts.ResDataType_Date, contracts.ResDataType_Datetime:
return strings.Trim(cast.ToString(v), " ")
case contracts.ResDataType_Integer, contracts.ResDataType_SmallInteger:
return cast.ToInt(v)
case contracts.ResDataType_Decimal:
return strings.Trim(cast.ToString(v), " ")
case contracts.ResDataType_Boolean:
if v, _ := strconv.ParseBool(fmt.Sprintf("%v", v)); v {
return 1
}
return 0
case contracts.ResDataType_Json:
if v == nil {
if this.Default != "" && this.Default[0:1] == "[" {
return db.Raw("'[]'")
} else if this.Default != "" && this.Default[0:1] == "{" {
return db.Raw("'{}'")
} else if this.Default == "" {
return db.Raw("'{}'")
}
return this.Default
}
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 strings.Trim(cast.ToString(v), " ")
}
func (this ResField) GetRawDefault(driver string) db.Expression {
if this.DataType == contracts.ResDataType_Json {
if this.Default != "" && this.Default[0:1] == "[" {
return db.Raw("'[]'")
} else if this.Default != "" && this.Default[0:1] == "{" {
return db.Raw("'{}'")
} else if this.Default == "" {
return db.Raw("'{}'")
}
} else if this.DataType == contracts.ResDataType_Boolean {
if v, _ := strconv.ParseBool(this.Default); v {
return db.Raw("'1'")
}
return db.Raw("'0'")
}
if len(this.Default) > 4 && strings.ToLower(this.Default[0:4]) == "sql:" {
sql := strings.ToLower(this.Default[4:])
if sql == "uuid()" {
if driver == "sqlite" {
return db.Raw("'" + uuid.NewString() + "'")
}
return db.Raw("uuid()")
}
return db.Raw(sql)
}
if this.Default == "" {
if this.GetDataType() == contracts.ResDataType_Date || this.GetDataType() == contracts.ResDataType_Datetime {
return db.Raw("NULL")
}
return db.Raw("''")
}
if strings.ToUpper(this.Default) == "CURRENT_TIMESTAMP" {
return db.Raw(this.Default)
}
return db.Raw("'" + this.Default + "'")
}
func (this ResField) ToBlueprint(table *schema.Blueprint) (temp *schema.ColumnDefinition) {
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":
if this.DataType == "date" {
temp = table.Date(this.Code)
} else {
temp = table.DateTime(this.Code)
}
if strings.ToUpper(this.Default) == "CURRENT_TIMESTAMP" {
def = db.Raw(this.Default)
} 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
}
if isNull {
temp.Nullable()
} else {
temp.Default(def)
}
temp.Comment(comment)
return temp
}
func (this ResField) ToQueryField(t contracts.QueryDataType, alias string, options int) contracts.QueryField {
o := &QueryField{
ResField: this,
typ: t,
alias: alias,
}
return o.SetOptions(options)
}