mirror of
https://gitee.com/johng/gf.git
synced 2024-11-30 03:07:45 +08:00
Merge branch 'zhiwei' of https://github.com/564104865/gf into zhiwei
This commit is contained in:
commit
be274478d0
@ -9,10 +9,8 @@ package gdb
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
"time"
|
||||
|
||||
"github.com/gogf/gf/v2/text/gregex"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
)
|
||||
@ -45,8 +43,7 @@ type Model struct {
|
||||
distinct string // Force the query to only return distinct results.
|
||||
lockInfo string // Lock for update or in shared lock.
|
||||
cacheEnabled bool // Enable sql result cache feature.
|
||||
cacheDuration time.Duration // Cache TTL duration (< 1 for removing cache, >= 0 for saving cache).
|
||||
cacheName string // Cache name for custom operation.
|
||||
cacheOption CacheOption // Cache option for query statement.
|
||||
unscoped bool // Disables soft deleting features when select/delete operations.
|
||||
safe bool // If true, it clones and returns a new model object whenever operation done; or else it changes the attribute of current model.
|
||||
onDuplicate interface{} // onDuplicate is used for ON "DUPLICATE KEY UPDATE" statement.
|
||||
|
@ -11,26 +11,32 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
type CacheOption struct {
|
||||
// Duration is the TTL for the cache.
|
||||
// If the parameter `Duration` < 0, which means it clear the cache with given `Name`.
|
||||
// If the parameter `Duration` = 0, which means it never expires.
|
||||
// If the parameter `Duration` > 0, which means it expires after `Duration`.
|
||||
Duration time.Duration
|
||||
|
||||
// Name is an optional unique name for the cache.
|
||||
// The Name is used to bind a name to the cache, which means you can later control the cache
|
||||
// like changing the `duration` or clearing the cache with specified Name.
|
||||
Name string
|
||||
|
||||
// Force caches the query result whatever the result is nil or not.
|
||||
// It is used to avoid Cache Penetration.
|
||||
Force bool
|
||||
}
|
||||
|
||||
// Cache sets the cache feature for the model. It caches the result of the sql, which means
|
||||
// if there's another same sql request, it just reads and returns the result from cache, it
|
||||
// but not committed and executed into the database.
|
||||
//
|
||||
// If the parameter `duration` < 0, which means it clear the cache with given `name`.
|
||||
// If the parameter `duration` = 0, which means it never expires.
|
||||
// If the parameter `duration` > 0, which means it expires after `duration`.
|
||||
//
|
||||
// The optional parameter `name` is used to bind a name to the cache, which means you can
|
||||
// later control the cache like changing the `duration` or clearing the cache with specified
|
||||
// `name`.
|
||||
//
|
||||
// Note that, the cache feature is disabled if the model is performing select statement
|
||||
// on a transaction.
|
||||
func (m *Model) Cache(duration time.Duration, name ...string) *Model {
|
||||
func (m *Model) Cache(option CacheOption) *Model {
|
||||
model := m.getModel()
|
||||
model.cacheDuration = duration
|
||||
if len(name) > 0 {
|
||||
model.cacheName = name[0]
|
||||
}
|
||||
model.cacheOption = option
|
||||
model.cacheEnabled = true
|
||||
return model
|
||||
}
|
||||
@ -38,9 +44,9 @@ func (m *Model) Cache(duration time.Duration, name ...string) *Model {
|
||||
// checkAndRemoveCache checks and removes the cache in insert/update/delete statement if
|
||||
// cache feature is enabled.
|
||||
func (m *Model) checkAndRemoveCache() {
|
||||
if m.cacheEnabled && m.cacheDuration < 0 && len(m.cacheName) > 0 {
|
||||
if m.cacheEnabled && m.cacheOption.Duration < 0 && len(m.cacheOption.Name) > 0 {
|
||||
var ctx = m.GetCtx()
|
||||
_, err := m.db.GetCache().Remove(ctx, m.cacheName)
|
||||
_, err := m.db.GetCache().Remove(ctx, m.cacheOption.Name)
|
||||
if err != nil {
|
||||
intlog.Error(ctx, err)
|
||||
}
|
||||
|
@ -437,7 +437,7 @@ func (m *Model) doGetAllBySql(sql string, args ...interface{}) (result Result, e
|
||||
)
|
||||
// Retrieve from cache.
|
||||
if m.cacheEnabled && m.tx == nil {
|
||||
cacheKey = m.cacheName
|
||||
cacheKey = m.cacheOption.Name
|
||||
if len(cacheKey) == 0 {
|
||||
cacheKey = sql + ", @PARAMS:" + gconv.String(args)
|
||||
}
|
||||
@ -461,16 +461,16 @@ func (m *Model) doGetAllBySql(sql string, args ...interface{}) (result Result, e
|
||||
)
|
||||
// Cache the result.
|
||||
if cacheKey != "" && err == nil {
|
||||
if m.cacheDuration < 0 {
|
||||
if m.cacheOption.Duration < 0 {
|
||||
if _, err := cacheObj.Remove(ctx, cacheKey); err != nil {
|
||||
intlog.Error(m.GetCtx(), err)
|
||||
}
|
||||
} else {
|
||||
// In case of Cache Penetration.
|
||||
if result == nil {
|
||||
if result.IsEmpty() && m.cacheOption.Force {
|
||||
result = Result{}
|
||||
}
|
||||
if err := cacheObj.Set(ctx, cacheKey, result, m.cacheDuration); err != nil {
|
||||
if err := cacheObj.Set(ctx, cacheKey, result, m.cacheOption.Duration); err != nil {
|
||||
intlog.Error(m.GetCtx(), err)
|
||||
}
|
||||
}
|
||||
|
@ -2479,7 +2479,11 @@ func Test_Model_Cache(t *testing.T) {
|
||||
defer dropTable(table)
|
||||
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
one, err := db.Model(table).Cache(time.Second, "test1").WherePri(1).One()
|
||||
one, err := db.Model(table).Cache(gdb.CacheOption{
|
||||
Duration: time.Second,
|
||||
Name: "test1",
|
||||
Force: false,
|
||||
}).WherePri(1).One()
|
||||
t.AssertNil(err)
|
||||
t.Assert(one["passport"], "user_1")
|
||||
|
||||
@ -2489,63 +2493,107 @@ func Test_Model_Cache(t *testing.T) {
|
||||
t.AssertNil(err)
|
||||
t.Assert(n, 1)
|
||||
|
||||
one, err = db.Model(table).Cache(time.Second, "test1").WherePri(1).One()
|
||||
one, err = db.Model(table).Cache(gdb.CacheOption{
|
||||
Duration: time.Second,
|
||||
Name: "test1",
|
||||
Force: false,
|
||||
}).WherePri(1).One()
|
||||
t.AssertNil(err)
|
||||
t.Assert(one["passport"], "user_1")
|
||||
|
||||
time.Sleep(time.Second * 2)
|
||||
|
||||
one, err = db.Model(table).Cache(time.Second, "test1").WherePri(1).One()
|
||||
one, err = db.Model(table).Cache(gdb.CacheOption{
|
||||
Duration: time.Second,
|
||||
Name: "test1",
|
||||
Force: false,
|
||||
}).WherePri(1).One()
|
||||
t.AssertNil(err)
|
||||
t.Assert(one["passport"], "user_100")
|
||||
})
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
one, err := db.Model(table).Cache(time.Second, "test2").WherePri(2).One()
|
||||
one, err := db.Model(table).Cache(gdb.CacheOption{
|
||||
Duration: time.Second,
|
||||
Name: "test2",
|
||||
Force: false,
|
||||
}).WherePri(2).One()
|
||||
t.AssertNil(err)
|
||||
t.Assert(one["passport"], "user_2")
|
||||
|
||||
r, err := db.Model(table).Data("passport", "user_200").Cache(-1, "test2").WherePri(2).Update()
|
||||
r, err := db.Model(table).Data("passport", "user_200").Cache(gdb.CacheOption{
|
||||
Duration: -1,
|
||||
Name: "test2",
|
||||
Force: false,
|
||||
}).WherePri(2).Update()
|
||||
t.AssertNil(err)
|
||||
n, err := r.RowsAffected()
|
||||
t.AssertNil(err)
|
||||
t.Assert(n, 1)
|
||||
|
||||
one, err = db.Model(table).Cache(time.Second, "test2").WherePri(2).One()
|
||||
one, err = db.Model(table).Cache(gdb.CacheOption{
|
||||
Duration: time.Second,
|
||||
Name: "test2",
|
||||
Force: false,
|
||||
}).WherePri(2).One()
|
||||
t.AssertNil(err)
|
||||
t.Assert(one["passport"], "user_200")
|
||||
})
|
||||
// transaction.
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
// make cache for id 3
|
||||
one, err := db.Model(table).Cache(time.Second, "test3").WherePri(3).One()
|
||||
one, err := db.Model(table).Cache(gdb.CacheOption{
|
||||
Duration: time.Second,
|
||||
Name: "test3",
|
||||
Force: false,
|
||||
}).WherePri(3).One()
|
||||
t.AssertNil(err)
|
||||
t.Assert(one["passport"], "user_3")
|
||||
|
||||
r, err := db.Model(table).Data("passport", "user_300").Cache(time.Second, "test3").WherePri(3).Update()
|
||||
r, err := db.Model(table).Data("passport", "user_300").Cache(gdb.CacheOption{
|
||||
Duration: time.Second,
|
||||
Name: "test3",
|
||||
Force: false,
|
||||
}).WherePri(3).Update()
|
||||
t.AssertNil(err)
|
||||
n, err := r.RowsAffected()
|
||||
t.AssertNil(err)
|
||||
t.Assert(n, 1)
|
||||
|
||||
err = db.Transaction(context.TODO(), func(ctx context.Context, tx *gdb.TX) error {
|
||||
one, err := tx.Model(table).Cache(time.Second, "test3").WherePri(3).One()
|
||||
one, err := tx.Model(table).Cache(gdb.CacheOption{
|
||||
Duration: time.Second,
|
||||
Name: "test3",
|
||||
Force: false,
|
||||
}).WherePri(3).One()
|
||||
t.AssertNil(err)
|
||||
t.Assert(one["passport"], "user_300")
|
||||
return nil
|
||||
})
|
||||
t.AssertNil(err)
|
||||
|
||||
one, err = db.Model(table).Cache(time.Second, "test3").WherePri(3).One()
|
||||
one, err = db.Model(table).Cache(gdb.CacheOption{
|
||||
Duration: time.Second,
|
||||
Name: "test3",
|
||||
Force: false,
|
||||
}).WherePri(3).One()
|
||||
t.AssertNil(err)
|
||||
t.Assert(one["passport"], "user_3")
|
||||
})
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
// make cache for id 4
|
||||
one, err := db.Model(table).Cache(time.Second, "test4").WherePri(4).One()
|
||||
one, err := db.Model(table).Cache(gdb.CacheOption{
|
||||
Duration: time.Second,
|
||||
Name: "test4",
|
||||
Force: false,
|
||||
}).WherePri(4).One()
|
||||
t.AssertNil(err)
|
||||
t.Assert(one["passport"], "user_4")
|
||||
|
||||
r, err := db.Model(table).Data("passport", "user_400").Cache(time.Second, "test3").WherePri(4).Update()
|
||||
r, err := db.Model(table).Data("passport", "user_400").Cache(gdb.CacheOption{
|
||||
Duration: time.Second,
|
||||
Name: "test3",
|
||||
Force: false,
|
||||
}).WherePri(4).Update()
|
||||
t.AssertNil(err)
|
||||
n, err := r.RowsAffected()
|
||||
t.AssertNil(err)
|
||||
@ -2553,12 +2601,20 @@ func Test_Model_Cache(t *testing.T) {
|
||||
|
||||
err = db.Transaction(context.TODO(), func(ctx context.Context, tx *gdb.TX) error {
|
||||
// Cache feature disabled.
|
||||
one, err := tx.Model(table).Cache(time.Second, "test4").WherePri(4).One()
|
||||
one, err := tx.Model(table).Cache(gdb.CacheOption{
|
||||
Duration: time.Second,
|
||||
Name: "test4",
|
||||
Force: false,
|
||||
}).WherePri(4).One()
|
||||
t.AssertNil(err)
|
||||
t.Assert(one["passport"], "user_400")
|
||||
// Update the cache.
|
||||
r, err := tx.Model(table).Data("passport", "user_4000").
|
||||
Cache(-1, "test4").WherePri(4).Update()
|
||||
Cache(gdb.CacheOption{
|
||||
Duration: -1,
|
||||
Name: "test4",
|
||||
Force: false,
|
||||
}).WherePri(4).Update()
|
||||
t.AssertNil(err)
|
||||
n, err := r.RowsAffected()
|
||||
t.AssertNil(err)
|
||||
@ -2567,7 +2623,11 @@ func Test_Model_Cache(t *testing.T) {
|
||||
})
|
||||
t.AssertNil(err)
|
||||
// Read from db.
|
||||
one, err = db.Model(table).Cache(time.Second, "test4").WherePri(4).One()
|
||||
one, err = db.Model(table).Cache(gdb.CacheOption{
|
||||
Duration: time.Second,
|
||||
Name: "test4",
|
||||
Force: false,
|
||||
}).WherePri(4).One()
|
||||
t.AssertNil(err)
|
||||
t.Assert(one["passport"], "user_4000")
|
||||
})
|
||||
|
@ -13,7 +13,7 @@ import (
|
||||
|
||||
// IsNil checks whether `value` is nil.
|
||||
func IsNil(value interface{}) bool {
|
||||
return value == nil
|
||||
return empty.IsNil(value)
|
||||
}
|
||||
|
||||
// IsEmpty checks whether `value` is empty.
|
||||
|
@ -134,7 +134,7 @@ func TestCache_UpdateExpire(t *testing.T) {
|
||||
newExpire := 10 * time.Second
|
||||
oldExpire2, err := cache.UpdateExpire(ctx, 1, newExpire)
|
||||
t.AssertNil(err)
|
||||
t.Assert(oldExpire2, oldExpire)
|
||||
t.AssertIN(oldExpire2, g.Slice{oldExpire, `2.999s`})
|
||||
|
||||
e, _ := cache.GetExpire(ctx, 1)
|
||||
t.AssertNE(e, oldExpire)
|
||||
|
@ -196,8 +196,12 @@ func doExport(value interface{}, indent string, buffer *bytes.Buffer, option doE
|
||||
if structContentStr == "" {
|
||||
structContentStr = "{}"
|
||||
} else {
|
||||
structContentStr = fmt.Sprintf(`"%s"`, gstr.AddSlashes(structContentStr))
|
||||
attributeCountStr = fmt.Sprintf(`%d`, len(structContentStr)-2)
|
||||
if strings.HasPrefix(structContentStr, `"`) && strings.HasSuffix(structContentStr, `"`) {
|
||||
attributeCountStr = fmt.Sprintf(`%d`, len(structContentStr))
|
||||
} else {
|
||||
structContentStr = fmt.Sprintf(`"%s"`, gstr.AddSlashes(structContentStr))
|
||||
attributeCountStr = fmt.Sprintf(`%d`, len(structContentStr)-2)
|
||||
}
|
||||
}
|
||||
if option.WithoutType {
|
||||
buffer.WriteString(structContentStr)
|
||||
|
@ -6,16 +6,29 @@
|
||||
|
||||
package gvalid
|
||||
|
||||
import "context"
|
||||
import (
|
||||
"context"
|
||||
"github.com/gogf/gf/v2/container/gvar"
|
||||
)
|
||||
|
||||
// RuleFunc is the custom function for data validation.
|
||||
//
|
||||
// The parameter `rule` specifies the validation rule string, like "required", "between:1,100", etc.
|
||||
// The parameter `value` specifies the value for this rule to validate.
|
||||
// The parameter `message` specifies the custom error message or configured i18n message for this rule.
|
||||
// The parameter `data` specifies the `data` which is passed to the Validator. It might be a type of map/struct or a nil value.
|
||||
// You can ignore the parameter `data` if you do not really need it in your custom validation rule.
|
||||
type RuleFunc func(ctx context.Context, rule string, value interface{}, message string, data interface{}) error
|
||||
type RuleFunc func(ctx context.Context, in RuleFuncInput) error
|
||||
|
||||
// RuleFuncInput holds the input parameters that passed to custom rule function RuleFunc.
|
||||
type RuleFuncInput struct {
|
||||
// Rule specifies the validation rule string, like "required", "between:1,100", etc.
|
||||
Rule string
|
||||
|
||||
// Message specifies the custom error message or configured i18n message for this rule.
|
||||
Message string
|
||||
|
||||
// Value specifies the value for this rule to validate.
|
||||
Value *gvar.Var
|
||||
|
||||
// Data specifies the `data` which is passed to the Validator. It might be a type of map/struct or a nil value.
|
||||
// You can ignore the parameter `Data` if you do not really need it in your custom validation rule.
|
||||
Data *gvar.Var
|
||||
}
|
||||
|
||||
var (
|
||||
// customRuleFuncMap stores the custom rule functions.
|
||||
@ -24,13 +37,20 @@ var (
|
||||
)
|
||||
|
||||
// RegisterRule registers custom validation rule and function for package.
|
||||
// It returns error if there's already the same rule registered previously.
|
||||
func RegisterRule(rule string, f RuleFunc) error {
|
||||
func RegisterRule(rule string, f RuleFunc) {
|
||||
customRuleFuncMap[rule] = f
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeleteRule deletes custom defined validation rule and its function from global package.
|
||||
func DeleteRule(rule string) {
|
||||
delete(customRuleFuncMap, rule)
|
||||
// RegisterRuleByMap registers custom validation rules using map for package.
|
||||
func RegisterRuleByMap(m map[string]RuleFunc) {
|
||||
for k, v := range m {
|
||||
customRuleFuncMap[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
// DeleteRule deletes custom defined validation one or more rules and associated functions from global package.
|
||||
func DeleteRule(rules ...string) {
|
||||
for _, rule := range rules {
|
||||
delete(customRuleFuncMap, rule)
|
||||
}
|
||||
}
|
||||
|
@ -19,50 +19,62 @@ type Error interface {
|
||||
Code() gcode.Code
|
||||
Current() error
|
||||
Error() string
|
||||
FirstItem() (key string, messages map[string]string)
|
||||
FirstRule() (rule string, err string)
|
||||
FirstString() (err string)
|
||||
Items() (items []map[string]map[string]string)
|
||||
Map() map[string]string
|
||||
Maps() map[string]map[string]string
|
||||
FirstItem() (key string, messages map[string]error)
|
||||
FirstRule() (rule string, err error)
|
||||
FirstError() (err error)
|
||||
Items() (items []map[string]map[string]error)
|
||||
Map() map[string]error
|
||||
Maps() map[string]map[string]error
|
||||
String() string
|
||||
Strings() (errs []string)
|
||||
}
|
||||
|
||||
// validationError is the validation error for validation result.
|
||||
type validationError struct {
|
||||
code gcode.Code // Error code.
|
||||
rules []fieldRule // Rules by sequence, which is used for keeping error sequence.
|
||||
errors map[string]map[string]string // Error map:map[field]map[rule]message
|
||||
firstKey string // The first error rule key(empty in default).
|
||||
firstItem map[string]string // The first error rule value(nil in default).
|
||||
code gcode.Code // Error code.
|
||||
rules []fieldRule // Rules by sequence, which is used for keeping error sequence.
|
||||
errors map[string]map[string]error // Error map:map[field]map[rule]message
|
||||
firstKey string // The first error rule key(empty in default).
|
||||
firstItem map[string]error // The first error rule value(nil in default).
|
||||
}
|
||||
|
||||
// newError creates and returns a validation error.
|
||||
func newError(code gcode.Code, rules []fieldRule, errors map[string]map[string]string) *validationError {
|
||||
for field, m := range errors {
|
||||
for k, v := range m {
|
||||
v = strings.Replace(v, ":attribute", field, -1)
|
||||
v, _ = gregex.ReplaceString(`\s{2,}`, ` `, v)
|
||||
v = gstr.Trim(v)
|
||||
m[k] = v
|
||||
// newValidationError creates and returns a validation error.
|
||||
func newValidationError(code gcode.Code, rules []fieldRule, fieldRuleErrorMap map[string]map[string]error) *validationError {
|
||||
var (
|
||||
s string
|
||||
)
|
||||
for field, ruleErrorMap := range fieldRuleErrorMap {
|
||||
for rule, err := range ruleErrorMap {
|
||||
if !gerror.HasStack(err) {
|
||||
s = strings.Replace(err.Error(), ":attribute", field, -1)
|
||||
s, _ = gregex.ReplaceString(`\s{2,}`, ` `, s)
|
||||
ruleErrorMap[rule] = gerror.NewOption(gerror.Option{
|
||||
Stack: false,
|
||||
Text: gstr.Trim(s),
|
||||
Code: code,
|
||||
})
|
||||
}
|
||||
}
|
||||
errors[field] = m
|
||||
fieldRuleErrorMap[field] = ruleErrorMap
|
||||
}
|
||||
return &validationError{
|
||||
code: code,
|
||||
rules: rules,
|
||||
errors: errors,
|
||||
errors: fieldRuleErrorMap,
|
||||
}
|
||||
}
|
||||
|
||||
// newErrorStr creates and returns a validation error by string.
|
||||
func newErrorStr(key, err string) *validationError {
|
||||
return newError(gcode.CodeInternalError, nil, map[string]map[string]string{
|
||||
internalErrorMapKey: {
|
||||
key: err,
|
||||
// newValidationErrorByStr creates and returns a validation error by string.
|
||||
func newValidationErrorByStr(key string, err error) *validationError {
|
||||
return newValidationError(
|
||||
gcode.CodeInternalError,
|
||||
nil,
|
||||
map[string]map[string]error{
|
||||
internalErrorMapKey: {
|
||||
key: err,
|
||||
},
|
||||
},
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
// Code returns the error code of current validation error.
|
||||
@ -74,16 +86,16 @@ func (e *validationError) Code() gcode.Code {
|
||||
}
|
||||
|
||||
// Map returns the first error message as map.
|
||||
func (e *validationError) Map() map[string]string {
|
||||
func (e *validationError) Map() map[string]error {
|
||||
if e == nil {
|
||||
return map[string]string{}
|
||||
return map[string]error{}
|
||||
}
|
||||
_, m := e.FirstItem()
|
||||
return m
|
||||
}
|
||||
|
||||
// Maps returns all error messages as map.
|
||||
func (e *validationError) Maps() map[string]map[string]string {
|
||||
func (e *validationError) Maps() map[string]map[string]error {
|
||||
if e == nil {
|
||||
return nil
|
||||
}
|
||||
@ -92,16 +104,16 @@ func (e *validationError) Maps() map[string]map[string]string {
|
||||
|
||||
// Items retrieves and returns error items array in sequence if possible,
|
||||
// or else it returns error items with no sequence .
|
||||
func (e *validationError) Items() (items []map[string]map[string]string) {
|
||||
func (e *validationError) Items() (items []map[string]map[string]error) {
|
||||
if e == nil {
|
||||
return []map[string]map[string]string{}
|
||||
return []map[string]map[string]error{}
|
||||
}
|
||||
items = make([]map[string]map[string]string, 0)
|
||||
items = make([]map[string]map[string]error, 0)
|
||||
// By sequence.
|
||||
if len(e.rules) > 0 {
|
||||
for _, v := range e.rules {
|
||||
if errorItemMap, ok := e.errors[v.Name]; ok {
|
||||
items = append(items, map[string]map[string]string{
|
||||
items = append(items, map[string]map[string]error{
|
||||
v.Name: errorItemMap,
|
||||
})
|
||||
}
|
||||
@ -110,7 +122,7 @@ func (e *validationError) Items() (items []map[string]map[string]string) {
|
||||
}
|
||||
// No sequence.
|
||||
for name, errorRuleMap := range e.errors {
|
||||
items = append(items, map[string]map[string]string{
|
||||
items = append(items, map[string]map[string]error{
|
||||
name: errorRuleMap,
|
||||
})
|
||||
}
|
||||
@ -118,9 +130,9 @@ func (e *validationError) Items() (items []map[string]map[string]string) {
|
||||
}
|
||||
|
||||
// FirstItem returns the field name and error messages for the first validation rule error.
|
||||
func (e *validationError) FirstItem() (key string, messages map[string]string) {
|
||||
func (e *validationError) FirstItem() (key string, messages map[string]error) {
|
||||
if e == nil {
|
||||
return "", map[string]string{}
|
||||
return "", map[string]error{}
|
||||
}
|
||||
if e.firstItem != nil {
|
||||
return e.firstKey, e.firstItem
|
||||
@ -145,9 +157,9 @@ func (e *validationError) FirstItem() (key string, messages map[string]string) {
|
||||
}
|
||||
|
||||
// FirstRule returns the first error rule and message string.
|
||||
func (e *validationError) FirstRule() (rule string, err string) {
|
||||
func (e *validationError) FirstRule() (rule string, err error) {
|
||||
if e == nil {
|
||||
return "", ""
|
||||
return "", nil
|
||||
}
|
||||
// By sequence.
|
||||
if len(e.rules) > 0 {
|
||||
@ -169,26 +181,22 @@ func (e *validationError) FirstRule() (rule string, err string) {
|
||||
return k, v
|
||||
}
|
||||
}
|
||||
return "", ""
|
||||
return "", nil
|
||||
}
|
||||
|
||||
// FirstString returns the first error message as string.
|
||||
// FirstError returns the first error message as string.
|
||||
// Note that the returned message might be different if it has no sequence.
|
||||
func (e *validationError) FirstString() (err string) {
|
||||
func (e *validationError) FirstError() (err error) {
|
||||
if e == nil {
|
||||
return ""
|
||||
return nil
|
||||
}
|
||||
_, err = e.FirstRule()
|
||||
return
|
||||
}
|
||||
|
||||
// Current is alis of FirstString, which implements interface gerror.iCurrent.
|
||||
// Current is alis of FirstError, which implements interface gerror.iCurrent.
|
||||
func (e *validationError) Current() error {
|
||||
if e == nil {
|
||||
return nil
|
||||
}
|
||||
_, err := e.FirstRule()
|
||||
return gerror.NewCode(e.code, err)
|
||||
return e.FirstError()
|
||||
}
|
||||
|
||||
// String returns all error messages as string, multiple error messages joined using char ';'.
|
||||
@ -221,13 +229,13 @@ func (e *validationError) Strings() (errs []string) {
|
||||
for _, ruleItem := range strings.Split(v.Rule, "|") {
|
||||
ruleItem = strings.TrimSpace(strings.Split(ruleItem, ":")[0])
|
||||
if err, ok := errorItemMap[ruleItem]; ok {
|
||||
errs = append(errs, err)
|
||||
errs = append(errs, err.Error())
|
||||
}
|
||||
}
|
||||
// internal error checks.
|
||||
for k, _ := range internalErrKeyMap {
|
||||
if err, ok := errorItemMap[k]; ok {
|
||||
errs = append(errs, err)
|
||||
errs = append(errs, err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -237,7 +245,7 @@ func (e *validationError) Strings() (errs []string) {
|
||||
// No sequence.
|
||||
for _, errorItemMap := range e.errors {
|
||||
for _, err := range errorItemMap {
|
||||
errs = append(errs, err)
|
||||
errs = append(errs, err.Error())
|
||||
}
|
||||
}
|
||||
return
|
||||
|
@ -8,6 +8,7 @@ package gvalid
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"github.com/gogf/gf/v2/errors/gcode"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
"strings"
|
||||
@ -27,7 +28,7 @@ func (v *Validator) doCheckMap(ctx context.Context, params interface{}) Error {
|
||||
var (
|
||||
checkRules = make([]fieldRule, 0)
|
||||
customMessage = make(CustomMsg) // map[RuleKey]ErrorMsg.
|
||||
errorMaps = make(map[string]map[string]string)
|
||||
errorMaps = make(map[string]map[string]error)
|
||||
)
|
||||
switch assertValue := v.rules.(type) {
|
||||
// Sequence tag: []sequence tag
|
||||
@ -80,9 +81,9 @@ func (v *Validator) doCheckMap(ctx context.Context, params interface{}) Error {
|
||||
}
|
||||
data := gconv.Map(params)
|
||||
if data == nil {
|
||||
return newErrorStr(
|
||||
return newValidationErrorByStr(
|
||||
internalParamsErrRuleName,
|
||||
"invalid params type: convert to map failed",
|
||||
errors.New("invalid params type: convert to map failed"),
|
||||
)
|
||||
}
|
||||
if msg, ok := v.messages.(CustomMsg); ok && len(msg) > 0 {
|
||||
@ -139,7 +140,7 @@ func (v *Validator) doCheckMap(ctx context.Context, params interface{}) Error {
|
||||
}
|
||||
}
|
||||
if _, ok := errorMaps[checkRuleItem.Name]; !ok {
|
||||
errorMaps[checkRuleItem.Name] = make(map[string]string)
|
||||
errorMaps[checkRuleItem.Name] = make(map[string]error)
|
||||
}
|
||||
for ruleKey, errorItemMsgMap := range errorItem {
|
||||
errorMaps[checkRuleItem.Name][ruleKey] = errorItemMsgMap
|
||||
@ -150,7 +151,7 @@ func (v *Validator) doCheckMap(ctx context.Context, params interface{}) Error {
|
||||
}
|
||||
}
|
||||
if len(errorMaps) > 0 {
|
||||
return newError(gcode.CodeValidationFailed, checkRules, errorMaps)
|
||||
return newValidationError(gcode.CodeValidationFailed, checkRules, errorMaps)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -23,8 +23,8 @@ func (v *Validator) CheckStruct(ctx context.Context, object interface{}) Error {
|
||||
|
||||
func (v *Validator) doCheckStruct(ctx context.Context, object interface{}) Error {
|
||||
var (
|
||||
errorMaps = make(map[string]map[string]string) // Returning error.
|
||||
fieldToAliasNameMap = make(map[string]string) // Field names to alias name map.
|
||||
errorMaps = make(map[string]map[string]error) // Returning error.
|
||||
fieldToAliasNameMap = make(map[string]string) // Field names to alias name map.
|
||||
)
|
||||
fieldMap, err := structs.FieldMap(structs.FieldMapInput{
|
||||
Pointer: object,
|
||||
@ -32,7 +32,7 @@ func (v *Validator) doCheckStruct(ctx context.Context, object interface{}) Error
|
||||
RecursiveOption: structs.RecursiveOptionEmbedded,
|
||||
})
|
||||
if err != nil {
|
||||
return newErrorStr(internalObjectErrRuleName, err.Error())
|
||||
return newValidationErrorByStr(internalObjectErrRuleName, err)
|
||||
}
|
||||
// It checks the struct recursively if its attribute is an embedded struct.
|
||||
for _, field := range fieldMap {
|
||||
@ -59,7 +59,7 @@ func (v *Validator) doCheckStruct(ctx context.Context, object interface{}) Error
|
||||
// It here must use structs.TagFields not structs.FieldMap to ensure error sequence.
|
||||
tagField, err := structs.TagFields(object, structTagPriority)
|
||||
if err != nil {
|
||||
return newErrorStr(internalObjectErrRuleName, err.Error())
|
||||
return newValidationErrorByStr(internalObjectErrRuleName, err)
|
||||
}
|
||||
// If there's no struct tag and validation rules, it does nothing and returns quickly.
|
||||
if len(tagField) == 0 && v.messages == nil {
|
||||
@ -278,7 +278,7 @@ func (v *Validator) doCheckStruct(ctx context.Context, object interface{}) Error
|
||||
}
|
||||
}
|
||||
if _, ok := errorMaps[checkRuleItem.Name]; !ok {
|
||||
errorMaps[checkRuleItem.Name] = make(map[string]string)
|
||||
errorMaps[checkRuleItem.Name] = make(map[string]error)
|
||||
}
|
||||
for ruleKey, errorItemMsgMap := range errorItem {
|
||||
errorMaps[checkRuleItem.Name][ruleKey] = errorItemMsgMap
|
||||
@ -289,7 +289,7 @@ func (v *Validator) doCheckStruct(ctx context.Context, object interface{}) Error
|
||||
}
|
||||
}
|
||||
if len(errorMaps) > 0 {
|
||||
return newError(gcode.CodeValidationFailed, checkRules, errorMaps)
|
||||
return newValidationError(gcode.CodeValidationFailed, checkRules, errorMaps)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -8,8 +8,9 @@ package gvalid
|
||||
|
||||
import (
|
||||
"context"
|
||||
"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"
|
||||
@ -60,7 +61,7 @@ func (v *Validator) doCheckValue(ctx context.Context, input doCheckValueInput) E
|
||||
// It converts value to string and then does the validation.
|
||||
var (
|
||||
// Do not trim it as the space is also part of the value.
|
||||
errorMsgArray = make(map[string]string)
|
||||
ruleErrorMap = make(map[string]error)
|
||||
)
|
||||
// Custom error messages handling.
|
||||
var (
|
||||
@ -86,9 +87,9 @@ func (v *Validator) doCheckValue(ctx context.Context, input doCheckValueInput) E
|
||||
ruleItems[i-1] += "|" + ruleItems[i]
|
||||
ruleItems = append(ruleItems[:i], ruleItems[i+1:]...)
|
||||
} else {
|
||||
return newErrorStr(
|
||||
return newValidationErrorByStr(
|
||||
internalRulesErrRuleName,
|
||||
internalRulesErrRuleName+": "+input.Rule,
|
||||
errors.New(internalRulesErrRuleName+": "+input.Rule),
|
||||
)
|
||||
}
|
||||
} else {
|
||||
@ -133,9 +134,14 @@ 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, ruleItems[index], input.Value, message, input.DataRaw); err != nil {
|
||||
if err := customRuleFunc(ctx, RuleFuncInput{
|
||||
Rule: ruleItems[index],
|
||||
Message: message,
|
||||
Value: gvar.New(input.Value),
|
||||
Data: gvar.New(input.DataRaw),
|
||||
}); err != nil {
|
||||
match = false
|
||||
errorMsgArray[ruleKey] = err.Error()
|
||||
ruleErrorMap[ruleKey] = err
|
||||
} else {
|
||||
match = true
|
||||
}
|
||||
@ -154,7 +160,7 @@ func (v *Validator) doCheckValue(ctx context.Context, input doCheckValueInput) E
|
||||
},
|
||||
)
|
||||
if !match && err != nil {
|
||||
errorMsgArray[ruleKey] = err.Error()
|
||||
ruleErrorMap[ruleKey] = err
|
||||
}
|
||||
}
|
||||
|
||||
@ -162,8 +168,8 @@ func (v *Validator) doCheckValue(ctx context.Context, input doCheckValueInput) E
|
||||
if !match {
|
||||
// It does nothing if the error message for this rule
|
||||
// is already set in previous validation.
|
||||
if _, ok := errorMsgArray[ruleKey]; !ok {
|
||||
errorMsgArray[ruleKey] = v.getErrorMessageByRule(ctx, ruleKey, customMsgMap)
|
||||
if _, ok := ruleErrorMap[ruleKey]; !ok {
|
||||
ruleErrorMap[ruleKey] = errors.New(v.getErrorMessageByRule(ctx, ruleKey, customMsgMap))
|
||||
}
|
||||
// If it is with error and there's bail rule,
|
||||
// it then does not continue validating for left rules.
|
||||
@ -173,12 +179,12 @@ func (v *Validator) doCheckValue(ctx context.Context, input doCheckValueInput) E
|
||||
}
|
||||
index++
|
||||
}
|
||||
if len(errorMsgArray) > 0 {
|
||||
return newError(
|
||||
if len(ruleErrorMap) > 0 {
|
||||
return newValidationError(
|
||||
gcode.CodeValidationFailed,
|
||||
[]fieldRule{{Name: input.Name, Rule: input.Rule}},
|
||||
map[string]map[string]string{
|
||||
input.Name: errorMsgArray,
|
||||
map[string]map[string]error{
|
||||
input.Name: ruleErrorMap,
|
||||
},
|
||||
)
|
||||
}
|
||||
@ -217,10 +223,7 @@ func (v *Validator) doCheckBuildInRules(ctx context.Context, input doCheckBuildI
|
||||
"max-length",
|
||||
"size":
|
||||
if msg := v.checkLength(ctx, valueStr, input.RuleKey, input.RulePattern, input.CustomMsgMap); msg != "" {
|
||||
return match, gerror.NewOption(gerror.Option{
|
||||
Text: msg,
|
||||
Code: gcode.CodeValidationFailed,
|
||||
})
|
||||
return match, errors.New(msg)
|
||||
} else {
|
||||
match = true
|
||||
}
|
||||
@ -231,10 +234,7 @@ func (v *Validator) doCheckBuildInRules(ctx context.Context, input doCheckBuildI
|
||||
"max",
|
||||
"between":
|
||||
if msg := v.checkRange(ctx, valueStr, input.RuleKey, input.RulePattern, input.CustomMsgMap); msg != "" {
|
||||
return match, gerror.NewOption(gerror.Option{
|
||||
Text: msg,
|
||||
Code: gcode.CodeValidationFailed,
|
||||
})
|
||||
return match, errors.New(msg)
|
||||
} else {
|
||||
match = true
|
||||
}
|
||||
@ -282,10 +282,7 @@ func (v *Validator) doCheckBuildInRules(ctx context.Context, input doCheckBuildI
|
||||
)
|
||||
msg = v.getErrorMessageByRule(ctx, input.RuleKey, input.CustomMsgMap)
|
||||
msg = strings.Replace(msg, ":format", input.RulePattern, -1)
|
||||
return match, gerror.NewOption(gerror.Option{
|
||||
Text: msg,
|
||||
Code: gcode.CodeValidationFailed,
|
||||
})
|
||||
return match, errors.New(msg)
|
||||
}
|
||||
|
||||
// Values of two fields should be equal as string.
|
||||
@ -300,10 +297,7 @@ func (v *Validator) doCheckBuildInRules(ctx context.Context, input doCheckBuildI
|
||||
var msg string
|
||||
msg = v.getErrorMessageByRule(ctx, input.RuleKey, input.CustomMsgMap)
|
||||
msg = strings.Replace(msg, ":field", input.RulePattern, -1)
|
||||
return match, gerror.NewOption(gerror.Option{
|
||||
Text: msg,
|
||||
Code: gcode.CodeValidationFailed,
|
||||
})
|
||||
return match, errors.New(msg)
|
||||
}
|
||||
|
||||
// Values of two fields should not be equal as string.
|
||||
@ -319,10 +313,7 @@ func (v *Validator) doCheckBuildInRules(ctx context.Context, input doCheckBuildI
|
||||
var msg string
|
||||
msg = v.getErrorMessageByRule(ctx, input.RuleKey, input.CustomMsgMap)
|
||||
msg = strings.Replace(msg, ":field", input.RulePattern, -1)
|
||||
return match, gerror.NewOption(gerror.Option{
|
||||
Text: msg,
|
||||
Code: gcode.CodeValidationFailed,
|
||||
})
|
||||
return match, errors.New(msg)
|
||||
}
|
||||
|
||||
// Field value should be in range of.
|
||||
@ -505,10 +496,7 @@ func (v *Validator) doCheckBuildInRules(ctx context.Context, input doCheckBuildI
|
||||
match = gregex.IsMatchString(`^([0-9A-Fa-f]{2}[\-:]){5}[0-9A-Fa-f]{2}$`, valueStr)
|
||||
|
||||
default:
|
||||
return match, gerror.NewOption(gerror.Option{
|
||||
Text: "Invalid rule name: " + input.RuleKey,
|
||||
Code: gcode.CodeInvalidParameter,
|
||||
})
|
||||
return match, errors.New("Invalid rule name: " + input.RuleKey)
|
||||
}
|
||||
return match, nil
|
||||
}
|
||||
|
@ -33,7 +33,7 @@ func ExampleCheckMap() {
|
||||
if e := gvalid.CheckMap(gctx.New(), params, rules); e != nil {
|
||||
fmt.Println(e.Map())
|
||||
fmt.Println(e.FirstItem())
|
||||
fmt.Println(e.FirstString())
|
||||
fmt.Println(e.FirstError())
|
||||
}
|
||||
// May Output:
|
||||
// map[required:账号不能为空 length:账号长度应当在6到16之间]
|
||||
@ -55,7 +55,7 @@ func ExampleCheckMap2() {
|
||||
if e := gvalid.CheckMap(gctx.New(), params, rules); e != nil {
|
||||
fmt.Println(e.Map())
|
||||
fmt.Println(e.FirstItem())
|
||||
fmt.Println(e.FirstString())
|
||||
fmt.Println(e.FirstError())
|
||||
}
|
||||
// Output:
|
||||
// map[same:两次密码输入不相等]
|
||||
@ -127,17 +127,17 @@ func ExampleRegisterRule() {
|
||||
}
|
||||
|
||||
rule := "unique-name"
|
||||
gvalid.RegisterRule(rule, func(ctx context.Context, rule string, value interface{}, message string, data interface{}) error {
|
||||
gvalid.RegisterRule(rule, func(ctx context.Context, in gvalid.RuleFuncInput) error {
|
||||
var (
|
||||
id = data.(*User).Id
|
||||
name = gconv.String(value)
|
||||
id = in.Data.Val().(*User).Id
|
||||
name = gconv.String(in.Value)
|
||||
)
|
||||
n, err := g.Model("user").Where("id != ? and name = ?", id, name).Count()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if n > 0 {
|
||||
return errors.New(message)
|
||||
return errors.New(in.Message)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
@ -149,8 +149,8 @@ func ExampleRegisterRule() {
|
||||
|
||||
func ExampleRegisterRule_OverwriteRequired() {
|
||||
rule := "required"
|
||||
gvalid.RegisterRule(rule, func(ctx context.Context, rule string, value interface{}, message string, data interface{}) error {
|
||||
reflectValue := reflect.ValueOf(value)
|
||||
gvalid.RegisterRule(rule, func(ctx context.Context, in gvalid.RuleFuncInput) error {
|
||||
reflectValue := reflect.ValueOf(in.Value.Val())
|
||||
if reflectValue.Kind() == reflect.Ptr {
|
||||
reflectValue = reflectValue.Elem()
|
||||
}
|
||||
@ -171,7 +171,7 @@ func ExampleRegisterRule_OverwriteRequired() {
|
||||
isEmpty = reflectValue.Len() == 0
|
||||
}
|
||||
if isEmpty {
|
||||
return errors.New(message)
|
||||
return errors.New(in.Message)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
@ -1037,7 +1037,7 @@ func Test_InternalError_String(t *testing.T) {
|
||||
|
||||
t.Assert(err.String(), "InvalidRules: hh")
|
||||
t.Assert(err.Strings(), g.Slice{"InvalidRules: hh"})
|
||||
t.Assert(err.FirstString(), "InvalidRules: hh")
|
||||
t.Assert(err.FirstError(), "InvalidRules: hh")
|
||||
t.Assert(gerror.Current(err), "InvalidRules: hh")
|
||||
})
|
||||
}
|
||||
|
@ -12,29 +12,27 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
|
||||
"github.com/gogf/gf/v2/test/gtest"
|
||||
"github.com/gogf/gf/v2/util/gvalid"
|
||||
)
|
||||
|
||||
func Test_CustomRule1(t *testing.T) {
|
||||
rule := "custom"
|
||||
err := gvalid.RegisterRule(
|
||||
gvalid.RegisterRule(
|
||||
rule,
|
||||
func(ctx context.Context, rule string, value interface{}, message string, data interface{}) error {
|
||||
pass := gconv.String(value)
|
||||
func(ctx context.Context, in gvalid.RuleFuncInput) error {
|
||||
pass := in.Value.String()
|
||||
if len(pass) != 6 {
|
||||
return errors.New(message)
|
||||
return errors.New(in.Message)
|
||||
}
|
||||
m := gconv.Map(data)
|
||||
m := in.Data.Map()
|
||||
if m["data"] != pass {
|
||||
return errors.New(message)
|
||||
return errors.New(in.Message)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
)
|
||||
gtest.Assert(err, nil)
|
||||
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
err := gvalid.CheckValue(context.TODO(), "123456", rule, "custom message")
|
||||
t.Assert(err.String(), "custom message")
|
||||
@ -71,14 +69,13 @@ func Test_CustomRule1(t *testing.T) {
|
||||
|
||||
func Test_CustomRule2(t *testing.T) {
|
||||
rule := "required-map"
|
||||
err := gvalid.RegisterRule(rule, func(ctx context.Context, rule string, value interface{}, message string, data interface{}) error {
|
||||
m := gconv.Map(value)
|
||||
gvalid.RegisterRule(rule, func(ctx context.Context, in gvalid.RuleFuncInput) error {
|
||||
m := in.Value.Map()
|
||||
if len(m) == 0 {
|
||||
return errors.New(message)
|
||||
return errors.New(in.Message)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
gtest.Assert(err, nil)
|
||||
// Check.
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
errStr := "data map should not be empty"
|
||||
@ -115,14 +112,13 @@ func Test_CustomRule2(t *testing.T) {
|
||||
|
||||
func Test_CustomRule_AllowEmpty(t *testing.T) {
|
||||
rule := "allow-empty-str"
|
||||
err := gvalid.RegisterRule(rule, func(ctx context.Context, rule string, value interface{}, message string, data interface{}) error {
|
||||
s := gconv.String(value)
|
||||
gvalid.RegisterRule(rule, func(ctx context.Context, in gvalid.RuleFuncInput) error {
|
||||
s := in.Value.String()
|
||||
if len(s) == 0 || s == "gf" {
|
||||
return nil
|
||||
}
|
||||
return errors.New(message)
|
||||
return errors.New(in.Message)
|
||||
})
|
||||
gtest.Assert(err, nil)
|
||||
// Check.
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
errStr := "error"
|
||||
@ -160,13 +156,13 @@ func Test_CustomRule_AllowEmpty(t *testing.T) {
|
||||
|
||||
func TestValidator_RuleFunc(t *testing.T) {
|
||||
ruleName := "custom_1"
|
||||
ruleFunc := func(ctx context.Context, rule string, value interface{}, message string, data interface{}) error {
|
||||
pass := gconv.String(value)
|
||||
ruleFunc := func(ctx context.Context, in gvalid.RuleFuncInput) error {
|
||||
pass := in.Value.String()
|
||||
if len(pass) != 6 {
|
||||
return errors.New(message)
|
||||
return errors.New(in.Message)
|
||||
}
|
||||
if m := gconv.Map(data); m["data"] != pass {
|
||||
return errors.New(message)
|
||||
if m := in.Data.Map(); m["data"] != pass {
|
||||
return errors.New(in.Message)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@ -214,13 +210,13 @@ func TestValidator_RuleFunc(t *testing.T) {
|
||||
|
||||
func TestValidator_RuleFuncMap(t *testing.T) {
|
||||
ruleName := "custom_1"
|
||||
ruleFunc := func(ctx context.Context, rule string, value interface{}, message string, data interface{}) error {
|
||||
pass := gconv.String(value)
|
||||
ruleFunc := func(ctx context.Context, in gvalid.RuleFuncInput) error {
|
||||
pass := in.Value.String()
|
||||
if len(pass) != 6 {
|
||||
return errors.New(message)
|
||||
return errors.New(in.Message)
|
||||
}
|
||||
if m := gconv.Map(data); m["data"] != pass {
|
||||
return errors.New(message)
|
||||
if m := in.Data.Map(); m["data"] != pass {
|
||||
return errors.New(in.Message)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -35,9 +35,8 @@ func Test_FirstString(t *testing.T) {
|
||||
rule = "ipv4"
|
||||
val = "0.0.0"
|
||||
err = gvalid.CheckValue(context.TODO(), val, rule, nil)
|
||||
n = err.FirstString()
|
||||
)
|
||||
t.Assert(n, "The value must be a valid IPv4 address")
|
||||
t.Assert(err.FirstError(), "The value must be a valid IPv4 address")
|
||||
})
|
||||
}
|
||||
|
||||
@ -52,12 +51,12 @@ func Test_CustomError1(t *testing.T) {
|
||||
t.Error("规则校验失败")
|
||||
} else {
|
||||
if v, ok := e.Map()["integer"]; ok {
|
||||
if strings.Compare(v, msgs["integer"]) != 0 {
|
||||
if strings.Compare(v.Error(), msgs["integer"]) != 0 {
|
||||
t.Error("错误信息不匹配")
|
||||
}
|
||||
}
|
||||
if v, ok := e.Map()["length"]; ok {
|
||||
if strings.Compare(v, msgs["length"]) != 0 {
|
||||
if strings.Compare(v.Error(), msgs["length"]) != 0 {
|
||||
t.Error("错误信息不匹配")
|
||||
}
|
||||
}
|
||||
@ -72,12 +71,12 @@ func Test_CustomError2(t *testing.T) {
|
||||
t.Error("规则校验失败")
|
||||
} else {
|
||||
if v, ok := e.Map()["integer"]; ok {
|
||||
if strings.Compare(v, "请输入一个整数") != 0 {
|
||||
if strings.Compare(v.Error(), "请输入一个整数") != 0 {
|
||||
t.Error("错误信息不匹配")
|
||||
}
|
||||
}
|
||||
if v, ok := e.Map()["length"]; ok {
|
||||
if strings.Compare(v, "参数长度不对啊老铁") != 0 {
|
||||
if strings.Compare(v.Error(), "参数长度不对啊老铁") != 0 {
|
||||
t.Error("错误信息不匹配")
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user