Merge pull request '支持嵌套结构体验证' (#1) from feture/nested_struct into master
Reviewed-on: #1
This commit is contained in:
commit
5775c41074
18
define.go
18
define.go
@ -14,23 +14,23 @@ import (
|
|||||||
const (
|
const (
|
||||||
TagErrMsg = "err" // json结构体中, 错误信息 tag 字段
|
TagErrMsg = "err" // json结构体中, 错误信息 tag 字段
|
||||||
TagValidate = "validator" // json结构体中, 验证规则 rule 字段
|
TagValidate = "validator" // json结构体中, 验证规则 rule 字段
|
||||||
TagDefaultValue = "d" // json结构体中默认值标签
|
TagDefaultValue = "default" // json结构体中默认值标签
|
||||||
)
|
)
|
||||||
|
|
||||||
// Rule 规则定义
|
// Rule 规则定义
|
||||||
type Rule struct {
|
type Rule struct {
|
||||||
Tag string `json:"tag" dc:"规则标签,如:required, email, phone, etc."` // 规则标签,如:required, email, phone, etc.
|
Tag string `json:"tag" dc:"规则标签,如:required, email, phone, etc."` // 规则标签,如:required, email, phone, etc.
|
||||||
Args []string `json:"args" dc:"规则参数"` // 规则参数,如: Tag=min, Args=[1], 则会转化成验证规则 min=1
|
Args []string `json:"args" dc:"规则参数"` // 规则参数,如: Tag=min, Args=[1], 则会转化成验证规则 min=1
|
||||||
}
|
}
|
||||||
|
|
||||||
// StructField 结构体字段定义
|
// StructField 结构体字段定义
|
||||||
type StructField struct {
|
type StructField struct {
|
||||||
JsonTag string `json:"json_tag" dc:"字段对外输出的json标签"` // 结构体字段名称, 不单独设置, 从 TargetPath 解析
|
JsonTag string `json:"json_tag" dc:"字段对外输出的json标签"` // 结构体字段名称, 不单独设置, 从 TargetPath 解析
|
||||||
Type consts.DataType `json:"type" dc:"字段的数据类型"` // 字段的数据类型
|
Type consts.DataType `json:"type" dc:"字段的数据类型"` // 字段的数据类型
|
||||||
Required bool `json:"required" dc:"是否必传"` // 对应验证规则的 required 属性, 在非必传的情况下, 字段不存在, 不会进行规则验证, 字段存在, 才会进行验证, Required == false 时, 会在 RuleList 检测是否有required 规则
|
Required bool `json:"required" dc:"是否必传"` // 对应验证规则的 required 属性, 在非必传的情况下, 字段不存在, 不会进行规则验证, 字段存在, 才会进行验证, Required == false 时, 会在 RuleList 检测是否有required 规则
|
||||||
RuleList []Rule `json:"rule_list" dc:"字段规则列表"` // 字段规则列表
|
RuleList []Rule `json:"rule_list" dc:"字段规则列表"` // 字段规则列表
|
||||||
DefaultValue string `json:"default_value" dc:"字段默认值"` // 字段默认值, 仅对非必传字段生效, 统一用字符串类型, 后面会转换成 FieldType 类型
|
DefaultValue string `json:"default_value" dc:"字段默认值"` // 字段默认值, 仅对非必传字段生效, 统一用字符串类型, 后面会转换成 FieldType 类型
|
||||||
SourcePath string `json:"source_path" dc:"读取数据的数据源路径"` // 读取数据的数据源路径
|
SourcePath string `json:"source_path" dc:"读取数据的数据源路径"` // 读取数据的数据源路径
|
||||||
TargetPath string `json:"target_path" dc:"数据设置哪一个路径"` // 目标数据路径
|
TargetPath string `json:"target_path" dc:"数据设置哪一个路径"` // 目标数据路径
|
||||||
Errmsg string `json:"errmsg" dc:"规则验证不通过时, 报错的信息"` // 规则验证不通过时, 报错的信息
|
Errmsg string `json:"errmsg" dc:"规则验证不通过时, 报错的信息"` // 规则验证不通过时, 报错的信息
|
||||||
}
|
}
|
||||||
|
11
go.mod
11
go.mod
@ -3,11 +3,11 @@ module git.zhangdeman.cn/gateway/validate
|
|||||||
go 1.24.1
|
go 1.24.1
|
||||||
|
|
||||||
require (
|
require (
|
||||||
git.zhangdeman.cn/zhangdeman/consts v0.0.0-20250227040546-863c03f34bb8
|
git.zhangdeman.cn/zhangdeman/consts v0.0.0-20250321102241-d6e86b64f7ca
|
||||||
git.zhangdeman.cn/zhangdeman/dynamic-struct v0.0.0-20250319072714-eab2a7abde63
|
git.zhangdeman.cn/zhangdeman/dynamic-struct v0.0.0-20250321154326-850866d6f568
|
||||||
git.zhangdeman.cn/zhangdeman/json_filter v0.0.0-20241205105007-b8c8c9d4338c
|
git.zhangdeman.cn/zhangdeman/json_filter v0.0.0-20250321103029-786c03293a28
|
||||||
git.zhangdeman.cn/zhangdeman/serialize v0.0.0-20241223084948-de2e49144fcd
|
git.zhangdeman.cn/zhangdeman/serialize v0.0.0-20241223084948-de2e49144fcd
|
||||||
git.zhangdeman.cn/zhangdeman/wrapper v0.0.0-20250302133417-c1588abcb436
|
github.com/creasty/defaults v1.8.0
|
||||||
github.com/go-playground/validator/v10 v10.25.0
|
github.com/go-playground/validator/v10 v10.25.0
|
||||||
github.com/tidwall/gjson v1.18.0
|
github.com/tidwall/gjson v1.18.0
|
||||||
github.com/tidwall/sjson v1.2.5
|
github.com/tidwall/sjson v1.2.5
|
||||||
@ -16,6 +16,7 @@ require (
|
|||||||
require (
|
require (
|
||||||
git.zhangdeman.cn/zhangdeman/op_type v0.0.0-20240122104027-4928421213c0 // indirect
|
git.zhangdeman.cn/zhangdeman/op_type v0.0.0-20240122104027-4928421213c0 // indirect
|
||||||
git.zhangdeman.cn/zhangdeman/util v0.0.0-20240618042405-6ee2c904644e // indirect
|
git.zhangdeman.cn/zhangdeman/util v0.0.0-20240618042405-6ee2c904644e // indirect
|
||||||
|
git.zhangdeman.cn/zhangdeman/wrapper v0.0.0-20250321102712-1cbfbe959740 // indirect
|
||||||
github.com/BurntSushi/toml v1.5.0 // indirect
|
github.com/BurntSushi/toml v1.5.0 // indirect
|
||||||
github.com/axgle/mahonia v0.0.0-20180208002826-3358181d7394 // indirect
|
github.com/axgle/mahonia v0.0.0-20180208002826-3358181d7394 // indirect
|
||||||
github.com/gabriel-vasile/mimetype v1.4.8 // indirect
|
github.com/gabriel-vasile/mimetype v1.4.8 // indirect
|
||||||
@ -34,5 +35,3 @@ require (
|
|||||||
golang.org/x/text v0.23.0 // indirect
|
golang.org/x/text v0.23.0 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
)
|
)
|
||||||
|
|
||||||
replace git.zhangdeman.cn/zhangdeman/dynamic-struct => ../dynamic-struct
|
|
||||||
|
13
go.sum
13
go.sum
@ -1,7 +1,16 @@
|
|||||||
git.zhangdeman.cn/zhangdeman/consts v0.0.0-20250227040546-863c03f34bb8 h1:VEifPc+vkpEQoX9rj7zxmT1m+IA81XjOxe7+Z1aqWNM=
|
git.zhangdeman.cn/zhangdeman/consts v0.0.0-20250227040546-863c03f34bb8 h1:VEifPc+vkpEQoX9rj7zxmT1m+IA81XjOxe7+Z1aqWNM=
|
||||||
git.zhangdeman.cn/zhangdeman/consts v0.0.0-20250227040546-863c03f34bb8/go.mod h1:IXXaZkb7vGzGnGM5RRWrASAuwrVSNxuoe0DmeXx5g6k=
|
git.zhangdeman.cn/zhangdeman/consts v0.0.0-20250227040546-863c03f34bb8/go.mod h1:IXXaZkb7vGzGnGM5RRWrASAuwrVSNxuoe0DmeXx5g6k=
|
||||||
|
git.zhangdeman.cn/zhangdeman/consts v0.0.0-20250321101544-734d9a9f7733 h1:j5tG00W5C+1kYLJV73Iw3wvMo212x4taUHGolf3kikQ=
|
||||||
|
git.zhangdeman.cn/zhangdeman/consts v0.0.0-20250321101544-734d9a9f7733/go.mod h1:IXXaZkb7vGzGnGM5RRWrASAuwrVSNxuoe0DmeXx5g6k=
|
||||||
|
git.zhangdeman.cn/zhangdeman/consts v0.0.0-20250321102241-d6e86b64f7ca h1:uxjzbY5fDozjyK6jkoQtuQouVTcVfXjbe3chARYSjRM=
|
||||||
|
git.zhangdeman.cn/zhangdeman/consts v0.0.0-20250321102241-d6e86b64f7ca/go.mod h1:IXXaZkb7vGzGnGM5RRWrASAuwrVSNxuoe0DmeXx5g6k=
|
||||||
|
git.zhangdeman.cn/zhangdeman/dynamic-struct v0.0.0-20250319072714-eab2a7abde63/go.mod h1:10CdqBLr/d7vDQ7HlZoPdJWV9PF7zNM9QmhKt9Iz0/8=
|
||||||
|
git.zhangdeman.cn/zhangdeman/dynamic-struct v0.0.0-20250321154326-850866d6f568 h1:LKmmtWBhhw2ne8/mZ5qsgm9d4tX0ut2u1FFrM745N7g=
|
||||||
|
git.zhangdeman.cn/zhangdeman/dynamic-struct v0.0.0-20250321154326-850866d6f568/go.mod h1:S5KcY8KjsOFC/jPaUz4ndxcD8Prqwwsa7Thp9VHBD0Y=
|
||||||
git.zhangdeman.cn/zhangdeman/json_filter v0.0.0-20241205105007-b8c8c9d4338c h1:y8WLSdY8dBkKmazLt/XokW/LGz3hbdvNUdCUnsWXpRw=
|
git.zhangdeman.cn/zhangdeman/json_filter v0.0.0-20241205105007-b8c8c9d4338c h1:y8WLSdY8dBkKmazLt/XokW/LGz3hbdvNUdCUnsWXpRw=
|
||||||
git.zhangdeman.cn/zhangdeman/json_filter v0.0.0-20241205105007-b8c8c9d4338c/go.mod h1:GzCzTobrpI6J94Cluj9gjN/o5ZdNEyrXQcfGfj05ohs=
|
git.zhangdeman.cn/zhangdeman/json_filter v0.0.0-20241205105007-b8c8c9d4338c/go.mod h1:GzCzTobrpI6J94Cluj9gjN/o5ZdNEyrXQcfGfj05ohs=
|
||||||
|
git.zhangdeman.cn/zhangdeman/json_filter v0.0.0-20250321103029-786c03293a28 h1:wzEv9TXimkXuvjIgLuU+JETmWzj3AjfS3JA2cvU51xM=
|
||||||
|
git.zhangdeman.cn/zhangdeman/json_filter v0.0.0-20250321103029-786c03293a28/go.mod h1:RHYpM8BsZg9CuK78oY0+/n3g4kHMXk04+Gj1Sfg6E3U=
|
||||||
git.zhangdeman.cn/zhangdeman/op_type v0.0.0-20240122104027-4928421213c0 h1:gUDlQMuJ4xNfP2Abl1Msmpa3fASLWYkNlqDFF/6GN0Y=
|
git.zhangdeman.cn/zhangdeman/op_type v0.0.0-20240122104027-4928421213c0 h1:gUDlQMuJ4xNfP2Abl1Msmpa3fASLWYkNlqDFF/6GN0Y=
|
||||||
git.zhangdeman.cn/zhangdeman/op_type v0.0.0-20240122104027-4928421213c0/go.mod h1:VHb9qmhaPDAQDcS6vUiDCamYjZ4R5lD1XtVsh55KsMI=
|
git.zhangdeman.cn/zhangdeman/op_type v0.0.0-20240122104027-4928421213c0/go.mod h1:VHb9qmhaPDAQDcS6vUiDCamYjZ4R5lD1XtVsh55KsMI=
|
||||||
git.zhangdeman.cn/zhangdeman/serialize v0.0.0-20241223084948-de2e49144fcd h1:q7GG14qgXKB4MEXQFOe7/UYebsqMfPaSX80TcPdOosI=
|
git.zhangdeman.cn/zhangdeman/serialize v0.0.0-20241223084948-de2e49144fcd h1:q7GG14qgXKB4MEXQFOe7/UYebsqMfPaSX80TcPdOosI=
|
||||||
@ -10,10 +19,14 @@ git.zhangdeman.cn/zhangdeman/util v0.0.0-20240618042405-6ee2c904644e h1:Q973S6Cc
|
|||||||
git.zhangdeman.cn/zhangdeman/util v0.0.0-20240618042405-6ee2c904644e/go.mod h1:VpPjBlwz8U+OxZuxzHQBv1aEEZ3pStH6bZvT21ADEbI=
|
git.zhangdeman.cn/zhangdeman/util v0.0.0-20240618042405-6ee2c904644e/go.mod h1:VpPjBlwz8U+OxZuxzHQBv1aEEZ3pStH6bZvT21ADEbI=
|
||||||
git.zhangdeman.cn/zhangdeman/wrapper v0.0.0-20250302133417-c1588abcb436 h1:SM4zc54W2wmM72+4pMNQ8iS371H6lj4J8rj8KJKf7pw=
|
git.zhangdeman.cn/zhangdeman/wrapper v0.0.0-20250302133417-c1588abcb436 h1:SM4zc54W2wmM72+4pMNQ8iS371H6lj4J8rj8KJKf7pw=
|
||||||
git.zhangdeman.cn/zhangdeman/wrapper v0.0.0-20250302133417-c1588abcb436/go.mod h1:YJ1FlvFgkfAHkxkt3l5rKKUqEpQkNMbCFDzDmgteEU8=
|
git.zhangdeman.cn/zhangdeman/wrapper v0.0.0-20250302133417-c1588abcb436/go.mod h1:YJ1FlvFgkfAHkxkt3l5rKKUqEpQkNMbCFDzDmgteEU8=
|
||||||
|
git.zhangdeman.cn/zhangdeman/wrapper v0.0.0-20250321102712-1cbfbe959740 h1:zPUoylfJTbc0EcxW+NEzOTBmoeFZ2I/rLFBnEzxb4Wk=
|
||||||
|
git.zhangdeman.cn/zhangdeman/wrapper v0.0.0-20250321102712-1cbfbe959740/go.mod h1:1ct92dbVc49pmXusA/iGfcQUJzcYmJ+cjAhgc3sDv1I=
|
||||||
github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=
|
github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=
|
||||||
github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
|
github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
|
||||||
github.com/axgle/mahonia v0.0.0-20180208002826-3358181d7394 h1:OYA+5W64v3OgClL+IrOD63t4i/RW7RqrAVl9LTZ9UqQ=
|
github.com/axgle/mahonia v0.0.0-20180208002826-3358181d7394 h1:OYA+5W64v3OgClL+IrOD63t4i/RW7RqrAVl9LTZ9UqQ=
|
||||||
github.com/axgle/mahonia v0.0.0-20180208002826-3358181d7394/go.mod h1:Q8n74mJTIgjX4RBBcHnJ05h//6/k6foqmgE45jTQtxg=
|
github.com/axgle/mahonia v0.0.0-20180208002826-3358181d7394/go.mod h1:Q8n74mJTIgjX4RBBcHnJ05h//6/k6foqmgE45jTQtxg=
|
||||||
|
github.com/creasty/defaults v1.8.0 h1:z27FJxCAa0JKt3utc0sCImAEb+spPucmKoOdLHvHYKk=
|
||||||
|
github.com/creasty/defaults v1.8.0/go.mod h1:iGzKe6pbEHnpMPtfDXZEr0NVxWnPTjb1bbDy08fPzYM=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM=
|
github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM=
|
||||||
|
86
validate.go
86
validate.go
@ -15,7 +15,7 @@ import (
|
|||||||
dynamicStructGenerate "git.zhangdeman.cn/zhangdeman/dynamic-struct"
|
dynamicStructGenerate "git.zhangdeman.cn/zhangdeman/dynamic-struct"
|
||||||
"git.zhangdeman.cn/zhangdeman/json_filter/gjson_hack"
|
"git.zhangdeman.cn/zhangdeman/json_filter/gjson_hack"
|
||||||
"git.zhangdeman.cn/zhangdeman/serialize"
|
"git.zhangdeman.cn/zhangdeman/serialize"
|
||||||
"git.zhangdeman.cn/zhangdeman/wrapper"
|
"github.com/creasty/defaults"
|
||||||
"github.com/go-playground/validator/v10"
|
"github.com/go-playground/validator/v10"
|
||||||
"github.com/tidwall/gjson"
|
"github.com/tidwall/gjson"
|
||||||
"github.com/tidwall/sjson"
|
"github.com/tidwall/sjson"
|
||||||
@ -36,18 +36,36 @@ func init() {
|
|||||||
// Date : 15:12 2025/3/18
|
// Date : 15:12 2025/3/18
|
||||||
func Run(sourceData []byte, fieldList []StructField) ([]byte, error) {
|
func Run(sourceData []byte, fieldList []StructField) ([]byte, error) {
|
||||||
handleInstance := &handle{
|
handleInstance := &handle{
|
||||||
sourceData: sourceData,
|
sourceData: sourceData,
|
||||||
fieldList: fieldList,
|
fieldList: fieldList,
|
||||||
dynamicStruct: dynamicStructGenerate.NewStruct(),
|
parentFieldTable: map[string]bool{},
|
||||||
}
|
}
|
||||||
|
tagTable := map[string]string{}
|
||||||
|
for _, item := range fieldList {
|
||||||
|
tagTable[item.TargetPath] = handleInstance.generateTag(item)
|
||||||
|
// 检测当前字段是否是某一个字段的父级字段
|
||||||
|
for _, field := range fieldList {
|
||||||
|
if field.TargetPath == item.TargetPath {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// 当前字段以itemTarget开头
|
||||||
|
if strings.HasPrefix(field.TargetPath, item.TargetPath) {
|
||||||
|
// item.TargetPath是父级字段
|
||||||
|
handleInstance.parentFieldTable[item.TargetPath] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
handleInstance.dynamicStruct = dynamicStructGenerate.NewStruct(tagTable)
|
||||||
|
|
||||||
return handleInstance.Run()
|
return handleInstance.Run()
|
||||||
}
|
}
|
||||||
|
|
||||||
type handle struct {
|
type handle struct {
|
||||||
sourceData []byte
|
sourceData []byte
|
||||||
fieldList []StructField
|
fieldList []StructField
|
||||||
dynamicStruct dynamicStructGenerate.Builder
|
dynamicStruct dynamicStructGenerate.Builder
|
||||||
formatVal string
|
formatVal string
|
||||||
|
parentFieldTable map[string]bool // 父级字段路径表
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run 执行验证
|
// Run 执行验证
|
||||||
@ -58,6 +76,13 @@ func (h *handle) Run() ([]byte, error) {
|
|||||||
}
|
}
|
||||||
required, hasRequired := h.checkRequired(field)
|
required, hasRequired := h.checkRequired(field)
|
||||||
field.Required = required
|
field.Required = required
|
||||||
|
if h.parentFieldTable[field.TargetPath] {
|
||||||
|
// 中间层级字段, 无需额外处理, 验一下必传就行
|
||||||
|
if !gjson.GetBytes(h.sourceData, field.SourcePath).Exists() && field.Required {
|
||||||
|
return nil, errors.New(field.TargetPath + " : 数据源路径数据不存在 => " + field.SourcePath)
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
if field.Required && !hasRequired {
|
if field.Required && !hasRequired {
|
||||||
if nil == field.RuleList {
|
if nil == field.RuleList {
|
||||||
field.RuleList = make([]Rule, 0)
|
field.RuleList = make([]Rule, 0)
|
||||||
@ -67,23 +92,23 @@ func (h *handle) Run() ([]byte, error) {
|
|||||||
Args: nil,
|
Args: nil,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
sourceValue, err := h.getSourceDataValue(field)
|
// 格式化数据
|
||||||
if nil != err {
|
if _, err := h.formatDataValue(field); nil != err {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if nil == sourceValue {
|
// 支持嵌套结构体
|
||||||
// 没出现异常, 但是value为nil, 视作参数不存在处理
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
fieldName := wrapper.String(field.JsonTag).SnakeCaseToCamel()
|
|
||||||
// TODO : 支持嵌套结构体
|
|
||||||
fieldTag := h.generateTag(field)
|
fieldTag := h.generateTag(field)
|
||||||
h.dynamicStruct.AddField(fieldName, "", sourceValue, fieldTag, false)
|
// 这里需要设置为对应类型的零值就行, 此处传入值的目的只是为了确认数据类型
|
||||||
|
h.dynamicStruct.AddField(field.JsonTag, "", consts.GetDataTypeDefaultValue(field.Type), fieldTag, false)
|
||||||
}
|
}
|
||||||
val := h.dynamicStruct.Build().New()
|
val := h.dynamicStruct.Build().New()
|
||||||
if err := serialize.JSON.UnmarshalWithNumber([]byte(h.formatVal), &val); nil != err {
|
if err := serialize.JSON.UnmarshalWithNumber([]byte(h.formatVal), &val); nil != err {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
if err := defaults.Set(val); nil != err {
|
||||||
|
// 默认值设置失败
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
if err := validatorInstance.Struct(val); nil != err {
|
if err := validatorInstance.Struct(val); nil != err {
|
||||||
return nil, GetValidateErr(val, err, TagErrMsg)
|
return nil, GetValidateErr(val, err, TagErrMsg)
|
||||||
}
|
}
|
||||||
@ -106,15 +131,18 @@ func (h *handle) checkRequired(field StructField) (bool, bool) {
|
|||||||
if isHasRequiredRule {
|
if isHasRequiredRule {
|
||||||
required = true
|
required = true
|
||||||
}
|
}
|
||||||
if required && !isHasRequiredRule {
|
if required {
|
||||||
// 必传, 但是没有必传校验规则
|
if !isHasRequiredRule {
|
||||||
return true, true
|
// 必传, 但是没有必传校验规则
|
||||||
|
return true, true
|
||||||
|
}
|
||||||
|
return true, false
|
||||||
}
|
}
|
||||||
return true, false
|
return false, isHasRequiredRule
|
||||||
}
|
}
|
||||||
|
|
||||||
// getSourceDataValue 获取源数据值
|
// getSourceDataValue 获取源数据值
|
||||||
func (h *handle) getSourceDataValue(field StructField) (any, error) {
|
func (h *handle) formatDataValue(field StructField) (any, error) {
|
||||||
sourceValue := gjson.GetBytes(h.sourceData, field.SourcePath)
|
sourceValue := gjson.GetBytes(h.sourceData, field.SourcePath)
|
||||||
if !sourceValue.Exists() {
|
if !sourceValue.Exists() {
|
||||||
if field.Required {
|
if field.Required {
|
||||||
@ -146,6 +174,7 @@ func (h *handle) getSourceDataValue(field StructField) (any, error) {
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
switch field.Type {
|
switch field.Type {
|
||||||
|
|
||||||
case consts.DataTypeInt: // Int类型
|
case consts.DataTypeInt: // Int类型
|
||||||
fallthrough
|
fallthrough
|
||||||
case consts.DataTypeIntPtr: // Uint类型
|
case consts.DataTypeIntPtr: // Uint类型
|
||||||
@ -156,15 +185,17 @@ func (h *handle) getSourceDataValue(field StructField) (any, error) {
|
|||||||
case consts.DataTypeUintPtr: // Uint类型
|
case consts.DataTypeUintPtr: // Uint类型
|
||||||
val, err = gjson_hack.Uint(sourceValue)
|
val, err = gjson_hack.Uint(sourceValue)
|
||||||
return val, err
|
return val, err
|
||||||
case consts.DataTypeFloat:
|
case consts.DataTypeFloat32:
|
||||||
fallthrough
|
fallthrough
|
||||||
case consts.DataTypeFloatPtr: // Float类型
|
case consts.DataTypeFloat32Ptr: // Float类型
|
||||||
val, err = gjson_hack.Float64(sourceValue)
|
val, err = gjson_hack.Float64(sourceValue)
|
||||||
return val, err
|
return val, err
|
||||||
case consts.DataTypeString: // String类型
|
case consts.DataTypeString: // String类型
|
||||||
return sourceValue.String(), nil
|
val = sourceValue.String()
|
||||||
|
return val, nil
|
||||||
case consts.DataTypeBool: // Bool类型
|
case consts.DataTypeBool: // Bool类型
|
||||||
return sourceValue.Bool(), nil
|
val = sourceValue.Bool()
|
||||||
|
return val, nil
|
||||||
case consts.DataTypeSliceFloat: // Float slice
|
case consts.DataTypeSliceFloat: // Float slice
|
||||||
val, err = gjson_hack.SliceFloat(sourceValue)
|
val, err = gjson_hack.SliceFloat(sourceValue)
|
||||||
return val, err
|
return val, err
|
||||||
@ -208,6 +239,9 @@ func (h *handle) generateTag(field StructField) string {
|
|||||||
// 验证规则tag
|
// 验证规则tag
|
||||||
tagList = append(tagList, fmt.Sprintf(`%s:"%s"`, TagValidate, strings.Join(validateRuleList, ",")))
|
tagList = append(tagList, fmt.Sprintf(`%s:"%s"`, TagValidate, strings.Join(validateRuleList, ",")))
|
||||||
// 默认值
|
// 默认值
|
||||||
|
if field.DefaultValue == "-" && (field.Type == consts.DataTypeString || field.Type == consts.DataTypeStringPtr) {
|
||||||
|
field.DefaultValue = ""
|
||||||
|
}
|
||||||
tagList = append(tagList, fmt.Sprintf(`%s:"%s"`, TagDefaultValue, field.DefaultValue))
|
tagList = append(tagList, fmt.Sprintf(`%s:"%s"`, TagDefaultValue, field.DefaultValue))
|
||||||
return strings.Join(tagList, " ")
|
return strings.Join(tagList, " ")
|
||||||
}
|
}
|
||||||
|
@ -16,11 +16,20 @@ import (
|
|||||||
|
|
||||||
// TestRun_Simple_Data 无嵌套、无复杂数据类型的处理
|
// TestRun_Simple_Data 无嵌套、无复杂数据类型的处理
|
||||||
func TestRun_Simple_Data(t *testing.T) {
|
func TestRun_Simple_Data(t *testing.T) {
|
||||||
testMap := map[string]any{
|
userInfo := map[string]any{
|
||||||
"age": 18,
|
"age": 1800,
|
||||||
"height": 179.5,
|
"height": 179.5,
|
||||||
"name": "baicha",
|
"name": "baicha",
|
||||||
}
|
}
|
||||||
|
companyInfo := map[string]any{
|
||||||
|
"address": "beijing",
|
||||||
|
"name": "xxxx",
|
||||||
|
}
|
||||||
|
|
||||||
|
testMap := map[string]any{
|
||||||
|
"user": userInfo,
|
||||||
|
"company": companyInfo,
|
||||||
|
}
|
||||||
sourceByteData, _ := json.Marshal(testMap)
|
sourceByteData, _ := json.Marshal(testMap)
|
||||||
fieldList := []StructField{
|
fieldList := []StructField{
|
||||||
{
|
{
|
||||||
@ -34,15 +43,43 @@ func TestRun_Simple_Data(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
Tag: "max",
|
Tag: "max",
|
||||||
Args: []string{"20"},
|
Args: []string{"2000"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
DefaultValue: "",
|
DefaultValue: "",
|
||||||
SourcePath: "age",
|
SourcePath: "user.age",
|
||||||
TargetPath: "user_age",
|
TargetPath: "user_age",
|
||||||
Errmsg: "年龄必须在[1,20]之间",
|
Errmsg: "年龄必须在[1,2000]之间",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
JsonTag: "company",
|
||||||
|
Type: consts.DataTypeString,
|
||||||
|
Required: false,
|
||||||
|
RuleList: []Rule{
|
||||||
|
{
|
||||||
|
Tag: "required",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
DefaultValue: "",
|
||||||
|
SourcePath: "company",
|
||||||
|
TargetPath: "company",
|
||||||
|
Errmsg: "公司信息必传",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
JsonTag: "company_name",
|
||||||
|
Type: consts.DataTypeString,
|
||||||
|
Required: false,
|
||||||
|
RuleList: []Rule{
|
||||||
|
{
|
||||||
|
Tag: "required",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
DefaultValue: "",
|
||||||
|
SourcePath: "company.name",
|
||||||
|
TargetPath: "company.company_name",
|
||||||
|
Errmsg: "公司名称必须在[1,20]之间",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
_, err := Run(sourceByteData, fieldList)
|
res, err := Run(sourceByteData, fieldList)
|
||||||
fmt.Println(err)
|
fmt.Println(err, string(res))
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user