validator/run.go

260 lines
6.9 KiB
Go
Raw Normal View History

2024-04-29 12:17:18 +08:00
// Package validator ...
//
// Description : validator ...
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 2024-04-29 10:51
package validator
2024-04-29 17:29:46 +08:00
import (
"bytes"
"encoding/json"
"fmt"
"git.zhangdeman.cn/gateway/validator/define"
"git.zhangdeman.cn/zhangdeman/consts"
"github.com/tidwall/gjson"
"github.com/tidwall/sjson"
"strings"
)
2024-04-29 12:17:18 +08:00
2024-04-29 17:29:46 +08:00
// RunForStruct 验证结构体
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 14:18 2024/4/29
func RunForStruct(sourceData any, ruleList []*define.FieldRule) (map[string]any, error) {
2024-04-29 17:29:46 +08:00
if nil == sourceData {
return map[string]any{}, nil
2024-04-29 17:29:46 +08:00
}
byteData, _ := json.Marshal(sourceData)
var (
sourceMapData map[string]any
2024-04-29 17:29:46 +08:00
err error
)
d := json.NewDecoder(bytes.NewReader(byteData))
d.UseNumber()
if err = d.Decode(&sourceMapData); nil != err {
return nil, err
}
if err = Run(sourceMapData, ruleList); nil != err {
return nil, err
}
return sourceMapData, nil
}
// Run 运行参数验证
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 14:13 2024/4/29
func Run(sourceData map[string]any, ruleList []*define.FieldRule) error {
2024-04-29 17:29:46 +08:00
if nil == sourceData || len(sourceData) == 0 {
return nil
}
byteData, _ := json.Marshal(sourceData)
for _, itemRule := range ruleList {
if len(itemRule.Path) == 0 {
// 未指定验证数据位置
continue
}
2024-05-16 21:12:17 +08:00
// 通过有条件必传, 填充 is_required
checkRuleConditionRequiredRule(byteData, itemRule)
2024-04-29 17:29:46 +08:00
inputFieldVal := gjson.GetBytes(byteData, itemRule.Path)
if formatRule, err := validate(byteData, inputFieldVal, itemRule); nil != err {
return err
} else {
if !itemRule.DisableRewrite {
// 更新数据
byteData, _ = sjson.SetBytes(byteData, itemRule.Path, formatRule)
}
}
}
sourceData = make(map[string]any)
2024-04-29 17:29:46 +08:00
d := json.NewDecoder(bytes.NewReader(byteData))
d.UseNumber()
if err := d.Decode(&sourceData); nil != err {
return err
}
return nil
}
2024-05-16 21:12:17 +08:00
// checkRuleConditionRequiredRule 校验有条件必传
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 21:10 2024/5/16
func checkRuleConditionRequiredRule(sourceData []byte, rule *define.FieldRule) {
if rule.IsRequired {
// 本身已经必传, 无所谓有条件无条件
return
}
// 验证有条件必传
if len(rule.RequiredConditionGroup) > 0 {
for _, itemRuleGroup := range rule.RequiredConditionGroup {
isRequired := true
for _, itemFieldRule := range itemRuleGroup {
dependFieldStatus := getDataStatus(gjson.GetBytes(sourceData, itemFieldRule.DependOnField), itemFieldRule.DependOnFieldType)
isRequired = isRequired && inArray(itemFieldRule.DependOnFieldStatus, dependFieldStatus)
}
if isRequired {
rule.IsRequired = true // 非必传参数, 命中有条件必传
break
}
}
}
}
2024-04-29 17:29:46 +08:00
// getDataStatus 获取数据状态
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 15:59 2024/4/29
func getDataStatus(val gjson.Result, dataType string) string {
if !val.Exists() {
return consts.DataStatusNotFound
}
switch dataType {
case consts.DataTypeString:
if len(val.String()) == 0 {
return consts.DataStatusIsEmpty
}
case consts.DataTypeFloat:
fallthrough
case consts.DataTypeInt:
if val.Float() == 0 {
return consts.DataStatusIsZero
}
default:
if strings.HasPrefix(dataType, "[]") {
// 数组
if len(val.Array()) == 0 {
return consts.DataStatusIsEmpty
}
} else if strings.HasPrefix(dataType, "map") {
// 对象
if len(val.Map()) == 0 {
return consts.DataStatusIsEmpty
}
}
}
return ""
}
2024-05-02 18:36:19 +08:00
// formatInputVal ...
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 18:02 2024/5/2
func formatInputVal(val gjson.Result, rule *define.FieldRule) (any, error) {
inputVal := val.Value()
if nil == inputVal {
if rule.IsRequired {
return nil, fmt.Errorf("%v : data is required, but get nil", rule.Path)
}
if rule.DisableAutoConvert {
inputVal = rule.DefaultValue
} else {
inputVal = strings.TrimSpace(rule.DefaultValue)
}
} else {
2024-05-16 20:46:53 +08:00
if inputValStr, ok := inputVal.(string); ok {
2024-05-17 14:08:52 +08:00
if !rule.DisableAutoTrimSpace {
2024-05-16 20:46:53 +08:00
// 自动去空格
inputVal = strings.TrimSpace(inputValStr)
} else {
2024-05-02 18:36:19 +08:00
inputVal = inputValStr
}
}
}
return inputVal, nil
}
2024-05-16 21:12:17 +08:00
// inArray ...
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 21:00 2024/5/16
func inArray(enumList []string, val string) bool {
for _, item := range enumList {
if strings.ToUpper(val) == strings.ToUpper(item) {
return true
}
}
return false
}
2024-04-29 17:29:46 +08:00
// validate 验证字段
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 14:32 2024/4/29
func validate(sourceData []byte, val gjson.Result, rule *define.FieldRule) (any, error) {
2024-05-02 18:36:19 +08:00
var (
err error
inputVal any
)
2024-05-16 21:12:17 +08:00
2024-04-29 17:29:46 +08:00
if !val.Exists() {
if rule.IsRequired {
return nil, fmt.Errorf("%v : field is required, but not found", rule.Path)
}
inputVal = rule.DefaultValue
} else {
2024-05-02 18:36:19 +08:00
if inputVal, err = formatInputVal(val, rule); nil != err {
return nil, err
2024-04-29 17:29:46 +08:00
}
}
return handleData(inputVal, rule)
}
// handleData 处理数据
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 14:43 2024/4/29
func handleData(inputVal any, rule *define.FieldRule) (any, error) {
2024-04-29 17:29:46 +08:00
switch rule.Type {
case consts.DataTypeAny: // 任意类型
return inputVal, nil
case consts.DataTypeFloat: // float数据
return handleFloat(inputVal, rule)
case consts.DataTypeInt: // int类型
return handleInt(inputVal, rule)
2024-04-30 22:22:28 +08:00
case consts.DataTypeUint:
return handleUint(inputVal, rule)
2024-04-29 17:29:46 +08:00
case consts.DataTypeString: // 字符串处理
return handleString(inputVal, rule)
2024-04-30 22:22:28 +08:00
case consts.DataTypeBool:
return handleBool(inputVal, rule)
2024-04-29 17:29:46 +08:00
case consts.DataTypeMapStrFloat, consts.DataTypeMapStrBool,
consts.DataTypeMapStrInt, consts.DataTypeMapStrUint:
// 一律按照 map[string]float64处理
return handleMapStringFloat(inputVal, rule)
case consts.DataTypeMapStrAny: // 对象结构
return handleMapStringAny(inputVal, rule)
2024-05-17 14:08:52 +08:00
case consts.DataTypeMapStrStr: // 对象结构
return handleMapStringString(inputVal, rule)
2024-04-29 17:29:46 +08:00
case consts.DataTypeMapStrSlice: // map列表
return handleMapStringSlice(inputVal, rule)
2024-04-29 17:29:46 +08:00
case consts.DataTypeMapAnyAny: // 任意类型map
return handleMapAnyAny(inputVal, rule)
2024-05-01 21:44:59 +08:00
case consts.DataTypeSliceInt, consts.DataTypeSliceIntWithChar: // int数组处理
return handleSliceInt(inputVal, rule)
2024-04-30 22:22:28 +08:00
case consts.DataTypeSliceUint, consts.DataTypeSliceUintWithChar: // uint数组处理
2024-05-01 21:44:59 +08:00
return handleSliceUint(inputVal, rule)
case consts.DataTypeSliceFloat, consts.DataTypeSliceFloatWithChar: // float数组处理
return handleSliceFloat(inputVal, rule)
case consts.DataTypeSliceBool, consts.DataTypeSliceBoolWithChar: // bool数组
return handleSliceBool(inputVal, rule)
2024-05-01 22:28:01 +08:00
case consts.DataTypeSliceSlice:
return handleSliceSlice(inputVal, rule)
2024-05-01 21:44:59 +08:00
case consts.DataTypeSliceMapAnyAny: // map 列表
return handleSliceMapAny(inputVal, rule)
case consts.DataTypeSliceMapStringAny:
return handleSliceMapString(inputVal, rule)
}
return nil, fmt.Errorf("%v : data type [%v] is not support", rule.Path, rule.Type)
2024-04-29 17:29:46 +08:00
}