Skip to content

Commit d9c7865

Browse files
author
Dean Karn
authored
Fix dive only (#7)
1 parent cad431a commit d9c7865

File tree

5 files changed

+138
-64
lines changed

5 files changed

+138
-64
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Package mold
22
============
3-
![Project status](https://img.shields.io/badge/version-3.0.0-green.svg)
3+
![Project status](https://img.shields.io/badge/version-3.0.1-green.svg)
44
[![Build Status](https://travis-ci.org/go-playground/mold.svg?branch=v2)](https://travis-ci.org/go-playground/mold)
55
[![Coverage Status](https://coveralls.io/repos/github/go-playground/mold/badge.svg?branch=v2)](https://coveralls.io/github/go-playground/mold?branch=v2)
66
[![Go Report Card](https://goreportcard.com/badge/github.com/go-playground/mold)](https://goreportcard.com/report/github.com/go-playground/mold)

_examples/full/main.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import (
1111
"github.com/go-playground/mold/v3/modifiers"
1212
"github.com/go-playground/mold/v3/scrubbers"
1313

14-
"gopkg.in/go-playground/validator.v9"
14+
"github.com/go-playground/validator/v10"
1515
)
1616

1717
// This example is centered around a form post, but doesn't have to be

go.sum

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
github.com/go-playground/assert v1.2.1 h1:ad06XqC+TOv0nJWnbULSlh3ehp5uLuQEojZY5Tq8RgI=
21
github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A=
32
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
43
github.com/segmentio/go-snakecase v1.2.0 h1:4cTmEjPGi03WmyAHWBjX53viTpBkn/z+4DO++fqYvpw=

mold.go

Lines changed: 58 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import (
1010

1111
var (
1212
timeType = reflect.TypeOf(time.Time{})
13-
defaultCField = &cField{}
1413
restrictedAliasErr = "Alias '%s' either contains restricted characters or is the same as a restricted tag needed for normal operation"
1514
restrictedTagErr = "Tag '%s' either contains restricted characters or is the same as a restricted tag needed for normal operation"
1615
)
@@ -76,7 +75,6 @@ func (t *Transformer) Register(tag string, fn Func) {
7675
if ok || strings.ContainsAny(tag, restrictedTagChars) {
7776
panic(fmt.Sprintf(restrictedTagErr, tag))
7877
}
79-
8078
t.transformations[tag] = fn
8179
}
8280

@@ -132,11 +130,10 @@ func (t *Transformer) Struct(ctx context.Context, v interface{}) error {
132130
if val.Kind() != reflect.Struct || val.Type() == timeType {
133131
return &ErrInvalidTransformation{typ: reflect.TypeOf(v)}
134132
}
135-
136-
return t.setByStruct(ctx, val, typ, nil)
133+
return t.setByStruct(ctx, val, typ)
137134
}
138135

139-
func (t *Transformer) setByStruct(ctx context.Context, current reflect.Value, typ reflect.Type, ct *cTag) (err error) {
136+
func (t *Transformer) setByStruct(ctx context.Context, current reflect.Value, typ reflect.Type) (err error) {
140137
cs, ok := t.cCache.Get(typ)
141138
if !ok {
142139
if cs, err = t.extractStructCache(current); err != nil {
@@ -155,7 +152,7 @@ func (t *Transformer) setByStruct(ctx context.Context, current reflect.Value, ty
155152

156153
for i := 0; i < len(cs.fields); i++ {
157154
f = cs.fields[i]
158-
if err = t.setByField(ctx, current.Field(f.idx), f, f.cTags); err != nil {
155+
if err = t.setByField(ctx, current.Field(f.idx), f.cTags); err != nil {
159156
return
160157
}
161158
}
@@ -192,19 +189,15 @@ func (t *Transformer) Field(ctx context.Context, v interface{}, tags string) (er
192189
}
193190
t.tCache.lock.Unlock()
194191
}
195-
err = t.setByField(ctx, val, defaultCField, ctag)
192+
err = t.setByField(ctx, val, ctag)
196193
return
197194
}
198195

199-
func (t *Transformer) setByField(ctx context.Context, orig reflect.Value, cf *cField, ct *cTag) (err error) {
196+
func (t *Transformer) setByField(ctx context.Context, orig reflect.Value, ct *cTag) (err error) {
200197
current, kind := extractType(orig)
201198

202-
if ct.hasTag {
203-
for {
204-
if ct == nil {
205-
break
206-
}
207-
199+
if ct != nil && ct.hasTag {
200+
for ct != nil {
208201
switch ct.typeof {
209202
case typeEndKeys:
210203
return
@@ -213,52 +206,9 @@ func (t *Transformer) setByField(ctx context.Context, orig reflect.Value, cf *cF
213206

214207
switch kind {
215208
case reflect.Slice, reflect.Array:
216-
reusableCF := &cField{}
217-
218-
for i := 0; i < current.Len(); i++ {
219-
if err = t.setByField(ctx, current.Index(i), reusableCF, ct); err != nil {
220-
return
221-
}
222-
}
223-
209+
err = t.setByIterable(ctx, current, ct)
224210
case reflect.Map:
225-
reusableCF := &cField{}
226-
227-
hasKeys := ct != nil && ct.typeof == typeKeys && ct.keys != nil
228-
229-
for _, key := range current.MapKeys() {
230-
newVal := reflect.New(current.Type().Elem()).Elem()
231-
newVal.Set(current.MapIndex(key))
232-
233-
if hasKeys {
234-
235-
// remove current map key as we may be changing it
236-
// and re-add to the map afterwards
237-
current.SetMapIndex(key, reflect.Value{})
238-
239-
newKey := reflect.New(current.Type().Key()).Elem()
240-
newKey.Set(key)
241-
key = newKey
242-
243-
// handle map key
244-
if err = t.setByField(ctx, key, reusableCF, ct.keys); err != nil {
245-
return
246-
}
247-
248-
// can be nil when just keys being validated
249-
if ct.next != nil {
250-
if err = t.setByField(ctx, newVal, reusableCF, ct.next); err != nil {
251-
return
252-
}
253-
}
254-
} else {
255-
if err = t.setByField(ctx, newVal, reusableCF, ct); err != nil {
256-
return
257-
}
258-
}
259-
current.SetMapIndex(key, newVal)
260-
}
261-
211+
err = t.setByMap(ctx, current, ct)
262212
default:
263213
err = ErrInvalidDive
264214
}
@@ -300,13 +250,60 @@ func (t *Transformer) setByField(ctx context.Context, orig reflect.Value, cf *cF
300250
newVal := reflect.New(typ).Elem()
301251
newVal.Set(current)
302252

303-
if err = t.setByStruct(ctx, newVal, typ, ct); err != nil {
253+
if err = t.setByStruct(ctx, newVal, typ); err != nil {
304254
return
305255
}
306256
orig.Set(newVal)
307257
return
308258
}
309-
err = t.setByStruct(ctx, current, typ, ct)
259+
err = t.setByStruct(ctx, current, typ)
260+
}
261+
return
262+
}
263+
264+
func (t *Transformer) setByIterable(ctx context.Context, current reflect.Value, ct *cTag) (err error) {
265+
for i := 0; i < current.Len(); i++ {
266+
if err = t.setByField(ctx, current.Index(i), ct); err != nil {
267+
return
268+
}
310269
}
311270
return
312271
}
272+
273+
func (t *Transformer) setByMap(ctx context.Context, current reflect.Value, ct *cTag) error {
274+
hasKeys := ct != nil && ct.typeof == typeKeys && ct.keys != nil
275+
276+
for _, key := range current.MapKeys() {
277+
newVal := reflect.New(current.Type().Elem()).Elem()
278+
newVal.Set(current.MapIndex(key))
279+
280+
if hasKeys {
281+
// remove current map key as we may be changing it
282+
// and re-add to the map afterwards
283+
current.SetMapIndex(key, reflect.Value{})
284+
285+
newKey := reflect.New(current.Type().Key()).Elem()
286+
newKey.Set(key)
287+
key = newKey
288+
289+
// handle map key
290+
if err := t.setByField(ctx, key, ct.keys); err != nil {
291+
return err
292+
}
293+
294+
// can be nil when just keys being validated
295+
if ct.next != nil {
296+
if err := t.setByField(ctx, newVal, ct.next); err != nil {
297+
return err
298+
}
299+
}
300+
} else {
301+
if err := t.setByField(ctx, newVal, ct); err != nil {
302+
return err
303+
}
304+
}
305+
current.SetMapIndex(key, newVal)
306+
}
307+
308+
return nil
309+
}

mold_test.go

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -601,3 +601,81 @@ func TestDiveKeys(t *testing.T) {
601601
err = set.Field(context.Background(), &m, "dive,keys,default,endkeys,err")
602602
NotEqual(t, err, nil)
603603
}
604+
605+
func TestStructArray(t *testing.T) {
606+
type InnerStruct struct {
607+
String string `s:"defaultStr"`
608+
}
609+
610+
type Test struct {
611+
Inner InnerStruct
612+
Arr []InnerStruct `s:"defaultArr"`
613+
ArrDive []InnerStruct `s:"defaultArr,dive"`
614+
ArrNoTag []InnerStruct
615+
}
616+
617+
set := New()
618+
set.SetTagName("s")
619+
set.Register("defaultArr", func(ctx context.Context, t *Transformer, value reflect.Value, param string) error {
620+
if HasValue(value) {
621+
return nil
622+
}
623+
value.Set(reflect.MakeSlice(value.Type(), 2, 2))
624+
return nil
625+
})
626+
set.Register("defaultStr", func(ctx context.Context, t *Transformer, value reflect.Value, param string) error {
627+
if value.String() == "ok" {
628+
return errors.New("ALREADY OK")
629+
}
630+
value.SetString("default")
631+
return nil
632+
})
633+
634+
var tt Test
635+
636+
err := set.Struct(context.Background(), &tt)
637+
Equal(t, err, nil)
638+
Equal(t, len(tt.Arr), 2)
639+
Equal(t, len(tt.ArrDive), 2)
640+
Equal(t, tt.Arr[0].String, "")
641+
Equal(t, tt.Arr[1].String, "")
642+
Equal(t, tt.ArrDive[0].String, "default")
643+
Equal(t, tt.ArrDive[1].String, "default")
644+
645+
Equal(t, tt.Inner.String, "default")
646+
647+
tt2 := Test{
648+
Arr: make([]InnerStruct, 1),
649+
}
650+
651+
err = set.Struct(context.Background(), &tt2)
652+
Equal(t, err, nil)
653+
Equal(t, len(tt2.Arr), 1)
654+
Equal(t, tt2.Arr[0].String, "")
655+
656+
tt3 := Test{
657+
Arr: []InnerStruct{{"ok"}},
658+
}
659+
660+
err = set.Struct(context.Background(), &tt3)
661+
Equal(t, err, nil)
662+
Equal(t, len(tt3.Arr), 1)
663+
Equal(t, tt3.Arr[0].String, "ok")
664+
665+
tt4 := Test{
666+
ArrDive: []InnerStruct{{"ok"}},
667+
}
668+
669+
err = set.Struct(context.Background(), &tt4)
670+
NotEqual(t, err, nil)
671+
Equal(t, err.Error(), "ALREADY OK")
672+
673+
tt5 := Test{
674+
ArrNoTag: make([]InnerStruct, 1),
675+
}
676+
677+
err = set.Struct(context.Background(), &tt5)
678+
Equal(t, err, nil)
679+
Equal(t, len(tt5.ArrNoTag), 1)
680+
Equal(t, tt5.ArrNoTag[0].String, "")
681+
}

0 commit comments

Comments
 (0)