add Recursively validation
Showing
2 changed files
with
69 additions
and
0 deletions
| ... | @@ -334,3 +334,42 @@ func (v *Validation) Valid(obj interface{}) (b bool, err error) { | ... | @@ -334,3 +334,42 @@ func (v *Validation) Valid(obj interface{}) (b bool, err error) { |
| 334 | 334 | ||
| 335 | return !v.HasErrors(), nil | 335 | return !v.HasErrors(), nil |
| 336 | } | 336 | } |
| 337 | |||
| 338 | // Recursively validate a struct. | ||
| 339 | // Step1: Validate by v.Valid | ||
| 340 | // Step2: If pass on step1, then reflect obj's fields | ||
| 341 | // Step3: Do the Recursively validation to all struct or struct pointer fields | ||
| 342 | // Anonymous fields will be ignored | ||
| 343 | func (v *Validation) RecursiveValid(objc interface{}) (bool, error) { | ||
| 344 | //Step 1: validate obj itself firstly | ||
| 345 | pass, err := v.Valid(objc) | ||
| 346 | if err != nil || false == pass { | ||
| 347 | return pass, err // Stop recursive validation | ||
| 348 | } else { //pass | ||
| 349 | // Step 2: Validate struct's struct fields | ||
| 350 | objT := reflect.TypeOf(objc) | ||
| 351 | objV := reflect.ValueOf(objc) | ||
| 352 | if isStruct(objT) || isStructPtr(objT) { | ||
| 353 | |||
| 354 | if isStructPtr(objT) { | ||
| 355 | objT = objT.Elem() | ||
| 356 | objV = objV.Elem() | ||
| 357 | } | ||
| 358 | |||
| 359 | for i := 0; i < objT.NumField(); i++ { | ||
| 360 | |||
| 361 | t := objT.Field(i).Type | ||
| 362 | |||
| 363 | if isStruct(t) || isStructPtr(t) { | ||
| 364 | // Step 3: do the recursive validation | ||
| 365 | // Only valid the Public field recursively | ||
| 366 | if objV.Field(i).CanInterface() { | ||
| 367 | pass, err = v.RecursiveValid(objV.Field(i).Interface()) | ||
| 368 | } | ||
| 369 | } | ||
| 370 | } | ||
| 371 | } | ||
| 372 | |||
| 373 | return pass, err | ||
| 374 | } | ||
| 375 | } | ... | ... |
| ... | @@ -349,3 +349,33 @@ func TestValid(t *testing.T) { | ... | @@ -349,3 +349,33 @@ func TestValid(t *testing.T) { |
| 349 | t.Errorf("Message key should be `Name.Match` but got %s", valid.Errors[0].Key) | 349 | t.Errorf("Message key should be `Name.Match` but got %s", valid.Errors[0].Key) |
| 350 | } | 350 | } |
| 351 | } | 351 | } |
| 352 | |||
| 353 | func TestRecursiveValid(t *testing.T) { | ||
| 354 | type User struct { | ||
| 355 | Id int | ||
| 356 | Name string `valid:"Required;Match(/^(test)?\\w*@(/test/);com$/)"` | ||
| 357 | Age int `valid:"Required;Range(1, 140)"` | ||
| 358 | } | ||
| 359 | |||
| 360 | type AnonymouseUser struct { | ||
| 361 | Id2 int | ||
| 362 | Name2 string `valid:"Required;Match(/^(test)?\\w*@(/test/);com$/)"` | ||
| 363 | Age2 int `valid:"Required;Range(1, 140)"` | ||
| 364 | } | ||
| 365 | |||
| 366 | type Account struct { | ||
| 367 | Password string `valid:"Required"` | ||
| 368 | U User | ||
| 369 | AnonymouseUser | ||
| 370 | } | ||
| 371 | valid := Validation{} | ||
| 372 | |||
| 373 | u := Account{Password: "abc123_", U: User{}} | ||
| 374 | b, err := valid.RecursiveValid(u) | ||
| 375 | if err != nil { | ||
| 376 | t.Fatal(err) | ||
| 377 | } | ||
| 378 | if b { | ||
| 379 | t.Error("validation should not be passed") | ||
| 380 | } | ||
| 381 | } | ... | ... |
-
Please register or sign in to post a comment