Skip to content

Commit

Permalink
fix: Multi-level nested slices, array, map
Browse files Browse the repository at this point in the history
Change-Id: I69e3b7fcf0143f6a1be50f3df08dbacfe753539c
  • Loading branch information
andeya committed Jul 30, 2019
1 parent 803d3df commit 43be00e
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 16 deletions.
41 changes: 27 additions & 14 deletions tagexpr.go
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,7 @@ func (vm *VM) registerStructLocked(structType reflect.Type) (*structVM, error) {
return s, nil
}
s = vm.newStructVM()
s.name = structType.String()
vm.structJar[tid] = s
var numField = structType.NumField()
var structField reflect.StructField
Expand Down Expand Up @@ -306,7 +307,9 @@ func (vm *VM) registerIndirectStructLocked(field *fieldVM) error {
if err != nil {
return err
}
if len(s.exprSelectorList) > 0 || len(s.ifaceTagExprGetters) > 0 {
if len(s.exprSelectorList) > 0 ||
len(s.ifaceTagExprGetters) > 0 ||
len(s.fieldsWithIndirectStructVM) > 0 {
if i == 0 {
field.mapOrSliceElemStructVM = s
} else {
Expand Down Expand Up @@ -393,11 +396,19 @@ func (s *structVM) mergeSubStructVM(field *fieldVM, sub *structVM) {
}
for _, k := range sub.fieldSelectorList {
v := sub.fields[k]
f := s.newChildField(field, v)
f := s.newChildField(field, v, true)
if _, ok := fieldsWithIndirectStructVM[v]; ok {
s.fieldsWithIndirectStructVM = append(s.fieldsWithIndirectStructVM, f)
// TODO: maybe needed?
// delete(fieldsWithIndirectStructVM, v)
}
}
// TODO: maybe needed?
// for v := range fieldsWithIndirectStructVM {
// f := s.newChildField(field, v, false)
// s.fieldsWithIndirectStructVM = append(s.fieldsWithIndirectStructVM, f)
// }

for _, _subFn := range sub.ifaceTagExprGetters {
subFn := _subFn
s.ifaceTagExprGetters = append(s.ifaceTagExprGetters, func(ptr unsafe.Pointer, pathPrefix string, fn func(*TagExpr, error) error) error {
Expand All @@ -416,7 +427,7 @@ func (s *structVM) mergeSubStructVM(field *fieldVM, sub *structVM) {
}
}

func (s *structVM) newChildField(parent *fieldVM, child *fieldVM) *fieldVM {
func (s *structVM) newChildField(parent *fieldVM, child *fieldVM, toBind bool) *fieldVM {
f := &fieldVM{
structField: child.structField,
exprs: make(map[string]*Expr, len(child.exprs)),
Expand All @@ -429,29 +440,18 @@ func (s *structVM) newChildField(parent *fieldVM, child *fieldVM) *fieldVM {
mapOrSliceIfaceKinds: child.mapOrSliceIfaceKinds,
fieldSelector: parent.fieldSelector + FieldSeparator + child.fieldSelector,
}
s.fields[f.fieldSelector] = f
s.fieldSelectorList = append(s.fieldSelectorList, f.fieldSelector)

if parent.tagOp != tagOmit {
f.tagOp = child.tagOp
for k, v := range child.exprs {
selector := parent.fieldSelector + FieldSeparator + k
f.exprs[selector] = v
s.exprs[selector] = v
s.exprSelectorList = append(s.exprSelectorList, selector)
}
} else {
f.tagOp = parent.tagOp
}

f.getPtr = func(ptr unsafe.Pointer) unsafe.Pointer {
ptr = parent.getElemPtr(ptr)
if ptr == nil {
return nil
}
return child.getPtr(ptr)
}

if child.valueGetter != nil {
if parent.ptrDeep == 0 {
f.valueGetter = func(ptr unsafe.Pointer) interface{} {
Expand Down Expand Up @@ -486,6 +486,19 @@ func (s *structVM) newChildField(parent *fieldVM, child *fieldVM) *fieldVM {
}
}
}

if toBind {
s.fields[f.fieldSelector] = f
s.fieldSelectorList = append(s.fieldSelectorList, f.fieldSelector)
if parent.tagOp != tagOmit {
for k, v := range child.exprs {
selector := parent.fieldSelector + FieldSeparator + k
f.exprs[selector] = v
s.exprs[selector] = v
s.exprSelectorList = append(s.exprSelectorList, selector)
}
}
}
return f
}

Expand Down
5 changes: 3 additions & 2 deletions validator/validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,15 +76,16 @@ func (v *Validator) Validate(value interface{}, checkAll ...bool) error {
return io.EOF
}
err = te.Range(func(path string, es tagexpr.ExprSelector, eval func() interface{}) error {
if strings.Contains(path, tagexpr.ExprNameSeparator) {
s := es.String()
if strings.Contains(s, tagexpr.ExprNameSeparator) {
return nil
}
valid := tagexpr.FakeBool(eval())
if valid {
return nil
}
errInfos = append(errInfos, &ErrInfo{
selector: es.String(),
selector: s,
path: path,
te: te,
})
Expand Down
42 changes: 42 additions & 0 deletions validator/validator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,45 @@ func TestAll(t *testing.T) {
}
assert.EqualError(t, vd.Validate(new(T), true), "invalid parameter: a\tinvalid parameter: f.g")
}

func TestIssue(t *testing.T) {
type MailBox struct {
Address *string `vd:"email($)"`
Name *string
}
type EmailMsg struct {
Recipients []*MailBox
RecipientsCc []*MailBox
RecipientsBcc []*MailBox
Subject *string
Content *string
AttachmentIDList []string
ReplyTo *string
Params map[string]string
FromEmailAddress *string
FromEmailName *string
}
type EmailTaskInfo struct {
Msg *EmailMsg
StartTimeMS *int64
LogTag *string
}
type BatchCreateEmailTaskRequest struct {
InfoList []*EmailTaskInfo
}
var invalid = "invalid email"
req := &BatchCreateEmailTaskRequest{
InfoList: []*EmailTaskInfo{
{
Msg: &EmailMsg{
Recipients: []*MailBox{
{
Address: &invalid,
},
},
},
},
},
}
t.Log(vd.Validate(req, true))
}

0 comments on commit 43be00e

Please sign in to comment.