1 Star 1 Fork 0

Cinus/go-tagexpr

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
validator.go 3.67 KB
一键复制 编辑 原始数据 按行查看 历史
// Package validator is a powerful validator that supports struct tag expression.
//
// Copyright 2019 Bytedance Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package validator
import (
"errors"
"io"
"reflect"
"strings"
_ "unsafe"
tagexpr "github.com/bytedance/go-tagexpr"
)
const (
// MatchExprName the name of the expression used for validation
MatchExprName = tagexpr.DefaultExprName
// ErrMsgExprName the name of the expression used to specify the message
// returned when validation failed
ErrMsgExprName = "msg"
)
// Validator struct fields validator
type Validator struct {
vm *tagexpr.VM
errFactory func(failPath, msg string) error
}
// New creates a struct fields validator.
func New(tagName string) *Validator {
v := &Validator{
vm: tagexpr.New(tagName),
errFactory: defaultErrorFactory,
}
return v
}
// VM returns the struct tag expression interpreter.
func (v *Validator) VM() *tagexpr.VM {
return v.vm
}
// Validate validates whether the fields of value is valid.
// NOTE:
// If checkAll=true, validate all the error.
func (v *Validator) Validate(value interface{}, checkAll ...bool) error {
var all bool
if len(checkAll) > 0 {
all = checkAll[0]
}
var errs = make([]error, 0, 8)
v.vm.RunAny(value, func(te *tagexpr.TagExpr, err error) error {
if err != nil {
errs = append(errs, err)
if all {
return nil
}
return io.EOF
}
nilParentFields := make(map[string]bool, 16)
err = te.Range(func(eh *tagexpr.ExprHandler) error {
if strings.Contains(eh.StringSelector(), tagexpr.ExprNameSeparator) {
return nil
}
if eh.EvalBool() {
return nil
}
// Ignore this error if the value of the parent is nil
if pfs, ok := eh.ExprSelector().ParentField(); ok {
if nilParentFields[pfs] {
return nil
}
if fh, ok := eh.TagExpr().Field(pfs); ok {
v := fh.Value(false)
if !v.IsValid() || (v.Kind() == reflect.Ptr && v.IsNil()) {
nilParentFields[pfs] = true
return nil
}
}
}
errs = append(errs, v.errFactory(
eh.Path(),
eh.TagExpr().EvalString(eh.StringSelector()+tagexpr.ExprNameSeparator+ErrMsgExprName),
))
if all {
return nil
}
return io.EOF
})
if err != nil && !all {
return err
}
return nil
})
switch len(errs) {
case 0:
return nil
case 1:
return errs[0]
default:
var errStr string
for _, e := range errs {
errStr += e.Error() + "\t"
}
return errors.New(errStr[:len(errStr)-1])
}
}
// SetErrorFactory customizes the factory of validation error.
// NOTE:
// If errFactory==nil, the default is used
func (v *Validator) SetErrorFactory(errFactory func(failPath, msg string) error) *Validator {
if errFactory == nil {
errFactory = defaultErrorFactory
}
v.errFactory = errFactory
return v
}
// Error validate error
type Error struct {
FailPath, Msg string
}
// Error implements error interface.
func (e *Error) Error() string {
if e.Msg != "" {
return e.Msg
}
return "invalid parameter: " + e.FailPath
}
//go:linkname defaultErrorFactory validator.defaultErrorFactory
//go:nosplit
func defaultErrorFactory(failPath, msg string) error {
return &Error{
FailPath: failPath,
Msg: msg,
}
}
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
Go
1
https://gitee.com/cinus/go-tagexpr.git
git@gitee.com:cinus/go-tagexpr.git
cinus
go-tagexpr
go-tagexpr
v2.5.2

搜索帮助