util/reflect: add new funcs
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
This commit is contained in:
parent
a7e6d61b95
commit
a839f75a2f
@ -7,7 +7,6 @@ import (
|
|||||||
"reflect"
|
"reflect"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// ErrInvalidParam specifies invalid url query params
|
// ErrInvalidParam specifies invalid url query params
|
||||||
@ -15,11 +14,12 @@ var ErrInvalidParam = errors.New("invalid url query param provided")
|
|||||||
|
|
||||||
var bracketSplitter = regexp.MustCompile(`\[|\]`)
|
var bracketSplitter = regexp.MustCompile(`\[|\]`)
|
||||||
|
|
||||||
var timeKind = reflect.TypeOf(time.Time{}).Kind()
|
//var timeKind = reflect.ValueOf(time.Time{}).Kind()
|
||||||
|
|
||||||
type StructField struct {
|
type StructField struct {
|
||||||
Field reflect.StructField
|
Field reflect.StructField
|
||||||
Value reflect.Value
|
Value reflect.Value
|
||||||
|
Path string
|
||||||
}
|
}
|
||||||
|
|
||||||
func StructFieldByTag(src interface{}, tkey string, tval string) (interface{}, error) {
|
func StructFieldByTag(src interface{}, tkey string, tval string) (interface{}, error) {
|
||||||
@ -35,7 +35,7 @@ func StructFieldByTag(src interface{}, tkey string, tval string) (interface{}, e
|
|||||||
for idx := 0; idx < typ.NumField(); idx++ {
|
for idx := 0; idx < typ.NumField(); idx++ {
|
||||||
fld := typ.Field(idx)
|
fld := typ.Field(idx)
|
||||||
val := sv.Field(idx)
|
val := sv.Field(idx)
|
||||||
if !val.CanSet() || len(fld.PkgPath) != 0 {
|
if len(fld.PkgPath) != 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -66,6 +66,17 @@ func StructFieldByTag(src interface{}, tkey string, tval string) (interface{}, e
|
|||||||
return nil, ErrNotFound
|
return nil, ErrNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func StructFieldByPath(src interface{}, path string) (interface{}, error) {
|
||||||
|
var err error
|
||||||
|
for _, p := range strings.Split(path, ".") {
|
||||||
|
src, err = StructFieldByName(src, p)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return src, err
|
||||||
|
}
|
||||||
|
|
||||||
func StructFieldByName(src interface{}, tkey string) (interface{}, error) {
|
func StructFieldByName(src interface{}, tkey string) (interface{}, error) {
|
||||||
sv := reflect.ValueOf(src)
|
sv := reflect.ValueOf(src)
|
||||||
if sv.Kind() == reflect.Ptr {
|
if sv.Kind() == reflect.Ptr {
|
||||||
@ -79,7 +90,7 @@ func StructFieldByName(src interface{}, tkey string) (interface{}, error) {
|
|||||||
for idx := 0; idx < typ.NumField(); idx++ {
|
for idx := 0; idx < typ.NumField(); idx++ {
|
||||||
fld := typ.Field(idx)
|
fld := typ.Field(idx)
|
||||||
val := sv.Field(idx)
|
val := sv.Field(idx)
|
||||||
if !val.CanSet() || len(fld.PkgPath) != 0 {
|
if len(fld.PkgPath) != 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if fld.Name == tkey {
|
if fld.Name == tkey {
|
||||||
@ -105,6 +116,19 @@ func StructFieldByName(src interface{}, tkey string) (interface{}, error) {
|
|||||||
return nil, ErrNotFound
|
return nil, ErrNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// StructFieldsMap returns map[string]interface{} or error
|
||||||
|
func StructFieldsMap(src interface{}) (map[string]interface{}, error) {
|
||||||
|
fields, err := StructFields(src)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
mp := make(map[string]interface{}, len(fields))
|
||||||
|
for _, field := range fields {
|
||||||
|
mp[field.Path] = field.Value.Interface()
|
||||||
|
}
|
||||||
|
return mp, nil
|
||||||
|
}
|
||||||
|
|
||||||
// StructFields returns slice of struct fields
|
// StructFields returns slice of struct fields
|
||||||
func StructFields(src interface{}) ([]StructField, error) {
|
func StructFields(src interface{}) ([]StructField, error) {
|
||||||
var fields []StructField
|
var fields []StructField
|
||||||
@ -116,25 +140,29 @@ func StructFields(src interface{}) ([]StructField, error) {
|
|||||||
if sv.Kind() != reflect.Struct {
|
if sv.Kind() != reflect.Struct {
|
||||||
return nil, ErrInvalidStruct
|
return nil, ErrInvalidStruct
|
||||||
}
|
}
|
||||||
|
|
||||||
typ := sv.Type()
|
typ := sv.Type()
|
||||||
for idx := 0; idx < typ.NumField(); idx++ {
|
for idx := 0; idx < typ.NumField(); idx++ {
|
||||||
fld := typ.Field(idx)
|
fld := typ.Field(idx)
|
||||||
val := sv.Field(idx)
|
val := sv.Field(idx)
|
||||||
if !val.CanSet() || len(fld.PkgPath) != 0 {
|
if !val.IsValid() || len(fld.PkgPath) != 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
switch val.Kind() {
|
switch val.Kind() {
|
||||||
case timeKind:
|
//case timeKind:
|
||||||
fields = append(fields, StructField{Field: fld, Value: val})
|
//fmt.Printf("GGG\n")
|
||||||
|
//fields = append(fields, StructField{Field: fld, Value: val, Path: fld.Name})
|
||||||
case reflect.Struct:
|
case reflect.Struct:
|
||||||
infields, err := StructFields(val.Interface())
|
infields, err := StructFields(val.Interface())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
fields = append(fields, infields...)
|
for _, infield := range infields {
|
||||||
|
infield.Path = fmt.Sprintf("%s.%s", fld.Name, infield.Path)
|
||||||
|
fields = append(fields, infield)
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
fields = append(fields, StructField{Field: fld, Value: val})
|
fields = append(fields, StructField{Field: fld, Value: val, Path: fld.Name})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -194,7 +222,7 @@ func StructURLValues(src interface{}, pref string, tags []string) (url.Values, e
|
|||||||
for idx := 0; idx < typ.NumField(); idx++ {
|
for idx := 0; idx < typ.NumField(); idx++ {
|
||||||
fld := typ.Field(idx)
|
fld := typ.Field(idx)
|
||||||
val := sv.Field(idx)
|
val := sv.Field(idx)
|
||||||
if !val.CanSet() || len(fld.PkgPath) != 0 || !val.IsValid() {
|
if len(fld.PkgPath) != 0 || !val.IsValid() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,9 +2,80 @@ package reflect
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"reflect"
|
||||||
|
rfl "reflect"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func TestStructFieldsMap(t *testing.T) {
|
||||||
|
type NestedStr struct {
|
||||||
|
BBB string
|
||||||
|
CCC int
|
||||||
|
}
|
||||||
|
type Str struct {
|
||||||
|
Name []string `json:"name" codec:"flatten"`
|
||||||
|
XXX string `json:"xxx"`
|
||||||
|
Nested NestedStr
|
||||||
|
}
|
||||||
|
|
||||||
|
val := &Str{Name: []string{"first", "second"}, XXX: "ttt", Nested: NestedStr{BBB: "ddd", CCC: 9}}
|
||||||
|
fields, err := StructFieldsMap(val)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if v, ok := fields["Nested.BBB"]; !ok || v != "ddd" {
|
||||||
|
t.Fatalf("invalid field from %v", fields)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStructFields(t *testing.T) {
|
||||||
|
type NestedStr struct {
|
||||||
|
BBB string
|
||||||
|
CCC int
|
||||||
|
}
|
||||||
|
type Str struct {
|
||||||
|
Name []string `json:"name" codec:"flatten"`
|
||||||
|
XXX string `json:"xxx"`
|
||||||
|
Nested NestedStr
|
||||||
|
}
|
||||||
|
|
||||||
|
val := &Str{Name: []string{"first", "second"}, XXX: "ttt", Nested: NestedStr{BBB: "ddd", CCC: 9}}
|
||||||
|
fields, err := StructFields(val)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
var ok bool
|
||||||
|
for _, field := range fields {
|
||||||
|
if field.Path == "Nested.CCC" {
|
||||||
|
ok = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("struct fields returns invalid path: %v", fields)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStructByPath(t *testing.T) {
|
||||||
|
type NestedStr struct {
|
||||||
|
BBB string
|
||||||
|
CCC int
|
||||||
|
}
|
||||||
|
type Str struct {
|
||||||
|
Name []string `json:"name" codec:"flatten"`
|
||||||
|
XXX string `json:"xxx"`
|
||||||
|
Nested NestedStr
|
||||||
|
}
|
||||||
|
|
||||||
|
val := &Str{Name: []string{"first", "second"}, XXX: "ttt", Nested: NestedStr{BBB: "ddd", CCC: 9}}
|
||||||
|
field, err := StructFieldByPath(val, "Nested.CCC")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if rfl.Indirect(reflect.ValueOf(field)).Int() != 9 {
|
||||||
|
t.Fatalf("invalid elem returned: %v", field)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestStructByTag(t *testing.T) {
|
func TestStructByTag(t *testing.T) {
|
||||||
type Str struct {
|
type Str struct {
|
||||||
Name []string `json:"name" codec:"flatten"`
|
Name []string `json:"name" codec:"flatten"`
|
||||||
|
Loading…
Reference in New Issue
Block a user