mirror of
https://gitee.com/johng/gf
synced 2026-06-07 02:12:11 +08:00
This pull request standardizes the use of the Go 1.18+ `any` type alias
instead of `interface{}` throughout the codebase. The change improves
code readability and aligns with modern Go best practices. The update
touches many files, including core data structures, code generation
templates, logging utilities, and test data, ensuring consistency across
all usages.
**Type alias migration to `any`:**
* Replaced all instances of `interface{}` with `any` in core data
structures such as `garray` and in generated model structs (e.g.,
`TableUser`, `User1`, `User2`) to modernize type usage.
[[1]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L31-R31)
[[2]](diffhunk://#diff-6c19859cb32c7516ea95ddc8f8235460818eb2f24d2204308e0d9e1b19e7d90fL15-R19)
[[3]](diffhunk://#diff-a15ba2f5e830b4833c47b902515a4f9e5a4f83a3707698f3229b307ec3776b41L15-R18)
[[4]](diffhunk://#diff-52e0837e84d49221d1b810d88fdf78221f36cffcd664fb42f8aba49a79b974dcL15-R19)
[[5]](diffhunk://#diff-11c3457d1a23a4ca6ecd00d6b856289774936b6a708384cf03aff164044e7546L15-R19)
[[6]](diffhunk://#diff-2cff9cf8e6a0cc34087326d8c8149c3bbaf74c76fdbdf5a73daed13cc04249e1L15-R19)
* Updated function signatures, method parameters, and return types from
`interface{}` to `any` in various parts of the codebase, including code
generation, service logic, and logging utilities (e.g., `mlog`).
[[1]](diffhunk://#diff-175edfeea54490b8fe4e18ffcbea5835efaf8f0b8acf623359073987cae7eb76L48-R55)
[[2]](diffhunk://#diff-2b1953fb78cf3593d8c2c7d911e95b65fd0b847c30ed0b4d167d16fe6d781235L54-R74)
[[3]](diffhunk://#diff-e001b7a4b63603b9b14f00de78a4d570bb76c5f57d856a24643f071032e12356L66-R73)
[[4]](diffhunk://#diff-5582954e8a9983988dc8854ad82067fb2ac6269b988e07357ad8db1dfec5f1a0L39-R41)
[[5]](diffhunk://#diff-c5d51d56f487779a2b6207c7ad26c7a20bbadcc846ce094fe60ab4cabff58c51L107-R107)
[[6]](diffhunk://#diff-f96e6a9fdb416eb1804ceaba1fe0ac637bff22c43837f8bb849c2366ce72d4a1L116-R121)
[[7]](diffhunk://#diff-f94c83a1b08ae060d9346f4a6031fc4a7b9a0b894e02d9afaa09018b6598eac0L112-R112)
[[8]](diffhunk://#diff-748b11dbe8828dd4c040ec23cae0b8fe57ecf0a2d1b7694ea39102294e633c64L36-R36)
[[9]](diffhunk://#diff-748b11dbe8828dd4c040ec23cae0b8fe57ecf0a2d1b7694ea39102294e633c64L74-R74)
[[10]](diffhunk://#diff-748b11dbe8828dd4c040ec23cae0b8fe57ecf0a2d1b7694ea39102294e633c64L96-R96)
**Generated code and templates:**
* Adjusted generated files and code generation templates to output `any`
instead of `interface{}` for relevant struct fields and function
signatures, ensuring that new code generation aligns with the updated
convention.
[[1]](diffhunk://#diff-6c19859cb32c7516ea95ddc8f8235460818eb2f24d2204308e0d9e1b19e7d90fL15-R19)
[[2]](diffhunk://#diff-a15ba2f5e830b4833c47b902515a4f9e5a4f83a3707698f3229b307ec3776b41L15-R18)
[[3]](diffhunk://#diff-52e0837e84d49221d1b810d88fdf78221f36cffcd664fb42f8aba49a79b974dcL15-R19)
[[4]](diffhunk://#diff-11c3457d1a23a4ca6ecd00d6b856289774936b6a708384cf03aff164044e7546L15-R19)
[[5]](diffhunk://#diff-2cff9cf8e6a0cc34087326d8c8149c3bbaf74c76fdbdf5a73daed13cc04249e1L15-R19)
[[6]](diffhunk://#diff-175edfeea54490b8fe4e18ffcbea5835efaf8f0b8acf623359073987cae7eb76L48-R55)
[[7]](diffhunk://#diff-e001b7a4b63603b9b14f00de78a4d570bb76c5f57d856a24643f071032e12356L66-R73)
[[8]](diffhunk://#diff-5582954e8a9983988dc8854ad82067fb2ac6269b988e07357ad8db1dfec5f1a0L39-R41)
**Container and utility updates:**
* Refactored the `garray` container implementation and related
constructors/methods to use `[]any` instead of `[]interface{}`, along
with corresponding function signatures.
[[1]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L31-R31)
[[2]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L52-R52)
[[3]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L62-R62)
[[4]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L73-R86)
[[5]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L96-R97)
[[6]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L107-R114)
[[7]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L124-R124)
[[8]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L135-R143)
[[9]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L167-R167)
These changes collectively modernize the codebase and prepare it for
future Go developments by using the idiomatic `any` type.
513 lines
13 KiB
Go
513 lines
13 KiB
Go
// 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"
|
|
"database/sql/driver"
|
|
"math/big"
|
|
"reflect"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/gogf/gf/v2/encoding/gbinary"
|
|
"github.com/gogf/gf/v2/errors/gerror"
|
|
"github.com/gogf/gf/v2/internal/intlog"
|
|
"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"
|
|
)
|
|
|
|
// GetFieldTypeStr retrieves and returns the field type string for certain field by name.
|
|
func (c *Core) GetFieldTypeStr(ctx context.Context, fieldName, table, schema string) string {
|
|
field := c.GetFieldType(ctx, fieldName, table, schema)
|
|
if field != nil {
|
|
// Kinds of data type examples:
|
|
// year(4)
|
|
// datetime
|
|
// varchar(64)
|
|
// bigint(20)
|
|
// int(10) unsigned
|
|
typeName := gstr.StrTillEx(field.Type, "(") // int(10) unsigned -> int
|
|
if typeName != "" {
|
|
typeName = gstr.Trim(typeName)
|
|
} else {
|
|
typeName = field.Type
|
|
}
|
|
return typeName
|
|
}
|
|
return ""
|
|
}
|
|
|
|
// GetFieldType retrieves and returns the field type object for certain field by name.
|
|
func (c *Core) GetFieldType(ctx context.Context, fieldName, table, schema string) *TableField {
|
|
fieldsMap, err := c.db.TableFields(ctx, table, schema)
|
|
if err != nil {
|
|
intlog.Errorf(
|
|
ctx,
|
|
`TableFields failed for table "%s", schema "%s": %+v`,
|
|
table, schema, err,
|
|
)
|
|
return nil
|
|
}
|
|
for tableFieldName, tableField := range fieldsMap {
|
|
if tableFieldName == fieldName {
|
|
return tableField
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// ConvertDataForRecord is a very important function, which does converting for any data that
|
|
// will be inserted into table/collection as a record.
|
|
//
|
|
// The parameter `value` should be type of *map/map/*struct/struct.
|
|
// It supports embedded struct definition for struct.
|
|
func (c *Core) ConvertDataForRecord(ctx context.Context, value any, table string) (map[string]any, error) {
|
|
var (
|
|
err error
|
|
data = MapOrStructToMapDeep(value, true)
|
|
)
|
|
for fieldName, fieldValue := range data {
|
|
var fieldType = c.GetFieldTypeStr(ctx, fieldName, table, c.GetSchema())
|
|
data[fieldName], err = c.db.ConvertValueForField(
|
|
ctx,
|
|
fieldType,
|
|
fieldValue,
|
|
)
|
|
if err != nil {
|
|
return nil, gerror.Wrapf(err, `ConvertDataForRecord failed for value: %#v`, fieldValue)
|
|
}
|
|
}
|
|
return data, nil
|
|
}
|
|
|
|
// ConvertValueForField converts value to the type of the record field.
|
|
// The parameter `fieldType` is the target record field.
|
|
// The parameter `fieldValue` is the value that to be committed to record field.
|
|
func (c *Core) ConvertValueForField(ctx context.Context, fieldType string, fieldValue any) (any, error) {
|
|
var (
|
|
err error
|
|
convertedValue = fieldValue
|
|
)
|
|
switch fieldValue.(type) {
|
|
case time.Time, *time.Time, gtime.Time, *gtime.Time:
|
|
goto Default
|
|
}
|
|
// If `value` implements interface `driver.Valuer`, it then uses the interface for value converting.
|
|
if valuer, ok := fieldValue.(driver.Valuer); ok {
|
|
if convertedValue, err = valuer.Value(); err != nil {
|
|
return nil, err
|
|
}
|
|
return convertedValue, nil
|
|
}
|
|
Default:
|
|
// Default value converting.
|
|
var (
|
|
rvValue = reflect.ValueOf(fieldValue)
|
|
rvKind = rvValue.Kind()
|
|
)
|
|
for rvKind == reflect.Pointer {
|
|
rvValue = rvValue.Elem()
|
|
rvKind = rvValue.Kind()
|
|
}
|
|
switch rvKind {
|
|
case reflect.Invalid:
|
|
convertedValue = nil
|
|
|
|
case reflect.Slice, reflect.Array, reflect.Map:
|
|
// It should ignore the bytes type.
|
|
if _, ok := fieldValue.([]byte); !ok {
|
|
// Convert the value to JSON.
|
|
convertedValue, err = json.Marshal(fieldValue)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
case reflect.Struct:
|
|
switch r := fieldValue.(type) {
|
|
// If the time is zero, it then updates it to nil,
|
|
// which will insert/update the value to database as "null".
|
|
case time.Time:
|
|
if r.IsZero() {
|
|
convertedValue = nil
|
|
} else {
|
|
switch fieldType {
|
|
case fieldTypeYear:
|
|
convertedValue = r.Format("2006")
|
|
case fieldTypeDate:
|
|
convertedValue = r.Format("2006-01-02")
|
|
case fieldTypeTime:
|
|
convertedValue = r.Format("15:04:05")
|
|
default:
|
|
}
|
|
}
|
|
|
|
case *time.Time:
|
|
if r == nil {
|
|
// Nothing to do.
|
|
} else {
|
|
switch fieldType {
|
|
case fieldTypeYear:
|
|
convertedValue = r.Format("2006")
|
|
case fieldTypeDate:
|
|
convertedValue = r.Format("2006-01-02")
|
|
case fieldTypeTime:
|
|
convertedValue = r.Format("15:04:05")
|
|
default:
|
|
}
|
|
}
|
|
|
|
case gtime.Time:
|
|
if r.IsZero() {
|
|
convertedValue = nil
|
|
} else {
|
|
switch fieldType {
|
|
case fieldTypeYear:
|
|
convertedValue = r.Layout("2006")
|
|
case fieldTypeDate:
|
|
convertedValue = r.Layout("2006-01-02")
|
|
case fieldTypeTime:
|
|
convertedValue = r.Layout("15:04:05")
|
|
default:
|
|
convertedValue = r.Time
|
|
}
|
|
}
|
|
|
|
case *gtime.Time:
|
|
if r.IsZero() {
|
|
convertedValue = nil
|
|
} else {
|
|
switch fieldType {
|
|
case fieldTypeYear:
|
|
convertedValue = r.Layout("2006")
|
|
case fieldTypeDate:
|
|
convertedValue = r.Layout("2006-01-02")
|
|
case fieldTypeTime:
|
|
convertedValue = r.Layout("15:04:05")
|
|
default:
|
|
convertedValue = r.Time
|
|
}
|
|
}
|
|
|
|
case Counter, *Counter:
|
|
// Nothing to do.
|
|
|
|
default:
|
|
// If `value` implements interface iNil,
|
|
// check its IsNil() function, if got ture,
|
|
// which will insert/update the value to database as "null".
|
|
if v, ok := fieldValue.(iNil); ok && v.IsNil() {
|
|
convertedValue = nil
|
|
} else if s, ok := fieldValue.(iString); ok {
|
|
// Use string conversion in default.
|
|
convertedValue = s.String()
|
|
} else {
|
|
// Convert the value to JSON.
|
|
convertedValue, err = json.Marshal(fieldValue)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
}
|
|
default:
|
|
}
|
|
|
|
return convertedValue, nil
|
|
}
|
|
|
|
// GetFormattedDBTypeNameForField retrieves and returns the formatted database type name
|
|
// eg. `int(10) unsigned` -> `int`, `varchar(100)` -> `varchar`, etc.
|
|
func (c *Core) GetFormattedDBTypeNameForField(fieldType string) (typeName, typePattern string) {
|
|
match, _ := gregex.MatchString(`(.+?)\((.+)\)`, fieldType)
|
|
if len(match) == 3 {
|
|
typeName = gstr.Trim(match[1])
|
|
typePattern = gstr.Trim(match[2])
|
|
} else {
|
|
var array = gstr.SplitAndTrim(fieldType, " ")
|
|
if len(array) > 1 && gstr.Equal(array[0], "unsigned") {
|
|
typeName = array[1]
|
|
} else if len(array) > 0 {
|
|
typeName = array[0]
|
|
}
|
|
}
|
|
typeName = strings.ToLower(typeName)
|
|
return
|
|
}
|
|
|
|
// CheckLocalTypeForField checks and returns corresponding type for given db type.
|
|
// The `fieldType` is retrieved from ColumnTypes of db driver, example:
|
|
// UNSIGNED INT
|
|
func (c *Core) CheckLocalTypeForField(ctx context.Context, fieldType string, _ any) (LocalType, error) {
|
|
var (
|
|
typeName string
|
|
typePattern string
|
|
)
|
|
typeName, typePattern = c.GetFormattedDBTypeNameForField(fieldType)
|
|
switch typeName {
|
|
case
|
|
fieldTypeBinary,
|
|
fieldTypeVarbinary,
|
|
fieldTypeBlob,
|
|
fieldTypeTinyblob,
|
|
fieldTypeMediumblob,
|
|
fieldTypeLongblob:
|
|
return LocalTypeBytes, nil
|
|
|
|
case
|
|
fieldTypeInt,
|
|
fieldTypeTinyint,
|
|
fieldTypeSmallInt,
|
|
fieldTypeSmallint,
|
|
fieldTypeMediumInt,
|
|
fieldTypeMediumint,
|
|
fieldTypeSerial:
|
|
if gstr.ContainsI(fieldType, "unsigned") {
|
|
return LocalTypeUint, nil
|
|
}
|
|
return LocalTypeInt, nil
|
|
|
|
case
|
|
fieldTypeBigInt,
|
|
fieldTypeBigint,
|
|
fieldTypeBigserial:
|
|
if gstr.ContainsI(fieldType, "unsigned") {
|
|
return LocalTypeUint64, nil
|
|
}
|
|
return LocalTypeInt64, nil
|
|
|
|
case
|
|
fieldTypeInt128,
|
|
fieldTypeInt256,
|
|
fieldTypeUint128,
|
|
fieldTypeUint256:
|
|
return LocalTypeBigInt, nil
|
|
|
|
case
|
|
fieldTypeReal:
|
|
return LocalTypeFloat32, nil
|
|
|
|
case
|
|
fieldTypeDecimal,
|
|
fieldTypeMoney,
|
|
fieldTypeNumeric,
|
|
fieldTypeSmallmoney:
|
|
return LocalTypeString, nil
|
|
case
|
|
fieldTypeFloat,
|
|
fieldTypeDouble:
|
|
return LocalTypeFloat64, nil
|
|
|
|
case
|
|
fieldTypeBit:
|
|
// It is suggested using bit(1) as boolean.
|
|
if typePattern == "1" {
|
|
return LocalTypeBool, nil
|
|
}
|
|
if gstr.ContainsI(fieldType, "unsigned") {
|
|
return LocalTypeUint64Bytes, nil
|
|
}
|
|
return LocalTypeInt64Bytes, nil
|
|
|
|
case
|
|
fieldTypeBool:
|
|
return LocalTypeBool, nil
|
|
|
|
case
|
|
fieldTypeDate:
|
|
return LocalTypeDate, nil
|
|
|
|
case
|
|
fieldTypeTime:
|
|
return LocalTypeTime, nil
|
|
|
|
case
|
|
fieldTypeDatetime,
|
|
fieldTypeTimestamp,
|
|
fieldTypeTimestampz:
|
|
return LocalTypeDatetime, nil
|
|
|
|
case
|
|
fieldTypeJson:
|
|
return LocalTypeJson, nil
|
|
|
|
case
|
|
fieldTypeJsonb:
|
|
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"):
|
|
if gstr.ContainsI(fieldType, "unsigned") {
|
|
return LocalTypeUint, nil
|
|
}
|
|
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.
|
|
func (c *Core) ConvertValueForLocal(
|
|
ctx context.Context, fieldType string, fieldValue any,
|
|
) (any, error) {
|
|
// If there's no type retrieved, it returns the `fieldValue` directly
|
|
// to use its original data type, as `fieldValue` is type of any.
|
|
if fieldType == "" {
|
|
return fieldValue, nil
|
|
}
|
|
typeName, err := c.db.CheckLocalTypeForField(ctx, fieldType, fieldValue)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
switch typeName {
|
|
case LocalTypeBytes:
|
|
var typeNameStr = string(typeName)
|
|
if strings.Contains(typeNameStr, "binary") || strings.Contains(typeNameStr, "blob") {
|
|
return fieldValue, nil
|
|
}
|
|
return gconv.Bytes(fieldValue), nil
|
|
|
|
case LocalTypeInt:
|
|
return gconv.Int(gconv.String(fieldValue)), nil
|
|
|
|
case LocalTypeUint:
|
|
return gconv.Uint(gconv.String(fieldValue)), nil
|
|
|
|
case LocalTypeInt64:
|
|
return gconv.Int64(gconv.String(fieldValue)), nil
|
|
|
|
case LocalTypeUint64:
|
|
return gconv.Uint64(gconv.String(fieldValue)), nil
|
|
|
|
case LocalTypeInt64Bytes:
|
|
return gbinary.BeDecodeToInt64(gconv.Bytes(fieldValue)), nil
|
|
|
|
case LocalTypeUint64Bytes:
|
|
return gbinary.BeDecodeToUint64(gconv.Bytes(fieldValue)), nil
|
|
|
|
case LocalTypeBigInt:
|
|
switch v := fieldValue.(type) {
|
|
case big.Int:
|
|
return v.String(), nil
|
|
case *big.Int:
|
|
return v.String(), nil
|
|
default:
|
|
return gconv.String(fieldValue), nil
|
|
}
|
|
|
|
case LocalTypeFloat32:
|
|
return gconv.Float32(gconv.String(fieldValue)), nil
|
|
|
|
case LocalTypeFloat64:
|
|
return gconv.Float64(gconv.String(fieldValue)), nil
|
|
|
|
case LocalTypeBool:
|
|
s := gconv.String(fieldValue)
|
|
// mssql is true|false string.
|
|
if strings.EqualFold(s, "true") {
|
|
return 1, nil
|
|
}
|
|
if strings.EqualFold(s, "false") {
|
|
return 0, nil
|
|
}
|
|
return gconv.Bool(fieldValue), nil
|
|
|
|
case LocalTypeDate:
|
|
if t, ok := fieldValue.(time.Time); ok {
|
|
return gtime.NewFromTime(t).Format("Y-m-d"), nil
|
|
}
|
|
t, _ := gtime.StrToTime(gconv.String(fieldValue))
|
|
return t.Format("Y-m-d"), nil
|
|
|
|
case LocalTypeTime:
|
|
if t, ok := fieldValue.(time.Time); ok {
|
|
return gtime.NewFromTime(t).Format("H:i:s"), nil
|
|
}
|
|
t, _ := gtime.StrToTime(gconv.String(fieldValue))
|
|
return t.Format("H:i:s"), nil
|
|
|
|
case LocalTypeDatetime:
|
|
if t, ok := fieldValue.(time.Time); ok {
|
|
return gtime.NewFromTime(t), nil
|
|
}
|
|
t, _ := gtime.StrToTime(gconv.String(fieldValue))
|
|
return t, nil
|
|
|
|
default:
|
|
return gconv.String(fieldValue), nil
|
|
}
|
|
}
|
|
|
|
// mappingAndFilterData automatically mappings the map key to table field and removes
|
|
// all key-value pairs that are not the field of given table.
|
|
func (c *Core) mappingAndFilterData(ctx context.Context, schema, table string, data map[string]any, filter bool) (map[string]any, error) {
|
|
fieldsMap, err := c.db.TableFields(ctx, c.guessPrimaryTableName(table), schema)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if len(fieldsMap) == 0 {
|
|
return nil, gerror.Newf(`The table %s may not exist, or the table contains no fields`, table)
|
|
}
|
|
fieldsKeyMap := make(map[string]any, len(fieldsMap))
|
|
for k := range fieldsMap {
|
|
fieldsKeyMap[k] = nil
|
|
}
|
|
// Automatic data key to table field name mapping.
|
|
var foundKey string
|
|
for dataKey, dataValue := range data {
|
|
if _, ok := fieldsKeyMap[dataKey]; !ok {
|
|
foundKey, _ = gutil.MapPossibleItemByKey(fieldsKeyMap, dataKey)
|
|
if foundKey != "" {
|
|
if _, ok = data[foundKey]; !ok {
|
|
data[foundKey] = dataValue
|
|
}
|
|
delete(data, dataKey)
|
|
}
|
|
}
|
|
}
|
|
// Data filtering.
|
|
// It deletes all key-value pairs that has incorrect field name.
|
|
if filter {
|
|
for dataKey := range data {
|
|
if _, ok := fieldsMap[dataKey]; !ok {
|
|
delete(data, dataKey)
|
|
}
|
|
}
|
|
if len(data) == 0 {
|
|
return nil, gerror.Newf(`input data match no fields in table %s`, table)
|
|
}
|
|
}
|
|
return data, nil
|
|
}
|