From d0e7dd686bd151c0b3fce7c0004819576360a00d Mon Sep 17 00:00:00 2001 From: Wyatt Fang Date: Fri, 24 Apr 2015 10:58:46 +0800 Subject: [PATCH] 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") + } +}