diff --git a/doc.go b/doc.go index ba60177..db05710 100644 --- a/doc.go +++ b/doc.go @@ -102,6 +102,14 @@ Here is a list of the current built in validators: you know the struct will be valid, but need to verify it has been assigned. NOTE: only "required" and "omitempty" can be used on a struct itself. + 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 Allows conditional validation, for example if a field is not set with a value (Determined by the "required" validator) then other validation diff --git a/validator.go b/validator.go index d8f35b6..d02ad10 100644 --- a/validator.go +++ b/validator.go @@ -29,6 +29,7 @@ const ( omitempty = "omitempty" skipValidationTag = "-" diveTag = "dive" + existsTag = "exists" fieldErrMsg = "Key: \"%s\" Error:Field validation for \"%s\" failed on the \"%s\" tag" arrayIndexFieldName = "%s[%d]" mapIndexFieldName = "%s[%v]" @@ -418,6 +419,10 @@ func (v *Validate) traverseField(topStruct reflect.Value, currentStruct reflect. for _, cTag := range tags { + if cTag.tagVals[0][0] == existsTag { + continue + } + if cTag.tagVals[0][0] == diveTag { dive = true diveSubTag = strings.TrimLeft(strings.SplitN(tag, diveTag, 2)[1], ",") diff --git a/validator_test.go b/validator_test.go index 4b93f92..9bcd09e 100644 --- a/validator_test.go +++ b/validator_test.go @@ -3,6 +3,7 @@ package validator import ( "database/sql" "database/sql/driver" + "encoding/json" "errors" "fmt" "reflect" @@ -191,6 +192,36 @@ func ValidateValuerType(field reflect.Value) interface{} { return nil } +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) + AssertError(t, errs, "Thing.Truthiness", "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 TestSQLValue2Validation(t *testing.T) { config := Config{