mirror of
https://github.com/Fishwaldo/validator.git
synced 2025-07-08 14:10:18 +00:00
add required_without_all validator
This commit is contained in:
parent
03bfd38cc1
commit
3ec10f9949
2 changed files with 163 additions and 102 deletions
246
baked_in.go
246
baked_in.go
|
@ -62,108 +62,109 @@ var (
|
||||||
// you can add, remove or even replace items to suite your needs,
|
// you can add, remove or even replace items to suite your needs,
|
||||||
// or even disregard and use your own map if so desired.
|
// or even disregard and use your own map if so desired.
|
||||||
bakedInValidators = map[string]Func{
|
bakedInValidators = map[string]Func{
|
||||||
"required": hasValue,
|
"required": hasValue,
|
||||||
"required_with": requiredWith,
|
"required_with": requiredWith,
|
||||||
"required_with_all": requiredWithAll,
|
"required_with_all": requiredWithAll,
|
||||||
"required_without": requiredWithout,
|
"required_without": requiredWithout,
|
||||||
"isdefault": isDefault,
|
"required_without_all": requiredWithoutAll,
|
||||||
"len": hasLengthOf,
|
"isdefault": isDefault,
|
||||||
"min": hasMinOf,
|
"len": hasLengthOf,
|
||||||
"max": hasMaxOf,
|
"min": hasMinOf,
|
||||||
"eq": isEq,
|
"max": hasMaxOf,
|
||||||
"ne": isNe,
|
"eq": isEq,
|
||||||
"lt": isLt,
|
"ne": isNe,
|
||||||
"lte": isLte,
|
"lt": isLt,
|
||||||
"gt": isGt,
|
"lte": isLte,
|
||||||
"gte": isGte,
|
"gt": isGt,
|
||||||
"eqfield": isEqField,
|
"gte": isGte,
|
||||||
"eqcsfield": isEqCrossStructField,
|
"eqfield": isEqField,
|
||||||
"necsfield": isNeCrossStructField,
|
"eqcsfield": isEqCrossStructField,
|
||||||
"gtcsfield": isGtCrossStructField,
|
"necsfield": isNeCrossStructField,
|
||||||
"gtecsfield": isGteCrossStructField,
|
"gtcsfield": isGtCrossStructField,
|
||||||
"ltcsfield": isLtCrossStructField,
|
"gtecsfield": isGteCrossStructField,
|
||||||
"ltecsfield": isLteCrossStructField,
|
"ltcsfield": isLtCrossStructField,
|
||||||
"nefield": isNeField,
|
"ltecsfield": isLteCrossStructField,
|
||||||
"gtefield": isGteField,
|
"nefield": isNeField,
|
||||||
"gtfield": isGtField,
|
"gtefield": isGteField,
|
||||||
"ltefield": isLteField,
|
"gtfield": isGtField,
|
||||||
"ltfield": isLtField,
|
"ltefield": isLteField,
|
||||||
"fieldcontains": fieldContains,
|
"ltfield": isLtField,
|
||||||
"fieldexcludes": fieldExcludes,
|
"fieldcontains": fieldContains,
|
||||||
"alpha": isAlpha,
|
"fieldexcludes": fieldExcludes,
|
||||||
"alphanum": isAlphanum,
|
"alpha": isAlpha,
|
||||||
"alphaunicode": isAlphaUnicode,
|
"alphanum": isAlphanum,
|
||||||
"alphanumunicode": isAlphanumUnicode,
|
"alphaunicode": isAlphaUnicode,
|
||||||
"numeric": isNumeric,
|
"alphanumunicode": isAlphanumUnicode,
|
||||||
"number": isNumber,
|
"numeric": isNumeric,
|
||||||
"hexadecimal": isHexadecimal,
|
"number": isNumber,
|
||||||
"hexcolor": isHEXColor,
|
"hexadecimal": isHexadecimal,
|
||||||
"rgb": isRGB,
|
"hexcolor": isHEXColor,
|
||||||
"rgba": isRGBA,
|
"rgb": isRGB,
|
||||||
"hsl": isHSL,
|
"rgba": isRGBA,
|
||||||
"hsla": isHSLA,
|
"hsl": isHSL,
|
||||||
"email": isEmail,
|
"hsla": isHSLA,
|
||||||
"url": isURL,
|
"email": isEmail,
|
||||||
"uri": isURI,
|
"url": isURL,
|
||||||
"urn_rfc2141": isUrnRFC2141, // RFC 2141
|
"uri": isURI,
|
||||||
"file": isFile,
|
"urn_rfc2141": isUrnRFC2141, // RFC 2141
|
||||||
"base64": isBase64,
|
"file": isFile,
|
||||||
"base64url": isBase64URL,
|
"base64": isBase64,
|
||||||
"contains": contains,
|
"base64url": isBase64URL,
|
||||||
"containsany": containsAny,
|
"contains": contains,
|
||||||
"containsrune": containsRune,
|
"containsany": containsAny,
|
||||||
"excludes": excludes,
|
"containsrune": containsRune,
|
||||||
"excludesall": excludesAll,
|
"excludes": excludes,
|
||||||
"excludesrune": excludesRune,
|
"excludesall": excludesAll,
|
||||||
"startswith": startsWith,
|
"excludesrune": excludesRune,
|
||||||
"endswith": endsWith,
|
"startswith": startsWith,
|
||||||
"isbn": isISBN,
|
"endswith": endsWith,
|
||||||
"isbn10": isISBN10,
|
"isbn": isISBN,
|
||||||
"isbn13": isISBN13,
|
"isbn10": isISBN10,
|
||||||
"eth_addr": isEthereumAddress,
|
"isbn13": isISBN13,
|
||||||
"btc_addr": isBitcoinAddress,
|
"eth_addr": isEthereumAddress,
|
||||||
"btc_addr_bech32": isBitcoinBech32Address,
|
"btc_addr": isBitcoinAddress,
|
||||||
"uuid": isUUID,
|
"btc_addr_bech32": isBitcoinBech32Address,
|
||||||
"uuid3": isUUID3,
|
"uuid": isUUID,
|
||||||
"uuid4": isUUID4,
|
"uuid3": isUUID3,
|
||||||
"uuid5": isUUID5,
|
"uuid4": isUUID4,
|
||||||
"uuid_rfc4122": isUUIDRFC4122,
|
"uuid5": isUUID5,
|
||||||
"uuid3_rfc4122": isUUID3RFC4122,
|
"uuid_rfc4122": isUUIDRFC4122,
|
||||||
"uuid4_rfc4122": isUUID4RFC4122,
|
"uuid3_rfc4122": isUUID3RFC4122,
|
||||||
"uuid5_rfc4122": isUUID5RFC4122,
|
"uuid4_rfc4122": isUUID4RFC4122,
|
||||||
"ascii": isASCII,
|
"uuid5_rfc4122": isUUID5RFC4122,
|
||||||
"printascii": isPrintableASCII,
|
"ascii": isASCII,
|
||||||
"multibyte": hasMultiByteCharacter,
|
"printascii": isPrintableASCII,
|
||||||
"datauri": isDataURI,
|
"multibyte": hasMultiByteCharacter,
|
||||||
"latitude": isLatitude,
|
"datauri": isDataURI,
|
||||||
"longitude": isLongitude,
|
"latitude": isLatitude,
|
||||||
"ssn": isSSN,
|
"longitude": isLongitude,
|
||||||
"ipv4": isIPv4,
|
"ssn": isSSN,
|
||||||
"ipv6": isIPv6,
|
"ipv4": isIPv4,
|
||||||
"ip": isIP,
|
"ipv6": isIPv6,
|
||||||
"cidrv4": isCIDRv4,
|
"ip": isIP,
|
||||||
"cidrv6": isCIDRv6,
|
"cidrv4": isCIDRv4,
|
||||||
"cidr": isCIDR,
|
"cidrv6": isCIDRv6,
|
||||||
"tcp4_addr": isTCP4AddrResolvable,
|
"cidr": isCIDR,
|
||||||
"tcp6_addr": isTCP6AddrResolvable,
|
"tcp4_addr": isTCP4AddrResolvable,
|
||||||
"tcp_addr": isTCPAddrResolvable,
|
"tcp6_addr": isTCP6AddrResolvable,
|
||||||
"udp4_addr": isUDP4AddrResolvable,
|
"tcp_addr": isTCPAddrResolvable,
|
||||||
"udp6_addr": isUDP6AddrResolvable,
|
"udp4_addr": isUDP4AddrResolvable,
|
||||||
"udp_addr": isUDPAddrResolvable,
|
"udp6_addr": isUDP6AddrResolvable,
|
||||||
"ip4_addr": isIP4AddrResolvable,
|
"udp_addr": isUDPAddrResolvable,
|
||||||
"ip6_addr": isIP6AddrResolvable,
|
"ip4_addr": isIP4AddrResolvable,
|
||||||
"ip_addr": isIPAddrResolvable,
|
"ip6_addr": isIP6AddrResolvable,
|
||||||
"unix_addr": isUnixAddrResolvable,
|
"ip_addr": isIPAddrResolvable,
|
||||||
"mac": isMAC,
|
"unix_addr": isUnixAddrResolvable,
|
||||||
"hostname": isHostnameRFC952, // RFC 952
|
"mac": isMAC,
|
||||||
"hostname_rfc1123": isHostnameRFC1123, // RFC 1123
|
"hostname": isHostnameRFC952, // RFC 952
|
||||||
"fqdn": isFQDN,
|
"hostname_rfc1123": isHostnameRFC1123, // RFC 1123
|
||||||
"unique": isUnique,
|
"fqdn": isFQDN,
|
||||||
"oneof": isOneOf,
|
"unique": isUnique,
|
||||||
"html": isHTML,
|
"oneof": isOneOf,
|
||||||
"html_encoded": isHTMLEncoded,
|
"html": isHTML,
|
||||||
"url_encoded": isURLEncoded,
|
"html_encoded": isHTMLEncoded,
|
||||||
"dir": isDir,
|
"url_encoded": isURLEncoded,
|
||||||
|
"dir": isDir,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -1435,6 +1436,47 @@ func requiredWithout(fl FieldLevel) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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 {
|
||||||
|
|
||||||
|
field := fl.Field()
|
||||||
|
isValidateCurrentField := true
|
||||||
|
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.
|
// 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 {
|
func isGteField(fl FieldLevel) bool {
|
||||||
|
|
||||||
|
|
|
@ -8678,3 +8678,22 @@ func TestRequiredWithout(t *testing.T) {
|
||||||
t.Fatalf("failed Error: %s", errs)
|
t.Fatalf("failed Error: %s", errs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestRequiredWithoutAll(t *testing.T) {
|
||||||
|
|
||||||
|
test := struct {
|
||||||
|
Field1 string `validate:"omitempty" json:"field_1"`
|
||||||
|
Field2 string `validate:"omitempty" json:"field_2"`
|
||||||
|
Field3 string `validate:"required_without_all=Field1 Field2" json:"field_3"`
|
||||||
|
}{
|
||||||
|
Field3: "test_field3",
|
||||||
|
}
|
||||||
|
|
||||||
|
validate := New()
|
||||||
|
|
||||||
|
errs := validate.Struct(test)
|
||||||
|
|
||||||
|
if errs != nil {
|
||||||
|
t.Fatalf("failed Error: %s", errs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue