2021-01-03 23:44:44 +08:00
|
|
|
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
|
2019-01-14 22:55:43 +08:00
|
|
|
//
|
|
|
|
// 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,
|
2019-02-02 16:18:25 +08:00
|
|
|
// You can obtain one at https://github.com/gogf/gf.
|
2019-01-14 22:55:43 +08:00
|
|
|
|
|
|
|
package gdb
|
|
|
|
|
|
|
|
import (
|
2019-07-11 15:41:06 +08:00
|
|
|
"strings"
|
2020-08-21 23:41:12 +08:00
|
|
|
"time"
|
2019-07-11 15:41:06 +08:00
|
|
|
|
2021-05-21 13:25:53 +08:00
|
|
|
"github.com/gogf/gf/util/gutil"
|
|
|
|
|
2019-09-03 00:06:24 +08:00
|
|
|
"github.com/gogf/gf/text/gstr"
|
|
|
|
|
2019-09-02 15:48:25 +08:00
|
|
|
"github.com/gogf/gf/os/gtime"
|
|
|
|
|
2019-07-29 21:01:19 +08:00
|
|
|
"github.com/gogf/gf/encoding/gbinary"
|
2019-07-11 18:58:31 +08:00
|
|
|
|
2019-07-29 21:01:19 +08:00
|
|
|
"github.com/gogf/gf/text/gregex"
|
|
|
|
"github.com/gogf/gf/util/gconv"
|
2019-01-14 22:55:43 +08:00
|
|
|
)
|
|
|
|
|
2020-11-29 23:47:57 +08:00
|
|
|
// convertFieldValueToLocalValue automatically checks and converts field value from database type
|
2019-12-17 21:06:34 +08:00
|
|
|
// to golang variable type.
|
2020-11-29 23:47:57 +08:00
|
|
|
func (c *Core) convertFieldValueToLocalValue(fieldValue interface{}, fieldType string) interface{} {
|
2021-02-08 17:57:21 +08:00
|
|
|
// If there's no type retrieved, it returns the `fieldValue` directly
|
|
|
|
// to use its original data type, as `fieldValue` is type of interface{}.
|
2020-07-23 21:01:16 +08:00
|
|
|
if fieldType == "" {
|
|
|
|
return fieldValue
|
|
|
|
}
|
2019-06-19 09:06:52 +08:00
|
|
|
t, _ := gregex.ReplaceString(`\(.+\)`, "", fieldType)
|
|
|
|
t = strings.ToLower(t)
|
|
|
|
switch t {
|
2020-05-14 21:15:44 +08:00
|
|
|
case
|
|
|
|
"binary",
|
|
|
|
"varbinary",
|
|
|
|
"blob",
|
|
|
|
"tinyblob",
|
|
|
|
"mediumblob",
|
|
|
|
"longblob":
|
2020-07-28 20:31:50 +08:00
|
|
|
return gconv.Bytes(fieldValue)
|
2019-01-14 22:55:43 +08:00
|
|
|
|
2020-05-14 21:15:44 +08:00
|
|
|
case
|
|
|
|
"int",
|
|
|
|
"tinyint",
|
|
|
|
"small_int",
|
|
|
|
"smallint",
|
|
|
|
"medium_int",
|
|
|
|
"mediumint",
|
2020-06-06 14:38:05 +08:00
|
|
|
"serial":
|
2019-09-03 00:06:24 +08:00
|
|
|
if gstr.ContainsI(fieldType, "unsigned") {
|
2020-07-28 20:31:50 +08:00
|
|
|
gconv.Uint(gconv.String(fieldValue))
|
2019-09-03 00:06:24 +08:00
|
|
|
}
|
2020-07-28 20:31:50 +08:00
|
|
|
return gconv.Int(gconv.String(fieldValue))
|
2019-01-14 22:55:43 +08:00
|
|
|
|
2020-05-14 21:15:44 +08:00
|
|
|
case
|
2021-01-03 23:44:44 +08:00
|
|
|
"int8", // For pgsql, int8 = bigint.
|
2020-05-14 21:15:44 +08:00
|
|
|
"big_int",
|
|
|
|
"bigint",
|
2020-05-29 15:41:37 +08:00
|
|
|
"bigserial":
|
2019-09-03 00:06:24 +08:00
|
|
|
if gstr.ContainsI(fieldType, "unsigned") {
|
2020-07-28 20:31:50 +08:00
|
|
|
gconv.Uint64(gconv.String(fieldValue))
|
2019-09-03 00:06:24 +08:00
|
|
|
}
|
2020-07-28 20:31:50 +08:00
|
|
|
return gconv.Int64(gconv.String(fieldValue))
|
2019-01-14 22:55:43 +08:00
|
|
|
|
2020-05-14 21:15:44 +08:00
|
|
|
case "real":
|
2020-07-28 20:31:50 +08:00
|
|
|
return gconv.Float32(gconv.String(fieldValue))
|
2020-05-14 21:15:44 +08:00
|
|
|
|
|
|
|
case
|
|
|
|
"float",
|
|
|
|
"double",
|
|
|
|
"decimal",
|
2020-05-29 15:41:37 +08:00
|
|
|
"money",
|
2020-06-06 14:38:05 +08:00
|
|
|
"numeric",
|
|
|
|
"smallmoney":
|
2020-07-28 20:31:50 +08:00
|
|
|
return gconv.Float64(gconv.String(fieldValue))
|
2019-01-14 22:55:43 +08:00
|
|
|
|
2019-07-11 18:58:31 +08:00
|
|
|
case "bit":
|
2020-07-28 20:31:50 +08:00
|
|
|
s := gconv.String(fieldValue)
|
2019-10-28 16:42:30 +08:00
|
|
|
// mssql is true|false string.
|
2019-07-11 18:58:31 +08:00
|
|
|
if strings.EqualFold(s, "true") {
|
|
|
|
return 1
|
|
|
|
}
|
|
|
|
if strings.EqualFold(s, "false") {
|
|
|
|
return 0
|
|
|
|
}
|
2020-07-28 20:31:50 +08:00
|
|
|
return gbinary.BeDecodeToInt64(gconv.Bytes(fieldValue))
|
2019-07-11 18:58:31 +08:00
|
|
|
|
|
|
|
case "bool":
|
2019-06-19 09:06:52 +08:00
|
|
|
return gconv.Bool(fieldValue)
|
2019-01-14 22:55:43 +08:00
|
|
|
|
2019-10-28 16:42:30 +08:00
|
|
|
case "date":
|
2020-08-21 23:41:12 +08:00
|
|
|
if t, ok := fieldValue.(time.Time); ok {
|
|
|
|
return gtime.NewFromTime(t).Format("Y-m-d")
|
|
|
|
}
|
2020-07-28 20:31:50 +08:00
|
|
|
t, _ := gtime.StrToTime(gconv.String(fieldValue))
|
2019-10-28 16:42:30 +08:00
|
|
|
return t.Format("Y-m-d")
|
|
|
|
|
2020-05-14 21:15:44 +08:00
|
|
|
case
|
|
|
|
"datetime",
|
2021-05-24 13:30:04 +08:00
|
|
|
"timestamp",
|
|
|
|
"timestamptz":
|
2020-08-21 23:41:12 +08:00
|
|
|
if t, ok := fieldValue.(time.Time); ok {
|
|
|
|
return gtime.NewFromTime(t)
|
|
|
|
}
|
2020-07-28 20:31:50 +08:00
|
|
|
t, _ := gtime.StrToTime(gconv.String(fieldValue))
|
2019-08-14 22:44:57 +08:00
|
|
|
return t.String()
|
|
|
|
|
2019-06-19 09:06:52 +08:00
|
|
|
default:
|
2019-10-28 16:42:30 +08:00
|
|
|
// Auto detect field type, using key match.
|
2019-06-19 09:06:52 +08:00
|
|
|
switch {
|
2020-05-14 21:15:44 +08:00
|
|
|
case strings.Contains(t, "text") || strings.Contains(t, "char") || strings.Contains(t, "character"):
|
2020-07-28 20:31:50 +08:00
|
|
|
return gconv.String(fieldValue)
|
2019-01-14 22:55:43 +08:00
|
|
|
|
2020-05-14 21:15:44 +08:00
|
|
|
case strings.Contains(t, "float") || strings.Contains(t, "double") || strings.Contains(t, "numeric"):
|
2020-07-28 20:31:50 +08:00
|
|
|
return gconv.Float64(gconv.String(fieldValue))
|
2019-01-14 22:55:43 +08:00
|
|
|
|
2019-06-19 09:06:52 +08:00
|
|
|
case strings.Contains(t, "bool"):
|
2020-07-28 20:31:50 +08:00
|
|
|
return gconv.Bool(gconv.String(fieldValue))
|
2019-01-14 22:55:43 +08:00
|
|
|
|
2019-06-19 09:06:52 +08:00
|
|
|
case strings.Contains(t, "binary") || strings.Contains(t, "blob"):
|
2019-07-22 15:10:40 +08:00
|
|
|
return fieldValue
|
2019-01-14 22:55:43 +08:00
|
|
|
|
2019-10-28 16:42:30 +08:00
|
|
|
case strings.Contains(t, "int"):
|
2020-07-28 20:31:50 +08:00
|
|
|
return gconv.Int(gconv.String(fieldValue))
|
2019-10-28 16:42:30 +08:00
|
|
|
|
|
|
|
case strings.Contains(t, "time"):
|
2020-07-28 20:31:50 +08:00
|
|
|
s := gconv.String(fieldValue)
|
2020-01-15 21:23:40 +08:00
|
|
|
t, err := gtime.StrToTime(s)
|
|
|
|
if err != nil {
|
|
|
|
return s
|
|
|
|
}
|
2019-10-28 16:42:30 +08:00
|
|
|
return t.String()
|
|
|
|
|
|
|
|
case strings.Contains(t, "date"):
|
2020-07-28 20:31:50 +08:00
|
|
|
s := gconv.String(fieldValue)
|
2020-01-15 21:23:40 +08:00
|
|
|
t, err := gtime.StrToTime(s)
|
|
|
|
if err != nil {
|
|
|
|
return s
|
|
|
|
}
|
2019-10-28 16:42:30 +08:00
|
|
|
return t.Format("Y-m-d")
|
|
|
|
|
2019-06-19 09:06:52 +08:00
|
|
|
default:
|
2020-07-28 20:31:50 +08:00
|
|
|
return gconv.String(fieldValue)
|
2019-06-19 09:06:52 +08:00
|
|
|
}
|
|
|
|
}
|
2019-01-14 22:55:43 +08:00
|
|
|
}
|
|
|
|
|
2020-11-29 23:47:57 +08:00
|
|
|
// mappingAndFilterData automatically mappings the map key to table field and removes
|
|
|
|
// all key-value pairs that are not the field of given table.
|
2020-10-17 18:16:13 +08:00
|
|
|
func (c *Core) mappingAndFilterData(schema, table string, data map[string]interface{}, filter bool) (map[string]interface{}, error) {
|
2021-05-21 13:25:53 +08:00
|
|
|
if fieldsMap, err := c.db.TableFields(c.GetCtx(), nil, table, schema); err == nil {
|
2020-10-17 18:16:13 +08:00
|
|
|
fieldsKeyMap := make(map[string]interface{}, 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 != "" {
|
|
|
|
data[foundKey] = dataValue
|
|
|
|
delete(data, dataKey)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Data filtering.
|
2021-01-04 19:46:46 +08:00
|
|
|
// It deletes all key-value pairs that has incorrect field name.
|
2020-10-17 18:16:13 +08:00
|
|
|
if filter {
|
|
|
|
for dataKey, _ := range data {
|
|
|
|
if _, ok := fieldsMap[dataKey]; !ok {
|
|
|
|
delete(data, dataKey)
|
|
|
|
}
|
2019-06-19 09:06:52 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-10-17 18:16:13 +08:00
|
|
|
return data, nil
|
2019-01-14 22:55:43 +08:00
|
|
|
}
|
2020-10-17 18:16:13 +08:00
|
|
|
|
|
|
|
//// filterFields removes all key-value pairs which are not the field of given table.
|
|
|
|
//func (c *Core) filterFields(schema, table string, data map[string]interface{}) map[string]interface{} {
|
|
|
|
// // It must use data copy here to avoid its changing the origin data map.
|
|
|
|
// newDataMap := make(map[string]interface{}, len(data))
|
2021-02-08 17:57:21 +08:00
|
|
|
// if fields, err := c.db.TableFields(table, schema); err == nil {
|
2020-10-17 18:16:13 +08:00
|
|
|
// for k, v := range data {
|
|
|
|
// if _, ok := fields[k]; ok {
|
|
|
|
// newDataMap[k] = v
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
// return newDataMap
|
|
|
|
//}
|