1
0
mirror of https://github.com/gogf/gf.git synced 2025-04-05 03:05:05 +08:00

Merge branch 'feat/v2.9.0' of github.com:gogf/gf into feat/v2.9.0

This commit is contained in:
John Guo 2024-12-18 20:48:05 +08:00
commit 2c1fcec88c
15 changed files with 1038 additions and 491 deletions

View File

@ -130,9 +130,9 @@ jobs:
# ClickHouse backend server.
# docker run -d --name clickhouse \
# -p 9000:9000 -p 8123:8123 -p 9001:9001 \
# loads/clickhouse-server:22.1.3.7
# clickhouse/clickhouse-server:24.11.1.2557-alpine
clickhouse-server:
image: loads/clickhouse-server:22.1.3.7
image: clickhouse/clickhouse-server:24.11.1.2557-alpine
ports:
- 9000:9000
- 8123:8123

View File

@ -280,9 +280,18 @@ func Test_DB_Delete(t *testing.T) {
defer dropTable(table)
gtest.C(t, func(t *gtest.T) {
_, err := db.Delete(ctx, table, "id>3")
t.AssertNE(err, nil)
//db.SetDebug(true)
count, err := db.Model(table).Ctx(ctx).Count()
t.AssertNil(err)
t.Assert(count, 10)
result, err := db.Delete(ctx, table, "id>3")
t.AssertNil(err)
t.AssertNil(result)
count, err = db.Model(table).Ctx(ctx).Count()
t.AssertNil(err)
t.Assert(count, 3)
})
}

View File

@ -90,13 +90,10 @@ func Test_Grpcx_Grpc_Server_Config_Logger(t *testing.T) {
time.Sleep(time.Millisecond * 100)
defer s.Stop()
var (
logFilePath = fmt.Sprintf("/tmp/log/%s.log", gtime.Now().Format("Y-m-d"))
logFileContent = gfile.GetContents(logFilePath)
)
defer gfile.Remove(logFilePath)
var logFilePath = fmt.Sprintf("/tmp/log/%s.log", gtime.Now().Format("Y-m-d"))
defer gfile.RemoveFile(logFilePath)
t.Assert(gfile.Exists(logFilePath), true)
t.Assert(gstr.Contains(logFileContent, "TestLogger "), true)
t.Assert(s.Logger().GetConfig().Prefix, "TestLogger")
})
}

View File

