This commit is contained in:
huangqian
2021-11-23 20:22:00 +08:00
13 changed files with 349 additions and 127 deletions

View File

@ -320,7 +320,12 @@ func (m *Model) Scan(pointer interface{}, where ...interface{}) error {
//
// See Result.ScanList.
func (m *Model) ScanList(structSlicePointer interface{}, bindToAttrName string, relationAttrNameAndFields ...string) (err error) {
result, err := m.All()
out, err := checkGetSliceElementInfoForScanList(structSlicePointer, bindToAttrName)
if err != nil {
return err
}
// Filter fields using temporary created struct using reflect.New.
result, err := m.Fields(reflect.New(out.BindToAttrType).Interface()).All()
if err != nil {
return err
}
@ -335,7 +340,15 @@ func (m *Model) ScanList(structSlicePointer interface{}, bindToAttrName string,
case 1:
relationFields = relationAttrNameAndFields[0]
}
return doScanList(m, result, structSlicePointer, bindToAttrName, relationAttrName, relationFields)
return doScanList(doScanListInput{
Model: m,
Result: result,
StructSlicePointer: structSlicePointer,
StructSliceValue: out.SliceReflectValue,
BindToAttrName: bindToAttrName,
RelationAttrName: relationAttrName,
RelationFields: relationFields,
})
}
// Count does "SELECT COUNT(x) FROM ..." statement for the model.

View File

@ -85,6 +85,11 @@ import (
//
// See the example or unit testing cases for clear understanding for this function.
func (r Result) ScanList(structSlicePointer interface{}, bindToAttrName string, relationAttrNameAndFields ...string) (err error) {
out, err := checkGetSliceElementInfoForScanList(structSlicePointer, bindToAttrName)
if err != nil {
return err
}
var (
relationAttrName string
relationFields string
@ -96,27 +101,32 @@ func (r Result) ScanList(structSlicePointer interface{}, bindToAttrName string,
case 1:
relationFields = relationAttrNameAndFields[0]
}
return doScanList(nil, r, structSlicePointer, bindToAttrName, relationAttrName, relationFields)
return doScanList(doScanListInput{
Model: nil,
Result: r,
StructSlicePointer: structSlicePointer,
StructSliceValue: out.SliceReflectValue,
BindToAttrName: bindToAttrName,
RelationAttrName: relationAttrName,
RelationFields: relationFields,
})
}
// doScanList converts `result` to struct slice which contains other complex struct attributes recursively.
// The parameter `model` is used for recursively scanning purpose, which means, it can scan the attribute struct/structs recursively,
// but it needs the Model for database accessing.
// Note that the parameter `structSlicePointer` should be type of *[]struct/*[]*struct.
func doScanList(model *Model, result Result, structSlicePointer interface{}, bindToAttrName, relationAttrName, relationFields string) (err error) {
if result.IsEmpty() {
return nil
}
type checkGetSliceElementInfoForScanListOutput struct {
SliceReflectValue reflect.Value
BindToAttrType reflect.Type
}
func checkGetSliceElementInfoForScanList(structSlicePointer interface{}, bindToAttrName string) (out *checkGetSliceElementInfoForScanListOutput, err error) {
// Necessary checks for parameters.
if structSlicePointer == nil {
return nil, gerror.NewCode(gcode.CodeInvalidParameter, `structSlicePointer cannot be nil`)
}
if bindToAttrName == "" {
return gerror.NewCode(gcode.CodeInvalidParameter, `bindToAttrName should not be empty`)
return nil, gerror.NewCode(gcode.CodeInvalidParameter, `bindToAttrName should not be empty`)
}
if relationAttrName == "." {
relationAttrName = ""
}
var (
reflectType reflect.Type
reflectValue = reflect.ValueOf(structSlicePointer)
reflectKind = reflectValue.Kind()
)
@ -125,28 +135,84 @@ func doScanList(model *Model, result Result, structSlicePointer interface{}, bin
reflectKind = reflectValue.Kind()
}
if reflectKind != reflect.Ptr {
return gerror.NewCodef(
return nil, gerror.NewCodef(
gcode.CodeInvalidParameter,
"structSlicePointer should be type of *[]struct/*[]*struct, but got: %v",
reflectKind,
"structSlicePointer should be type of *[]struct/*[]*struct, but got: %s",
reflect.TypeOf(structSlicePointer).String(),
)
}
reflectValue = reflectValue.Elem()
reflectKind = reflectValue.Kind()
if reflectKind != reflect.Slice && reflectKind != reflect.Array {
return gerror.NewCodef(
out = &checkGetSliceElementInfoForScanListOutput{
SliceReflectValue: reflectValue.Elem(),
}
// Find the element struct type of the slice.
reflectType = reflectValue.Type().Elem().Elem()
reflectKind = reflectType.Kind()
for reflectKind == reflect.Ptr {
reflectType = reflectType.Elem()
reflectKind = reflectType.Kind()
}
if reflectKind != reflect.Struct {
err = gerror.NewCodef(
gcode.CodeInvalidParameter,
"structSlicePointer should be type of *[]struct/*[]*struct, but got: %v",
reflectKind,
"structSlicePointer should be type of *[]struct/*[]*struct, but got: %s",
reflect.TypeOf(structSlicePointer).String(),
)
return
}
// Find the target field by given name.
structField, ok := reflectType.FieldByName(bindToAttrName)
if !ok {
return nil, gerror.NewCodef(
gcode.CodeInvalidParameter,
`field "%s" not found in element of "%s"`,
bindToAttrName,
reflect.TypeOf(structSlicePointer).String(),
)
}
length := len(result)
// Find the attribute struct type for ORM fields filtering.
reflectType = structField.Type
reflectKind = reflectType.Kind()
for reflectKind == reflect.Ptr {
reflectType = reflectType.Elem()
reflectKind = reflectType.Kind()
}
if reflectKind == reflect.Slice || reflectKind == reflect.Array {
reflectType = reflectType.Elem()
reflectKind = reflectType.Kind()
}
out.BindToAttrType = reflectType
return
}
type doScanListInput struct {
Model *Model
Result Result
StructSlicePointer interface{}
StructSliceValue reflect.Value
BindToAttrName string
RelationAttrName string
RelationFields string
}
// doScanList converts `result` to struct slice which contains other complex struct attributes recursively.
// The parameter `model` is used for recursively scanning purpose, which means, it can scan the attribute struct/structs recursively,
// but it needs the Model for database accessing.
// Note that the parameter `structSlicePointer` should be type of *[]struct/*[]*struct.
func doScanList(in doScanListInput) (err error) {
if in.Result.IsEmpty() {
return nil
}
if in.BindToAttrName == "" {
return gerror.NewCode(gcode.CodeInvalidParameter, `bindToAttrName should not be empty`)
}
length := len(in.Result)
if length == 0 {
// The pointed slice is not empty.
if reflectValue.Len() > 0 {
if in.StructSliceValue.Len() > 0 {
// It here checks if it has struct item, which is already initialized.
// It then returns error to warn the developer its empty and no conversion.
if v := reflectValue.Index(0); v.Kind() != reflect.Ptr {
if v := in.StructSliceValue.Index(0); v.Kind() != reflect.Ptr {
return sql.ErrNoRows
}
}
@ -156,10 +222,10 @@ func doScanList(model *Model, result Result, structSlicePointer interface{}, bin
var (
arrayValue reflect.Value // Like: []*Entity
arrayItemType reflect.Type // Like: *Entity
reflectType = reflect.TypeOf(structSlicePointer)
reflectType = reflect.TypeOf(in.StructSlicePointer)
)
if reflectValue.Len() > 0 {
arrayValue = reflectValue
if in.StructSliceValue.Len() > 0 {
arrayValue = in.StructSliceValue
} else {
arrayValue = reflect.MakeSlice(reflectType.Elem(), length, length)
}
@ -173,17 +239,17 @@ func doScanList(model *Model, result Result, structSlicePointer interface{}, bin
relationFromFieldName string // Eg: relationKV: id:uid -> id
relationBindToFieldName string // Eg: relationKV: id:uid -> uid
)
if len(relationFields) > 0 {
if len(in.RelationFields) > 0 {
// The relation key string of table filed name and attribute name
// can be joined with char '=' or ':'.
array := gstr.SplitAndTrim(relationFields, "=")
array := gstr.SplitAndTrim(in.RelationFields, "=")
if len(array) == 1 {
// Compatible with old splitting char ':'.
array = gstr.SplitAndTrim(relationFields, ":")
array = gstr.SplitAndTrim(in.RelationFields, ":")
}
if len(array) == 1 {
// The relation names are the same.
array = []string{relationFields, relationFields}
array = []string{in.RelationFields, in.RelationFields}
}
if len(array) == 2 {
// Defined table field to relation attribute name.
@ -192,12 +258,12 @@ func doScanList(model *Model, result Result, structSlicePointer interface{}, bin
// uid:UserId
relationFromFieldName = array[0]
relationBindToFieldName = array[1]
if key, _ := gutil.MapPossibleItemByKey(result[0].Map(), relationFromFieldName); key == "" {
if key, _ := gutil.MapPossibleItemByKey(in.Result[0].Map(), relationFromFieldName); key == "" {
return gerror.NewCodef(
gcode.CodeInvalidParameter,
`cannot find possible related table field name "%s" from given relation fields "%s"`,
relationFromFieldName,
relationFields,
in.RelationFields,
)
} else {
relationFromFieldName = key
@ -210,13 +276,13 @@ func doScanList(model *Model, result Result, structSlicePointer interface{}, bin
}
if relationFromFieldName != "" {
// Note that the value might be type of slice.
relationDataMap = result.MapKeyValue(relationFromFieldName)
relationDataMap = in.Result.MapKeyValue(relationFromFieldName)
}
if len(relationDataMap) == 0 {
return gerror.NewCodef(
gcode.CodeInvalidParameter,
`cannot find the relation data map, maybe invalid relation fields given "%v"`,
relationFields,
in.RelationFields,
)
}
}
@ -229,19 +295,19 @@ func doScanList(model *Model, result Result, structSlicePointer interface{}, bin
bindToAttrField reflect.StructField
)
if arrayItemType.Kind() == reflect.Ptr {
if bindToAttrField, ok = arrayItemType.Elem().FieldByName(bindToAttrName); !ok {
if bindToAttrField, ok = arrayItemType.Elem().FieldByName(in.BindToAttrName); !ok {
return gerror.NewCodef(
gcode.CodeInvalidParameter,
`invalid parameter bindToAttrName: cannot find attribute with name "%s" from slice element`,
bindToAttrName,
in.BindToAttrName,
)
}
} else {
if bindToAttrField, ok = arrayItemType.FieldByName(bindToAttrName); !ok {
if bindToAttrField, ok = arrayItemType.FieldByName(in.BindToAttrName); !ok {
return gerror.NewCodef(
gcode.CodeInvalidParameter,
`invalid parameter bindToAttrName: cannot find attribute with name "%s" from slice element`,
bindToAttrName,
in.BindToAttrName,
)
}
}
@ -272,10 +338,10 @@ func doScanList(model *Model, result Result, structSlicePointer interface{}, bin
} else {
// Like: []Entity
}
bindToAttrValue = arrayElemValue.FieldByName(bindToAttrName)
if relationAttrName != "" {
bindToAttrValue = arrayElemValue.FieldByName(in.BindToAttrName)
if in.RelationAttrName != "" {
// Attribute value of current slice element.
relationFromAttrValue = arrayElemValue.FieldByName(relationAttrName)
relationFromAttrValue = arrayElemValue.FieldByName(in.RelationAttrName)
if relationFromAttrValue.Kind() == reflect.Ptr {
relationFromAttrValue = relationFromAttrValue.Elem()
}
@ -284,10 +350,10 @@ func doScanList(model *Model, result Result, structSlicePointer interface{}, bin
relationFromAttrValue = arrayElemValue
}
if len(relationDataMap) > 0 && !relationFromAttrValue.IsValid() {
return gerror.NewCodef(gcode.CodeInvalidParameter, `invalid relation fields specified: "%v"`, relationFields)
return gerror.NewCodef(gcode.CodeInvalidParameter, `invalid relation fields specified: "%v"`, in.RelationFields)
}
// Check and find possible bind to attribute name.
if relationFields != "" && !relationBindToFieldNameChecked {
if in.RelationFields != "" && !relationBindToFieldNameChecked {
relationFromAttrField = relationFromAttrValue.FieldByName(relationBindToFieldName)
if !relationFromAttrField.IsValid() {
filedMap, _ := structs.FieldMap(structs.FieldMapInput{
@ -299,7 +365,7 @@ func doScanList(model *Model, result Result, structSlicePointer interface{}, bin
gcode.CodeInvalidParameter,
`cannot find possible related attribute name "%s" from given relation fields "%s"`,
relationBindToFieldName,
relationFields,
in.RelationFields,
)
} else {
relationBindToFieldName = key
@ -320,20 +386,20 @@ func doScanList(model *Model, result Result, structSlicePointer interface{}, bin
return err
}
// Recursively Scan.
if model != nil {
if err = model.doWithScanStructs(bindToAttrValue.Addr()); err != nil {
if in.Model != nil {
if err = in.Model.doWithScanStructs(bindToAttrValue.Addr()); err != nil {
return nil
}
}
} else {
// Maybe the attribute does not exist yet.
return gerror.NewCodef(gcode.CodeInvalidParameter, `invalid relation fields specified: "%v"`, relationFields)
return gerror.NewCodef(gcode.CodeInvalidParameter, `invalid relation fields specified: "%v"`, in.RelationFields)
}
} else {
return gerror.NewCodef(
gcode.CodeInvalidParameter,
`relationKey should not be empty as field "%s" is slice`,
bindToAttrName,
in.BindToAttrName,
)
}
@ -363,14 +429,14 @@ func doScanList(model *Model, result Result, structSlicePointer interface{}, bin
}
} else {
// Maybe the attribute does not exist yet.
return gerror.NewCodef(gcode.CodeInvalidParameter, `invalid relation fields specified: "%v"`, relationFields)
return gerror.NewCodef(gcode.CodeInvalidParameter, `invalid relation fields specified: "%v"`, in.RelationFields)
}
} else {
if i >= len(result) {
if i >= len(in.Result) {
// There's no relational data.
continue
}
v := result[i]
v := in.Result[i]
if v == nil {
// There's no relational data.
continue
@ -380,8 +446,8 @@ func doScanList(model *Model, result Result, structSlicePointer interface{}, bin
}
}
// Recursively Scan.
if model != nil {
if err = model.doWithScanStruct(element); err != nil {
if in.Model != nil {
if err = in.Model.doWithScanStruct(element); err != nil {
return err
}
}
@ -407,14 +473,14 @@ func doScanList(model *Model, result Result, structSlicePointer interface{}, bin
}
} else {
// Maybe the attribute does not exist yet.
return gerror.NewCodef(gcode.CodeInvalidParameter, `invalid relation fields specified: "%v"`, relationFields)
return gerror.NewCodef(gcode.CodeInvalidParameter, `invalid relation fields specified: "%v"`, in.RelationFields)
}
} else {
if i >= len(result) {
if i >= len(in.Result) {
// There's no relational data.
continue
}
relationDataItem := result[i]
relationDataItem := in.Result[i]
if relationDataItem == nil {
// There's no relational data.
continue
@ -424,8 +490,8 @@ func doScanList(model *Model, result Result, structSlicePointer interface{}, bin
}
}
// Recursively Scan.
if model != nil {
if err = model.doWithScanStruct(bindToAttrValue); err != nil {
if in.Model != nil {
if err = in.Model.doWithScanStruct(bindToAttrValue); err != nil {
return err
}
}
@ -434,6 +500,6 @@ func doScanList(model *Model, result Result, structSlicePointer interface{}, bin
return gerror.NewCodef(gcode.CodeInvalidParameter, `unsupported attribute type: %s`, bindToAttrKind.String())
}
}
reflect.ValueOf(structSlicePointer).Elem().Set(arrayValue)
reflect.ValueOf(in.StructSlicePointer).Elem().Set(arrayValue)
return nil
}

View File

@ -477,6 +477,133 @@ CREATE TABLE %s (
})
}
func Test_Table_Relation_Many_ModelScanList(t *testing.T) {
var (
tableUser = "user_" + gtime.TimestampMicroStr()
tableUserDetail = "user_detail_" + gtime.TimestampMicroStr()
tableUserScores = "user_scores_" + gtime.TimestampMicroStr()
)
if _, err := db.Exec(ctx, fmt.Sprintf(`
CREATE TABLE %s (
uid int(10) unsigned NOT NULL AUTO_INCREMENT,
name varchar(45) NOT NULL,
PRIMARY KEY (uid)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
`, tableUser)); err != nil {
gtest.Error(err)
}
defer dropTable(tableUser)
if _, err := db.Exec(ctx, fmt.Sprintf(`
CREATE TABLE %s (
uid int(10) unsigned NOT NULL AUTO_INCREMENT,
address varchar(45) NOT NULL,
PRIMARY KEY (uid)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
`, tableUserDetail)); err != nil {
gtest.Error(err)
}
defer dropTable(tableUserDetail)
if _, err := db.Exec(ctx, fmt.Sprintf(`
CREATE TABLE %s (
id int(10) unsigned NOT NULL AUTO_INCREMENT,
uid int(10) unsigned NOT NULL,
score int(10) unsigned NOT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
`, tableUserScores)); err != nil {
gtest.Error(err)
}
defer dropTable(tableUserScores)
type EntityUser struct {
Uid int `json:"uid"`
Name string `json:"name"`
}
type EntityUserDetail struct {
Uid int `json:"uid"`
Address string `json:"address"`
}
type EntityUserScores struct {
Id int `json:"id"`
Uid int `json:"uid"`
Score int `json:"score"`
}
type Entity struct {
User *EntityUser
UserDetail *EntityUserDetail
UserScores []*EntityUserScores
}
// Initialize the data.
gtest.C(t, func(t *gtest.T) {
var err error
for i := 1; i <= 5; i++ {
// User.
_, err = db.Insert(ctx, tableUser, g.Map{
"uid": i,
"name": fmt.Sprintf(`name_%d`, i),
})
t.AssertNil(err)
// Detail.
_, err = db.Insert(ctx, tableUserDetail, g.Map{
"uid": i,
"address": fmt.Sprintf(`address_%d`, i),
})
t.AssertNil(err)
// Scores.
for j := 1; j <= 5; j++ {
_, err = db.Insert(ctx, tableUserScores, g.Map{
"uid": i,
"score": j,
})
t.AssertNil(err)
}
}
})
//db.SetDebug(true)
// Result ScanList with struct elements and pointer attributes.
gtest.C(t, func(t *gtest.T) {
var users []Entity
// User
err := db.Model(tableUser).
Where("uid", g.Slice{3, 4}).
Order("uid asc").
ScanList(&users, "User")
t.AssertNil(err)
t.AssertNil(err)
t.Assert(len(users), 2)
t.Assert(users[0].User, &EntityUser{3, "name_3"})
t.Assert(users[1].User, &EntityUser{4, "name_4"})
// Detail
err = db.Model(tableUserDetail).
Where("uid", gdb.ListItemValues(users, "User", "Uid")).
Order("uid asc").
ScanList(&users, "UserDetail", "User", "uid")
t.AssertNil(err)
t.Assert(users[0].UserDetail, &EntityUserDetail{3, "address_3"})
t.Assert(users[1].UserDetail, &EntityUserDetail{4, "address_4"})
// Scores
err = db.Model(tableUserScores).
Where("uid", gdb.ListItemValues(users, "User", "Uid")).
Order("id asc").
ScanList(&users, "UserScores", "User", "uid:Uid")
t.AssertNil(err)
t.Assert(len(users[0].UserScores), 5)
t.Assert(len(users[1].UserScores), 5)
t.Assert(users[0].UserScores[0].Uid, 3)
t.Assert(users[0].UserScores[0].Score, 1)
t.Assert(users[0].UserScores[4].Score, 5)
t.Assert(users[1].UserScores[0].Uid, 4)
t.Assert(users[1].UserScores[0].Score, 1)
t.Assert(users[1].UserScores[4].Score, 5)
})
}
func Test_Table_Relation_Many_RelationKeyCaseInsensitive(t *testing.T) {
var (
tableUser = "user_" + gtime.TimestampMicroStr()

View File

@ -719,10 +719,19 @@ func Test_Model_Count(t *testing.T) {
func Test_Model_Select(t *testing.T) {
table := createInitTable()
defer dropTable(table)
type User struct {
Id int
Passport string
Password string
NickName string
CreateTime gtime.Time
}
gtest.C(t, func(t *gtest.T) {
result, err := db.Model(table).All()
var users []User
err := db.Model(table).Scan(&users)
t.AssertNil(err)
t.Assert(len(result), TableSize)
t.Assert(len(users), TableSize)
})
}

View File

@ -107,7 +107,7 @@ func (r *Request) doParse(pointer interface{}, requestType int) error {
}
}
// Validation.
if err = gvalid.New().Data(pointer, data).Run(r.Context()); err != nil {
if err = gvalid.New().Data(pointer).Assoc(data).Run(r.Context()); err != nil {
return err
}
@ -126,7 +126,7 @@ func (r *Request) doParse(pointer interface{}, requestType int) error {
for i := 0; i < reflectVal2.Len(); i++ {
if err = gvalid.New().
Data(reflectVal2.Index(i), j.Get(gconv.String(i)).Map()).
Data(reflectVal2.Index(i)).Assoc(j.Get(gconv.String(i)).Map()).
Run(r.Context()); err != nil {
return err
}

View File

@ -105,26 +105,33 @@ func (v *Validator) Bail() *Validator {
return newValidator
}
// CaseInsensitive sets the mark for Case-Insensitive for those rules that need value comparison.
func (v *Validator) CaseInsensitive() *Validator {
// Ci sets the mark for Case-Insensitive for those rules that need value comparison.
func (v *Validator) Ci() *Validator {
newValidator := v.Clone()
newValidator.caseInsensitive = true
return newValidator
}
// Data is a chaining operation function, which sets validation data for current operation.
// The optional parameter `assoc` is usually type of map, which specifies the parameter map used in union validation.
// Calling this function with `assoc` also sets `useDataInsteadOfObjectAttributes` true
func (v *Validator) Data(data interface{}, assoc ...interface{}) *Validator {
func (v *Validator) Data(data interface{}) *Validator {
if data == nil {
return v
}
newValidator := v.Clone()
newValidator.data = data
if len(assoc) > 0 {
newValidator.assoc = assoc[0]
newValidator.useDataInsteadOfObjectAttributes = true
return newValidator
}
// Assoc is a chaining operation function, which sets associated validation data for current operation.
// The optional parameter `assoc` is usually type of map, which specifies the parameter map used in union validation.
// Calling this function with `assoc` also sets `useDataInsteadOfObjectAttributes` true
func (v *Validator) Assoc(assoc interface{}) *Validator {
if assoc == nil {
return v
}
newValidator := v.Clone()
newValidator.assoc = assoc
newValidator.useDataInsteadOfObjectAttributes = true
return newValidator
}

View File

@ -550,7 +550,7 @@ func (v *Validator) doCheckValueRecursively(ctx context.Context, in doCheckValue
validator := v.Clone()
validator.rules = nil
validator.messages = nil
if err := validator.Data(reflect.New(in.Type).Interface(), in.Value).Run(ctx); err != nil {
if err := validator.Data(reflect.New(in.Type).Interface()).Assoc(in.Value).Run(ctx); err != nil {
// It merges the errors into single error map.
for k, m := range err.(*validationError).errors {
in.ErrorMaps[k] = m

View File

@ -199,7 +199,7 @@ func ExampleValidator_Rules() {
data := g.Map{
"password": "123",
}
err := g.Validator().Data("", data).
err := g.Validator().Data("").Assoc(data).
Rules("required-with:password").
Messages("请输入确认密码").
Run(gctx.New())
@ -269,7 +269,7 @@ func ExampleValidator_CheckStruct() {
if err := gconv.Scan(data, &user); err != nil {
panic(err)
}
err := g.Validator().Data(user, data).Run(gctx.New())
err := g.Validator().Data(user).Assoc(data).Run(gctx.New())
if err != nil {
fmt.Println(err.Items())
}

View File

@ -414,10 +414,10 @@ func TestValidator_CheckStructWithData(t *testing.T) {
Uid: 1,
Nickname: "john",
}
t.Assert(g.Validator().Data(
data,
g.Map{"uid": 1, "nickname": "john"},
).Run(context.TODO()),
t.Assert(
g.Validator().Data(data).Assoc(
g.Map{"uid": 1, "nickname": "john"},
).Run(context.TODO()),
nil,
)
})
@ -427,7 +427,7 @@ func TestValidator_CheckStructWithData(t *testing.T) {
Nickname string `v:"required-with:uid"`
}
data := UserApiSearch{}
t.AssertNE(g.Validator().Data(data, g.Map{}).Run(context.TODO()), nil)
t.AssertNE(g.Validator().Data(data).Assoc(g.Map{}).Run(context.TODO()), nil)
})
gtest.C(t, func(t *gtest.T) {
type UserApiSearch struct {
@ -437,7 +437,7 @@ func TestValidator_CheckStructWithData(t *testing.T) {
data := UserApiSearch{
Uid: 1,
}
t.AssertNE(g.Validator().Data(data, g.Map{}).Run(context.TODO()), nil)
t.AssertNE(g.Validator().Data(data).Assoc(g.Map{}).Run(context.TODO()), nil)
})
gtest.C(t, func(t *gtest.T) {
@ -451,7 +451,7 @@ func TestValidator_CheckStructWithData(t *testing.T) {
StartTime: nil,
EndTime: nil,
}
t.Assert(g.Validator().Data(data, g.Map{}).Run(context.TODO()), nil)
t.Assert(g.Validator().Data(data).Assoc(g.Map{}).Run(context.TODO()), nil)
})
gtest.C(t, func(t *gtest.T) {
type UserApiSearch struct {
@ -464,6 +464,6 @@ func TestValidator_CheckStructWithData(t *testing.T) {
StartTime: gtime.Now(),
EndTime: nil,
}
t.AssertNE(g.Validator().Data(data, g.Map{"start_time": gtime.Now()}).Run(context.TODO()), nil)
t.AssertNE(g.Validator().Data(data).Assoc(g.Map{"start_time": gtime.Now()}).Run(context.TODO()), nil)
})
}

View File

@ -23,7 +23,7 @@ func Test_CI(t *testing.T) {
t.AssertNil(err)
})
gtest.C(t, func(t *gtest.T) {
err := g.Validator().CaseInsensitive().Rules("in:Id,Name").Data("id").Run(ctx)
err := g.Validator().Ci().Rules("in:Id,Name").Data("id").Run(ctx)
t.AssertNil(err)
})
}

View File

@ -36,7 +36,7 @@ func Test_CustomRule1(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
err := g.Validator().Data("123456").Rules(rule).Messages("custom message").Run(ctx)
t.Assert(err.String(), "custom message")
err = g.Validator().Data("123456", g.Map{"data": "123456"}).Rules(rule).Messages("custom message").Run(ctx)
err = g.Validator().Data("123456").Assoc(g.Map{"data": "123456"}).Rules(rule).Messages("custom message").Run(ctx)
t.Assert(err, nil)
})
// Error with struct validation.
@ -176,7 +176,7 @@ func TestValidator_RuleFunc(t *testing.T) {
err = g.Validator().
Rules(ruleName).
Messages("custom message").
Data("123456", g.Map{"data": "123456"}).
Data("123456").Assoc(g.Map{"data": "123456"}).
RuleFunc(ruleName, ruleFunc).
Run(ctx)
t.AssertNil(err)
@ -232,7 +232,7 @@ func TestValidator_RuleFuncMap(t *testing.T) {
err = g.Validator().
Rules(ruleName).
Messages("custom message").
Data("123456", g.Map{"data": "123456"}).
Data("123456").Assoc(g.Map{"data": "123456"}).
RuleFuncMap(map[string]gvalid.RuleFunc{
ruleName: ruleFunc,
}).Run(ctx)

View File

@ -59,7 +59,7 @@ func Test_CheckStruct_Recursive_Struct_WithData(t *testing.T) {
"Pass2": 200,
},
}
err := g.Validator().Data(user, data).Run(ctx)
err := g.Validator().Data(user).Assoc(data).Run(ctx)
t.AssertNE(err, nil)
t.Assert(err.Maps()["Name"], nil)
t.Assert(err.Maps()["Pass1"], g.Map{"same": "The Pass1 value `100` must be the same as field Pass2"})

View File

@ -44,10 +44,10 @@ func Test_Required(t *testing.T) {
if m := g.Validator().Data("").Rules("required").Messages(nil).Run(ctx); m == nil {
t.Error(m)
}
if m := g.Validator().Data("", map[string]interface{}{"id": 1, "age": 19}).Rules("required-if: id,1,age,18").Messages(nil).Run(ctx); m == nil {
if m := g.Validator().Data("").Assoc(map[string]interface{}{"id": 1, "age": 19}).Rules("required-if: id,1,age,18").Messages(nil).Run(ctx); m == nil {
t.Error("Required校验失败")
}
if m := g.Validator().Data("", map[string]interface{}{"id": 2, "age": 19}).Rules("required-if: id,1,age,18").Messages(nil).Run(ctx); m != nil {
if m := g.Validator().Data("").Assoc(map[string]interface{}{"id": 2, "age": 19}).Rules("required-if: id,1,age,18").Messages(nil).Run(ctx); m != nil {
t.Error("Required校验失败")
}
}
@ -55,20 +55,20 @@ func Test_Required(t *testing.T) {
func Test_RequiredIf(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
rule := "required-if:id,1,age,18"
t.AssertNE(g.Validator().Data("", g.Map{"id": 1}).Rules(rule).Messages(nil).Run(ctx), nil)
t.Assert(g.Validator().Data("", g.Map{"id": 0}).Rules(rule).Messages(nil).Run(ctx), nil)
t.AssertNE(g.Validator().Data("", g.Map{"age": 18}).Rules(rule).Messages(nil).Run(ctx), nil)
t.Assert(g.Validator().Data("", g.Map{"age": 20}).Rules(rule).Messages(nil).Run(ctx), nil)
t.AssertNE(g.Validator().Data("").Assoc(g.Map{"id": 1}).Rules(rule).Messages(nil).Run(ctx), nil)
t.Assert(g.Validator().Data("").Assoc(g.Map{"id": 0}).Rules(rule).Messages(nil).Run(ctx), nil)
t.AssertNE(g.Validator().Data("").Assoc(g.Map{"age": 18}).Rules(rule).Messages(nil).Run(ctx), nil)
t.Assert(g.Validator().Data("").Assoc(g.Map{"age": 20}).Rules(rule).Messages(nil).Run(ctx), nil)
})
}
func Test_RequiredUnless(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
rule := "required-unless:id,1,age,18"
t.Assert(g.Validator().Data("", g.Map{"id": 1}).Rules(rule).Messages(nil).Run(ctx), nil)
t.AssertNE(g.Validator().Data("", g.Map{"id": 0}).Rules(rule).Messages(nil).Run(ctx), nil)
t.Assert(g.Validator().Data("", g.Map{"age": 18}).Rules(rule).Messages(nil).Run(ctx), nil)
t.AssertNE(g.Validator().Data("", g.Map{"age": 20}).Rules(rule).Messages(nil).Run(ctx), nil)
t.Assert(g.Validator().Data("").Assoc(g.Map{"id": 1}).Rules(rule).Messages(nil).Run(ctx), nil)
t.AssertNE(g.Validator().Data("").Assoc(g.Map{"id": 0}).Rules(rule).Messages(nil).Run(ctx), nil)
t.Assert(g.Validator().Data("").Assoc(g.Map{"age": 18}).Rules(rule).Messages(nil).Run(ctx), nil)
t.AssertNE(g.Validator().Data("").Assoc(g.Map{"age": 20}).Rules(rule).Messages(nil).Run(ctx), nil)
})
}
@ -86,9 +86,9 @@ func Test_RequiredWith(t *testing.T) {
"id": 100,
"name": "john",
}
err1 := g.Validator().Data(val1, params1).Rules(rule).Messages(nil).Run(ctx)
err2 := g.Validator().Data(val1, params2).Rules(rule).Messages(nil).Run(ctx)
err3 := g.Validator().Data(val1, params3).Rules(rule).Messages(nil).Run(ctx)
err1 := g.Validator().Data(val1).Assoc(params1).Rules(rule).Messages(nil).Run(ctx)
err2 := g.Validator().Data(val1).Assoc(params2).Rules(rule).Messages(nil).Run(ctx)
err3 := g.Validator().Data(val1).Assoc(params3).Rules(rule).Messages(nil).Run(ctx)
t.Assert(err1, nil)
t.AssertNE(err2, nil)
t.AssertNE(err3, nil)
@ -106,9 +106,9 @@ func Test_RequiredWith(t *testing.T) {
params3 := g.Map{
"time": time.Time{},
}
err1 := g.Validator().Data(val1, params1).Rules(rule).Messages(nil).Run(ctx)
err2 := g.Validator().Data(val1, params2).Rules(rule).Messages(nil).Run(ctx)
err3 := g.Validator().Data(val1, params3).Rules(rule).Messages(nil).Run(ctx)
err1 := g.Validator().Data(val1).Assoc(params1).Rules(rule).Messages(nil).Run(ctx)
err2 := g.Validator().Data(val1).Assoc(params2).Rules(rule).Messages(nil).Run(ctx)
err3 := g.Validator().Data(val1).Assoc(params3).Rules(rule).Messages(nil).Run(ctx)
t.Assert(err1, nil)
t.AssertNE(err2, nil)
t.Assert(err3, nil)
@ -125,9 +125,9 @@ func Test_RequiredWith(t *testing.T) {
params3 := g.Map{
"time": time.Now(),
}
err1 := g.Validator().Data(val1, params1).Rules(rule).Messages(nil).Run(ctx)
err2 := g.Validator().Data(val1, params2).Rules(rule).Messages(nil).Run(ctx)
err3 := g.Validator().Data(val1, params3).Rules(rule).Messages(nil).Run(ctx)
err1 := g.Validator().Data(val1).Assoc(params1).Rules(rule).Messages(nil).Run(ctx)
err2 := g.Validator().Data(val1).Assoc(params2).Rules(rule).Messages(nil).Run(ctx)
err3 := g.Validator().Data(val1).Assoc(params3).Rules(rule).Messages(nil).Run(ctx)
t.Assert(err1, nil)
t.AssertNE(err2, nil)
t.AssertNE(err3, nil)
@ -175,9 +175,9 @@ func Test_RequiredWithAll(t *testing.T) {
"id": 100,
"name": "john",
}
err1 := g.Validator().Data(val1, params1).Rules(rule).Messages(nil).Run(ctx)
err2 := g.Validator().Data(val1, params2).Rules(rule).Messages(nil).Run(ctx)
err3 := g.Validator().Data(val1, params3).Rules(rule).Messages(nil).Run(ctx)
err1 := g.Validator().Data(val1).Assoc(params1).Rules(rule).Messages(nil).Run(ctx)
err2 := g.Validator().Data(val1).Assoc(params2).Rules(rule).Messages(nil).Run(ctx)
err3 := g.Validator().Data(val1).Assoc(params3).Rules(rule).Messages(nil).Run(ctx)
t.Assert(err1, nil)
t.Assert(err2, nil)
t.AssertNE(err3, nil)
@ -198,9 +198,9 @@ func Test_RequiredWithOut(t *testing.T) {
"id": 100,
"name": "john",
}
err1 := g.Validator().Data(val1, params1).Rules(rule).Messages(nil).Run(ctx)
err2 := g.Validator().Data(val1, params2).Rules(rule).Messages(nil).Run(ctx)
err3 := g.Validator().Data(val1, params3).Rules(rule).Messages(nil).Run(ctx)
err1 := g.Validator().Data(val1).Assoc(params1).Rules(rule).Messages(nil).Run(ctx)
err2 := g.Validator().Data(val1).Assoc(params2).Rules(rule).Messages(nil).Run(ctx)
err3 := g.Validator().Data(val1).Assoc(params3).Rules(rule).Messages(nil).Run(ctx)
t.AssertNE(err1, nil)
t.AssertNE(err2, nil)
t.Assert(err3, nil)
@ -221,9 +221,9 @@ func Test_RequiredWithOutAll(t *testing.T) {
"id": 100,
"name": "john",
}
err1 := g.Validator().Data(val1, params1).Rules(rule).Messages(nil).Run(ctx)
err2 := g.Validator().Data(val1, params2).Rules(rule).Messages(nil).Run(ctx)
err3 := g.Validator().Data(val1, params3).Rules(rule).Messages(nil).Run(ctx)
err1 := g.Validator().Data(val1).Assoc(params1).Rules(rule).Messages(nil).Run(ctx)
err2 := g.Validator().Data(val1).Assoc(params2).Rules(rule).Messages(nil).Run(ctx)
err3 := g.Validator().Data(val1).Assoc(params3).Rules(rule).Messages(nil).Run(ctx)
t.AssertNE(err1, nil)
t.Assert(err2, nil)
t.Assert(err3, nil)
@ -914,9 +914,9 @@ func Test_Same(t *testing.T) {
"id": 100,
"name": "john",
}
err1 := g.Validator().Data(val1, params1).Rules(rule).Messages(nil).Run(ctx)
err2 := g.Validator().Data(val1, params2).Rules(rule).Messages(nil).Run(ctx)
err3 := g.Validator().Data(val1, params3).Rules(rule).Messages(nil).Run(ctx)
err1 := g.Validator().Data(val1).Assoc(params1).Rules(rule).Messages(nil).Run(ctx)
err2 := g.Validator().Data(val1).Assoc(params2).Rules(rule).Messages(nil).Run(ctx)
err3 := g.Validator().Data(val1).Assoc(params3).Rules(rule).Messages(nil).Run(ctx)
t.AssertNE(err1, nil)
t.Assert(err2, nil)
t.Assert(err3, nil)
@ -937,9 +937,9 @@ func Test_Different(t *testing.T) {
"id": 100,
"name": "john",
}
err1 := g.Validator().Data(val1, params1).Rules(rule).Messages(nil).Run(ctx)
err2 := g.Validator().Data(val1, params2).Rules(rule).Messages(nil).Run(ctx)
err3 := g.Validator().Data(val1, params3).Rules(rule).Messages(nil).Run(ctx)
err1 := g.Validator().Data(val1).Assoc(params1).Rules(rule).Messages(nil).Run(ctx)
err2 := g.Validator().Data(val1).Assoc(params2).Rules(rule).Messages(nil).Run(ctx)
err3 := g.Validator().Data(val1).Assoc(params3).Rules(rule).Messages(nil).Run(ctx)
t.Assert(err1, nil)
t.AssertNE(err2, nil)
t.AssertNE(err3, nil)