1package dynamodbattribute
2
3import (
4	"encoding/base64"
5	"fmt"
6	"reflect"
7	"strconv"
8	"time"
9
10	"github.com/aws/aws-sdk-go/aws"
11	"github.com/aws/aws-sdk-go/service/dynamodb"
12)
13
14// An Unmarshaler is an interface to provide custom unmarshaling of
15// AttributeValues. Use this to provide custom logic determining
16// how AttributeValues should be unmarshaled.
17// 		type ExampleUnmarshaler struct {
18// 			Value int
19// 		}
20//
21// 		func (u *ExampleUnmarshaler) UnmarshalDynamoDBAttributeValue(av *dynamodb.AttributeValue) error {
22// 			if av.N == nil {
23// 				return nil
24// 			}
25//
26// 			n, err := strconv.ParseInt(*av.N, 10, 0)
27// 			if err != nil {
28// 				return err
29// 			}
30//
31// 			u.Value = int(n)
32// 			return nil
33// 		}
34type Unmarshaler interface {
35	UnmarshalDynamoDBAttributeValue(*dynamodb.AttributeValue) error
36}
37
38// Unmarshal will unmarshal DynamoDB AttributeValues to Go value types.
39// Both generic interface{} and concrete types are valid unmarshal
40// destination types.
41//
42// Unmarshal will allocate maps, slices, and pointers as needed to
43// unmarshal the AttributeValue into the provided type value.
44//
45// When unmarshaling AttributeValues into structs Unmarshal matches
46// the field names of the struct to the AttributeValue Map keys.
47// Initially it will look for exact field name matching, but will
48// fall back to case insensitive if not exact match is found.
49//
50// With the exception of omitempty, omitemptyelem, binaryset, numberset
51// and stringset all struct tags used by Marshal are also used by
52// Unmarshal.
53//
54// When decoding AttributeValues to interfaces Unmarshal will use the
55// following types.
56//
57//		[]byte,                 AV Binary (B)
58//		[][]byte,               AV Binary Set (BS)
59//		bool,                   AV Boolean (BOOL)
60//		[]interface{},          AV List (L)
61//		map[string]interface{}, AV Map (M)
62//		float64,                AV Number (N)
63//		Number,                 AV Number (N) with UseNumber set
64//		[]float64,              AV Number Set (NS)
65//		[]Number,               AV Number Set (NS) with UseNumber set
66//		string,                 AV String (S)
67//		[]string,               AV String Set (SS)
68//
69// If the Decoder option, UseNumber is set numbers will be unmarshaled
70// as Number values instead of float64. Use this to maintain the original
71// string formating of the number as it was represented in the AttributeValue.
72// In addition provides additional opportunities to parse the number
73// string based on individual use cases.
74//
75// When unmarshaling any error that occurs will halt the unmarshal
76// and return the error.
77//
78// The output value provided must be a non-nil pointer
79func Unmarshal(av *dynamodb.AttributeValue, out interface{}) error {
80	return NewDecoder().Decode(av, out)
81}
82
83// UnmarshalMap is an alias for Unmarshal which unmarshals from
84// a map of AttributeValues.
85//
86// The output value provided must be a non-nil pointer
87func UnmarshalMap(m map[string]*dynamodb.AttributeValue, out interface{}) error {
88	return NewDecoder().Decode(&dynamodb.AttributeValue{M: m}, out)
89}
90
91// UnmarshalList is an alias for Unmarshal func which unmarshals
92// a slice of AttributeValues.
93//
94// The output value provided must be a non-nil pointer
95func UnmarshalList(l []*dynamodb.AttributeValue, out interface{}) error {
96	return NewDecoder().Decode(&dynamodb.AttributeValue{L: l}, out)
97}
98
99// UnmarshalListOfMaps is an alias for Unmarshal func which unmarshals a
100// slice of maps of attribute values.
101//
102// This is useful for when you need to unmarshal the Items from a DynamoDB
103// Query API call.
104//
105// The output value provided must be a non-nil pointer
106func UnmarshalListOfMaps(l []map[string]*dynamodb.AttributeValue, out interface{}) error {
107	items := make([]*dynamodb.AttributeValue, len(l))
108	for i, m := range l {
109		items[i] = &dynamodb.AttributeValue{M: m}
110	}
111
112	return UnmarshalList(items, out)
113}
114
115// A Decoder provides unmarshaling AttributeValues to Go value types.
116type Decoder struct {
117	MarshalOptions
118
119	// Instructs the decoder to decode AttributeValue Numbers as
120	// Number type instead of float64 when the destination type
121	// is interface{}. Similar to encoding/json.Number
122	UseNumber bool
123}
124
125// NewDecoder creates a new Decoder with default configuration. Use
126// the `opts` functional options to override the default configuration.
127func NewDecoder(opts ...func(*Decoder)) *Decoder {
128	d := &Decoder{
129		MarshalOptions: MarshalOptions{
130			SupportJSONTags: true,
131		},
132	}
133	for _, o := range opts {
134		o(d)
135	}
136
137	return d
138}
139
140// Decode will unmarshal an AttributeValue into a Go value type. An error
141// will be return if the decoder is unable to unmarshal the AttributeValue
142// to the provide Go value type.
143//
144// The output value provided must be a non-nil pointer
145func (d *Decoder) Decode(av *dynamodb.AttributeValue, out interface{}, opts ...func(*Decoder)) error {
146	v := reflect.ValueOf(out)
147	if v.Kind() != reflect.Ptr || v.IsNil() || !v.IsValid() {
148		return &InvalidUnmarshalError{Type: reflect.TypeOf(out)}
149	}
150
151	return d.decode(av, v, tag{})
152}
153
154var stringInterfaceMapType = reflect.TypeOf(map[string]interface{}(nil))
155var byteSliceType = reflect.TypeOf([]byte(nil))
156var byteSliceSlicetype = reflect.TypeOf([][]byte(nil))
157var numberType = reflect.TypeOf(Number(""))
158var timeType = reflect.TypeOf(time.Time{})
159var ptrStringType = reflect.TypeOf(aws.String(""))
160
161func (d *Decoder) decode(av *dynamodb.AttributeValue, v reflect.Value, fieldTag tag) error {
162	var u Unmarshaler
163	if av == nil || av.NULL != nil {
164		u, v = indirect(v, true)
165		if u != nil {
166			return u.UnmarshalDynamoDBAttributeValue(av)
167		}
168		return d.decodeNull(v)
169	}
170
171	u, v = indirect(v, false)
172	if u != nil {
173		return u.UnmarshalDynamoDBAttributeValue(av)
174	}
175
176	switch {
177	case len(av.B) != 0 || (av.B != nil && d.EnableEmptyCollections):
178		return d.decodeBinary(av.B, v)
179	case av.BOOL != nil:
180		return d.decodeBool(av.BOOL, v)
181	case len(av.BS) != 0 || (av.BS != nil && d.EnableEmptyCollections):
182		return d.decodeBinarySet(av.BS, v)
183	case len(av.L) != 0 || (av.L != nil && d.EnableEmptyCollections):
184		return d.decodeList(av.L, v)
185	case len(av.M) != 0 || (av.M != nil && d.EnableEmptyCollections):
186		return d.decodeMap(av.M, v)
187	case av.N != nil:
188		return d.decodeNumber(av.N, v, fieldTag)
189	case len(av.NS) != 0 || (av.NS != nil && d.EnableEmptyCollections):
190		return d.decodeNumberSet(av.NS, v)
191	case av.S != nil: // DynamoDB does not allow for empty strings, so we do not consider the length or EnableEmptyCollections flag here
192		return d.decodeString(av.S, v, fieldTag)
193	case len(av.SS) != 0 || (av.SS != nil && d.EnableEmptyCollections):
194		return d.decodeStringSet(av.SS, v)
195	}
196
197	return nil
198}
199
200func (d *Decoder) decodeBinary(b []byte, v reflect.Value) error {
201	if v.Kind() == reflect.Interface {
202		buf := make([]byte, len(b))
203		copy(buf, b)
204		v.Set(reflect.ValueOf(buf))
205		return nil
206	}
207
208	if v.Kind() != reflect.Slice && v.Kind() != reflect.Array {
209		return &UnmarshalTypeError{Value: "binary", Type: v.Type()}
210	}
211
212	if v.Type() == byteSliceType {
213		// Optimization for []byte types
214		if v.IsNil() || v.Cap() < len(b) {
215			v.Set(reflect.MakeSlice(byteSliceType, len(b), len(b)))
216		} else if v.Len() != len(b) {
217			v.SetLen(len(b))
218		}
219		copy(v.Interface().([]byte), b)
220		return nil
221	}
222
223	switch v.Type().Elem().Kind() {
224	case reflect.Uint8:
225		// Fallback to reflection copy for type aliased of []byte type
226		if v.Kind() != reflect.Array && (v.IsNil() || v.Cap() < len(b)) {
227			v.Set(reflect.MakeSlice(v.Type(), len(b), len(b)))
228		} else if v.Len() != len(b) {
229			v.SetLen(len(b))
230		}
231		for i := 0; i < len(b); i++ {
232			v.Index(i).SetUint(uint64(b[i]))
233		}
234	default:
235		if v.Kind() == reflect.Array {
236			switch v.Type().Elem().Kind() {
237			case reflect.Uint8:
238				reflect.Copy(v, reflect.ValueOf(b))
239			default:
240				return &UnmarshalTypeError{Value: "binary", Type: v.Type()}
241			}
242
243			break
244		}
245
246		return &UnmarshalTypeError{Value: "binary", Type: v.Type()}
247	}
248
249	return nil
250}
251
252func (d *Decoder) decodeBool(b *bool, v reflect.Value) error {
253	switch v.Kind() {
254	case reflect.Bool, reflect.Interface:
255		v.Set(reflect.ValueOf(*b).Convert(v.Type()))
256	default:
257		return &UnmarshalTypeError{Value: "bool", Type: v.Type()}
258	}
259
260	return nil
261}
262
263func (d *Decoder) decodeBinarySet(bs [][]byte, v reflect.Value) error {
264	isArray := false
265
266	switch v.Kind() {
267	case reflect.Slice:
268		// Make room for the slice elements if needed
269		if v.IsNil() || v.Cap() < len(bs) {
270			// What about if ignoring nil/empty values?
271			v.Set(reflect.MakeSlice(v.Type(), 0, len(bs)))
272		}
273	case reflect.Array:
274		// Limited to capacity of existing array.
275		isArray = true
276	case reflect.Interface:
277		set := make([][]byte, len(bs))
278		for i, b := range bs {
279			if err := d.decodeBinary(b, reflect.ValueOf(&set[i]).Elem()); err != nil {
280				return err
281			}
282		}
283		v.Set(reflect.ValueOf(set))
284		return nil
285	default:
286		return &UnmarshalTypeError{Value: "binary set", Type: v.Type()}
287	}
288
289	for i := 0; i < v.Cap() && i < len(bs); i++ {
290		if !isArray {
291			v.SetLen(i + 1)
292		}
293		u, elem := indirect(v.Index(i), false)
294		if u != nil {
295			return u.UnmarshalDynamoDBAttributeValue(&dynamodb.AttributeValue{BS: bs})
296		}
297		if err := d.decodeBinary(bs[i], elem); err != nil {
298			return err
299		}
300	}
301
302	return nil
303}
304
305func (d *Decoder) decodeNumber(n *string, v reflect.Value, fieldTag tag) error {
306	switch v.Kind() {
307	case reflect.Interface:
308		i, err := d.decodeNumberToInterface(n)
309		if err != nil {
310			return err
311		}
312		v.Set(reflect.ValueOf(i))
313		return nil
314	case reflect.String:
315		if v.Type() == numberType { // Support Number value type
316			v.Set(reflect.ValueOf(Number(*n)))
317			return nil
318		}
319		v.Set(reflect.ValueOf(*n))
320	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
321		i, err := strconv.ParseInt(*n, 10, 64)
322		if err != nil {
323			return err
324		}
325		if v.OverflowInt(i) {
326			return &UnmarshalTypeError{
327				Value: fmt.Sprintf("number overflow, %s", *n),
328				Type:  v.Type(),
329			}
330		}
331		v.SetInt(i)
332	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
333		i, err := strconv.ParseUint(*n, 10, 64)
334		if err != nil {
335			return err
336		}
337		if v.OverflowUint(i) {
338			return &UnmarshalTypeError{
339				Value: fmt.Sprintf("number overflow, %s", *n),
340				Type:  v.Type(),
341			}
342		}
343		v.SetUint(i)
344	case reflect.Float32, reflect.Float64:
345		i, err := strconv.ParseFloat(*n, 64)
346		if err != nil {
347			return err
348		}
349		if v.OverflowFloat(i) {
350			return &UnmarshalTypeError{
351				Value: fmt.Sprintf("number overflow, %s", *n),
352				Type:  v.Type(),
353			}
354		}
355		v.SetFloat(i)
356	default:
357		if v.Type().ConvertibleTo(timeType) && fieldTag.AsUnixTime {
358			t, err := decodeUnixTime(*n)
359			if err != nil {
360				return err
361			}
362			v.Set(reflect.ValueOf(t).Convert(v.Type()))
363			return nil
364		}
365		return &UnmarshalTypeError{Value: "number", Type: v.Type()}
366	}
367
368	return nil
369}
370
371func (d *Decoder) decodeNumberToInterface(n *string) (interface{}, error) {
372	if d.UseNumber {
373		return Number(*n), nil
374	}
375
376	// Default to float64 for all numbers
377	return strconv.ParseFloat(*n, 64)
378}
379
380func (d *Decoder) decodeNumberSet(ns []*string, v reflect.Value) error {
381	isArray := false
382
383	switch v.Kind() {
384	case reflect.Slice:
385		// Make room for the slice elements if needed
386		if v.IsNil() || v.Cap() < len(ns) {
387			// What about if ignoring nil/empty values?
388			v.Set(reflect.MakeSlice(v.Type(), 0, len(ns)))
389		}
390	case reflect.Array:
391		// Limited to capacity of existing array.
392		isArray = true
393	case reflect.Interface:
394		if d.UseNumber {
395			set := make([]Number, len(ns))
396			for i, n := range ns {
397				if err := d.decodeNumber(n, reflect.ValueOf(&set[i]).Elem(), tag{}); err != nil {
398					return err
399				}
400			}
401			v.Set(reflect.ValueOf(set))
402		} else {
403			set := make([]float64, len(ns))
404			for i, n := range ns {
405				if err := d.decodeNumber(n, reflect.ValueOf(&set[i]).Elem(), tag{}); err != nil {
406					return err
407				}
408			}
409			v.Set(reflect.ValueOf(set))
410		}
411		return nil
412	default:
413		return &UnmarshalTypeError{Value: "number set", Type: v.Type()}
414	}
415
416	for i := 0; i < v.Cap() && i < len(ns); i++ {
417		if !isArray {
418			v.SetLen(i + 1)
419		}
420		u, elem := indirect(v.Index(i), false)
421		if u != nil {
422			return u.UnmarshalDynamoDBAttributeValue(&dynamodb.AttributeValue{NS: ns})
423		}
424		if err := d.decodeNumber(ns[i], elem, tag{}); err != nil {
425			return err
426		}
427	}
428
429	return nil
430}
431
432func (d *Decoder) decodeList(avList []*dynamodb.AttributeValue, v reflect.Value) error {
433	isArray := false
434
435	switch v.Kind() {
436	case reflect.Slice:
437		// Make room for the slice elements if needed
438		if v.IsNil() || v.Cap() < len(avList) {
439			// What about if ignoring nil/empty values?
440			v.Set(reflect.MakeSlice(v.Type(), 0, len(avList)))
441		}
442	case reflect.Array:
443		// Limited to capacity of existing array.
444		isArray = true
445	case reflect.Interface:
446		s := make([]interface{}, len(avList))
447		for i, av := range avList {
448			if err := d.decode(av, reflect.ValueOf(&s[i]).Elem(), tag{}); err != nil {
449				return err
450			}
451		}
452		v.Set(reflect.ValueOf(s))
453		return nil
454	default:
455		return &UnmarshalTypeError{Value: "list", Type: v.Type()}
456	}
457
458	// If v is not a slice, array
459	for i := 0; i < v.Cap() && i < len(avList); i++ {
460		if !isArray {
461			v.SetLen(i + 1)
462		}
463
464		if err := d.decode(avList[i], v.Index(i), tag{}); err != nil {
465			return err
466		}
467	}
468
469	return nil
470}
471
472func (d *Decoder) decodeMap(avMap map[string]*dynamodb.AttributeValue, v reflect.Value) error {
473	switch v.Kind() {
474	case reflect.Map:
475		t := v.Type()
476		if t.Key().Kind() != reflect.String {
477			return &UnmarshalTypeError{Value: "map string key", Type: t.Key()}
478		}
479		if v.IsNil() {
480			v.Set(reflect.MakeMap(t))
481		}
482	case reflect.Struct:
483	case reflect.Interface:
484		v.Set(reflect.MakeMap(stringInterfaceMapType))
485		v = v.Elem()
486	default:
487		return &UnmarshalTypeError{Value: "map", Type: v.Type()}
488	}
489
490	if v.Kind() == reflect.Map {
491		for k, av := range avMap {
492			key := reflect.New(v.Type().Key()).Elem()
493			key.SetString(k)
494			elem := reflect.New(v.Type().Elem()).Elem()
495			if err := d.decode(av, elem, tag{}); err != nil {
496				return err
497			}
498			v.SetMapIndex(key, elem)
499		}
500	} else if v.Kind() == reflect.Struct {
501		fields := unionStructFields(v.Type(), d.MarshalOptions)
502		for k, av := range avMap {
503			if f, ok := fieldByName(fields, k); ok {
504				fv := fieldByIndex(v, f.Index, func(v *reflect.Value) bool {
505					v.Set(reflect.New(v.Type().Elem()))
506					return true // to continue the loop.
507				})
508				if err := d.decode(av, fv, f.tag); err != nil {
509					return err
510				}
511			}
512		}
513	}
514
515	return nil
516}
517
518func (d *Decoder) decodeNull(v reflect.Value) error {
519	if v.IsValid() && v.CanSet() {
520		v.Set(reflect.Zero(v.Type()))
521	}
522
523	return nil
524}
525
526func (d *Decoder) decodeString(s *string, v reflect.Value, fieldTag tag) error {
527	if fieldTag.AsString {
528		return d.decodeNumber(s, v, fieldTag)
529	}
530
531	// To maintain backwards compatibility with ConvertFrom family of methods which
532	// converted strings to time.Time structs
533	if v.Type().ConvertibleTo(timeType) {
534		t, err := time.Parse(time.RFC3339, *s)
535		if err != nil {
536			return err
537		}
538		v.Set(reflect.ValueOf(t).Convert(v.Type()))
539		return nil
540	}
541
542	switch v.Kind() {
543	case reflect.String:
544		v.SetString(*s)
545	case reflect.Slice:
546		// To maintain backwards compatibility with the ConvertFrom family of methods
547		// which converted []byte into base64-encoded strings if the input was typed
548		if v.Type() == byteSliceType {
549			decoded, err := base64.StdEncoding.DecodeString(*s)
550			if err != nil {
551				return &UnmarshalError{Err: err, Value: "string", Type: v.Type()}
552			}
553			v.SetBytes(decoded)
554		}
555	case reflect.Interface:
556		// Ensure type aliasing is handled properly
557		v.Set(reflect.ValueOf(*s).Convert(v.Type()))
558	default:
559		return &UnmarshalTypeError{Value: "string", Type: v.Type()}
560	}
561
562	return nil
563}
564
565func (d *Decoder) decodeStringSet(ss []*string, v reflect.Value) error {
566	isArray := false
567
568	switch v.Kind() {
569	case reflect.Slice:
570		// Make room for the slice elements if needed
571		if v.IsNil() || v.Cap() < len(ss) {
572			v.Set(reflect.MakeSlice(v.Type(), 0, len(ss)))
573		}
574	case reflect.Array:
575		// Limited to capacity of existing array.
576		isArray = true
577	case reflect.Interface:
578		set := make([]string, len(ss))
579		for i, s := range ss {
580			if err := d.decodeString(s, reflect.ValueOf(&set[i]).Elem(), tag{}); err != nil {
581				return err
582			}
583		}
584		v.Set(reflect.ValueOf(set))
585		return nil
586	default:
587		return &UnmarshalTypeError{Value: "string set", Type: v.Type()}
588	}
589
590	for i := 0; i < v.Cap() && i < len(ss); i++ {
591		if !isArray {
592			v.SetLen(i + 1)
593		}
594		u, elem := indirect(v.Index(i), false)
595		if u != nil {
596			return u.UnmarshalDynamoDBAttributeValue(&dynamodb.AttributeValue{SS: ss})
597		}
598		if err := d.decodeString(ss[i], elem, tag{}); err != nil {
599			return err
600		}
601	}
602
603	return nil
604}
605
606func decodeUnixTime(n string) (time.Time, error) {
607	v, err := strconv.ParseInt(n, 10, 64)
608	if err != nil {
609		return time.Time{}, &UnmarshalError{
610			Err: err, Value: n, Type: timeType,
611		}
612	}
613
614	return time.Unix(v, 0), nil
615}
616
617// indirect will walk a value's interface or pointer value types. Returning
618// the final value or the value a unmarshaler is defined on.
619//
620// Based on the enoding/json type reflect value type indirection in Go Stdlib
621// https://golang.org/src/encoding/json/decode.go indirect func.
622func indirect(v reflect.Value, decodingNull bool) (Unmarshaler, reflect.Value) {
623	if v.Kind() != reflect.Ptr && v.Type().Name() != "" && v.CanAddr() {
624		v = v.Addr()
625	}
626	for {
627		if v.Kind() == reflect.Interface && !v.IsNil() {
628			e := v.Elem()
629			if e.Kind() == reflect.Ptr && !e.IsNil() && (!decodingNull || e.Elem().Kind() == reflect.Ptr) {
630				v = e
631				continue
632			}
633		}
634		if v.Kind() != reflect.Ptr {
635			break
636		}
637		if v.Elem().Kind() != reflect.Ptr && decodingNull && v.CanSet() {
638			break
639		}
640		if v.IsNil() {
641			v.Set(reflect.New(v.Type().Elem()))
642		}
643		if v.Type().NumMethod() > 0 {
644			if u, ok := v.Interface().(Unmarshaler); ok {
645				return u, reflect.Value{}
646			}
647		}
648		v = v.Elem()
649	}
650
651	return nil, v
652}
653
654// A Number represents a Attributevalue number literal.
655type Number string
656
657// Float64 attempts to cast the number ot a float64, returning
658// the result of the case or error if the case failed.
659func (n Number) Float64() (float64, error) {
660	return strconv.ParseFloat(string(n), 64)
661}
662
663// Int64 attempts to cast the number ot a int64, returning
664// the result of the case or error if the case failed.
665func (n Number) Int64() (int64, error) {
666	return strconv.ParseInt(string(n), 10, 64)
667}
668
669// Uint64 attempts to cast the number ot a uint64, returning
670// the result of the case or error if the case failed.
671func (n Number) Uint64() (uint64, error) {
672	return strconv.ParseUint(string(n), 10, 64)
673}
674
675// String returns the raw number represented as a string
676func (n Number) String() string {
677	return string(n)
678}
679
680type emptyOrigError struct{}
681
682func (e emptyOrigError) OrigErr() error {
683	return nil
684}
685
686// An UnmarshalTypeError is an error type representing a error
687// unmarshaling the AttributeValue's element to a Go value type.
688// Includes details about the AttributeValue type and Go value type.
689type UnmarshalTypeError struct {
690	emptyOrigError
691	Value string
692	Type  reflect.Type
693}
694
695// Error returns the string representation of the error.
696// satisfying the error interface
697func (e *UnmarshalTypeError) Error() string {
698	return fmt.Sprintf("%s: %s", e.Code(), e.Message())
699}
700
701// Code returns the code of the error, satisfying the awserr.Error
702// interface.
703func (e *UnmarshalTypeError) Code() string {
704	return "UnmarshalTypeError"
705}
706
707// Message returns the detailed message of the error, satisfying
708// the awserr.Error interface.
709func (e *UnmarshalTypeError) Message() string {
710	return "cannot unmarshal " + e.Value + " into Go value of type " + e.Type.String()
711}
712
713// An InvalidUnmarshalError is an error type representing an invalid type
714// encountered while unmarshaling a AttributeValue to a Go value type.
715type InvalidUnmarshalError struct {
716	emptyOrigError
717	Type reflect.Type
718}
719
720// Error returns the string representation of the error.
721// satisfying the error interface
722func (e *InvalidUnmarshalError) Error() string {
723	return fmt.Sprintf("%s: %s", e.Code(), e.Message())
724}
725
726// Code returns the code of the error, satisfying the awserr.Error
727// interface.
728func (e *InvalidUnmarshalError) Code() string {
729	return "InvalidUnmarshalError"
730}
731
732// Message returns the detailed message of the error, satisfying
733// the awserr.Error interface.
734func (e *InvalidUnmarshalError) Message() string {
735	if e.Type == nil {
736		return "cannot unmarshal to nil value"
737	}
738	if e.Type.Kind() != reflect.Ptr {
739		return "cannot unmarshal to non-pointer value, got " + e.Type.String()
740	}
741	return "cannot unmarshal to nil value, " + e.Type.String()
742}
743
744// An UnmarshalError wraps an error that occurred while unmarshaling a DynamoDB
745// AttributeValue element into a Go type. This is different from UnmarshalTypeError
746// in that it wraps the underlying error that occurred.
747type UnmarshalError struct {
748	Err   error
749	Value string
750	Type  reflect.Type
751}
752
753// Error returns the string representation of the error.
754// satisfying the error interface.
755func (e *UnmarshalError) Error() string {
756	return fmt.Sprintf("%s: %s\ncaused by: %v", e.Code(), e.Message(), e.Err)
757}
758
759// OrigErr returns the original error that caused this issue.
760func (e UnmarshalError) OrigErr() error {
761	return e.Err
762}
763
764// Code returns the code of the error, satisfying the awserr.Error
765// interface.
766func (e *UnmarshalError) Code() string {
767	return "UnmarshalError"
768}
769
770// Message returns the detailed message of the error, satisfying
771// the awserr.Error interface.
772func (e *UnmarshalError) Message() string {
773	return fmt.Sprintf("cannot unmarshal %q into %s.",
774		e.Value, e.Type.String())
775}
776