From a80f7c5767bcef5f2c3d5bb59f12ec7357b4983d Mon Sep 17 00:00:00 2001 From: Samuel Berthe Date: Mon, 27 Apr 2020 00:29:20 +0200 Subject: [PATCH] feat(conditional): adding rules for "else" case (#107) --- README.md | 11 ++++++----- when.go | 10 +++++++++- when_test.go | 39 +++++++++++++++++++++------------------ 3 files changed, 36 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index 692050c..307b46e 100644 --- a/README.md +++ b/README.md @@ -416,23 +416,23 @@ fmt.Println(err) Sometimes, we may want to validate a value only when certain condition is met. For example, we want to ensure the `unit` struct field is not empty only when the `quantity` field is not empty; or we may want to ensure either `email` or `phone` is provided. The so-called conditional validation can be achieved with the help of `validation.When`. -The following code implements the aforementioned two examples: +The following code implements the aforementioned examples: ```go result := validation.ValidateStruct(&a, - validation.Field(&a.Unit, validation.When(a.Quantity != "", validation.Required)), + validation.Field(&a.Unit, validation.When(a.Quantity != "", validation.Required).Else(validation.Nil)), validation.Field(&a.Phone, validation.When(a.Email == "", validation.Required.Error('Either phone or Email is required.')), - validation.Field(&a.Email, validation.When(a.Phone == "", validation.Required.Error('Either phone or Email is required.')), + validation.Field(&a.Email, validation.When(a.Phone == "", validation.Required.Error('Either phone or Email is required.')), ) ``` -Note that `validation.When` can take a list of validation rules. These rules will be executed only when the condition is true. +Note that `validation.When` and `validation.When.Else` can take a list of validation rules. These rules will be executed only when the condition is true (When) or false (Else). The above code can also be simplified using the shortcut `validation.Required.When`: ```go result := validation.ValidateStruct(&a, - validation.Field(&a.Unit, validation.Required.When(a.Quantity != "")), + validation.Field(&a.Unit, validation.Required.When(a.Quantity != ""), validation.Nil.When(a.Quantity == "")), validation.Field(&a.Phone, validation.Required.When(a.Email == "").Error('Either phone or Email is required.')), validation.Field(&a.Email, validation.Required.When(a.Phone == "").Error('Either phone or Email is required.')), ) @@ -463,6 +463,7 @@ The following rules are provided in the `validation` package: * `MultipleOf`: checks if the value is a multiple of the specified range. * `Each(rules ...Rule)`: checks the elements within an iterable (map/slice/array) with other rules. * `When(condition, rules ...Rule)`: validates with the specified rules only when the condition is true. +* `Else(rules ...Rule)`: must be used with `When(condition, rules ...Rule)`, validates with the specified rules only when the condition is false. The `is` sub-package provides a list of commonly used string validation rules that can be used to check if the format of a value satisfies certain requirements. Note that these rules only handle strings and byte slices and if a string diff --git a/when.go b/when.go index 06fab3b..bc24a4f 100644 --- a/when.go +++ b/when.go @@ -5,6 +5,7 @@ func When(condition bool, rules ...Rule) WhenRule { return WhenRule{ condition: condition, rules: rules, + elseRules: []Rule{}, } } @@ -12,6 +13,7 @@ func When(condition bool, rules ...Rule) WhenRule { type WhenRule struct { condition bool rules []Rule + elseRules []Rule } // Validate checks if the condition is true and if so, it validates the value using the specified rules. @@ -20,5 +22,11 @@ func (r WhenRule) Validate(value interface{}) error { return Validate(value, r.rules...) } - return nil + return Validate(value, r.elseRules...) +} + +// When returns a validation rule that executes the given list of rules when the condition is false. +func (r WhenRule) Else(rules ...Rule) WhenRule { + r.elseRules = rules + return r } diff --git a/when_test.go b/when_test.go index a952cd7..e55c73e 100644 --- a/when_test.go +++ b/when_test.go @@ -21,32 +21,35 @@ func TestWhen(t *testing.T) { condition bool value interface{} rules []Rule + elseRules []Rule err string }{ // True condition - {"t1.1", true, nil, []Rule{}, ""}, - {"t1.2", true, "", []Rule{}, ""}, - {"t1.3", true, "", []Rule{abcRule}, ""}, - {"t1.4", true, 12, []Rule{Required}, ""}, - {"t1.5", true, nil, []Rule{Required}, "cannot be blank"}, - {"t1.6", true, "123", []Rule{abcRule}, "wrong_abc"}, - {"t1.7", true, "abc", []Rule{abcRule}, ""}, - {"t1.8", true, "abc", []Rule{abcRule, abcRule}, ""}, - {"t1.9", true, "abc", []Rule{abcRule, validateMeRule}, "wrong_me"}, - {"t1.10", true, "me", []Rule{abcRule, validateMeRule}, "wrong_abc"}, + {"t1.1", true, nil, []Rule{}, []Rule{}, ""}, + {"t1.2", true, "", []Rule{}, []Rule{}, ""}, + {"t1.3", true, "", []Rule{abcRule}, []Rule{}, ""}, + {"t1.4", true, 12, []Rule{Required}, []Rule{}, ""}, + {"t1.5", true, nil, []Rule{Required}, []Rule{}, "cannot be blank"}, + {"t1.6", true, "123", []Rule{abcRule}, []Rule{}, "wrong_abc"}, + {"t1.7", true, "abc", []Rule{abcRule}, []Rule{}, ""}, + {"t1.8", true, "abc", []Rule{abcRule, abcRule}, []Rule{}, ""}, + {"t1.9", true, "abc", []Rule{abcRule, validateMeRule}, []Rule{}, "wrong_me"}, + {"t1.10", true, "me", []Rule{abcRule, validateMeRule}, []Rule{}, "wrong_abc"}, + {"t1.11", true, "me", []Rule{}, []Rule{abcRule}, ""}, // False condition - {"t2.1", false, "", []Rule{}, ""}, - {"t2.2", false, "", []Rule{abcRule}, ""}, - {"t2.3", false, "abc", []Rule{abcRule}, ""}, - {"t2.4", false, "abc", []Rule{abcRule, abcRule}, ""}, - {"t2.5", false, "abc", []Rule{abcRule, validateMeRule}, ""}, - {"t2.6", false, "me", []Rule{abcRule, validateMeRule}, ""}, - {"t2.7", false, "", []Rule{abcRule, validateMeRule}, ""}, + {"t2.1", false, "", []Rule{}, []Rule{}, ""}, + {"t2.2", false, "", []Rule{abcRule}, []Rule{}, ""}, + {"t2.3", false, "abc", []Rule{abcRule}, []Rule{}, ""}, + {"t2.4", false, "abc", []Rule{abcRule, abcRule}, []Rule{}, ""}, + {"t2.5", false, "abc", []Rule{abcRule, validateMeRule}, []Rule{}, ""}, + {"t2.6", false, "me", []Rule{abcRule, validateMeRule}, []Rule{}, ""}, + {"t2.7", false, "", []Rule{abcRule, validateMeRule}, []Rule{}, ""}, + {"t2.8", false, "me", []Rule{}, []Rule{abcRule, validateMeRule}, "wrong_abc"}, } for _, test := range tests { - err := Validate(test.value, When(test.condition, test.rules...)) + err := Validate(test.value, When(test.condition, test.rules...).Else(test.elseRules...)) assertError(t, test.err, err, test.tag) } }