mirror of
https://gitee.com/johng/gf
synced 2026-06-06 16:21:40 +08:00
add interface DB.CheckLocalTypeForField for package gdb (#2059)
This commit is contained in:
2
.github/workflows/cli.yml
vendored
2
.github/workflows/cli.yml
vendored
@ -52,7 +52,7 @@ jobs:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
tag_name: ${{ github.ref }}
|
||||
release_name: GoFrame CLI Release ${{ github.ref }}
|
||||
release_name: GoFrame Release ${{ github.ref }}
|
||||
draft: false
|
||||
prerelease: false
|
||||
|
||||
|
||||
@ -34,6 +34,7 @@ func generateDo(ctx context.Context, db gdb.DB, tableNames, newTableNames []stri
|
||||
doFilePath = gfile.Join(doDirPath, gstr.CaseSnake(newTableName)+".go")
|
||||
structDefinition = generateStructDefinition(ctx, generateStructDefinitionInput{
|
||||
CGenDaoInternalInput: in,
|
||||
DB: db,
|
||||
StructName: gstr.CaseCamel(newTableName),
|
||||
FieldMap: fieldMap,
|
||||
IsDo: true,
|
||||
|
||||
@ -30,6 +30,7 @@ func generateEntity(ctx context.Context, db gdb.DB, tableNames, newTableNames []
|
||||
gstr.CaseCamel(newTableName),
|
||||
generateStructDefinition(ctx, generateStructDefinitionInput{
|
||||
CGenDaoInternalInput: in,
|
||||
DB: db,
|
||||
StructName: gstr.CaseCamel(newTableName),
|
||||
FieldMap: fieldMap,
|
||||
IsDo: false,
|
||||
|
||||
@ -14,20 +14,12 @@ import (
|
||||
|
||||
type generateStructDefinitionInput struct {
|
||||
CGenDaoInternalInput
|
||||
DB gdb.DB // Current DB.
|
||||
StructName string // Struct name.
|
||||
FieldMap map[string]*gdb.TableField // Table field map.
|
||||
IsDo bool // Is generating DTO struct.
|
||||
}
|
||||
|
||||
const (
|
||||
typeDate = "date"
|
||||
typeDatetime = "datetime"
|
||||
typeInt64Bytes = "int64-bytes"
|
||||
typeUint64Bytes = "uint64-bytes"
|
||||
typeJson = "json"
|
||||
typeJsonb = "jsonb"
|
||||
)
|
||||
|
||||
func generateStructDefinition(ctx context.Context, in generateStructDefinitionInput) string {
|
||||
buffer := bytes.NewBuffer(nil)
|
||||
array := make([][]string, len(in.FieldMap))
|
||||
@ -67,26 +59,26 @@ func generateStructFieldDefinition(
|
||||
typeName string
|
||||
jsonTag = getJsonTagFromCase(field.Name, in.JsonCase)
|
||||
)
|
||||
typeName, err = gdb.CheckValueForLocalType(ctx, field.Type, nil)
|
||||
typeName, err = in.DB.CheckLocalTypeForField(ctx, field.Type, nil)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
switch typeName {
|
||||
case typeDate, typeDatetime:
|
||||
case gdb.LocalTypeDate, gdb.LocalTypeDatetime:
|
||||
if in.StdTime {
|
||||
typeName = "time.Time"
|
||||
} else {
|
||||
typeName = "*gtime.Time"
|
||||
}
|
||||
|
||||
case typeInt64Bytes:
|
||||
case gdb.LocalTypeInt64Bytes:
|
||||
typeName = "int64"
|
||||
|
||||
case typeUint64Bytes:
|
||||
case gdb.LocalTypeUint64Bytes:
|
||||
typeName = "uint64"
|
||||
|
||||
// Special type handle.
|
||||
case typeJson, typeJsonb:
|
||||
case gdb.LocalTypeJson, gdb.LocalTypeJsonb:
|
||||
if in.GJsonSupport {
|
||||
typeName = "*gjson.Json"
|
||||
} else {
|
||||
|
||||
@ -121,6 +121,43 @@ func (d *Driver) GetChars() (charLeft string, charRight string) {
|
||||
return `"`, `"`
|
||||
}
|
||||
|
||||
// CheckLocalTypeForValue checks and returns corresponding local golang type for given db type.
|
||||
func (d *Driver) CheckLocalTypeForValue(ctx context.Context, fieldType string, fieldValue interface{}) (string, error) {
|
||||
var typeName string
|
||||
match, _ := gregex.MatchString(`(.+?)\((.+)\)`, fieldType)
|
||||
if len(match) == 3 {
|
||||
typeName = gstr.Trim(match[1])
|
||||
} else {
|
||||
typeName = fieldType
|
||||
}
|
||||
typeName = strings.ToLower(typeName)
|
||||
switch typeName {
|
||||
case
|
||||
// For pgsql, int2 = smallint.
|
||||
"int2",
|
||||
// For pgsql, int4 = integer
|
||||
"int4":
|
||||
return gdb.LocalTypeInt, nil
|
||||
|
||||
case
|
||||
// For pgsql, int8 = bigint
|
||||
"int8":
|
||||
return gdb.LocalTypeInt64, nil
|
||||
|
||||
case
|
||||
"_int2",
|
||||
"_int4":
|
||||
return gdb.LocalTypeIntSlice, nil
|
||||
|
||||
case
|
||||
"_int8":
|
||||
return gdb.LocalTypeInt64Slice, nil
|
||||
|
||||
default:
|
||||
return d.Core.CheckLocalTypeForField(ctx, fieldType, fieldValue)
|
||||
}
|
||||
}
|
||||
|
||||
// ConvertValueForLocal converts value to local Golang type of value according field type name from database.
|
||||
// The parameter `fieldType` is in lower case, like:
|
||||
// `float(5,2)`, `unsigned double(5,2)`, `decimal(10,2)`, `char(45)`, `varchar(100)`, etc.
|
||||
|
||||
@ -172,6 +172,7 @@ type DB interface {
|
||||
TableFields(ctx context.Context, table string, schema ...string) (map[string]*TableField, error) // See Core.TableFields.
|
||||
ConvertDataForRecord(ctx context.Context, data interface{}) (map[string]interface{}, error) // See Core.ConvertDataForRecord
|
||||
ConvertValueForLocal(ctx context.Context, fieldType string, fieldValue interface{}) (interface{}, error) // See Core.ConvertValueForLocal
|
||||
CheckLocalTypeForField(ctx context.Context, fieldType string, fieldValue interface{}) (string, error) // See Core.CheckLocalTypeForField
|
||||
FilteredLink() string // FilteredLink is used for filtering sensitive information in `Link` configuration before output it to tracing server.
|
||||
}
|
||||
|
||||
@ -312,6 +313,27 @@ const (
|
||||
SqlTypeStmtQueryRowContext = "DB.Statement.QueryRowContext"
|
||||
)
|
||||
|
||||
const (
|
||||
LocalTypeString = "string"
|
||||
LocalTypeDate = "date"
|
||||
LocalTypeDatetime = "datetime"
|
||||
LocalTypeInt = "int"
|
||||
LocalTypeUint = "uint"
|
||||
LocalTypeInt64 = "int64"
|
||||
LocalTypeUint64 = "uint64"
|
||||
LocalTypeIntSlice = "[]int"
|
||||
LocalTypeInt64Slice = "[]int64"
|
||||
LocalTypeUint64Slice = "[]uint64"
|
||||
LocalTypeInt64Bytes = "int64-bytes"
|
||||
LocalTypeUint64Bytes = "uint64-bytes"
|
||||
LocalTypeFloat32 = "float32"
|
||||
LocalTypeFloat64 = "float64"
|
||||
LocalTypeBytes = "[]byte"
|
||||
LocalTypeBool = "bool"
|
||||
LocalTypeJson = "json"
|
||||
LocalTypeJsonb = "jsonb"
|
||||
)
|
||||
|
||||
var (
|
||||
// instances is the management map for instances.
|
||||
instances = gmap.NewStrAnyMap(true)
|
||||
|
||||
@ -17,6 +17,8 @@ import (
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"github.com/gogf/gf/v2/internal/json"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
"github.com/gogf/gf/v2/text/gregex"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
"github.com/gogf/gf/v2/util/gutil"
|
||||
)
|
||||
@ -119,6 +121,133 @@ func (c *Core) ConvertDataForRecordValue(ctx context.Context, value interface{})
|
||||
return convertedValue, nil
|
||||
}
|
||||
|
||||
// CheckLocalTypeForField checks and returns corresponding type for given db type.
|
||||
func (c *Core) 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 = fieldType
|
||||
}
|
||||
typeName = strings.ToLower(typeName)
|
||||
switch typeName {
|
||||
case
|
||||
"binary",
|
||||
"varbinary",
|
||||
"blob",
|
||||
"tinyblob",
|
||||
"mediumblob",
|
||||
"longblob":
|
||||
return LocalTypeBytes, nil
|
||||
|
||||
case
|
||||
"int",
|
||||
"tinyint",
|
||||
"small_int",
|
||||
"smallint",
|
||||
"medium_int",
|
||||
"mediumint",
|
||||
"serial":
|
||||
if gstr.ContainsI(fieldType, "unsigned") {
|
||||
return LocalTypeUint, nil
|
||||
}
|
||||
return LocalTypeInt, nil
|
||||
|
||||
case
|
||||
"big_int",
|
||||
"bigint",
|
||||
"bigserial":
|
||||
if gstr.ContainsI(fieldType, "unsigned") {
|
||||
return LocalTypeUint64, nil
|
||||
}
|
||||
return LocalTypeInt64, nil
|
||||
|
||||
case
|
||||
"real":
|
||||
return LocalTypeFloat32, nil
|
||||
|
||||
case
|
||||
"float",
|
||||
"double",
|
||||
"decimal",
|
||||
"money",
|
||||
"numeric",
|
||||
"smallmoney":
|
||||
return LocalTypeFloat64, nil
|
||||
|
||||
case
|
||||
"bit":
|
||||
// It is suggested using bit(1) as boolean.
|
||||
if typePattern == "1" {
|
||||
return LocalTypeBool, nil
|
||||
}
|
||||
s := gconv.String(fieldValue)
|
||||
// mssql is true|false string.
|
||||
if strings.EqualFold(s, "true") || strings.EqualFold(s, "false") {
|
||||
return LocalTypeBool, nil
|
||||
}
|
||||
if gstr.ContainsI(fieldType, "unsigned") {
|
||||
return LocalTypeUint64Bytes, nil
|
||||
}
|
||||
return LocalTypeInt64Bytes, nil
|
||||
|
||||
case
|
||||
"bool":
|
||||
return LocalTypeBool, nil
|
||||
|
||||
case
|
||||
"date":
|
||||
return LocalTypeDate, nil
|
||||
|
||||
case
|
||||
"datetime",
|
||||
"timestamp",
|
||||
"timestamptz":
|
||||
return LocalTypeDatetime, nil
|
||||
|
||||
case
|
||||
"json":
|
||||
return LocalTypeJson, nil
|
||||
|
||||
case
|
||||
"jsonb":
|
||||
return 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 LocalTypeString, nil
|
||||
|
||||
case strings.Contains(typeName, "float") || strings.Contains(typeName, "double") || strings.Contains(typeName, "numeric"):
|
||||
return LocalTypeFloat64, nil
|
||||
|
||||
case strings.Contains(typeName, "bool"):
|
||||
return LocalTypeBool, nil
|
||||
|
||||
case strings.Contains(typeName, "binary") || strings.Contains(typeName, "blob"):
|
||||
return LocalTypeBytes, nil
|
||||
|
||||
case strings.Contains(typeName, "int"):
|
||||
return LocalTypeInt, nil
|
||||
|
||||
case strings.Contains(typeName, "time"):
|
||||
return LocalTypeDatetime, nil
|
||||
|
||||
case strings.Contains(typeName, "date"):
|
||||
return LocalTypeDatetime, nil
|
||||
|
||||
default:
|
||||
return LocalTypeString, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ConvertValueForLocal converts value to local Golang type of value according field type name from database.
|
||||
// The parameter `fieldType` is in lower case, like:
|
||||
// `float(5,2)`, `unsigned double(5,2)`, `decimal(10,2)`, `char(45)`, `varchar(100)`, etc.
|
||||
@ -128,42 +257,42 @@ func (c *Core) ConvertValueForLocal(ctx context.Context, fieldType string, field
|
||||
if fieldType == "" {
|
||||
return fieldValue, nil
|
||||
}
|
||||
typeName, err := CheckValueForLocalType(ctx, fieldType, fieldValue)
|
||||
typeName, err := c.db.CheckLocalTypeForField(ctx, fieldType, fieldValue)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch typeName {
|
||||
case typeBytes:
|
||||
case LocalTypeBytes:
|
||||
if strings.Contains(typeName, "binary") || strings.Contains(typeName, "blob") {
|
||||
return fieldValue, nil
|
||||
}
|
||||
return gconv.Bytes(fieldValue), nil
|
||||
|
||||
case typeInt:
|
||||
case LocalTypeInt:
|
||||
return gconv.Int(gconv.String(fieldValue)), nil
|
||||
|
||||
case typeUint:
|
||||
case LocalTypeUint:
|
||||
return gconv.Uint(gconv.String(fieldValue)), nil
|
||||
|
||||
case typeInt64:
|
||||
case LocalTypeInt64:
|
||||
return gconv.Int64(gconv.String(fieldValue)), nil
|
||||
|
||||
case typeUint64:
|
||||
case LocalTypeUint64:
|
||||
return gconv.Uint64(gconv.String(fieldValue)), nil
|
||||
|
||||
case typeInt64Bytes:
|
||||
case LocalTypeInt64Bytes:
|
||||
return gbinary.BeDecodeToInt64(gconv.Bytes(fieldValue)), nil
|
||||
|
||||
case typeUint64Bytes:
|
||||
case LocalTypeUint64Bytes:
|
||||
return gbinary.BeDecodeToUint64(gconv.Bytes(fieldValue)), nil
|
||||
|
||||
case typeFloat32:
|
||||
case LocalTypeFloat32:
|
||||
return gconv.Float32(gconv.String(fieldValue)), nil
|
||||
|
||||
case typeFloat64:
|
||||
case LocalTypeFloat64:
|
||||
return gconv.Float64(gconv.String(fieldValue)), nil
|
||||
|
||||
case typeBool:
|
||||
case LocalTypeBool:
|
||||
s := gconv.String(fieldValue)
|
||||
// mssql is true|false string.
|
||||
if strings.EqualFold(s, "true") {
|
||||
@ -174,7 +303,7 @@ func (c *Core) ConvertValueForLocal(ctx context.Context, fieldType string, field
|
||||
}
|
||||
return gconv.Bool(fieldValue), nil
|
||||
|
||||
case typeDate:
|
||||
case LocalTypeDate:
|
||||
// Date without time.
|
||||
if t, ok := fieldValue.(time.Time); ok {
|
||||
return gtime.NewFromTime(t).Format("Y-m-d"), nil
|
||||
@ -182,7 +311,7 @@ func (c *Core) ConvertValueForLocal(ctx context.Context, fieldType string, field
|
||||
t, _ := gtime.StrToTime(gconv.String(fieldValue))
|
||||
return t.Format("Y-m-d"), nil
|
||||
|
||||
case typeDatetime:
|
||||
case LocalTypeDatetime:
|
||||
if t, ok := fieldValue.(time.Time); ok {
|
||||
return gtime.NewFromTime(t), nil
|
||||
}
|
||||
|
||||
@ -1,167 +0,0 @@
|
||||
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
package gdb
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
"github.com/gogf/gf/v2/text/gregex"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
)
|
||||
|
||||
const (
|
||||
typeString = "string"
|
||||
typeDate = "date"
|
||||
typeDatetime = "datetime"
|
||||
typeInt = "int"
|
||||
typeUint = "uint"
|
||||
typeInt64 = "int64"
|
||||
typeUint64 = "uint64"
|
||||
typeIntSlice = "[]int"
|
||||
typeInt64Slice = "[]int64"
|
||||
typeUint64Slice = "[]uint64"
|
||||
typeInt64Bytes = "int64-bytes"
|
||||
typeUint64Bytes = "uint64-bytes"
|
||||
typeFloat32 = "float32"
|
||||
typeFloat64 = "float64"
|
||||
typeBytes = "[]byte"
|
||||
typeBool = "bool"
|
||||
typeJson = "json"
|
||||
typeJsonb = "jsonb"
|
||||
)
|
||||
|
||||
// CheckValueForLocalType checks and returns corresponding type for given db type.
|
||||
func CheckValueForLocalType(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 = fieldType
|
||||
}
|
||||
typeName = strings.ToLower(typeName)
|
||||
switch typeName {
|
||||
case
|
||||
"binary",
|
||||
"varbinary",
|
||||
"blob",
|
||||
"tinyblob",
|
||||
"mediumblob",
|
||||
"longblob":
|
||||
return typeBytes, nil
|
||||
|
||||
case
|
||||
"int2", // For pgsql, int2 = smallint.
|
||||
"int4", // For pgsql, int4 = integer.
|
||||
"int",
|
||||
"tinyint",
|
||||
"small_int",
|
||||
"smallint",
|
||||
"medium_int",
|
||||
"mediumint",
|
||||
"serial":
|
||||
if gstr.ContainsI(fieldType, "unsigned") {
|
||||
return typeUint, nil
|
||||
}
|
||||
return typeInt, nil
|
||||
|
||||
case
|
||||
"int8", // For pgsql, int8 = bigint.
|
||||
"big_int",
|
||||
"bigint",
|
||||
"bigserial":
|
||||
if gstr.ContainsI(fieldType, "unsigned") {
|
||||
return typeUint64, nil
|
||||
}
|
||||
return typeInt64, nil
|
||||
|
||||
case "_int2", "_int4":
|
||||
return typeIntSlice, nil
|
||||
|
||||
case "_int8":
|
||||
return typeInt64Slice, nil
|
||||
|
||||
case "real":
|
||||
return typeFloat32, nil
|
||||
|
||||
case
|
||||
"float",
|
||||
"double",
|
||||
"decimal",
|
||||
"money",
|
||||
"numeric",
|
||||
"smallmoney":
|
||||
return typeFloat64, nil
|
||||
|
||||
case "bit":
|
||||
// It is suggested using bit(1) as boolean.
|
||||
if typePattern == "1" {
|
||||
return typeBool, nil
|
||||
}
|
||||
s := gconv.String(fieldValue)
|
||||
// mssql is true|false string.
|
||||
if strings.EqualFold(s, "true") || strings.EqualFold(s, "false") {
|
||||
return typeBool, nil
|
||||
}
|
||||
if gstr.ContainsI(fieldType, "unsigned") {
|
||||
return typeUint64Bytes, nil
|
||||
}
|
||||
return typeInt64Bytes, nil
|
||||
|
||||
case "bool":
|
||||
return typeBool, nil
|
||||
|
||||
case "date":
|
||||
return typeDate, nil
|
||||
|
||||
case
|
||||
"datetime",
|
||||
"timestamp",
|
||||
"timestamptz":
|
||||
return typeDatetime, nil
|
||||
|
||||
case "json":
|
||||
return typeJson, nil
|
||||
|
||||
case "jsonb":
|
||||
return typeJsonb, nil
|
||||
|
||||
default:
|
||||
// Auto-detect field type, using key match.
|
||||
switch {
|
||||
case strings.Contains(typeName, "text") || strings.Contains(typeName, "char") || strings.Contains(typeName, "character"):
|
||||
return typeString, nil
|
||||
|
||||
case strings.Contains(typeName, "float") || strings.Contains(typeName, "double") || strings.Contains(typeName, "numeric"):
|
||||
return typeFloat64, nil
|
||||
|
||||
case strings.Contains(typeName, "bool"):
|
||||
return typeBool, nil
|
||||
|
||||
case strings.Contains(typeName, "binary") || strings.Contains(typeName, "blob"):
|
||||
return typeBytes, nil
|
||||
|
||||
case strings.Contains(typeName, "int"):
|
||||
return typeInt, nil
|
||||
|
||||
case strings.Contains(typeName, "time"):
|
||||
return typeDatetime, nil
|
||||
|
||||
case strings.Contains(typeName, "date"):
|
||||
return typeDatetime, nil
|
||||
|
||||
default:
|
||||
return typeString, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user