Skip to content

Commit

Permalink
Enhanced ValidationCtx method to support nested map in slice #915 (#917)
Browse files Browse the repository at this point in the history
  • Loading branch information
leftjs committed May 1, 2022
1 parent 99922fc commit d3e4be3
Show file tree
Hide file tree
Showing 3 changed files with 122 additions and 8 deletions.
14 changes: 14 additions & 0 deletions _examples/map-validation/main.go
Expand Up @@ -48,6 +48,16 @@ func validateNestedMap() {
"mother_name": "Hannah",
},
"salary": "1000",
"phones": []map[string]interface{}{
{
"number": "11-111-1111",
"remark": "home",
},
{
"number": "22-222-2222",
"remark": "work",
},
},
},
}

Expand All @@ -62,6 +72,10 @@ func validateNestedMap() {
"mother_name": "required,min=4,max=32",
},
"salary": "number",
"phones": map[string]interface{}{
"number": "required,min=4,max=32",
"remark": "required,min=1,max=32",
},
},
}

Expand Down
25 changes: 17 additions & 8 deletions validator_instance.go
Expand Up @@ -154,15 +154,24 @@ func (v *Validate) SetTagName(name string) {
func (v Validate) ValidateMapCtx(ctx context.Context, data map[string]interface{}, rules map[string]interface{}) map[string]interface{} {
errs := make(map[string]interface{})
for field, rule := range rules {
if reflect.ValueOf(rule).Kind() == reflect.Map && reflect.ValueOf(data[field]).Kind() == reflect.Map {
err := v.ValidateMapCtx(ctx, data[field].(map[string]interface{}), rule.(map[string]interface{}))
if len(err) > 0 {
errs[field] = err
if ruleObj, ok := rule.(map[string]interface{}); ok {
if dataObj, ok := data[field].(map[string]interface{}); ok {
err := v.ValidateMapCtx(ctx, dataObj, ruleObj)
if len(err) > 0 {
errs[field] = err
}
} else if dataObjs, ok := data[field].([]map[string]interface{}); ok {
for _, obj := range dataObjs {
err := v.ValidateMapCtx(ctx, obj, ruleObj)
if len(err) > 0 {
errs[field] = err
}
}
} else {
errs[field] = errors.New("The field: '" + field + "' is not a map to dive")
}
} else if reflect.ValueOf(rule).Kind() == reflect.Map {
errs[field] = errors.New("The field: '" + field + "' is not a map to dive")
} else {
err := v.VarCtx(ctx, data[field], rule.(string))
} else if ruleStr, ok := rule.(string); ok {
err := v.VarCtx(ctx, data[field], ruleStr)
if err != nil {
errs[field] = err
}
Expand Down
91 changes: 91 additions & 0 deletions validator_test.go
Expand Up @@ -12134,6 +12134,97 @@ func TestPostCodeByIso3166Alpha2Field_InvalidKind(t *testing.T) {
t.Errorf("Didn't panic as expected")
}

func TestValidate_ValidateMapCtx(t *testing.T) {

type args struct {
data map[string]interface{}
rules map[string]interface{}
}
tests := []struct {
name string
args args
want int
}{
{
name: "test nested map in slice",
args: args{
data: map[string]interface{}{
"Test_A": map[string]interface{}{
"Test_B": "Test_B",
"Test_C": []map[string]interface{}{
{
"Test_D": "Test_D",
},
},
"Test_E": map[string]interface{}{
"Test_F": "Test_F",
},
},
},
rules: map[string]interface{}{
"Test_A": map[string]interface{}{
"Test_B": "min=2",
"Test_C": map[string]interface{}{
"Test_D": "min=2",
},
"Test_E": map[string]interface{}{
"Test_F": "min=2",
},
},
},
},
want: 0,
},

{
name: "test nested map error",
args: args{
data: map[string]interface{}{
"Test_A": map[string]interface{}{
"Test_B": "Test_B",
"Test_C": []interface{}{"Test_D"},
"Test_E": map[string]interface{}{
"Test_F": "Test_F",
},
"Test_G": "Test_G",
"Test_I": []map[string]interface{}{
{
"Test_J": "Test_J",
},
},
},
},
rules: map[string]interface{}{
"Test_A": map[string]interface{}{
"Test_B": "min=2",
"Test_C": map[string]interface{}{
"Test_D": "min=2",
},
"Test_E": map[string]interface{}{
"Test_F": "min=100",
},
"Test_G": map[string]interface{}{
"Test_H": "min=2",
},
"Test_I": map[string]interface{}{
"Test_J": "min=100",
},
},
},
},
want: 1,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
validate := New()
if got := validate.ValidateMapCtx(context.Background(), tt.args.data, tt.args.rules); len(got) != tt.want {
t.Errorf("ValidateMapCtx() = %v, want %v", got, tt.want)
}
})
}
}

func TestCreditCardFormatValidation(t *testing.T) {
tests := []struct {
value string `validate:"credit_card"`
Expand Down

0 comments on commit d3e4be3

Please sign in to comment.