From bc53f265af35efd1c70f27cc6ef233f92dd06447 Mon Sep 17 00:00:00 2001 From: John Date: Fri, 3 Jan 2020 20:23:10 +0800 Subject: [PATCH] improve gconv.Map/String --- .../net/ghttp/server/request/struct/parse1.go | 25 +++++++++++++ .../net/ghttp/server/request/struct/parse2.go | 36 +++++++++++++++++++ .example/other/test.go | 15 +++----- database/gdb/gdb_unit_z_mysql_method_test.go | 14 ++++---- util/gconv/gconv.go | 22 ++++++++++-- util/gconv/gconv_map.go | 29 ++++++--------- util/gconv/gconv_z_all_test.go | 1 - 7 files changed, 105 insertions(+), 37 deletions(-) create mode 100644 .example/net/ghttp/server/request/struct/parse1.go create mode 100644 .example/net/ghttp/server/request/struct/parse2.go diff --git a/.example/net/ghttp/server/request/struct/parse1.go b/.example/net/ghttp/server/request/struct/parse1.go new file mode 100644 index 000000000..4018bfa97 --- /dev/null +++ b/.example/net/ghttp/server/request/struct/parse1.go @@ -0,0 +1,25 @@ +package main + +import ( + "github.com/gogf/gf/frame/g" + "github.com/gogf/gf/net/ghttp" +) + +func main() { + type User struct { + Id int `json:"id"` + Name string `json:"name"` + Pass1 string `json:"password1" p:"password1"` + Pass2 string `json:"password2" p:"password2"` + } + s := g.Server() + s.BindHandler("/", func(r *ghttp.Request) { + var user *User + if err := r.Parse(&user); err != nil { + r.Response.WriteExit(err) + } + r.Response.WriteExit(user) + }) + s.SetPort(8199) + s.Run() +} diff --git a/.example/net/ghttp/server/request/struct/parse2.go b/.example/net/ghttp/server/request/struct/parse2.go new file mode 100644 index 000000000..66e4d093e --- /dev/null +++ b/.example/net/ghttp/server/request/struct/parse2.go @@ -0,0 +1,36 @@ +package main + +import ( + "github.com/gogf/gf/frame/g" + "github.com/gogf/gf/net/ghttp" +) + +type RegisterReq struct { + Name string + Pass string `p:"password1"` + Pass2 string `p:"password2"` +} + +type RegisterRes struct { + Code int `json:"code"` + Error string `json:"error"` + Data interface{} `json:"data"` +} + +func main() { + s := g.Server() + s.BindHandler("/register", func(r *ghttp.Request) { + var req *RegisterReq + if err := r.Parse(&req); err != nil { + r.Response.WriteJsonExit(RegisterRes{ + Code: 1, + Error: err.Error(), + }) + } + r.Response.WriteJsonExit(RegisterRes{ + Data: req, + }) + }) + s.SetPort(8199) + s.Run() +} diff --git a/.example/other/test.go b/.example/other/test.go index 9ce95323c..8775af613 100644 --- a/.example/other/test.go +++ b/.example/other/test.go @@ -1,32 +1,27 @@ package main import ( - "github.com/gogf/gf/frame/g" + "fmt" "github.com/gogf/gf/util/gconv" ) func main() { - type Ids struct { - Id int `c:"id"` - Uid int `c:"uid"` - } type Base struct { - Ids + Id int `c:"id"` CreateTime string `c:"create_time"` } type User struct { - Base + Base `c:"base"` Passport string `c:"passport"` Password string `c:"password"` Nickname string `c:"nickname"` } user := new(User) user.Id = 1 - user.Uid = 100 user.Nickname = "John" user.Passport = "johng" user.Password = "123456" user.CreateTime = "2019" - g.Dump(gconv.Map(user)) - g.Dump(gconv.MapDeep(user)) + fmt.Println(gconv.Map(user)) + fmt.Println(gconv.MapDeep(user)) } diff --git a/database/gdb/gdb_unit_z_mysql_method_test.go b/database/gdb/gdb_unit_z_mysql_method_test.go index b150c847b..7710526ba 100644 --- a/database/gdb/gdb_unit_z_mysql_method_test.go +++ b/database/gdb/gdb_unit_z_mysql_method_test.go @@ -252,17 +252,20 @@ func Test_DB_BatchInsert(t *testing.T) { gtest.Assert(n, 1) }) +} + +func Test_DB_BatchInsert_Struct(t *testing.T) { // batch insert struct gtest.Case(t, func() { table := createTable() defer dropTable(table) type User struct { - Id int `gconv:"id"` - Passport string `gconv:"passport"` - Password string `gconv:"password"` - NickName string `gconv:"nickname"` - CreateTime *gtime.Time `gconv:"create_time"` + Id int `c:"id"` + Passport string `c:"passport"` + Password string `c:"password"` + NickName string `c:"nickname"` + CreateTime *gtime.Time `c:"create_time"` } user := &User{ Id: 1, @@ -276,7 +279,6 @@ func Test_DB_BatchInsert(t *testing.T) { n, _ := result.RowsAffected() gtest.Assert(n, 1) }) - } func Test_DB_Save(t *testing.T) { diff --git a/util/gconv/gconv.go b/util/gconv/gconv.go index 491f4e7bf..5f6313bc0 100644 --- a/util/gconv/gconv.go +++ b/util/gconv/gconv.go @@ -10,7 +10,6 @@ package gconv import ( "encoding/json" "fmt" - "github.com/gogf/gf/internal/empty" "github.com/gogf/gf/os/gtime" "reflect" "strconv" @@ -213,7 +212,8 @@ func String(i interface{}) string { } return value.String() default: - if empty.IsNil(value) { + // Empty checks. + if value == nil { return "" } if f, ok := value.(apiString); ok { @@ -225,6 +225,24 @@ func String(i interface{}) string { // then use that interface to perform the conversion return f.Error() } else { + // Reflect checks. + rv := reflect.ValueOf(value) + kind := rv.Kind() + switch kind { + case reflect.Chan, + reflect.Map, + reflect.Slice, + reflect.Func, + reflect.Ptr, + reflect.Interface, + reflect.UnsafePointer: + if rv.IsNil() { + return "" + } + } + if kind == reflect.Ptr { + return String(rv.Elem().Interface()) + } // Finally we use json.Marshal to convert. if jsonContent, err := json.Marshal(value); err != nil { return fmt.Sprint(value) diff --git a/util/gconv/gconv_map.go b/util/gconv/gconv_map.go index bebabcb0f..ef172defd 100644 --- a/util/gconv/gconv_map.go +++ b/util/gconv/gconv_map.go @@ -45,7 +45,7 @@ func doMapConvert(value interface{}, recursive bool, tags ...string) map[string] if r, ok := value.(map[string]interface{}); ok { return r } else { - // Only assert the common combination of types, and finally it uses reflection. + // Assert the common combination of types, and finally it uses reflection. m := make(map[string]interface{}) switch value.(type) { case map[interface{}]interface{}: @@ -104,7 +104,7 @@ func doMapConvert(value interface{}, recursive bool, tags ...string) map[string] for k, v := range value.(map[uint]string) { m[String(k)] = v } - // Not a common type, use reflection + // Not a common type, then use reflection. default: rv := reflect.ValueOf(value) kind := rv.Kind() @@ -136,6 +136,7 @@ func doMapConvert(value interface{}, recursive bool, tags ...string) map[string] } var rtField reflect.StructField var rvField reflect.Value + var rvKind reflect.Kind for i := 0; i < rv.NumField(); i++ { rtField = rt.Field(i) rvField = rv.Field(i) @@ -173,28 +174,20 @@ func doMapConvert(value interface{}, recursive bool, tags ...string) map[string] } } } - switch rvField.Kind() { - case reflect.Ptr: - if rvField.Elem().Kind() == reflect.Struct { - if recursive { - for k, v := range doMapConvert(rvField.Interface(), recursive, tags...) { - m[k] = v - } - } else { - m[name] = doMapConvert(rvField.Interface(), recursive, tags...) - } - } else { - m[name] = rvField.Interface() + if recursive { + rvKind = rvField.Kind() + if rvKind == reflect.Ptr { + rvField = rvField.Elem() + rvKind = rvField.Kind() } - case reflect.Struct: - if recursive { + if rvKind == reflect.Struct { for k, v := range doMapConvert(rvField.Interface(), recursive, tags...) { m[k] = v } } else { - m[name] = doMapConvert(rvField.Interface(), recursive, tags...) + m[name] = rvField.Interface() } - default: + } else { m[name] = rvField.Interface() } } diff --git a/util/gconv/gconv_z_all_test.go b/util/gconv/gconv_z_all_test.go index 71a2b05d6..bf466828a 100644 --- a/util/gconv/gconv_z_all_test.go +++ b/util/gconv/gconv_z_all_test.go @@ -940,7 +940,6 @@ func Test_Map_StructInherit_All(t *testing.T) { func Test_Struct_Basic1_All(t *testing.T) { gtest.Case(t, func() { - type Score struct { Name int Result string