Merge branch 'v3' into v3-development

pull/16/head
Dean Karn 10 years ago
commit 773ef71208
  1. 2
      README.md
  2. 37
      doc.go
  3. 51
      validator.go
  4. 430
      validator_test.go

@ -1,6 +1,6 @@
Package go-validate-yourself
================
[![Build Status](https://travis-ci.org/joeybloggs/go-validate-yourself.svg?branch=v3-development)](https://travis-ci.org/joeybloggs/go-validate-yourself)
[![Build Status](https://travis-ci.org/joeybloggs/go-validate-yourself.svg?branch=v3)](https://travis-ci.org/joeybloggs/go-validate-yourself)
Package validator implements value validations for structs and individual fields based on tags.

@ -3,15 +3,12 @@ Package validator implements value validations for structs and individual fields
Built In Validator
The package contains a built in Validator instance for use,
but you may also create a new instance if needed.
v3 no longer contains a built in Validator instance.
// built in
errs := validator.ValidateStruct(//your struct)
valErr := validator.ValidateFieldByTag(field, "omitempty,min=1,max=10")
myValidator = validator.New("validate", validator.BakedInFunctions)
// new
newValidator = validator.New("struct tag name", validator.BakedInFunctions)
errs := myValidator.ValidateStruct(//your struct)
valErr := myValidator.ValidateFieldByTag(field, "omitempty,min=1,max=10")
A simple example usage:
@ -32,7 +29,7 @@ A simple example usage:
// errs will contain a hierarchical list of errors
// using the StructValidationErrors struct
// or nil if no errors exist
errs := validator.ValidateStruct(user)
errs := myValidator.ValidateStruct(user)
// in this case 1 error Name is required
errs.Struct will be "User"
@ -68,7 +65,7 @@ I needed to know the field and what validation failed so that I could provide an
return "Translated string based on field"
}
The hierarchical structure is hard to work with sometimes.. Agreed Flatten function to the rescue!
The hierarchical error structure is hard to work with sometimes.. Agreed Flatten function to the rescue!
Flatten will return a map of FieldValidationError's but the field name will be namespaced.
// if UserDetail Details field failed validation
@ -91,7 +88,7 @@ Custom functions can be added
return true
}
validator.AddFunction("custom tag name", customFunc)
myValidator.AddFunction("custom tag name", customFunc)
// NOTES: using the same tag name as an existing function
// will overwrite the existing one
@ -99,16 +96,16 @@ Cross Field Validation
Cross Field Validation can be implemented, for example Start & End Date range validation
// NOTE: when calling validator.validateStruct(val) val will be the top level struct passed
// NOTE: when calling myValidator.validateStruct(val) val will be the top level struct passed
// into the function
// when calling validator.ValidateFieldByTagAndValue(val, field, tag) val will be
// when calling myValidator.ValidateFieldByTagAndValue(val, field, tag) val will be
// whatever you pass, struct, field...
// when calling validator.ValidateFieldByTag(field, tag) val will be nil
// when calling myValidator.ValidateFieldByTag(field, tag) val will be nil
//
// Because of the specific requirements and field names within each persons project that
// uses this library it is unlikely that any baked in function for this type of validation
// would be added, but you can add your own custom ones and keep all your validation logic
// in one place.
// uses this library it is likely that custom functions will need to be created.
// however there are some build in Generic Cross Field validation, see Baked In Validators and
// Tags below
func isDateRangeValid(val interface{}, field interface{}, param string) bool {
@ -121,12 +118,6 @@ Cross Field Validation can be implemented, for example Start & End Date range va
return true
}
Custom Tag Name
A custom tag name can be set to avoid conficts, or just have a shorter name
validator.SetTag("valid")
Multiple Validators
Multiple validators on a field will process in the order defined
@ -325,6 +316,6 @@ This package panics when bad input is provided, this is by design, bad code like
TestField: "Test"
}
validator.ValidateStruct(t) // this will panic
myValidator.ValidateStruct(t) // this will panic
*/
package validator

@ -18,7 +18,10 @@ import (
)
const (
defaultTagName = "validate"
tagSeparator = ","
orSeparator = "|"
noValidationTag = "-"
tagKeySeparator = "="
omitempty = "omitempty"
validationFieldErrMsg = "Field validation for \"%s\" failed on the \"%s\" tag\n"
validationStructErrMsg = "Struct:%s\n"
@ -111,10 +114,6 @@ type Validator struct {
validationFuncs map[string]ValidationFunc
}
// var bakedInValidators = map[string]ValidationFunc{}
var internalValidator = NewValidator(defaultTagName, BakedInValidators)
// NewValidator creates a new Validator instance
// NOTE: it is not necessary to create a new validator as the internal one will do in 99.9% of cases, but the option is there.
func NewValidator(tagName string, funcs map[string]ValidationFunc) *Validator {
@ -124,21 +123,11 @@ func NewValidator(tagName string, funcs map[string]ValidationFunc) *Validator {
}
}
// SetTag sets the baked in Validator's tagName to one of your choosing
func SetTag(tagName string) {
internalValidator.SetTag(tagName)
}
// SetTag sets tagName of the Validator to one of your choosing
func (v *Validator) SetTag(tagName string) {
v.tagName = tagName
}
// AddFunction adds a ValidationFunc to the baked in Validator's map of validators denoted by the key
func AddFunction(key string, f ValidationFunc) error {
return internalValidator.AddFunction(key, f)
}
// AddFunction adds a ValidationFunc to a Validator's map of validators denoted by the key
func (v *Validator) AddFunction(key string, f ValidationFunc) error {
@ -160,12 +149,6 @@ func (v *Validator) AddFunction(key string, f ValidationFunc) error {
return nil
}
// ValidateStruct validates a struct and returns a struct containing the errors
func ValidateStruct(s interface{}) *StructValidationErrors {
return internalValidator.ValidateStruct(s)
}
// ValidateStruct validates a struct and returns a struct containing the errors
func (v *Validator) ValidateStruct(s interface{}) *StructValidationErrors {
@ -206,7 +189,7 @@ func (v *Validator) validateStructRecursive(top interface{}, s interface{}) *Str
tag := typeField.Tag.Get(v.tagName)
if tag == "-" {
if tag == noValidationTag {
continue
}
@ -257,24 +240,12 @@ func (v *Validator) validateStructRecursive(top interface{}, s interface{}) *Str
return validationErrors
}
// ValidateFieldByTag allows validation of a single field with the internal validator, still using tag style validation to check multiple errors
func ValidateFieldByTag(f interface{}, tag string) *FieldValidationError {
return internalValidator.ValidateFieldByTag(f, tag)
}
// ValidateFieldByTag allows validation of a single field, still using tag style validation to check multiple errors
func (v *Validator) ValidateFieldByTag(f interface{}, tag string) *FieldValidationError {
return v.ValidateFieldByTagAndValue(nil, f, tag)
}
// ValidateFieldByTagAndValue allows validation of a single field with the internal validator, still using tag style validation to check multiple errors
func ValidateFieldByTagAndValue(val interface{}, f interface{}, tag string) *FieldValidationError {
return internalValidator.ValidateFieldByTagAndValue(val, f, tag)
}
// ValidateFieldByTagAndValue allows validation of a single field, still using tag style validation to check multiple errors
func (v *Validator) ValidateFieldByTagAndValue(val interface{}, f interface{}, tag string) *FieldValidationError {
@ -284,7 +255,7 @@ func (v *Validator) ValidateFieldByTagAndValue(val interface{}, f interface{}, t
func (v *Validator) validateFieldByNameAndTagAndValue(val interface{}, f interface{}, name string, tag string) *FieldValidationError {
// This is a double check if coming from ValidateStruct but need to be here in case function is called directly
if tag == "-" {
if tag == noValidationTag {
return nil
}
@ -312,11 +283,11 @@ func (v *Validator) validateFieldByNameAndTagAndValue(val interface{}, f interfa
var valErr *FieldValidationError
var err error
valTags := strings.Split(tag, ",")
valTags := strings.Split(tag, tagSeparator)
for _, valTag := range valTags {
orVals := strings.Split(valTag, "|")
orVals := strings.Split(valTag, orSeparator)
if len(orVals) > 1 {
@ -330,11 +301,11 @@ func (v *Validator) validateFieldByNameAndTagAndValue(val interface{}, f interfa
return nil
}
errTag += "|" + valErr.ErrorTag
errTag += orSeparator + valErr.ErrorTag
}
errTag = strings.TrimLeft(errTag, "|")
errTag = strings.TrimLeft(errTag, orSeparator)
valErr.ErrorTag = errTag
valErr.Kind = fieldKind
@ -356,7 +327,7 @@ func (v *Validator) validateFieldByNameAndTagAndValue(val interface{}, f interfa
func (v *Validator) validateFieldByNameAndSingleTag(val interface{}, f interface{}, name string, valTag string) (*FieldValidationError, error) {
vals := strings.Split(valTag, "=")
vals := strings.Split(valTag, tagKeySeparator)
key := strings.Trim(vals[0], " ")
if len(key) == 0 {

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save