From d0e7dd686bd151c0b3fce7c0004819576360a00d Mon Sep 17 00:00:00 2001 From: Wyatt Fang Date: Fri, 24 Apr 2015 10:58:46 +0800 Subject: [PATCH 1/3] add Recursively validation --- validation/validation.go | 39 +++++++++++++++++++++++++++++++++++ validation/validation_test.go | 30 +++++++++++++++++++++++++++ 2 files changed, 69 insertions(+) diff --git a/validation/validation.go b/validation/validation.go index addf6b7e..d91679f7 100644 --- a/validation/validation.go +++ b/validation/validation.go @@ -333,3 +333,42 @@ func (v *Validation) Valid(obj interface{}) (b bool, err error) { return !v.HasErrors(), nil } + +// Recursively validate a struct. +// Step1: Validate by v.Valid +// Step2: If pass on step1, then reflect obj's fields +// Step3: Do the Recursively validation to all struct or struct pointer fields +// Anonymous fields will be ignored +func (v *Validation) RecursiveValid(objc interface{}) (bool, error) { + //Step 1: validate obj itself firstly + pass, err := v.Valid(objc) + if err != nil || false == pass { + return pass, err // Stop recursive validation + } else { //pass + // Step 2: Validate struct's struct fields + objT := reflect.TypeOf(objc) + objV := reflect.ValueOf(objc) + if isStruct(objT) || isStructPtr(objT) { + + if isStructPtr(objT) { + objT = objT.Elem() + objV = objV.Elem() + } + + for i := 0; i < objT.NumField(); i++ { + + t := objT.Field(i).Type + + if isStruct(t) || isStructPtr(t) { + // Step 3: do the recursive validation + // Only valid the Public field recursively + if objV.Field(i).CanInterface() { + pass, err = v.RecursiveValid(objV.Field(i).Interface()) + } + } + } + } + + return pass, err + } +} diff --git a/validation/validation_test.go b/validation/validation_test.go index be63ac93..78201198 100644 --- a/validation/validation_test.go +++ b/validation/validation_test.go @@ -343,3 +343,33 @@ func TestValid(t *testing.T) { t.Errorf("Message key should be `Name.Match` but got %s", valid.Errors[0].Key) } } + +func TestRecursiveValid(t *testing.T) { + type User struct { + Id int + Name string `valid:"Required;Match(/^(test)?\\w*@(/test/);com$/)"` + Age int `valid:"Required;Range(1, 140)"` + } + + type AnonymouseUser struct { + Id2 int + Name2 string `valid:"Required;Match(/^(test)?\\w*@(/test/);com$/)"` + Age2 int `valid:"Required;Range(1, 140)"` + } + + type Account struct { + Password string `valid:"Required"` + U User + AnonymouseUser + } + valid := Validation{} + + u := Account{Password: "abc123_", U: User{}} + b, err := valid.RecursiveValid(u) + if err != nil { + t.Fatal(err) + } + if b { + t.Error("validation should not be passed") + } +} From 73650e1f2be427a355e313179560831d242500dd Mon Sep 17 00:00:00 2001 From: Wyatt Fang Date: Fri, 24 Apr 2015 11:14:49 +0800 Subject: [PATCH 2/3] remove the double isStruct/isStructPtr check --- validation/validation.go | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/validation/validation.go b/validation/validation.go index d91679f7..21226e02 100644 --- a/validation/validation.go +++ b/validation/validation.go @@ -341,6 +341,7 @@ func (v *Validation) Valid(obj interface{}) (b bool, err error) { // Anonymous fields will be ignored func (v *Validation) RecursiveValid(objc interface{}) (bool, error) { //Step 1: validate obj itself firstly + // fails if objc is not struct pass, err := v.Valid(objc) if err != nil || false == pass { return pass, err // Stop recursive validation @@ -348,23 +349,22 @@ func (v *Validation) RecursiveValid(objc interface{}) (bool, error) { // Step 2: Validate struct's struct fields objT := reflect.TypeOf(objc) objV := reflect.ValueOf(objc) - if isStruct(objT) || isStructPtr(objT) { - if isStructPtr(objT) { - objT = objT.Elem() - objV = objV.Elem() - } + if isStructPtr(objT) { + objT = objT.Elem() + objV = objV.Elem() + } - for i := 0; i < objT.NumField(); i++ { + for i := 0; i < objT.NumField(); i++ { - t := objT.Field(i).Type + t := objT.Field(i).Type - if isStruct(t) || isStructPtr(t) { - // Step 3: do the recursive validation - // Only valid the Public field recursively - if objV.Field(i).CanInterface() { - pass, err = v.RecursiveValid(objV.Field(i).Interface()) - } + // Recursive applies to struct or pointer to structs fields + if isStruct(t) || isStructPtr(t) { + // Step 3: do the recursive validation + // Only valid the Public field recursively + if objV.Field(i).CanInterface() { + pass, err = v.RecursiveValid(objV.Field(i).Interface()) } } } From 5534258e222b905994e59b5c553653f109fbc7ae Mon Sep 17 00:00:00 2001 From: Wyatt Fang Date: Fri, 24 Apr 2015 11:17:12 +0800 Subject: [PATCH 3/3] remove useless comments --- validation/validation.go | 1 - 1 file changed, 1 deletion(-) diff --git a/validation/validation.go b/validation/validation.go index 21226e02..362e14ad 100644 --- a/validation/validation.go +++ b/validation/validation.go @@ -338,7 +338,6 @@ func (v *Validation) Valid(obj interface{}) (b bool, err error) { // Step1: Validate by v.Valid // Step2: If pass on step1, then reflect obj's fields // Step3: Do the Recursively validation to all struct or struct pointer fields -// Anonymous fields will be ignored func (v *Validation) RecursiveValid(objc interface{}) (bool, error) { //Step 1: validate obj itself firstly // fails if objc is not struct