You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
246 lines
4.5 KiB
246 lines
4.5 KiB
package v
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
)
|
|
|
|
var emptyErrors []*Error
|
|
|
|
func init() {
|
|
emptyErrors = make([]*Error, 0)
|
|
}
|
|
|
|
// Error 验证错误结构体
|
|
type Error struct {
|
|
error error
|
|
code string
|
|
format string
|
|
params map[string]any
|
|
field string
|
|
label string
|
|
value any
|
|
}
|
|
|
|
// ErrorOption 错误配置函数签名
|
|
type ErrorOption func(*Error)
|
|
|
|
func merge(options []ErrorOption, presets ...ErrorOption) []ErrorOption {
|
|
return append(presets, options...)
|
|
}
|
|
|
|
// NewError 创建错误实例
|
|
func NewError(code string, options ...ErrorOption) *Error {
|
|
e := Error{code: code}
|
|
for _, option := range options {
|
|
option(&e)
|
|
}
|
|
return &e
|
|
}
|
|
|
|
// ErrorFormat 设置错误格式化字符串
|
|
func ErrorFormat(format string) ErrorOption {
|
|
return func(e *Error) {
|
|
e.format = format
|
|
}
|
|
}
|
|
|
|
// ErrorParam 设置验证参数
|
|
func ErrorParam(key string, value any) ErrorOption {
|
|
return func(e *Error) {
|
|
if e.params == nil {
|
|
e.params = make(map[string]any)
|
|
}
|
|
e.params[key] = value
|
|
}
|
|
}
|
|
|
|
// ErrorCode 设置错误代码
|
|
func ErrorCode(code string) ErrorOption {
|
|
return func(e *Error) {
|
|
e.code = code
|
|
}
|
|
}
|
|
|
|
// Code 返回错误代码
|
|
func (e *Error) Code() string {
|
|
return e.code
|
|
}
|
|
|
|
// Format 返回错误格式化模板
|
|
func (e *Error) Format() string {
|
|
return e.format
|
|
}
|
|
|
|
// Params 返回错误格式化蚕食
|
|
func (e *Error) Params() map[string]any {
|
|
p := map[string]any{}
|
|
if e.params != nil {
|
|
for k, v := range e.params {
|
|
p[k] = v
|
|
}
|
|
}
|
|
return p
|
|
}
|
|
|
|
// Field 返回字段名
|
|
func (e *Error) Field() string {
|
|
return e.field
|
|
}
|
|
|
|
// Label 返回错误标签
|
|
func (e *Error) Label() string {
|
|
return e.label
|
|
}
|
|
|
|
// Value 返回用于验证的值
|
|
func (e *Error) Value() any {
|
|
return e.value
|
|
}
|
|
|
|
// String 实现 fmt.Stringer 接口,返回格式化后的字符串
|
|
func (e *Error) String() string {
|
|
message := e.format
|
|
params := e.Params()
|
|
params["label"] = e.label
|
|
params["value"] = e.value
|
|
//params["field"] = e.field
|
|
// 定义了消息或翻译函数
|
|
if t, found := translations[e.code]; found {
|
|
if message == "" {
|
|
message = t.message
|
|
}
|
|
if t.trans != nil {
|
|
return t.trans(message, params)
|
|
}
|
|
}
|
|
// 设置了默认翻译函数
|
|
if defaultTranslator != nil {
|
|
return defaultTranslator(message, params)
|
|
}
|
|
for key, value := range params {
|
|
message = strings.ReplaceAll(message, "{"+key+"}", fmt.Sprintf("%v", value))
|
|
}
|
|
return message
|
|
}
|
|
|
|
// Error 实现内置错误接口(优先使用内部错误)
|
|
func (e *Error) Error() string {
|
|
if e.error != nil {
|
|
return e.error.Error()
|
|
}
|
|
return e.String()
|
|
}
|
|
|
|
// Errors 错误集
|
|
type Errors struct {
|
|
errors []*Error
|
|
}
|
|
|
|
// IsEmpty 是否存在错误
|
|
func (e *Errors) IsEmpty() bool {
|
|
if e == nil || e.errors == nil {
|
|
return true
|
|
}
|
|
return len(e.errors) == 0
|
|
}
|
|
|
|
// Add 添加一个错误
|
|
func (e *Errors) Add(err error) {
|
|
if err == nil {
|
|
return
|
|
}
|
|
if e.errors == nil {
|
|
e.errors = make([]*Error, 0)
|
|
}
|
|
if ex, ok := err.(*Errors); ok {
|
|
if !ex.IsEmpty() {
|
|
e.errors = append(e.errors, ex.errors...)
|
|
}
|
|
} else if ex, ok := err.(*Error); ok && ex != nil {
|
|
e.errors = append(e.errors, ex)
|
|
} else {
|
|
e.errors = append(e.errors, &Error{error: err})
|
|
}
|
|
}
|
|
|
|
// First 返回第一个错误实例,如果不存在则返回 nil
|
|
func (e *Errors) First() *Error {
|
|
if e.IsEmpty() {
|
|
return nil
|
|
}
|
|
return e.errors[0]
|
|
}
|
|
|
|
// Get 获取指定标签的错误列表,如果不存在将返回 nil
|
|
func (e *Errors) Get(field string) []*Error {
|
|
if e.IsEmpty() {
|
|
return nil
|
|
}
|
|
errs := make([]*Error, 0)
|
|
for _, err := range e.errors {
|
|
if err.field == field {
|
|
errs = append(errs, err)
|
|
}
|
|
}
|
|
if len(errs) > 0 {
|
|
return errs
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (e *Errors) All() []*Error {
|
|
if e == nil {
|
|
return emptyErrors
|
|
}
|
|
return e.errors
|
|
}
|
|
|
|
// ToMap 根据错误标签分组
|
|
func (e *Errors) ToMap() map[string][]*Error {
|
|
if e == nil || e.IsEmpty() {
|
|
return nil
|
|
}
|
|
errs := map[string][]*Error{}
|
|
for _, err := range e.errors {
|
|
if _, ok := errs[err.field]; !ok {
|
|
errs[err.field] = []*Error{}
|
|
}
|
|
errs[err.field] = append(errs[err.field], err)
|
|
}
|
|
return errs
|
|
}
|
|
|
|
func (e *Errors) String() string {
|
|
errsMap := e.ToMap()
|
|
if errsMap == nil {
|
|
return ""
|
|
}
|
|
|
|
var errors []string
|
|
for _, errs := range errsMap {
|
|
buf := strings.Builder{}
|
|
for i, err := range errs {
|
|
if i > 0 {
|
|
buf.WriteString("\n")
|
|
}
|
|
buf.WriteString(err.String())
|
|
}
|
|
errors = append(errors, buf.String())
|
|
}
|
|
return strings.Join(errors, "\n")
|
|
}
|
|
|
|
func (e *Errors) Error() string {
|
|
return e.String()
|
|
}
|
|
|
|
func isBuiltinError(err error) bool {
|
|
if _, ok := err.(*Error); ok {
|
|
return true
|
|
}
|
|
if _, ok := err.(*Errors); ok {
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|