improve error handling for custom validation rule for package gvalid

This commit is contained in:
John Guo 2021-11-14 17:47:21 +08:00
parent 1a7450b9e9
commit ce16dad88f
5 changed files with 41 additions and 11 deletions

View File

@ -97,7 +97,7 @@ func (set *Set) AddIfNotExist(item interface{}) bool {
}
// AddIfNotExistFunc checks whether item exists in the set,
// it adds the item to set and returns true if it does not exists in the set and
// it adds the item to set and returns true if it does not exist in the set and
// function `f` returns true, or else it does nothing and returns false.
//
// Note that, if `item` is nil, it does nothing and returns false. The function `f`

View File

@ -21,7 +21,7 @@ import (
type Error struct {
error error // Wrapped error.
stack stack // Stack array, which records the stack information when this error is created or wrapped.
text string // Error text, which is created by New* functions.
text string // Custom Error text when Error is created, might be empty when its code is not nil.
code gcode.Code // Error code if necessary.
}
@ -31,8 +31,7 @@ const (
)
var (
// goRootForFilter is used for stack filtering purpose.
// Mainly for development environment.
// goRootForFilter is used for stack filtering in development environment purpose.
goRootForFilter = runtime.GOROOT()
)
@ -107,18 +106,18 @@ func (err *Error) Format(s fmt.State, verb rune) {
switch {
case s.Flag('-'):
if err.text != "" {
io.WriteString(s, err.text)
_, _ = io.WriteString(s, err.text)
} else {
io.WriteString(s, err.Error())
_, _ = io.WriteString(s, err.Error())
}
case s.Flag('+'):
if verb == 's' {
io.WriteString(s, err.Stack())
_, _ = io.WriteString(s, err.Stack())
} else {
io.WriteString(s, err.Error()+"\n"+err.Stack())
_, _ = io.WriteString(s, err.Error()+"\n"+err.Stack())
}
default:
io.WriteString(s, err.Error())
_, _ = io.WriteString(s, err.Error())
}
}
}
@ -176,6 +175,14 @@ func (err *Error) Next() error {
return err.error
}
// SetCode updates the internal code with given code.
func (err *Error) SetCode(code gcode.Code) {
if err == nil {
return
}
err.code = code
}
// MarshalJSON implements the interface MarshalJSON for json.Marshal.
// Note that do not use pointer as its receiver here.
func (err *Error) MarshalJSON() ([]byte, error) {

View File

@ -311,6 +311,18 @@ func Test_Code(t *testing.T) {
})
}
func Test_SetCode(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
err := gerror.New("123")
t.Assert(gerror.Code(err), -1)
t.Assert(err.Error(), "123")
err.(*gerror.Error).SetCode(gcode.CodeValidationFailed)
t.Assert(gerror.Code(err), gcode.CodeValidationFailed)
t.Assert(err.Error(), "123")
})
}
func Test_Json(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
err := gerror.Wrap(gerror.New("1"), "2")

View File

@ -11,6 +11,7 @@ import (
"errors"
"github.com/gogf/gf/v2/container/gvar"
"github.com/gogf/gf/v2/errors/gcode"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/text/gstr"
"strconv"
"strings"
@ -134,13 +135,23 @@ func (v *Validator) doCheckValue(ctx context.Context, input doCheckValueInput) E
if customRuleFunc != nil {
// It checks custom validation rules with most priority.
message := v.getErrorMessageByRule(ctx, ruleKey, customMsgMap)
if err := customRuleFunc(ctx, RuleFuncInput{
if err = customRuleFunc(ctx, RuleFuncInput{
Rule: ruleItems[index],
Message: message,
Value: gvar.New(input.Value),
Data: gvar.New(input.DataRaw),
}); err != nil {
match = false
// The error should have stack info to indicate the error position.
if !gerror.HasStack(err) {
err = gerror.NewCodeSkip(gcode.CodeValidationFailed, 1, err.Error())
}
// The error should have error code that is `gcode.CodeValidationFailed`.
if gerror.Code(err) == gcode.CodeNil {
if e, ok := err.(*gerror.Error); ok {
e.SetCode(gcode.CodeValidationFailed)
}
}
ruleErrorMap[ruleKey] = err
} else {
match = true

View File

@ -10,7 +10,7 @@ import "context"
// getErrorMessageByRule retrieves and returns the error message for specified rule.
// It firstly retrieves the message from custom message map, and then checks i18n manager,
// it returns the default error message if it's not found in custom message map or i18n manager.
// it returns the default error message if it's not found in neither custom message map nor i18n manager.
func (v *Validator) getErrorMessageByRule(ctx context.Context, ruleKey string, customMsgMap map[string]string) string {
content := customMsgMap[ruleKey]
if content != "" {