diff --git a/README.md b/README.md index ef9ada9..7288c25 100644 --- a/README.md +++ b/README.md @@ -86,6 +86,13 @@ regexp nonnil Validates that the given value is not nil. (Usage: nonnil) + +list + Validates that the given value is present in a list of + provided values. These values should be provided inside + square brackets separated by comma without any additional + spaces. It can be used with strings, integers and floating + point numbers. (Usage: list=[FOO,BAR,BAZ]) ``` Custom validators diff --git a/builtins.go b/builtins.go index 6fdb92b..c257ea7 100644 --- a/builtins.go +++ b/builtins.go @@ -20,6 +20,7 @@ import ( "reflect" "regexp" "strconv" + "strings" "unicode/utf8" ) @@ -287,3 +288,66 @@ func nonnil(v interface{}, param string) error { } return nil } + +// list validates that the given value exists in the list of values +func list(v interface{}, param string) error { + value := reflect.ValueOf(v) + if value.Kind() == reflect.Ptr { + if value.IsNil() { + return nil + } + value = value.Elem() + } + + // get array of possible values + l := len(param) + if l < 3 || param[0] != '[' || param[l-1] != ']' { + return ErrBadParameter + } + param = param[1 : l-1] + + possible := strings.Split(param, ",") + + switch value.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + for _, str := range possible { + i, err := strconv.ParseInt(str, 10, 64) + if err != nil { + return ErrBadParameter + } + if value.Int() == i { + return nil + } + } + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + for _, str := range possible { + i, err := strconv.ParseUint(str, 10, 64) + if err != nil { + return ErrBadParameter + } + if value.Uint() == i { + return nil + } + } + case reflect.Float32, reflect.Float64: + for _, str := range possible { + f, err := strconv.ParseFloat(str, 64) + if err != nil { + return ErrBadParameter + } + if value.Float() == f { + return nil + } + } + case reflect.String: + for _, str := range possible { + if value.String() == str { + return nil + } + } + default: + return ErrUnsupported + } + + return ErrInvalid +} diff --git a/validator.go b/validator.go index 4d610be..bc95d37 100644 --- a/validator.go +++ b/validator.go @@ -140,6 +140,7 @@ func NewValidator() *Validator { "max": max, "regexp": regex, "nonnil": nonnil, + "list": list, }, printJSON: false, }