From cd1342d77e7eadaf99fedd2f4b27b3df467b527d Mon Sep 17 00:00:00 2001 From: andrew Date: Tue, 20 May 2014 18:09:43 +1000 Subject: [PATCH 1/4] added parameters to validation --- v.go | 17 ++++++-- v_test.go | 114 +++++++++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 114 insertions(+), 17 deletions(-) diff --git a/v.go b/v.go index 7b3dcb3..cd0e42b 100644 --- a/v.go +++ b/v.go @@ -42,13 +42,13 @@ import ( ) // V is a map of tag names to validators. -type V map[string]func(interface{}) error +type V map[string]func(interface{}, []string) error // BadField is an error type containing a field name and associated error. // This is the type returned from Validate. type BadField struct { Field string - Err error + Err error } func (b BadField) Error() string { @@ -92,15 +92,24 @@ func (v V) Validate(s interface{}) []error { continue } + // Check for params (ie. "max_length[10]") + params := []string{} + b := strings.Index(vt, "[") + if b != -1 { + params = strings.Split(vt[b+1:len(vt)-1], "|") + vt = vt[0:b] + } + vf := v[vt] if vf == nil { errs = append(errs, BadField{ Field: f.Name, - Err: fmt.Errorf("undefined validator: %q", vt), + Err: fmt.Errorf("undefined validator: %q", vt), }) continue } - if err := vf(val); err != nil { + + if err := vf(val, params); err != nil { errs = append(errs, BadField{f.Name, err}) } } diff --git a/v_test.go b/v_test.go index b374a97..71b9b6d 100644 --- a/v_test.go +++ b/v_test.go @@ -2,9 +2,97 @@ package validate import ( "fmt" + "strconv" "testing" ) +func ExampleVWithTwoParams_Validate() { + type X struct { + A string `validate:"between[5|12]"` + B string `validate:"between[4|7]"` + C string + D string + } + + vd := make(V) + + vd["between"] = func(i interface{}, p []string) error { + s := i.(string) + + switch len(p) { + case 1: + l, err := strconv.Atoi(p[0]) + + if err != nil { + panic(err) //"Param needs to be an int") + } + + if len(s) != l { + return fmt.Errorf("%q needs to be %d in length", s, l) + } + case 2: + b, err := strconv.Atoi(p[0]) + if err != nil { + panic(err) //"Param needs to be an int") + } + e, err := strconv.Atoi(p[1]) + if err != nil { + panic(err) //"Param needs to be an int") + } + if len(s) < b || len(s) > e { + return fmt.Errorf("%q needs to be between %d and %d in length", s, b, e) + } + } + + return nil + } + + fmt.Println(vd.Validate(X{ + A: "hello there", + B: "hi", + C: "help me", + D: "I am not validated", + })) + + // Output: [field B is invalid: "hi" needs to be between 4 and 7 in length] +} + +func ExampleVWithOneParam_Validate() { + type X struct { + A string + B string + C string `validate:"max_length[10]"` + D string `validate:"max_length[10]"` + } + + vd := make(V) + + vd["max_length"] = func(i interface{}, p []string) error { + s := i.(string) + + l, err := strconv.Atoi(p[0]) + + if err != nil { + panic(err) //"Param needs to be an int") + } + + if len(s) > l { + return fmt.Errorf("%q needs to be less than %d in length", s, l) + } + + return nil + } + + fmt.Println(vd.Validate(X{ + A: "hello there", + B: "hi", + C: "help me", + D: "I am not validated", + })) + + // Output: [field D is invalid: "I am not validated" needs to be less than 10 in length] +} + func ExampleV_Validate() { type X struct { A string `validate:"long"` @@ -14,14 +102,14 @@ func ExampleV_Validate() { } vd := make(V) - vd["long"] = func(i interface{}) error { + vd["long"] = func(i interface{}, p []string) error { s := i.(string) if len(s) < 5 { return fmt.Errorf("%q is too short", s) } return nil } - vd["short"] = func(i interface{}) error { + vd["short"] = func(i interface{}, p []string) error { s := i.(string) if len(s) >= 5 { return fmt.Errorf("%q is too long", s) @@ -45,9 +133,9 @@ func TestV_Validate_allgood(t *testing.T) { } vd := make(V) - vd["odd"] = func(i interface{}) error { + vd["odd"] = func(i interface{}, p []string) error { n := i.(int) - if n & 1 == 0 { + if n&1 == 0 { return fmt.Errorf("%d is not odd", n) } return nil @@ -90,16 +178,16 @@ func TestV_Validate_multi(t *testing.T) { } vd := make(V) - vd["nonzero"] = func(i interface{}) error { + vd["nonzero"] = func(i interface{}, p []string) error { n := i.(int) if n == 0 { return fmt.Errorf("should be nonzero") } return nil } - vd["odd"] = func(i interface{}) error { + vd["odd"] = func(i interface{}, p []string) error { n := i.(int) - if n & 1 == 0 { + if n&1 == 0 { return fmt.Errorf("%d is not odd", n) } return nil @@ -129,22 +217,22 @@ func ExampleV_Validate_struct() { } vd := make(V) - vd["nonzero"] = func(i interface{}) error { + vd["nonzero"] = func(i interface{}, p []string) error { n := i.(int) if n == 0 { return fmt.Errorf("should be nonzero") } return nil } - vd["odd"] = func(i interface{}) error { + vd["odd"] = func(i interface{}, p []string) error { x := i.(X) - if x.A & 1 == 0 { + if x.A&1 == 0 { return fmt.Errorf("%d is not odd", x.A) } return nil } - errs := vd.Validate(Y{ X{ + errs := vd.Validate(Y{X{ A: 0, }}) @@ -162,7 +250,7 @@ func TestV_Validate_uninterfaceable(t *testing.T) { } vd := make(V) - vd["nonzero"] = func(i interface{}) error { + vd["nonzero"] = func(i interface{}, p []string) error { n := i.(int) if n == 0 { return fmt.Errorf("should be nonzero") @@ -181,7 +269,7 @@ func TestV_Validate_uninterfaceable(t *testing.T) { func TestV_Validate_nonstruct(t *testing.T) { vd := make(V) - vd["wrong"] = func(i interface{}) error { + vd["wrong"] = func(i interface{}, p []string) error { return fmt.Errorf("WRONG: %v", i) } From 6de0642ab0e39635191e03ccb9e8eff6964c7523 Mon Sep 17 00:00:00 2001 From: Andrew Date: Wed, 28 May 2014 20:55:55 +1000 Subject: [PATCH 2/4] adding in required --- v.go | 36 ++++++++++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/v.go b/v.go index cd0e42b..1c5e514 100644 --- a/v.go +++ b/v.go @@ -39,6 +39,7 @@ import ( "fmt" "reflect" "strings" + "time" ) // V is a map of tag names to validators. @@ -61,7 +62,7 @@ func (b BadField) Error() string { // // Fields that are not tagged or cannot be interfaced via reflection // are skipped. -func (v V) Validate(s interface{}) []error { +func (v V) Validate(s interface{}, r []string) []error { t := reflect.TypeOf(s) if t == nil || t.Kind() != reflect.Struct { return nil @@ -73,6 +74,36 @@ func (v V) Validate(s interface{}) []error { for i := 0; i < t.NumField(); i++ { f := t.Field(i) fv := val.Field(i) + + // Check for required fields + for _, rf := range r { + if rf == f.Name { + + // This field is required + switch f.Type.Name() { + case "string": + if fv.Len() == 0 { + errs = append(errs, BadField{ + Field: f.Name, + Err: fmt.Errorf("%s is required", f.Name), + }) + } + continue + case "Time": + ti := fv.Interface() + tt := ti.(time.Time) + if tt.IsZero() { + errs = append(errs, BadField{ + Field: f.Name, + Err: fmt.Errorf("%s is required", f.Name), + }) + } + continue + } + break + } + } + if !fv.CanInterface() { continue } @@ -85,7 +116,7 @@ func (v V) Validate(s interface{}) []error { for _, vt := range vts { if vt == "struct" { - errs2 := v.Validate(val) + errs2 := v.Validate(val, r) if len(errs2) > 0 { errs = append(errs, errs2...) } @@ -113,6 +144,7 @@ func (v V) Validate(s interface{}) []error { errs = append(errs, BadField{f.Name, err}) } } + } return errs From e5edf4c2fc867726eff9d84e334123385972b892 Mon Sep 17 00:00:00 2001 From: Andrew Edwards Date: Tue, 24 Jun 2014 16:30:46 +1000 Subject: [PATCH 3/4] removed required fields nonsense --- v.go | 38 ++++++-------------------------------- 1 file changed, 6 insertions(+), 32 deletions(-) diff --git a/v.go b/v.go index 1c5e514..ae2fd27 100644 --- a/v.go +++ b/v.go @@ -39,7 +39,6 @@ import ( "fmt" "reflect" "strings" - "time" ) // V is a map of tag names to validators. @@ -56,13 +55,17 @@ func (b BadField) Error() string { return fmt.Sprintf("field %s is invalid: %v", b.Field, b.Err) } +func NotCovered() { + fmt.Println("This will not be covered") + +} // Validate accepts a struct and returns a list of errors for all // fields that are invalid. If all fields are valid, or s is not a struct type, // Validate returns nil. // // Fields that are not tagged or cannot be interfaced via reflection // are skipped. -func (v V) Validate(s interface{}, r []string) []error { +func (v V) Validate(s interface{}) []error { t := reflect.TypeOf(s) if t == nil || t.Kind() != reflect.Struct { return nil @@ -75,35 +78,6 @@ func (v V) Validate(s interface{}, r []string) []error { f := t.Field(i) fv := val.Field(i) - // Check for required fields - for _, rf := range r { - if rf == f.Name { - - // This field is required - switch f.Type.Name() { - case "string": - if fv.Len() == 0 { - errs = append(errs, BadField{ - Field: f.Name, - Err: fmt.Errorf("%s is required", f.Name), - }) - } - continue - case "Time": - ti := fv.Interface() - tt := ti.(time.Time) - if tt.IsZero() { - errs = append(errs, BadField{ - Field: f.Name, - Err: fmt.Errorf("%s is required", f.Name), - }) - } - continue - } - break - } - } - if !fv.CanInterface() { continue } @@ -116,7 +90,7 @@ func (v V) Validate(s interface{}, r []string) []error { for _, vt := range vts { if vt == "struct" { - errs2 := v.Validate(val, r) + errs2 := v.Validate(val) if len(errs2) > 0 { errs = append(errs, errs2...) } From b279cc5e59cf010acd4c5fae2f730cd5b196400f Mon Sep 17 00:00:00 2001 From: Andrew Edwards Date: Tue, 1 Jul 2014 15:53:22 +1000 Subject: [PATCH 4/4] made changes to accomodate attendly stuff.... --- v.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/v.go b/v.go index ae2fd27..4a25024 100644 --- a/v.go +++ b/v.go @@ -57,22 +57,22 @@ func (b BadField) Error() string { func NotCovered() { fmt.Println("This will not be covered") - } + // Validate accepts a struct and returns a list of errors for all // fields that are invalid. If all fields are valid, or s is not a struct type, // Validate returns nil. // // Fields that are not tagged or cannot be interfaced via reflection // are skipped. -func (v V) Validate(s interface{}) []error { +func (v V) Validate(s interface{}) []BadField { t := reflect.TypeOf(s) if t == nil || t.Kind() != reflect.Struct { return nil } val := reflect.ValueOf(s) - var errs []error + var errs []BadField for i := 0; i < t.NumField(); i++ { f := t.Field(i)