hotgo/server/internal/library/hggen/views/column.go

263 lines
6.4 KiB
Go

// Package views
// @Link https://github.com/bufanyun/hotgo
// @Copyright Copyright (c) 2022 HotGo CLI
// @Author Ms <133814250@qq.com>
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
//
package views
import (
"context"
"fmt"
"github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/text/gregex"
"github.com/gogf/gf/v2/text/gstr"
"github.com/gogf/gf/v2/util/gconv"
"hotgo/internal/library/hggen/internal/cmd/gendao"
"hotgo/internal/model/input/sysin"
"strings"
)
// DoTableColumns 获取指定表生成字段列表
func DoTableColumns(ctx context.Context, in sysin.GenCodesColumnListInp, config gendao.CGenDaoInput) (fields []*sysin.GenCodesColumnListModel, err error) {
var (
sql = "select ORDINAL_POSITION as `id`, COLUMN_NAME as `name`, COLUMN_COMMENT as `dc`, DATA_TYPE as `dataType`, COLUMN_TYPE as `sqlType`, CHARACTER_MAXIMUM_LENGTH as `length`, IS_NULLABLE as `isAllowNull`, COLUMN_DEFAULT as `defaultValue`, COLUMN_KEY as `index`, EXTRA as `extra` from information_schema.COLUMNS where TABLE_SCHEMA = '%s' and TABLE_NAME = '%s' ORDER BY `id` ASC"
conf = g.DB(in.Name).GetConfig()
)
err = g.DB(in.Name).Ctx(ctx).Raw(fmt.Sprintf(sql, conf.Name, in.Table)).Scan(&fields)
if err != nil {
return nil, err
}
if len(fields) == 0 {
return
}
for _, field := range fields {
if in.IsLink == 1 {
CustomLinkAttributes(ctx, in.Alias, field, config)
} else {
CustomAttributes(ctx, field, config)
}
}
return
}
// CustomLinkAttributes 可自定义关联表的字段属性
func CustomLinkAttributes(ctx context.Context, alias string, field *sysin.GenCodesColumnListModel, in gendao.CGenDaoInput) {
field.GoName, field.GoType, field.TsName, field.TsType = GenGotype(ctx, field, in)
field.GoName = gstr.UcFirst(alias + field.GoName)
field.TsName = gstr.LcFirst(field.GoName)
setDefaultQueryWhere(field)
setDefaultValue(field)
}
// CustomAttributes 可自定义的字段属性
func CustomAttributes(ctx context.Context, field *sysin.GenCodesColumnListModel, in gendao.CGenDaoInput) {
field.GoName, field.GoType, field.TsName, field.TsType = GenGotype(ctx, field, in)
setDefault(field)
}
// GenGotype 生成字段的go类型
func GenGotype(ctx context.Context, field *sysin.GenCodesColumnListModel, in gendao.CGenDaoInput) (goName, typeName, tsName, tsType string) {
var (
err error
)
tsName = getJsonTagFromCase(field.Name, in.JsonCase)
goName = gstr.CaseCamel(field.Name)
typeName, err = CheckLocalTypeForField(ctx, field.DataType, nil)
if err != nil {
panic(err)
}
switch typeName {
case gdb.LocalTypeDate, gdb.LocalTypeDatetime:
if in.StdTime {
typeName = "time.Time"
} else {
typeName = "*gtime.Time"
}
case gdb.LocalTypeInt64Bytes:
typeName = "int64"
case gdb.LocalTypeUint64Bytes:
typeName = "uint64"
// Special type handle.
case gdb.LocalTypeJson, gdb.LocalTypeJsonb:
if in.GJsonSupport {
typeName = "*gjson.Json"
} else {
typeName = "string"
}
}
tsType = ShiftMap[typeName]
return
}
// CheckLocalTypeForField checks and returns corresponding type for given db type.
func CheckLocalTypeForField(ctx context.Context, fieldType string, fieldValue interface{}) (string, error) {
var (
typeName string
typePattern string
)
match, _ := gregex.MatchString(`(.+?)\((.+)\)`, fieldType)
if len(match) == 3 {
typeName = gstr.Trim(match[1])
typePattern = gstr.Trim(match[2])
} else {
typeName = gstr.Split(fieldType, " ")[0]
}
typeName = strings.ToLower(typeName)
switch typeName {
case
"binary",
"varbinary",
"blob",
"tinyblob",
"mediumblob",
"longblob":
return gdb.LocalTypeBytes, nil
case
"int",
"tinyint",
"small_int",
"smallint",
"medium_int",
"mediumint",
"serial":
if gstr.ContainsI(fieldType, "unsigned") {
return gdb.LocalTypeUint, nil
}
return gdb.LocalTypeInt, nil
case
"big_int",
"bigint",
"bigserial":
if gstr.ContainsI(fieldType, "unsigned") {
return gdb.LocalTypeUint64, nil
}
return gdb.LocalTypeInt64, nil
case
"real":
return gdb.LocalTypeFloat32, nil
case
"float",
"double",
"decimal",
"money",
"numeric",
"smallmoney":
return gdb.LocalTypeFloat64, nil
case
"bit":
// It is suggested using bit(1) as boolean.
if typePattern == "1" {
return gdb.LocalTypeBool, nil
}
s := gconv.String(fieldValue)
// mssql is true|false string.
if strings.EqualFold(s, "true") || strings.EqualFold(s, "false") {
return gdb.LocalTypeBool, nil
}
if gstr.ContainsI(fieldType, "unsigned") {
return gdb.LocalTypeUint64Bytes, nil
}
return gdb.LocalTypeInt64Bytes, nil
case
"bool":
return gdb.LocalTypeBool, nil
case
"date":
return gdb.LocalTypeDate, nil
case
"datetime",
"timestamp",
"timestamptz":
return gdb.LocalTypeDatetime, nil
case
"json":
return gdb.LocalTypeJson, nil
case
"jsonb":
return gdb.LocalTypeJsonb, nil
default:
// Auto-detect field type, using key match.
switch {
case strings.Contains(typeName, "text") || strings.Contains(typeName, "char") || strings.Contains(typeName, "character"):
return gdb.LocalTypeString, nil
case strings.Contains(typeName, "float") || strings.Contains(typeName, "double") || strings.Contains(typeName, "numeric"):
return gdb.LocalTypeFloat64, nil
case strings.Contains(typeName, "bool"):
return gdb.LocalTypeBool, nil
case strings.Contains(typeName, "binary") || strings.Contains(typeName, "blob"):
return gdb.LocalTypeBytes, nil
case strings.Contains(typeName, "int"):
if gstr.ContainsI(fieldType, "unsigned") {
return gdb.LocalTypeUint, nil
}
return gdb.LocalTypeInt, nil
case strings.Contains(typeName, "time"):
return gdb.LocalTypeDatetime, nil
case strings.Contains(typeName, "date"):
return gdb.LocalTypeDatetime, nil
default:
return gdb.LocalTypeString, nil
}
}
}
// getJsonTagFromCase call gstr.Case* function to convert the s to specified case.
func getJsonTagFromCase(str, caseStr string) string {
switch gstr.ToLower(caseStr) {
case gstr.ToLower("Camel"):
return gstr.CaseCamel(str)
case gstr.ToLower("CamelLower"):
return gstr.CaseCamelLower(str)
case gstr.ToLower("Kebab"):
return gstr.CaseKebab(str)
case gstr.ToLower("KebabScreaming"):
return gstr.CaseKebabScreaming(str)
case gstr.ToLower("Snake"):
return gstr.CaseSnake(str)
case gstr.ToLower("SnakeFirstUpper"):
return gstr.CaseSnakeFirstUpper(str)
case gstr.ToLower("SnakeScreaming"):
return gstr.CaseSnakeScreaming(str)
}
return str
}