Add isdefault validation

pull/307/head
Dean Karn 7 years ago
parent 65480b6f6c
commit 0b5dc7605b
  1. 2
      README.md
  2. 7
      baked_in.go
  3. 5
      cache.go
  4. 7
      doc.go
  5. 39
      validator.go
  6. 1
      validator_instance.go
  7. 40
      validator_test.go

@ -1,7 +1,7 @@
Package validator
================
<img align="right" src="https://raw.githubusercontent.com/go-playground/validator/v9/logo.png">[![Join the chat at https://gitter.im/go-playground/validator](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/go-playground/validator?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
![Project status](https://img.shields.io/badge/version-9.6.0-green.svg)
![Project status](https://img.shields.io/badge/version-9.7.0-green.svg)
[![Build Status](https://semaphoreci.com/api/v1/joeybloggs/validator/branches/v9/badge.svg)](https://semaphoreci.com/joeybloggs/validator)
[![Coverage Status](https://coveralls.io/repos/go-playground/validator/badge.svg?branch=v9&service=github)](https://coveralls.io/github/go-playground/validator?branch=v9)
[![Go Report Card](https://goreportcard.com/badge/github.com/go-playground/validator)](https://goreportcard.com/report/github.com/go-playground/validator)

@ -37,6 +37,7 @@ var (
utf8Pipe: {},
noStructLevelTag: {},
requiredTag: {},
isdefault: {},
}
// BakedInAliasValidators is a default mapping of a single validation tag that
@ -51,6 +52,7 @@ var (
// or even disregard and use your own map if so desired.
bakedInValidators = map[string]Func{
"required": hasValue,
"isdefault": isDefault,
"len": hasLengthOf,
"min": hasMinOf,
"max": hasMaxOf,
@ -903,6 +905,11 @@ func isAlphaUnicode(fl FieldLevel) bool {
return alphaUnicodeRegex.MatchString(fl.Field().String())
}
// isDefault is the opposite of required aka hasValue
func isDefault(fl FieldLevel) bool {
return !hasValue(fl)
}
// HasValue is the validation function for validating if the current field's value is not the default static value.
func hasValue(fl FieldLevel) bool {

@ -13,6 +13,7 @@ type tagType uint8
const (
typeDefault tagType = iota
typeOmitEmpty
typeIsDefault
typeNoStructLevel
typeStructOnly
typeDive
@ -224,6 +225,10 @@ func (v *Validate) parseFieldTagsRecursive(tag string, fieldName string, alias s
default:
if t == isdefault {
current.typeof = typeIsDefault
}
// if a pipe character is needed within the param you must use the utf8Pipe representation "0x7C"
orVals := strings.Split(t, orSeparator)

@ -220,6 +220,13 @@ ensures the value is not nil.
Usage: required
Is Default
This validates that the value is the default value and is almost the
opposite of required.
Usage: isdefault
Length
For numbers, length will ensure that the value is

@ -112,7 +112,7 @@ func (v *validate) traverseField(ctx context.Context, parent reflect.Value, curr
return
}
if ct.typeof == typeOmitEmpty {
if ct.typeof == typeOmitEmpty || ct.typeof == typeIsDefault {
return
}
@ -174,6 +174,39 @@ func (v *validate) traverseField(ctx context.Context, parent reflect.Value, curr
if ct.typeof == typeStructOnly {
goto CONTINUE
} else if ct.typeof == typeIsDefault {
// set Field Level fields
v.slflParent = parent
v.flField = current
v.cf = cf
v.ct = ct
if !ct.fn(ctx, v) {
v.str1 = string(append(ns, cf.altName...))
if v.v.hasTagNameFunc {
v.str2 = string(append(structNs, cf.name...))
} else {
v.str2 = v.str1
}
v.errs = append(v.errs,
&fieldError{
v: v.v,
tag: ct.aliasTag,
actualTag: ct.tag,
ns: v.str1,
structNs: v.str2,
fieldLen: uint8(len(cf.altName)),
structfieldLen: uint8(len(cf.name)),
value: current.Interface(),
param: ct.param,
kind: kind,
typ: typ,
},
)
return
}
}
ct = ct.next
@ -404,10 +437,6 @@ OUTER:
v.cf = cf
v.ct = ct
// // report error interface functions need these
// v.ns = ns
// v.actualNs = structNs
if !ct.fn(ctx, v) {
v.str1 = string(append(ns, cf.altName...))

@ -22,6 +22,7 @@ const (
structOnlyTag = "structonly"
noStructLevelTag = "nostructlevel"
omitempty = "omitempty"
isdefault = "isdefault"
skipValidationTag = "-"
diveTag = "dive"
requiredTag = "required"

@ -7213,3 +7213,43 @@ func TestFQDNValidation(t *testing.T) {
}
}
}
func TestIsDefault(t *testing.T) {
validate := New()
type Inner struct {
String string `validate:"isdefault"`
}
type Test struct {
String string `validate:"isdefault"`
Inner *Inner `validate:"isdefault"`
}
var tt Test
errs := validate.Struct(tt)
Equal(t, errs, nil)
tt.Inner = &Inner{String: ""}
errs = validate.Struct(tt)
NotEqual(t, errs, nil)
fe := errs.(ValidationErrors)[0]
Equal(t, fe.Field(), "Inner")
Equal(t, fe.Namespace(), "Test.Inner")
Equal(t, fe.Tag(), "isdefault")
type Test2 struct {
Inner Inner `validate:"isdefault"`
}
var t2 Test2
errs = validate.Struct(t2)
Equal(t, errs, nil)
t2.Inner.String = "Changed"
errs = validate.Struct(t2)
NotEqual(t, errs, nil)
}

Loading…
Cancel
Save