From e31163038e6a237aa3ff3782562e35f3c99c655e Mon Sep 17 00:00:00 2001 From: John Guo Date: Fri, 28 Feb 2025 12:17:24 +0800 Subject: [PATCH] up --- contrib/drivers/mysql/db_utils_test.go | 169 ------------------ .../drivers/mysql/mysql_z_unit_issue_test.go | 37 +++- util/gconv/gconv_basic.go | 7 +- util/gconv/gconv_float.go | 5 +- util/gconv/gconv_int.go | 3 +- util/gconv/gconv_slice_any.go | 11 +- util/gconv/gconv_slice_float.go | 19 +- util/gconv/gconv_slice_int.go | 27 ++- util/gconv/gconv_slice_str.go | 11 +- util/gconv/gconv_slice_uint.go | 27 ++- util/gconv/gconv_time.go | 3 +- util/gconv/gconv_uint.go | 11 +- 12 files changed, 133 insertions(+), 197 deletions(-) delete mode 100644 contrib/drivers/mysql/db_utils_test.go diff --git a/contrib/drivers/mysql/db_utils_test.go b/contrib/drivers/mysql/db_utils_test.go deleted file mode 100644 index 04fa21eb7..000000000 --- a/contrib/drivers/mysql/db_utils_test.go +++ /dev/null @@ -1,169 +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 mysql_test - -import ( - "database/sql" - "fmt" - "reflect" - "strings" - "testing" - - "github.com/gogf/gf/v2/test/gtest" -) - -// DBConfig represents database configuration -type DBConfig struct { - Username string - Password string - Host string - DBName string -} - -// QueryAndScan executes a query and scans the results into a slice of struct pointers -// Parameters: -// - query: SQL query string -// - args: Query arguments -// - dest: Pointer to slice of struct pointers where results will be stored -// -// Returns error if any occurs during the process -func QueryAndScan(config DBConfig, query string, args []interface{}, dest interface{}) error { - // Validate input parameters - destValue := reflect.ValueOf(dest) - if destValue.Kind() != reflect.Ptr || destValue.Elem().Kind() != reflect.Slice { - return fmt.Errorf("dest must be a pointer to slice") - } - - // Connect to database - dsn := fmt.Sprintf("%s:%s@tcp(%s)/%s?parseTime=true", - config.Username, - config.Password, - config.Host, - config.DBName, - ) - - db, err := sql.Open("mysql", dsn) - if err != nil { - return fmt.Errorf("failed to connect to database: %v", err) - } - defer db.Close() - - // Execute query - rows, err := db.Query(query, args...) - if err != nil { - return fmt.Errorf("failed to execute query: %v", err) - } - defer rows.Close() - - // Get column names - columns, err := rows.Columns() - if err != nil { - return fmt.Errorf("failed to get column names: %v", err) - } - - // Get the type of slice elements - sliceType := destValue.Elem().Type() - elementType := sliceType.Elem() - if elementType.Kind() == reflect.Ptr { - elementType = elementType.Elem() - } - - // Create a map of field names to struct fields - fieldMap := make(map[string]int) - for i := 0; i < elementType.NumField(); i++ { - field := elementType.Field(i) - // Check orm tag first, then json tag, then field name - tagName := field.Tag.Get("orm") - if tagName == "" { - tagName = field.Tag.Get("json") - } - if tagName == "" { - tagName = strings.ToLower(field.Name) - } - fieldMap[tagName] = i - } - - // Prepare slice to store results - sliceValue := destValue.Elem() - - // Scan rows - for rows.Next() { - // Create a new struct instance - newElem := reflect.New(elementType) - - // Create scan destinations that point directly to struct fields - scanDest := make([]interface{}, len(columns)) - for i, colName := range columns { - if fieldIndex, ok := fieldMap[colName]; ok { - field := newElem.Elem().Field(fieldIndex) - if field.CanAddr() { - scanDest[i] = field.Addr().Interface() - } else { - // For fields that can't be addressed, use a temporary variable - var v interface{} - scanDest[i] = &v - } - } else { - // Column doesn't map to any field, use a placeholder - var v interface{} - scanDest[i] = &v - } - } - - // Scan the row directly into struct fields - if err := rows.Scan(scanDest...); err != nil { - return fmt.Errorf("failed to scan row: %v", err) - } - - // Append the new element to the result slice - if sliceType.Elem().Kind() == reflect.Ptr { - sliceValue.Set(reflect.Append(sliceValue, newElem)) - } else { - sliceValue.Set(reflect.Append(sliceValue, newElem.Elem())) - } - } - - // Check for errors from iterating over rows - if err := rows.Err(); err != nil { - return fmt.Errorf("error iterating over rows: %v", err) - } - - return nil -} - -func Test_Issue4086_2(t *testing.T) { - config := DBConfig{ - Username: "root", - Password: "12345678", - Host: "127.0.0.1", - DBName: "test1", - } - gtest.C(t, func(t *gtest.T) { - type ProxyParam struct { - ProxyId int64 `json:"proxyId" orm:"proxy_id"` - RecommendIds []int64 `json:"recommendIds" orm:"recommend_ids"` - Photos []string `json:"photos" orm:"photos"` - } - - var proxyParamList []*ProxyParam - - err := QueryAndScan(config, "SELECT * FROM issue4086", nil, &proxyParamList) - fmt.Println(err) - t.Assert(proxyParamList, []*ProxyParam{ - { - ProxyId: 1, - RecommendIds: []int64{584, 585}, - Photos: nil, - }, - { - ProxyId: 2, - RecommendIds: []int64{}, - Photos: nil, - }, - }) - }) -} diff --git a/contrib/drivers/mysql/mysql_z_unit_issue_test.go b/contrib/drivers/mysql/mysql_z_unit_issue_test.go index 5abc11ab2..7f7f0a854 100644 --- a/contrib/drivers/mysql/mysql_z_unit_issue_test.go +++ b/contrib/drivers/mysql/mysql_z_unit_issue_test.go @@ -1719,9 +1719,9 @@ func Test_Issue4086(t *testing.T) { gtest.C(t, func(t *gtest.T) { type ProxyParam struct { - ProxyId int64 `json:"proxyId" orm:"proxy_id"` - RecommendIds []int64 `json:"recommendIds" orm:"recommend_ids"` - Photos []string `json:"photos" orm:"photos"` + ProxyId int64 `json:"proxyId" orm:"proxy_id"` + RecommendIds []int64 `json:"recommendIds" orm:"recommend_ids"` + Photos []int64 `json:"photos" orm:"photos"` } var proxyParamList []*ProxyParam @@ -1744,9 +1744,34 @@ func Test_Issue4086(t *testing.T) { gtest.C(t, func(t *gtest.T) { type ProxyParam struct { - ProxyId int64 `json:"proxyId" orm:"proxy_id"` - RecommendIds []int64 `json:"recommendIds" orm:"recommend_ids"` - Photos []int64 `json:"photos" orm:"photos"` + ProxyId int64 `json:"proxyId" orm:"proxy_id"` + RecommendIds []int64 `json:"recommendIds" orm:"recommend_ids"` + Photos []float32 `json:"photos" orm:"photos"` + } + + var proxyParamList []*ProxyParam + err := db.Model(table).Ctx(ctx).Scan(&proxyParamList) + t.AssertNil(err) + t.Assert(len(proxyParamList), 2) + t.Assert(proxyParamList, []*ProxyParam{ + { + ProxyId: 1, + RecommendIds: []int64{584, 585}, + Photos: nil, + }, + { + ProxyId: 2, + RecommendIds: []int64{}, + Photos: nil, + }, + }) + }) + + gtest.C(t, func(t *gtest.T) { + type ProxyParam struct { + ProxyId int64 `json:"proxyId" orm:"proxy_id"` + RecommendIds []int64 `json:"recommendIds" orm:"recommend_ids"` + Photos []string `json:"photos" orm:"photos"` } var proxyParamList []*ProxyParam diff --git a/util/gconv/gconv_basic.go b/util/gconv/gconv_basic.go index 5eff3b78b..03449231e 100644 --- a/util/gconv/gconv_basic.go +++ b/util/gconv/gconv_basic.go @@ -17,6 +17,7 @@ import ( "github.com/gogf/gf/v2/encoding/gbinary" "github.com/gogf/gf/v2/errors/gcode" "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/internal/empty" "github.com/gogf/gf/v2/internal/json" "github.com/gogf/gf/v2/internal/reflection" "github.com/gogf/gf/v2/os/gtime" @@ -43,7 +44,7 @@ func Bytes(any any) []byte { } func doBytes(any any) ([]byte, error) { - if any == nil { + if empty.IsNil(any) { return nil, nil } switch value := any.(type) { @@ -133,7 +134,7 @@ func String(any any) string { } func doString(any any) (string, error) { - if any == nil { + if empty.IsNil(any) { return "", nil } switch value := any.(type) { @@ -254,7 +255,7 @@ func Bool(any any) bool { } func doBool(any any) (bool, error) { - if any == nil { + if empty.IsNil(any) { return false, nil } switch value := any.(type) { diff --git a/util/gconv/gconv_float.go b/util/gconv/gconv_float.go index 2f7204a5c..fac2d1c98 100644 --- a/util/gconv/gconv_float.go +++ b/util/gconv/gconv_float.go @@ -13,6 +13,7 @@ import ( "github.com/gogf/gf/v2/encoding/gbinary" "github.com/gogf/gf/v2/errors/gcode" "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/internal/empty" "github.com/gogf/gf/v2/util/gconv/internal/localinterface" ) @@ -23,7 +24,7 @@ func Float32(any any) float32 { } func doFloat32(any any) (float32, error) { - if any == nil { + if empty.IsNil(any) { return 0, nil } switch value := any.(type) { @@ -86,7 +87,7 @@ func Float64(any any) float64 { } func doFloat64(any any) (float64, error) { - if any == nil { + if empty.IsNil(any) { return 0, nil } switch value := any.(type) { diff --git a/util/gconv/gconv_int.go b/util/gconv/gconv_int.go index 7e1e6a129..a3f833ae6 100644 --- a/util/gconv/gconv_int.go +++ b/util/gconv/gconv_int.go @@ -14,6 +14,7 @@ import ( "github.com/gogf/gf/v2/encoding/gbinary" "github.com/gogf/gf/v2/errors/gcode" "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/internal/empty" "github.com/gogf/gf/v2/util/gconv/internal/localinterface" ) @@ -92,7 +93,7 @@ func Int64(any any) int64 { } func doInt64(any any) (int64, error) { - if any == nil { + if empty.IsNil(any) { return 0, nil } if v, ok := any.(int64); ok { diff --git a/util/gconv/gconv_slice_any.go b/util/gconv/gconv_slice_any.go index f61044330..12de2ae30 100644 --- a/util/gconv/gconv_slice_any.go +++ b/util/gconv/gconv_slice_any.go @@ -7,8 +7,11 @@ package gconv import ( + "bytes" "reflect" + "strings" + "github.com/gogf/gf/v2/internal/empty" "github.com/gogf/gf/v2/internal/json" "github.com/gogf/gf/v2/internal/reflection" "github.com/gogf/gf/v2/util/gconv/internal/localinterface" @@ -21,7 +24,7 @@ func SliceAny(any interface{}) []interface{} { // Interfaces converts `any` to []interface{}. func Interfaces(any interface{}) []interface{} { - if any == nil { + if empty.IsNil(any) { return nil } var array []interface{} @@ -68,6 +71,9 @@ func Interfaces(any interface{}) []interface{} { if _ = json.UnmarshalUseNumber(value, &array); array != nil { return array } + if bytes.EqualFold([]byte("null"), value) { + return nil + } } array = make([]interface{}, len(value)) for k, v := range value { @@ -79,6 +85,9 @@ func Interfaces(any interface{}) []interface{} { if _ = json.UnmarshalUseNumber(byteValue, &array); array != nil { return array } + if strings.EqualFold(value, "null") { + return nil + } } case []uint16: diff --git a/util/gconv/gconv_slice_float.go b/util/gconv/gconv_slice_float.go index f497fa92b..9d23d7002 100644 --- a/util/gconv/gconv_slice_float.go +++ b/util/gconv/gconv_slice_float.go @@ -7,8 +7,11 @@ package gconv import ( + "bytes" "reflect" + "strings" + "github.com/gogf/gf/v2/internal/empty" "github.com/gogf/gf/v2/internal/json" "github.com/gogf/gf/v2/internal/reflection" "github.com/gogf/gf/v2/internal/utils" @@ -37,7 +40,7 @@ func Floats(any interface{}) []float64 { // Float32s converts `any` to []float32. func Float32s(any interface{}) []float32 { - if any == nil { + if empty.IsNil(any) { return nil } var ( @@ -83,6 +86,9 @@ func Float32s(any interface{}) []float32 { if _ = json.UnmarshalUseNumber(value, &array); array != nil { return array } + if bytes.EqualFold([]byte("null"), value) { + return nil + } } array = make([]float32, len(value)) for k, v := range value { @@ -94,6 +100,9 @@ func Float32s(any interface{}) []float32 { if _ = json.UnmarshalUseNumber(byteValue, &array); array != nil { return array } + if strings.EqualFold(value, "null") { + return nil + } } if value == "" { return []float32{} @@ -166,7 +175,7 @@ func Float32s(any interface{}) []float32 { // Float64s converts `any` to []float64. func Float64s(any interface{}) []float64 { - if any == nil { + if empty.IsNil(any) { return nil } var ( @@ -212,6 +221,9 @@ func Float64s(any interface{}) []float64 { if _ = json.UnmarshalUseNumber(value, &array); array != nil { return array } + if bytes.EqualFold([]byte("null"), value) { + return nil + } } array = make([]float64, len(value)) for k, v := range value { @@ -223,6 +235,9 @@ func Float64s(any interface{}) []float64 { if _ = json.UnmarshalUseNumber(byteValue, &array); array != nil { return array } + if strings.EqualFold(value, "null") { + return nil + } } if value == "" { return []float64{} diff --git a/util/gconv/gconv_slice_int.go b/util/gconv/gconv_slice_int.go index dc8ef41f4..4b2931e08 100644 --- a/util/gconv/gconv_slice_int.go +++ b/util/gconv/gconv_slice_int.go @@ -7,8 +7,11 @@ package gconv import ( + "bytes" "reflect" + "strings" + "github.com/gogf/gf/v2/internal/empty" "github.com/gogf/gf/v2/internal/json" "github.com/gogf/gf/v2/internal/reflection" "github.com/gogf/gf/v2/internal/utils" @@ -32,7 +35,7 @@ func SliceInt64(any interface{}) []int64 { // Ints converts `any` to []int. func Ints(any interface{}) []int { - if any == nil { + if empty.IsNil(any) { return nil } var ( @@ -76,6 +79,9 @@ func Ints(any interface{}) []int { if _ = json.UnmarshalUseNumber(value, &array); array != nil { return array } + if bytes.EqualFold([]byte("null"), value) { + return nil + } } array = make([]int, len(value)) for k, v := range value { @@ -87,6 +93,9 @@ func Ints(any interface{}) []int { if _ = json.UnmarshalUseNumber(byteValue, &array); array != nil { return array } + if strings.EqualFold(value, "null") { + return nil + } } if value == "" { return []int{} @@ -171,7 +180,7 @@ func Ints(any interface{}) []int { // Int32s converts `any` to []int32. func Int32s(any interface{}) []int32 { - if any == nil { + if empty.IsNil(any) { return nil } var ( @@ -215,6 +224,9 @@ func Int32s(any interface{}) []int32 { if _ = json.UnmarshalUseNumber(value, &array); array != nil { return array } + if bytes.EqualFold([]byte("null"), value) { + return nil + } } array = make([]int32, len(value)) for k, v := range value { @@ -226,6 +238,9 @@ func Int32s(any interface{}) []int32 { if _ = json.UnmarshalUseNumber(byteValue, &array); array != nil { return array } + if strings.EqualFold(value, "null") { + return nil + } } if value == "" { return []int32{} @@ -310,7 +325,7 @@ func Int32s(any interface{}) []int32 { // Int64s converts `any` to []int64. func Int64s(any interface{}) []int64 { - if any == nil { + if empty.IsNil(any) { return nil } var ( @@ -354,6 +369,9 @@ func Int64s(any interface{}) []int64 { if _ = json.UnmarshalUseNumber(value, &array); array != nil { return array } + if bytes.EqualFold([]byte("null"), value) { + return nil + } } array = make([]int64, len(value)) for k, v := range value { @@ -365,6 +383,9 @@ func Int64s(any interface{}) []int64 { if _ = json.UnmarshalUseNumber(byteValue, &array); array != nil { return array } + if strings.EqualFold(value, "null") { + return nil + } } if value == "" { return []int64{} diff --git a/util/gconv/gconv_slice_str.go b/util/gconv/gconv_slice_str.go index 2640be0d0..ff2157b3c 100644 --- a/util/gconv/gconv_slice_str.go +++ b/util/gconv/gconv_slice_str.go @@ -7,8 +7,11 @@ package gconv import ( + "bytes" "reflect" + "strings" + "github.com/gogf/gf/v2/internal/empty" "github.com/gogf/gf/v2/internal/json" "github.com/gogf/gf/v2/internal/reflection" "github.com/gogf/gf/v2/util/gconv/internal/localinterface" @@ -21,7 +24,7 @@ func SliceStr(any interface{}) []string { // Strings converts `any` to []string. func Strings(any interface{}) []string { - if any == nil { + if empty.IsNil(any) { return nil } var ( @@ -63,6 +66,9 @@ func Strings(any interface{}) []string { if _ = json.UnmarshalUseNumber(value, &array); array != nil { return array } + if bytes.EqualFold([]byte("null"), value) { + return nil + } } array = make([]string, len(value)) for k, v := range value { @@ -75,6 +81,9 @@ func Strings(any interface{}) []string { if _ = json.UnmarshalUseNumber(byteValue, &array); array != nil { return array } + if strings.EqualFold(value, "null") { + return nil + } } if value == "" { return []string{} diff --git a/util/gconv/gconv_slice_uint.go b/util/gconv/gconv_slice_uint.go index 1b5160e4d..00ae9e491 100644 --- a/util/gconv/gconv_slice_uint.go +++ b/util/gconv/gconv_slice_uint.go @@ -7,8 +7,11 @@ package gconv import ( + "bytes" "reflect" + "strings" + "github.com/gogf/gf/v2/internal/empty" "github.com/gogf/gf/v2/internal/json" "github.com/gogf/gf/v2/internal/reflection" "github.com/gogf/gf/v2/internal/utils" @@ -32,7 +35,7 @@ func SliceUint64(any interface{}) []uint64 { // Uints converts `any` to []uint. func Uints(any interface{}) []uint { - if any == nil { + if empty.IsNil(any) { return nil } var ( @@ -71,6 +74,9 @@ func Uints(any interface{}) []uint { if _ = json.UnmarshalUseNumber(value, &array); array != nil { return array } + if bytes.EqualFold([]byte("null"), value) { + return nil + } } array = make([]uint, len(value)) for k, v := range value { @@ -82,6 +88,9 @@ func Uints(any interface{}) []uint { if _ = json.UnmarshalUseNumber(byteValue, &array); array != nil { return array } + if strings.EqualFold(value, "null") { + return nil + } } if value == "" { return []uint{} @@ -169,7 +178,7 @@ func Uints(any interface{}) []uint { // Uint32s converts `any` to []uint32. func Uint32s(any interface{}) []uint32 { - if any == nil { + if empty.IsNil(any) { return nil } var ( @@ -211,6 +220,9 @@ func Uint32s(any interface{}) []uint32 { if _ = json.UnmarshalUseNumber(value, &array); array != nil { return array } + if bytes.EqualFold([]byte("null"), value) { + return nil + } } array = make([]uint32, len(value)) for k, v := range value { @@ -222,6 +234,9 @@ func Uint32s(any interface{}) []uint32 { if _ = json.UnmarshalUseNumber(byteValue, &array); array != nil { return array } + if strings.EqualFold(value, "null") { + return nil + } } if value == "" { return []uint32{} @@ -305,7 +320,7 @@ func Uint32s(any interface{}) []uint32 { // Uint64s converts `any` to []uint64. func Uint64s(any interface{}) []uint64 { - if any == nil { + if empty.IsNil(any) { return nil } var ( @@ -347,6 +362,9 @@ func Uint64s(any interface{}) []uint64 { if _ = json.UnmarshalUseNumber(value, &array); array != nil { return array } + if bytes.EqualFold([]byte("null"), value) { + return nil + } } array = make([]uint64, len(value)) for k, v := range value { @@ -358,6 +376,9 @@ func Uint64s(any interface{}) []uint64 { if _ = json.UnmarshalUseNumber(byteValue, &array); array != nil { return array } + if strings.EqualFold(value, "null") { + return nil + } } if value == "" { return []uint64{} diff --git a/util/gconv/gconv_time.go b/util/gconv/gconv_time.go index d42a06395..202b5b557 100644 --- a/util/gconv/gconv_time.go +++ b/util/gconv/gconv_time.go @@ -9,6 +9,7 @@ package gconv import ( "time" + "github.com/gogf/gf/v2/internal/empty" "github.com/gogf/gf/v2/internal/utils" "github.com/gogf/gf/v2/os/gtime" "github.com/gogf/gf/v2/util/gconv/internal/localinterface" @@ -50,7 +51,7 @@ func Duration(any interface{}) time.Duration { // If no `format` given, it converts `any` using gtime.NewFromTimeStamp if `any` is numeric, // or using gtime.StrToTime if `any` is string. func GTime(any interface{}, format ...string) *gtime.Time { - if any == nil { + if empty.IsNil(any) { return nil } if v, ok := any.(localinterface.IGTime); ok { diff --git a/util/gconv/gconv_uint.go b/util/gconv/gconv_uint.go index 367a71a79..75e876f51 100644 --- a/util/gconv/gconv_uint.go +++ b/util/gconv/gconv_uint.go @@ -14,6 +14,7 @@ import ( "github.com/gogf/gf/v2/encoding/gbinary" "github.com/gogf/gf/v2/errors/gcode" "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/internal/empty" "github.com/gogf/gf/v2/util/gconv/internal/localinterface" ) @@ -24,7 +25,7 @@ func Uint(any any) uint { } func doUint(any any) (uint, error) { - if any == nil { + if empty.IsNil(any) { return 0, nil } if v, ok := any.(uint); ok { @@ -41,7 +42,7 @@ func Uint8(any any) uint8 { } func doUint8(any any) (uint8, error) { - if any == nil { + if empty.IsNil(any) { return 0, nil } if v, ok := any.(uint8); ok { @@ -58,7 +59,7 @@ func Uint16(any any) uint16 { } func doUint16(any any) (uint16, error) { - if any == nil { + if empty.IsNil(any) { return 0, nil } if v, ok := any.(uint16); ok { @@ -75,7 +76,7 @@ func Uint32(any any) uint32 { } func doUint32(any any) (uint32, error) { - if any == nil { + if empty.IsNil(any) { return 0, nil } if v, ok := any.(uint32); ok { @@ -92,7 +93,7 @@ func Uint64(any any) uint64 { } func doUint64(any any) (uint64, error) { - if any == nil { + if empty.IsNil(any) { return 0, nil } if v, ok := any.(uint64); ok {