From c36b654328ee9f30c503d92cd2a1bccf70a07980 Mon Sep 17 00:00:00 2001 From: Fatih Arslan Date: Mon, 28 Jul 2014 01:19:02 +0300 Subject: [PATCH] structure: add IsValid() function --- structure.go | 51 +++++++++++++++++++++++++++++++++++++++++++---- structure_test.go | 17 ++++++++++++++++ 2 files changed, 64 insertions(+), 4 deletions(-) diff --git a/structure.go b/structure.go index 5871b74..ac4820e 100644 --- a/structure.go +++ b/structure.go @@ -14,19 +14,18 @@ import ( func ToMap(s interface{}) map[string]interface{} { out := make(map[string]interface{}) - t := reflect.TypeOf(s) v := reflect.ValueOf(s) // if pointer get the underlying element≤ - if t.Kind() == reflect.Ptr { - t = t.Elem() + if v.Kind() == reflect.Ptr { v = v.Elem() } - if t.Kind() != reflect.Struct { + if v.Kind() != reflect.Struct { panic("not struct") } + t := v.Type() for i := 0; i < t.NumField(); i++ { field := t.Field(i) @@ -74,6 +73,50 @@ func ToSlice(s interface{}) []interface{} { } +// IsValid returns true if all fields in a struct are initialized (non zero +// value). A struct tag with the content of `structure:"-"` omits the checking +// of field. 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 IsValid(s interface{}) bool { + v := reflect.ValueOf(s) + + // if pointer get the underlying element≤ + if v.Kind() == reflect.Ptr { + v = v.Elem() + } + + if v.Kind() != reflect.Struct { + panic("not struct") + } + + t := v.Type() + for i := 0; i < t.NumField(); i++ { + field := t.Field(i) + + // we can't access the value of unexported fields + if field.PkgPath != "" { + continue + } + + // don't check if it's omitted + if tag := field.Tag.Get("structure"); tag == "-" { + continue + } + + // zero value of the given field, such as "" for string, 0 for int + zero := reflect.Zero(v.Field(i).Type()).Interface() + + // current value of the given field + current := v.Field(i).Interface() + + if reflect.DeepEqual(current, zero) { + return false + } + } + + return true +} + // Fields returns a sorted slice of field names. Note that only exported // fields of a struct can be accessed, non exported fields will be neglected. func Fields(s interface{}) []string { diff --git a/structure_test.go b/structure_test.go index 57c3d2f..5bfb18a 100644 --- a/structure_test.go +++ b/structure_test.go @@ -167,3 +167,20 @@ func TestFields(t *testing.T) { } } } + +func TestIsValid(t *testing.T) { + var T = struct { + A string + B int + C bool `structure:"-"` + D []string + }{ + A: "a-value", + B: 2, + } + + ok := IsValid(T) + if ok { + t.Error("IsValid should return false because D is not initialized") + } +}