@ -12,6 +12,7 @@ import (
"fmt"
htmltpl "html/template"
"strconv"
"strings"
texttpl "text/template"
"github.com/gogf/gf/v2/container/gmap"
@ -372,31 +373,48 @@ func (view *View) formatTemplateObjectCreatingError(filePath, tplName string, er
// searchFile returns the absolute path of the `file` and its template folder path.
// The returned `folder` is the template folder path, not the folder of the template file `path`.
func (view *View) searchFile(ctx context.Context, file string) (path string, folder string, resource *gres.File, err error) {
var tempPath string
// Firstly, checking the resource manager.
var (
tempPath string
trimmedFile = strings.TrimLeft(file, `\/`)
)
// Firstly checking the resource manager.
if !gres.IsEmpty() {
// Try folders.
for _, tryFolder := range resourceTryFolders {
tempPath = tryFolder + file
if resource = gres.Get(tempPath); resource != nil {
path = resource.Name()
folder = tryFolder
return
}
}
// Search folders.
view.searchPaths.RLockFunc(func(array []string) {
for _, searchPath := range array {
for _, tryFolder := range resourceTryFolders {
tempPath = searchPath + tryFolder + file
if resFile := gres.Get(tempPath); resFile != nil {
path = resFile.Name()
folder = searchPath + tryFolder
if path == "" {
view.searchPaths.RLockFunc(func(array []string) {
for _, searchPath := range array {
tempPath = strings.TrimRight(searchPath, `\/`) + `/` + trimmedFile
if tmpFile := gres.Get(tempPath); tmpFile != nil {
path = tmpFile.Name()
folder = searchPath
resource = tmpFile
return
}
for _, tryFolder := range resourceTryFolders {
tempPath = strings.TrimRight(searchPath, `\/`) + `/` + strings.TrimRight(tryFolder, `\/`) + `/` + file
if tmpFile := gres.Get(tempPath); tmpFile != nil {
path = tmpFile.Name()
folder = searchPath + tryFolder
resource = tmpFile
return
}
}
}
})
}
// Try folders.
if path == "" {
for _, tryFolder := range resourceTryFolders {
tempPath = strings.TrimRight(tryFolder, `\/`) + `/` + trimmedFile
if tmpFile := gres.Get(tempPath); tmpFile != nil {
path = tmpFile.Name()
folder = tryFolder
resource = tmpFile
return
}
}
})
}
}
// Secondly, checking the file system.

View File

@ -621,6 +621,10 @@ func init() {
if err := gres.Add("H4sIAAAAAAAC/wrwZmYRYeBg4GBIFA0LY0ACEgycDCWpuQU5iSWp+ullmanl8SWpxSV6GSW5OaEhrAyM5o1fk095n/HdumrdNeaLW7c2MDAw/P8f4M3OoZ+9QESIgYGBj4GBAWYBA0MTmgUcSBaADSxt/JoM0o6sKMCbkUmEGeFCZKNBLoSBbY0gkqB7EcZhdw8ECDD8d0xEMg7JdaxsIAVMDEwMfQwMDAvAygEBAAD//0d6jptEAQAA"); err != nil {
panic("add binary content to resource manager failed: " + err.Error())
}
if err := gres.Add("H4sIAAAAAAAC/wrwZmYRYeBg4GBIFA0LY0ACEgycDCWpuQU5iSWp+ullmanl8SWpxSV6GSW5OaEhrAyM5o1fk095n/HdumrdNeaLW7c2MDAw/P8f4M3OoZ+9QESIgYGBj4GBAWYBA0MTmgUcSBaADSxt/JoM0o6sKMCbkUmEGeFCZKNBLoSBbY0gkqB7EcZhdw8ECDD8d0xEMg7JdaxsIAVMDEwMfQwMDAvAygEBAAD//0d6jptEAQAA", "assets/"); err != nil {
panic("add binary content to resource manager failed: " + err.Error())
}
}
func Test_GviewInGres(t *testing.T) {
@ -635,3 +639,23 @@ func Test_GviewInGres(t *testing.T) {
t.Assert(result, "name:john")
})
}
func Test_GviewSearchFileInGres(t *testing.T) {
gres.Dump()
gtest.C(t, func(t *gtest.T) {
v := gview.New()
v.SetPath("assets/template")
result, err := v.Parse(context.TODO(), "gview_test.html", g.Map{
"name": "john",
})
t.AssertNil(err)
t.Assert(result, "name:john")
v1 := gview.New("assets/template")
result1, err1 := v1.Parse(context.TODO(), "gview_test.html", g.Map{
"name": "john",
})
t.AssertNil(err1)
t.Assert(result1, "name:john")
})
}

View File

@ -10,19 +10,6 @@
package gconv
import (
"context"
"fmt"
"math"
"reflect"
"strconv"
"strings"
"time"
"github.com/gogf/gf/v2/encoding/gbinary"
"github.com/gogf/gf/v2/internal/intlog"
"github.com/gogf/gf/v2/internal/json"
"github.com/gogf/gf/v2/internal/reflection"
"github.com/gogf/gf/v2/os/gtime"
"github.com/gogf/gf/v2/util/gconv/internal/localinterface"
"github.com/gogf/gf/v2/util/gconv/internal/structcache"
)
@ -56,265 +43,3 @@ func init() {
Bool: Bool,
})
}
// Byte converts `any` to byte.
func Byte(any interface{}) byte {
if v, ok := any.(byte); ok {
return v
}
return Uint8(any)
}
// Bytes converts `any` to []byte.
func Bytes(any interface{}) []byte {
if any == nil {
return nil
}
switch value := any.(type) {
case string:
return []byte(value)
case []byte:
return value
default:
if f, ok := value.(localinterface.IBytes); ok {
return f.Bytes()
}
originValueAndKind := reflection.OriginValueAndKind(any)
switch originValueAndKind.OriginKind {
case reflect.Map:
bytes, err := json.Marshal(any)
if err != nil {
intlog.Errorf(context.TODO(), `%+v`, err)
}
return bytes
case reflect.Array, reflect.Slice:
var (
ok = true
bytes = make([]byte, originValueAndKind.OriginValue.Len())
)
for i := range bytes {
int32Value := Int32(originValueAndKind.OriginValue.Index(i).Interface())
if int32Value < 0 || int32Value > math.MaxUint8 {
ok = false
break
}
bytes[i] = byte(int32Value)
}
if ok {
return bytes
}
}
return gbinary.Encode(any)
}
}
// Rune converts `any` to rune.
func Rune(any interface{}) rune {
if v, ok := any.(rune); ok {
return v
}
return Int32(any)
}
// Runes converts `any` to []rune.
func Runes(any interface{}) []rune {
if v, ok := any.([]rune); ok {
return v
}
return []rune(String(any))
}
// String converts `any` to string.
// It's most commonly used converting function.
func String(any interface{}) string {
if any == nil {
return ""
}
switch value := any.(type) {
case int:
return strconv.Itoa(value)
case int8:
return strconv.Itoa(int(value))
case int16:
return strconv.Itoa(int(value))
case int32:
return strconv.Itoa(int(value))
case int64:
return strconv.FormatInt(value, 10)
case uint:
return strconv.FormatUint(uint64(value), 10)
case uint8:
return strconv.FormatUint(uint64(value), 10)
case uint16:
return strconv.FormatUint(uint64(value), 10)
case uint32:
return strconv.FormatUint(uint64(value), 10)
case uint64:
return strconv.FormatUint(value, 10)
case float32:
return strconv.FormatFloat(float64(value), 'f', -1, 32)
case float64:
return strconv.FormatFloat(value, 'f', -1, 64)
case bool:
return strconv.FormatBool(value)
case string:
return value
case []byte:
return string(value)
case time.Time:
if value.IsZero() {
return ""
}
return value.String()
case *time.Time:
if value == nil {
return ""
}
return value.String()
case gtime.Time:
if value.IsZero() {
return ""
}
return value.String()
case *gtime.Time:
if value == nil {
return ""
}
return value.String()
default:
if f, ok := value.(localinterface.IString); ok {
// If the variable implements the String() interface,
// then use that interface to perform the conversion
return f.String()
}
if f, ok := value.(localinterface.IError); ok {
// If the variable implements the Error() interface,
// then use that interface to perform the conversion
return f.Error()
}
// Reflect checks.
var (
rv = reflect.ValueOf(value)
kind = rv.Kind()
)
switch kind {
case
reflect.Chan,
reflect.Map,
reflect.Slice,
reflect.Func,
reflect.Interface,
reflect.UnsafePointer:
if rv.IsNil() {
return ""
}
case reflect.String:
return rv.String()
case reflect.Ptr:
if rv.IsNil() {
return ""
}
return String(rv.Elem().Interface())
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return strconv.FormatInt(rv.Int(), 10)
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
return strconv.FormatUint(rv.Uint(), 10)
case reflect.Uintptr:
return strconv.FormatUint(rv.Uint(), 10)
case reflect.Float32, reflect.Float64:
return strconv.FormatFloat(rv.Float(), 'f', -1, 64)
case reflect.Bool:
return strconv.FormatBool(rv.Bool())
}
// Finally, we use json.Marshal to convert.
if jsonContent, err := json.Marshal(value); err != nil {
return fmt.Sprint(value)
} else {
return string(jsonContent)
}
}
}
// Bool converts `any` to bool.
// It returns false if `any` is: false, "", 0, "false", "off", "no", empty slice/map.
func Bool(any interface{}) bool {
if any == nil {
return false
}
switch value := any.(type) {
case bool:
return value
case []byte:
if _, ok := emptyStringMap[strings.ToLower(string(value))]; ok {
return false
}
return true
case string:
if _, ok := emptyStringMap[strings.ToLower(value)]; ok {
return false
}
return true
default:
if f, ok := value.(localinterface.IBool); ok {
return f.Bool()
}
rv := reflect.ValueOf(any)
switch rv.Kind() {
case reflect.Ptr:
if rv.IsNil() {
return false
}
if rv.Type().Elem().Kind() == reflect.Bool {
return rv.Elem().Bool()
}
return Bool(rv.Elem().Interface())
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return rv.Int() != 0
case reflect.Uintptr, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
return rv.Uint() != 0
case reflect.Float32, reflect.Float64:
return rv.Float() != 0
case reflect.Bool:
return rv.Bool()
// TODO(MapArraySliceStruct) It might panic here for these types.
case reflect.Map, reflect.Array:
fallthrough
case reflect.Slice:
return rv.Len() != 0
case reflect.Struct:
return true
default:
s := strings.ToLower(String(any))
if _, ok := emptyStringMap[s]; ok {
return false
}
return true
}
}
}
// checkJsonAndUnmarshalUseNumber checks if given `any` is JSON formatted string value and does converting using `json.UnmarshalUseNumber`.
func checkJsonAndUnmarshalUseNumber(any interface{}, target interface{}) bool {
switch r := any.(type) {
case []byte:
if json.Valid(r) {
if err := json.UnmarshalUseNumber(r, &target); err != nil {
return false
}
return true
}
case string:
anyAsBytes := []byte(r)
if json.Valid(anyAsBytes) {
if err := json.UnmarshalUseNumber(anyAsBytes, &target); err != nil {
return false
}
return true
}
}
return false
}

336
util/gconv/gconv_basic.go Normal file
View File

@ -0,0 +1,336 @@
// 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 gconv
import (
"fmt"
"math"
"reflect"
"strconv"
"strings"
"time"
"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/json"
"github.com/gogf/gf/v2/internal/reflection"
"github.com/gogf/gf/v2/os/gtime"
"github.com/gogf/gf/v2/util/gconv/internal/localinterface"
)
// Byte converts `any` to byte.
func Byte(any any) byte {
v, _ := doByte(any)
return v
}
func doByte(any any) (byte, error) {
if v, ok := any.(byte); ok {
return v, nil
}
return doUint8(any)
}
// Bytes converts `any` to []byte.
func Bytes(any any) []byte {
v, _ := doBytes(any)
return v
}
func doBytes(any any) ([]byte, error) {
if any == nil {
return nil, nil
}
switch value := any.(type) {
case string:
return []byte(value), nil
case []byte:
return value, nil
default:
if f, ok := value.(localinterface.IBytes); ok {
return f.Bytes(), nil
}
originValueAndKind := reflection.OriginValueAndKind(any)
switch originValueAndKind.OriginKind {
case reflect.Map:
bytes, err := json.Marshal(any)
if err != nil {
return nil, err
}
return bytes, nil
case reflect.Array, reflect.Slice:
var (
ok = true
bytes = make([]byte, originValueAndKind.OriginValue.Len())
)
for i := range bytes {
int32Value, err := doInt32(originValueAndKind.OriginValue.Index(i).Interface())
if err != nil {
return nil, err
}
if int32Value < 0 || int32Value > math.MaxUint8 {
ok = false
break
}
bytes[i] = byte(int32Value)
}
if ok {
return bytes, nil
}
default:
}
return gbinary.Encode(any), nil
}
}
// Rune converts `any` to rune.
func Rune(any any) rune {
v, _ := doRune(any)
return v
}
func doRune(any any) (rune, error) {
if v, ok := any.(rune); ok {
return v, nil
}
v, err := doInt32(any)
if err != nil {
return 0, err
}
return v, nil
}
// Runes converts `any` to []rune.
func Runes(any any) []rune {
v, _ := doRunes(any)
return v
}
func doRunes(any any) ([]rune, error) {
if v, ok := any.([]rune); ok {
return v, nil
}
s, err := doString(any)
if err != nil {
return nil, err
}
return []rune(s), nil
}
// String converts `any` to string.
// It's most commonly used converting function.
func String(any any) string {
v, _ := doString(any)
return v
}
func doString(any any) (string, error) {
if any == nil {
return "", nil
}
switch value := any.(type) {
case int:
return strconv.Itoa(value), nil
case int8:
return strconv.Itoa(int(value)), nil
case int16:
return strconv.Itoa(int(value)), nil
case int32:
return strconv.Itoa(int(value)), nil
case int64:
return strconv.FormatInt(value, 10), nil
case uint:
return strconv.FormatUint(uint64(value), 10), nil
case uint8:
return strconv.FormatUint(uint64(value), 10), nil
case uint16:
return strconv.FormatUint(uint64(value), 10), nil
case uint32:
return strconv.FormatUint(uint64(value), 10), nil
case uint64:
return strconv.FormatUint(value, 10), nil
case float32:
return strconv.FormatFloat(float64(value), 'f', -1, 32), nil
case float64:
return strconv.FormatFloat(value, 'f', -1, 64), nil
case bool:
return strconv.FormatBool(value), nil
case string:
return value, nil
case []byte:
return string(value), nil
case complex64, complex128:
return fmt.Sprintf("%v", value), nil
case time.Time:
if value.IsZero() {
return "", nil
}
return value.String(), nil
case *time.Time:
if value == nil {
return "", nil
}
return value.String(), nil
case gtime.Time:
if value.IsZero() {
return "", nil
}
return value.String(), nil
case *gtime.Time:
if value == nil {
return "", nil
}
return value.String(), nil
default:
if f, ok := value.(localinterface.IString); ok {
// If the variable implements the String() interface,
// then use that interface to perform the conversion
return f.String(), nil
}
if f, ok := value.(localinterface.IError); ok {
// If the variable implements the Error() interface,
// then use that interface to perform the conversion
return f.Error(), nil
}
// Reflect checks.
var (
rv = reflect.ValueOf(value)
kind = rv.Kind()
)
switch kind {
case
reflect.Chan,
reflect.Map,
reflect.Slice,
reflect.Func,
reflect.Interface,
reflect.UnsafePointer:
if rv.IsNil() {
return "", nil
}
case reflect.String:
return rv.String(), nil
case reflect.Ptr:
if rv.IsNil() {
return "", nil
}
return doString(rv.Elem().Interface())
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return strconv.FormatInt(rv.Int(), 10), nil
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
return strconv.FormatUint(rv.Uint(), 10), nil
case reflect.Uintptr:
return strconv.FormatUint(rv.Uint(), 10), nil
case reflect.Float32, reflect.Float64:
return strconv.FormatFloat(rv.Float(), 'f', -1, 64), nil
case reflect.Bool:
return strconv.FormatBool(rv.Bool()), nil
default:
}
// Finally, we use json.Marshal to convert.
jsonContent, err := json.Marshal(value)
if err != nil {
return fmt.Sprint(value), gerror.WrapCodef(
gcode.CodeInvalidParameter, err, "error marshaling value to JSON for: %v", value,
)
}
return string(jsonContent), nil
}
}
// Bool converts `any` to bool.
// It returns false if `any` is: false, "", 0, "false", "off", "no", empty slice/map.
func Bool(any any) bool {
v, _ := doBool(any)
return v
}
func doBool(any any) (bool, error) {
if any == nil {
return false, nil
}
switch value := any.(type) {
case bool:
return value, nil
case []byte:
if _, ok := emptyStringMap[strings.ToLower(string(value))]; ok {
return false, nil
}
return true, nil
case string:
if _, ok := emptyStringMap[strings.ToLower(value)]; ok {
return false, nil
}
return true, nil
default:
if f, ok := value.(localinterface.IBool); ok {
return f.Bool(), nil
}
rv := reflect.ValueOf(any)
switch rv.Kind() {
case reflect.Ptr:
if rv.IsNil() {
return false, nil
}
if rv.Type().Elem().Kind() == reflect.Bool {
return rv.Elem().Bool(), nil
}
return doBool(rv.Elem().Interface())
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return rv.Int() != 0, nil
case reflect.Uintptr, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
return rv.Uint() != 0, nil
case reflect.Float32, reflect.Float64:
return rv.Float() != 0, nil
case reflect.Bool:
return rv.Bool(), nil
// TODO(MapArraySliceStruct) It might panic here for these types.
case reflect.Map, reflect.Array:
fallthrough
case reflect.Slice:
return rv.Len() != 0, nil
case reflect.Struct:
return true, nil
default:
s, err := doString(any)
if err != nil {
return false, err
}
if _, ok := emptyStringMap[strings.ToLower(s)]; ok {
return false, nil
}
return true, nil
}
}
}
// checkJsonAndUnmarshalUseNumber checks if given `any` is JSON formatted string value and does converting using `json.UnmarshalUseNumber`.
func checkJsonAndUnmarshalUseNumber(any any, target any) bool {
switch r := any.(type) {
case []byte:
if json.Valid(r) {
if err := json.UnmarshalUseNumber(r, &target); err != nil {
return false
}
return true
}
case string:
anyAsBytes := []byte(r)
if json.Valid(anyAsBytes) {
if err := json.UnmarshalUseNumber(anyAsBytes, &target); err != nil {
return false
}
return true
}
}
return false
}

View File

@ -11,106 +11,138 @@ import (
"strconv"
"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/util/gconv/internal/localinterface"
)
// Float32 converts `any` to float32.
func Float32(any interface{}) float32 {
func Float32(any any) float32 {
v, _ := doFloat32(any)
return v
}
func doFloat32(any any) (float32, error) {
if any == nil {
return 0
return 0, nil
}
switch value := any.(type) {
case float32:
return value
return value, nil
case float64:
return float32(value)
return float32(value), nil
case []byte:
// TODO: It might panic here for these types.
return gbinary.DecodeToFloat32(value)
return gbinary.DecodeToFloat32(value), nil
default:
rv := reflect.ValueOf(any)
switch rv.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return float32(rv.Int())
return float32(rv.Int()), nil
case reflect.Uintptr, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
return float32(rv.Uint())
return float32(rv.Uint()), nil
case reflect.Float32, reflect.Float64:
return float32(rv.Float())
return float32(rv.Float()), nil
case reflect.Bool:
if rv.Bool() {
return 1
return 1, nil
}
return 0
return 0, nil
case reflect.String:
f, _ := strconv.ParseFloat(rv.String(), 32)
return float32(f)
f, err := strconv.ParseFloat(rv.String(), 32)
if err != nil {
return 0, gerror.WrapCodef(
gcode.CodeInvalidParameter, err, "converting string to float32 failed for: %v", any,
)
}
return float32(f), nil
case reflect.Ptr:
if rv.IsNil() {
return 0
return 0, nil
}
if f, ok := value.(localinterface.IFloat32); ok {
return f.Float32()
return f.Float32(), nil
}
return Float32(rv.Elem().Interface())
return doFloat32(rv.Elem().Interface())
default:
if f, ok := value.(localinterface.IFloat32); ok {
return f.Float32()
return f.Float32(), nil
}
v, _ := strconv.ParseFloat(String(any), 32)
return float32(v)
v, err := strconv.ParseFloat(String(any), 32)
if err != nil {
return 0, gerror.WrapCodef(
gcode.CodeInvalidParameter, err, "converting string to float32 failed for: %v", any,
)
}
return float32(v), nil
}
}
}
// Float64 converts `any` to float64.
func Float64(any interface{}) float64 {
func Float64(any any) float64 {
v, _ := doFloat64(any)
return v
}
func doFloat64(any any) (float64, error) {
if any == nil {
return 0
return 0, nil
}
switch value := any.(type) {
case float32:
return float64(value)
return float64(value), nil
case float64:
return value
return value, nil
case []byte:
// TODO: It might panic here for these types.
return gbinary.DecodeToFloat64(value)
return gbinary.DecodeToFloat64(value), nil
default:
rv := reflect.ValueOf(any)
switch rv.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return float64(rv.Int())
return float64(rv.Int()), nil
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
return float64(rv.Uint())
return float64(rv.Uint()), nil
case reflect.Uintptr:
return float64(rv.Uint())
return float64(rv.Uint()), nil
case reflect.Float32, reflect.Float64:
// Please Note:
// When the type is float32 or a custom type defined based on float32,
// switching to float64 may result in a few extra decimal places.
return rv.Float()
return rv.Float(), nil
case reflect.Bool:
if rv.Bool() {
return 1
return 1, nil
}
return 0
return 0, nil
case reflect.String:
f, _ := strconv.ParseFloat(rv.String(), 64)
return f
f, err := strconv.ParseFloat(rv.String(), 64)
if err != nil {
return 0, gerror.WrapCodef(
gcode.CodeInvalidParameter, err, "converting string to float64 failed for: %v", any,
)
}
return f, nil
case reflect.Ptr:
if rv.IsNil() {
return 0
return 0, nil
}
if f, ok := value.(localinterface.IFloat64); ok {
return f.Float64()
return f.Float64(), nil
}
return Float64(rv.Elem().Interface())
return doFloat64(rv.Elem().Interface())
default:
if f, ok := value.(localinterface.IFloat64); ok {
return f.Float64()
return f.Float64(), nil
}
v, _ := strconv.ParseFloat(String(any), 64)
return v
v, err := strconv.ParseFloat(String(any), 64)
if err != nil {
return 0, gerror.WrapCodef(
gcode.CodeInvalidParameter, err, "converting string to float64 failed for: %v", any,
)
}
return v, nil
}
}
}

View File

@ -12,85 +12,119 @@ import (
"strconv"
"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/util/gconv/internal/localinterface"
)
// Int converts `any` to int.
func Int(any interface{}) int {
if any == nil {
return 0
}
func Int(any any) int {
v, _ := doInt(any)
return v
}
func doInt(any any) (int, error) {
if v, ok := any.(int); ok {
return v
return v, nil
}
return int(Int64(any))
v, err := doInt64(any)
if err != nil {
return 0, err
}
return int(v), nil
}
// Int8 converts `any` to int8.
func Int8(any interface{}) int8 {
if any == nil {
return 0
}
func Int8(any any) int8 {
v, _ := doInt8(any)
return v
}
func doInt8(any any) (int8, error) {
if v, ok := any.(int8); ok {
return v
return v, nil
}
return int8(Int64(any))
v, err := doInt64(any)
if err != nil {
return 0, err
}
return int8(v), nil
}
// Int16 converts `any` to int16.
func Int16(any interface{}) int16 {
if any == nil {
return 0
}
func Int16(any any) int16 {
v, _ := doInt16(any)
return v
}
func doInt16(any any) (int16, error) {
if v, ok := any.(int16); ok {
return v
return v, nil
}
return int16(Int64(any))
v, err := doInt64(any)
if err != nil {
return 0, err
}
return int16(v), nil
}
// Int32 converts `any` to int32.
func Int32(any interface{}) int32 {
if any == nil {
return 0
}
func Int32(any any) int32 {
v, _ := doInt32(any)
return v
}
func doInt32(any any) (int32, error) {
if v, ok := any.(int32); ok {
return v
return v, nil
}
return int32(Int64(any))
v, err := doInt64(any)
if err != nil {
return 0, err
}
return int32(v), nil
}
// Int64 converts `any` to int64.
func Int64(any interface{}) int64 {
func Int64(any any) int64 {
v, _ := doInt64(any)
return v
}
func doInt64(any any) (int64, error) {
if any == nil {
return 0
return 0, nil
}
if v, ok := any.(int64); ok {
return v, nil
}
rv := reflect.ValueOf(any)
switch rv.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return int64(rv.Int())
return rv.Int(), nil
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
return int64(rv.Uint())
return int64(rv.Uint()), nil
case reflect.Uintptr:
return int64(rv.Uint())
return int64(rv.Uint()), nil
case reflect.Float32, reflect.Float64:
return int64(rv.Float())
return int64(rv.Float()), nil
case reflect.Bool:
if rv.Bool() {
return 1
return 1, nil
}
return 0
return 0, nil
case reflect.Ptr:
if rv.IsNil() {
return 0
return 0, nil
}
if f, ok := any.(localinterface.IInt64); ok {
return f.Int64()
return f.Int64(), nil
}
return Int64(rv.Elem().Interface())
return doInt64(rv.Elem().Interface())
case reflect.Slice:
// TODO: It might panic here for these types.
if rv.Type().Elem().Kind() == reflect.Uint8 {
return gbinary.DecodeToInt64(rv.Bytes())
return gbinary.DecodeToInt64(rv.Bytes()), nil
}
case reflect.String:
var (
@ -109,31 +143,39 @@ func Int64(any interface{}) int64 {
if len(s) > 2 && s[0] == '0' && (s[1] == 'x' || s[1] == 'X') {
if v, e := strconv.ParseInt(s[2:], 16, 64); e == nil {
if isMinus {
return -v
return -v, nil
}
return v
return v, nil
}
}
// Decimal.
if v, e := strconv.ParseInt(s, 10, 64); e == nil {
if isMinus {
return -v
return -v, nil
}
return v
return v, nil
}
// Float64.
if valueInt64 := Float64(s); math.IsNaN(valueInt64) {
return 0
valueInt64, err := doFloat64(s)
if err != nil {
return 0, err
}
if math.IsNaN(valueInt64) {
return 0, nil
} else {
if isMinus {
return -int64(valueInt64)
return -int64(valueInt64), nil
}
return int64(valueInt64)
return int64(valueInt64), nil
}
default:
if f, ok := any.(localinterface.IInt64); ok {
return f.Int64()
return f.Int64(), nil
}
}
return 0
return 0, gerror.NewCodef(
gcode.CodeInvalidParameter,
`unsupport value type for converting to int64: %v`,
reflect.TypeOf(any),
)
}

View File

@ -539,6 +539,8 @@ func doMapConvertForMapOrStructValue(in doMapConvertForMapOrStructValueInput) in
})
}
return array
default:
}
return in.Value
}

View File

@ -16,14 +16,21 @@ import (
)
// Scan automatically checks the type of `pointer` and converts `params` to `pointer`.
// It supports `pointer` in type of `*map/*[]map/*[]*map/*struct/**struct/*[]struct/*[]*struct` for converting.
// It supports various types of parameter conversions, including:
// 1. Basic types (int, string, float, etc.)
// 2. Pointer types
// 3. Slice types
// 4. Map types
// 5. Struct types
//
// TODO change `paramKeyToAttrMap` to `ScanOption` to be more scalable; add `DeepCopy` option for `ScanOption`.
func Scan(srcValue interface{}, dstPointer interface{}, paramKeyToAttrMap ...map[string]string) (err error) {
// The `paramKeyToAttrMap` parameter is used for mapping between attribute names and parameter keys.
// TODO: change `paramKeyToAttrMap` to `ScanOption` to be more scalable; add `DeepCopy` option for `ScanOption`.
func Scan(srcValue any, dstPointer any, paramKeyToAttrMap ...map[string]string) (err error) {
// Check if srcValue is nil, in which case no conversion is needed
if srcValue == nil {
// If `srcValue` is nil, no conversion.
return nil
}
// Check if dstPointer is nil, which is an invalid parameter
if dstPointer == nil {
return gerror.NewCode(
gcode.CodeInvalidParameter,
@ -31,15 +38,7 @@ func Scan(srcValue interface{}, dstPointer interface{}, paramKeyToAttrMap ...map
)
}
// json converting check.
ok, err := doConvertWithJsonCheck(srcValue, dstPointer)
if err != nil {
return err
}
if ok {
return nil
}
// Get the reflection type and value of dstPointer
var (
dstPointerReflectType reflect.Type
dstPointerReflectValue reflect.Value
@ -49,18 +48,20 @@ func Scan(srcValue interface{}, dstPointer interface{}, paramKeyToAttrMap ...map
dstPointerReflectType = v.Type()
} else {
dstPointerReflectValue = reflect.ValueOf(dstPointer)
// do not use dstPointerReflectValue.Type() as dstPointerReflectValue might be zero.
// Do not use dstPointerReflectValue.Type() as dstPointerReflectValue might be zero
dstPointerReflectType = reflect.TypeOf(dstPointer)
}
// pointer kind validation.
// Validate the kind of dstPointer
var dstPointerReflectKind = dstPointerReflectType.Kind()
if dstPointerReflectKind != reflect.Ptr {
// If dstPointer is not a pointer, try to get its address
if dstPointerReflectValue.CanAddr() {
dstPointerReflectValue = dstPointerReflectValue.Addr()
dstPointerReflectType = dstPointerReflectValue.Type()
dstPointerReflectKind = dstPointerReflectType.Kind()
} else {
// If dstPointer is not a pointer and cannot be addressed, return an error
return gerror.NewCodef(
gcode.CodeInvalidParameter,
`destination pointer should be type of pointer, but got type: %v`,
@ -68,23 +69,144 @@ func Scan(srcValue interface{}, dstPointer interface{}, paramKeyToAttrMap ...map
)
}
}
// direct assignment checks!
// Get the reflection value of srcValue
var srcValueReflectValue reflect.Value
if v, ok := srcValue.(reflect.Value); ok {
srcValueReflectValue = v
} else {
srcValueReflectValue = reflect.ValueOf(srcValue)
}
// if `srcValue` and `dstPointer` are the same type, the do directly assignment.
// For performance enhancement purpose.
var dstPointerReflectValueElem = dstPointerReflectValue.Elem()
// if `srcValue` and `dstPointer` are the same type, the do directly assignment.
// for performance enhancement purpose.
if ok = doConvertWithTypeCheck(srcValueReflectValue, dstPointerReflectValueElem); ok {
// Get the element type and kind of dstPointer
var (
dstPointerReflectValueElem = dstPointerReflectValue.Elem()
dstPointerReflectValueElemKind = dstPointerReflectValueElem.Kind()
)
// Handle multiple level pointers
if dstPointerReflectValueElemKind == reflect.Ptr {
if dstPointerReflectValueElem.IsNil() {
// Create a new value for the pointer dereference
nextLevelPtr := reflect.New(dstPointerReflectValueElem.Type().Elem())
// Recursively scan into the dereferenced pointer
if err = Scan(srcValueReflectValue, nextLevelPtr, paramKeyToAttrMap...); err == nil {
dstPointerReflectValueElem.Set(nextLevelPtr)
}
return
}
return Scan(srcValueReflectValue, dstPointerReflectValueElem, paramKeyToAttrMap...)
}
// Check if srcValue and dstPointer are the same type, in which case direct assignment can be performed
if ok := doConvertWithTypeCheck(srcValueReflectValue, dstPointerReflectValueElem); ok {
return nil
}
// do the converting.
// Handle different destination types
switch dstPointerReflectValueElemKind {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
// Convert to int type
dstPointerReflectValueElem.SetInt(Int64(srcValue))
return nil
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
// Convert to uint type
dstPointerReflectValueElem.SetUint(Uint64(srcValue))
return nil
case reflect.Float32, reflect.Float64:
// Convert to float type
dstPointerReflectValueElem.SetFloat(Float64(srcValue))
return nil
case reflect.String:
// Convert to string type
dstPointerReflectValueElem.SetString(String(srcValue))
return nil
case reflect.Bool:
// Convert to bool type
dstPointerReflectValueElem.SetBool(Bool(srcValue))
return nil
case reflect.Slice:
// Handle slice type conversion
var (
dstElemType = dstPointerReflectValueElem.Type().Elem()
dstElemKind = dstElemType.Kind()
)
// The slice element might be a pointer type
if dstElemKind == reflect.Ptr {
dstElemType = dstElemType.Elem()
dstElemKind = dstElemType.Kind()
}
// Special handling for struct or map slice elements
if dstElemKind == reflect.Struct || dstElemKind == reflect.Map {
return doScanForComplicatedTypes(srcValue, dstPointer, dstPointerReflectType, paramKeyToAttrMap...)
}
// Handle basic type slice conversions
var srcValueReflectValueKind = srcValueReflectValue.Kind()
if srcValueReflectValueKind == reflect.Slice || srcValueReflectValueKind == reflect.Array {
var (
srcLen = srcValueReflectValue.Len()
newSlice = reflect.MakeSlice(dstPointerReflectValueElem.Type(), srcLen, srcLen)
)
for i := 0; i < srcLen; i++ {
srcElem := srcValueReflectValue.Index(i).Interface()
switch dstElemType.Kind() {
case reflect.String:
newSlice.Index(i).SetString(String(srcElem))
case reflect.Int:
newSlice.Index(i).SetInt(Int64(srcElem))
case reflect.Int64:
newSlice.Index(i).SetInt(Int64(srcElem))
case reflect.Float64:
newSlice.Index(i).SetFloat(Float64(srcElem))
case reflect.Bool:
newSlice.Index(i).SetBool(Bool(srcElem))
default:
return Scan(
srcElem, newSlice.Index(i).Addr().Interface(), paramKeyToAttrMap...,
)
}
}
dstPointerReflectValueElem.Set(newSlice)
return nil
}
return doScanForComplicatedTypes(srcValue, dstPointer, dstPointerReflectType, paramKeyToAttrMap...)
default:
// Handle complex types (structs, maps, etc.)
return doScanForComplicatedTypes(srcValue, dstPointer, dstPointerReflectType, paramKeyToAttrMap...)
}
}
// doScanForComplicatedTypes handles the scanning of complex data types.
// It supports converting between maps, structs, and slices of these types.
// The function first attempts JSON conversion, then falls back to specific type handling.
//
// It supports `pointer` in type of `*map/*[]map/*[]*map/*struct/**struct/*[]struct/*[]*struct` for converting.
//
// Parameters:
// - srcValue: The source value to convert from
// - dstPointer: The destination pointer to convert to
// - dstPointerReflectType: The reflection type of the destination pointer
// - paramKeyToAttrMap: Optional mapping between parameter keys and struct attribute names
func doScanForComplicatedTypes(
srcValue, dstPointer any,
dstPointerReflectType reflect.Type,
paramKeyToAttrMap ...map[string]string,
) error {
// Try JSON conversion first
ok, err := doConvertWithJsonCheck(srcValue, dstPointer)
if err != nil {
return err
}
if ok {
return nil
}
// Handle specific type conversions
var (
dstPointerReflectTypeElem = dstPointerReflectType.Elem()
dstPointerReflectTypeElemKind = dstPointerReflectTypeElem.Kind()
@ -93,8 +215,11 @@ func Scan(srcValue interface{}, dstPointer interface{}, paramKeyToAttrMap ...map
if len(paramKeyToAttrMap) > 0 {
keyToAttributeNameMapping = paramKeyToAttrMap[0]
}
// Handle different destination types
switch dstPointerReflectTypeElemKind {
case reflect.Map:
// Convert map to map
return doMapToMap(srcValue, dstPointer, paramKeyToAttrMap...)
case reflect.Array, reflect.Slice:
@ -102,53 +227,59 @@ func Scan(srcValue interface{}, dstPointer interface{}, paramKeyToAttrMap ...map
sliceElem = dstPointerReflectTypeElem.Elem()
sliceElemKind = sliceElem.Kind()
)
// Handle pointer elements
for sliceElemKind == reflect.Ptr {
sliceElem = sliceElem.Elem()
sliceElemKind = sliceElem.Kind()
}
if sliceElemKind == reflect.Map {
// Convert to slice of maps
return doMapToMaps(srcValue, dstPointer, paramKeyToAttrMap...)
}
// Convert to slice of structs
return doStructs(srcValue, dstPointer, keyToAttributeNameMapping, "")
default:
// Convert to single struct
return doStruct(srcValue, dstPointer, keyToAttributeNameMapping, "")
}
}
// doConvertWithTypeCheck supports `pointer` in type of `*map/*[]map/*[]*map/*struct/**struct/*[]struct/*[]*struct`
// for converting.
func doConvertWithTypeCheck(srcValueReflectValue, dstPointerReflectValueElem reflect.Value) (ok bool) {
if !dstPointerReflectValueElem.IsValid() || !srcValueReflectValue.IsValid() {
return false
}
switch {
// Example:
// UploadFile => UploadFile
// []UploadFile => []UploadFile
// *UploadFile => *UploadFile
// *[]UploadFile => *[]UploadFile
// map => map
// []map => []map
// *[]map => *[]map
// Examples:
// UploadFile => UploadFile
// []UploadFile => []UploadFile
// *UploadFile => *UploadFile
// *[]UploadFile => *[]UploadFile
// map[int][int] => map[int][int]
// []map[int][int] => []map[int][int]
// *[]map[int][int] => *[]map[int][int]
case dstPointerReflectValueElem.Type() == srcValueReflectValue.Type():
dstPointerReflectValueElem.Set(srcValueReflectValue)
return true
// Example:
// UploadFile => *UploadFile
// []UploadFile => *[]UploadFile
// map => *map
// []map => *[]map
// Examples:
// UploadFile => *UploadFile
// []UploadFile => *[]UploadFile
// map[int][int] => *map[int][int]
// []map[int][int] => *[]map[int][int]
case dstPointerReflectValueElem.Kind() == reflect.Ptr &&
dstPointerReflectValueElem.Elem().IsValid() &&
dstPointerReflectValueElem.Elem().Type() == srcValueReflectValue.Type():
dstPointerReflectValueElem.Elem().Set(srcValueReflectValue)
return true
// Example:
// *UploadFile => UploadFile
// *[]UploadFile => []UploadFile
// *map => map
// *[]map => []map
// Examples:
// *UploadFile => UploadFile
// *[]UploadFile => []UploadFile
// *map[int][int] => map[int][int]
// *[]map[int][int] => []map[int][int]
case srcValueReflectValue.Kind() == reflect.Ptr &&
srcValueReflectValue.Elem().IsValid() &&
dstPointerReflectValueElem.Type() == srcValueReflectValue.Elem().Type():
@ -160,9 +291,18 @@ func doConvertWithTypeCheck(srcValueReflectValue, dstPointerReflectValueElem ref
}
}
// doConvertWithJsonCheck does json converting check.
// If given `params` is JSON, it then uses json.Unmarshal doing the converting.
func doConvertWithJsonCheck(srcValue interface{}, dstPointer interface{}) (ok bool, err error) {
// doConvertWithJsonCheck attempts to convert the source value to the destination
// using JSON marshaling and unmarshaling. This is particularly useful for complex
// types that can be represented as JSON.
//
// Parameters:
// - srcValue: The source value to convert from
// - dstPointer: The destination pointer to convert to
//
// Returns:
// - bool: true if JSON conversion was successful
// - error: any error that occurred during conversion
func doConvertWithJsonCheck(srcValue any, dstPointer any) (ok bool, err error) {
switch valueResult := srcValue.(type) {
case []byte:
if json.Valid(valueResult) {

View File

@ -12,110 +12,174 @@ import (
"strconv"
"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/util/gconv/internal/localinterface"
)
// Uint converts `any` to uint.
func Uint(any interface{}) uint {
func Uint(any any) uint {
v, _ := doUint(any)
return v
}
func doUint(any any) (uint, error) {
if any == nil {
return 0
return 0, nil
}
if v, ok := any.(uint); ok {
return v
return v, nil
}
return uint(Uint64(any))
v, err := doUint64(any)
return uint(v), err
}
// Uint8 converts `any` to uint8.
func Uint8(any interface{}) uint8 {
func Uint8(any any) uint8 {
v, _ := doUint8(any)
return v
}
func doUint8(any any) (uint8, error) {
if any == nil {
return 0
return 0, nil
}
if v, ok := any.(uint8); ok {
return v
return v, nil
}
return uint8(Uint64(any))
v, err := doUint64(any)
return uint8(v), err
}
// Uint16 converts `any` to uint16.
func Uint16(any interface{}) uint16 {
func Uint16(any any) uint16 {
v, _ := doUint16(any)
return v
}
func doUint16(any any) (uint16, error) {
if any == nil {
return 0
return 0, nil
}
if v, ok := any.(uint16); ok {
return v
return v, nil
}
return uint16(Uint64(any))
v, err := doUint64(any)
return uint16(v), err
}
// Uint32 converts `any` to uint32.
func Uint32(any interface{}) uint32 {
func Uint32(any any) uint32 {
v, _ := doUint32(any)
return v
}
func doUint32(any any) (uint32, error) {
if any == nil {
return 0
return 0, nil
}
if v, ok := any.(uint32); ok {
return v
return v, nil
}
return uint32(Uint64(any))
v, err := doUint64(any)
return uint32(v), err
}
// Uint64 converts `any` to uint64.
func Uint64(any interface{}) uint64 {
func Uint64(any any) uint64 {
v, _ := doUint64(any)
return v
}
func doUint64(any any) (uint64, error) {
if any == nil {
return 0
return 0, nil
}
if v, ok := any.(uint64); ok {
return v, nil
}
rv := reflect.ValueOf(any)
switch rv.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return uint64(rv.Int())
val := rv.Int()
if val < 0 {
return uint64(val), gerror.NewCodef(
gcode.CodeInvalidParameter,
`cannot convert negative value "%d" to uint64`,
val,
)
}
return uint64(val), nil
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
return uint64(rv.Uint())
return rv.Uint(), nil
case reflect.Uintptr:
return uint64(rv.Uint())
return rv.Uint(), nil
case reflect.Float32, reflect.Float64:
return uint64(rv.Float())
val := rv.Float()
if val < 0 {
return uint64(val), gerror.NewCodef(
gcode.CodeInvalidParameter,
`cannot convert negative value "%f" to uint64`,
val,
)
}
return uint64(val), nil
case reflect.Bool:
if rv.Bool() {
return 1
return 1, nil
}
return 0
return 0, nil
case reflect.Ptr:
if rv.IsNil() {
return 0
return 0, nil
}
if f, ok := any.(localinterface.IUint64); ok {
return f.Uint64()
return f.Uint64(), nil
}
return Uint64(rv.Elem().Interface())
return doUint64(rv.Elem().Interface())
case reflect.Slice:
// TODOThese types should be panic
if rv.Type().Elem().Kind() == reflect.Uint8 {
return gbinary.DecodeToUint64(rv.Bytes())
return gbinary.DecodeToUint64(rv.Bytes()), nil
}
case reflect.String:
var (
s = rv.String()
return 0, gerror.NewCodef(
gcode.CodeInvalidParameter,
`unsupport slice type "%s" for converting to uint64`,
rv.Type().String(),
)
case reflect.String:
var s = rv.String()
// Hexadecimal
if len(s) > 2 && s[0] == '0' && (s[1] == 'x' || s[1] == 'X') {
if v, e := strconv.ParseUint(s[2:], 16, 64); e == nil {
return v
v, err := strconv.ParseUint(s[2:], 16, 64)
if err == nil {
return v, nil
}
return 0, gerror.WrapCodef(
gcode.CodeInvalidParameter,
err,
`cannot convert hexadecimal string "%s" to uint64`,
s,
)
}
// Decimal
if v, e := strconv.ParseUint(s, 10, 64); e == nil {
return v
if v, err := strconv.ParseUint(s, 10, 64); err == nil {
return v, nil
}
// Float64
if valueFloat64 := Float64(any); math.IsNaN(valueFloat64) {
return 0
} else {
return uint64(valueFloat64)
if v, err := doFloat64(any); err == nil {
if math.IsNaN(v) {
return 0, nil
}
return uint64(v), nil
}
default:
if f, ok := any.(localinterface.IUint64); ok {
return f.Uint64()
return f.Uint64(), nil
}
}
return 0
return 0, gerror.NewCodef(
gcode.CodeInvalidParameter,
`unsupport value type "%s" for converting to uint64`,
reflect.TypeOf(any).String(),
)
}

View File

@ -0,0 +1,171 @@
// 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 gconv_test
import (
"testing"
"time"
"github.com/gogf/gf/v2/test/gtest"
"github.com/gogf/gf/v2/util/gconv"
)
type testScan struct {
Src any
Dst any
Expect any
}
func TestScanBasicTypes(t *testing.T) {
// Define test data structure
type User struct {
Name string
Age int
}
type UserWithTag struct {
Name string `json:"name"`
Age int `json:"age"`
}
// Prepare test data
var testScanData = []testScan{
// Basic type conversion
{1, new(int), 1},
{int8(1), new(int16), int16(1)},
{int16(1), new(int32), int32(1)},
{int32(1), new(int64), int64(1)},
{uint(1), new(int), 1},
{uint8(1), new(int), 1},
{uint16(1), new(int), 1},
{uint32(1), new(int), 1},
{uint64(1), new(int), 1},
{float32(1.0), new(int), 1},
{float64(1.0), new(int), 1},
{true, new(int), 1},
{false, new(int), 0},
{"1", new(int), 1},
{"true", new(bool), true},
{"false", new(bool), false},
{1, new(bool), true},
{0, new(bool), false},
// String conversion
{1, new(string), "1"},
{1.1, new(string), "1.1"},
{true, new(string), "true"},
{false, new(string), "false"},
{[]byte("hello"), new(string), "hello"},
// Slice conversion
{[]int{1, 2, 3}, new([]string), []string{"1", "2", "3"}},
{[]string{"1", "2", "3"}, new([]int), []int{1, 2, 3}},
{`["1","2","3"]`, new([]string), []string{"1", "2", "3"}},
{`[1,2,3]`, new([]int), []int{1, 2, 3}},
// Map conversion
{
map[string]interface{}{"name": "john", "age": 18},
new(User),
&User{Name: "john", Age: 18},
},
{
`{"name":"john","age":18}`,
new(User),
&User{Name: "john", Age: 18},
},
{
map[string]interface{}{"name": "john", "age": 18},
new(UserWithTag),
&UserWithTag{Name: "john", Age: 18},
},
{
map[string]string{"name": "john", "age": "18"},
new(map[string]interface{}),
&map[string]interface{}{"name": "john", "age": "18"},
},
// Struct conversion
{
User{Name: "john", Age: 18},
new(map[string]interface{}),
&map[string]interface{}{"Name": "john", "Age": 18},
},
{
&User{Name: "john", Age: 18},
new(UserWithTag),
&UserWithTag{Name: "john", Age: 18},
},
// Special cases
{nil, new(interface{}), nil},
{nil, new(*int), (*int)(nil)},
{[]byte(nil), new(string), ""},
{"", new(int), 0},
{"", new(float64), 0.0},
{"", new(bool), false},
// Time type
{time.Date(2023, 1, 2, 0, 0, 0, 0, time.Local), new(string), "2023-01-02 00:00:00"},
// Pointer conversion
{&User{Name: "john"}, new(*User), &User{Name: "john"}},
}
// Basic types test.
gtest.C(t, func(t *gtest.T) {
for _, v := range testScanData {
// t.Logf(`%#v`, v)
err := gconv.Scan(v.Src, v.Dst)
t.AssertNil(err)
}
})
// int -> **int
gtest.C(t, func(t *gtest.T) {
var (
v = 100
i *int
)
err := gconv.Scan(v, &i)
t.AssertNil(err)
t.AssertNE(i, nil)
t.Assert(*i, v)
})
// *int -> **int
gtest.C(t, func(t *gtest.T) {
var (
v = 100
i *int
)
err := gconv.Scan(&v, &i)
t.AssertNil(err)
t.AssertNE(i, nil)
t.Assert(*i, v)
})
// string -> **string
gtest.C(t, func(t *gtest.T) {
var (
v = "1000"
i *string
)
err := gconv.Scan(v, &i)
t.AssertNil(err)
t.AssertNE(i, nil)
t.Assert(*i, v)
})
// *string -> **string
gtest.C(t, func(t *gtest.T) {
var (
v = "1000"
i *string
)
err := gconv.Scan(&v, &i)
t.AssertNil(err)
t.AssertNE(i, nil)
t.Assert(*i, v)
})
}

View File

@ -362,29 +362,15 @@ func TestScan(t *testing.T) {
mapParameter = map[string]string{"Name": "Place", "Place": "Name"}
)
// TODO: The following test cases should be working, but they are not.
//err = gconv.Scan(test, &scanExpects.mapStrStr, mapParameter)
//t.AssertNil(err)
//t.Assert(test["Name"], scanExpects.mapStrStr["Place"])
//t.Assert(test["Place"], scanExpects.mapStrStr["Name"])
//
//err = gconv.Scan(test, &scanExpects.mapStrAny, mapParameter)
//t.AssertNil(err)
//t.Assert(test["Name"], scanExpects.mapStrAny["Place"])
//t.Assert(test["Place"], scanExpects.mapStrAny["Name"])
//
//err = gconv.Scan(test, &scanExpects.mapAnyAny, mapParameter)
//t.AssertNil(err)
//t.Assert(test["Name"], scanExpects.mapAnyAny["Place"])
//t.Assert(test["Place"], scanExpects.mapAnyAny["Name"])
err = gconv.Scan(test, &scanExpects.structSub, mapParameter)
t.AssertNil(err)
t.Assert(test["Name"], scanExpects.structSub.Place)
t.Assert(test["Place"], scanExpects.structSub.Name)
//t.Logf("%#v", test)
err = gconv.Scan(test, &scanExpects.structSubPtr, mapParameter)
t.AssertNil(err)
//t.Logf("%#v", scanExpects.structSubPtr)
t.Assert(test["Name"], scanExpects.structSubPtr.Place)
t.Assert(test["Place"], scanExpects.structSubPtr.Name)
}

View File

@ -120,8 +120,9 @@ var uintTests = []struct {
func TestUint(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
for _, test := range uintTests {
t.AssertEQ(gconv.Uint(test.value), test.expect)
for _, v := range uintTests {
//t.Logf(`%+v`, v)
t.AssertEQ(gconv.Uint(v.value), v.expect)
}
})
}