example
field A is required
field B is required if field A equal "ABC"
please help
package main
import (
"fmt"
"reflect"
"strconv"
"strings"
"gopkg.in/go-playground/validator.v9"
)
func main() {
validate := validator.New()
// register custom validation: rfe(Required if Field is Equal to some value).
validate.RegisterValidation(`rfe`, func(fl validator.FieldLevel) bool {
param := strings.Split(fl.Param(), `:`)
paramField := param[0]
paramValue := param[1]
if paramField == `` {
return true
}
// param field reflect.Value.
var paramFieldValue reflect.Value
if fl.Parent().Kind() == reflect.Ptr {
paramFieldValue = fl.Parent().Elem().FieldByName(paramField)
} else {
paramFieldValue = fl.Parent().FieldByName(paramField)
}
if isEq(paramFieldValue, paramValue) == false {
return true
}
return hasValue(fl)
})
// usage demo.
type Foo struct {
A int `validate:"required"`
B int `validate:"rfe=A:1"`
}
foo := Foo{
A: 1,
B: 0,
}
err := validate.Struct(&foo)
if err != nil {
fmt.Println(err)
} else {
fmt.Println(`pass validation`)
}
}
// The following functions are copied from validator.v9 lib.
func hasValue(fl validator.FieldLevel) bool {
return requireCheckFieldKind(fl, "")
}
func requireCheckFieldKind(fl validator.FieldLevel, param string) bool {
field := fl.Field()
if len(param) > 0 {
if fl.Parent().Kind() == reflect.Ptr {
field = fl.Parent().Elem().FieldByName(param)
} else {
field = fl.Parent().FieldByName(param)
}
}
switch field.Kind() {
case reflect.Slice, reflect.Map, reflect.Ptr, reflect.Interface, reflect.Chan, reflect.Func:
return !field.IsNil()
default:
_, _, nullable := fl.ExtractType(field)
if nullable && field.Interface() != nil {
return true
}
return field.IsValid() && field.Interface() != reflect.Zero(field.Type()).Interface()
}
}
func isEq(field reflect.Value, value string) bool {
switch field.Kind() {
case reflect.String:
return field.String() == value
case reflect.Slice, reflect.Map, reflect.Array:
p := asInt(value)
return int64(field.Len()) == p
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
p := asInt(value)
return field.Int() == p
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
p := asUint(value)
return field.Uint() == p
case reflect.Float32, reflect.Float64:
p := asFloat(value)
return field.Float() == p
}
panic(fmt.Sprintf("Bad field type %T", field.Interface()))
}
func asInt(param string) int64 {
i, err := strconv.ParseInt(param, 0, 64)
panicIf(err)
return i
}
func asUint(param string) uint64 {
i, err := strconv.ParseUint(param, 0, 64)
panicIf(err)
return i
}
func asFloat(param string) float64 {
i, err := strconv.ParseFloat(param, 64)
panicIf(err)
return i
}
func panicIf(err error) {
if err != nil {
panic(err.Error())
}
}
Thank you very much
Can anyone do this in validator v10, it seems some of the struct definitions and functions have been changed.
Most helpful comment