improve empty slice/object validation logic for package gvalid

This commit is contained in:
John Guo
2022-03-25 17:53:58 +08:00
parent 6810e71220
commit ec92d2b7f4
3 changed files with 31 additions and 9 deletions

View File

@ -9,6 +9,7 @@ package gvalid
import (
"context"
"reflect"
"regexp"
"strings"
@ -22,9 +23,10 @@ type CustomMsg = map[string]interface{}
// fieldRule defined the alias name and rule string for specified field.
type fieldRule struct {
Name string // Alias name for the field.
Rule string // Rule string like: "max:6"
IsMeta bool // Is this rule is from gmeta.Meta, which marks it as whole struct rule.
Name string // Alias name for the field.
Rule string // Rule string like: "max:6"
IsMeta bool // Is this rule is from gmeta.Meta, which marks it as whole struct rule.
FieldKind reflect.Kind // Kind of struct field, which is used for parameter type checks.
}
// iNoValidation is an interface that marks current struct not validated by package `gvalid`.
@ -43,6 +45,8 @@ const (
noValidationTagName = "nv" // no validation tag name for struct attribute.
ruleNameBail = "bail" // the name for rule "bail"
ruleNameCi = "ci" // the name for rule "ci"
emptyJsonArrayStr = "[]" // Empty json string for array type.
emptyJsonObjectStr = "{}" // Empty json string for object type.
)
var (

View File

@ -177,9 +177,10 @@ func (v *Validator) doCheckStruct(ctx context.Context, object interface{}) Error
_, isMeta = fieldValue.(gmeta.Meta)
}
checkRules = append(checkRules, fieldRule{
Name: name,
Rule: rule,
IsMeta: isMeta,
Name: name,
Rule: rule,
IsMeta: isMeta,
FieldKind: field.OriginalKind(),
})
}
} else {
@ -278,6 +279,19 @@ func (v *Validator) doCheckStruct(ctx context.Context, object interface{}) Error
}
}
}
// Empty json string checks according to mapping field kind.
if value != nil {
switch checkRuleItem.FieldKind {
case reflect.Struct, reflect.Map:
if gconv.String(value) == emptyJsonObjectStr {
value = ""
}
case reflect.Slice, reflect.Array:
if gconv.String(value) == emptyJsonArrayStr {
value = ""
}
}
}
// It checks each rule and its value in loop.
if validatedError := v.doCheckValue(ctx, doCheckValueInput{
Name: checkRuleItem.Name,
@ -302,6 +316,11 @@ func (v *Validator) doCheckStruct(ctx context.Context, object interface{}) Error
required = true
break
}
// All custom validation rules are required rules.
if _, ok := customRuleFuncMap[ruleKey]; ok {
required = true
break
}
}
if !required {
continue

View File

@ -216,8 +216,6 @@ func Test_CheckMap_Recursive_SliceStruct(t *testing.T) {
}
func Test_CheckStruct_Recursively_SliceAttribute(t *testing.T) {
// TODO
return
gtest.C(t, func(t *gtest.T) {
type Student struct {
Name string `v:"required#Student Name is required"`
@ -235,8 +233,9 @@ func Test_CheckStruct_Recursively_SliceAttribute(t *testing.T) {
}
)
err := g.Validator().Assoc(data).Data(teacher).Run(ctx)
t.Assert(err, `Student Name is required`)
t.Assert(err, `The Students field is required`)
})
gtest.C(t, func(t *gtest.T) {
type Student struct {
Name string `v:"required#Student Name is required"`