github.com/gogf/gf@v1.16.9/database/gdb/gdb_core_structure.go (about)

     1  // Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
     2  //
     3  // This Source Code Form is subject to the terms of the MIT License.
     4  // If a copy of the MIT was not distributed with this file,
     5  // You can obtain one at https://github.com/gogf/gf.
     6  
     7  package gdb
     8  
     9  import (
    10  	"strings"
    11  	"time"
    12  
    13  	"github.com/gogf/gf/util/gutil"
    14  
    15  	"github.com/gogf/gf/text/gstr"
    16  
    17  	"github.com/gogf/gf/os/gtime"
    18  
    19  	"github.com/gogf/gf/encoding/gbinary"
    20  
    21  	"github.com/gogf/gf/text/gregex"
    22  	"github.com/gogf/gf/util/gconv"
    23  )
    24  
    25  // convertFieldValueToLocalValue automatically checks and converts field value from database type
    26  // to golang variable type.
    27  func (c *Core) convertFieldValueToLocalValue(fieldValue interface{}, fieldType string) interface{} {
    28  	// If there's no type retrieved, it returns the `fieldValue` directly
    29  	// to use its original data type, as `fieldValue` is type of interface{}.
    30  	if fieldType == "" {
    31  		return fieldValue
    32  	}
    33  	t, _ := gregex.ReplaceString(`\(.+\)`, "", fieldType)
    34  	t = strings.ToLower(t)
    35  	switch t {
    36  	case
    37  		"binary",
    38  		"varbinary",
    39  		"blob",
    40  		"tinyblob",
    41  		"mediumblob",
    42  		"longblob":
    43  		return gconv.Bytes(fieldValue)
    44  
    45  	case
    46  		"int",
    47  		"tinyint",
    48  		"small_int",
    49  		"smallint",
    50  		"medium_int",
    51  		"mediumint",
    52  		"serial":
    53  		if gstr.ContainsI(fieldType, "unsigned") {
    54  			gconv.Uint(gconv.String(fieldValue))
    55  		}
    56  		return gconv.Int(gconv.String(fieldValue))
    57  
    58  	case
    59  		"int8", // For pgsql, int8 = bigint.
    60  		"big_int",
    61  		"bigint",
    62  		"bigserial":
    63  		if gstr.ContainsI(fieldType, "unsigned") {
    64  			gconv.Uint64(gconv.String(fieldValue))
    65  		}
    66  		return gconv.Int64(gconv.String(fieldValue))
    67  
    68  	case "real":
    69  		return gconv.Float32(gconv.String(fieldValue))
    70  
    71  	case
    72  		"float",
    73  		"double",
    74  		"decimal",
    75  		"money",
    76  		"numeric",
    77  		"smallmoney":
    78  		return gconv.Float64(gconv.String(fieldValue))
    79  
    80  	case "bit":
    81  		s := gconv.String(fieldValue)
    82  		// mssql is true|false string.
    83  		if strings.EqualFold(s, "true") {
    84  			return 1
    85  		}
    86  		if strings.EqualFold(s, "false") {
    87  			return 0
    88  		}
    89  		return gbinary.BeDecodeToInt64(gconv.Bytes(fieldValue))
    90  
    91  	case "bool":
    92  		return gconv.Bool(fieldValue)
    93  
    94  	case "date":
    95  		if t, ok := fieldValue.(time.Time); ok {
    96  			return gtime.NewFromTime(t).Format("Y-m-d")
    97  		}
    98  		t, _ := gtime.StrToTime(gconv.String(fieldValue))
    99  		return t.Format("Y-m-d")
   100  
   101  	case
   102  		"datetime",
   103  		"timestamp",
   104  		"timestamptz":
   105  		if t, ok := fieldValue.(time.Time); ok {
   106  			return gtime.NewFromTime(t)
   107  		}
   108  		t, _ := gtime.StrToTime(gconv.String(fieldValue))
   109  		return t.String()
   110  
   111  	default:
   112  		// Auto detect field type, using key match.
   113  		switch {
   114  		case strings.Contains(t, "text") || strings.Contains(t, "char") || strings.Contains(t, "character"):
   115  			return gconv.String(fieldValue)
   116  
   117  		case strings.Contains(t, "float") || strings.Contains(t, "double") || strings.Contains(t, "numeric"):
   118  			return gconv.Float64(gconv.String(fieldValue))
   119  
   120  		case strings.Contains(t, "bool"):
   121  			return gconv.Bool(gconv.String(fieldValue))
   122  
   123  		case strings.Contains(t, "binary") || strings.Contains(t, "blob"):
   124  			return fieldValue
   125  
   126  		case strings.Contains(t, "int"):
   127  			return gconv.Int(gconv.String(fieldValue))
   128  
   129  		case strings.Contains(t, "time"):
   130  			s := gconv.String(fieldValue)
   131  			t, err := gtime.StrToTime(s)
   132  			if err != nil {
   133  				return s
   134  			}
   135  			return t.String()
   136  
   137  		case strings.Contains(t, "date"):
   138  			s := gconv.String(fieldValue)
   139  			t, err := gtime.StrToTime(s)
   140  			if err != nil {
   141  				return s
   142  			}
   143  			return t.Format("Y-m-d")
   144  
   145  		default:
   146  			return gconv.String(fieldValue)
   147  		}
   148  	}
   149  }
   150  
   151  // mappingAndFilterData automatically mappings the map key to table field and removes
   152  // all key-value pairs that are not the field of given table.
   153  func (c *Core) mappingAndFilterData(schema, table string, data map[string]interface{}, filter bool) (map[string]interface{}, error) {
   154  	if fieldsMap, err := c.db.TableFields(c.GetCtx(), table, schema); err == nil {
   155  		fieldsKeyMap := make(map[string]interface{}, len(fieldsMap))
   156  		for k, _ := range fieldsMap {
   157  			fieldsKeyMap[k] = nil
   158  		}
   159  		// Automatic data key to table field name mapping.
   160  		var foundKey string
   161  		for dataKey, dataValue := range data {
   162  			if _, ok := fieldsKeyMap[dataKey]; !ok {
   163  				foundKey, _ = gutil.MapPossibleItemByKey(fieldsKeyMap, dataKey)
   164  				if foundKey != "" {
   165  					data[foundKey] = dataValue
   166  					delete(data, dataKey)
   167  				}
   168  			}
   169  		}
   170  		// Data filtering.
   171  		// It deletes all key-value pairs that has incorrect field name.
   172  		if filter {
   173  			for dataKey, _ := range data {
   174  				if _, ok := fieldsMap[dataKey]; !ok {
   175  					delete(data, dataKey)
   176  				}
   177  			}
   178  		}
   179  	}
   180  	return data, nil
   181  }
   182  
   183  //// filterFields removes all key-value pairs which are not the field of given table.
   184  //func (c *Core) filterFields(schema, table string, data map[string]interface{}) map[string]interface{} {
   185  //	// It must use data copy here to avoid its changing the origin data map.
   186  //	newDataMap := make(map[string]interface{}, len(data))
   187  //	if fields, err := c.db.TableFields(table, schema); err == nil {
   188  //		for k, v := range data {
   189  //			if _, ok := fields[k]; ok {
   190  //				newDataMap[k] = v
   191  //			}
   192  //		}
   193  //	}
   194  //	return newDataMap
   195  //}