|
|
@ -148,8 +148,6 @@ type Validate struct { |
|
|
|
hasCustomFuncs bool |
|
|
|
hasCustomFuncs bool |
|
|
|
hasAliasValidators bool |
|
|
|
hasAliasValidators bool |
|
|
|
hasStructLevelFuncs bool |
|
|
|
hasStructLevelFuncs bool |
|
|
|
// oldTagCache *tagCacheMap
|
|
|
|
|
|
|
|
// oldStructCache *structCacheMap
|
|
|
|
|
|
|
|
tagCache *tagCache |
|
|
|
tagCache *tagCache |
|
|
|
structCache *structCache |
|
|
|
structCache *structCache |
|
|
|
errsPool *sync.Pool |
|
|
|
errsPool *sync.Pool |
|
|
@ -234,8 +232,6 @@ func New(config *Config) *Validate { |
|
|
|
fieldNameTag: config.FieldNameTag, |
|
|
|
fieldNameTag: config.FieldNameTag, |
|
|
|
tagCache: tc, |
|
|
|
tagCache: tc, |
|
|
|
structCache: sc, |
|
|
|
structCache: sc, |
|
|
|
// oldTagCache: &tagCacheMap{m: map[string]*cachedTag{}},
|
|
|
|
|
|
|
|
// oldStructCache: &structCacheMap{m: map[reflect.Type]*cachedStruct{}},
|
|
|
|
|
|
|
|
errsPool: &sync.Pool{New: func() interface{} { |
|
|
|
errsPool: &sync.Pool{New: func() interface{} { |
|
|
|
return ValidationErrors{} |
|
|
|
return ValidationErrors{} |
|
|
|
}}} |
|
|
|
}}} |
|
|
@ -364,8 +360,6 @@ func (v *Validate) Field(field interface{}, tag string) error { |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// fmt.Println("CTAG:", ctag)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
v.traverseField(fieldVal, fieldVal, fieldVal, blank, blank, errs, false, false, nil, nil, defaultCField, ctag) |
|
|
|
v.traverseField(fieldVal, fieldVal, fieldVal, blank, blank, errs, false, false, nil, nil, defaultCField, ctag) |
|
|
|
|
|
|
|
|
|
|
|
if len(errs) == 0 { |
|
|
|
if len(errs) == 0 { |
|
|
@ -400,6 +394,7 @@ func (v *Validate) FieldWithValue(val interface{}, field interface{}, tag string |
|
|
|
ctag, ok = v.tagCache.Get(tag) |
|
|
|
ctag, ok = v.tagCache.Get(tag) |
|
|
|
if !ok { |
|
|
|
if !ok { |
|
|
|
ctag, _ = v.parseFieldTagsRecursive(tag, blank, blank, false) |
|
|
|
ctag, _ = v.parseFieldTagsRecursive(tag, blank, blank, false) |
|
|
|
|
|
|
|
v.tagCache.Set(tag, ctag) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -533,20 +528,15 @@ func (v *Validate) ensureValidStruct(topStruct reflect.Value, currentStruct refl |
|
|
|
// tranverseStruct traverses a structs fields and then passes them to be validated by traverseField
|
|
|
|
// tranverseStruct traverses a structs fields and then passes them to be validated by traverseField
|
|
|
|
func (v *Validate) tranverseStruct(topStruct reflect.Value, currentStruct reflect.Value, current reflect.Value, errPrefix string, nsPrefix string, errs ValidationErrors, useStructName bool, partial bool, exclude bool, includeExclude map[string]*struct{}, cs *cStruct, ct *cTag) { |
|
|
|
func (v *Validate) tranverseStruct(topStruct reflect.Value, currentStruct reflect.Value, current reflect.Value, errPrefix string, nsPrefix string, errs ValidationErrors, useStructName bool, partial bool, exclude bool, includeExclude map[string]*struct{}, cs *cStruct, ct *cTag) { |
|
|
|
|
|
|
|
|
|
|
|
// var ok bool
|
|
|
|
var ok bool |
|
|
|
first := len(nsPrefix) == 0 |
|
|
|
first := len(nsPrefix) == 0 |
|
|
|
typ := current.Type() |
|
|
|
typ := current.Type() |
|
|
|
var ok bool |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// var sName string
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
cs, ok = v.structCache.Get(typ) |
|
|
|
cs, ok = v.structCache.Get(typ) |
|
|
|
if !ok { |
|
|
|
if !ok { |
|
|
|
cs = v.extractStructCache(current, typ.Name()) |
|
|
|
cs = v.extractStructCache(current, typ.Name()) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// sName := typ.Name()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if useStructName { |
|
|
|
if useStructName { |
|
|
|
errPrefix += cs.Name + namespaceSeparator |
|
|
|
errPrefix += cs.Name + namespaceSeparator |
|
|
|
|
|
|
|
|
|
|
@ -560,55 +550,6 @@ func (v *Validate) tranverseStruct(topStruct reflect.Value, currentStruct reflec |
|
|
|
// if present
|
|
|
|
// if present
|
|
|
|
if first || ct == nil || !ct.isStructOnly { |
|
|
|
if first || ct == nil || !ct.isStructOnly { |
|
|
|
|
|
|
|
|
|
|
|
// var fld reflect.StructField
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// is anonymous struct, cannot parse or cache as
|
|
|
|
|
|
|
|
// it has no name to index by
|
|
|
|
|
|
|
|
// if sName == blank {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// var customName string
|
|
|
|
|
|
|
|
// var ok bool
|
|
|
|
|
|
|
|
// numFields := current.NumField()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// for i := 0; i < numFields; i++ {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// fld = typ.Field(i)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// if !fld.Anonymous && fld.PkgPath != blank {
|
|
|
|
|
|
|
|
// continue
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// if partial {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// _, ok = includeExclude[errPrefix+fld.Name]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// if (ok && exclude) || (!ok && !exclude) {
|
|
|
|
|
|
|
|
// continue
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// customName = fld.Name
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// if v.fieldNameTag != blank {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// name := strings.SplitN(fld.Tag.Get(v.fieldNameTag), ",", 2)[0]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// // dash check is for json "-" means don't output in json
|
|
|
|
|
|
|
|
// if name != blank && name != dash {
|
|
|
|
|
|
|
|
// customName = name
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// v.traverseField(topStruct, currentStruct, current.Field(i), errPrefix, nsPrefix, errs, true, fld.Tag.Get(v.tagName), fld.Name, customName, partial, exclude, includeExclude, nil)
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
// } else {
|
|
|
|
|
|
|
|
// s, ok := v.oldStructCache.Get(typ)
|
|
|
|
|
|
|
|
// if !ok {
|
|
|
|
|
|
|
|
// s = v.parseStruct(current, sName)
|
|
|
|
|
|
|
|
// ccs := v.extractStructCache(current, sName)
|
|
|
|
|
|
|
|
// fmt.Println(ccs, ccs.fields[0], s.fields[0].CachedTag)
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for _, f := range cs.fields { |
|
|
|
for _, f := range cs.fields { |
|
|
|
|
|
|
|
|
|
|
|
if partial { |
|
|
|
if partial { |
|
|
@ -619,48 +560,26 @@ func (v *Validate) tranverseStruct(topStruct reflect.Value, currentStruct reflec |
|
|
|
continue |
|
|
|
continue |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
// fld = typ.Field(f.Idx)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// fmt.Println(errPrefix+f.Name, f.cTags)
|
|
|
|
|
|
|
|
v.traverseField(topStruct, currentStruct, current.Field(f.Idx), errPrefix, nsPrefix, errs, partial, exclude, includeExclude, cs, f, f.cTags) |
|
|
|
v.traverseField(topStruct, currentStruct, current.Field(f.Idx), errPrefix, nsPrefix, errs, partial, exclude, includeExclude, cs, f, f.cTags) |
|
|
|
} |
|
|
|
} |
|
|
|
// }
|
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// check if any struct level validations, after all field validations already checked.
|
|
|
|
// check if any struct level validations, after all field validations already checked.
|
|
|
|
if cs.fn != nil { |
|
|
|
if cs.fn != nil { |
|
|
|
// if fsn, ok := v.structLevelFuncs[current.Type()]; ok {
|
|
|
|
|
|
|
|
cs.fn(v, &StructLevel{v: v, TopStruct: topStruct, CurrentStruct: current, errPrefix: errPrefix, nsPrefix: nsPrefix, errs: errs}) |
|
|
|
cs.fn(v, &StructLevel{v: v, TopStruct: topStruct, CurrentStruct: current, errPrefix: errPrefix, nsPrefix: nsPrefix, errs: errs}) |
|
|
|
// }
|
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// traverseField validates any field, be it a struct or single field, ensures it's validity and passes it along to be validated via it's tag options
|
|
|
|
// traverseField validates any field, be it a struct or single field, ensures it's validity and passes it along to be validated via it's tag options
|
|
|
|
func (v *Validate) traverseField(topStruct reflect.Value, currentStruct reflect.Value, current reflect.Value, errPrefix string, nsPrefix string, errs ValidationErrors, partial bool, exclude bool, includeExclude map[string]*struct{}, cs *cStruct, cf *cField, ct *cTag) { |
|
|
|
func (v *Validate) traverseField(topStruct reflect.Value, currentStruct reflect.Value, current reflect.Value, errPrefix string, nsPrefix string, errs ValidationErrors, partial bool, exclude bool, includeExclude map[string]*struct{}, cs *cStruct, cf *cField, ct *cTag) { |
|
|
|
|
|
|
|
|
|
|
|
// if tag == skipValidationTag {
|
|
|
|
|
|
|
|
// return
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// if cTag == nil {
|
|
|
|
|
|
|
|
// var isCached bool
|
|
|
|
|
|
|
|
// cTag, isCached = v.oldTagCache.Get(tag)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// if !isCached {
|
|
|
|
|
|
|
|
// cTag = v.parseTags(tag, name)
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
current, kind := v.ExtractType(current) |
|
|
|
current, kind := v.ExtractType(current) |
|
|
|
var typ reflect.Type |
|
|
|
var typ reflect.Type |
|
|
|
|
|
|
|
|
|
|
|
// fmt.Println("TS:", ct, kind)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
switch kind { |
|
|
|
switch kind { |
|
|
|
case reflect.Ptr, reflect.Interface, reflect.Invalid: |
|
|
|
case reflect.Ptr, reflect.Interface, reflect.Invalid: |
|
|
|
|
|
|
|
|
|
|
|
// return
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if ct == nil { |
|
|
|
if ct == nil { |
|
|
|
return |
|
|
|
return |
|
|
|
} |
|
|
|
} |
|
|
@ -669,7 +588,6 @@ func (v *Validate) traverseField(topStruct reflect.Value, currentStruct reflect. |
|
|
|
return |
|
|
|
return |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// if !ct.hasTag {
|
|
|
|
|
|
|
|
if ct.hasTag { |
|
|
|
if ct.hasTag { |
|
|
|
|
|
|
|
|
|
|
|
ns := errPrefix + cf.Name |
|
|
|
ns := errPrefix + cf.Name |
|
|
@ -704,8 +622,6 @@ func (v *Validate) traverseField(topStruct reflect.Value, currentStruct reflect. |
|
|
|
return |
|
|
|
return |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// return
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// if we get here tag length is zero and we can leave
|
|
|
|
// if we get here tag length is zero and we can leave
|
|
|
|
if kind == reflect.Invalid { |
|
|
|
if kind == reflect.Invalid { |
|
|
|
return |
|
|
|
return |
|
|
@ -718,15 +634,12 @@ func (v *Validate) traverseField(topStruct reflect.Value, currentStruct reflect. |
|
|
|
|
|
|
|
|
|
|
|
if ct != nil { |
|
|
|
if ct != nil { |
|
|
|
ct = ct.next |
|
|
|
ct = ct.next |
|
|
|
// fmt.Println("CHECKING NO STRUCT LEVEL", ct.isNoStructLevel, ct.next)
|
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// if ct != nil && (ct.isNoStructLevel || (ct.next != nil && ct.next.isNoStructLevel)) {
|
|
|
|
|
|
|
|
if ct != nil && ct.isNoStructLevel { |
|
|
|
if ct != nil && ct.isNoStructLevel { |
|
|
|
return |
|
|
|
return |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// func (v *Validate) tranverseStruct(topStruct reflect.Value, errPrefix string, nsPrefix string, errs ValidationErrors, useStructName bool, partial bool, exclude bool, includeExclude map[string]*struct{}, cs *cStruct, ct *cTag)
|
|
|
|
|
|
|
|
v.tranverseStruct(topStruct, current, current, errPrefix+cf.Name+namespaceSeparator, nsPrefix+cf.AltName+namespaceSeparator, errs, false, partial, exclude, includeExclude, cs, ct) |
|
|
|
v.tranverseStruct(topStruct, current, current, errPrefix+cf.Name+namespaceSeparator, nsPrefix+cf.AltName+namespaceSeparator, errs, false, partial, exclude, includeExclude, cs, ct) |
|
|
|
return |
|
|
|
return |
|
|
|
} |
|
|
|
} |
|
|
@ -761,12 +674,8 @@ OUTER: |
|
|
|
|
|
|
|
|
|
|
|
if ct.isDive { |
|
|
|
if ct.isDive { |
|
|
|
|
|
|
|
|
|
|
|
// fmt.Println("IN DIVE:", ct)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ct = ct.next |
|
|
|
ct = ct.next |
|
|
|
|
|
|
|
|
|
|
|
// fmt.Println("NEXT:", ct)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// traverse slice or map here
|
|
|
|
// traverse slice or map here
|
|
|
|
// or panic ;)
|
|
|
|
// or panic ;)
|
|
|
|
switch kind { |
|
|
|
switch kind { |
|
|
@ -775,14 +684,12 @@ OUTER: |
|
|
|
for i := 0; i < current.Len(); i++ { |
|
|
|
for i := 0; i < current.Len(); i++ { |
|
|
|
v.traverseField(topStruct, currentStruct, current.Index(i), errPrefix, nsPrefix, errs, partial, exclude, includeExclude, cs, &cField{Name: fmt.Sprintf(arrayIndexFieldName, cf.Name, i), AltName: fmt.Sprintf(arrayIndexFieldName, cf.AltName, i)}, ct) |
|
|
|
v.traverseField(topStruct, currentStruct, current.Index(i), errPrefix, nsPrefix, errs, partial, exclude, includeExclude, cs, &cField{Name: fmt.Sprintf(arrayIndexFieldName, cf.Name, i), AltName: fmt.Sprintf(arrayIndexFieldName, cf.AltName, i)}, ct) |
|
|
|
} |
|
|
|
} |
|
|
|
// v.traverseSlice(topStruct, currentStruct, current, errPrefix, nsPrefix, errs, diveSubTag, name, customName, partial, exclude, includeExclude, nil)
|
|
|
|
|
|
|
|
case reflect.Map: |
|
|
|
case reflect.Map: |
|
|
|
for _, key := range current.MapKeys() { |
|
|
|
for _, key := range current.MapKeys() { |
|
|
|
v.traverseField(topStruct, currentStruct, current.MapIndex(key), errPrefix, nsPrefix, errs, partial, exclude, includeExclude, cs, &cField{Name: fmt.Sprintf(mapIndexFieldName, cf.Name, key.Interface()), AltName: fmt.Sprintf(mapIndexFieldName, cf.AltName, key.Interface())}, ct) |
|
|
|
v.traverseField(topStruct, currentStruct, current.MapIndex(key), errPrefix, nsPrefix, errs, partial, exclude, includeExclude, cs, &cField{Name: fmt.Sprintf(mapIndexFieldName, cf.Name, key.Interface()), AltName: fmt.Sprintf(mapIndexFieldName, cf.AltName, key.Interface())}, ct) |
|
|
|
// v.traverseField(topStruct, currentStruct, current.MapIndex(key), errPrefix, nsPrefix, errs, false, tag, fmt.Sprintf(mapIndexFieldName, name, key.Interface()), fmt.Sprintf(mapIndexFieldName, customName, key.Interface()), partial, exclude, includeExclude, cTag)
|
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// v.traverseMap(topStruct, currentStruct, current, errPrefix, nsPrefix, errs, diveSubTag, name, customName, partial, exclude, includeExclude, nil)
|
|
|
|
|
|
|
|
default: |
|
|
|
default: |
|
|
|
// throw error, if not a slice or map then should not have gotten here
|
|
|
|
// throw error, if not a slice or map then should not have gotten here
|
|
|
|
// bad dive tag
|
|
|
|
// bad dive tag
|
|
|
@ -796,44 +703,8 @@ OUTER: |
|
|
|
|
|
|
|
|
|
|
|
errTag := blank |
|
|
|
errTag := blank |
|
|
|
|
|
|
|
|
|
|
|
// for _, val := range valTag.tagVals {
|
|
|
|
|
|
|
|
for { |
|
|
|
for { |
|
|
|
|
|
|
|
|
|
|
|
// fmt.Println(ct)
|
|
|
|
|
|
|
|
// if ct == nil {
|
|
|
|
|
|
|
|
// // if we get here, no valid 'or' value and no more tags
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// ns := errPrefix + cf.Name
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// if ct.hasAlias {
|
|
|
|
|
|
|
|
// errs[ns] = &FieldError{
|
|
|
|
|
|
|
|
// FieldNamespace: ns,
|
|
|
|
|
|
|
|
// NameNamespace: nsPrefix + cf.AltName,
|
|
|
|
|
|
|
|
// Name: cf.AltName,
|
|
|
|
|
|
|
|
// Field: cf.Name,
|
|
|
|
|
|
|
|
// Tag: ct.aliasTag,
|
|
|
|
|
|
|
|
// ActualTag: ct.tag,
|
|
|
|
|
|
|
|
// Value: current.Interface(),
|
|
|
|
|
|
|
|
// Type: typ,
|
|
|
|
|
|
|
|
// Kind: kind,
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
// } else {
|
|
|
|
|
|
|
|
// errs[errPrefix+cf.Name] = &FieldError{
|
|
|
|
|
|
|
|
// FieldNamespace: ns,
|
|
|
|
|
|
|
|
// NameNamespace: nsPrefix + cf.AltName,
|
|
|
|
|
|
|
|
// Name: cf.AltName,
|
|
|
|
|
|
|
|
// Field: cf.Name,
|
|
|
|
|
|
|
|
// Tag: errTag[1:],
|
|
|
|
|
|
|
|
// ActualTag: errTag[1:],
|
|
|
|
|
|
|
|
// Value: current.Interface(),
|
|
|
|
|
|
|
|
// Type: typ,
|
|
|
|
|
|
|
|
// Kind: kind,
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// return
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if !ct.isOrVal { |
|
|
|
if !ct.isOrVal { |
|
|
|
// if we get here, no valid 'or' value, but more tags
|
|
|
|
// if we get here, no valid 'or' value, but more tags
|
|
|
|
|
|
|
|
|
|
|
@ -866,15 +737,8 @@ OUTER: |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
continue OUTER |
|
|
|
continue OUTER |
|
|
|
// break
|
|
|
|
|
|
|
|
// goto VAL
|
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// valFunc, ok = v.validationFuncs[val[0]]
|
|
|
|
|
|
|
|
// if !ok {
|
|
|
|
|
|
|
|
// panic(strings.TrimSpace(fmt.Sprintf(undefinedValidation, name)))
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if ct.fn(v, topStruct, currentStruct, current, typ, kind, ct.param) { |
|
|
|
if ct.fn(v, topStruct, currentStruct, current, typ, kind, ct.param) { |
|
|
|
|
|
|
|
|
|
|
|
// drain rest of the 'or' values, then continue or leave
|
|
|
|
// drain rest of the 'or' values, then continue or leave
|
|
|
@ -888,8 +752,6 @@ OUTER: |
|
|
|
|
|
|
|
|
|
|
|
if !ct.isOrVal { |
|
|
|
if !ct.isOrVal { |
|
|
|
continue OUTER |
|
|
|
continue OUTER |
|
|
|
// break
|
|
|
|
|
|
|
|
// goto VAL
|
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
@ -932,45 +794,7 @@ OUTER: |
|
|
|
|
|
|
|
|
|
|
|
ct = ct.next |
|
|
|
ct = ct.next |
|
|
|
} |
|
|
|
} |
|
|
|
// if valFunc(v, topStruct, currentStruct, current, currentType, currentKind, val[1]) {
|
|
|
|
} |
|
|
|
// return false
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// errTag += orSeparator + val[0]
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// ns := errPrefix + name
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// if valTag.isAlias {
|
|
|
|
|
|
|
|
// errs[ns] = &FieldError{
|
|
|
|
|
|
|
|
// FieldNamespace: ns,
|
|
|
|
|
|
|
|
// NameNamespace: nsPrefix + customName,
|
|
|
|
|
|
|
|
// Name: customName,
|
|
|
|
|
|
|
|
// Field: name,
|
|
|
|
|
|
|
|
// Tag: valTag.tag,
|
|
|
|
|
|
|
|
// ActualTag: errTag[1:],
|
|
|
|
|
|
|
|
// Value: current.Interface(),
|
|
|
|
|
|
|
|
// Type: currentType,
|
|
|
|
|
|
|
|
// Kind: currentKind,
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
// } else {
|
|
|
|
|
|
|
|
// errs[errPrefix+name] = &FieldError{
|
|
|
|
|
|
|
|
// FieldNamespace: ns,
|
|
|
|
|
|
|
|
// NameNamespace: nsPrefix + customName,
|
|
|
|
|
|
|
|
// Name: customName,
|
|
|
|
|
|
|
|
// Field: name,
|
|
|
|
|
|
|
|
// Tag: errTag[1:],
|
|
|
|
|
|
|
|
// ActualTag: errTag[1:],
|
|
|
|
|
|
|
|
// Value: current.Interface(),
|
|
|
|
|
|
|
|
// Type: currentType,
|
|
|
|
|
|
|
|
// Kind: currentKind,
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// NOT SURE ABOUT THE BELOW LINE BEING COMMENT, LINT SAYS IT's Unreachable but....
|
|
|
|
|
|
|
|
// return
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// fmt.Println(ct)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if !ct.fn(v, topStruct, currentStruct, current, typ, kind, ct.param) { |
|
|
|
if !ct.fn(v, topStruct, currentStruct, current, typ, kind, ct.param) { |
|
|
|
|
|
|
|
|
|
|
@ -992,176 +816,7 @@ OUTER: |
|
|
|
return |
|
|
|
return |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
// VAL:
|
|
|
|
|
|
|
|
// valFunc, ok = v.validationFuncs[valTag.tagVals[0][0]]
|
|
|
|
|
|
|
|
// if !ok {
|
|
|
|
|
|
|
|
// panic(strings.TrimSpace(fmt.Sprintf(undefinedValidation, name)))
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// if valFunc(v, topStruct, currentStruct, current, currentType, currentKind, valTag.tagVals[0][1]) {
|
|
|
|
|
|
|
|
// return false
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// ns := errPrefix + name
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// errs[ns] = &FieldError{
|
|
|
|
|
|
|
|
// FieldNamespace: ns,
|
|
|
|
|
|
|
|
// NameNamespace: nsPrefix + customName,
|
|
|
|
|
|
|
|
// Name: customName,
|
|
|
|
|
|
|
|
// Field: name,
|
|
|
|
|
|
|
|
// Tag: valTag.tag,
|
|
|
|
|
|
|
|
// ActualTag: valTag.tagVals[0][0],
|
|
|
|
|
|
|
|
// Value: current.Interface(),
|
|
|
|
|
|
|
|
// Param: valTag.tagVals[0][1],
|
|
|
|
|
|
|
|
// Type: currentType,
|
|
|
|
|
|
|
|
// Kind: currentKind,
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// if v.validateField(topStruct, currentStruct, current, typ, kind, errPrefix, nsPrefix, errs, valTag, name, customName) {
|
|
|
|
|
|
|
|
// return
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ct = ct.next |
|
|
|
ct = ct.next |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// var dive bool
|
|
|
|
|
|
|
|
// var diveSubTag string
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// for _, valTag := range cTag.tags {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// // if valTag.tagVals[0][0] == existsTag {
|
|
|
|
|
|
|
|
// // continue
|
|
|
|
|
|
|
|
// // }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// // if valTag.tagVals[0][0] == diveTag {
|
|
|
|
|
|
|
|
// // dive = true
|
|
|
|
|
|
|
|
// // diveSubTag = strings.TrimLeft(strings.SplitN(cTag.diveTag, diveTag, 2)[1], ",")
|
|
|
|
|
|
|
|
// // break
|
|
|
|
|
|
|
|
// // }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// // if valTag.tagVals[0][0] == omitempty {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// // if !HasValue(v, topStruct, currentStruct, current, typ, kind, blank) {
|
|
|
|
|
|
|
|
// // return
|
|
|
|
|
|
|
|
// // }
|
|
|
|
|
|
|
|
// // continue
|
|
|
|
|
|
|
|
// // }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// if v.validateField(topStruct, currentStruct, current, typ, kind, errPrefix, nsPrefix, errs, valTag, name, customName) {
|
|
|
|
|
|
|
|
// return
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// if dive {
|
|
|
|
|
|
|
|
// // traverse slice or map here
|
|
|
|
|
|
|
|
// // or panic ;)
|
|
|
|
|
|
|
|
// switch kind {
|
|
|
|
|
|
|
|
// case reflect.Slice, reflect.Array:
|
|
|
|
|
|
|
|
// v.traverseSlice(topStruct, currentStruct, current, errPrefix, nsPrefix, errs, diveSubTag, name, customName, partial, exclude, includeExclude, nil)
|
|
|
|
|
|
|
|
// case reflect.Map:
|
|
|
|
|
|
|
|
// v.traverseMap(topStruct, currentStruct, current, errPrefix, nsPrefix, errs, diveSubTag, name, customName, partial, exclude, includeExclude, nil)
|
|
|
|
|
|
|
|
// default:
|
|
|
|
|
|
|
|
// // throw error, if not a slice or map then should not have gotten here
|
|
|
|
|
|
|
|
// // bad dive tag
|
|
|
|
|
|
|
|
// panic("dive error! can't dive on a non slice or map")
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// // traverseSlice traverses a Slice or Array's elements and passes them to traverseField for validation
|
|
|
|
|
|
|
|
// func (v *Validate) traverseSlice(topStruct reflect.Value, currentStruct reflect.Value, current reflect.Value, errPrefix string, nsPrefix string, errs ValidationErrors, tag, name, customName string, partial bool, exclude bool, includeExclude map[string]*struct{}, cTag *cachedTag) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// for i := 0; i < current.Len(); i++ {
|
|
|
|
|
|
|
|
// v.traverseField(topStruct, currentStruct, current.Index(i), errPrefix, nsPrefix, errs, false, tag, fmt.Sprintf(arrayIndexFieldName, name, i), fmt.Sprintf(arrayIndexFieldName, customName, i), partial, exclude, includeExclude, cTag)
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// // traverseMap traverses a map's elements and passes them to traverseField for validation
|
|
|
|
|
|
|
|
// func (v *Validate) traverseMap(topStruct reflect.Value, currentStruct reflect.Value, current reflect.Value, errPrefix string, nsPrefix string, errs ValidationErrors, tag, name, customName string, partial bool, exclude bool, includeExclude map[string]*struct{}, cTag *cachedTag) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// for _, key := range current.MapKeys() {
|
|
|
|
|
|
|
|
// v.traverseField(topStruct, currentStruct, current.MapIndex(key), errPrefix, nsPrefix, errs, false, tag, fmt.Sprintf(mapIndexFieldName, name, key.Interface()), fmt.Sprintf(mapIndexFieldName, customName, key.Interface()), partial, exclude, includeExclude, cTag)
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// // validateField validates a field based on the provided tag's key and param values and returns true if there is an error or false if all ok
|
|
|
|
|
|
|
|
// func (v *Validate) validateField(topStruct reflect.Value, currentStruct reflect.Value, current reflect.Value, currentType reflect.Type, currentKind reflect.Kind, errPrefix string, nsPrefix string, errs ValidationErrors, valTag *tagVals, name, customName string) bool {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// var valFunc Func
|
|
|
|
|
|
|
|
// var ok bool
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// if valTag.isOrVal {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// errTag := blank
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// for _, val := range valTag.tagVals {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// valFunc, ok = v.validationFuncs[val[0]]
|
|
|
|
|
|
|
|
// if !ok {
|
|
|
|
|
|
|
|
// panic(strings.TrimSpace(fmt.Sprintf(undefinedValidation, name)))
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// if valFunc(v, topStruct, currentStruct, current, currentType, currentKind, val[1]) {
|
|
|
|
|
|
|
|
// return false
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// errTag += orSeparator + val[0]
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// ns := errPrefix + name
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// if valTag.isAlias {
|
|
|
|
|
|
|
|
// errs[ns] = &FieldError{
|
|
|
|
|
|
|
|
// FieldNamespace: ns,
|
|
|
|
|
|
|
|
// NameNamespace: nsPrefix + customName,
|
|
|
|
|
|
|
|
// Name: customName,
|
|
|
|
|
|
|
|
// Field: name,
|
|
|
|
|
|
|
|
// Tag: valTag.tag,
|
|
|
|
|
|
|
|
// ActualTag: errTag[1:],
|
|
|
|
|
|
|
|
// Value: current.Interface(),
|
|
|
|
|
|
|
|
// Type: currentType,
|
|
|
|
|
|
|
|
// Kind: currentKind,
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
// } else {
|
|
|
|
|
|
|
|
// errs[errPrefix+name] = &FieldError{
|
|
|
|
|
|
|
|
// FieldNamespace: ns,
|
|
|
|
|
|
|
|
// NameNamespace: nsPrefix + customName,
|
|
|
|
|
|
|
|
// Name: customName,
|
|
|
|
|
|
|
|
// Field: name,
|
|
|
|
|
|
|
|
// Tag: errTag[1:],
|
|
|
|
|
|
|
|
// ActualTag: errTag[1:],
|
|
|
|
|
|
|
|
// Value: current.Interface(),
|
|
|
|
|
|
|
|
// Type: currentType,
|
|
|
|
|
|
|
|
// Kind: currentKind,
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// return true
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// valFunc, ok = v.validationFuncs[valTag.tagVals[0][0]]
|
|
|
|
|
|
|
|
// if !ok {
|
|
|
|
|
|
|
|
// panic(strings.TrimSpace(fmt.Sprintf(undefinedValidation, name)))
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// if valFunc(v, topStruct, currentStruct, current, currentType, currentKind, valTag.tagVals[0][1]) {
|
|
|
|
|
|
|
|
// return false
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// ns := errPrefix + name
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// errs[ns] = &FieldError{
|
|
|
|
|
|
|
|
// FieldNamespace: ns,
|
|
|
|
|
|
|
|
// NameNamespace: nsPrefix + customName,
|
|
|
|
|
|
|
|
// Name: customName,
|
|
|
|
|
|
|
|
// Field: name,
|
|
|
|
|
|
|
|
// Tag: valTag.tag,
|
|
|
|
|
|
|
|
// ActualTag: valTag.tagVals[0][0],
|
|
|
|
|
|
|
|
// Value: current.Interface(),
|
|
|
|
|
|
|
|
// Param: valTag.tagVals[0][1],
|
|
|
|
|
|
|
|
// Type: currentType,
|
|
|
|
|
|
|
|
// Kind: currentKind,
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// return true
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|