forked from Fuyu/validate
Add support for custom validation rules
This commit is contained in:
parent
922297b368
commit
f79b7c6649
14
input.go
14
input.go
@ -6,15 +6,21 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
func inputInt(kind reflect.Kind, value string) interface{} {
|
// InputFunc is a function that converts the parameter of a validation rule to the desired type
|
||||||
return int(inputSame(reflect.Int, value).(int64))
|
type InputFunc func(reflect.Kind, string) interface{}
|
||||||
|
|
||||||
|
// InputInt always returns an int
|
||||||
|
func InputInt(kind reflect.Kind, value string) interface{} {
|
||||||
|
return int(InputSame(reflect.Int, value).(int64))
|
||||||
}
|
}
|
||||||
|
|
||||||
func inputRegexp(kind reflect.Kind, value string) interface{} {
|
// InputRegexp always returns a compiled regular expression
|
||||||
|
func InputRegexp(kind reflect.Kind, value string) interface{} {
|
||||||
return regexp.MustCompile(value)
|
return regexp.MustCompile(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
func inputSame(kind reflect.Kind, value string) interface{} {
|
// InputSame returns the type matching the field
|
||||||
|
func InputSame(kind reflect.Kind, value string) interface{} {
|
||||||
var val interface{}
|
var val interface{}
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
|
38
rules.go
38
rules.go
@ -6,17 +6,25 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
type listFunc func(reflect.Value, interface{}) bool
|
// ValidationFunc is a function to validate a field
|
||||||
|
type ValidationFunc func(reflect.Value, interface{}) bool
|
||||||
|
|
||||||
|
// Kinds is a map with validation funcs for each reflect.Kind
|
||||||
|
type Kinds map[reflect.Kind]ValidationFunc
|
||||||
|
|
||||||
type listFuncInfo struct {
|
type listFuncInfo struct {
|
||||||
inputFunc func(reflect.Kind, string) interface{}
|
inputFunc InputFunc
|
||||||
kinds _kinds
|
kinds Kinds
|
||||||
}
|
}
|
||||||
|
|
||||||
type _kinds map[reflect.Kind]listFunc
|
// AddRule adds a rule to the list of validation functions
|
||||||
|
func AddRule(name string, inputFunc InputFunc, kinds Kinds) {
|
||||||
|
funcs[name] = listFuncInfo{inputFunc, kinds}
|
||||||
|
}
|
||||||
|
|
||||||
// nolint: dupl
|
// nolint: dupl
|
||||||
var funcs = map[string]listFuncInfo{
|
var funcs = map[string]listFuncInfo{
|
||||||
`required`: {nil, _kinds{
|
`required`: {nil, Kinds{
|
||||||
reflect.Ptr: func(rv reflect.Value, _ interface{}) bool {
|
reflect.Ptr: func(rv reflect.Value, _ interface{}) bool {
|
||||||
return !rv.IsNil()
|
return !rv.IsNil()
|
||||||
},
|
},
|
||||||
@ -44,29 +52,29 @@ var funcs = map[string]listFuncInfo{
|
|||||||
}},
|
}},
|
||||||
|
|
||||||
// Strings
|
// Strings
|
||||||
`prefix`: {inputSame, _kinds{
|
`prefix`: {InputSame, Kinds{
|
||||||
reflect.String: func(rv reflect.Value, val interface{}) bool {
|
reflect.String: func(rv reflect.Value, val interface{}) bool {
|
||||||
return strings.HasPrefix(rv.String(), val.(string))
|
return strings.HasPrefix(rv.String(), val.(string))
|
||||||
},
|
},
|
||||||
}},
|
}},
|
||||||
`suffix`: {inputSame, _kinds{
|
`suffix`: {InputSame, Kinds{
|
||||||
reflect.String: func(rv reflect.Value, val interface{}) bool {
|
reflect.String: func(rv reflect.Value, val interface{}) bool {
|
||||||
return strings.HasSuffix(rv.String(), val.(string))
|
return strings.HasSuffix(rv.String(), val.(string))
|
||||||
},
|
},
|
||||||
}},
|
}},
|
||||||
`contains`: {inputSame, _kinds{
|
`contains`: {InputSame, Kinds{
|
||||||
reflect.String: func(rv reflect.Value, val interface{}) bool {
|
reflect.String: func(rv reflect.Value, val interface{}) bool {
|
||||||
return strings.Contains(rv.String(), val.(string))
|
return strings.Contains(rv.String(), val.(string))
|
||||||
},
|
},
|
||||||
}},
|
}},
|
||||||
`regexp`: {inputRegexp, _kinds{
|
`regexp`: {InputRegexp, Kinds{
|
||||||
reflect.String: func(rv reflect.Value, val interface{}) bool {
|
reflect.String: func(rv reflect.Value, val interface{}) bool {
|
||||||
return val.(*regexp.Regexp).MatchString(rv.String())
|
return val.(*regexp.Regexp).MatchString(rv.String())
|
||||||
},
|
},
|
||||||
}},
|
}},
|
||||||
|
|
||||||
// Comparisons
|
// Comparisons
|
||||||
`eq`: {inputSame, _kinds{
|
`eq`: {InputSame, Kinds{
|
||||||
reflect.String: func(rv reflect.Value, val interface{}) bool {
|
reflect.String: func(rv reflect.Value, val interface{}) bool {
|
||||||
return rv.String() == val.(string)
|
return rv.String() == val.(string)
|
||||||
},
|
},
|
||||||
@ -82,7 +90,7 @@ var funcs = map[string]listFuncInfo{
|
|||||||
}},
|
}},
|
||||||
|
|
||||||
// Integers
|
// Integers
|
||||||
`gt`: {inputSame, _kinds{
|
`gt`: {InputSame, Kinds{
|
||||||
reflect.Int: func(rv reflect.Value, val interface{}) bool {
|
reflect.Int: func(rv reflect.Value, val interface{}) bool {
|
||||||
return rv.Int() > val.(int64)
|
return rv.Int() > val.(int64)
|
||||||
},
|
},
|
||||||
@ -93,7 +101,7 @@ var funcs = map[string]listFuncInfo{
|
|||||||
return rv.Float() > val.(float64)
|
return rv.Float() > val.(float64)
|
||||||
},
|
},
|
||||||
}},
|
}},
|
||||||
`lt`: {inputSame, _kinds{
|
`lt`: {InputSame, Kinds{
|
||||||
reflect.Int: func(rv reflect.Value, val interface{}) bool {
|
reflect.Int: func(rv reflect.Value, val interface{}) bool {
|
||||||
return rv.Int() < val.(int64)
|
return rv.Int() < val.(int64)
|
||||||
},
|
},
|
||||||
@ -106,7 +114,7 @@ var funcs = map[string]listFuncInfo{
|
|||||||
}},
|
}},
|
||||||
|
|
||||||
// Slices, maps & strings
|
// Slices, maps & strings
|
||||||
`len`: {inputInt, _kinds{
|
`len`: {InputInt, Kinds{
|
||||||
reflect.Slice: func(rv reflect.Value, val interface{}) bool {
|
reflect.Slice: func(rv reflect.Value, val interface{}) bool {
|
||||||
return rv.Len() == val.(int)
|
return rv.Len() == val.(int)
|
||||||
},
|
},
|
||||||
@ -117,7 +125,7 @@ var funcs = map[string]listFuncInfo{
|
|||||||
return rv.Len() == val.(int)
|
return rv.Len() == val.(int)
|
||||||
},
|
},
|
||||||
}},
|
}},
|
||||||
`min`: {inputInt, _kinds{
|
`min`: {InputInt, Kinds{
|
||||||
reflect.Slice: func(rv reflect.Value, val interface{}) bool {
|
reflect.Slice: func(rv reflect.Value, val interface{}) bool {
|
||||||
return rv.Len() >= val.(int)
|
return rv.Len() >= val.(int)
|
||||||
},
|
},
|
||||||
@ -128,7 +136,7 @@ var funcs = map[string]listFuncInfo{
|
|||||||
return rv.Len() >= val.(int)
|
return rv.Len() >= val.(int)
|
||||||
},
|
},
|
||||||
}},
|
}},
|
||||||
`max`: {inputInt, _kinds{
|
`max`: {InputInt, Kinds{
|
||||||
reflect.Slice: func(rv reflect.Value, val interface{}) bool {
|
reflect.Slice: func(rv reflect.Value, val interface{}) bool {
|
||||||
return rv.Len() <= val.(int)
|
return rv.Len() <= val.(int)
|
||||||
},
|
},
|
||||||
|
@ -1,9 +1,29 @@
|
|||||||
package validate
|
package validate
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func TestAddRule(t *testing.T) {
|
||||||
|
type s struct {
|
||||||
|
A string `validate:"custom"`
|
||||||
|
}
|
||||||
|
|
||||||
|
AddRule(`custom`, nil, Kinds{
|
||||||
|
reflect.String: func(rv reflect.Value, _ interface{}) bool {
|
||||||
|
return rv.String() == `custom`
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
var pass = s{`custom`}
|
||||||
|
|
||||||
|
var fail = s{`somethingelse`}
|
||||||
|
|
||||||
|
check(t, pass, 0)
|
||||||
|
check(t, fail, 1)
|
||||||
|
}
|
||||||
|
|
||||||
func TestRuleRequired(t *testing.T) {
|
func TestRuleRequired(t *testing.T) {
|
||||||
type s struct {
|
type s struct {
|
||||||
A *string `validate:"required"`
|
A *string `validate:"required"`
|
||||||
|
@ -222,7 +222,7 @@ func getTagFuncs(i int, ft reflect.StructField, kind reflect.Kind, tags []string
|
|||||||
return rules
|
return rules
|
||||||
}
|
}
|
||||||
|
|
||||||
func getTagFunc(tag, value string, kind reflect.Kind) (listFunc, interface{}) {
|
func getTagFunc(tag, value string, kind reflect.Kind) (ValidationFunc, interface{}) {
|
||||||
tagInfo, ok := funcs[tag]
|
tagInfo, ok := funcs[tag]
|
||||||
if !ok {
|
if !ok {
|
||||||
panic(`Unknown validation ` + tag)
|
panic(`Unknown validation ` + tag)
|
||||||
|
Loading…
Reference in New Issue
Block a user