func (e *Encoder) encodeScalar(av *dynamodb.AttributeValue, v reflect.Value, fieldTag tag) error { if v.Type() == numberType { s := v.String() if fieldTag.AsString { av.S = &s } else { av.N = &s } return nil } switch v.Kind() { case reflect.Bool: av.BOOL = new(bool) *av.BOOL = v.Bool() case reflect.String: if err := e.encodeString(av, v); err != nil { return err } default: // Fallback to encoding numbers, will return invalid type if not supported if err := e.encodeNumber(av, v); err != nil { return err } if fieldTag.AsString && av.NULL == nil && av.N != nil { av.S = av.N av.N = nil } } return nil }
func (e *Encoder) encodeScalar(av *dynamodb.AttributeValue, v reflect.Value, fieldTag tag) error { switch typed := v.Interface().(type) { case bool: av.BOOL = new(bool) *av.BOOL = typed case string: if err := e.encodeString(av, v); err != nil { return err } case Number: s := string(typed) if fieldTag.AsString { av.S = &s } else { av.N = &s } default: // Fallback to encoding numbers, will return invalid type if not supported if err := e.encodeNumber(av, v); err != nil { return err } if fieldTag.AsString && av.NULL == nil && av.N != nil { av.S = av.N av.N = nil } } return nil }
func (e *Encoder) encodeStruct(av *dynamodb.AttributeValue, v reflect.Value) error { // To maintain backwards compatibility with ConvertTo family of methods which // converted time.Time structs to strings if t, ok := v.Interface().(time.Time); ok { s := t.Format(time.RFC3339Nano) av.S = &s return nil } av.M = map[string]*dynamodb.AttributeValue{} fields := unionStructFields(v.Type(), e.MarshalOptions) for _, f := range fields { if f.Name == "" { return &InvalidMarshalError{msg: "map key cannot be empty"} } fv := v.FieldByIndex(f.Index) elem := &dynamodb.AttributeValue{} err := e.encode(elem, fv, f.tag) skip, err := keepOrOmitEmpty(f.OmitEmpty, elem, err) if err != nil { return err } else if skip { continue } av.M[f.Name] = elem } if len(av.M) == 0 { encodeNull(av) } return nil }
func (e *Encoder) encodeSlice(av *dynamodb.AttributeValue, v reflect.Value, fieldTag tag) error { switch v.Type().Elem().Kind() { case reflect.Uint8: b := v.Bytes() if len(b) == 0 { encodeNull(av) return nil } av.B = append([]byte{}, b...) default: var elemFn func(dynamodb.AttributeValue) error if fieldTag.AsBinSet || v.Type() == byteSliceSlicetype { // Binary Set av.BS = make([][]byte, 0, v.Len()) elemFn = func(elem dynamodb.AttributeValue) error { if elem.B == nil { return &InvalidMarshalError{msg: "binary set must only contain non-nil byte slices"} } av.BS = append(av.BS, elem.B) return nil } } else if fieldTag.AsNumSet { // Number Set av.NS = make([]*string, 0, v.Len()) elemFn = func(elem dynamodb.AttributeValue) error { if elem.N == nil { return &InvalidMarshalError{msg: "number set must only contain non-nil string numbers"} } av.NS = append(av.NS, elem.N) return nil } } else if fieldTag.AsStrSet { // String Set av.SS = make([]*string, 0, v.Len()) elemFn = func(elem dynamodb.AttributeValue) error { if elem.S == nil { return &InvalidMarshalError{msg: "string set must only contain non-nil strings"} } av.SS = append(av.SS, elem.S) return nil } } else { // List av.L = make([]*dynamodb.AttributeValue, 0, v.Len()) elemFn = func(elem dynamodb.AttributeValue) error { av.L = append(av.L, &elem) return nil } } if n, err := e.encodeList(v, fieldTag, elemFn); err != nil { return err } else if n == 0 { encodeNull(av) } } return nil }
func (e *Encoder) encodeMap(av *dynamodb.AttributeValue, v reflect.Value, fieldTag tag) error { av.M = map[string]*dynamodb.AttributeValue{} for _, key := range v.MapKeys() { keyName := fmt.Sprint(key.Interface()) if keyName == "" { return &InvalidMarshalError{msg: "map key cannot be empty"} } elemVal := v.MapIndex(key) elem := &dynamodb.AttributeValue{} err := e.encode(elem, elemVal, tag{}) skip, err := keepOrOmitEmpty(fieldTag.OmitEmptyElem, elem, err) if err != nil { return err } else if skip { continue } av.M[keyName] = elem } if len(av.M) == 0 { encodeNull(av) } return nil }
func (e *Encoder) encodeStruct(av *dynamodb.AttributeValue, v reflect.Value) error { av.M = map[string]*dynamodb.AttributeValue{} fields := unionStructFields(v.Type(), e.MarshalOptions) for _, f := range fields { if f.Name == "" { return &InvalidMarshalError{msg: "map key cannot be empty"} } fv := v.FieldByIndex(f.Index) elem := &dynamodb.AttributeValue{} err := e.encode(elem, fv, f.tag) skip, err := keepOrOmitEmpty(f.OmitEmpty, elem, err) if err != nil { return err } else if skip { continue } av.M[f.Name] = elem } if len(av.M) == 0 { encodeNull(av) } return nil }
func (m *marshalMarshaler) MarshalDynamoDBAttributeValue(av *dynamodb.AttributeValue) error { av.M = map[string]*dynamodb.AttributeValue{ "abc": {S: &m.Value}, "def": {N: aws.String(fmt.Sprintf("%d", m.Value2))}, "ghi": {BOOL: &m.Value3}, } return nil }
func (e *Encoder) encodeString(av *dynamodb.AttributeValue, v reflect.Value) error { if used, err := tryMarshaler(av, v); used { return err } switch typed := v.Interface().(type) { case string: if len(typed) == 0 && e.NullEmptyString { encodeNull(av) } else { av.S = &typed } default: return &unsupportedMarshalTypeError{Type: v.Type()} } return nil }
func (e *Encoder) encodeString(av *dynamodb.AttributeValue, v reflect.Value) error { if used, err := tryMarshaler(av, v); used { return err } switch v.Kind() { case reflect.String: s := v.String() if len(s) == 0 && e.NullEmptyString { encodeNull(av) } else { av.S = &s } default: return &unsupportedMarshalTypeError{Type: v.Type()} } return nil }
func (e *Encoder) encodeNumber(av *dynamodb.AttributeValue, v reflect.Value) error { if used, err := tryMarshaler(av, v); used { return err } var out string switch v.Kind() { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: out = encodeInt(v.Int()) case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: out = encodeUint(v.Uint()) case reflect.Float32, reflect.Float64: out = encodeFloat(v.Float()) default: return &unsupportedMarshalTypeError{Type: v.Type()} } av.N = &out return nil }
func (e *Encoder) encodeNumber(av *dynamodb.AttributeValue, v reflect.Value) error { if used, err := tryMarshaler(av, v); used { return err } var out string switch typed := v.Interface().(type) { case int: out = encodeInt(int64(typed)) case int8: out = encodeInt(int64(typed)) case int16: out = encodeInt(int64(typed)) case int32: out = encodeInt(int64(typed)) case int64: out = encodeInt(typed) case uint: out = encodeUint(uint64(typed)) case uint8: out = encodeUint(uint64(typed)) case uint16: out = encodeUint(uint64(typed)) case uint32: out = encodeUint(uint64(typed)) case uint64: out = encodeUint(typed) case float32: out = encodeFloat(float64(typed)) case float64: out = encodeFloat(typed) default: return &unsupportedMarshalTypeError{Type: v.Type()} } av.N = &out return nil }