Skip to content

Commit 132bcfc

Browse files
committed
sync dynamodbstreams attributevalue
1 parent 09a54db commit 132bcfc

File tree

9 files changed

+409
-87
lines changed

9 files changed

+409
-87
lines changed

feature/dynamodbstreams/attributevalue/decode.go

Lines changed: 50 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,18 @@ import (
1616
// Value int
1717
// }
1818
//
19-
// func (u *exampleUnmarshaler) UnmarshalDynamoDBStreamsAttributeValue(av *types.AttributeValue) error {
20-
// if av.N == nil {
19+
// func (u *ExampleUnmarshaler) UnmarshalDynamoDBStreamsAttributeValue(av types.AttributeValue) error {
20+
// avN, ok := av.(*types.AttributeValueMemberN)
21+
// if !ok {
2122
// return nil
2223
// }
2324
//
24-
// n, err := strconv.ParseInt(*av.N, 10, 0)
25+
// n, err := strconv.ParseInt(avN.Value, 10, 0)
2526
// if err != nil {
2627
// return err
2728
// }
2829
//
29-
// u.Value = n
30+
// u.Value = int(n)
3031
// return nil
3132
// }
3233
type Unmarshaler interface {
@@ -271,6 +272,8 @@ func (d *Decoder) decodeBool(b bool, v reflect.Value) error {
271272
}
272273

273274
func (d *Decoder) decodeBinarySet(bs [][]byte, v reflect.Value) error {
275+
var isArray bool
276+
274277
switch v.Kind() {
275278
case reflect.Slice:
276279
// Make room for the slice elements if needed
@@ -280,6 +283,7 @@ func (d *Decoder) decodeBinarySet(bs [][]byte, v reflect.Value) error {
280283
}
281284
case reflect.Array:
282285
// Limited to capacity of existing array.
286+
isArray = true
283287
case reflect.Interface:
284288
set := make([][]byte, len(bs))
285289
for i, b := range bs {
@@ -294,7 +298,9 @@ func (d *Decoder) decodeBinarySet(bs [][]byte, v reflect.Value) error {
294298
}
295299

296300
for i := 0; i < v.Cap() && i < len(bs); i++ {
297-
v.SetLen(i + 1)
301+
if !isArray {
302+
v.SetLen(i + 1)
303+
}
298304
u, elem := indirect(v.Index(i), false)
299305
if u != nil {
300306
return u.UnmarshalDynamoDBStreamsAttributeValue(&types.AttributeValueMemberBS{Value: bs})
@@ -383,6 +389,8 @@ func (d *Decoder) decodeNumberToInterface(n string) (interface{}, error) {
383389
}
384390

385391
func (d *Decoder) decodeNumberSet(ns []string, v reflect.Value) error {
392+
var isArray bool
393+
386394
switch v.Kind() {
387395
case reflect.Slice:
388396
// Make room for the slice elements if needed
@@ -392,6 +400,7 @@ func (d *Decoder) decodeNumberSet(ns []string, v reflect.Value) error {
392400
}
393401
case reflect.Array:
394402
// Limited to capacity of existing array.
403+
isArray = true
395404
case reflect.Interface:
396405
if d.options.UseNumber {
397406
set := make([]Number, len(ns))
@@ -416,7 +425,9 @@ func (d *Decoder) decodeNumberSet(ns []string, v reflect.Value) error {
416425
}
417426

418427
for i := 0; i < v.Cap() && i < len(ns); i++ {
419-
v.SetLen(i + 1)
428+
if !isArray {
429+
v.SetLen(i + 1)
430+
}
420431
u, elem := indirect(v.Index(i), false)
421432
if u != nil {
422433
return u.UnmarshalDynamoDBStreamsAttributeValue(&types.AttributeValueMemberNS{Value: ns})
@@ -430,6 +441,8 @@ func (d *Decoder) decodeNumberSet(ns []string, v reflect.Value) error {
430441
}
431442

432443
func (d *Decoder) decodeList(avList []types.AttributeValue, v reflect.Value) error {
444+
var isArray bool
445+
433446
switch v.Kind() {
434447
case reflect.Slice:
435448
// Make room for the slice elements if needed
@@ -439,6 +452,7 @@ func (d *Decoder) decodeList(avList []types.AttributeValue, v reflect.Value) err
439452
}
440453
case reflect.Array:
441454
// Limited to capacity of existing array.
455+
isArray = true
442456
case reflect.Interface:
443457
s := make([]interface{}, len(avList))
444458
for i, av := range avList {
@@ -454,7 +468,9 @@ func (d *Decoder) decodeList(avList []types.AttributeValue, v reflect.Value) err
454468

455469
// If v is not a slice, array
456470
for i := 0; i < v.Cap() && i < len(avList); i++ {
457-
v.SetLen(i + 1)
471+
if !isArray {
472+
v.SetLen(i + 1)
473+
}
458474
if err := d.decode(avList[i], v.Index(i), tag{}); err != nil {
459475
return err
460476
}
@@ -496,11 +512,8 @@ func (d *Decoder) decodeMap(avMap map[string]types.AttributeValue, v reflect.Val
496512
TagKey: d.options.TagKey,
497513
})
498514
for k, av := range avMap {
499-
if f, ok := fieldByName(fields, k); ok {
500-
fv := fieldByIndex(v, f.Index, func(v *reflect.Value) bool {
501-
v.Set(reflect.New(v.Type().Elem()))
502-
return true // to continue the loop.
503-
})
515+
if f, ok := fields.FieldByName(k); ok {
516+
fv := decoderFieldByIndex(v, f.Index)
504517
if err := d.decode(av, fv, f.tag); err != nil {
505518
return err
506519
}
@@ -549,6 +562,8 @@ func (d *Decoder) decodeString(s string, v reflect.Value, fieldTag tag) error {
549562
}
550563

551564
func (d *Decoder) decodeStringSet(ss []string, v reflect.Value) error {
565+
var isArray bool
566+
552567
switch v.Kind() {
553568
case reflect.Slice:
554569
// Make room for the slice elements if needed
@@ -557,6 +572,7 @@ func (d *Decoder) decodeStringSet(ss []string, v reflect.Value) error {
557572
}
558573
case reflect.Array:
559574
// Limited to capacity of existing array.
575+
isArray = true
560576
case reflect.Interface:
561577
set := make([]string, len(ss))
562578
for i, s := range ss {
@@ -571,7 +587,9 @@ func (d *Decoder) decodeStringSet(ss []string, v reflect.Value) error {
571587
}
572588

573589
for i := 0; i < v.Cap() && i < len(ss); i++ {
574-
v.SetLen(i + 1)
590+
if !isArray {
591+
v.SetLen(i + 1)
592+
}
575593
u, elem := indirect(v.Index(i), false)
576594
if u != nil {
577595
return u.UnmarshalDynamoDBStreamsAttributeValue(&types.AttributeValueMemberSS{Value: ss})
@@ -595,6 +613,21 @@ func decodeUnixTime(n string) (time.Time, error) {
595613
return time.Unix(v, 0), nil
596614
}
597615

616+
// decoderFieldByIndex finds the field with the provided nested index, allocating
617+
// embedded parent structs if needed
618+
func decoderFieldByIndex(v reflect.Value, index []int) reflect.Value {
619+
for i, x := range index {
620+
if i > 0 && v.Kind() == reflect.Ptr && v.Type().Elem().Kind() == reflect.Struct {
621+
if v.IsNil() {
622+
v.Set(reflect.New(v.Type().Elem()))
623+
}
624+
v = v.Elem()
625+
}
626+
v = v.Field(x)
627+
}
628+
return v
629+
}
630+
598631
// indirect will walk a value's interface or pointer value types. Returning
599632
// the final value or the value a unmarshaler is defined on.
600633
//
@@ -703,6 +736,10 @@ type UnmarshalError struct {
703736
Type reflect.Type
704737
}
705738

739+
func (e *UnmarshalError) Unwrap() error {
740+
return e.Err
741+
}
742+
706743
// Error returns the string representation of the error satisfying the error
707744
// interface.
708745
func (e *UnmarshalError) Error() string {

feature/dynamodbstreams/attributevalue/decode_test.go

Lines changed: 113 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99

1010
"github.com/aws/aws-sdk-go-v2/aws"
1111
"github.com/aws/aws-sdk-go-v2/service/dynamodbstreams/types"
12+
"github.com/google/go-cmp/cmp"
1213
)
1314

1415
func TestUnmarshalShared(t *testing.T) {
@@ -191,10 +192,53 @@ func TestUnmarshal(t *testing.T) {
191192
Type: reflect.TypeOf(uint8(0)),
192193
},
193194
},
195+
// -------
196+
// Empty Values
197+
// -------
198+
{
199+
in: &types.AttributeValueMemberB{Value: []byte{}},
200+
actual: &[]byte{},
201+
expected: []byte{},
202+
},
203+
{
204+
in: &types.AttributeValueMemberBS{Value: [][]byte{}},
205+
actual: &[][]byte{},
206+
expected: [][]byte{},
207+
},
208+
{
209+
in: &types.AttributeValueMemberL{Value: []types.AttributeValue{}},
210+
actual: &[]interface{}{},
211+
expected: []interface{}{},
212+
},
213+
{
214+
in: &types.AttributeValueMemberM{Value: map[string]types.AttributeValue{}},
215+
actual: &map[string]interface{}{},
216+
expected: map[string]interface{}{},
217+
},
218+
{
219+
in: &types.AttributeValueMemberN{Value: ""},
220+
actual: new(int),
221+
err: fmt.Errorf("invalid syntax"),
222+
},
223+
{
224+
in: &types.AttributeValueMemberNS{Value: []string{}},
225+
actual: &[]string{},
226+
expected: []string{},
227+
},
228+
{
229+
in: &types.AttributeValueMemberS{Value: ""},
230+
actual: new(string),
231+
expected: "",
232+
},
233+
{
234+
in: &types.AttributeValueMemberSS{Value: []string{}},
235+
actual: &[]string{},
236+
expected: []string{},
237+
},
194238
}
195239

196240
for i, c := range cases {
197-
t.Run(fmt.Sprintf("case %d", i), func(t *testing.T) {
241+
t.Run(fmt.Sprintf("case %d/%d", i, len(cases)), func(t *testing.T) {
198242
err := Unmarshal(c.in, c.actual)
199243
assertConvertTest(t, c.actual, c.expected, err, c.err)
200244
})
@@ -611,3 +655,71 @@ func TestDecodeAliasedUnixTime(t *testing.T) {
611655
t.Errorf("expect %v, got %v", expect, actual)
612656
}
613657
}
658+
659+
// see github issue #1594
660+
func TestDecodeArrayType(t *testing.T) {
661+
cases := []struct {
662+
to, from interface{}
663+
}{
664+
{
665+
&[2]int{1, 2},
666+
&[2]int{},
667+
},
668+
{
669+
&[2]int64{1, 2},
670+
&[2]int64{},
671+
},
672+
{
673+
&[2]byte{1, 2},
674+
&[2]byte{},
675+
},
676+
{
677+
&[2]bool{true, false},
678+
&[2]bool{},
679+
},
680+
{
681+
&[2]string{"1", "2"},
682+
&[2]string{},
683+
},
684+
{
685+
&[2][]string{{"1", "2"}},
686+
&[2][]string{},
687+
},
688+
}
689+
690+
for _, c := range cases {
691+
marshaled, err := Marshal(c.to)
692+
if err != nil {
693+
t.Errorf("expected no error, but received %v", err)
694+
}
695+
696+
if err = Unmarshal(marshaled, c.from); err != nil {
697+
t.Errorf("expected no error, but received %v", err)
698+
}
699+
700+
if diff := cmp.Diff(c.to, c.from); len(diff) != 0 {
701+
t.Errorf("expected match\n:%s", diff)
702+
}
703+
}
704+
}
705+
706+
func TestDecoderFieldByIndex(t *testing.T) {
707+
type (
708+
Middle struct{ Inner int }
709+
Outer struct{ *Middle }
710+
)
711+
var outer Outer
712+
713+
outerType := reflect.TypeOf(outer)
714+
outerValue := reflect.ValueOf(&outer)
715+
outerFields := unionStructFields(outerType, structFieldOptions{})
716+
innerField, _ := outerFields.FieldByName("Inner")
717+
718+
f := decoderFieldByIndex(outerValue.Elem(), innerField.Index)
719+
if outer.Middle == nil {
720+
t.Errorf("expected outer.Middle to be non-nil")
721+
}
722+
if f.Kind() != reflect.Int || f.Int() != int64(outer.Inner) {
723+
t.Error("expected f to be an int with value equal to outer.Inner")
724+
}
725+
}

feature/dynamodbstreams/attributevalue/encode.go

Lines changed: 16 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -258,24 +258,6 @@ func (e *Encoder) Encode(in interface{}) (types.AttributeValue, error) {
258258
return e.encode(reflect.ValueOf(in), tag{})
259259
}
260260

261-
func fieldByIndex(
262-
v reflect.Value, index []int, OnEmbeddedNilStruct func(*reflect.Value) bool,
263-
) reflect.Value {
264-
fv := v
265-
for i, x := range index {
266-
if i > 0 {
267-
if fv.Kind() == reflect.Ptr && fv.Type().Elem().Kind() == reflect.Struct {
268-
if fv.IsNil() && !OnEmbeddedNilStruct(&fv) {
269-
break
270-
}
271-
fv = fv.Elem()
272-
}
273-
}
274-
fv = fv.Field(x)
275-
}
276-
return fv
277-
}
278-
279261
func (e *Encoder) encode(v reflect.Value, fieldTag tag) (types.AttributeValue, error) {
280262
// Ignore fields explicitly marked to be skipped.
281263
if fieldTag.Ignore {
@@ -350,16 +332,12 @@ func (e *Encoder) encodeStruct(v reflect.Value, fieldTag tag) (types.AttributeVa
350332
fields := unionStructFields(v.Type(), structFieldOptions{
351333
TagKey: e.options.TagKey,
352334
})
353-
for _, f := range fields {
335+
for _, f := range fields.All() {
354336
if f.Name == "" {
355337
return nil, &InvalidMarshalError{msg: "map key cannot be empty"}
356338
}
357339

358-
found := true
359-
fv := fieldByIndex(v, f.Index, func(v *reflect.Value) bool {
360-
found = false
361-
return false // to break the loop.
362-
})
340+
fv, found := encoderFieldByIndex(v, f.Index)
363341
if !found {
364342
continue
365343
}
@@ -603,6 +581,20 @@ func encodeNull() types.AttributeValue {
603581
return &types.AttributeValueMemberNULL{Value: true}
604582
}
605583

584+
// encoderFieldByIndex finds the field with the provided nested index
585+
func encoderFieldByIndex(v reflect.Value, index []int) (reflect.Value, bool) {
586+
for i, x := range index {
587+
if i > 0 && v.Kind() == reflect.Ptr && v.Type().Elem().Kind() == reflect.Struct {
588+
if v.IsNil() {
589+
return reflect.Value{}, false
590+
}
591+
v = v.Elem()
592+
}
593+
v = v.Field(x)
594+
}
595+
return v, true
596+
}
597+
606598
func valueElem(v reflect.Value) reflect.Value {
607599
switch v.Kind() {
608600
case reflect.Interface, reflect.Ptr:

0 commit comments

Comments
 (0)