New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closes #660 added excluded with and without #664
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -68,6 +68,10 @@ var ( | |
"required_with_all": requiredWithAll, | ||
"required_without": requiredWithout, | ||
"required_without_all": requiredWithoutAll, | ||
"excluded_with": excludedWith, | ||
"excluded_with_all": excludedWithAll, | ||
"excluded_without": excludedWithout, | ||
"excluded_without_all": excludedWithoutAll, | ||
"isdefault": isDefault, | ||
"len": hasLengthOf, | ||
"min": hasMinOf, | ||
|
@@ -1383,6 +1387,18 @@ func requireCheckFieldKind(fl FieldLevel, param string, defaultNotFoundValue boo | |
} | ||
} | ||
|
||
// ExcludedWith is the validation function | ||
// The field under validation must not be present or is empty if any of the other specified fields are present. | ||
func excludedWith(fl FieldLevel) bool { | ||
params := parseOneOfParam2(fl.Param()) | ||
for _, param := range params { | ||
if !requireCheckFieldKind(fl, param, true) { | ||
return !hasValue(fl) | ||
} | ||
} | ||
return true | ||
} | ||
|
||
// RequiredWith is the validation function | ||
// The field under validation must be present and not empty only if any of the other specified fields are present. | ||
func requiredWith(fl FieldLevel) bool { | ||
|
@@ -1395,6 +1411,18 @@ func requiredWith(fl FieldLevel) bool { | |
return true | ||
} | ||
|
||
// ExcludedWithAll is the validation function | ||
// The field under validation must not be present or is empty if all of the other specified fields are present. | ||
func excludedWithAll(fl FieldLevel) bool { | ||
params := parseOneOfParam2(fl.Param()) | ||
for _, param := range params { | ||
if requireCheckFieldKind(fl, param, true) { | ||
return true | ||
} | ||
} | ||
return !hasValue(fl) | ||
} | ||
|
||
// RequiredWithAll is the validation function | ||
// The field under validation must be present and not empty only if all of the other specified fields are present. | ||
func requiredWithAll(fl FieldLevel) bool { | ||
|
@@ -1407,6 +1435,15 @@ func requiredWithAll(fl FieldLevel) bool { | |
return hasValue(fl) | ||
} | ||
|
||
// ExcludedWithout is the validation function | ||
// The field under validation must not be present or is empty when any of the other specified fields are not present. | ||
func excludedWithout(fl FieldLevel) bool { | ||
if requireCheckFieldKind(fl, strings.TrimSpace(fl.Param()), true) { | ||
return !hasValue(fl) | ||
} | ||
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 { | ||
|
@@ -1416,6 +1453,18 @@ func requiredWithout(fl FieldLevel) bool { | |
return true | ||
} | ||
|
||
// RequiredWithoutAll is the validation function | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should be There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You could open a PR ;) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sure, I'll do it tomorrow :) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
// The field under validation must not be present or is empty when all of the other specified fields are not present. | ||
func excludedWithoutAll(fl FieldLevel) bool { | ||
params := parseOneOfParam2(fl.Param()) | ||
for _, param := range params { | ||
if !requireCheckFieldKind(fl, param, true) { | ||
return true | ||
} | ||
} | ||
return !hasValue(fl) | ||
} | ||
|
||
// RequiredWithoutAll is the validation function | ||
// The field under validation must be present and not empty only when all of the other specified fields are not present. | ||
func requiredWithoutAll(fl FieldLevel) bool { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm trying to use
excluded_with
and not getting the expected behaviour. I only passes the validation if I set all the fields with theexcluded_with
validation, which is kind of the opposite of what I expected. Example:If I set
AAA
, I getThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you have a play we could look at? Can you simplify it further (dive, omitempty) to expose the issue?
/cc @yaliv maybe you can spot the mistake?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, I'll try to confirm it and make sure I'm not messing up somewhere. I'll get back to you tomorrow!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
excluded_with
validator works fine with basic/primitive fields (string, int).I never set any validations for the sub-structs, because in my case I use
json.Unmarshal()
before validate.Using
json.Unmarshal()
will always populate the sub-structs even if they do not present in the source JSON bytes.This leads me to ask a fundamental question: "What is an empty struct value?"
nil
?struct{}
(with zero fields)?Unlike
map[string]interface{}
, which can hold "dynamic" fields, struct has a static set of fields.If I define a struct with some fields in it (e.g.
MyStruct
), and then I create a struct value from it with its default (e.g.var test MyStruct
), I still have access to those fields.@jfrancisco0 if the built-in validators do not fit with your case, you can try creating some struct-level validations (see example). Plus, using this technique can minimize overhead, because you can validate multiple fields at once.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@yaliv in this case the struct pointers are nil and hence definitely empty. The source code/docs confirm this. This is similar to a string that is treated as „not existing“ when it has the zero value.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can confirm though that a field of type
bool
does not fail the validation, giving some strength to the hypothesis of structs behaving differently.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@andig if I write just
var test *MyStruct
, thentest
would benil
, but if I writevar test MyStruct
, then&test
would not benil
.So struct pointers have possible
nil
value.Yes, I can see that fields with struct type and struct pointer type have a complete opposite behavior against primitive types.
Using the
excluded_with
validator on 2 fields, each mentioning each other:There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
so to summarise: there is an issue with struct pointers and excluded* validations. Sounds like it would be good to open a new issue with minimal example to reproduce. Might also be good to check required* behaviour for struct pointers too, as the pr code was a close copy.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@yaliv did you by chance open follow-up issue?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@andig sorry, I haven't done it yet.
I see this validator is quite complex, so I'm not sure if the problem is fixed it will not break other parts (e.g. the primitive types) or it will not cost performance.
But yes, it's still a good issue to be posted. Before it is fixed, maybe someone has a running workaround 😉