From 03bfd38cc15ce2c8d64ef2d25ea15214000e9e01 Mon Sep 17 00:00:00 2001 From: A Mashmooli Date: Mon, 29 Apr 2019 16:01:11 +0430 Subject: [PATCH] add required_without validator --- baked_in.go | 42 ++++++++++++++++++++++++++++++++++++++++++ validator_test.go | 20 +++++++++++++++++++- 2 files changed, 61 insertions(+), 1 deletion(-) diff --git a/baked_in.go b/baked_in.go index 8ad8773..6a3aca9 100644 --- a/baked_in.go +++ b/baked_in.go @@ -65,6 +65,7 @@ var ( "required": hasValue, "required_with": requiredWith, "required_with_all": requiredWithAll, + "required_without": requiredWithout, "isdefault": isDefault, "len": hasLengthOf, "min": hasMinOf, @@ -1393,6 +1394,47 @@ func requiredWithAll(fl FieldLevel) bool { return true } +// RequiredWithout is the validation function +// The field under validation must be present and not empty only when any of the other specified fields are not present. +func requiredWithout(fl FieldLevel) bool { + + field := fl.Field() + isValidateCurrentField := false + params := parseOneOfParam2(fl.Param()) + for _, param := range params { + isParamFieldPresent := false + + paramField := fl.Parent().FieldByName(param) + + switch paramField.Kind() { + case reflect.Slice, reflect.Map, reflect.Ptr, reflect.Interface, reflect.Chan, reflect.Func: + isParamFieldPresent = !paramField.IsNil() + default: + if fl.(*validate).fldIsPointer && paramField.Interface() != nil { + isParamFieldPresent = true + } + isParamFieldPresent = paramField.IsValid() && paramField.Interface() != reflect.Zero(field.Type()).Interface() + } + if isParamFieldPresent { + isValidateCurrentField = isParamFieldPresent + } + } + + if !isValidateCurrentField { + switch field.Kind() { + case reflect.Slice, reflect.Map, reflect.Ptr, reflect.Interface, reflect.Chan, reflect.Func: + return !field.IsNil() + default: + if fl.(*validate).fldIsPointer && field.Interface() != nil { + return true + } + return field.IsValid() && field.Interface() != reflect.Zero(field.Type()).Interface() + } + } + + return true +} + // IsGteField is the validation function for validating if the current field's value is greater than or equal to the field specified by the param's value. func isGteField(fl FieldLevel) bool { diff --git a/validator_test.go b/validator_test.go index 244d0c9..52b8331 100644 --- a/validator_test.go +++ b/validator_test.go @@ -8627,7 +8627,6 @@ func TestRequiredWith(t *testing.T) { Field3 string `validate:"required_with=Field1 Field2" json:"field_3"` }{ Field1: "test_field1", - Field2: "test_field2", Field3: "test_field3", } @@ -8660,3 +8659,22 @@ func TestRequiredWithAll(t *testing.T) { t.Fatalf("failed Error: %s", errs) } } + +func TestRequiredWithout(t *testing.T) { + + test := struct { + Field1 string `validate:"omitempty" json:"field_1"` + Field2 string `validate:"omitempty" json:"field_2"` + Field3 string `validate:"required_without=Field1 Field2" json:"field_3"` + }{ + Field3: "test_field3", + } + + validate := New() + + errs := validate.Struct(test) + + if errs != nil { + t.Fatalf("failed Error: %s", errs) + } +}