From 38d6e482d7ef470758e320bb80f9d929d6d55765 Mon Sep 17 00:00:00 2001 From: Vasiliy Tolstov Date: Wed, 27 Oct 2021 22:51:35 +0300 Subject: [PATCH] util/reflect: fix StructFields Signed-off-by: Vasiliy Tolstov --- util/reflect/struct.go | 27 +++++++++++++++++++++--- util/reflect/struct_test.go | 41 ++++++++++++++++++++++++++++--------- 2 files changed, 55 insertions(+), 13 deletions(-) diff --git a/util/reflect/struct.go b/util/reflect/struct.go index 3c8d31ca..b0e7eba1 100644 --- a/util/reflect/struct.go +++ b/util/reflect/struct.go @@ -7,6 +7,7 @@ import ( "reflect" "regexp" "strings" + "time" ) // ErrInvalidParam specifies invalid url query params @@ -233,10 +234,30 @@ func StructFields(src interface{}) ([]StructField, error) { continue } + switch val.Interface().(type) { + case time.Time, *time.Time: + fields = append(fields, StructField{Field: fld, Value: val, Path: fld.Name}) + continue + case time.Duration, *time.Duration: + fields = append(fields, StructField{Field: fld, Value: val, Path: fld.Name}) + continue + } + switch val.Kind() { - // case timeKind: - // fmt.Printf("GGG\n") - // fields = append(fields, StructField{Field: fld, Value: val, Path: fld.Name}) + case reflect.Ptr: + // if !val.IsValid() + if reflect.Indirect(val).Kind() == reflect.Struct { + infields, err := StructFields(val.Interface()) + if err != nil { + return nil, err + } + for _, infield := range infields { + infield.Path = fmt.Sprintf("%s.%s", fld.Name, infield.Path) + fields = append(fields, infield) + } + } else { + fields = append(fields, StructField{Field: fld, Value: val, Path: fld.Name}) + } case reflect.Struct: infields, err := StructFields(val.Interface()) if err != nil { diff --git a/util/reflect/struct_test.go b/util/reflect/struct_test.go index e9c3b382..0c98ac32 100644 --- a/util/reflect/struct_test.go +++ b/util/reflect/struct_test.go @@ -4,24 +4,45 @@ import ( "net/url" "reflect" "testing" + "time" rutil "go.unistack.org/micro/v3/util/reflect" ) +func TestStructfields(t *testing.T) { + type Config struct { + Wait time.Duration + Time time.Time + Metadata map[string]int + Broker string + Addr []string + Verbose bool + Nested *Config + } + cfg := &Config{Nested: &Config{}} + fields, err := rutil.StructFields(cfg) + if err != nil { + t.Fatal(err) + } + if len(fields) != 13 { + t.Fatalf("invalid fields number: %v", fields) + } +} + func TestSetFieldByPath(t *testing.T) { type NestedStr struct { BBB string `json:"bbb"` - CCC int `json:"ccc"` + CCC int `json:"ccc"` } type Str1 struct { - Name []string `json:"name" codec:"flatten"` - XXX string `json:"xxx"` + Name []string `json:"name" codec:"flatten"` + XXX string `json:"xxx"` Nested NestedStr `json:"nested"` } type Str2 struct { - XXX string `json:"xxx"` + XXX string `json:"xxx"` Nested *NestedStr `json:"nested"` - Name []string `json:"name" codec:"flatten"` + Name []string `json:"name" codec:"flatten"` } var err error val1 := &Str1{Name: []string{"first", "second"}, XXX: "ttt", Nested: NestedStr{BBB: "ddd", CCC: 9}} @@ -45,17 +66,17 @@ func TestSetFieldByPath(t *testing.T) { func TestZeroFieldByPath(t *testing.T) { type NestedStr struct { BBB string `json:"bbb"` - CCC int `json:"ccc"` + CCC int `json:"ccc"` } type Str1 struct { - Name []string `json:"name" codec:"flatten"` - XXX string `json:"xxx"` + Name []string `json:"name" codec:"flatten"` + XXX string `json:"xxx"` Nested NestedStr `json:"nested"` } type Str2 struct { - XXX string `json:"xxx"` + XXX string `json:"xxx"` Nested *NestedStr `json:"nested"` - Name []string `json:"name" codec:"flatten"` + Name []string `json:"name" codec:"flatten"` } var err error val1 := &Str1{Name: []string{"first", "second"}, XXX: "ttt", Nested: NestedStr{BBB: "ddd", CCC: 9}}