github.com/aavshr/aws-sdk-go@v1.41.3/service/dynamodb/dynamodbattribute/encode.go (about)

     1  package dynamodbattribute
     2  
     3  import (
     4  	"fmt"
     5  	"reflect"
     6  	"strconv"
     7  	"time"
     8  
     9  	"github.com/aavshr/aws-sdk-go/aws"
    10  	"github.com/aavshr/aws-sdk-go/service/dynamodb"
    11  )
    12  
    13  // An UnixTime provides aliasing of time.Time into a type that when marshaled
    14  // and unmarshaled with DynamoDB AttributeValues it will be done so as number
    15  // instead of string in seconds since January 1, 1970 UTC.
    16  //
    17  // This type is useful as an alternative to the struct tag `unixtime` when you
    18  // want to have your time value marshaled as Unix time in seconds intead of
    19  // the default time.RFC3339.
    20  //
    21  // Important to note that zero value time as unixtime is not 0 seconds
    22  // from January 1, 1970 UTC, but -62135596800. Which is seconds between
    23  // January 1, 0001 UTC, and January 1, 0001 UTC.
    24  type UnixTime time.Time
    25  
    26  // MarshalDynamoDBAttributeValue implements the Marshaler interface so that
    27  // the UnixTime can be marshaled from to a DynamoDB AttributeValue number
    28  // value encoded in the number of seconds since January 1, 1970 UTC.
    29  func (e UnixTime) MarshalDynamoDBAttributeValue(av *dynamodb.AttributeValue) error {
    30  	t := time.Time(e)
    31  	s := strconv.FormatInt(t.Unix(), 10)
    32  	av.N = &s
    33  
    34  	return nil
    35  }
    36  
    37  // UnmarshalDynamoDBAttributeValue implements the Unmarshaler interface so that
    38  // the UnixTime can be unmarshaled from a DynamoDB AttributeValue number representing
    39  // the number of seconds since January 1, 1970 UTC.
    40  //
    41  // If an error parsing the AttributeValue number occurs UnmarshalError will be
    42  // returned.
    43  func (e *UnixTime) UnmarshalDynamoDBAttributeValue(av *dynamodb.AttributeValue) error {
    44  	t, err := decodeUnixTime(aws.StringValue(av.N))
    45  	if err != nil {
    46  		return err
    47  	}
    48  
    49  	*e = UnixTime(t)
    50  	return nil
    51  }
    52  
    53  // A Marshaler is an interface to provide custom marshaling of Go value types
    54  // to AttributeValues. Use this to provide custom logic determining how a
    55  // Go Value type should be marshaled.
    56  //
    57  //		type ExampleMarshaler struct {
    58  //			Value int
    59  //		}
    60  //		func (m *ExampleMarshaler) 	MarshalDynamoDBAttributeValue(av *dynamodb.AttributeValue) error {
    61  //			n := fmt.Sprintf("%v", m.Value)
    62  //			av.N = &n
    63  //			return nil
    64  //		}
    65  //
    66  type Marshaler interface {
    67  	MarshalDynamoDBAttributeValue(*dynamodb.AttributeValue) error
    68  }
    69  
    70  // Marshal will serialize the passed in Go value type into a DynamoDB AttributeValue
    71  // type. This value can be used in DynamoDB API operations to simplify marshaling
    72  // your Go value types into AttributeValues.
    73  //
    74  // Marshal will recursively transverse the passed in value marshaling its
    75  // contents into a AttributeValue. Marshal supports basic scalars
    76  // (int,uint,float,bool,string), maps, slices, and structs. Anonymous
    77  // nested types are flattened based on Go anonymous type visibility.
    78  //
    79  // Marshaling slices to AttributeValue will default to a List for all
    80  // types except for []byte and [][]byte. []byte will be marshaled as
    81  // Binary data (B), and [][]byte will be marshaled as binary data set
    82  // (BS).
    83  //
    84  // `dynamodbav` struct tag can be used to control how the value will be
    85  // marshaled into a AttributeValue.
    86  //
    87  //		// Field is ignored
    88  //		Field int `dynamodbav:"-"`
    89  //
    90  //		// Field AttributeValue map key "myName"
    91  //		Field int `dynamodbav:"myName"`
    92  //
    93  //		// Field AttributeValue map key "myName", and
    94  //		// Field is omitted if it is empty
    95  //		Field int `dynamodbav:"myName,omitempty"`
    96  //
    97  //		// Field AttributeValue map key "Field", and
    98  //		// Field is omitted if it is empty
    99  //		Field int `dynamodbav:",omitempty"`
   100  //
   101  //		// Field's elems will be omitted if empty
   102  //		// only valid for slices, and maps.
   103  //		Field []string `dynamodbav:",omitemptyelem"`
   104  //
   105  //		// Field will be marshaled as a AttributeValue string
   106  //		// only value for number types, (int,uint,float)
   107  //		Field int `dynamodbav:",string"`
   108  //
   109  //		// Field will be marshaled as a binary set
   110  //		Field [][]byte `dynamodbav:",binaryset"`
   111  //
   112  //		// Field will be marshaled as a number set
   113  //		Field []int `dynamodbav:",numberset"`
   114  //
   115  //		// Field will be marshaled as a string set
   116  //		Field []string `dynamodbav:",stringset"`
   117  //
   118  //		// Field will be marshaled as Unix time number in seconds.
   119  //		// This tag is only valid with time.Time typed struct fields.
   120  //		// Important to note that zero value time as unixtime is not 0 seconds
   121  //		// from January 1, 1970 UTC, but -62135596800. Which is seconds between
   122  //		// January 1, 0001 UTC, and January 1, 0001 UTC.
   123  //		Field time.Time `dynamodbav:",unixtime"`
   124  //
   125  // The omitempty tag is only used during Marshaling and is ignored for
   126  // Unmarshal. Any zero value or a value when marshaled results in a
   127  // AttributeValue NULL will be added to AttributeValue Maps during struct
   128  // marshal. The omitemptyelem tag works the same as omitempty except it
   129  // applies to maps and slices instead of struct fields, and will not be
   130  // included in the marshaled AttributeValue Map, List, or Set.
   131  //
   132  // For convenience and backwards compatibility with ConvertTo functions
   133  // json struct tags are supported by the Marshal and Unmarshal. If
   134  // both json and dynamodbav struct tags are provided the json tag will
   135  // be ignored in favor of dynamodbav.
   136  //
   137  // All struct fields and with anonymous fields, are marshaled unless the
   138  // any of the following conditions are meet.
   139  //
   140  //		- the field is not exported
   141  //		- json or dynamodbav field tag is "-"
   142  //		- json or dynamodbav field tag specifies "omitempty", and is empty.
   143  //
   144  // Pointer and interfaces values encode as the value pointed to or contained
   145  // in the interface. A nil value encodes as the AttributeValue NULL value.
   146  //
   147  // Channel, complex, and function values are not encoded and will be skipped
   148  // when walking the value to be marshaled.
   149  //
   150  // When marshaling any error that occurs will halt the marshal and return
   151  // the error.
   152  //
   153  // Marshal cannot represent cyclic data structures and will not handle them.
   154  // Passing cyclic structures to Marshal will result in an infinite recursion.
   155  func Marshal(in interface{}) (*dynamodb.AttributeValue, error) {
   156  	return NewEncoder().Encode(in)
   157  }
   158  
   159  // MarshalMap is an alias for Marshal func which marshals Go value
   160  // type to a map of AttributeValues.
   161  //
   162  // This is useful for DynamoDB APIs such as PutItem.
   163  func MarshalMap(in interface{}) (map[string]*dynamodb.AttributeValue, error) {
   164  	av, err := NewEncoder().Encode(in)
   165  	if err != nil || av == nil || av.M == nil {
   166  		return map[string]*dynamodb.AttributeValue{}, err
   167  	}
   168  
   169  	return av.M, nil
   170  }
   171  
   172  // MarshalList is an alias for Marshal func which marshals Go value
   173  // type to a slice of AttributeValues.
   174  func MarshalList(in interface{}) ([]*dynamodb.AttributeValue, error) {
   175  	av, err := NewEncoder().Encode(in)
   176  	if err != nil || av == nil || av.L == nil {
   177  		return []*dynamodb.AttributeValue{}, err
   178  	}
   179  
   180  	return av.L, nil
   181  }
   182  
   183  // A MarshalOptions is a collection of options shared between marshaling
   184  // and unmarshaling
   185  type MarshalOptions struct {
   186  	// States that the encoding/json struct tags should be supported.
   187  	// if a `dynamodbav` struct tag is also provided the encoding/json
   188  	// tag will be ignored.
   189  	//
   190  	// Enabled by default.
   191  	SupportJSONTags bool
   192  
   193  	// Support other custom struct tag keys, such as `yaml` or `toml`.
   194  	// Note that values provided with a custom TagKey must also be supported
   195  	// by the (un)marshalers in this package.
   196  	TagKey string
   197  
   198  	// EnableEmptyCollections modifies how structures, maps, and slices are (un)marshalled.
   199  	// When set to true empty collection values will be preserved as their respective
   200  	// empty DynamoDB AttributeValue type when set to true.
   201  	//
   202  	// Disabled by default.
   203  	EnableEmptyCollections bool
   204  }
   205  
   206  // An Encoder provides marshaling Go value types to AttributeValues.
   207  type Encoder struct {
   208  	MarshalOptions
   209  
   210  	// Empty strings, "", will be marked as NULL AttributeValue types.
   211  	// Will not apply to lists, sets, or maps. Use the struct tag `omitemptyelem`
   212  	// to skip empty (zero) values in lists, sets and maps.
   213  	//
   214  	// Enabled by default.
   215  	NullEmptyString bool
   216  
   217  	// Empty byte slices, len([]byte{}) == 0, will be marked as NULL AttributeValue types.
   218  	// Will not apply to lists, sets, or maps. Use the struct tag `omitemptyelem`
   219  	// to skip empty (zero) values in lists, sets and maps.
   220  	//
   221  	// Enabled by default.
   222  	NullEmptyByteSlice bool
   223  }
   224  
   225  // NewEncoder creates a new Encoder with default configuration. Use
   226  // the `opts` functional options to override the default configuration.
   227  func NewEncoder(opts ...func(*Encoder)) *Encoder {
   228  	e := &Encoder{
   229  		MarshalOptions: MarshalOptions{
   230  			SupportJSONTags: true,
   231  		},
   232  		NullEmptyString:    true,
   233  		NullEmptyByteSlice: true,
   234  	}
   235  	for _, o := range opts {
   236  		o(e)
   237  	}
   238  
   239  	return e
   240  }
   241  
   242  // Encode will marshal a Go value type to an AttributeValue. Returning
   243  // the AttributeValue constructed or error.
   244  func (e *Encoder) Encode(in interface{}) (*dynamodb.AttributeValue, error) {
   245  	av := &dynamodb.AttributeValue{}
   246  	if err := e.encode(av, reflect.ValueOf(in), tag{}); err != nil {
   247  		return nil, err
   248  	}
   249  
   250  	return av, nil
   251  }
   252  
   253  func (e *Encoder) encode(av *dynamodb.AttributeValue, v reflect.Value, fieldTag tag) error {
   254  	// We should check for omitted values first before dereferencing.
   255  	if fieldTag.OmitEmpty && emptyValue(v, e.EnableEmptyCollections) {
   256  		encodeNull(av)
   257  		return nil
   258  	}
   259  
   260  	// Handle both pointers and interface conversion into types
   261  	v = valueElem(v)
   262  
   263  	if v.Kind() != reflect.Invalid {
   264  		if used, err := tryMarshaler(av, v); used {
   265  			return err
   266  		}
   267  	}
   268  
   269  	switch v.Kind() {
   270  	case reflect.Invalid:
   271  		encodeNull(av)
   272  	case reflect.Struct:
   273  		return e.encodeStruct(av, v, fieldTag)
   274  	case reflect.Map:
   275  		return e.encodeMap(av, v, fieldTag)
   276  	case reflect.Slice, reflect.Array:
   277  		return e.encodeSlice(av, v, fieldTag)
   278  	case reflect.Chan, reflect.Func, reflect.UnsafePointer:
   279  		// do nothing for unsupported types
   280  	default:
   281  		return e.encodeScalar(av, v, fieldTag)
   282  	}
   283  
   284  	return nil
   285  }
   286  
   287  func (e *Encoder) encodeStruct(av *dynamodb.AttributeValue, v reflect.Value, fieldTag tag) error {
   288  	// To maintain backwards compatibility with ConvertTo family of methods which
   289  	// converted time.Time structs to strings
   290  	if v.Type().ConvertibleTo(timeType) {
   291  		var t time.Time
   292  		t = v.Convert(timeType).Interface().(time.Time)
   293  		if fieldTag.AsUnixTime {
   294  			return UnixTime(t).MarshalDynamoDBAttributeValue(av)
   295  		}
   296  		s := t.Format(time.RFC3339Nano)
   297  		av.S = &s
   298  		return nil
   299  	}
   300  
   301  	av.M = map[string]*dynamodb.AttributeValue{}
   302  	fields := unionStructFields(v.Type(), e.MarshalOptions)
   303  	for _, f := range fields.All() {
   304  		if f.Name == "" {
   305  			return &InvalidMarshalError{msg: "map key cannot be empty"}
   306  		}
   307  
   308  		fv, found := encoderFieldByIndex(v, f.Index)
   309  		if !found {
   310  			continue
   311  		}
   312  		elem := &dynamodb.AttributeValue{}
   313  		err := e.encode(elem, fv, f.tag)
   314  		if err != nil {
   315  			return err
   316  		}
   317  		skip, err := keepOrOmitEmpty(f.OmitEmpty, elem, err)
   318  		if err != nil {
   319  			return err
   320  		} else if skip {
   321  			continue
   322  		}
   323  
   324  		av.M[f.Name] = elem
   325  	}
   326  	if len(av.M) == 0 && !e.EnableEmptyCollections {
   327  		encodeNull(av)
   328  	}
   329  
   330  	return nil
   331  }
   332  
   333  func (e *Encoder) encodeMap(av *dynamodb.AttributeValue, v reflect.Value, fieldTag tag) error {
   334  	av.M = map[string]*dynamodb.AttributeValue{}
   335  	for _, key := range v.MapKeys() {
   336  		keyName := fmt.Sprint(key.Interface())
   337  		if keyName == "" {
   338  			return &InvalidMarshalError{msg: "map key cannot be empty"}
   339  		}
   340  
   341  		elemVal := v.MapIndex(key)
   342  		elem := &dynamodb.AttributeValue{}
   343  		err := e.encode(elem, elemVal, tag{})
   344  		skip, err := keepOrOmitEmpty(fieldTag.OmitEmptyElem, elem, err)
   345  		if err != nil {
   346  			return err
   347  		} else if skip {
   348  			continue
   349  		}
   350  
   351  		av.M[keyName] = elem
   352  	}
   353  
   354  	if v.IsNil() || (len(av.M) == 0 && !e.EnableEmptyCollections) {
   355  		encodeNull(av)
   356  	}
   357  
   358  	return nil
   359  }
   360  
   361  func (e *Encoder) encodeSlice(av *dynamodb.AttributeValue, v reflect.Value, fieldTag tag) error {
   362  	if v.Kind() == reflect.Array && v.Len() == 0 && e.EnableEmptyCollections && fieldTag.OmitEmpty {
   363  		encodeNull(av)
   364  		return nil
   365  	}
   366  
   367  	switch v.Type().Elem().Kind() {
   368  	case reflect.Uint8:
   369  		slice := reflect.MakeSlice(byteSliceType, v.Len(), v.Len())
   370  		reflect.Copy(slice, v)
   371  
   372  		b := slice.Bytes()
   373  		if (v.Kind() == reflect.Slice && v.IsNil()) || (len(b) == 0 && !e.EnableEmptyCollections && e.NullEmptyByteSlice) {
   374  			encodeNull(av)
   375  			return nil
   376  		}
   377  		av.B = append([]byte{}, b...)
   378  	default:
   379  		var elemFn func(dynamodb.AttributeValue) error
   380  
   381  		if fieldTag.AsBinSet || v.Type() == byteSliceSlicetype { // Binary Set
   382  			av.BS = make([][]byte, 0, v.Len())
   383  			elemFn = func(elem dynamodb.AttributeValue) error {
   384  				if elem.B == nil {
   385  					return &InvalidMarshalError{msg: "binary set must only contain non-nil byte slices"}
   386  				}
   387  				av.BS = append(av.BS, elem.B)
   388  				return nil
   389  			}
   390  		} else if fieldTag.AsNumSet { // Number Set
   391  			av.NS = make([]*string, 0, v.Len())
   392  			elemFn = func(elem dynamodb.AttributeValue) error {
   393  				if elem.N == nil {
   394  					return &InvalidMarshalError{msg: "number set must only contain non-nil string numbers"}
   395  				}
   396  				av.NS = append(av.NS, elem.N)
   397  				return nil
   398  			}
   399  		} else if fieldTag.AsStrSet { // String Set
   400  			av.SS = make([]*string, 0, v.Len())
   401  			elemFn = func(elem dynamodb.AttributeValue) error {
   402  				if elem.S == nil {
   403  					return &InvalidMarshalError{msg: "string set must only contain non-nil strings"}
   404  				}
   405  				av.SS = append(av.SS, elem.S)
   406  				return nil
   407  			}
   408  		} else { // List
   409  			av.L = make([]*dynamodb.AttributeValue, 0, v.Len())
   410  			elemFn = func(elem dynamodb.AttributeValue) error {
   411  				av.L = append(av.L, &elem)
   412  				return nil
   413  			}
   414  		}
   415  
   416  		if n, err := e.encodeList(v, fieldTag, elemFn); err != nil {
   417  			return err
   418  		} else if (v.Kind() == reflect.Slice && v.IsNil()) || (n == 0 && !e.EnableEmptyCollections) {
   419  			encodeNull(av)
   420  		}
   421  	}
   422  
   423  	return nil
   424  }
   425  
   426  func (e *Encoder) encodeList(v reflect.Value, fieldTag tag, elemFn func(dynamodb.AttributeValue) error) (int, error) {
   427  	count := 0
   428  	for i := 0; i < v.Len(); i++ {
   429  		elem := dynamodb.AttributeValue{}
   430  		err := e.encode(&elem, v.Index(i), tag{OmitEmpty: fieldTag.OmitEmptyElem})
   431  		skip, err := keepOrOmitEmpty(fieldTag.OmitEmptyElem, &elem, err)
   432  		if err != nil {
   433  			return 0, err
   434  		} else if skip {
   435  			continue
   436  		}
   437  
   438  		if err := elemFn(elem); err != nil {
   439  			return 0, err
   440  		}
   441  		count++
   442  	}
   443  
   444  	return count, nil
   445  }
   446  
   447  func (e *Encoder) encodeScalar(av *dynamodb.AttributeValue, v reflect.Value, fieldTag tag) error {
   448  	if v.Type() == numberType || v.Type() == jsonNumberType {
   449  		s := v.String()
   450  		if fieldTag.AsString {
   451  			av.S = &s
   452  		} else {
   453  			av.N = &s
   454  		}
   455  		return nil
   456  	}
   457  
   458  	switch v.Kind() {
   459  	case reflect.Bool:
   460  		av.BOOL = new(bool)
   461  		*av.BOOL = v.Bool()
   462  	case reflect.String:
   463  		if err := e.encodeString(av, v); err != nil {
   464  			return err
   465  		}
   466  	default:
   467  		// Fallback to encoding numbers, will return invalid type if not supported
   468  		if err := e.encodeNumber(av, v); err != nil {
   469  			return err
   470  		}
   471  		if fieldTag.AsString && av.NULL == nil && av.N != nil {
   472  			av.S = av.N
   473  			av.N = nil
   474  		}
   475  	}
   476  
   477  	return nil
   478  }
   479  
   480  func (e *Encoder) encodeNumber(av *dynamodb.AttributeValue, v reflect.Value) error {
   481  	if used, err := tryMarshaler(av, v); used {
   482  		return err
   483  	}
   484  
   485  	var out string
   486  	switch v.Kind() {
   487  	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
   488  		out = encodeInt(v.Int())
   489  	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
   490  		out = encodeUint(v.Uint())
   491  	case reflect.Float32:
   492  		out = encodeFloat(v.Float(), 32)
   493  	case reflect.Float64:
   494  		out = encodeFloat(v.Float(), 64)
   495  	default:
   496  		return &unsupportedMarshalTypeError{Type: v.Type()}
   497  	}
   498  
   499  	av.N = &out
   500  
   501  	return nil
   502  }
   503  
   504  func (e *Encoder) encodeString(av *dynamodb.AttributeValue, v reflect.Value) error {
   505  	if used, err := tryMarshaler(av, v); used {
   506  		return err
   507  	}
   508  
   509  	switch v.Kind() {
   510  	case reflect.String:
   511  		s := v.String()
   512  		if len(s) == 0 && e.NullEmptyString {
   513  			encodeNull(av)
   514  		} else {
   515  			av.S = &s
   516  		}
   517  	default:
   518  		return &unsupportedMarshalTypeError{Type: v.Type()}
   519  	}
   520  
   521  	return nil
   522  }
   523  
   524  func encodeInt(i int64) string {
   525  	return strconv.FormatInt(i, 10)
   526  }
   527  func encodeUint(u uint64) string {
   528  	return strconv.FormatUint(u, 10)
   529  }
   530  func encodeFloat(f float64, bitSize int) string {
   531  	return strconv.FormatFloat(f, 'f', -1, bitSize)
   532  }
   533  func encodeNull(av *dynamodb.AttributeValue) {
   534  	t := true
   535  	*av = dynamodb.AttributeValue{NULL: &t}
   536  }
   537  
   538  // encoderFieldByIndex finds the field with the provided nested index
   539  func encoderFieldByIndex(v reflect.Value, index []int) (reflect.Value, bool) {
   540  	for i, x := range index {
   541  		if i > 0 && v.Kind() == reflect.Ptr && v.Type().Elem().Kind() == reflect.Struct {
   542  			if v.IsNil() {
   543  				return reflect.Value{}, false
   544  			}
   545  			v = v.Elem()
   546  		}
   547  		v = v.Field(x)
   548  	}
   549  	return v, true
   550  }
   551  
   552  func valueElem(v reflect.Value) reflect.Value {
   553  	switch v.Kind() {
   554  	case reflect.Interface, reflect.Ptr:
   555  		for v.Kind() == reflect.Interface || v.Kind() == reflect.Ptr {
   556  			v = v.Elem()
   557  		}
   558  	}
   559  
   560  	return v
   561  }
   562  
   563  func emptyValue(v reflect.Value, emptyCollections bool) bool {
   564  	switch v.Kind() {
   565  	case reflect.Array:
   566  		return v.Len() == 0 && !emptyCollections
   567  	case reflect.Map, reflect.Slice:
   568  		return v.IsNil() || (v.Len() == 0 && !emptyCollections)
   569  	case reflect.String:
   570  		return v.Len() == 0
   571  	case reflect.Bool:
   572  		return !v.Bool()
   573  	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
   574  		return v.Int() == 0
   575  	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
   576  		return v.Uint() == 0
   577  	case reflect.Float32, reflect.Float64:
   578  		return v.Float() == 0
   579  	case reflect.Interface, reflect.Ptr:
   580  		return v.IsNil()
   581  	}
   582  	return false
   583  }
   584  
   585  func tryMarshaler(av *dynamodb.AttributeValue, v reflect.Value) (bool, error) {
   586  	if v.Kind() != reflect.Ptr && v.Type().Name() != "" && v.CanAddr() {
   587  		v = v.Addr()
   588  	}
   589  
   590  	if v.Type().NumMethod() == 0 {
   591  		return false, nil
   592  	}
   593  
   594  	if m, ok := v.Interface().(Marshaler); ok {
   595  		return true, m.MarshalDynamoDBAttributeValue(av)
   596  	}
   597  
   598  	return false, nil
   599  }
   600  
   601  func keepOrOmitEmpty(omitEmpty bool, av *dynamodb.AttributeValue, err error) (bool, error) {
   602  	if err != nil {
   603  		if _, ok := err.(*unsupportedMarshalTypeError); ok {
   604  			return true, nil
   605  		}
   606  		return false, err
   607  	}
   608  
   609  	if av.NULL != nil && omitEmpty {
   610  		return true, nil
   611  	}
   612  
   613  	return false, nil
   614  }
   615  
   616  // An InvalidMarshalError is an error type representing an error
   617  // occurring when marshaling a Go value type to an AttributeValue.
   618  type InvalidMarshalError struct {
   619  	emptyOrigError
   620  	msg string
   621  }
   622  
   623  // Error returns the string representation of the error.
   624  // satisfying the error interface
   625  func (e *InvalidMarshalError) Error() string {
   626  	return fmt.Sprintf("%s: %s", e.Code(), e.Message())
   627  }
   628  
   629  // Code returns the code of the error, satisfying the awserr.Error
   630  // interface.
   631  func (e *InvalidMarshalError) Code() string {
   632  	return "InvalidMarshalError"
   633  }
   634  
   635  // Message returns the detailed message of the error, satisfying
   636  // the awserr.Error interface.
   637  func (e *InvalidMarshalError) Message() string {
   638  	return e.msg
   639  }
   640  
   641  // An unsupportedMarshalTypeError represents a Go value type
   642  // which cannot be marshaled into an AttributeValue and should
   643  // be skipped by the marshaler.
   644  type unsupportedMarshalTypeError struct {
   645  	emptyOrigError
   646  	Type reflect.Type
   647  }
   648  
   649  // Error returns the string representation of the error.
   650  // satisfying the error interface
   651  func (e *unsupportedMarshalTypeError) Error() string {
   652  	return fmt.Sprintf("%s: %s", e.Code(), e.Message())
   653  }
   654  
   655  // Code returns the code of the error, satisfying the awserr.Error
   656  // interface.
   657  func (e *unsupportedMarshalTypeError) Code() string {
   658  	return "unsupportedMarshalTypeError"
   659  }
   660  
   661  // Message returns the detailed message of the error, satisfying
   662  // the awserr.Error interface.
   663  func (e *unsupportedMarshalTypeError) Message() string {
   664  	return "Go value type " + e.Type.String() + " is not supported"
   665  }