From 73512fad590ffaca4af5c4eb288f5aec23968ed4 Mon Sep 17 00:00:00 2001 From: E99p1ant Date: Sun, 18 Aug 2024 00:51:31 +0800 Subject: [PATCH] checker: nested struct validation --- checker_test.go | 60 +++++++++++++++++++++++++++++++++++++++++++++++++ govalid.go | 10 ++++++--- parser.go | 8 ++++++- 3 files changed, 74 insertions(+), 4 deletions(-) diff --git a/checker_test.go b/checker_test.go index 186af5f..a7c4bc1 100644 --- a/checker_test.go +++ b/checker_test.go @@ -737,3 +737,63 @@ func Test_UserDefinedError(t *testing.T) { assert.Equal(t, "是错误的年龄呢~", errs[0].Error()) }) } + +func Test_NestedStruct(t *testing.T) { + type order struct { + FieldUID string `valid:"required"` + OrderType string `valid:"list:asc,desc"` + } + + type view struct { + Field string `valid:"required"` + Order order + } + + t.Run("ok", func(t *testing.T) { + v := view{ + Field: "name", + Order: order{ + FieldUID: "name", + OrderType: "asc", + }, + } + + errs, ok := Check(v) + assert.True(t, ok) + assert.Equal(t, 0, len(errs)) + }) + + t.Run("unexpected orderType", func(t *testing.T) { + v := view{ + Field: "name", + Order: order{ + FieldUID: "name", + OrderType: "123", + }, + } + + errs, ok := Check(v) + assert.False(t, ok) + assert.Equal(t, 1, len(errs)) + assert.Equal(t, "OrderType不是一个有效的值", errs[0].Error()) + }) + + t.Run("nested with tag", func(t *testing.T) { + type view struct { + Field string `valid:"required"` + Order order `valid:"required"` + } + + v := view{ + Field: "name", + Order: order{ + FieldUID: "name", + OrderType: "asc", + }, + } + + errs, ok := Check(v) + assert.True(t, ok) + assert.Equal(t, 0, len(errs)) + }) +} diff --git a/govalid.go b/govalid.go index 1abb8b8..6cfb986 100644 --- a/govalid.go +++ b/govalid.go @@ -1,8 +1,9 @@ package govalid import ( - "golang.org/x/text/language" "reflect" + + "golang.org/x/text/language" ) // Check checks the struct value. @@ -23,10 +24,13 @@ func Check(v interface{}, lang ...language.Tag) (errs []*ErrContext, ok bool) { structFields := parseStruct(structType, structValue, templateLanguage) for _, field := range structFields { + field := field + fieldErrorMessage := field.errorMessage - for _, r := range field.rules { - rule := r + for _, rule := range field.rules { + rule := rule + checkerName := rule.checker checkerContext := CheckerContext{ StructValue: structValue, diff --git a/parser.go b/parser.go index f27579d..dee1658 100644 --- a/parser.go +++ b/parser.go @@ -1,9 +1,10 @@ package govalid import ( - "golang.org/x/text/language" "reflect" "strings" + + "golang.org/x/text/language" ) var ( @@ -52,6 +53,11 @@ func parseStruct(structType reflect.Type, structValue reflect.Value, languageTag } } + // Check if the field is a struct. + if field.Type.Kind() == reflect.Struct { + fields = append(fields, parseStruct(field.Type, structValue.Field(i), languageTag)...) + } + // Check if this field has a validator tag. rawRules, ok := field.Tag.Lookup(RulesField) if !ok {