2023-04-12 16:56:55 +08:00
|
|
|
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"
|
2023-04-12 19:50:25 +08:00
|
|
|
"github.com/google/uuid"
|
|
|
|
"github.com/spf13/cast"
|
2023-04-12 16:56:55 +08:00
|
|
|
)
|
|
|
|
|
|
|
|
// 资源字段
|
|
|
|
type ResField struct {
|
2023-04-12 19:53:45 +08:00
|
|
|
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"`
|
2023-04-12 16:56:55 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
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:
|
2023-06-23 00:10:24 +08:00
|
|
|
typ = reflect.TypeOf(string(""))
|
2023-04-12 16:56:55 +08:00
|
|
|
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(res_type.ResFieldByAnys{})
|
|
|
|
} else {
|
2023-06-23 00:10:24 +08:00
|
|
|
typ = reflect.TypeOf(map[string]any{})
|
2023-04-12 16:56:55 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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 {
|
|
|
|
// 类型转换, 填补 cast 未知的类型
|
|
|
|
switch data := v.(type) {
|
|
|
|
case res_type.ResFieldByInteger:
|
|
|
|
v = int64(data)
|
|
|
|
case res_type.ResFieldByFloat:
|
|
|
|
v = float64(data)
|
|
|
|
case res_type.ResFieldByNumber:
|
|
|
|
v = float64(data)
|
2023-06-23 00:10:24 +08:00
|
|
|
case string:
|
2023-04-12 16:56:55 +08:00
|
|
|
v = strings.Trim(string(data), " ")
|
2023-06-23 00:12:10 +08:00
|
|
|
case []any, []string, []int, []float64, []float32, []int64:
|
2023-04-12 16:56:55 +08:00
|
|
|
if v != nil {
|
|
|
|
b, _ := json.Marshal(v)
|
|
|
|
return string(b)
|
|
|
|
}
|
2023-06-23 00:12:10 +08:00
|
|
|
v = data
|
|
|
|
case map[string]any, map[string]string, map[string]int:
|
2023-04-12 16:56:55 +08:00
|
|
|
if v != nil {
|
|
|
|
b, _ := json.Marshal(v)
|
|
|
|
return string(b)
|
|
|
|
}
|
|
|
|
v = data
|
2023-06-23 00:12:10 +08:00
|
|
|
default:
|
2023-04-12 16:56:55 +08:00
|
|
|
if v != nil {
|
|
|
|
b, _ := json.Marshal(v)
|
|
|
|
return string(b)
|
|
|
|
}
|
|
|
|
v = data
|
|
|
|
}
|
|
|
|
|
|
|
|
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:
|
2023-07-30 16:44:50 +08:00
|
|
|
if v, _ := strconv.ParseBool(fmt.Sprintf("%v", v)); v {
|
|
|
|
return 1
|
|
|
|
}
|
|
|
|
return 0
|
2023-04-12 16:56:55 +08:00
|
|
|
case contracts.ResDataType_Json:
|
|
|
|
if v == nil {
|
|
|
|
if this.Default != "" && this.Default[0:1] == "[" {
|
|
|
|
return "[]"
|
|
|
|
} else if this.Default != "" && this.Default[0:1] == "{" {
|
|
|
|
return "{}"
|
|
|
|
} else if this.Default == "" {
|
|
|
|
return "{}"
|
|
|
|
}
|
|
|
|
|
|
|
|
return this.Default
|
|
|
|
}
|
|
|
|
b, _ := json.Marshal(v)
|
|
|
|
return string(b)
|
|
|
|
}
|
|
|
|
|
|
|
|
return strings.Trim(cast.ToString(v), " ")
|
|
|
|
}
|
|
|
|
|
|
|
|
func (this ResField) GetRawDefault(driver string) db.Expression {
|
|
|
|
if this.DataType == "json" && this.Default == "" {
|
|
|
|
return db.Raw("'{}'")
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(this.Default) > 4 && strings.ToLower(this.Default[0:4]) == "sql:" {
|
|
|
|
sql := strings.ToLower(this.Default[4:])
|
|
|
|
if sql == "uuid()" {
|
2023-04-12 19:50:25 +08:00
|
|
|
if driver == "sqlite" {
|
|
|
|
return db.Raw("'" + uuid.NewString() + "'")
|
|
|
|
}
|
|
|
|
return db.Raw("uuid()")
|
2023-04-12 16:56:55 +08:00
|
|
|
}
|
|
|
|
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
|
|
|
|
}
|
2023-04-22 01:49:03 +08:00
|
|
|
|
|
|
|
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)
|
|
|
|
}
|