Merge pull request #141 from bluesuncorp/v6-development

Add RegisterCustomTypeFunc for easier adding of CustomTypeFunc
pull/153/head
Dean Karn 9 years ago
commit a13509df8f
  1. 83
      README.md
  2. 48
      examples/custom/custom.go
  3. 0
      examples/simple/simple.go
  4. 14
      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)
[![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)
[![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
import (
"errors"
"database/sql"
"database/sql/driver"
"fmt"
"reflect"
sql "database/sql/driver"
"gopkg.in/bluesuncorp/validator.v6"
)
var validate *validator.Validate
type valuer struct {
Name string
}
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
// DbBackedUser User struct
type DbBackedUser struct {
Name sql.NullString `validate:"required"`
Age sql.NullInt64 `validate:"required"`
}
func main() {
customTypes := map[reflect.Type]validator.CustomTypeFunc{}
customTypes[reflect.TypeOf((*sql.Valuer)(nil))] = ValidateValuerType
customTypes[reflect.TypeOf(valuer{})] = ValidateValuerType
config := validator.Config{
TagName: "validate",
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() {
val := valuer{
Name: "blankme",
}
x := DbBackedUser{Name: sql.NullString{String: "", Valid: true}, Age: sql.NullInt64{Int64: 0, Valid: false}}
errs := validate.Struct(x)
errs := validate.Field(val, "required")
if errs != nil {
fmt.Println(errs) // output: Key: "" Error:Field validation for "" failed on the "required" tag
return
if len(errs) > 0 {
fmt.Printf("Errs:\n%+v\n", errs)
}
// 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

@ -0,0 +1,48 @@
package main
import (
"database/sql"
"database/sql/driver"
"fmt"
"reflect"
"gopkg.in/bluesuncorp/validator.v6"
)
// DbBackedUser User struct
type DbBackedUser struct {
Name sql.NullString `validate:"required"`
Age sql.NullInt64 `validate:"required"`
}
func main() {
config := validator.Config{
TagName: "validate",
ValidationFuncs: validator.BakedInValidators,
}
validate := validator.New(config)
// register all sql.Null* types to use the ValidateValuer CustomTypeFunc
validate.RegisterCustomTypeFunc(ValidateValuer, sql.NullString{}, sql.NullInt64{}, sql.NullBool{}, sql.NullFloat64{})
x := DbBackedUser{Name: sql.NullString{String: "", Valid: true}, Age: sql.NullInt64{Int64: 0, Valid: false}}
errs := validate.Struct(x)
if len(errs) > 0 {
fmt.Printf("Errs:\n%+v\n", errs)
}
}
// 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
}

@ -157,6 +157,20 @@ func (v *Validate) RegisterValidation(key string, f Func) error {
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{}
}
for _, t := range types {
v.config.CustomTypeFuncs[reflect.TypeOf(t)] = fn
}
v.config.hasCustomFuncs = true
}
// Field validates a single field using tag style validation and returns ValidationErrors
// 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

@ -1,14 +1,14 @@
package validator
import (
"database/sql"
"database/sql/driver"
"errors"
"fmt"
"reflect"
"testing"
"time"
sql "database/sql/driver"
. "gopkg.in/bluesuncorp/assert.v1"
)
@ -126,7 +126,7 @@ type valuer struct {
Name string
}
func (v valuer) Value() (sql.Value, error) {
func (v valuer) Value() (driver.Value, error) {
if v.Name == "errorme" {
return nil, errors.New("some kind of error")
@ -178,7 +178,7 @@ type CustomMadeUpStruct struct {
}
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()
if err != nil {
// handle the error how you want
@ -191,10 +191,68 @@ func ValidateValuerType(field reflect.Value) interface{} {
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) {
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(MadeUpCustomType{})] = ValidateCustomType
customTypes[reflect.TypeOf(1)] = OverrideIntTypeForSomeReason

Loading…
Cancel
Save