mirror of
https://gitee.com/johng/gf.git
synced 2024-11-30 03:07:45 +08:00
fix issue @1380
This commit is contained in:
parent
64a5cedcdf
commit
68e760d13a
@ -14,11 +14,6 @@ import (
|
||||
"github.com/gogf/gf/util/gconv"
|
||||
)
|
||||
|
||||
// Interface converts and returns `r` as type of interface{}.
|
||||
func (r Record) Interface() interface{} {
|
||||
return r
|
||||
}
|
||||
|
||||
// Json converts `r` to JSON format content.
|
||||
func (r Record) Json() string {
|
||||
content, _ := gparser.VarToJson(r.Map())
|
||||
|
@ -13,11 +13,6 @@ import (
|
||||
"math"
|
||||
)
|
||||
|
||||
// Interface converts and returns `r` as type of interface{}.
|
||||
func (r Result) Interface() interface{} {
|
||||
return r
|
||||
}
|
||||
|
||||
// IsEmpty checks and returns whether `r` is empty.
|
||||
func (r Result) IsEmpty() bool {
|
||||
return r.Len() == 0
|
||||
@ -33,7 +28,7 @@ func (r Result) Size() int {
|
||||
return r.Len()
|
||||
}
|
||||
|
||||
// Chunk splits an Result into multiple Results,
|
||||
// Chunk splits a Result into multiple Results,
|
||||
// the size of each array is determined by `size`.
|
||||
// The last chunk may contain less than size elements.
|
||||
func (r Result) Chunk(size int) []Result {
|
||||
|
@ -14,6 +14,7 @@ import (
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/os/gtime"
|
||||
"github.com/gogf/gf/test/gtest"
|
||||
"github.com/gogf/gf/text/gstr"
|
||||
"github.com/gogf/gf/util/gconv"
|
||||
"reflect"
|
||||
"testing"
|
||||
@ -480,3 +481,119 @@ func Test_Scan_AutoFilteringByStructAttributes(t *testing.T) {
|
||||
t.Assert(users[0].Id, 1)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Scan_JsonAttributes(t *testing.T) {
|
||||
type GiftImage struct {
|
||||
Uid string `json:"uid"`
|
||||
Url string `json:"url"`
|
||||
Status string `json:"status"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
type GiftComment struct {
|
||||
Name string `json:"name"`
|
||||
Field string `json:"field"`
|
||||
Required bool `json:"required"`
|
||||
}
|
||||
|
||||
type Prop struct {
|
||||
Name string `json:"name"`
|
||||
Values []string `json:"values"`
|
||||
}
|
||||
|
||||
type Sku struct {
|
||||
GiftId int64 `json:"gift_id"`
|
||||
Name string `json:"name"`
|
||||
ScorePrice int `json:"score_price"`
|
||||
MarketPrice int `json:"market_price"`
|
||||
CostPrice int `json:"cost_price"`
|
||||
Stock int `json:"stock"`
|
||||
}
|
||||
|
||||
type Covers struct {
|
||||
List []GiftImage `json:"list"`
|
||||
}
|
||||
|
||||
type GiftEntity struct {
|
||||
Id int64 `json:"id"`
|
||||
StoreId int64 `json:"store_id"`
|
||||
GiftType int `json:"gift_type"`
|
||||
GiftName string `json:"gift_name"`
|
||||
Description string `json:"description"`
|
||||
Covers Covers `json:"covers"`
|
||||
Cover string `json:"cover"`
|
||||
GiftCategoryId []int64 `json:"gift_category_id"`
|
||||
HasProps bool `json:"has_props"`
|
||||
OutSn string `json:"out_sn"`
|
||||
IsLimitSell bool `json:"is_limit_sell"`
|
||||
LimitSellType int `json:"limit_sell_type"`
|
||||
LimitSellCycle string `json:"limit_sell_cycle"`
|
||||
LimitSellCycleCount int `json:"limit_sell_cycle_count"`
|
||||
LimitSellCustom bool `json:"limit_sell_custom"` // 只允许特定会员兑换
|
||||
LimitCustomerTags []int64 `json:"limit_customer_tags"` // 允许兑换的成员
|
||||
ScorePrice int `json:"score_price"`
|
||||
MarketPrice float64 `json:"market_price"`
|
||||
CostPrice int `json:"cost_price"`
|
||||
Stock int `json:"stock"`
|
||||
Props []Prop `json:"props"`
|
||||
Skus []Sku `json:"skus"`
|
||||
ExpressType []string `json:"express_type"`
|
||||
Comments []GiftComment `json:"comments"`
|
||||
Content string `json:"content"`
|
||||
AtLeastRechargeCount int `json:"at_least_recharge_count"`
|
||||
Status int `json:"status"`
|
||||
}
|
||||
|
||||
type User struct {
|
||||
Id int
|
||||
Passport string
|
||||
}
|
||||
|
||||
var (
|
||||
table = "jfy_gift"
|
||||
)
|
||||
array := gstr.SplitAndTrim(gtest.TestDataContent(`issue1380.sql`), ";")
|
||||
for _, v := range array {
|
||||
if _, err := db.Exec(v); err != nil {
|
||||
gtest.Error(err)
|
||||
}
|
||||
}
|
||||
defer dropTable(table)
|
||||
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
var (
|
||||
entity = new(GiftEntity)
|
||||
err = db.Model(table).Where("id", 17).Scan(entity)
|
||||
)
|
||||
t.AssertNil(err)
|
||||
t.Assert(len(entity.Skus), 2)
|
||||
|
||||
t.Assert(entity.Skus[0].Name, "red")
|
||||
t.Assert(entity.Skus[0].Stock, 10)
|
||||
t.Assert(entity.Skus[0].GiftId, 1)
|
||||
t.Assert(entity.Skus[0].CostPrice, 80)
|
||||
t.Assert(entity.Skus[0].ScorePrice, 188)
|
||||
t.Assert(entity.Skus[0].MarketPrice, 388)
|
||||
|
||||
t.Assert(entity.Skus[1].Name, "blue")
|
||||
t.Assert(entity.Skus[1].Stock, 100)
|
||||
t.Assert(entity.Skus[1].GiftId, 2)
|
||||
t.Assert(entity.Skus[1].CostPrice, 81)
|
||||
t.Assert(entity.Skus[1].ScorePrice, 200)
|
||||
t.Assert(entity.Skus[1].MarketPrice, 288)
|
||||
|
||||
t.Assert(entity.Id, 17)
|
||||
t.Assert(entity.StoreId, 100004)
|
||||
t.Assert(entity.GiftType, 1)
|
||||
t.Assert(entity.GiftName, "GIFT")
|
||||
t.Assert(entity.Description, "支持个性定制的父亲节老师长辈的专属礼物")
|
||||
t.Assert(len(entity.Covers.List), 3)
|
||||
t.Assert(entity.OutSn, "259402")
|
||||
t.Assert(entity.LimitCustomerTags, "[]")
|
||||
t.Assert(entity.ScorePrice, 10)
|
||||
t.Assert(len(entity.Props), 1)
|
||||
t.Assert(len(entity.Comments), 2)
|
||||
t.Assert(entity.Status, 99)
|
||||
t.Assert(entity.Content, `<p>礼品详情</p>`)
|
||||
})
|
||||
}
|
||||
|
35
database/gdb/testdata/issue1380.sql
vendored
Normal file
35
database/gdb/testdata/issue1380.sql
vendored
Normal file
@ -0,0 +1,35 @@
|
||||
CREATE TABLE `jfy_gift` (
|
||||
`id` int(0) UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`gift_name` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '礼品名称',
|
||||
`at_least_recharge_count` int(0) UNSIGNED NOT NULL DEFAULT 1 COMMENT '最少兑换数量',
|
||||
`comments` json NOT NULL COMMENT '礼品留言',
|
||||
`content` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '礼品详情',
|
||||
`cost_price` decimal(10, 2) NULL DEFAULT NULL COMMENT '成本价',
|
||||
`cover` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '封面',
|
||||
`covers` json NOT NULL COMMENT '礼品图片库',
|
||||
`description` varchar(62) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '礼品备注',
|
||||
`express_type` json NOT NULL COMMENT '配送方式',
|
||||
`gift_type` int(0) NOT NULL COMMENT '礼品类型:1:实物;2:虚拟;3:优惠券;4:积分券',
|
||||
`has_props` tinyint(1) NOT NULL DEFAULT 0 COMMENT '是否有多个属性',
|
||||
`is_limit_sell` tinyint(0) UNSIGNED NOT NULL DEFAULT 0 COMMENT '是否限购',
|
||||
`limit_customer_tags` json NOT NULL COMMENT '语序购买的会员标签',
|
||||
`limit_sell_custom` tinyint(0) UNSIGNED NOT NULL DEFAULT 0 COMMENT '是否开启允许购买的会员标签',
|
||||
`limit_sell_cycle` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '限购周期',
|
||||
`limit_sell_cycle_count` int(0) NOT NULL COMMENT '限购期内允许购买的数量',
|
||||
`limit_sell_type` tinyint(0) NOT NULL COMMENT '限购类型',
|
||||
`market_price` decimal(10, 2) NOT NULL COMMENT '市场价',
|
||||
`out_sn` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '内部编码',
|
||||
`props` json NOT NULL COMMENT '规格',
|
||||
`skus` json NOT NULL COMMENT 'SKU',
|
||||
`score_price` decimal(10, 2) NOT NULL COMMENT '兑换所需积分',
|
||||
`stock` int(0) NOT NULL COMMENT '库存',
|
||||
`create_at` datetime(0) NOT NULL COMMENT '创建日期',
|
||||
`store_id` int(0) NOT NULL COMMENT '所属商城',
|
||||
`status` int(0) UNSIGNED NULL DEFAULT 1 COMMENT '1:下架;20:审核中;30:复审中;99:上架',
|
||||
`view_count` int(0) NOT NULL DEFAULT 0 COMMENT '访问量',
|
||||
`sell_count` int(0) NULL DEFAULT 0 COMMENT '销量',
|
||||
PRIMARY KEY (`id`) USING BTREE
|
||||
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
|
||||
|
||||
|
||||
INSERT INTO `jfy_gift` VALUES (17, 'GIFT', 1, '[{\"name\": \"身份证\", \"field\": \"idcard\", \"required\": false}, {\"name\": \"留言2\", \"field\": \"text\", \"required\": false}]', '<p>礼品详情</p>', 0.00, '', '{\"list\": [{\"uid\": \"vc-upload-1629292486099-3\", \"url\": \"https://cdn.taobao.com/sULsYiwaOPjsKGoBXwKtuewPzACpBDfQ.jpg\", \"name\": \"O1CN01OH6PIP1Oc5ot06U17_!!922361725.jpg\", \"status\": \"done\"}, {\"uid\": \"vc-upload-1629292486099-4\", \"url\": \"https://cdn.taobao.com/lqLHDcrFTgNvlWyXfLYZwmsrODzIBtFH.jpg\", \"name\": \"O1CN018hBckI1Oc5ouc8ppl_!!922361725.jpg\", \"status\": \"done\"}, {\"uid\": \"vc-upload-1629292486099-5\", \"url\": \"https://cdn.taobao.com/pvqyutXckICmHhbPBQtrVLHuMlXuGxUg.jpg\", \"name\": \"O1CN0185Ubp91Oc5osQTTcc_!!922361725.jpg\", \"status\": \"done\"}]}', '支持个性定制的父亲节老师长辈的专属礼物', '[\"快递包邮\", \"同城配送\"]', 1, 0, 0, '[]', 0, 'day', 0, 1, 0.00, '259402', '[{\"name\": \"颜色\", \"values\": [\"红色\", \"蓝色\"]}]', '[{\"name\": \"red\", \"stock\": 10, \"gift_id\": 1, \"cost_price\": 80, \"score_price\": 188, \"market_price\": 388}, {\"name\": \"blue\", \"stock\": 100, \"gift_id\": 2, \"cost_price\": 81, \"score_price\": 200, \"market_price\": 288}]', 10.00, 0, '2021-08-18 21:26:13', 100004, 99, 0, 0);
|
@ -219,11 +219,11 @@ func parsePatternItemValue(value string, itemType int) (int, error) {
|
||||
// it converts the value to number according to predefined map.
|
||||
switch itemType {
|
||||
case patternItemTypeWeek:
|
||||
if number, ok := monthMap[strings.ToLower(value)]; ok {
|
||||
if number, ok := weekMap[strings.ToLower(value)]; ok {
|
||||
return number, nil
|
||||
}
|
||||
case patternItemTypeMonth:
|
||||
if number, ok := weekMap[strings.ToLower(value)]; ok {
|
||||
if number, ok := monthMap[strings.ToLower(value)]; ok {
|
||||
return number, nil
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,9 @@ package gtest
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gogf/gf/internal/empty"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
@ -22,7 +24,7 @@ const (
|
||||
pathFilterKey = "/test/gtest/gtest"
|
||||
)
|
||||
|
||||
// C creates an unit testing case.
|
||||
// C creates a unit testing case.
|
||||
// The parameter `t` is the pointer to testing.T of stdlib (*testing.T).
|
||||
// The parameter `f` is the closure function for unit testing case.
|
||||
func C(t *testing.T, f func(t *T)) {
|
||||
@ -35,7 +37,7 @@ func C(t *testing.T, f func(t *T)) {
|
||||
f(&T{t})
|
||||
}
|
||||
|
||||
// Case creates an unit testing case.
|
||||
// Case creates a unit testing case.
|
||||
// The parameter `t` is the pointer to testing.T of stdlib (*testing.T).
|
||||
// The parameter `f` is the closure function for unit testing case.
|
||||
// Deprecated.
|
||||
@ -357,3 +359,28 @@ func AssertNil(value interface{}) {
|
||||
}
|
||||
AssertNE(value, nil)
|
||||
}
|
||||
|
||||
// TestDataPath retrieves and returns the testdata path of current package,
|
||||
// which is used for unit testing cases only.
|
||||
// The optional parameter `names` specifies the sub-folders/sub-files,
|
||||
// which will be joined with current system separator and returned with the path.
|
||||
func TestDataPath(names ...string) string {
|
||||
_, path, _ := gdebug.CallerWithFilter(pathFilterKey)
|
||||
path = filepath.Dir(path) + string(filepath.Separator) + "testdata"
|
||||
for _, name := range names {
|
||||
path += string(filepath.Separator) + name
|
||||
}
|
||||
return path
|
||||
}
|
||||
|
||||
// TestDataContent retrieves and returns the file content for specified testdata path of current package
|
||||
func TestDataContent(names ...string) string {
|
||||
path := TestDataPath(names...)
|
||||
if path != "" {
|
||||
data, err := ioutil.ReadFile(path)
|
||||
if err == nil {
|
||||
return string(data)
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
@ -53,235 +53,235 @@ type doConvertInput struct {
|
||||
Extra []interface{} // Extra values for implementing the converting.
|
||||
}
|
||||
|
||||
// doConvert does commonly used types converting.
|
||||
func doConvert(input doConvertInput) interface{} {
|
||||
switch input.ToTypeName {
|
||||
// doConvert does commonly use types converting.
|
||||
func doConvert(in doConvertInput) interface{} {
|
||||
switch in.ToTypeName {
|
||||
case "int":
|
||||
return Int(input.FromValue)
|
||||
return Int(in.FromValue)
|
||||
case "*int":
|
||||
if _, ok := input.FromValue.(*int); ok {
|
||||
return input.FromValue
|
||||
if _, ok := in.FromValue.(*int); ok {
|
||||
return in.FromValue
|
||||
}
|
||||
v := Int(input.FromValue)
|
||||
v := Int(in.FromValue)
|
||||
return &v
|
||||
|
||||
case "int8":
|
||||
return Int8(input.FromValue)
|
||||
return Int8(in.FromValue)
|
||||
case "*int8":
|
||||
if _, ok := input.FromValue.(*int8); ok {
|
||||
return input.FromValue
|
||||
if _, ok := in.FromValue.(*int8); ok {
|
||||
return in.FromValue
|
||||
}
|
||||
v := Int8(input.FromValue)
|
||||
v := Int8(in.FromValue)
|
||||
return &v
|
||||
|
||||
case "int16":
|
||||
return Int16(input.FromValue)
|
||||
return Int16(in.FromValue)
|
||||
case "*int16":
|
||||
if _, ok := input.FromValue.(*int16); ok {
|
||||
return input.FromValue
|
||||
if _, ok := in.FromValue.(*int16); ok {
|
||||
return in.FromValue
|
||||
}
|
||||
v := Int16(input.FromValue)
|
||||
v := Int16(in.FromValue)
|
||||
return &v
|
||||
|
||||
case "int32":
|
||||
return Int32(input.FromValue)
|
||||
return Int32(in.FromValue)
|
||||
case "*int32":
|
||||
if _, ok := input.FromValue.(*int32); ok {
|
||||
return input.FromValue
|
||||
if _, ok := in.FromValue.(*int32); ok {
|
||||
return in.FromValue
|
||||
}
|
||||
v := Int32(input.FromValue)
|
||||
v := Int32(in.FromValue)
|
||||
return &v
|
||||
|
||||
case "int64":
|
||||
return Int64(input.FromValue)
|
||||
return Int64(in.FromValue)
|
||||
case "*int64":
|
||||
if _, ok := input.FromValue.(*int64); ok {
|
||||
return input.FromValue
|
||||
if _, ok := in.FromValue.(*int64); ok {
|
||||
return in.FromValue
|
||||
}
|
||||
v := Int64(input.FromValue)
|
||||
v := Int64(in.FromValue)
|
||||
return &v
|
||||
|
||||
case "uint":
|
||||
return Uint(input.FromValue)
|
||||
return Uint(in.FromValue)
|
||||
case "*uint":
|
||||
if _, ok := input.FromValue.(*uint); ok {
|
||||
return input.FromValue
|
||||
if _, ok := in.FromValue.(*uint); ok {
|
||||
return in.FromValue
|
||||
}
|
||||
v := Uint(input.FromValue)
|
||||
v := Uint(in.FromValue)
|
||||
return &v
|
||||
|
||||
case "uint8":
|
||||
return Uint8(input.FromValue)
|
||||
return Uint8(in.FromValue)
|
||||
case "*uint8":
|
||||
if _, ok := input.FromValue.(*uint8); ok {
|
||||
return input.FromValue
|
||||
if _, ok := in.FromValue.(*uint8); ok {
|
||||
return in.FromValue
|
||||
}
|
||||
v := Uint8(input.FromValue)
|
||||
v := Uint8(in.FromValue)
|
||||
return &v
|
||||
|
||||
case "uint16":
|
||||
return Uint16(input.FromValue)
|
||||
return Uint16(in.FromValue)
|
||||
case "*uint16":
|
||||
if _, ok := input.FromValue.(*uint16); ok {
|
||||
return input.FromValue
|
||||
if _, ok := in.FromValue.(*uint16); ok {
|
||||
return in.FromValue
|
||||
}
|
||||
v := Uint16(input.FromValue)
|
||||
v := Uint16(in.FromValue)
|
||||
return &v
|
||||
|
||||
case "uint32":
|
||||
return Uint32(input.FromValue)
|
||||
return Uint32(in.FromValue)
|
||||
case "*uint32":
|
||||
if _, ok := input.FromValue.(*uint32); ok {
|
||||
return input.FromValue
|
||||
if _, ok := in.FromValue.(*uint32); ok {
|
||||
return in.FromValue
|
||||
}
|
||||
v := Uint32(input.FromValue)
|
||||
v := Uint32(in.FromValue)
|
||||
return &v
|
||||
|
||||
case "uint64":
|
||||
return Uint64(input.FromValue)
|
||||
return Uint64(in.FromValue)
|
||||
case "*uint64":
|
||||
if _, ok := input.FromValue.(*uint64); ok {
|
||||
return input.FromValue
|
||||
if _, ok := in.FromValue.(*uint64); ok {
|
||||
return in.FromValue
|
||||
}
|
||||
v := Uint64(input.FromValue)
|
||||
v := Uint64(in.FromValue)
|
||||
return &v
|
||||
|
||||
case "float32":
|
||||
return Float32(input.FromValue)
|
||||
return Float32(in.FromValue)
|
||||
case "*float32":
|
||||
if _, ok := input.FromValue.(*float32); ok {
|
||||
return input.FromValue
|
||||
if _, ok := in.FromValue.(*float32); ok {
|
||||
return in.FromValue
|
||||
}
|
||||
v := Float32(input.FromValue)
|
||||
v := Float32(in.FromValue)
|
||||
return &v
|
||||
|
||||
case "float64":
|
||||
return Float64(input.FromValue)
|
||||
return Float64(in.FromValue)
|
||||
case "*float64":
|
||||
if _, ok := input.FromValue.(*float64); ok {
|
||||
return input.FromValue
|
||||
if _, ok := in.FromValue.(*float64); ok {
|
||||
return in.FromValue
|
||||
}
|
||||
v := Float64(input.FromValue)
|
||||
v := Float64(in.FromValue)
|
||||
return &v
|
||||
|
||||
case "bool":
|
||||
return Bool(input.FromValue)
|
||||
return Bool(in.FromValue)
|
||||
case "*bool":
|
||||
if _, ok := input.FromValue.(*bool); ok {
|
||||
return input.FromValue
|
||||
if _, ok := in.FromValue.(*bool); ok {
|
||||
return in.FromValue
|
||||
}
|
||||
v := Bool(input.FromValue)
|
||||
v := Bool(in.FromValue)
|
||||
return &v
|
||||
|
||||
case "string":
|
||||
return String(input.FromValue)
|
||||
return String(in.FromValue)
|
||||
case "*string":
|
||||
if _, ok := input.FromValue.(*string); ok {
|
||||
return input.FromValue
|
||||
if _, ok := in.FromValue.(*string); ok {
|
||||
return in.FromValue
|
||||
}
|
||||
v := String(input.FromValue)
|
||||
v := String(in.FromValue)
|
||||
return &v
|
||||
|
||||
case "[]byte":
|
||||
return Bytes(input.FromValue)
|
||||
return Bytes(in.FromValue)
|
||||
case "[]int":
|
||||
return Ints(input.FromValue)
|
||||
return Ints(in.FromValue)
|
||||
case "[]int32":
|
||||
return Int32s(input.FromValue)
|
||||
return Int32s(in.FromValue)
|
||||
case "[]int64":
|
||||
return Int64s(input.FromValue)
|
||||
return Int64s(in.FromValue)
|
||||
case "[]uint":
|
||||
return Uints(input.FromValue)
|
||||
return Uints(in.FromValue)
|
||||
case "[]uint8":
|
||||
return Bytes(input.FromValue)
|
||||
return Bytes(in.FromValue)
|
||||
case "[]uint32":
|
||||
return Uint32s(input.FromValue)
|
||||
return Uint32s(in.FromValue)
|
||||
case "[]uint64":
|
||||
return Uint64s(input.FromValue)
|
||||
return Uint64s(in.FromValue)
|
||||
case "[]float32":
|
||||
return Float32s(input.FromValue)
|
||||
return Float32s(in.FromValue)
|
||||
case "[]float64":
|
||||
return Float64s(input.FromValue)
|
||||
return Float64s(in.FromValue)
|
||||
case "[]string":
|
||||
return Strings(input.FromValue)
|
||||
return Strings(in.FromValue)
|
||||
|
||||
case "Time", "time.Time":
|
||||
if len(input.Extra) > 0 {
|
||||
return Time(input.FromValue, String(input.Extra[0]))
|
||||
if len(in.Extra) > 0 {
|
||||
return Time(in.FromValue, String(in.Extra[0]))
|
||||
}
|
||||
return Time(input.FromValue)
|
||||
return Time(in.FromValue)
|
||||
case "*time.Time":
|
||||
var v interface{}
|
||||
if len(input.Extra) > 0 {
|
||||
v = Time(input.FromValue, String(input.Extra[0]))
|
||||
if len(in.Extra) > 0 {
|
||||
v = Time(in.FromValue, String(in.Extra[0]))
|
||||
} else {
|
||||
if _, ok := input.FromValue.(*time.Time); ok {
|
||||
return input.FromValue
|
||||
if _, ok := in.FromValue.(*time.Time); ok {
|
||||
return in.FromValue
|
||||
}
|
||||
v = Time(input.FromValue)
|
||||
v = Time(in.FromValue)
|
||||
}
|
||||
return &v
|
||||
|
||||
case "GTime", "gtime.Time":
|
||||
if len(input.Extra) > 0 {
|
||||
if v := GTime(input.FromValue, String(input.Extra[0])); v != nil {
|
||||
if len(in.Extra) > 0 {
|
||||
if v := GTime(in.FromValue, String(in.Extra[0])); v != nil {
|
||||
return *v
|
||||
} else {
|
||||
return *gtime.New()
|
||||
}
|
||||
}
|
||||
if v := GTime(input.FromValue); v != nil {
|
||||
if v := GTime(in.FromValue); v != nil {
|
||||
return *v
|
||||
} else {
|
||||
return *gtime.New()
|
||||
}
|
||||
case "*gtime.Time":
|
||||
if len(input.Extra) > 0 {
|
||||
if v := GTime(input.FromValue, String(input.Extra[0])); v != nil {
|
||||
if len(in.Extra) > 0 {
|
||||
if v := GTime(in.FromValue, String(in.Extra[0])); v != nil {
|
||||
return v
|
||||
} else {
|
||||
return gtime.New()
|
||||
}
|
||||
}
|
||||
if v := GTime(input.FromValue); v != nil {
|
||||
if v := GTime(in.FromValue); v != nil {
|
||||
return v
|
||||
} else {
|
||||
return gtime.New()
|
||||
}
|
||||
|
||||
case "Duration", "time.Duration":
|
||||
return Duration(input.FromValue)
|
||||
return Duration(in.FromValue)
|
||||
case "*time.Duration":
|
||||
if _, ok := input.FromValue.(*time.Duration); ok {
|
||||
return input.FromValue
|
||||
if _, ok := in.FromValue.(*time.Duration); ok {
|
||||
return in.FromValue
|
||||
}
|
||||
v := Duration(input.FromValue)
|
||||
v := Duration(in.FromValue)
|
||||
return &v
|
||||
|
||||
case "map[string]string":
|
||||
return MapStrStr(input.FromValue)
|
||||
return MapStrStr(in.FromValue)
|
||||
|
||||
case "map[string]interface{}":
|
||||
return Map(input.FromValue)
|
||||
return Map(in.FromValue)
|
||||
|
||||
case "[]map[string]interface{}":
|
||||
return Maps(input.FromValue)
|
||||
return Maps(in.FromValue)
|
||||
|
||||
default:
|
||||
if input.ReferValue != nil {
|
||||
if in.ReferValue != nil {
|
||||
var (
|
||||
referReflectValue reflect.Value
|
||||
)
|
||||
if v, ok := input.ReferValue.(reflect.Value); ok {
|
||||
if v, ok := in.ReferValue.(reflect.Value); ok {
|
||||
referReflectValue = v
|
||||
} else {
|
||||
referReflectValue = reflect.ValueOf(input.ReferValue)
|
||||
referReflectValue = reflect.ValueOf(in.ReferValue)
|
||||
}
|
||||
input.ToTypeName = referReflectValue.Kind().String()
|
||||
input.ReferValue = nil
|
||||
return reflect.ValueOf(doConvert(input)).Convert(referReflectValue.Type()).Interface()
|
||||
in.ToTypeName = referReflectValue.Kind().String()
|
||||
in.ReferValue = nil
|
||||
return reflect.ValueOf(doConvert(in)).Convert(referReflectValue.Type()).Interface()
|
||||
}
|
||||
return input.FromValue
|
||||
return in.FromValue
|
||||
}
|
||||
}
|
||||
|
||||
@ -786,3 +786,22 @@ func Float64(any interface{}) float64 {
|
||||
return v
|
||||
}
|
||||
}
|
||||
|
||||
// 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) {
|
||||
_ = json.UnmarshalUseNumber(r, &target)
|
||||
return true
|
||||
}
|
||||
|
||||
case string:
|
||||
anyAsBytes := []byte(r)
|
||||
if json.Valid(anyAsBytes) {
|
||||
_ = json.UnmarshalUseNumber(anyAsBytes, &target)
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
@ -48,6 +48,11 @@ type apiBytes interface {
|
||||
Bytes() []byte
|
||||
}
|
||||
|
||||
// apiInterface is used for type assert api for Interface().
|
||||
type apiInterface interface {
|
||||
Interface() interface{}
|
||||
}
|
||||
|
||||
// apiInterfaces is used for type assert api for Interfaces().
|
||||
type apiInterfaces interface {
|
||||
Interfaces() []interface{}
|
||||
|
@ -99,7 +99,7 @@ func doMapToMap(params interface{}, pointer interface{}, mapping ...map[string]s
|
||||
if e, ok := exception.(errorStack); ok {
|
||||
err = e
|
||||
} else {
|
||||
err = gerror.NewCodeSkipf(gcode.CodeInternalError, 1, "%v", exception)
|
||||
err = gerror.NewCodeSkipf(gcode.CodeInternalError, 1, "%+v", exception)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
@ -119,7 +119,7 @@ func doMapToMaps(params interface{}, pointer interface{}, mapping ...map[string]
|
||||
if e, ok := exception.(errorStack); ok {
|
||||
err = e
|
||||
} else {
|
||||
err = gerror.NewCodeSkipf(gcode.CodeInternalError, 1, "%v", exception)
|
||||
err = gerror.NewCodeSkipf(gcode.CodeInternalError, 1, "%+v", exception)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
@ -118,6 +118,11 @@ func Float32s(any interface{}) []float32 {
|
||||
if v, ok := any.(apiInterfaces); ok {
|
||||
return Float32s(v.Interfaces())
|
||||
}
|
||||
// JSON format string value converting.
|
||||
var result []float32
|
||||
if checkJsonAndUnmarshalUseNumber(any, &result) {
|
||||
return result
|
||||
}
|
||||
// Not a common type, it then uses reflection for conversion.
|
||||
var reflectValue reflect.Value
|
||||
if v, ok := value.(reflect.Value); ok {
|
||||
@ -142,6 +147,9 @@ func Float32s(any interface{}) []float32 {
|
||||
return slice
|
||||
|
||||
default:
|
||||
if reflectValue.IsZero() {
|
||||
return []float32{}
|
||||
}
|
||||
return []float32{Float32(any)}
|
||||
}
|
||||
}
|
||||
@ -238,6 +246,11 @@ func Float64s(any interface{}) []float64 {
|
||||
if v, ok := any.(apiInterfaces); ok {
|
||||
return Floats(v.Interfaces())
|
||||
}
|
||||
// JSON format string value converting.
|
||||
var result []float64
|
||||
if checkJsonAndUnmarshalUseNumber(any, &result) {
|
||||
return result
|
||||
}
|
||||
// Not a common type, it then uses reflection for conversion.
|
||||
var reflectValue reflect.Value
|
||||
if v, ok := value.(reflect.Value); ok {
|
||||
@ -262,6 +275,9 @@ func Float64s(any interface{}) []float64 {
|
||||
return slice
|
||||
|
||||
default:
|
||||
if reflectValue.IsZero() {
|
||||
return []float64{}
|
||||
}
|
||||
return []float64{Float64(any)}
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,9 @@
|
||||
|
||||
package gconv
|
||||
|
||||
import "reflect"
|
||||
import (
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// SliceInt is alias of Ints.
|
||||
func SliceInt(any interface{}) []int {
|
||||
@ -18,7 +20,7 @@ func SliceInt32(any interface{}) []int32 {
|
||||
return Int32s(any)
|
||||
}
|
||||
|
||||
// SliceInt is alias of Int64s.
|
||||
// SliceInt64 is alias of Int64s.
|
||||
func SliceInt64(any interface{}) []int64 {
|
||||
return Int64s(any)
|
||||
}
|
||||
@ -30,11 +32,6 @@ func Ints(any interface{}) []int {
|
||||
}
|
||||
var array []int
|
||||
switch value := any.(type) {
|
||||
case string:
|
||||
if value == "" {
|
||||
return []int{}
|
||||
}
|
||||
return []int{Int(value)}
|
||||
case []string:
|
||||
array = make([]int, len(value))
|
||||
for k, v := range value {
|
||||
@ -123,6 +120,11 @@ func Ints(any interface{}) []int {
|
||||
if v, ok := any.(apiInterfaces); ok {
|
||||
return Ints(v.Interfaces())
|
||||
}
|
||||
// JSON format string value converting.
|
||||
var result []int
|
||||
if checkJsonAndUnmarshalUseNumber(any, &result) {
|
||||
return result
|
||||
}
|
||||
// Not a common type, it then uses reflection for conversion.
|
||||
var reflectValue reflect.Value
|
||||
if v, ok := value.(reflect.Value); ok {
|
||||
@ -147,6 +149,9 @@ func Ints(any interface{}) []int {
|
||||
return slice
|
||||
|
||||
default:
|
||||
if reflectValue.IsZero() {
|
||||
return []int{}
|
||||
}
|
||||
return []int{Int(any)}
|
||||
}
|
||||
}
|
||||
@ -160,11 +165,6 @@ func Int32s(any interface{}) []int32 {
|
||||
}
|
||||
var array []int32
|
||||
switch value := any.(type) {
|
||||
case string:
|
||||
if value == "" {
|
||||
return []int32{}
|
||||
}
|
||||
return []int32{Int32(value)}
|
||||
case []string:
|
||||
array = make([]int32, len(value))
|
||||
for k, v := range value {
|
||||
@ -253,6 +253,11 @@ func Int32s(any interface{}) []int32 {
|
||||
if v, ok := any.(apiInterfaces); ok {
|
||||
return Int32s(v.Interfaces())
|
||||
}
|
||||
// JSON format string value converting.
|
||||
var result []int32
|
||||
if checkJsonAndUnmarshalUseNumber(any, &result) {
|
||||
return result
|
||||
}
|
||||
// Not a common type, it then uses reflection for conversion.
|
||||
var reflectValue reflect.Value
|
||||
if v, ok := value.(reflect.Value); ok {
|
||||
@ -277,6 +282,9 @@ func Int32s(any interface{}) []int32 {
|
||||
return slice
|
||||
|
||||
default:
|
||||
if reflectValue.IsZero() {
|
||||
return []int32{}
|
||||
}
|
||||
return []int32{Int32(any)}
|
||||
}
|
||||
}
|
||||
@ -290,11 +298,6 @@ func Int64s(any interface{}) []int64 {
|
||||
}
|
||||
var array []int64
|
||||
switch value := any.(type) {
|
||||
case string:
|
||||
if value == "" {
|
||||
return []int64{}
|
||||
}
|
||||
return []int64{Int64(value)}
|
||||
case []string:
|
||||
array = make([]int64, len(value))
|
||||
for k, v := range value {
|
||||
@ -383,6 +386,11 @@ func Int64s(any interface{}) []int64 {
|
||||
if v, ok := any.(apiInterfaces); ok {
|
||||
return Int64s(v.Interfaces())
|
||||
}
|
||||
// JSON format string value converting.
|
||||
var result []int64
|
||||
if checkJsonAndUnmarshalUseNumber(any, &result) {
|
||||
return result
|
||||
}
|
||||
// Not a common type, it then uses reflection for conversion.
|
||||
var reflectValue reflect.Value
|
||||
if v, ok := value.(reflect.Value); ok {
|
||||
@ -407,6 +415,9 @@ func Int64s(any interface{}) []int64 {
|
||||
return slice
|
||||
|
||||
default:
|
||||
if reflectValue.IsZero() {
|
||||
return []int64{}
|
||||
}
|
||||
return []int64{Int64(any)}
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,9 @@
|
||||
|
||||
package gconv
|
||||
|
||||
import "reflect"
|
||||
import (
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// SliceStr is alias of Strings.
|
||||
func SliceStr(any interface{}) []string {
|
||||
@ -104,6 +106,11 @@ func Strings(any interface{}) []string {
|
||||
if v, ok := any.(apiInterfaces); ok {
|
||||
return Strings(v.Interfaces())
|
||||
}
|
||||
// JSON format string value converting.
|
||||
var result []string
|
||||
if checkJsonAndUnmarshalUseNumber(any, &result) {
|
||||
return result
|
||||
}
|
||||
// Not a common type, it then uses reflection for conversion.
|
||||
var reflectValue reflect.Value
|
||||
if v, ok := value.(reflect.Value); ok {
|
||||
@ -128,6 +135,9 @@ func Strings(any interface{}) []string {
|
||||
return slice
|
||||
|
||||
default:
|
||||
if reflectValue.IsZero() {
|
||||
return []string{}
|
||||
}
|
||||
return []string{String(any)}
|
||||
}
|
||||
}
|
||||
|
@ -119,6 +119,11 @@ func Uints(any interface{}) []uint {
|
||||
if v, ok := any.(apiInterfaces); ok {
|
||||
return Uints(v.Interfaces())
|
||||
}
|
||||
// JSON format string value converting.
|
||||
var result []uint
|
||||
if checkJsonAndUnmarshalUseNumber(any, &result) {
|
||||
return result
|
||||
}
|
||||
// Not a common type, it then uses reflection for conversion.
|
||||
var reflectValue reflect.Value
|
||||
if v, ok := value.(reflect.Value); ok {
|
||||
@ -143,6 +148,9 @@ func Uints(any interface{}) []uint {
|
||||
return slice
|
||||
|
||||
default:
|
||||
if reflectValue.IsZero() {
|
||||
return []uint{}
|
||||
}
|
||||
return []uint{Uint(any)}
|
||||
}
|
||||
}
|
||||
@ -244,6 +252,11 @@ func Uint32s(any interface{}) []uint32 {
|
||||
if v, ok := any.(apiInterfaces); ok {
|
||||
return Uint32s(v.Interfaces())
|
||||
}
|
||||
// JSON format string value converting.
|
||||
var result []uint32
|
||||
if checkJsonAndUnmarshalUseNumber(any, &result) {
|
||||
return result
|
||||
}
|
||||
// Not a common type, it then uses reflection for conversion.
|
||||
var reflectValue reflect.Value
|
||||
if v, ok := value.(reflect.Value); ok {
|
||||
@ -268,6 +281,9 @@ func Uint32s(any interface{}) []uint32 {
|
||||
return slice
|
||||
|
||||
default:
|
||||
if reflectValue.IsZero() {
|
||||
return []uint32{}
|
||||
}
|
||||
return []uint32{Uint32(any)}
|
||||
}
|
||||
}
|
||||
@ -369,6 +385,11 @@ func Uint64s(any interface{}) []uint64 {
|
||||
if v, ok := any.(apiInterfaces); ok {
|
||||
return Uint64s(v.Interfaces())
|
||||
}
|
||||
// JSON format string value converting.
|
||||
var result []uint64
|
||||
if checkJsonAndUnmarshalUseNumber(any, &result) {
|
||||
return result
|
||||
}
|
||||
// Not a common type, it then uses reflection for conversion.
|
||||
var reflectValue reflect.Value
|
||||
if v, ok := value.(reflect.Value); ok {
|
||||
@ -393,6 +414,9 @@ func Uint64s(any interface{}) []uint64 {
|
||||
return slice
|
||||
|
||||
default:
|
||||
if reflectValue.IsZero() {
|
||||
return []uint64{}
|
||||
}
|
||||
return []uint64{Uint64(any)}
|
||||
}
|
||||
}
|
||||
|
@ -52,6 +52,42 @@ func StructDeep(params interface{}, pointer interface{}, mapping ...map[string]s
|
||||
return doStruct(params, pointer, keyToAttributeNameMapping, "")
|
||||
}
|
||||
|
||||
// doStructWithJsonCheck checks if given `params` is JSON, it then uses json.Unmarshal doing the converting.
|
||||
func doStructWithJsonCheck(params interface{}, pointer interface{}) (err error, ok bool) {
|
||||
switch r := params.(type) {
|
||||
case []byte:
|
||||
if json.Valid(r) {
|
||||
if rv, ok := pointer.(reflect.Value); ok {
|
||||
if rv.Kind() == reflect.Ptr {
|
||||
return json.UnmarshalUseNumber(r, rv.Interface()), true
|
||||
} else if rv.CanAddr() {
|
||||
return json.UnmarshalUseNumber(r, rv.Addr().Interface()), true
|
||||
}
|
||||
} else {
|
||||
return json.UnmarshalUseNumber(r, pointer), true
|
||||
}
|
||||
}
|
||||
case string:
|
||||
if paramsBytes := []byte(r); json.Valid(paramsBytes) {
|
||||
if rv, ok := pointer.(reflect.Value); ok {
|
||||
if rv.Kind() == reflect.Ptr {
|
||||
return json.UnmarshalUseNumber(paramsBytes, rv.Interface()), true
|
||||
} else if rv.CanAddr() {
|
||||
return json.UnmarshalUseNumber(paramsBytes, rv.Addr().Interface()), true
|
||||
}
|
||||
} else {
|
||||
return json.UnmarshalUseNumber(paramsBytes, pointer), true
|
||||
}
|
||||
}
|
||||
default:
|
||||
// The `params` might be struct that implements interface function Interface, eg: gvar.Var.
|
||||
if v, ok := params.(apiInterface); ok {
|
||||
return doStructWithJsonCheck(v.Interface(), pointer)
|
||||
}
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// doStruct is the core internal converting function for any data to struct.
|
||||
func doStruct(params interface{}, pointer interface{}, mapping map[string]string, priorityTag string) (err error) {
|
||||
if params == nil {
|
||||
@ -63,47 +99,28 @@ func doStruct(params interface{}, pointer interface{}, mapping map[string]string
|
||||
}
|
||||
|
||||
defer func() {
|
||||
// Catch the panic, especially the reflect operation panics.
|
||||
// Catch the panic, especially the reflection operation panics.
|
||||
if exception := recover(); exception != nil {
|
||||
if e, ok := exception.(errorStack); ok {
|
||||
err = e
|
||||
} else {
|
||||
err = gerror.NewCodeSkipf(gcode.CodeInternalError, 1, "%v", exception)
|
||||
err = gerror.NewCodeSkipf(gcode.CodeInternalError, 1, "%+v", exception)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
// If given `params` is JSON, it then uses json.Unmarshal doing the converting.
|
||||
switch r := params.(type) {
|
||||
case []byte:
|
||||
if json.Valid(r) {
|
||||
if rv, ok := pointer.(reflect.Value); ok {
|
||||
if rv.Kind() == reflect.Ptr {
|
||||
return json.UnmarshalUseNumber(r, rv.Interface())
|
||||
} else if rv.CanAddr() {
|
||||
return json.UnmarshalUseNumber(r, rv.Addr().Interface())
|
||||
}
|
||||
} else {
|
||||
return json.UnmarshalUseNumber(r, pointer)
|
||||
}
|
||||
}
|
||||
case string:
|
||||
if paramsBytes := []byte(r); json.Valid(paramsBytes) {
|
||||
if rv, ok := pointer.(reflect.Value); ok {
|
||||
if rv.Kind() == reflect.Ptr {
|
||||
return json.UnmarshalUseNumber(paramsBytes, rv.Interface())
|
||||
} else if rv.CanAddr() {
|
||||
return json.UnmarshalUseNumber(paramsBytes, rv.Addr().Interface())
|
||||
}
|
||||
} else {
|
||||
return json.UnmarshalUseNumber(paramsBytes, pointer)
|
||||
}
|
||||
// JSON content converting.
|
||||
err, ok := doStructWithJsonCheck(params, pointer)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
var (
|
||||
paramsReflectValue reflect.Value
|
||||
paramsInterface interface{} // DO NOT use `params` directly as it might be type of `reflect.Value`
|
||||
paramsInterface interface{} // DO NOT use `params` directly as it might be type `reflect.Value`
|
||||
pointerReflectValue reflect.Value
|
||||
pointerReflectKind reflect.Kind
|
||||
pointerElemReflectValue reflect.Value // The pointed element.
|
||||
@ -129,6 +146,7 @@ func doStruct(params interface{}, pointer interface{}, mapping map[string]string
|
||||
}
|
||||
pointerElemReflectValue = pointerReflectValue.Elem()
|
||||
}
|
||||
|
||||
// If `params` and `pointer` are the same type, the do directly assignment.
|
||||
// For performance enhancement purpose.
|
||||
if pointerElemReflectValue.IsValid() && pointerElemReflectValue.Type() == paramsReflectValue.Type() {
|
||||
@ -284,7 +302,7 @@ func doStruct(params interface{}, pointer interface{}, mapping map[string]string
|
||||
}
|
||||
// Mark it done.
|
||||
doneMap[attrName] = struct{}{}
|
||||
if err := bindVarToStructAttr(pointerElemReflectValue, attrName, mapV, mapping, priorityTag); err != nil {
|
||||
if err := bindVarToStructAttr(pointerElemReflectValue, attrName, mapV, mapping); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@ -292,7 +310,7 @@ func doStruct(params interface{}, pointer interface{}, mapping map[string]string
|
||||
}
|
||||
|
||||
// bindVarToStructAttr sets value to struct object attribute by name.
|
||||
func bindVarToStructAttr(elem reflect.Value, name string, value interface{}, mapping map[string]string, priorityTag string) (err error) {
|
||||
func bindVarToStructAttr(elem reflect.Value, name string, value interface{}, mapping map[string]string) (err error) {
|
||||
structFieldValue := elem.FieldByName(name)
|
||||
if !structFieldValue.IsValid() {
|
||||
return nil
|
||||
@ -303,7 +321,7 @@ func bindVarToStructAttr(elem reflect.Value, name string, value interface{}, map
|
||||
}
|
||||
defer func() {
|
||||
if exception := recover(); exception != nil {
|
||||
if err = bindVarToReflectValue(structFieldValue, value, mapping, priorityTag); err != nil {
|
||||
if err = bindVarToReflectValue(structFieldValue, value, mapping); err != nil {
|
||||
err = gerror.WrapCodef(gcode.CodeInternalError, err, `error binding value to attribute "%s"`, name)
|
||||
}
|
||||
}
|
||||
@ -323,7 +341,7 @@ func bindVarToStructAttr(elem reflect.Value, name string, value interface{}, map
|
||||
return nil
|
||||
}
|
||||
|
||||
// bindVarToReflectValueWithInterfaceCheck does binding using common interfaces checks.
|
||||
// bindVarToReflectValueWithInterfaceCheck does bind using common interfaces checks.
|
||||
func bindVarToReflectValueWithInterfaceCheck(reflectValue reflect.Value, value interface{}) (err error, ok bool) {
|
||||
var pointer interface{}
|
||||
if reflectValue.Kind() != reflect.Ptr && reflectValue.CanAddr() {
|
||||
@ -384,10 +402,21 @@ func bindVarToReflectValueWithInterfaceCheck(reflectValue reflect.Value, value i
|
||||
}
|
||||
|
||||
// bindVarToReflectValue sets `value` to reflect value object `structFieldValue`.
|
||||
func bindVarToReflectValue(structFieldValue reflect.Value, value interface{}, mapping map[string]string, priorityTag string) (err error) {
|
||||
func bindVarToReflectValue(structFieldValue reflect.Value, value interface{}, mapping map[string]string) (err error) {
|
||||
// JSON content converting.
|
||||
err, ok := doStructWithJsonCheck(value, structFieldValue)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Common interface check.
|
||||
if err, ok := bindVarToReflectValueWithInterfaceCheck(structFieldValue, value); ok {
|
||||
return err
|
||||
}
|
||||
|
||||
kind := structFieldValue.Kind()
|
||||
// Converting using interface, for some kinds.
|
||||
switch kind {
|
||||
@ -407,7 +436,7 @@ func bindVarToReflectValue(structFieldValue reflect.Value, value interface{}, ma
|
||||
|
||||
case reflect.Struct:
|
||||
// Recursively converting for struct attribute.
|
||||
if err := doStruct(value, structFieldValue, nil, ""); err != nil {
|
||||
if err = doStruct(value, structFieldValue, nil, ""); err != nil {
|
||||
// Note there's reflect conversion mechanism here.
|
||||
structFieldValue.Set(reflect.ValueOf(value).Convert(structFieldValue.Type()))
|
||||
}
|
||||
@ -424,14 +453,14 @@ func bindVarToReflectValue(structFieldValue reflect.Value, value interface{}, ma
|
||||
for i := 0; i < v.Len(); i++ {
|
||||
if t.Kind() == reflect.Ptr {
|
||||
e := reflect.New(t.Elem()).Elem()
|
||||
if err := doStruct(v.Index(i).Interface(), e, nil, ""); err != nil {
|
||||
if err = doStruct(v.Index(i).Interface(), e, nil, ""); err != nil {
|
||||
// Note there's reflect conversion mechanism here.
|
||||
e.Set(reflect.ValueOf(v.Index(i).Interface()).Convert(t))
|
||||
}
|
||||
a.Index(i).Set(e.Addr())
|
||||
} else {
|
||||
e := reflect.New(t).Elem()
|
||||
if err := doStruct(v.Index(i).Interface(), e, nil, ""); err != nil {
|
||||
if err = doStruct(v.Index(i).Interface(), e, nil, ""); err != nil {
|
||||
// Note there's reflect conversion mechanism here.
|
||||
e.Set(reflect.ValueOf(v.Index(i).Interface()).Convert(t))
|
||||
}
|
||||
@ -443,17 +472,18 @@ func bindVarToReflectValue(structFieldValue reflect.Value, value interface{}, ma
|
||||
a = reflect.MakeSlice(structFieldValue.Type(), 1, 1)
|
||||
t := a.Index(0).Type()
|
||||
if t.Kind() == reflect.Ptr {
|
||||
// Pointer element.
|
||||
e := reflect.New(t.Elem()).Elem()
|
||||
if err := doStruct(value, e, nil, ""); err != nil {
|
||||
if err = doStruct(value, e, nil, ""); err != nil {
|
||||
// Note there's reflect conversion mechanism here.
|
||||
e.Set(reflect.ValueOf(value).Convert(t))
|
||||
}
|
||||
a.Index(0).Set(e.Addr())
|
||||
} else {
|
||||
// Just consider it as struct element. (Although it might be other types but not basic types, eg: map)
|
||||
e := reflect.New(t).Elem()
|
||||
if err := doStruct(value, e, nil, ""); err != nil {
|
||||
// Note there's reflect conversion mechanism here.
|
||||
e.Set(reflect.ValueOf(value).Convert(t))
|
||||
if err = doStruct(value, e, nil, ""); err != nil {
|
||||
return err
|
||||
}
|
||||
a.Index(0).Set(e)
|
||||
}
|
||||
@ -467,7 +497,7 @@ func bindVarToReflectValue(structFieldValue reflect.Value, value interface{}, ma
|
||||
return err
|
||||
}
|
||||
elem := item.Elem()
|
||||
if err = bindVarToReflectValue(elem, value, mapping, priorityTag); err == nil {
|
||||
if err = bindVarToReflectValue(elem, value, mapping); err == nil {
|
||||
structFieldValue.Set(elem.Addr())
|
||||
}
|
||||
|
||||
|
@ -62,7 +62,7 @@ func doStructs(params interface{}, pointer interface{}, mapping map[string]strin
|
||||
if e, ok := exception.(errorStack); ok {
|
||||
err = e
|
||||
} else {
|
||||
err = gerror.NewCodeSkipf(gcode.CodeInternalError, 1, "%v", exception)
|
||||
err = gerror.NewCodeSkipf(gcode.CodeInternalError, 1, "%+v", exception)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
@ -7,6 +7,7 @@
|
||||
package gconv_test
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/container/gvar"
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/test/gtest"
|
||||
"github.com/gogf/gf/util/gconv"
|
||||
@ -193,3 +194,84 @@ func Test_Scan_Maps(t *testing.T) {
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Scan_JsonAttributes(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
type Sku struct {
|
||||
GiftId int64 `json:"gift_id"`
|
||||
Name string `json:"name"`
|
||||
ScorePrice int `json:"score_price"`
|
||||
MarketPrice int `json:"market_price"`
|
||||
CostPrice int `json:"cost_price"`
|
||||
Stock int `json:"stock"`
|
||||
}
|
||||
v := gvar.New(`
|
||||
[
|
||||
{"name": "red", "stock": 10, "gift_id": 1, "cost_price": 80, "score_price": 188, "market_price": 188},
|
||||
{"name": "blue", "stock": 100, "gift_id": 2, "cost_price": 81, "score_price": 200, "market_price": 288}
|
||||
]`)
|
||||
type Product struct {
|
||||
Skus []Sku
|
||||
}
|
||||
var p *Product
|
||||
err := gconv.Scan(g.Map{
|
||||
"Skus": v,
|
||||
}, &p)
|
||||
t.AssertNil(err)
|
||||
t.Assert(len(p.Skus), 2)
|
||||
|
||||
t.Assert(p.Skus[0].Name, "red")
|
||||
t.Assert(p.Skus[0].Stock, 10)
|
||||
t.Assert(p.Skus[0].GiftId, 1)
|
||||
t.Assert(p.Skus[0].CostPrice, 80)
|
||||
t.Assert(p.Skus[0].ScorePrice, 188)
|
||||
t.Assert(p.Skus[0].MarketPrice, 188)
|
||||
|
||||
t.Assert(p.Skus[1].Name, "blue")
|
||||
t.Assert(p.Skus[1].Stock, 100)
|
||||
t.Assert(p.Skus[1].GiftId, 2)
|
||||
t.Assert(p.Skus[1].CostPrice, 81)
|
||||
t.Assert(p.Skus[1].ScorePrice, 200)
|
||||
t.Assert(p.Skus[1].MarketPrice, 288)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Scan_JsonAttributes_StringArray(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
type S struct {
|
||||
Array []string
|
||||
}
|
||||
var s *S
|
||||
err := gconv.Scan(g.Map{
|
||||
"Array": `["a", "b"]`,
|
||||
}, &s)
|
||||
t.AssertNil(err)
|
||||
t.Assert(len(s.Array), 2)
|
||||
t.Assert(s.Array[0], "a")
|
||||
t.Assert(s.Array[1], "b")
|
||||
})
|
||||
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
type S struct {
|
||||
Array []string
|
||||
}
|
||||
var s *S
|
||||
err := gconv.Scan(g.Map{
|
||||
"Array": `[]`,
|
||||
}, &s)
|
||||
t.AssertNil(err)
|
||||
t.Assert(len(s.Array), 0)
|
||||
})
|
||||
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
type S struct {
|
||||
Array []int64
|
||||
}
|
||||
var s *S
|
||||
err := gconv.Scan(g.Map{
|
||||
"Array": `[]`,
|
||||
}, &s)
|
||||
t.AssertNil(err)
|
||||
t.Assert(len(s.Array), 0)
|
||||
})
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user