mirror of
https://gitee.com/johng/gf
synced 2026-06-06 02:25:47 +08:00
improve empty slice/object validation logic for package gvalid
This commit is contained in:
@ -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 (
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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"`
|
||||
|
||||
Reference in New Issue
Block a user