-
-
Notifications
You must be signed in to change notification settings - Fork 179
/
decode.go
117 lines (100 loc) · 2.96 KB
/
decode.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
package dynamo
import (
"fmt"
"reflect"
"github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue"
"github.com/aws/aws-sdk-go-v2/service/dynamodb/types"
)
// Unmarshaler is the interface implemented by objects that can unmarshal
// an AttributeValue into themselves.
type Unmarshaler interface {
UnmarshalDynamo(av types.AttributeValue) error
}
// ItemUnmarshaler is the interface implemented by objects that can unmarshal
// an Item (a map of strings to AttributeValues) into themselves.
type ItemUnmarshaler interface {
UnmarshalDynamoItem(item Item) error
}
// Unmarshal decodes a DynamoDB item into out, which must be a pointer.
func UnmarshalItem(item Item, out interface{}) error {
return unmarshalItem(item, out)
}
// Unmarshal decodes a DynamoDB value into out, which must be a pointer.
func Unmarshal(av types.AttributeValue, out interface{}) error {
switch out := out.(type) {
case awsEncoder:
return attributevalue.Unmarshal(av, out.iface)
}
rv := reflect.ValueOf(out)
plan, err := typedefOf(rv.Type())
if err != nil {
return err
}
return plan.decodeAttr(flagNone, av, rv)
}
// used in iterators for unmarshaling one item
type unmarshalFunc func(Item, interface{}) error
func unmarshalItem(item Item, out interface{}) error {
rv := reflect.ValueOf(out)
plan, err := typedefOf(rv.Type())
if err != nil {
return err
}
return plan.decodeItem(item, rv)
}
func unmarshalAppend(item Item, out interface{}) error {
if awsenc, ok := out.(awsEncoder); ok {
return unmarshalAppendAWS(item, awsenc.iface)
}
rv := reflect.ValueOf(out)
if rv.Kind() != reflect.Ptr || rv.Elem().Kind() != reflect.Slice {
return fmt.Errorf("dynamo: unmarshal append: result argument must be a slice pointer")
}
slicev := rv.Elem()
innerRV := reflect.New(slicev.Type().Elem())
if err := unmarshalItem(item, innerRV.Interface()); err != nil {
return err
}
slicev = reflect.Append(slicev, innerRV.Elem())
rv.Elem().Set(slicev)
return nil
}
func unmarshalAppendTo(out interface{}) func(item Item, out interface{}) error {
if awsenc, ok := out.(awsEncoder); ok {
return func(item Item, _ any) error {
return unmarshalAppendAWS(item, awsenc.iface)
}
}
ptr := reflect.ValueOf(out)
slicet := ptr.Type().Elem()
membert := slicet.Elem()
if ptr.Kind() != reflect.Ptr || slicet.Kind() != reflect.Slice {
return func(item Item, _ any) error {
return fmt.Errorf("dynamo: unmarshal append: result argument must be a slice pointer")
}
}
plan, err := typedefOf(membert)
if err != nil {
return func(item Item, _ any) error {
return err
}
}
/*
Like:
return func(item, ...) {
member := new(T)
decode(item, member)
*slice = append(*slice, *member)
}
*/
return func(item map[string]types.AttributeValue, _ any) error {
member := reflect.New(membert) // *T of *[]T
if err := plan.decodeItem(item, member); err != nil {
return err
}
slice := ptr.Elem()
slice = reflect.Append(slice, member.Elem())
ptr.Elem().Set(slice)
return nil
}
}