structure: add omitnested support to Fields

This commit is contained in:
Fatih Arslan 2014-08-07 22:18:04 +03:00
parent eacf1a7590
commit 72596462dd
2 changed files with 68 additions and 28 deletions

View File

@ -88,6 +88,37 @@ func Values(s interface{}) []interface{} {
} }
// Fields returns a slice of field names. A struct tag with the content of "-"
// ignores the checking of that particular field. Example:
//
// // Field is ignored by this package.
// Field bool `structure:"-"`
//
// Note that only exported fields of a struct can be accessed, non exported
// fields will be neglected. It panics if s's kind is not struct.
func Fields(s interface{}) []string {
v, fields := strctInfo(s)
keys := make([]string, 0)
for _, field := range fields {
val := v.FieldByName(field.Name)
_, tagOpts := parseTag(field.Tag.Get(DefaultTagName))
if IsStruct(val.Interface()) && !tagOpts.Has("omitnested") {
// look out for embedded structs, and convert them to a
// []string to be added to the final values slice
for _, embeddedVal := range Fields(val.Interface()) {
keys = append(keys, embeddedVal)
}
}
keys = append(keys, field.Name)
}
return keys
}
// IsZero returns true if all fields in a struct is a zero value (not // IsZero returns true if all fields in a struct is a zero value (not
// initialized) A struct tag with the content of "-" ignores the checking of // initialized) A struct tag with the content of "-" ignores the checking of
// that particular field. Example: // that particular field. Example:
@ -163,34 +194,6 @@ func HasZero(s interface{}) bool {
return false return false
} }
// Fields returns a slice of field names. A struct tag with the content of "-"
// ignores the checking of that particular field. Example:
//
// // Field is ignored by this package.
// Field bool `structure:"-"`
//
// Note that only exported fields of a struct can be accessed, non exported
// fields will be neglected. It panics if s's kind is not struct.
func Fields(s interface{}) []string {
v, fields := strctInfo(s)
keys := make([]string, 0)
for _, field := range fields {
val := v.FieldByName(field.Name)
if IsStruct(val.Interface()) {
// look out for embedded structs, and convert them to a
// []string to be added to the final values slice
for _, embeddedVal := range Fields(val.Interface()) {
keys = append(keys, embeddedVal)
}
}
keys = append(keys, field.Name)
}
return keys
}
// IsStruct returns true if the given variable is a struct or a pointer to // IsStruct returns true if the given variable is a struct or a pointer to
// struct. // struct.
func IsStruct(s interface{}) bool { func IsStruct(s interface{}) bool {

View File

@ -411,6 +411,43 @@ func TestFields(t *testing.T) {
} }
} }
func TestFields_OmitNested(t *testing.T) {
type A struct {
Name string
Value string
Number int
Enabled bool
}
a := A{Name: "example"}
type B struct {
A A `structure:",omitnested"`
C int
}
b := &B{A: a, C: 123}
s := Fields(b)
if len(s) != 2 {
t.Errorf("Fields should omit nested struct. Expecting 2 got: %d", len(s))
}
inSlice := func(val interface{}) bool {
for _, v := range s {
if reflect.DeepEqual(v, val) {
return true
}
}
return false
}
for _, val := range []interface{}{"A", "C"} {
if !inSlice(val) {
t.Errorf("Fields should have the value %v", val)
}
}
}
func TestFields_Nested(t *testing.T) { func TestFields_Nested(t *testing.T) {
type A struct { type A struct {
Name string Name string