Add RegisterCustomTypeFunc for easier adding of CustomTypeFunc

Thanks @johnniedoe for ths pull request!
pull/140/head
joeybloggs 9 years ago
parent 7c844893e1
commit d2ea21ad15
  1. 83
      README.md
  2. 3
      examples/custom/custom.go
  3. 0
      examples/simple/simple.go
  4. 11
      validator.go
  5. 68
      validator_test.go

@ -2,7 +2,7 @@ Package validator
================ ================
[![Join the chat at https://gitter.im/bluesuncorp/validator](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/bluesuncorp/validator?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Join the chat at https://gitter.im/bluesuncorp/validator](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/bluesuncorp/validator?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[![Build Status](https://semaphoreci.com/api/v1/projects/ec20115f-ef1b-4c7d-9393-cc76aba74eb4/487374/badge.svg)](https://semaphoreci.com/joeybloggs/validator) [![Build Status](https://semaphoreci.com/api/v1/projects/ec20115f-ef1b-4c7d-9393-cc76aba74eb4/487383/badge.svg)](https://semaphoreci.com/joeybloggs/validator)
[![Coverage Status](https://coveralls.io/repos/bluesuncorp/validator/badge.svg?branch=v6)](https://coveralls.io/r/bluesuncorp/validator?branch=v6) [![Coverage Status](https://coveralls.io/repos/bluesuncorp/validator/badge.svg?branch=v6)](https://coveralls.io/r/bluesuncorp/validator?branch=v6)
[![GoDoc](https://godoc.org/gopkg.in/bluesuncorp/validator.v6?status.svg)](https://godoc.org/gopkg.in/bluesuncorp/validator.v6) [![GoDoc](https://godoc.org/gopkg.in/bluesuncorp/validator.v6?status.svg)](https://godoc.org/gopkg.in/bluesuncorp/validator.v6)
@ -138,84 +138,51 @@ Custom Field Type
package main package main
import ( import (
"errors" "database/sql"
"database/sql/driver"
"fmt" "fmt"
"reflect" "reflect"
sql "database/sql/driver"
"gopkg.in/bluesuncorp/validator.v6" "gopkg.in/bluesuncorp/validator.v6"
) )
var validate *validator.Validate // DbBackedUser User struct
type DbBackedUser struct {
type valuer struct { Name sql.NullString `validate:"required"`
Name string Age sql.NullInt64 `validate:"required"`
}
func (v valuer) Value() (sql.Value, error) {
if v.Name == "errorme" {
return nil, errors.New("some kind of error")
}
if v.Name == "blankme" {
return "", nil
}
if len(v.Name) == 0 {
return nil, nil
}
return v.Name, nil
}
// ValidateValuerType implements validator.CustomTypeFunc
func ValidateValuerType(field reflect.Value) interface{} {
if valuer, ok := field.Interface().(sql.Valuer); ok {
val, err := valuer.Value()
if err != nil {
// handle the error how you want
return nil
}
return val
}
return nil
} }
func main() { func main() {
customTypes := map[reflect.Type]validator.CustomTypeFunc{}
customTypes[reflect.TypeOf((*sql.Valuer)(nil))] = ValidateValuerType
customTypes[reflect.TypeOf(valuer{})] = ValidateValuerType
config := validator.Config{ config := validator.Config{
TagName: "validate", TagName: "validate",
ValidationFuncs: validator.BakedInValidators, ValidationFuncs: validator.BakedInValidators,
CustomTypeFuncs: customTypes,
} }
validate = validator.New(config) validate := validator.New(config)
validateCustomFieldType() // register all sql.Null* types to use the ValidateValuer CustomTypeFunc
} validate.RegisterCustomTypeFunc(ValidateValuer, sql.NullString{}, sql.NullInt64{}, sql.NullBool{}, sql.NullFloat64{})
func validateCustomFieldType() { x := DbBackedUser{Name: sql.NullString{String: "", Valid: true}, Age: sql.NullInt64{Int64: 0, Valid: false}}
val := valuer{ errs := validate.Struct(x)
Name: "blankme",
}
errs := validate.Field(val, "required") if len(errs) > 0 {
if errs != nil { fmt.Printf("Errs:\n%+v\n", errs)
fmt.Println(errs) // output: Key: "" Error:Field validation for "" failed on the "required" tag
return
} }
// all ok
} }
// ValidateValuer implements validator.CustomTypeFunc
func ValidateValuer(field reflect.Value) interface{} {
if valuer, ok := field.Interface().(driver.Valuer); ok {
val, err := valuer.Value()
if err == nil {
return val
}
// handle the error how you want
}
return nil
}
``` ```
Benchmarks Benchmarks

@ -6,9 +6,10 @@ import (
"fmt" "fmt"
"reflect" "reflect"
validator "gopkg.in/bluesuncorp/validator.v6" "gopkg.in/bluesuncorp/validator.v6"
) )
// DbBackedUser User struct
type DbBackedUser struct { type DbBackedUser struct {
Name sql.NullString `validate:"required"` Name sql.NullString `validate:"required"`
Age sql.NullInt64 `validate:"required"` Age sql.NullInt64 `validate:"required"`

@ -157,14 +157,17 @@ func (v *Validate) RegisterValidation(key string, f Func) error {
return nil return nil
} }
// RegisterCustomTypeFunc registers types w/a custom type handler function. // RegisterCustomTypeFunc registers a CustomTypeFunc against a number of types
func (v *Validate) RegisterCustomTypeFunc(f CustomTypeFunc, sampleTypeValues ...interface{}) { func (v *Validate) RegisterCustomTypeFunc(fn CustomTypeFunc, types ...interface{}) {
if v.config.CustomTypeFuncs == nil { if v.config.CustomTypeFuncs == nil {
v.config.CustomTypeFuncs = map[reflect.Type]CustomTypeFunc{} v.config.CustomTypeFuncs = map[reflect.Type]CustomTypeFunc{}
} }
for _, sample := range sampleTypeValues {
v.config.CustomTypeFuncs[reflect.TypeOf(sample)] = f for _, t := range types {
v.config.CustomTypeFuncs[reflect.TypeOf(t)] = fn
} }
v.config.hasCustomFuncs = true v.config.hasCustomFuncs = true
} }

@ -1,14 +1,14 @@
package validator package validator
import ( import (
"database/sql"
"database/sql/driver"
"errors" "errors"
"fmt" "fmt"
"reflect" "reflect"
"testing" "testing"
"time" "time"
sql "database/sql/driver"
. "gopkg.in/bluesuncorp/assert.v1" . "gopkg.in/bluesuncorp/assert.v1"
) )
@ -126,7 +126,7 @@ type valuer struct {
Name string Name string
} }
func (v valuer) Value() (sql.Value, error) { func (v valuer) Value() (driver.Value, error) {
if v.Name == "errorme" { if v.Name == "errorme" {
return nil, errors.New("some kind of error") return nil, errors.New("some kind of error")
@ -178,7 +178,7 @@ type CustomMadeUpStruct struct {
} }
func ValidateValuerType(field reflect.Value) interface{} { func ValidateValuerType(field reflect.Value) interface{} {
if valuer, ok := field.Interface().(sql.Valuer); ok { if valuer, ok := field.Interface().(driver.Valuer); ok {
val, err := valuer.Value() val, err := valuer.Value()
if err != nil { if err != nil {
// handle the error how you want // handle the error how you want
@ -191,10 +191,68 @@ func ValidateValuerType(field reflect.Value) interface{} {
return nil return nil
} }
func TestSQLValue2Validation(t *testing.T) {
config := Config{
TagName: "validate",
ValidationFuncs: BakedInValidators,
}
validate := New(config)
validate.RegisterCustomTypeFunc(ValidateValuerType, valuer{}, (*driver.Valuer)(nil), sql.NullString{}, sql.NullInt64{}, sql.NullBool{}, sql.NullFloat64{})
validate.RegisterCustomTypeFunc(ValidateCustomType, MadeUpCustomType{})
validate.RegisterCustomTypeFunc(OverrideIntTypeForSomeReason, 1)
val := valuer{
Name: "",
}
errs := validate.Field(val, "required")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "required")
val.Name = "Valid Name"
errs = validate.Field(val, "required")
Equal(t, errs, nil)
val.Name = "errorme"
PanicMatches(t, func() { errs = validate.Field(val, "required") }, "SQL Driver Valuer error: some kind of error")
type myValuer valuer
myVal := valuer{
Name: "",
}
errs = validate.Field(myVal, "required")
NotEqual(t, errs, nil)
AssertError(t, errs, "", "", "required")
cust := MadeUpCustomType{
FirstName: "Joey",
LastName: "Bloggs",
}
c := CustomMadeUpStruct{MadeUp: cust, OverriddenInt: 2}
errs = validate.Struct(c)
Equal(t, errs, nil)
c.MadeUp.FirstName = ""
c.OverriddenInt = 1
errs = validate.Struct(c)
NotEqual(t, errs, nil)
Equal(t, len(errs), 2)
AssertError(t, errs, "CustomMadeUpStruct.MadeUp", "MadeUp", "required")
AssertError(t, errs, "CustomMadeUpStruct.OverriddenInt", "OverriddenInt", "gt")
}
func TestSQLValueValidation(t *testing.T) { func TestSQLValueValidation(t *testing.T) {
customTypes := map[reflect.Type]CustomTypeFunc{} customTypes := map[reflect.Type]CustomTypeFunc{}
customTypes[reflect.TypeOf((*sql.Valuer)(nil))] = ValidateValuerType customTypes[reflect.TypeOf((*driver.Valuer)(nil))] = ValidateValuerType
customTypes[reflect.TypeOf(valuer{})] = ValidateValuerType customTypes[reflect.TypeOf(valuer{})] = ValidateValuerType
customTypes[reflect.TypeOf(MadeUpCustomType{})] = ValidateCustomType customTypes[reflect.TypeOf(MadeUpCustomType{})] = ValidateCustomType
customTypes[reflect.TypeOf(1)] = OverrideIntTypeForSomeReason customTypes[reflect.TypeOf(1)] = OverrideIntTypeForSomeReason

Loading…
Cancel
Save