From 664b0c06a6b25581a3fc0c788039a3b74de8dc76 Mon Sep 17 00:00:00 2001 From: John Date: Sat, 11 May 2019 17:56:14 +0800 Subject: [PATCH] gjson updates --- g/container/gvar/gvar.go | 2 +- g/encoding/gjson/gjson_api_new_load.go | 59 ++++++++++++------- g/encoding/gjson/gjson_func.go | 63 +++++++++++++++++++++ g/encoding/gjson/gjson_z_unit_basic_test.go | 59 +++++++++++-------- g/encoding/gparser/gparser_api_encoding.go | 18 +++++- g/net/ghttp/ghttp_server_session.go | 2 +- g/util/gconv/gconv_map.go | 37 +++++++----- g/util/gutil/gutil.go | 48 ++++++---------- geg/other/test.go | 46 +++++++++------ 9 files changed, 225 insertions(+), 109 deletions(-) create mode 100644 g/encoding/gjson/gjson_func.go diff --git a/g/container/gvar/gvar.go b/g/container/gvar/gvar.go index 948c9fde7..16e573fe0 100644 --- a/g/container/gvar/gvar.go +++ b/g/container/gvar/gvar.go @@ -67,7 +67,7 @@ func (v *Var) Time(format...string) time.Time { // TimeDuration converts and returns as time.Duration. // If value of is string, then it uses time.ParseDuration for conversion. -func (v *Var) TimeDuration() time.Duration { +func (v *Var) Duration() time.Duration { return gconv.Duration(v.Val()) } diff --git a/g/encoding/gjson/gjson_api_new_load.go b/g/encoding/gjson/gjson_api_new_load.go index 0bccf23e5..72a0df0ec 100644 --- a/g/encoding/gjson/gjson_api_new_load.go +++ b/g/encoding/gjson/gjson_api_new_load.go @@ -19,6 +19,7 @@ import ( "github.com/gogf/gf/g/os/gfcache" "github.com/gogf/gf/g/text/gregex" "github.com/gogf/gf/g/util/gconv" + "reflect" ) // New creates a Json object with any variable type of , @@ -29,31 +30,45 @@ import ( func New(data interface{}, unsafe...bool) *Json { j := (*Json)(nil) switch data.(type) { - case map[string]interface{}, []interface{}, nil: - j = &Json { - p : &data, - c : byte(gDEFAULT_SPLIT_CHAR), - vc : false , - } case string, []byte: - j, _ = LoadContent(gconv.Bytes(data)) - default: - v := (interface{})(nil) - if m := gconv.Map(data); m != nil { - v = m - j = &Json { - p : &v, - c : byte(gDEFAULT_SPLIT_CHAR), - vc : false, - } + if r, err := LoadContent(gconv.Bytes(data)); err == nil { + j = r } else { - v = gconv.Interfaces(data) - j = &Json { - p : &v, - c : byte(gDEFAULT_SPLIT_CHAR), - vc : false, - } + j = &Json { + p : &data, + c : byte(gDEFAULT_SPLIT_CHAR), + vc : false , + } } + default: + rv := reflect.ValueOf(data) + kind := rv.Kind() + switch kind { + case reflect.Slice: fallthrough + case reflect.Array: + i := interface{}(nil) + i = gconv.Interfaces(data) + j = &Json { + p : &i, + c : byte(gDEFAULT_SPLIT_CHAR), + vc : false , + } + case reflect.Map: fallthrough + case reflect.Struct: + i := interface{}(nil) + i = gconv.Map(data) + j = &Json { + p : &i, + c : byte(gDEFAULT_SPLIT_CHAR), + vc : false , + } + default: + j = &Json { + p : &data, + c : byte(gDEFAULT_SPLIT_CHAR), + vc : false , + } + } } j.mu = rwmutex.New(unsafe...) return j diff --git a/g/encoding/gjson/gjson_func.go b/g/encoding/gjson/gjson_func.go new file mode 100644 index 000000000..ac4b9bcf3 --- /dev/null +++ b/g/encoding/gjson/gjson_func.go @@ -0,0 +1,63 @@ +// Copyright 2017 gf Author(https://github.com/gogf/gf). 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 gjson + +//func MarshalOrdered(value interface{}) ([]byte, error) { +// buffer := bytes.NewBuffer(nil) +// rv := reflect.ValueOf(value) +// kind := rv.Kind() +// if kind == reflect.Ptr { +// rv = rv.Elem() +// kind = rv.Kind() +// } +// switch kind { +// case reflect.Slice: fallthrough +// case reflect.Array: +// buffer.WriteByte('[') +// length := rv.Len() +// for i := 0; i < length; i++ { +// if p, err := MarshalOrdered(rv.Index(i).Interface()); err != nil { +// return nil, err +// } else { +// buffer.Write(p) +// if i < length - 1 { +// buffer.WriteByte(',') +// } +// } +// } +// buffer.WriteByte(']') +// case reflect.Map: fallthrough +// case reflect.Struct: +// m := gconv.Map(value, "json") +// keys := make([]string, len(m)) +// index := 0 +// for key := range m { +// keys[index] = key +// index++ +// } +// sort.Strings(keys) +// buffer.WriteByte('{') +// for i, key := range keys { +// if p, err := MarshalOrdered(m[key]); err != nil { +// return nil, err +// } else { +// buffer.WriteString(fmt.Sprintf(`"%s":%s`, key, string(p))) +// if i < index - 1 { +// buffer.WriteByte(',') +// } +// } +// } +// buffer.WriteByte('}') +// default: +// if p, err := json.Marshal(value); err != nil { +// return nil, err +// } else { +// buffer.Write(p) +// } +// } +// return buffer.Bytes(), nil +//} \ No newline at end of file diff --git a/g/encoding/gjson/gjson_z_unit_basic_test.go b/g/encoding/gjson/gjson_z_unit_basic_test.go index 102a2e15b..b1d3430f1 100644 --- a/g/encoding/gjson/gjson_z_unit_basic_test.go +++ b/g/encoding/gjson/gjson_z_unit_basic_test.go @@ -225,29 +225,42 @@ func Test_Len(t *testing.T) { } func Test_Append(t *testing.T) { - gtest.Case(t, func() { - p := gjson.New(nil) - p.Append("a", 1) - p.Append("a", 2) - gtest.Assert(p.Get("a"), g.Slice{1, 2}) - }) - gtest.Case(t, func() { - p := gjson.New(nil) - p.Append("a.b", 1) - p.Append("a.c", 2) - gtest.Assert(p.Get("a"), g.Map{ - "b" : g.Slice{1}, - "c" : g.Slice{2}, - }) - }) - gtest.Case(t, func() { - p := gjson.New(nil) - p.Set("a", 1) - err := p.Append("a", 2) - gtest.AssertNE(err, nil) - gtest.Assert(p.Get("a"), 1) - }) + gtest.Case(t, func() { + p := gjson.New(nil) + p.Append("a", 1) + p.Append("a", 2) + gtest.Assert(p.Get("a"), g.Slice{1, 2}) + }) + gtest.Case(t, func() { + p := gjson.New(nil) + p.Append("a.b", 1) + p.Append("a.c", 2) + gtest.Assert(p.Get("a"), g.Map{ + "b" : g.Slice{1}, + "c" : g.Slice{2}, + }) + }) + gtest.Case(t, func() { + p := gjson.New(nil) + p.Set("a", 1) + err := p.Append("a", 2) + gtest.AssertNE(err, nil) + gtest.Assert(p.Get("a"), 1) + }) } - +func TestJson_ToJson(t *testing.T) { + gtest.Case(t, func() { + p := gjson.New("1") + s, e := p.ToJsonString() + gtest.Assert(e, nil) + gtest.Assert(s, "1") + }) + gtest.Case(t, func() { + p := gjson.New("a") + s, e := p.ToJsonString() + gtest.Assert(e, nil) + gtest.Assert(s, `"a"`) + }) +} diff --git a/g/encoding/gparser/gparser_api_encoding.go b/g/encoding/gparser/gparser_api_encoding.go index 618271ed8..c9e17f252 100644 --- a/g/encoding/gparser/gparser_api_encoding.go +++ b/g/encoding/gparser/gparser_api_encoding.go @@ -18,10 +18,18 @@ func (p *Parser) ToJson() ([]byte, error) { return p.json.ToJson() } +func (p *Parser) ToJsonString() (string, error) { + return p.json.ToJsonString() +} + func (p *Parser) ToJsonIndent() ([]byte, error) { return p.json.ToJsonIndent() } +func (p *Parser) ToJsonIndentString() (string, error) { + return p.json.ToJsonIndentString() +} + func (p *Parser) ToYaml() ([]byte, error) { return p.json.ToYaml() } @@ -42,8 +50,16 @@ func VarToJson(value interface{}) ([]byte, error) { return New(value).ToJson() } +func VarToJsonString(value interface{}) (string, error) { + return New(value).ToJsonString() +} + func VarToJsonIndent(value interface{}) ([]byte, error) { - return New(value).ToJsonIndent() + return New(value).ToJsonIndent() +} + +func VarToJsonIndentString(value interface{}) (string, error) { + return New(value).ToJsonIndentString() } func VarToYaml(value interface{}) ([]byte, error) { diff --git a/g/net/ghttp/ghttp_server_session.go b/g/net/ghttp/ghttp_server_session.go index 496a9d0c3..58e588be6 100644 --- a/g/net/ghttp/ghttp_server_session.go +++ b/g/net/ghttp/ghttp_server_session.go @@ -114,7 +114,7 @@ func (s *Session) Get(key string, def...interface{}) interface{} { // 获取SESSION,建议都用该方法获取参数 func (s *Session) GetVar(key string, def...interface{}) *gvar.Var { - return gvar.NewRead(s.Get(key, def...), true) + return gvar.New(s.Get(key, def...), true) } // 删除session diff --git a/g/util/gconv/gconv_map.go b/g/util/gconv/gconv_map.go index 038651096..94f6f72e9 100644 --- a/g/util/gconv/gconv_map.go +++ b/g/util/gconv/gconv_map.go @@ -15,10 +15,9 @@ import ( // Map converts any variable to map[string]interface{}. // If the parameter is not a map type, then the conversion will fail and returns nil. -// If is a struct object, the second parameter noTagCheck means that -// the json tag is not detected, -// otherwise the json tag will be used as the map key name. -func Map(value interface{}, noTagCheck...bool) map[string]interface{} { +// If is a struct object, the second parameter specifies the most priority +// tags that will be detected, otherwise it detects the tags in order of: gconv, json. +func Map(value interface{}, tags...string) map[string]interface{} { if value == nil { return nil } @@ -52,7 +51,6 @@ func Map(value interface{}, noTagCheck...bool) map[string]interface{} { for k, v := range value.(map[interface{}]float64) { m[String(k)] = v } - case map[string]bool: for k, v := range value.(map[string]bool) { m[k] = v @@ -102,21 +100,32 @@ func Map(value interface{}, noTagCheck...bool) map[string]interface{} { m[String(k.Interface())] = rv.MapIndex(k).Interface() } case reflect.Struct: - rt := rv.Type() - name := "" + rt := rv.Type() + name := "" + gconvTag := "gconv" + tagArray := []string{gconvTag, "json"} + switch len(tags) { + case 0: + // No need handle. + case 1: + tagArray = strings.Split(tags[0], ",") + default: + tagArray = tags + } + if gstr.SearchArray(tagArray, gconvTag) < 0 { + tagArray = append(tagArray, gconvTag) + } for i := 0; i < rv.NumField(); i++ { // Only convert the public attributes. fieldName := rt.Field(i).Name if !gstr.IsLetterUpper(fieldName[0]) { continue } - name = "" - // Tag check, supporting "gconv" and "json" tag, - // "gconv" has the high priority to use. - if len(noTagCheck) == 0 || !noTagCheck[0] { - tag := rt.Field(i).Tag - if name = tag.Get("gconv"); name == "" { - name = tag.Get("json") + name = "" + fieldTag := rt.Field(i).Tag + for _, tag := range tagArray { + if name = fieldTag.Get(tag); name != "" { + break } } if name == "" { diff --git a/g/util/gutil/gutil.go b/g/util/gutil/gutil.go index a7d4b4f29..b664df319 100644 --- a/g/util/gutil/gutil.go +++ b/g/util/gutil/gutil.go @@ -8,17 +8,16 @@ package gutil import ( - "bytes" - "encoding/json" - "fmt" - "github.com/gogf/gf/g/internal/empty" - "github.com/gogf/gf/g/util/gconv" - "os" - "reflect" - "runtime" + "bytes" + "encoding/json" + "fmt" + "github.com/gogf/gf/g/internal/empty" + "github.com/gogf/gf/g/util/gconv" + "os" + "runtime" ) -// 格式化打印变量 +// Dump prints variables to stdout with more manually readable. func Dump(i...interface{}) { s := Export(i...) if s != "" { @@ -26,25 +25,16 @@ func Dump(i...interface{}) { } } -// 格式化导出变量 +// Export returns variables as a string with more manually readable. func Export(i...interface{}) string { buffer := bytes.NewBuffer(nil) for _, v := range i { if b, ok := v.([]byte); ok { buffer.Write(b) } else { - // 主要针对 map[interface{}]* 进行处理,json无法进行encode, - // 这里强制对所有map进行反射处理转换 - refValue := reflect.ValueOf(v) - if refValue.Kind() == reflect.Map { - m := make(map[string]interface{}) - keys := refValue.MapKeys() - for _, k := range keys { - m[gconv.String(k.Interface())] = refValue.MapIndex(k).Interface() - } - v = m + if m := gconv.Map(v); m != nil { + v = m } - // JSON格式化 encoder := json.NewEncoder(buffer) encoder.SetEscapeHTML(false) encoder.SetIndent("", "\t") @@ -56,7 +46,7 @@ func Export(i...interface{}) string { return buffer.String() } -// 打印完整的调用回溯信息 +// PrintBacktrace prints the caller backtrace to stdout. func PrintBacktrace() { index := 1 buffer := bytes.NewBuffer(nil) @@ -71,12 +61,12 @@ func PrintBacktrace() { fmt.Print(buffer.String()) } -// 抛出一个异常 +// Throw throws out an exception, which can be caught be TryCatch or recover. func Throw(exception interface{}) { panic(exception) } -// try...catch... +// TryCatch implements try...catch... logistics. func TryCatch(try func(), catch ... func(exception interface{})) { if len(catch) > 0 { defer func() { @@ -88,13 +78,9 @@ func TryCatch(try func(), catch ... func(exception interface{})) { try() } -// IsEmpty checks given value empty or not. -// false: integer(0), bool(false), slice/map(len=0), nil; -// true : other. -// -// 判断给定的变量是否为空。 -// 整型为0, 布尔为false, slice/map长度为0, 其他为nil的情况,都为空。 -// 为空时返回true,否则返回false。 +// IsEmpty checks given empty or not. +// It returns false if is: integer(0), bool(false), slice/map(len=0), nil; +// or else returns true. func IsEmpty(value interface{}) bool { return empty.IsEmpty(value) } diff --git a/geg/other/test.go b/geg/other/test.go index 660ee446f..fa60feef7 100644 --- a/geg/other/test.go +++ b/geg/other/test.go @@ -2,24 +2,38 @@ package main import ( "fmt" - "github.com/gogf/gf/g/container/gtree" + "github.com/gogf/gf/g/encoding/gparser" + "time" ) func main() { - tree := gtree.New(func(v1, v2 interface{}) int { - return v1.(int) - v2.(int) - }) - for i := 0; i < 20; i++ { - tree.Set(i, i) + //b, e := gjson.MarshalOrdered(g.Map{ + // "a" : 1, + // "b" : 2, + // "c" : 3, + //}) + //fmt.Println(e) + //fmt.Println(string(b)) + + //m := map[string]interface{}{ + // "facet_is_special_price":[]string{"1"}, + // "score_outlet":"0", + // "skus":[]string{"DI139BE71WDWDFMX", "DI139BE71WDWDFMX-519406"}, + // "facet_novelty_two_days":[]string{"0"}, + // "facet_brand":[]string{"139"}, + // "sku":[]string{"DI139BE71WDWDFMX"}, + //} + + for { + m := make(map[string]interface{}) + m["facet_is_special_price"] = []string{"1"} + m["score_outlet"] = "0" + m["skus"] = []string{"DI139BE71WDWDFMX", "DI139BE71WDWDFMX-519406"} + m["facet_novelty_two_days"] = []string{"0"} + m["facet_brand"] = []string{"139"} + m["sku"] = []string{"DI139BE71WDWDFMX"} + fmt.Println(gparser.VarToJsonString(m)) + time.Sleep(100*time.Millisecond) } - tree.Print() - tree.IteratorAsc(func(key, value interface{}) bool { - fmt.Println(key) - return true - }) - fmt.Println() - tree.IteratorDesc(func(key, value interface{}) bool { - fmt.Println(key) - return true - }) + } \ No newline at end of file