Skip to content

Commit 627fcfa

Browse files
Dean KarnDean Karn
authored andcommitted
Merge pull request #143 from joeybloggs/v5-development
Add exists tag
2 parents c6b1274 + 8eb07da commit 627fcfa

File tree

3 files changed

+71
-0
lines changed

3 files changed

+71
-0
lines changed

doc.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,14 @@ Here is a list of the current built in validators:
167167
inside of you program you know the struct will be valid, but need to
168168
verify it has been assigned.
169169
170+
exists
171+
Is a special tag without a validation function attached. It is used when a field
172+
is a Pointer, Interface or Invalid and you wish to validate that it exists.
173+
Example: want to ensure a bool exists if you define the bool as a pointer and
174+
use exists it will ensure there is a value; couldn't use required as it would
175+
fail when the bool was false. exists will fail is the value is a Pointer, Interface
176+
or Invalid and is nil. (Usage: exists)
177+
170178
omitempty
171179
Allows conditional validation, for example if a field is not set with
172180
a value (Determined by the required validator) then other validation

validator.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ const (
3333
mapErrMsg = "Field validation for \"%s\" failed on key \"%v\" with error(s): %s"
3434
structErrMsg = "Struct:%s\n"
3535
diveTag = "dive"
36+
existsTag = "exists"
3637
arrayIndexFieldName = "%s[%d]"
3738
mapIndexFieldName = "%s[%v]"
3839
)
@@ -722,7 +723,22 @@ func (v *Validate) fieldWithNameAndValue(val interface{}, current interface{}, f
722723

723724
for _, val := range cTag.keyVals {
724725

726+
// if (idxField.Kind() == reflect.Ptr || idxField.Kind() == reflect.Interface) && idxField.IsNil() {
727+
// if val[0] == existsTag {
728+
// if (cField.kind == reflect.Ptr || cField.kind == reflect.Interface) && valueField.IsNil() {
729+
// fieldErr = &FieldError{
730+
// Field: name,
731+
// Tag: val[0],
732+
// Value: f,
733+
// Param: val[1],
734+
// }
735+
// err = errors.New(fieldErr.Tag)
736+
// }
737+
738+
// } else {
739+
725740
fieldErr, err = v.fieldWithNameAndSingleTag(val, current, f, val[0], val[1], name)
741+
// }
726742

727743
if err == nil {
728744
return nil
@@ -740,6 +756,18 @@ func (v *Validate) fieldWithNameAndValue(val interface{}, current interface{}, f
740756
return fieldErr
741757
}
742758

759+
if cTag.keyVals[0][0] == existsTag {
760+
if (cField.kind == reflect.Ptr || cField.kind == reflect.Interface) && valueField.IsNil() {
761+
return &FieldError{
762+
Field: name,
763+
Tag: cTag.keyVals[0][0],
764+
Value: f,
765+
Param: cTag.keyVals[0][1],
766+
}
767+
}
768+
continue
769+
}
770+
743771
if fieldErr, err = v.fieldWithNameAndSingleTag(val, current, f, cTag.keyVals[0][0], cTag.keyVals[0][1], name); err != nil {
744772

745773
fieldErr.Kind = cField.kind
@@ -981,6 +1009,10 @@ func (v *Validate) fieldWithNameAndSingleTag(val interface{}, current interface{
9811009
return nil, nil
9821010
}
9831011

1012+
// if key == existsTag {
1013+
// continue
1014+
// }
1015+
9841016
valFunc, ok := v.validationFuncs[key]
9851017
if !ok {
9861018
panic(fmt.Sprintf("Undefined validation function on field %s", name))

validator_test.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package validator
22

33
import (
4+
"encoding/json"
45
"fmt"
56
"path"
67
"reflect"
@@ -231,6 +232,36 @@ func AssertMapFieldError(t *testing.T, s map[string]*FieldError, field string, e
231232
EqualSkip(t, 2, val.Tag, expectedTag)
232233
}
233234

235+
func TestExistsValidation(t *testing.T) {
236+
237+
jsonText := "{ \"truthiness2\": true }"
238+
239+
type Thing struct {
240+
Truthiness *bool `json:"truthiness" validate:"exists,required"`
241+
}
242+
243+
var ting Thing
244+
245+
err := json.Unmarshal([]byte(jsonText), &ting)
246+
Equal(t, err, nil)
247+
NotEqual(t, ting, nil)
248+
Equal(t, ting.Truthiness, nil)
249+
250+
errs := validate.Struct(ting)
251+
NotEqual(t, errs, nil)
252+
AssertFieldError(t, errs, "Truthiness", "exists")
253+
254+
jsonText = "{ \"truthiness\": true }"
255+
256+
err = json.Unmarshal([]byte(jsonText), &ting)
257+
Equal(t, err, nil)
258+
NotEqual(t, ting, nil)
259+
Equal(t, ting.Truthiness, true)
260+
261+
errs = validate.Struct(ting)
262+
Equal(t, errs, nil)
263+
}
264+
234265
func TestSliceMapArrayChanFuncPtrInterfaceRequiredValidation(t *testing.T) {
235266

236267
var m map[string]string

0 commit comments

Comments
 (0)