Example #1
0
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
}
Example #2
0
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
}
Example #3
0
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
}
Example #4
0
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
}
Example #5
0
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
}
Example #6
0
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
}
Example #8
0
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
}
Example #9
0
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
}
Example #10
0
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
}
Example #11
0
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
}