From 6dd7cda5223963c8160b9a8c213fa375cb1929a5 Mon Sep 17 00:00:00 2001 From: Fatih Arslan Date: Mon, 15 Sep 2014 12:39:09 +0300 Subject: [PATCH] structs: add omitempty support to Values() --- structs.go | 25 +++++++++++++++++++++---- structs_test.go | 18 ++++++++++++++++++ 2 files changed, 39 insertions(+), 4 deletions(-) diff --git a/structs.go b/structs.go index 00a778e..937b1cf 100644 --- a/structs.go +++ b/structs.go @@ -112,10 +112,16 @@ func (s *Struct) Map() map[string]interface{} { // A value with the option of "omitnested" stops iterating further if the type // is a struct. Example: // -// // Field is not processed further by this package. -// Field time.Time `structs:"myName,omitnested"` +// // Fields is not processed further by this package. +// Field time.Time `structs:",omitnested"` // Field *http.Request `structs:",omitnested"` // +// A tag value with the option of "omitempty" ignores that particular field and +// is not added to the values if the field value is empty. Example: +// +// // Field is skipped if empty +// Field string `structs:",omitempty"` +// // Note that only exported fields of a struct can be accessed, non exported // fields will be neglected. func (s *Struct) Values() []interface{} { @@ -128,6 +134,17 @@ func (s *Struct) Values() []interface{} { _, tagOpts := parseTag(field.Tag.Get(DefaultTagName)) + // if the value is a zero value and the field is marked as omitempty do + // not include + if tagOpts.Has("omitempty") { + zero := reflect.Zero(val.Type()).Interface() + current := val.Interface() + + if reflect.DeepEqual(current, zero) { + continue + } + } + if IsStruct(val.Interface()) && !tagOpts.Has("omitnested") { // look out for embedded structs, and convert them to a // []interface{} to be added to the final values slice @@ -182,7 +199,7 @@ func getFields(v reflect.Value) []*Field { } // Field returns a new Field struct that provides several high level functions -// around a single struct field entitiy. It panics if the field is not found. +// around a single struct field entity. It panics if the field is not found. func (s *Struct) Field(name string) *Field { f, ok := s.FieldOk(name) if !ok { @@ -193,7 +210,7 @@ func (s *Struct) Field(name string) *Field { } // Field returns a new Field struct that provides several high level functions -// around a single struct field entitiy. The boolean returns true if the field +// around a single struct field entity. The boolean returns true if the field // was found. func (s *Struct) FieldOk(name string) (*Field, bool) { t := s.value.Type() diff --git a/structs_test.go b/structs_test.go index 8ece554..6020cbc 100644 --- a/structs_test.go +++ b/structs_test.go @@ -301,6 +301,24 @@ func TestValues(t *testing.T) { } } +func TestValues_OmitEmpty(t *testing.T) { + type A struct { + Name string + Value int `structs:",omitempty"` + } + + a := A{Name: "example"} + s := Values(a) + + if len(s) != 1 { + t.Errorf("Values of omitted empty fields should be not counted") + } + + if s[0].(string) != "example" { + t.Errorf("Values of omitted empty fields should left the value example") + } +} + func TestValues_OmitNested(t *testing.T) { type A struct { Name string