Skip to content

Commit 7e97fcf

Browse files
joeybloggsjoeybloggs
authored andcommitted
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.
1 parent 442b210 commit 7e97fcf

File tree

3 files changed

+44
-0
lines changed

3 files changed

+44
-0
lines changed

doc.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,14 @@ Here is a list of the current built in validators:
102102
you know the struct will be valid, but need to verify it has been assigned.
103103
NOTE: only "required" and "omitempty" can be used on a struct itself.
104104
105+
exists
106+
Is a special tag without a validation function attached. It is used when a field
107+
is a Pointer, Interface or Invalid and you wish to validate that it exists.
108+
Example: want to ensure a bool exists if you define the bool as a pointer and
109+
use exists it will ensure there is a value; couldn't use required as it would
110+
fail when the bool was false. exists will fail is the value is a Pointer, Interface
111+
or Invalid and is nil. (Usage: exists)
112+
105113
omitempty
106114
Allows conditional validation, for example if a field is not set with
107115
a value (Determined by the "required" validator) then other validation

validator.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ const (
2929
omitempty = "omitempty"
3030
skipValidationTag = "-"
3131
diveTag = "dive"
32+
existsTag = "exists"
3233
fieldErrMsg = "Key: \"%s\" Error:Field validation for \"%s\" failed on the \"%s\" tag"
3334
arrayIndexFieldName = "%s[%d]"
3435
mapIndexFieldName = "%s[%v]"
@@ -418,6 +419,10 @@ func (v *Validate) traverseField(topStruct reflect.Value, currentStruct reflect.
418419

419420
for _, cTag := range tags {
420421

422+
if cTag.tagVals[0][0] == existsTag {
423+
continue
424+
}
425+
421426
if cTag.tagVals[0][0] == diveTag {
422427
dive = true
423428
diveSubTag = strings.TrimLeft(strings.SplitN(tag, diveTag, 2)[1], ",")

validator_test.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package validator
33
import (
44
"database/sql"
55
"database/sql/driver"
6+
"encoding/json"
67
"errors"
78
"fmt"
89
"reflect"
@@ -191,6 +192,36 @@ func ValidateValuerType(field reflect.Value) interface{} {
191192
return nil
192193
}
193194

195+
func TestExistsValidation(t *testing.T) {
196+
197+
jsonText := "{ \"truthiness2\": true }"
198+
199+
type Thing struct {
200+
Truthiness *bool `json:"truthiness" validate:"exists,required"`
201+
}
202+
203+
var ting Thing
204+
205+
err := json.Unmarshal([]byte(jsonText), &ting)
206+
Equal(t, err, nil)
207+
NotEqual(t, ting, nil)
208+
Equal(t, ting.Truthiness, nil)
209+
210+
errs := validate.Struct(ting)
211+
NotEqual(t, errs, nil)
212+
AssertError(t, errs, "Thing.Truthiness", "Truthiness", "exists")
213+
214+
jsonText = "{ \"truthiness\": true }"
215+
216+
err = json.Unmarshal([]byte(jsonText), &ting)
217+
Equal(t, err, nil)
218+
NotEqual(t, ting, nil)
219+
Equal(t, ting.Truthiness, true)
220+
221+
errs = validate.Struct(ting)
222+
Equal(t, errs, nil)
223+
}
224+
194225
func TestSQLValue2Validation(t *testing.T) {
195226

196227
config := Config{

0 commit comments

Comments
 (0)