Skip to content

Commit

Permalink
reorganization of code + variables to more appropriate structs
Browse files Browse the repository at this point in the history
  • Loading branch information
joeybloggs authored and joeybloggs committed Sep 2, 2015
1 parent 9988ba3 commit 10cf645
Show file tree
Hide file tree
Showing 6 changed files with 121 additions and 152 deletions.
4 changes: 2 additions & 2 deletions baked_in.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,14 @@ import (
// defines a common or complex set of validation(s) to simplify
// adding validation to structs. i.e. set key "_ageok" and the tags
// are "gt=0,lte=130" or key "_preferredname" and tags "omitempty,gt=0,lte=60"
var BakedInAliasValidators = map[string]string{
var bakedInAliasValidators = map[string]string{
"iscolor": "hexcolor|rgb|rgba|hsl|hsla",
}

// BakedInValidators is the default map of ValidationFunc
// you can add, remove or even replace items to suite your needs,
// or even disregard and use your own map if so desired.
var BakedInValidators = map[string]Func{
var bakedInValidators = map[string]Func{
"required": hasValue,
"len": hasLengthOf,
"min": hasMinOf,
Expand Down
21 changes: 1 addition & 20 deletions benchmarks_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,6 @@ func BenchmarkFieldDiveFailure(b *testing.B) {

func BenchmarkFieldCustomTypeSuccess(b *testing.B) {

// customTypes := map[reflect.Type]CustomTypeFunc{}
// customTypes[reflect.TypeOf((*sql.Valuer)(nil))] = ValidateValuerType
// customTypes[reflect.TypeOf(valuer{})] = ValidateValuerType

validate := New(Config{TagName: "validate"})
validate.RegisterCustomTypeFunc(ValidateValuerType, (*sql.Valuer)(nil), valuer{})

val := valuer{
Expand All @@ -50,11 +45,7 @@ func BenchmarkFieldCustomTypeSuccess(b *testing.B) {

func BenchmarkFieldCustomTypeFailure(b *testing.B) {

// customTypes := map[reflect.Type]CustomTypeFunc{}
// customTypes[reflect.TypeOf((*sql.Valuer)(nil))] = ValidateValuerType
// customTypes[reflect.TypeOf(valuer{})] = ValidateValuerType

validate := New(Config{TagName: "validate"})
// validate := New(Config{TagName: "validate"})
validate.RegisterCustomTypeFunc(ValidateValuerType, (*sql.Valuer)(nil), valuer{})

val := valuer{}
Expand All @@ -78,11 +69,6 @@ func BenchmarkFieldOrTagFailure(b *testing.B) {

func BenchmarkStructSimpleCustomTypeSuccess(b *testing.B) {

// customTypes := map[reflect.Type]CustomTypeFunc{}
// customTypes[reflect.TypeOf((*sql.Valuer)(nil))] = ValidateValuerType
// customTypes[reflect.TypeOf(valuer{})] = ValidateValuerType

validate := New(Config{TagName: "validate"})
validate.RegisterCustomTypeFunc(ValidateValuerType, (*sql.Valuer)(nil), valuer{})

val := valuer{
Expand All @@ -103,11 +89,6 @@ func BenchmarkStructSimpleCustomTypeSuccess(b *testing.B) {

func BenchmarkStructSimpleCustomTypeFailure(b *testing.B) {

// customTypes := map[reflect.Type]CustomTypeFunc{}
// customTypes[reflect.TypeOf((*sql.Valuer)(nil))] = ValidateValuerType
// customTypes[reflect.TypeOf(valuer{})] = ValidateValuerType

validate := New(Config{TagName: "validate"})
validate.RegisterCustomTypeFunc(ValidateValuerType, (*sql.Valuer)(nil), valuer{})

val := valuer{}
Expand Down
22 changes: 7 additions & 15 deletions examples_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,12 @@ package validator_test
import (
"fmt"

"gopkg.in/bluesuncorp/validator.v7"
// "gopkg.in/bluesuncorp/validator.v7"
"../validator"
)

func ExampleValidate_new() {
config := validator.Config{
TagName: "validate",
ValidationFuncs: validator.BakedInValidators,
}
config := validator.Config{TagName: "validate"}

validator.New(config)
}
Expand All @@ -19,16 +17,13 @@ func ExampleValidate_field() {
// This should be stored somewhere globally
var validate *validator.Validate

config := validator.Config{
TagName: "validate",
ValidationFuncs: validator.BakedInValidators,
}
config := validator.Config{TagName: "validate"}

validate = validator.New(config)

i := 0
errs := validate.Field(i, "gt=1,lte=10")
err := errs[""]
err := errs.(validator.ValidationErrors)[""]
fmt.Println(err.Field)
fmt.Println(err.Tag)
fmt.Println(err.Kind) // NOTE: Kind and Type can be different i.e. time Kind=struct and Type=time.Time
Expand All @@ -48,10 +43,7 @@ func ExampleValidate_struct() {
// This should be stored somewhere globally
var validate *validator.Validate

config := validator.Config{
TagName: "validate",
ValidationFuncs: validator.BakedInValidators,
}
config := validator.Config{TagName: "validate"}

validate = validator.New(config)

Expand Down Expand Up @@ -81,7 +73,7 @@ func ExampleValidate_struct() {
}

errs := validate.Struct(user)
for _, v := range errs {
for _, v := range errs.(validator.ValidationErrors) {
fmt.Println(v.Field) // Phone
fmt.Println(v.Tag) // required
//... and so forth
Expand Down
8 changes: 4 additions & 4 deletions util.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,8 @@ func (v *Validate) extractType(current reflect.Value) (reflect.Value, reflect.Ki

default:

if v.config.hasCustomFuncs {
if fn, ok := v.config.customTypeFuncs[current.Type()]; ok {
if v.hasCustomFuncs {
if fn, ok := v.customTypeFuncs[current.Type()]; ok {
return v.extractType(reflect.ValueOf(fn(current)))
}
}
Expand Down Expand Up @@ -248,9 +248,9 @@ func (v *Validate) parseTagsRecursive(cTag *cachedTag, tag, fieldName, alias str

for _, t := range strings.Split(tag, tagSeparator) {

if v.config.hasAliasValidators {
if v.hasAliasValidators {
// check map for alias and process new tags, otherwise process as usual
if tagsVal, ok := v.config.aliasValidators[t]; ok {
if tagsVal, ok := v.aliasValidators[t]; ok {

leave := v.parseTagsRecursive(cTag, tagsVal, fieldName, t, true)

Expand Down
94 changes: 44 additions & 50 deletions validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,8 @@ const (
var (
timeType = reflect.TypeOf(time.Time{})
timePtrType = reflect.TypeOf(&time.Time{})
errsPool = &sync.Pool{New: newValidationErrors}
tagsCache = &tagCacheMap{m: map[string]*cachedTag{}}
emptyStructPtr = new(struct{})
errsPool = &sync.Pool{New: newValidationErrors}
)

// returns new ValidationErrors to the pool
Expand Down Expand Up @@ -83,18 +82,19 @@ func (s *tagCacheMap) Set(key string, value *cachedTag) {

// Validate contains the validator settings passed in using the Config struct
type Validate struct {
config Config
}

// Config contains the options that a Validator instance will use.
// It is passed to the New() function
type Config struct {
TagName string
config Config
validationFuncs map[string]Func
customTypeFuncs map[reflect.Type]CustomTypeFunc
aliasValidators map[string]string
hasCustomFuncs bool
hasAliasValidators bool
tagsCache *tagCacheMap
}

// Config contains the options that a Validator instance will use.
// It is passed to the New() function
type Config struct {
TagName string
}

// CustomTypeFunc allows for overriding or adding custom field type handler functions
Expand Down Expand Up @@ -149,20 +149,20 @@ func New(config Config) *Validate {
// if config.CustomTypeFuncs != nil && len(config.CustomTypeFuncs) > 0 {
// config.hasCustomFuncs = true
// }
v := &Validate{config: config}
v := &Validate{config: config, tagsCache: &tagCacheMap{m: map[string]*cachedTag{}}}

if len(v.config.aliasValidators) == 0 {
// must copy validators for separate validations to be used in each
v.config.aliasValidators = map[string]string{}
for k, val := range BakedInAliasValidators {
if len(v.aliasValidators) == 0 {
// must copy validators for separate validations to be used in each validator instance
v.aliasValidators = map[string]string{}
for k, val := range bakedInAliasValidators {
v.RegisterAliasValidation(k, val)
}
}

if len(v.config.validationFuncs) == 0 {
// must copy validators for separate validations to be used in each
v.config.validationFuncs = map[string]Func{}
for k, val := range BakedInValidators {
if len(v.validationFuncs) == 0 {
// must copy validators for separate validations to be used in each instance
v.validationFuncs = map[string]Func{}
for k, val := range bakedInValidators {
v.RegisterValidation(k, val)
}
}
Expand All @@ -189,23 +189,23 @@ func (v *Validate) RegisterValidation(key string, f Func) error {
panic(fmt.Sprintf(restrictedTagErr, key))
}

v.config.validationFuncs[key] = f
v.validationFuncs[key] = f

return nil
}

// RegisterCustomTypeFunc registers a CustomTypeFunc against a number of types
func (v *Validate) RegisterCustomTypeFunc(fn CustomTypeFunc, types ...interface{}) {

if v.config.customTypeFuncs == nil {
v.config.customTypeFuncs = map[reflect.Type]CustomTypeFunc{}
if v.customTypeFuncs == nil {
v.customTypeFuncs = map[reflect.Type]CustomTypeFunc{}
}

for _, t := range types {
v.config.customTypeFuncs[reflect.TypeOf(t)] = fn
v.customTypeFuncs[reflect.TypeOf(t)] = fn
}

v.config.hasCustomFuncs = true
v.hasCustomFuncs = true
}

// RegisterAliasValidation registers a mapping of a single validationstag that
Expand All @@ -216,28 +216,21 @@ func (v *Validate) RegisterCustomTypeFunc(fn CustomTypeFunc, types ...interface{
// will be the actual tag within the alias that failed.
func (v *Validate) RegisterAliasValidation(alias, tags string) {

// if len(v.config.aliasValidators) == 0 {
// // must copy validators for separate validations to be used in each
// v.config.aliasValidators = map[string]string{}
// for k, val := range BakedInAliasValidators {
// v.config.aliasValidators[k] = val
// }
// }

_, ok := restrictedTags[alias]

if ok || strings.ContainsAny(alias, restrictedTagChars) {
panic(fmt.Sprintf(restrictedAliasErr, alias))
}

v.config.aliasValidators[alias] = tags
v.config.hasAliasValidators = true
v.aliasValidators[alias] = tags
v.hasAliasValidators = true
}

// Field validates a single field using tag style validation and returns ValidationErrors
// Field validates a single field using tag style validation and returns nil or ValidationErrors as type error.
// You will need to assert the error if it's not nil i.e. err.(validator.ValidationErrors) to access the map of errors.
// NOTE: it returns ValidationErrors instead of a single FieldError because this can also
// validate Array, Slice and maps fields which may contain more than one error
func (v *Validate) Field(field interface{}, tag string) ValidationErrors {
func (v *Validate) Field(field interface{}, tag string) error {

errs := errsPool.Get().(ValidationErrors)
fieldVal := reflect.ValueOf(field)
Expand All @@ -252,10 +245,11 @@ func (v *Validate) Field(field interface{}, tag string) ValidationErrors {
return errs
}

// FieldWithValue validates a single field, against another fields value using tag style validation and returns ValidationErrors
// FieldWithValue validates a single field, against another fields value using tag style validation and returns nil or ValidationErrors.
// You will need to assert the error if it's not nil i.e. err.(validator.ValidationErrors) to access the map of errors.
// NOTE: it returns ValidationErrors instead of a single FieldError because this can also
// validate Array, Slice and maps fields which may contain more than one error
func (v *Validate) FieldWithValue(val interface{}, field interface{}, tag string) ValidationErrors {
func (v *Validate) FieldWithValue(val interface{}, field interface{}, tag string) error {

errs := errsPool.Get().(ValidationErrors)
topVal := reflect.ValueOf(val)
Expand All @@ -272,10 +266,9 @@ func (v *Validate) FieldWithValue(val interface{}, field interface{}, tag string

// StructPartial validates the fields passed in only, ignoring all others.
// Fields may be provided in a namespaced fashion relative to the struct provided
// i.e. NestedStruct.Field or NestedArrayField[0].Struct.Name
// NOTE: This is normally not needed, however in some specific cases such as: tied to a
// legacy data structure, it will be useful
func (v *Validate) StructPartial(current interface{}, fields ...string) ValidationErrors {
// i.e. NestedStruct.Field or NestedArrayField[0].Struct.Name and returns nil or ValidationErrors as error
// You will need to assert the error if it's not nil i.e. err.(validator.ValidationErrors) to access the map of errors.
func (v *Validate) StructPartial(current interface{}, fields ...string) error {

sv, _ := v.extractType(reflect.ValueOf(current))
name := sv.Type().Name()
Expand Down Expand Up @@ -330,10 +323,9 @@ func (v *Validate) StructPartial(current interface{}, fields ...string) Validati

// StructExcept validates all fields except the ones passed in.
// Fields may be provided in a namespaced fashion relative to the struct provided
// i.e. NestedStruct.Field or NestedArrayField[0].Struct.Name
// NOTE: This is normally not needed, however in some specific cases such as: tied to a
// legacy data structure, it will be useful
func (v *Validate) StructExcept(current interface{}, fields ...string) ValidationErrors {
// i.e. NestedStruct.Field or NestedArrayField[0].Struct.Name and returns nil or ValidationErrors as error
// You will need to assert the error if it's not nil i.e. err.(validator.ValidationErrors) to access the map of errors.
func (v *Validate) StructExcept(current interface{}, fields ...string) error {

sv, _ := v.extractType(reflect.ValueOf(current))
name := sv.Type().Name()
Expand All @@ -356,7 +348,9 @@ func (v *Validate) StructExcept(current interface{}, fields ...string) Validatio
}

// Struct validates a structs exposed fields, and automatically validates nested structs, unless otherwise specified.
func (v *Validate) Struct(current interface{}) ValidationErrors {
// it returns nil or ValidationErrors as error.
// You will need to assert the error if it's not nil i.e. err.(validator.ValidationErrors) to access the map of errors.
func (v *Validate) Struct(current interface{}) error {

errs := errsPool.Get().(ValidationErrors)
sv := reflect.ValueOf(current)
Expand Down Expand Up @@ -420,11 +414,11 @@ func (v *Validate) traverseField(topStruct reflect.Value, currentStruct reflect.
return
}

cTag, isCached := tagsCache.Get(tag)
cTag, isCached := v.tagsCache.Get(tag)

if !isCached {
cTag = v.parseTags(tag, name)
tagsCache.Set(tag, cTag)
v.tagsCache.Set(tag, cTag)
}

current, kind := v.extractType(current)
Expand Down Expand Up @@ -561,7 +555,7 @@ func (v *Validate) validateField(topStruct reflect.Value, currentStruct reflect.

for _, val := range valTag.tagVals {

valFunc, ok = v.config.validationFuncs[val[0]]
valFunc, ok = v.validationFuncs[val[0]]
if !ok {
panic(strings.TrimSpace(fmt.Sprintf(undefinedValidation, name)))
}
Expand Down Expand Up @@ -596,7 +590,7 @@ func (v *Validate) validateField(topStruct reflect.Value, currentStruct reflect.
return true
}

valFunc, ok = v.config.validationFuncs[valTag.tagVals[0][0]]
valFunc, ok = v.validationFuncs[valTag.tagVals[0][0]]
if !ok {
panic(strings.TrimSpace(fmt.Sprintf(undefinedValidation, name)))
}
Expand Down
Loading

0 comments on commit 10cf645

Please sign in to comment.