Add exists tag

exists tag used to ensure that a Pointer, Interface or
Invalid has a value, but won't interfere with any other validation.
pull/143/head
joeybloggs 9 years ago
parent c6b12744c3
commit 8eb07da269
  1. 8
      doc.go
  2. 32
      validator.go
  3. 31
      validator_test.go

@ -167,6 +167,14 @@ Here is a list of the current built in validators:
inside of you program you know the struct will be valid, but need to inside of you program you know the struct will be valid, but need to
verify it has been assigned. verify it has been assigned.
exists
Is a special tag without a validation function attached. It is used when a field
is a Pointer, Interface or Invalid and you wish to validate that it exists.
Example: want to ensure a bool exists if you define the bool as a pointer and
use exists it will ensure there is a value; couldn't use required as it would
fail when the bool was false. exists will fail is the value is a Pointer, Interface
or Invalid and is nil. (Usage: exists)
omitempty omitempty
Allows conditional validation, for example if a field is not set with Allows conditional validation, for example if a field is not set with
a value (Determined by the required validator) then other validation a value (Determined by the required validator) then other validation

@ -33,6 +33,7 @@ const (
mapErrMsg = "Field validation for \"%s\" failed on key \"%v\" with error(s): %s" mapErrMsg = "Field validation for \"%s\" failed on key \"%v\" with error(s): %s"
structErrMsg = "Struct:%s\n" structErrMsg = "Struct:%s\n"
diveTag = "dive" diveTag = "dive"
existsTag = "exists"
arrayIndexFieldName = "%s[%d]" arrayIndexFieldName = "%s[%d]"
mapIndexFieldName = "%s[%v]" mapIndexFieldName = "%s[%v]"
) )
@ -722,7 +723,22 @@ func (v *Validate) fieldWithNameAndValue(val interface{}, current interface{}, f
for _, val := range cTag.keyVals { for _, val := range cTag.keyVals {
// if (idxField.Kind() == reflect.Ptr || idxField.Kind() == reflect.Interface) && idxField.IsNil() {
// if val[0] == existsTag {
// if (cField.kind == reflect.Ptr || cField.kind == reflect.Interface) && valueField.IsNil() {
// fieldErr = &FieldError{
// Field: name,
// Tag: val[0],
// Value: f,
// Param: val[1],
// }
// err = errors.New(fieldErr.Tag)
// }
// } else {
fieldErr, err = v.fieldWithNameAndSingleTag(val, current, f, val[0], val[1], name) fieldErr, err = v.fieldWithNameAndSingleTag(val, current, f, val[0], val[1], name)
// }
if err == nil { if err == nil {
return nil return nil
@ -740,6 +756,18 @@ func (v *Validate) fieldWithNameAndValue(val interface{}, current interface{}, f
return fieldErr return fieldErr
} }
if cTag.keyVals[0][0] == existsTag {
if (cField.kind == reflect.Ptr || cField.kind == reflect.Interface) && valueField.IsNil() {
return &FieldError{
Field: name,
Tag: cTag.keyVals[0][0],
Value: f,
Param: cTag.keyVals[0][1],
}
}
continue
}
if fieldErr, err = v.fieldWithNameAndSingleTag(val, current, f, cTag.keyVals[0][0], cTag.keyVals[0][1], name); err != nil { if fieldErr, err = v.fieldWithNameAndSingleTag(val, current, f, cTag.keyVals[0][0], cTag.keyVals[0][1], name); err != nil {
fieldErr.Kind = cField.kind fieldErr.Kind = cField.kind
@ -981,6 +1009,10 @@ func (v *Validate) fieldWithNameAndSingleTag(val interface{}, current interface{
return nil, nil return nil, nil
} }
// if key == existsTag {
// continue
// }
valFunc, ok := v.validationFuncs[key] valFunc, ok := v.validationFuncs[key]
if !ok { if !ok {
panic(fmt.Sprintf("Undefined validation function on field %s", name)) panic(fmt.Sprintf("Undefined validation function on field %s", name))

@ -1,6 +1,7 @@
package validator package validator
import ( import (
"encoding/json"
"fmt" "fmt"
"path" "path"
"reflect" "reflect"
@ -231,6 +232,36 @@ func AssertMapFieldError(t *testing.T, s map[string]*FieldError, field string, e
EqualSkip(t, 2, val.Tag, expectedTag) EqualSkip(t, 2, val.Tag, expectedTag)
} }
func TestExistsValidation(t *testing.T) {
jsonText := "{ \"truthiness2\": true }"
type Thing struct {
Truthiness *bool `json:"truthiness" validate:"exists,required"`
}
var ting Thing
err := json.Unmarshal([]byte(jsonText), &ting)
Equal(t, err, nil)
NotEqual(t, ting, nil)
Equal(t, ting.Truthiness, nil)
errs := validate.Struct(ting)
NotEqual(t, errs, nil)
AssertFieldError(t, errs, "Truthiness", "exists")
jsonText = "{ \"truthiness\": true }"
err = json.Unmarshal([]byte(jsonText), &ting)
Equal(t, err, nil)
NotEqual(t, ting, nil)
Equal(t, ting.Truthiness, true)
errs = validate.Struct(ting)
Equal(t, errs, nil)
}
func TestSliceMapArrayChanFuncPtrInterfaceRequiredValidation(t *testing.T) { func TestSliceMapArrayChanFuncPtrInterfaceRequiredValidation(t *testing.T) {
var m map[string]string var m map[string]string

Loading…
Cancel
Save