Skip to content

Commit

Permalink
util/reflect: ZeroFieldByPath and SetFieldByPath
Browse files Browse the repository at this point in the history
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
  • Loading branch information
vtolstov committed Oct 26, 2021
1 parent bcaea67 commit 45f30c0
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 2 deletions.
26 changes: 24 additions & 2 deletions util/reflect/struct.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,9 +72,10 @@ func StructFieldByTag(src interface{}, tkey string, tval string) (interface{}, e
// ZeroFieldByPath clean struct field by its path
func ZeroFieldByPath(src interface{}, path string) error {
var err error
var val reflect.Value
val := reflect.ValueOf(src)

for _, p := range strings.Split(path, ".") {
val, err = structValueByName(reflect.ValueOf(src), p)
val, err = structValueByName(reflect.ValueOf(val), p)
if err != nil {
return err
}
Expand All @@ -93,6 +94,27 @@ func ZeroFieldByPath(src interface{}, path string) error {
return nil
}

// SetFieldByPath set struct field by its path
func SetFieldByPath(src interface{}, dst interface{}, path string) error {
var err error
val := reflect.ValueOf(src)

for _, p := range strings.Split(path, ".") {
val, err = structValueByName(val, p)
if err != nil {
return err
}
}

if !val.CanSet() {
return ErrInvalidStruct
}

val.Set(reflect.ValueOf(dst))

return nil
}

// structValueByName get struct field by its name
func structValueByName(sv reflect.Value, tkey string) (reflect.Value, error) {
if sv.Kind() == reflect.Ptr {
Expand Down
34 changes: 34 additions & 0 deletions util/reflect/struct_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,40 @@ import (
rutil "go.unistack.org/micro/v3/util/reflect"
)

func TestSetFieldByPath(t *testing.T) {
type NestedStr struct {
BBB string
CCC int
}
type Str1 struct {
Name []string `json:"name" codec:"flatten"`
XXX string `json:"xxx"`
Nested NestedStr
}
type Str2 struct {
XXX string `json:"xxx"`
Nested *NestedStr
Name []string `json:"name" codec:"flatten"`
}
var err error
val1 := &Str1{Name: []string{"first", "second"}, XXX: "ttt", Nested: NestedStr{BBB: "ddd", CCC: 9}}
val2 := &Str2{Name: []string{"first", "second"}, XXX: "ttt", Nested: &NestedStr{BBB: "ddd", CCC: 9}}
err = rutil.SetFieldByPath(val1, "xxx", "Nested.BBB")
if err != nil {
t.Fatal(err)
}
if val1.Nested.BBB != "xxx" {
t.Fatalf("SetFieldByPath not works: %#+v", val1)
}
err = rutil.SetFieldByPath(val2, "xxx", "Nested.BBB")
if err != nil {
t.Fatal(err)
}
if val2.Nested.BBB != "xxx" {
t.Fatalf("SetFieldByPath not works: %#+v", val1)
}
}

func TestZeroFieldByPath(t *testing.T) {
type NestedStr struct {
BBB string
Expand Down

0 comments on commit 45f30c0

Please sign in to comment.