Switch to using the dep tool and update all the dependencies
This commit is contained in:
parent
5135ff73cb
commit
98c2d2c41b
5321 changed files with 4483201 additions and 5922 deletions
443
vendor/github.com/aws/aws-sdk-go/service/dynamodb/dynamodbattribute/converter.go
generated
vendored
Normal file
443
vendor/github.com/aws/aws-sdk-go/service/dynamodb/dynamodbattribute/converter.go
generated
vendored
Normal file
|
@ -0,0 +1,443 @@
|
|||
package dynamodbattribute
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"strconv"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
"github.com/aws/aws-sdk-go/service/dynamodb"
|
||||
)
|
||||
|
||||
// ConvertToMap accepts a map[string]interface{} or struct and converts it to a
|
||||
// map[string]*dynamodb.AttributeValue.
|
||||
//
|
||||
// If in contains any structs, it is first JSON encoded/decoded it to convert it
|
||||
// to a map[string]interface{}, so `json` struct tags are respected.
|
||||
//
|
||||
// Deprecated: Use MarshalMap instead
|
||||
func ConvertToMap(in interface{}) (item map[string]*dynamodb.AttributeValue, err error) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
if e, ok := r.(runtime.Error); ok {
|
||||
err = e
|
||||
} else if s, ok := r.(string); ok {
|
||||
err = fmt.Errorf(s)
|
||||
} else {
|
||||
err = r.(error)
|
||||
}
|
||||
item = nil
|
||||
}
|
||||
}()
|
||||
|
||||
if in == nil {
|
||||
return nil, awserr.New("SerializationError",
|
||||
"in must be a map[string]interface{} or struct, got <nil>", nil)
|
||||
}
|
||||
|
||||
v := reflect.ValueOf(in)
|
||||
if v.Kind() != reflect.Struct && !(v.Kind() == reflect.Map && v.Type().Key().Kind() == reflect.String) {
|
||||
return nil, awserr.New("SerializationError",
|
||||
fmt.Sprintf("in must be a map[string]interface{} or struct, got %s",
|
||||
v.Type().String()),
|
||||
nil)
|
||||
}
|
||||
|
||||
if isTyped(reflect.TypeOf(in)) {
|
||||
var out map[string]interface{}
|
||||
in = convertToUntyped(in, out)
|
||||
}
|
||||
|
||||
item = make(map[string]*dynamodb.AttributeValue)
|
||||
for k, v := range in.(map[string]interface{}) {
|
||||
item[k] = convertTo(v)
|
||||
}
|
||||
|
||||
return item, nil
|
||||
}
|
||||
|
||||
// ConvertFromMap accepts a map[string]*dynamodb.AttributeValue and converts it to a
|
||||
// map[string]interface{} or struct.
|
||||
//
|
||||
// If v points to a struct, the result is first converted it to a
|
||||
// map[string]interface{}, then JSON encoded/decoded it to convert to a struct,
|
||||
// so `json` struct tags are respected.
|
||||
//
|
||||
// Deprecated: Use UnmarshalMap instead
|
||||
func ConvertFromMap(item map[string]*dynamodb.AttributeValue, v interface{}) (err error) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
if e, ok := r.(runtime.Error); ok {
|
||||
err = e
|
||||
} else if s, ok := r.(string); ok {
|
||||
err = fmt.Errorf(s)
|
||||
} else {
|
||||
err = r.(error)
|
||||
}
|
||||
item = nil
|
||||
}
|
||||
}()
|
||||
|
||||
rv := reflect.ValueOf(v)
|
||||
if rv.Kind() != reflect.Ptr || rv.IsNil() {
|
||||
return awserr.New("SerializationError",
|
||||
fmt.Sprintf("v must be a non-nil pointer to a map[string]interface{} or struct, got %s",
|
||||
rv.Type()),
|
||||
nil)
|
||||
}
|
||||
if rv.Elem().Kind() != reflect.Struct && !(rv.Elem().Kind() == reflect.Map && rv.Elem().Type().Key().Kind() == reflect.String) {
|
||||
return awserr.New("SerializationError",
|
||||
fmt.Sprintf("v must be a non-nil pointer to a map[string]interface{} or struct, got %s",
|
||||
rv.Type()),
|
||||
nil)
|
||||
}
|
||||
|
||||
m := make(map[string]interface{})
|
||||
for k, v := range item {
|
||||
m[k] = convertFrom(v)
|
||||
}
|
||||
|
||||
if isTyped(reflect.TypeOf(v)) {
|
||||
err = convertToTyped(m, v)
|
||||
} else {
|
||||
rv.Elem().Set(reflect.ValueOf(m))
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// ConvertToList accepts an array or slice and converts it to a
|
||||
// []*dynamodb.AttributeValue.
|
||||
//
|
||||
// Converting []byte fields to dynamodb.AttributeValue are only currently supported
|
||||
// if the input is a map[string]interface{} type. []byte within typed structs are not
|
||||
// converted correctly and are converted into base64 strings. This is a known bug,
|
||||
// and will be fixed in a later release.
|
||||
//
|
||||
// If in contains any structs, it is first JSON encoded/decoded it to convert it
|
||||
// to a []interface{}, so `json` struct tags are respected.
|
||||
//
|
||||
// Deprecated: Use MarshalList instead
|
||||
func ConvertToList(in interface{}) (item []*dynamodb.AttributeValue, err error) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
if e, ok := r.(runtime.Error); ok {
|
||||
err = e
|
||||
} else if s, ok := r.(string); ok {
|
||||
err = fmt.Errorf(s)
|
||||
} else {
|
||||
err = r.(error)
|
||||
}
|
||||
item = nil
|
||||
}
|
||||
}()
|
||||
|
||||
if in == nil {
|
||||
return nil, awserr.New("SerializationError",
|
||||
"in must be an array or slice, got <nil>",
|
||||
nil)
|
||||
}
|
||||
|
||||
v := reflect.ValueOf(in)
|
||||
if v.Kind() != reflect.Array && v.Kind() != reflect.Slice {
|
||||
return nil, awserr.New("SerializationError",
|
||||
fmt.Sprintf("in must be an array or slice, got %s",
|
||||
v.Type().String()),
|
||||
nil)
|
||||
}
|
||||
|
||||
if isTyped(reflect.TypeOf(in)) {
|
||||
var out []interface{}
|
||||
in = convertToUntyped(in, out)
|
||||
}
|
||||
|
||||
item = make([]*dynamodb.AttributeValue, 0, len(in.([]interface{})))
|
||||
for _, v := range in.([]interface{}) {
|
||||
item = append(item, convertTo(v))
|
||||
}
|
||||
|
||||
return item, nil
|
||||
}
|
||||
|
||||
// ConvertFromList accepts a []*dynamodb.AttributeValue and converts it to an array or
|
||||
// slice.
|
||||
//
|
||||
// If v contains any structs, the result is first converted it to a
|
||||
// []interface{}, then JSON encoded/decoded it to convert to a typed array or
|
||||
// slice, so `json` struct tags are respected.
|
||||
//
|
||||
// Deprecated: Use UnmarshalList instead
|
||||
func ConvertFromList(item []*dynamodb.AttributeValue, v interface{}) (err error) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
if e, ok := r.(runtime.Error); ok {
|
||||
err = e
|
||||
} else if s, ok := r.(string); ok {
|
||||
err = fmt.Errorf(s)
|
||||
} else {
|
||||
err = r.(error)
|
||||
}
|
||||
item = nil
|
||||
}
|
||||
}()
|
||||
|
||||
rv := reflect.ValueOf(v)
|
||||
if rv.Kind() != reflect.Ptr || rv.IsNil() {
|
||||
return awserr.New("SerializationError",
|
||||
fmt.Sprintf("v must be a non-nil pointer to an array or slice, got %s",
|
||||
rv.Type()),
|
||||
nil)
|
||||
}
|
||||
if rv.Elem().Kind() != reflect.Array && rv.Elem().Kind() != reflect.Slice {
|
||||
return awserr.New("SerializationError",
|
||||
fmt.Sprintf("v must be a non-nil pointer to an array or slice, got %s",
|
||||
rv.Type()),
|
||||
nil)
|
||||
}
|
||||
|
||||
l := make([]interface{}, 0, len(item))
|
||||
for _, v := range item {
|
||||
l = append(l, convertFrom(v))
|
||||
}
|
||||
|
||||
if isTyped(reflect.TypeOf(v)) {
|
||||
err = convertToTyped(l, v)
|
||||
} else {
|
||||
rv.Elem().Set(reflect.ValueOf(l))
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// ConvertTo accepts any interface{} and converts it to a *dynamodb.AttributeValue.
|
||||
//
|
||||
// If in contains any structs, it is first JSON encoded/decoded it to convert it
|
||||
// to a interface{}, so `json` struct tags are respected.
|
||||
//
|
||||
// Deprecated: Use Marshal instead
|
||||
func ConvertTo(in interface{}) (item *dynamodb.AttributeValue, err error) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
if e, ok := r.(runtime.Error); ok {
|
||||
err = e
|
||||
} else if s, ok := r.(string); ok {
|
||||
err = fmt.Errorf(s)
|
||||
} else {
|
||||
err = r.(error)
|
||||
}
|
||||
item = nil
|
||||
}
|
||||
}()
|
||||
|
||||
if in != nil && isTyped(reflect.TypeOf(in)) {
|
||||
var out interface{}
|
||||
in = convertToUntyped(in, out)
|
||||
}
|
||||
|
||||
item = convertTo(in)
|
||||
return item, nil
|
||||
}
|
||||
|
||||
// ConvertFrom accepts a *dynamodb.AttributeValue and converts it to any interface{}.
|
||||
//
|
||||
// If v contains any structs, the result is first converted it to a interface{},
|
||||
// then JSON encoded/decoded it to convert to a struct, so `json` struct tags
|
||||
// are respected.
|
||||
//
|
||||
// Deprecated: Use Unmarshal instead
|
||||
func ConvertFrom(item *dynamodb.AttributeValue, v interface{}) (err error) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
if e, ok := r.(runtime.Error); ok {
|
||||
err = e
|
||||
} else if s, ok := r.(string); ok {
|
||||
err = fmt.Errorf(s)
|
||||
} else {
|
||||
err = r.(error)
|
||||
}
|
||||
item = nil
|
||||
}
|
||||
}()
|
||||
|
||||
rv := reflect.ValueOf(v)
|
||||
if rv.Kind() != reflect.Ptr || rv.IsNil() {
|
||||
return awserr.New("SerializationError",
|
||||
fmt.Sprintf("v must be a non-nil pointer to an interface{} or struct, got %s",
|
||||
rv.Type()),
|
||||
nil)
|
||||
}
|
||||
if rv.Elem().Kind() != reflect.Interface && rv.Elem().Kind() != reflect.Struct {
|
||||
return awserr.New("SerializationError",
|
||||
fmt.Sprintf("v must be a non-nil pointer to an interface{} or struct, got %s",
|
||||
rv.Type()),
|
||||
nil)
|
||||
}
|
||||
|
||||
res := convertFrom(item)
|
||||
|
||||
if isTyped(reflect.TypeOf(v)) {
|
||||
err = convertToTyped(res, v)
|
||||
} else if res != nil {
|
||||
rv.Elem().Set(reflect.ValueOf(res))
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func isTyped(v reflect.Type) bool {
|
||||
switch v.Kind() {
|
||||
case reflect.Struct:
|
||||
return true
|
||||
case reflect.Array, reflect.Slice:
|
||||
if isTyped(v.Elem()) {
|
||||
return true
|
||||
}
|
||||
case reflect.Map:
|
||||
if isTyped(v.Key()) {
|
||||
return true
|
||||
}
|
||||
if isTyped(v.Elem()) {
|
||||
return true
|
||||
}
|
||||
case reflect.Ptr:
|
||||
return isTyped(v.Elem())
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func convertToUntyped(in, out interface{}) interface{} {
|
||||
b, err := json.Marshal(in)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
decoder := json.NewDecoder(bytes.NewReader(b))
|
||||
decoder.UseNumber()
|
||||
err = decoder.Decode(&out)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
func convertToTyped(in, out interface{}) error {
|
||||
b, err := json.Marshal(in)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
decoder := json.NewDecoder(bytes.NewReader(b))
|
||||
return decoder.Decode(&out)
|
||||
}
|
||||
|
||||
func convertTo(in interface{}) *dynamodb.AttributeValue {
|
||||
a := &dynamodb.AttributeValue{}
|
||||
|
||||
if in == nil {
|
||||
a.NULL = new(bool)
|
||||
*a.NULL = true
|
||||
return a
|
||||
}
|
||||
|
||||
if m, ok := in.(map[string]interface{}); ok {
|
||||
a.M = make(map[string]*dynamodb.AttributeValue)
|
||||
for k, v := range m {
|
||||
a.M[k] = convertTo(v)
|
||||
}
|
||||
return a
|
||||
}
|
||||
|
||||
v := reflect.ValueOf(in)
|
||||
switch v.Kind() {
|
||||
case reflect.Bool:
|
||||
a.BOOL = new(bool)
|
||||
*a.BOOL = v.Bool()
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
a.N = new(string)
|
||||
*a.N = strconv.FormatInt(v.Int(), 10)
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
a.N = new(string)
|
||||
*a.N = strconv.FormatUint(v.Uint(), 10)
|
||||
case reflect.Float32, reflect.Float64:
|
||||
a.N = new(string)
|
||||
*a.N = strconv.FormatFloat(v.Float(), 'f', -1, 64)
|
||||
case reflect.String:
|
||||
if n, ok := in.(json.Number); ok {
|
||||
a.N = new(string)
|
||||
*a.N = n.String()
|
||||
} else {
|
||||
a.S = new(string)
|
||||
*a.S = v.String()
|
||||
}
|
||||
case reflect.Slice:
|
||||
switch v.Type() {
|
||||
case reflect.TypeOf(([]byte)(nil)):
|
||||
a.B = v.Bytes()
|
||||
default:
|
||||
a.L = make([]*dynamodb.AttributeValue, v.Len())
|
||||
for i := 0; i < v.Len(); i++ {
|
||||
a.L[i] = convertTo(v.Index(i).Interface())
|
||||
}
|
||||
}
|
||||
default:
|
||||
panic(fmt.Sprintf("the type %s is not supported", v.Type().String()))
|
||||
}
|
||||
|
||||
return a
|
||||
}
|
||||
|
||||
func convertFrom(a *dynamodb.AttributeValue) interface{} {
|
||||
if a.S != nil {
|
||||
return *a.S
|
||||
}
|
||||
|
||||
if a.N != nil {
|
||||
// Number is tricky b/c we don't know which numeric type to use. Here we
|
||||
// simply try the different types from most to least restrictive.
|
||||
if n, err := strconv.ParseInt(*a.N, 10, 64); err == nil {
|
||||
return int(n)
|
||||
}
|
||||
if n, err := strconv.ParseUint(*a.N, 10, 64); err == nil {
|
||||
return uint(n)
|
||||
}
|
||||
n, err := strconv.ParseFloat(*a.N, 64)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
if a.BOOL != nil {
|
||||
return *a.BOOL
|
||||
}
|
||||
|
||||
if a.NULL != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if a.M != nil {
|
||||
m := make(map[string]interface{})
|
||||
for k, v := range a.M {
|
||||
m[k] = convertFrom(v)
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
if a.L != nil {
|
||||
l := make([]interface{}, len(a.L))
|
||||
for index, v := range a.L {
|
||||
l[index] = convertFrom(v)
|
||||
}
|
||||
return l
|
||||
}
|
||||
|
||||
if a.B != nil {
|
||||
return a.B
|
||||
}
|
||||
|
||||
panic(fmt.Sprintf("%#v is not a supported dynamodb.AttributeValue", a))
|
||||
}
|
80
vendor/github.com/aws/aws-sdk-go/service/dynamodb/dynamodbattribute/converter_examples_test.go
generated
vendored
Normal file
80
vendor/github.com/aws/aws-sdk-go/service/dynamodb/dynamodbattribute/converter_examples_test.go
generated
vendored
Normal file
|
@ -0,0 +1,80 @@
|
|||
package dynamodbattribute_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"github.com/aws/aws-sdk-go/service/dynamodb/dynamodbattribute"
|
||||
)
|
||||
|
||||
func ExampleConvertTo() {
|
||||
type Record struct {
|
||||
MyField string
|
||||
Letters []string
|
||||
Numbers []int
|
||||
}
|
||||
|
||||
r := Record{
|
||||
MyField: "MyFieldValue",
|
||||
Letters: []string{"a", "b", "c", "d"},
|
||||
Numbers: []int{1, 2, 3},
|
||||
}
|
||||
av, err := dynamodbattribute.ConvertTo(r)
|
||||
fmt.Println("err", err)
|
||||
fmt.Println("MyField", av.M["MyField"])
|
||||
fmt.Println("Letters", av.M["Letters"])
|
||||
fmt.Println("Numbers", av.M["Numbers"])
|
||||
|
||||
// Output:
|
||||
// err <nil>
|
||||
// MyField {
|
||||
// S: "MyFieldValue"
|
||||
// }
|
||||
// Letters {
|
||||
// L: [
|
||||
// {
|
||||
// S: "a"
|
||||
// },
|
||||
// {
|
||||
// S: "b"
|
||||
// },
|
||||
// {
|
||||
// S: "c"
|
||||
// },
|
||||
// {
|
||||
// S: "d"
|
||||
// }
|
||||
// ]
|
||||
// }
|
||||
// Numbers {
|
||||
// L: [{
|
||||
// N: "1"
|
||||
// },{
|
||||
// N: "2"
|
||||
// },{
|
||||
// N: "3"
|
||||
// }]
|
||||
// }
|
||||
}
|
||||
|
||||
func ExampleConvertFrom() {
|
||||
type Record struct {
|
||||
MyField string
|
||||
Letters []string
|
||||
A2Num map[string]int
|
||||
}
|
||||
|
||||
r := Record{
|
||||
MyField: "MyFieldValue",
|
||||
Letters: []string{"a", "b", "c", "d"},
|
||||
A2Num: map[string]int{"a": 1, "b": 2, "c": 3},
|
||||
}
|
||||
av, err := dynamodbattribute.ConvertTo(r)
|
||||
|
||||
r2 := Record{}
|
||||
err = dynamodbattribute.ConvertFrom(av, &r2)
|
||||
fmt.Println(err, reflect.DeepEqual(r, r2))
|
||||
|
||||
// Output:
|
||||
// <nil> true
|
||||
}
|
498
vendor/github.com/aws/aws-sdk-go/service/dynamodb/dynamodbattribute/converter_test.go
generated
vendored
Normal file
498
vendor/github.com/aws/aws-sdk-go/service/dynamodb/dynamodbattribute/converter_test.go
generated
vendored
Normal file
|
@ -0,0 +1,498 @@
|
|||
package dynamodbattribute
|
||||
|
||||
import (
|
||||
"math"
|
||||
"testing"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
"github.com/aws/aws-sdk-go/service/dynamodb"
|
||||
)
|
||||
|
||||
type mySimpleStruct struct {
|
||||
String string
|
||||
Int int
|
||||
Uint uint
|
||||
Float32 float32
|
||||
Float64 float64
|
||||
Bool bool
|
||||
Null *interface{}
|
||||
}
|
||||
|
||||
type myComplexStruct struct {
|
||||
Simple []mySimpleStruct
|
||||
}
|
||||
|
||||
type converterTestInput struct {
|
||||
input interface{}
|
||||
expected interface{}
|
||||
err awserr.Error
|
||||
inputType string // "enum" of types
|
||||
}
|
||||
|
||||
var trueValue = true
|
||||
var falseValue = false
|
||||
|
||||
var converterScalarInputs = []converterTestInput{
|
||||
{
|
||||
input: nil,
|
||||
expected: &dynamodb.AttributeValue{NULL: &trueValue},
|
||||
},
|
||||
{
|
||||
input: "some string",
|
||||
expected: &dynamodb.AttributeValue{S: aws.String("some string")},
|
||||
},
|
||||
{
|
||||
input: true,
|
||||
expected: &dynamodb.AttributeValue{BOOL: &trueValue},
|
||||
},
|
||||
{
|
||||
input: false,
|
||||
expected: &dynamodb.AttributeValue{BOOL: &falseValue},
|
||||
},
|
||||
{
|
||||
input: 3.14,
|
||||
expected: &dynamodb.AttributeValue{N: aws.String("3.14")},
|
||||
},
|
||||
{
|
||||
input: math.MaxFloat32,
|
||||
expected: &dynamodb.AttributeValue{N: aws.String("340282346638528860000000000000000000000")},
|
||||
},
|
||||
{
|
||||
input: math.MaxFloat64,
|
||||
expected: &dynamodb.AttributeValue{N: aws.String("179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")},
|
||||
},
|
||||
{
|
||||
input: 12,
|
||||
expected: &dynamodb.AttributeValue{N: aws.String("12")},
|
||||
},
|
||||
{
|
||||
input: mySimpleStruct{},
|
||||
expected: &dynamodb.AttributeValue{
|
||||
M: map[string]*dynamodb.AttributeValue{
|
||||
"Bool": {BOOL: &falseValue},
|
||||
"Float32": {N: aws.String("0")},
|
||||
"Float64": {N: aws.String("0")},
|
||||
"Int": {N: aws.String("0")},
|
||||
"Null": {NULL: &trueValue},
|
||||
"String": {S: aws.String("")},
|
||||
"Uint": {N: aws.String("0")},
|
||||
},
|
||||
},
|
||||
inputType: "mySimpleStruct",
|
||||
},
|
||||
}
|
||||
|
||||
var converterMapTestInputs = []converterTestInput{
|
||||
// Scalar tests
|
||||
{
|
||||
input: nil,
|
||||
err: awserr.New("SerializationError", "in must be a map[string]interface{} or struct, got <nil>", nil),
|
||||
},
|
||||
{
|
||||
input: map[string]interface{}{"string": "some string"},
|
||||
expected: map[string]*dynamodb.AttributeValue{"string": {S: aws.String("some string")}},
|
||||
},
|
||||
{
|
||||
input: map[string]interface{}{"bool": true},
|
||||
expected: map[string]*dynamodb.AttributeValue{"bool": {BOOL: &trueValue}},
|
||||
},
|
||||
{
|
||||
input: map[string]interface{}{"bool": false},
|
||||
expected: map[string]*dynamodb.AttributeValue{"bool": {BOOL: &falseValue}},
|
||||
},
|
||||
{
|
||||
input: map[string]interface{}{"null": nil},
|
||||
expected: map[string]*dynamodb.AttributeValue{"null": {NULL: &trueValue}},
|
||||
},
|
||||
{
|
||||
input: map[string]interface{}{"float": 3.14},
|
||||
expected: map[string]*dynamodb.AttributeValue{"float": {N: aws.String("3.14")}},
|
||||
},
|
||||
{
|
||||
input: map[string]interface{}{"float": math.MaxFloat32},
|
||||
expected: map[string]*dynamodb.AttributeValue{"float": {N: aws.String("340282346638528860000000000000000000000")}},
|
||||
},
|
||||
{
|
||||
input: map[string]interface{}{"float": math.MaxFloat64},
|
||||
expected: map[string]*dynamodb.AttributeValue{"float": {N: aws.String("179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")}},
|
||||
},
|
||||
{
|
||||
input: map[string]interface{}{"int": int(12)},
|
||||
expected: map[string]*dynamodb.AttributeValue{"int": {N: aws.String("12")}},
|
||||
},
|
||||
{
|
||||
input: map[string]interface{}{"byte": []byte{48, 49}},
|
||||
expected: map[string]*dynamodb.AttributeValue{"byte": {B: []byte{48, 49}}},
|
||||
},
|
||||
// List
|
||||
{
|
||||
input: map[string]interface{}{"list": []interface{}{"a string", 12, 3.14, true, nil, false}},
|
||||
expected: map[string]*dynamodb.AttributeValue{
|
||||
"list": {
|
||||
L: []*dynamodb.AttributeValue{
|
||||
{S: aws.String("a string")},
|
||||
{N: aws.String("12")},
|
||||
{N: aws.String("3.14")},
|
||||
{BOOL: &trueValue},
|
||||
{NULL: &trueValue},
|
||||
{BOOL: &falseValue},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
// Map
|
||||
{
|
||||
input: map[string]interface{}{"map": map[string]interface{}{"nestedint": 12}},
|
||||
expected: map[string]*dynamodb.AttributeValue{
|
||||
"map": {
|
||||
M: map[string]*dynamodb.AttributeValue{
|
||||
"nestedint": {
|
||||
N: aws.String("12"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
// Structs
|
||||
{
|
||||
input: mySimpleStruct{},
|
||||
expected: map[string]*dynamodb.AttributeValue{
|
||||
"Bool": {BOOL: &falseValue},
|
||||
"Float32": {N: aws.String("0")},
|
||||
"Float64": {N: aws.String("0")},
|
||||
"Int": {N: aws.String("0")},
|
||||
"Null": {NULL: &trueValue},
|
||||
"String": {S: aws.String("")},
|
||||
"Uint": {N: aws.String("0")},
|
||||
},
|
||||
inputType: "mySimpleStruct",
|
||||
},
|
||||
{
|
||||
input: myComplexStruct{},
|
||||
expected: map[string]*dynamodb.AttributeValue{
|
||||
"Simple": {NULL: &trueValue},
|
||||
},
|
||||
inputType: "myComplexStruct",
|
||||
},
|
||||
{
|
||||
input: myComplexStruct{Simple: []mySimpleStruct{{Int: -2}, {Uint: 5}}},
|
||||
expected: map[string]*dynamodb.AttributeValue{
|
||||
"Simple": {
|
||||
L: []*dynamodb.AttributeValue{
|
||||
{
|
||||
M: map[string]*dynamodb.AttributeValue{
|
||||
"Bool": {BOOL: &falseValue},
|
||||
"Float32": {N: aws.String("0")},
|
||||
"Float64": {N: aws.String("0")},
|
||||
"Int": {N: aws.String("-2")},
|
||||
"Null": {NULL: &trueValue},
|
||||
"String": {S: aws.String("")},
|
||||
"Uint": {N: aws.String("0")},
|
||||
},
|
||||
},
|
||||
{
|
||||
M: map[string]*dynamodb.AttributeValue{
|
||||
"Bool": {BOOL: &falseValue},
|
||||
"Float32": {N: aws.String("0")},
|
||||
"Float64": {N: aws.String("0")},
|
||||
"Int": {N: aws.String("0")},
|
||||
"Null": {NULL: &trueValue},
|
||||
"String": {S: aws.String("")},
|
||||
"Uint": {N: aws.String("5")},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
inputType: "myComplexStruct",
|
||||
},
|
||||
}
|
||||
|
||||
var converterListTestInputs = []converterTestInput{
|
||||
{
|
||||
input: nil,
|
||||
err: awserr.New("SerializationError", "in must be an array or slice, got <nil>", nil),
|
||||
},
|
||||
{
|
||||
input: []interface{}{},
|
||||
expected: []*dynamodb.AttributeValue{},
|
||||
},
|
||||
{
|
||||
input: []interface{}{"a string", 12, 3.14, true, nil, false},
|
||||
expected: []*dynamodb.AttributeValue{
|
||||
{S: aws.String("a string")},
|
||||
{N: aws.String("12")},
|
||||
{N: aws.String("3.14")},
|
||||
{BOOL: &trueValue},
|
||||
{NULL: &trueValue},
|
||||
{BOOL: &falseValue},
|
||||
},
|
||||
},
|
||||
{
|
||||
input: []mySimpleStruct{{}},
|
||||
expected: []*dynamodb.AttributeValue{
|
||||
{
|
||||
M: map[string]*dynamodb.AttributeValue{
|
||||
"Bool": {BOOL: &falseValue},
|
||||
"Float32": {N: aws.String("0")},
|
||||
"Float64": {N: aws.String("0")},
|
||||
"Int": {N: aws.String("0")},
|
||||
"Null": {NULL: &trueValue},
|
||||
"String": {S: aws.String("")},
|
||||
"Uint": {N: aws.String("0")},
|
||||
},
|
||||
},
|
||||
},
|
||||
inputType: "mySimpleStruct",
|
||||
},
|
||||
}
|
||||
|
||||
func TestConvertTo(t *testing.T) {
|
||||
for _, test := range converterScalarInputs {
|
||||
testConvertTo(t, test)
|
||||
}
|
||||
}
|
||||
|
||||
func testConvertTo(t *testing.T, test converterTestInput) {
|
||||
actual, err := ConvertTo(test.input)
|
||||
if test.err != nil {
|
||||
if err == nil {
|
||||
t.Errorf("ConvertTo with input %#v retured %#v, expected error `%s`", test.input, actual, test.err)
|
||||
} else if err.Error() != test.err.Error() {
|
||||
t.Errorf("ConvertTo with input %#v retured error `%s`, expected error `%s`", test.input, err, test.err)
|
||||
}
|
||||
} else {
|
||||
if err != nil {
|
||||
t.Errorf("ConvertTo with input %#v retured error `%s`", test.input, err)
|
||||
}
|
||||
compareObjects(t, test.expected, actual)
|
||||
}
|
||||
}
|
||||
|
||||
func TestConvertFrom(t *testing.T) {
|
||||
// Using the same inputs from TestConvertTo, test the reverse mapping.
|
||||
for _, test := range converterScalarInputs {
|
||||
if test.expected != nil {
|
||||
testConvertFrom(t, test)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testConvertFrom(t *testing.T, test converterTestInput) {
|
||||
switch test.inputType {
|
||||
case "mySimpleStruct":
|
||||
var actual mySimpleStruct
|
||||
if err := ConvertFrom(test.expected.(*dynamodb.AttributeValue), &actual); err != nil {
|
||||
t.Errorf("ConvertFrom with input %#v retured error `%s`", test.expected, err)
|
||||
}
|
||||
compareObjects(t, test.input, actual)
|
||||
case "myComplexStruct":
|
||||
var actual myComplexStruct
|
||||
if err := ConvertFrom(test.expected.(*dynamodb.AttributeValue), &actual); err != nil {
|
||||
t.Errorf("ConvertFrom with input %#v retured error `%s`", test.expected, err)
|
||||
}
|
||||
compareObjects(t, test.input, actual)
|
||||
default:
|
||||
var actual interface{}
|
||||
if err := ConvertFrom(test.expected.(*dynamodb.AttributeValue), &actual); err != nil {
|
||||
t.Errorf("ConvertFrom with input %#v retured error `%s`", test.expected, err)
|
||||
}
|
||||
compareObjects(t, test.input, actual)
|
||||
}
|
||||
}
|
||||
|
||||
func TestConvertFromError(t *testing.T) {
|
||||
// Test that we get an error using ConvertFrom to convert to a map.
|
||||
var actual map[string]interface{}
|
||||
expected := awserr.New("SerializationError", `v must be a non-nil pointer to an interface{} or struct, got *map[string]interface {}`, nil).Error()
|
||||
if err := ConvertFrom(nil, &actual); err == nil {
|
||||
t.Errorf("ConvertFrom with input %#v returned no error, expected error `%s`", nil, expected)
|
||||
} else if err.Error() != expected {
|
||||
t.Errorf("ConvertFrom with input %#v returned error `%s`, expected error `%s`", nil, err, expected)
|
||||
}
|
||||
|
||||
// Test that we get an error using ConvertFrom to convert to a list.
|
||||
var actual2 []interface{}
|
||||
expected = awserr.New("SerializationError", `v must be a non-nil pointer to an interface{} or struct, got *[]interface {}`, nil).Error()
|
||||
if err := ConvertFrom(nil, &actual2); err == nil {
|
||||
t.Errorf("ConvertFrom with input %#v returned no error, expected error `%s`", nil, expected)
|
||||
} else if err.Error() != expected {
|
||||
t.Errorf("ConvertFrom with input %#v returned error `%s`, expected error `%s`", nil, err, expected)
|
||||
}
|
||||
}
|
||||
|
||||
func TestConvertToMap(t *testing.T) {
|
||||
for _, test := range converterMapTestInputs {
|
||||
testConvertToMap(t, test)
|
||||
}
|
||||
}
|
||||
|
||||
func testConvertToMap(t *testing.T, test converterTestInput) {
|
||||
actual, err := ConvertToMap(test.input)
|
||||
if test.err != nil {
|
||||
if err == nil {
|
||||
t.Errorf("ConvertToMap with input %#v retured %#v, expected error `%s`", test.input, actual, test.err)
|
||||
} else if err.Error() != test.err.Error() {
|
||||
t.Errorf("ConvertToMap with input %#v retured error `%s`, expected error `%s`", test.input, err, test.err)
|
||||
}
|
||||
} else {
|
||||
if err != nil {
|
||||
t.Errorf("ConvertToMap with input %#v retured error `%s`", test.input, err)
|
||||
}
|
||||
compareObjects(t, test.expected, actual)
|
||||
}
|
||||
}
|
||||
|
||||
func TestConvertFromMap(t *testing.T) {
|
||||
// Using the same inputs from TestConvertToMap, test the reverse mapping.
|
||||
for _, test := range converterMapTestInputs {
|
||||
if test.expected != nil {
|
||||
testConvertFromMap(t, test)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testConvertFromMap(t *testing.T, test converterTestInput) {
|
||||
switch test.inputType {
|
||||
case "mySimpleStruct":
|
||||
var actual mySimpleStruct
|
||||
if err := ConvertFromMap(test.expected.(map[string]*dynamodb.AttributeValue), &actual); err != nil {
|
||||
t.Errorf("ConvertFromMap with input %#v retured error `%s`", test.expected, err)
|
||||
}
|
||||
compareObjects(t, test.input, actual)
|
||||
case "myComplexStruct":
|
||||
var actual myComplexStruct
|
||||
if err := ConvertFromMap(test.expected.(map[string]*dynamodb.AttributeValue), &actual); err != nil {
|
||||
t.Errorf("ConvertFromMap with input %#v retured error `%s`", test.expected, err)
|
||||
}
|
||||
compareObjects(t, test.input, actual)
|
||||
default:
|
||||
var actual map[string]interface{}
|
||||
if err := ConvertFromMap(test.expected.(map[string]*dynamodb.AttributeValue), &actual); err != nil {
|
||||
t.Errorf("ConvertFromMap with input %#v retured error `%s`", test.expected, err)
|
||||
}
|
||||
compareObjects(t, test.input, actual)
|
||||
}
|
||||
}
|
||||
|
||||
func TestConvertFromMapError(t *testing.T) {
|
||||
// Test that we get an error using ConvertFromMap to convert to an interface{}.
|
||||
var actual interface{}
|
||||
expected := awserr.New("SerializationError", `v must be a non-nil pointer to a map[string]interface{} or struct, got *interface {}`, nil).Error()
|
||||
if err := ConvertFromMap(nil, &actual); err == nil {
|
||||
t.Errorf("ConvertFromMap with input %#v returned no error, expected error `%s`", nil, expected)
|
||||
} else if err.Error() != expected {
|
||||
t.Errorf("ConvertFromMap with input %#v returned error `%s`, expected error `%s`", nil, err, expected)
|
||||
}
|
||||
|
||||
// Test that we get an error using ConvertFromMap to convert to a slice.
|
||||
var actual2 []interface{}
|
||||
expected = awserr.New("SerializationError", `v must be a non-nil pointer to a map[string]interface{} or struct, got *[]interface {}`, nil).Error()
|
||||
if err := ConvertFromMap(nil, &actual2); err == nil {
|
||||
t.Errorf("ConvertFromMap with input %#v returned no error, expected error `%s`", nil, expected)
|
||||
} else if err.Error() != expected {
|
||||
t.Errorf("ConvertFromMap with input %#v returned error `%s`, expected error `%s`", nil, err, expected)
|
||||
}
|
||||
}
|
||||
|
||||
func TestConvertToList(t *testing.T) {
|
||||
for _, test := range converterListTestInputs {
|
||||
testConvertToList(t, test)
|
||||
}
|
||||
}
|
||||
|
||||
func testConvertToList(t *testing.T, test converterTestInput) {
|
||||
actual, err := ConvertToList(test.input)
|
||||
if test.err != nil {
|
||||
if err == nil {
|
||||
t.Errorf("ConvertToList with input %#v retured %#v, expected error `%s`", test.input, actual, test.err)
|
||||
} else if err.Error() != test.err.Error() {
|
||||
t.Errorf("ConvertToList with input %#v retured error `%s`, expected error `%s`", test.input, err, test.err)
|
||||
}
|
||||
} else {
|
||||
if err != nil {
|
||||
t.Errorf("ConvertToList with input %#v retured error `%s`", test.input, err)
|
||||
}
|
||||
compareObjects(t, test.expected, actual)
|
||||
}
|
||||
}
|
||||
|
||||
func TestConvertFromList(t *testing.T) {
|
||||
// Using the same inputs from TestConvertToList, test the reverse mapping.
|
||||
for _, test := range converterListTestInputs {
|
||||
if test.expected != nil {
|
||||
testConvertFromList(t, test)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testConvertFromList(t *testing.T, test converterTestInput) {
|
||||
switch test.inputType {
|
||||
case "mySimpleStruct":
|
||||
var actual []mySimpleStruct
|
||||
if err := ConvertFromList(test.expected.([]*dynamodb.AttributeValue), &actual); err != nil {
|
||||
t.Errorf("ConvertFromList with input %#v retured error `%s`", test.expected, err)
|
||||
}
|
||||
compareObjects(t, test.input, actual)
|
||||
case "myComplexStruct":
|
||||
var actual []myComplexStruct
|
||||
if err := ConvertFromList(test.expected.([]*dynamodb.AttributeValue), &actual); err != nil {
|
||||
t.Errorf("ConvertFromList with input %#v retured error `%s`", test.expected, err)
|
||||
}
|
||||
compareObjects(t, test.input, actual)
|
||||
default:
|
||||
var actual []interface{}
|
||||
if err := ConvertFromList(test.expected.([]*dynamodb.AttributeValue), &actual); err != nil {
|
||||
t.Errorf("ConvertFromList with input %#v retured error `%s`", test.expected, err)
|
||||
}
|
||||
compareObjects(t, test.input, actual)
|
||||
}
|
||||
}
|
||||
|
||||
func TestConvertFromListError(t *testing.T) {
|
||||
// Test that we get an error using ConvertFromList to convert to a map.
|
||||
var actual map[string]interface{}
|
||||
expected := awserr.New("SerializationError", `v must be a non-nil pointer to an array or slice, got *map[string]interface {}`, nil).Error()
|
||||
if err := ConvertFromList(nil, &actual); err == nil {
|
||||
t.Errorf("ConvertFromList with input %#v returned no error, expected error `%s`", nil, expected)
|
||||
} else if err.Error() != expected {
|
||||
t.Errorf("ConvertFromList with input %#v returned error `%s`, expected error `%s`", nil, err, expected)
|
||||
}
|
||||
|
||||
// Test that we get an error using ConvertFromList to convert to a struct.
|
||||
var actual2 myComplexStruct
|
||||
expected = awserr.New("SerializationError", `v must be a non-nil pointer to an array or slice, got *dynamodbattribute.myComplexStruct`, nil).Error()
|
||||
if err := ConvertFromList(nil, &actual2); err == nil {
|
||||
t.Errorf("ConvertFromList with input %#v returned no error, expected error `%s`", nil, expected)
|
||||
} else if err.Error() != expected {
|
||||
t.Errorf("ConvertFromList with input %#v returned error `%s`, expected error `%s`", nil, err, expected)
|
||||
}
|
||||
|
||||
// Test that we get an error using ConvertFromList to convert to an interface{}.
|
||||
var actual3 interface{}
|
||||
expected = awserr.New("SerializationError", `v must be a non-nil pointer to an array or slice, got *interface {}`, nil).Error()
|
||||
if err := ConvertFromList(nil, &actual3); err == nil {
|
||||
t.Errorf("ConvertFromList with input %#v returned no error, expected error `%s`", nil, expected)
|
||||
} else if err.Error() != expected {
|
||||
t.Errorf("ConvertFromList with input %#v returned error `%s`, expected error `%s`", nil, err, expected)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkConvertTo(b *testing.B) {
|
||||
d := mySimpleStruct{
|
||||
String: "abc",
|
||||
Int: 123,
|
||||
Uint: 123,
|
||||
Float32: 123.321,
|
||||
Float64: 123.321,
|
||||
Bool: true,
|
||||
Null: nil,
|
||||
}
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, err := ConvertTo(d)
|
||||
if err != nil {
|
||||
b.Fatal("unexpected error", err)
|
||||
}
|
||||
}
|
||||
}
|
732
vendor/github.com/aws/aws-sdk-go/service/dynamodb/dynamodbattribute/decode.go
generated
vendored
Normal file
732
vendor/github.com/aws/aws-sdk-go/service/dynamodb/dynamodbattribute/decode.go
generated
vendored
Normal file
|
@ -0,0 +1,732 @@
|
|||
package dynamodbattribute
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/service/dynamodb"
|
||||
)
|
||||
|
||||
// An Unmarshaler is an interface to provide custom unmarshaling of
|
||||
// AttributeValues. Use this to provide custom logic determining
|
||||
// how AttributeValues should be unmarshaled.
|
||||
// type ExampleUnmarshaler struct {
|
||||
// Value int
|
||||
// }
|
||||
//
|
||||
// type (u *exampleUnmarshaler) UnmarshalDynamoDBAttributeValue(av *dynamodb.AttributeValue) error {
|
||||
// if av.N == nil {
|
||||
// return nil
|
||||
// }
|
||||
//
|
||||
// n, err := strconv.ParseInt(*av.N, 10, 0)
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
//
|
||||
// u.Value = n
|
||||
// return nil
|
||||
// }
|
||||
type Unmarshaler interface {
|
||||
UnmarshalDynamoDBAttributeValue(*dynamodb.AttributeValue) error
|
||||
}
|
||||
|
||||
// Unmarshal will unmarshal DynamoDB AttributeValues to Go value types.
|
||||
// Both generic interface{} and concrete types are valid unmarshal
|
||||
// destination types.
|
||||
//
|
||||
// Unmarshal will allocate maps, slices, and pointers as needed to
|
||||
// unmarshal the AttributeValue into the provided type value.
|
||||
//
|
||||
// When unmarshaling AttributeValues into structs Unmarshal matches
|
||||
// the field names of the struct to the AttributeValue Map keys.
|
||||
// Initially it will look for exact field name matching, but will
|
||||
// fall back to case insensitive if not exact match is found.
|
||||
//
|
||||
// With the exception of omitempty, omitemptyelem, binaryset, numberset
|
||||
// and stringset all struct tags used by Marshal are also used by
|
||||
// Unmarshal.
|
||||
//
|
||||
// When decoding AttributeValues to interfaces Unmarshal will use the
|
||||
// following types.
|
||||
//
|
||||
// []byte, AV Binary (B)
|
||||
// [][]byte, AV Binary Set (BS)
|
||||
// bool, AV Boolean (BOOL)
|
||||
// []interface{}, AV List (L)
|
||||
// map[string]interface{}, AV Map (M)
|
||||
// float64, AV Number (N)
|
||||
// Number, AV Number (N) with UseNumber set
|
||||
// []float64, AV Number Set (NS)
|
||||
// []Number, AV Number Set (NS) with UseNumber set
|
||||
// string, AV String (S)
|
||||
// []string, AV String Set (SS)
|
||||
//
|
||||
// If the Decoder option, UseNumber is set numbers will be unmarshaled
|
||||
// as Number values instead of float64. Use this to maintain the original
|
||||
// string formating of the number as it was represented in the AttributeValue.
|
||||
// In addition provides additional opportunities to parse the number
|
||||
// string based on individual use cases.
|
||||
//
|
||||
// When unmarshaling any error that occurs will halt the unmarshal
|
||||
// and return the error.
|
||||
//
|
||||
// The output value provided must be a non-nil pointer
|
||||
func Unmarshal(av *dynamodb.AttributeValue, out interface{}) error {
|
||||
return NewDecoder().Decode(av, out)
|
||||
}
|
||||
|
||||
// UnmarshalMap is an alias for Unmarshal which unmarshals from
|
||||
// a map of AttributeValues.
|
||||
//
|
||||
// The output value provided must be a non-nil pointer
|
||||
func UnmarshalMap(m map[string]*dynamodb.AttributeValue, out interface{}) error {
|
||||
return NewDecoder().Decode(&dynamodb.AttributeValue{M: m}, out)
|
||||
}
|
||||
|
||||
// UnmarshalList is an alias for Unmarshal func which unmarshals
|
||||
// a slice of AttributeValues.
|
||||
//
|
||||
// The output value provided must be a non-nil pointer
|
||||
func UnmarshalList(l []*dynamodb.AttributeValue, out interface{}) error {
|
||||
return NewDecoder().Decode(&dynamodb.AttributeValue{L: l}, out)
|
||||
}
|
||||
|
||||
// UnmarshalListOfMaps is an alias for Unmarshal func which unmarshals a
|
||||
// slice of maps of attribute values.
|
||||
//
|
||||
// This is useful for when you need to unmarshal the Items from a DynamoDB
|
||||
// Query API call.
|
||||
//
|
||||
// The output value provided must be a non-nil pointer
|
||||
func UnmarshalListOfMaps(l []map[string]*dynamodb.AttributeValue, out interface{}) error {
|
||||
items := make([]*dynamodb.AttributeValue, len(l))
|
||||
for i, m := range l {
|
||||
items[i] = &dynamodb.AttributeValue{M: m}
|
||||
}
|
||||
|
||||
return UnmarshalList(items, out)
|
||||
}
|
||||
|
||||
// A Decoder provides unmarshaling AttributeValues to Go value types.
|
||||
type Decoder struct {
|
||||
MarshalOptions
|
||||
|
||||
// Instructs the decoder to decode AttributeValue Numbers as
|
||||
// Number type instead of float64 when the destination type
|
||||
// is interface{}. Similar to encoding/json.Number
|
||||
UseNumber bool
|
||||
}
|
||||
|
||||
// NewDecoder creates a new Decoder with default configuration. Use
|
||||
// the `opts` functional options to override the default configuration.
|
||||
func NewDecoder(opts ...func(*Decoder)) *Decoder {
|
||||
d := &Decoder{
|
||||
MarshalOptions: MarshalOptions{
|
||||
SupportJSONTags: true,
|
||||
},
|
||||
}
|
||||
for _, o := range opts {
|
||||
o(d)
|
||||
}
|
||||
|
||||
return d
|
||||
}
|
||||
|
||||
// Decode will unmarshal an AttributeValue into a Go value type. An error
|
||||
// will be return if the decoder is unable to unmarshal the AttributeValue
|
||||
// to the provide Go value type.
|
||||
//
|
||||
// The output value provided must be a non-nil pointer
|
||||
func (d *Decoder) Decode(av *dynamodb.AttributeValue, out interface{}, opts ...func(*Decoder)) error {
|
||||
v := reflect.ValueOf(out)
|
||||
if v.Kind() != reflect.Ptr || v.IsNil() || !v.IsValid() {
|
||||
return &InvalidUnmarshalError{Type: reflect.TypeOf(out)}
|
||||
}
|
||||
|
||||
return d.decode(av, v, tag{})
|
||||
}
|
||||
|
||||
var stringInterfaceMapType = reflect.TypeOf(map[string]interface{}(nil))
|
||||
var byteSliceType = reflect.TypeOf([]byte(nil))
|
||||
var byteSliceSlicetype = reflect.TypeOf([][]byte(nil))
|
||||
var numberType = reflect.TypeOf(Number(""))
|
||||
|
||||
func (d *Decoder) decode(av *dynamodb.AttributeValue, v reflect.Value, fieldTag tag) error {
|
||||
var u Unmarshaler
|
||||
if av == nil || av.NULL != nil {
|
||||
u, v = indirect(v, true)
|
||||
if u != nil {
|
||||
return u.UnmarshalDynamoDBAttributeValue(av)
|
||||
}
|
||||
return d.decodeNull(v)
|
||||
}
|
||||
|
||||
u, v = indirect(v, false)
|
||||
if u != nil {
|
||||
return u.UnmarshalDynamoDBAttributeValue(av)
|
||||
}
|
||||
|
||||
switch {
|
||||
case len(av.B) != 0:
|
||||
return d.decodeBinary(av.B, v)
|
||||
case av.BOOL != nil:
|
||||
return d.decodeBool(av.BOOL, v)
|
||||
case len(av.BS) != 0:
|
||||
return d.decodeBinarySet(av.BS, v)
|
||||
case len(av.L) != 0:
|
||||
return d.decodeList(av.L, v)
|
||||
case len(av.M) != 0:
|
||||
return d.decodeMap(av.M, v)
|
||||
case av.N != nil:
|
||||
return d.decodeNumber(av.N, v, fieldTag)
|
||||
case len(av.NS) != 0:
|
||||
return d.decodeNumberSet(av.NS, v)
|
||||
case av.S != nil:
|
||||
return d.decodeString(av.S, v, fieldTag)
|
||||
case len(av.SS) != 0:
|
||||
return d.decodeStringSet(av.SS, v)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *Decoder) decodeBinary(b []byte, v reflect.Value) error {
|
||||
if v.Kind() == reflect.Interface {
|
||||
buf := make([]byte, len(b))
|
||||
copy(buf, b)
|
||||
v.Set(reflect.ValueOf(buf))
|
||||
return nil
|
||||
}
|
||||
|
||||
if v.Kind() != reflect.Slice {
|
||||
return &UnmarshalTypeError{Value: "binary", Type: v.Type()}
|
||||
}
|
||||
|
||||
if v.Type() == byteSliceType {
|
||||
// Optimization for []byte types
|
||||
if v.IsNil() || v.Cap() < len(b) {
|
||||
v.Set(reflect.MakeSlice(byteSliceType, len(b), len(b)))
|
||||
} else if v.Len() != len(b) {
|
||||
v.SetLen(len(b))
|
||||
}
|
||||
copy(v.Interface().([]byte), b)
|
||||
return nil
|
||||
}
|
||||
|
||||
switch v.Type().Elem().Kind() {
|
||||
case reflect.Uint8:
|
||||
// Fallback to reflection copy for type aliased of []byte type
|
||||
if v.IsNil() || v.Cap() < len(b) {
|
||||
v.Set(reflect.MakeSlice(v.Type(), len(b), len(b)))
|
||||
} else if v.Len() != len(b) {
|
||||
v.SetLen(len(b))
|
||||
}
|
||||
for i := 0; i < len(b); i++ {
|
||||
v.Index(i).SetUint(uint64(b[i]))
|
||||
}
|
||||
default:
|
||||
if v.Kind() == reflect.Array && v.Type().Elem().Kind() == reflect.Uint8 {
|
||||
reflect.Copy(v, reflect.ValueOf(b))
|
||||
break
|
||||
}
|
||||
return &UnmarshalTypeError{Value: "binary", Type: v.Type()}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *Decoder) decodeBool(b *bool, v reflect.Value) error {
|
||||
switch v.Kind() {
|
||||
case reflect.Bool, reflect.Interface:
|
||||
v.Set(reflect.ValueOf(*b).Convert(v.Type()))
|
||||
default:
|
||||
return &UnmarshalTypeError{Value: "bool", Type: v.Type()}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *Decoder) decodeBinarySet(bs [][]byte, v reflect.Value) error {
|
||||
switch v.Kind() {
|
||||
case reflect.Slice:
|
||||
// Make room for the slice elements if needed
|
||||
if v.IsNil() || v.Cap() < len(bs) {
|
||||
// What about if ignoring nil/empty values?
|
||||
v.Set(reflect.MakeSlice(v.Type(), 0, len(bs)))
|
||||
}
|
||||
case reflect.Array:
|
||||
// Limited to capacity of existing array.
|
||||
case reflect.Interface:
|
||||
set := make([][]byte, len(bs))
|
||||
for i, b := range bs {
|
||||
if err := d.decodeBinary(b, reflect.ValueOf(&set[i]).Elem()); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
v.Set(reflect.ValueOf(set))
|
||||
return nil
|
||||
default:
|
||||
return &UnmarshalTypeError{Value: "binary set", Type: v.Type()}
|
||||
}
|
||||
|
||||
for i := 0; i < v.Cap() && i < len(bs); i++ {
|
||||
v.SetLen(i + 1)
|
||||
u, elem := indirect(v.Index(i), false)
|
||||
if u != nil {
|
||||
return u.UnmarshalDynamoDBAttributeValue(&dynamodb.AttributeValue{BS: bs})
|
||||
}
|
||||
if err := d.decodeBinary(bs[i], elem); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *Decoder) decodeNumber(n *string, v reflect.Value, fieldTag tag) error {
|
||||
switch v.Kind() {
|
||||
case reflect.Interface:
|
||||
i, err := d.decodeNumberToInterface(n)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
v.Set(reflect.ValueOf(i))
|
||||
return nil
|
||||
case reflect.String:
|
||||
if v.Type() == numberType { // Support Number value type
|
||||
v.Set(reflect.ValueOf(Number(*n)))
|
||||
return nil
|
||||
}
|
||||
v.Set(reflect.ValueOf(*n))
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
i, err := strconv.ParseInt(*n, 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if v.OverflowInt(i) {
|
||||
return &UnmarshalTypeError{
|
||||
Value: fmt.Sprintf("number overflow, %s", *n),
|
||||
Type: v.Type(),
|
||||
}
|
||||
}
|
||||
v.SetInt(i)
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
i, err := strconv.ParseUint(*n, 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if v.OverflowUint(i) {
|
||||
return &UnmarshalTypeError{
|
||||
Value: fmt.Sprintf("number overflow, %s", *n),
|
||||
Type: v.Type(),
|
||||
}
|
||||
}
|
||||
v.SetUint(i)
|
||||
case reflect.Float32, reflect.Float64:
|
||||
i, err := strconv.ParseFloat(*n, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if v.OverflowFloat(i) {
|
||||
return &UnmarshalTypeError{
|
||||
Value: fmt.Sprintf("number overflow, %s", *n),
|
||||
Type: v.Type(),
|
||||
}
|
||||
}
|
||||
v.SetFloat(i)
|
||||
default:
|
||||
if _, ok := v.Interface().(time.Time); ok && fieldTag.AsUnixTime {
|
||||
t, err := decodeUnixTime(*n)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
v.Set(reflect.ValueOf(t))
|
||||
return nil
|
||||
}
|
||||
return &UnmarshalTypeError{Value: "number", Type: v.Type()}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *Decoder) decodeNumberToInterface(n *string) (interface{}, error) {
|
||||
if d.UseNumber {
|
||||
return Number(*n), nil
|
||||
}
|
||||
|
||||
// Default to float64 for all numbers
|
||||
return strconv.ParseFloat(*n, 64)
|
||||
}
|
||||
|
||||
func (d *Decoder) decodeNumberSet(ns []*string, v reflect.Value) error {
|
||||
switch v.Kind() {
|
||||
case reflect.Slice:
|
||||
// Make room for the slice elements if needed
|
||||
if v.IsNil() || v.Cap() < len(ns) {
|
||||
// What about if ignoring nil/empty values?
|
||||
v.Set(reflect.MakeSlice(v.Type(), 0, len(ns)))
|
||||
}
|
||||
case reflect.Array:
|
||||
// Limited to capacity of existing array.
|
||||
case reflect.Interface:
|
||||
if d.UseNumber {
|
||||
set := make([]Number, len(ns))
|
||||
for i, n := range ns {
|
||||
if err := d.decodeNumber(n, reflect.ValueOf(&set[i]).Elem(), tag{}); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
v.Set(reflect.ValueOf(set))
|
||||
} else {
|
||||
set := make([]float64, len(ns))
|
||||
for i, n := range ns {
|
||||
if err := d.decodeNumber(n, reflect.ValueOf(&set[i]).Elem(), tag{}); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
v.Set(reflect.ValueOf(set))
|
||||
}
|
||||
return nil
|
||||
default:
|
||||
return &UnmarshalTypeError{Value: "number set", Type: v.Type()}
|
||||
}
|
||||
|
||||
for i := 0; i < v.Cap() && i < len(ns); i++ {
|
||||
v.SetLen(i + 1)
|
||||
u, elem := indirect(v.Index(i), false)
|
||||
if u != nil {
|
||||
return u.UnmarshalDynamoDBAttributeValue(&dynamodb.AttributeValue{NS: ns})
|
||||
}
|
||||
if err := d.decodeNumber(ns[i], elem, tag{}); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *Decoder) decodeList(avList []*dynamodb.AttributeValue, v reflect.Value) error {
|
||||
switch v.Kind() {
|
||||
case reflect.Slice:
|
||||
// Make room for the slice elements if needed
|
||||
if v.IsNil() || v.Cap() < len(avList) {
|
||||
// What about if ignoring nil/empty values?
|
||||
v.Set(reflect.MakeSlice(v.Type(), 0, len(avList)))
|
||||
}
|
||||
case reflect.Array:
|
||||
// Limited to capacity of existing array.
|
||||
case reflect.Interface:
|
||||
s := make([]interface{}, len(avList))
|
||||
for i, av := range avList {
|
||||
if err := d.decode(av, reflect.ValueOf(&s[i]).Elem(), tag{}); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
v.Set(reflect.ValueOf(s))
|
||||
return nil
|
||||
default:
|
||||
return &UnmarshalTypeError{Value: "list", Type: v.Type()}
|
||||
}
|
||||
|
||||
// If v is not a slice, array
|
||||
for i := 0; i < v.Cap() && i < len(avList); i++ {
|
||||
v.SetLen(i + 1)
|
||||
if err := d.decode(avList[i], v.Index(i), tag{}); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *Decoder) decodeMap(avMap map[string]*dynamodb.AttributeValue, v reflect.Value) error {
|
||||
switch v.Kind() {
|
||||
case reflect.Map:
|
||||
t := v.Type()
|
||||
if t.Key().Kind() != reflect.String {
|
||||
return &UnmarshalTypeError{Value: "map string key", Type: t.Key()}
|
||||
}
|
||||
if v.IsNil() {
|
||||
v.Set(reflect.MakeMap(t))
|
||||
}
|
||||
case reflect.Struct:
|
||||
case reflect.Interface:
|
||||
v.Set(reflect.MakeMap(stringInterfaceMapType))
|
||||
v = v.Elem()
|
||||
default:
|
||||
return &UnmarshalTypeError{Value: "map", Type: v.Type()}
|
||||
}
|
||||
|
||||
if v.Kind() == reflect.Map {
|
||||
for k, av := range avMap {
|
||||
key := reflect.ValueOf(k)
|
||||
elem := reflect.New(v.Type().Elem()).Elem()
|
||||
if err := d.decode(av, elem, tag{}); err != nil {
|
||||
return err
|
||||
}
|
||||
v.SetMapIndex(key, elem)
|
||||
}
|
||||
} else if v.Kind() == reflect.Struct {
|
||||
fields := unionStructFields(v.Type(), d.MarshalOptions)
|
||||
for k, av := range avMap {
|
||||
if f, ok := fieldByName(fields, k); ok {
|
||||
fv := fieldByIndex(v, f.Index, func(v *reflect.Value) bool {
|
||||
v.Set(reflect.New(v.Type().Elem()))
|
||||
return true // to continue the loop.
|
||||
})
|
||||
if err := d.decode(av, fv, f.tag); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *Decoder) decodeNull(v reflect.Value) error {
|
||||
if v.IsValid() && v.CanSet() {
|
||||
v.Set(reflect.Zero(v.Type()))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *Decoder) decodeString(s *string, v reflect.Value, fieldTag tag) error {
|
||||
if fieldTag.AsString {
|
||||
return d.decodeNumber(s, v, fieldTag)
|
||||
}
|
||||
|
||||
// To maintain backwards compatibility with ConvertFrom family of methods which
|
||||
// converted strings to time.Time structs
|
||||
if _, ok := v.Interface().(time.Time); ok {
|
||||
t, err := time.Parse(time.RFC3339, *s)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
v.Set(reflect.ValueOf(t))
|
||||
return nil
|
||||
}
|
||||
|
||||
switch v.Kind() {
|
||||
case reflect.String:
|
||||
v.SetString(*s)
|
||||
case reflect.Interface:
|
||||
// Ensure type aliasing is handled properly
|
||||
v.Set(reflect.ValueOf(*s).Convert(v.Type()))
|
||||
default:
|
||||
return &UnmarshalTypeError{Value: "string", Type: v.Type()}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *Decoder) decodeStringSet(ss []*string, v reflect.Value) error {
|
||||
switch v.Kind() {
|
||||
case reflect.Slice:
|
||||
// Make room for the slice elements if needed
|
||||
if v.IsNil() || v.Cap() < len(ss) {
|
||||
v.Set(reflect.MakeSlice(v.Type(), 0, len(ss)))
|
||||
}
|
||||
case reflect.Array:
|
||||
// Limited to capacity of existing array.
|
||||
case reflect.Interface:
|
||||
set := make([]string, len(ss))
|
||||
for i, s := range ss {
|
||||
if err := d.decodeString(s, reflect.ValueOf(&set[i]).Elem(), tag{}); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
v.Set(reflect.ValueOf(set))
|
||||
return nil
|
||||
default:
|
||||
return &UnmarshalTypeError{Value: "string set", Type: v.Type()}
|
||||
}
|
||||
|
||||
for i := 0; i < v.Cap() && i < len(ss); i++ {
|
||||
v.SetLen(i + 1)
|
||||
u, elem := indirect(v.Index(i), false)
|
||||
if u != nil {
|
||||
return u.UnmarshalDynamoDBAttributeValue(&dynamodb.AttributeValue{SS: ss})
|
||||
}
|
||||
if err := d.decodeString(ss[i], elem, tag{}); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func decodeUnixTime(n string) (time.Time, error) {
|
||||
v, err := strconv.ParseInt(n, 10, 64)
|
||||
if err != nil {
|
||||
return time.Time{}, &UnmarshalError{
|
||||
Err: err, Value: n, Type: reflect.TypeOf(time.Time{}),
|
||||
}
|
||||
}
|
||||
|
||||
return time.Unix(v, 0), nil
|
||||
}
|
||||
|
||||
// indirect will walk a value's interface or pointer value types. Returning
|
||||
// the final value or the value a unmarshaler is defined on.
|
||||
//
|
||||
// Based on the enoding/json type reflect value type indirection in Go Stdlib
|
||||
// https://golang.org/src/encoding/json/decode.go indirect func.
|
||||
func indirect(v reflect.Value, decodingNull bool) (Unmarshaler, reflect.Value) {
|
||||
if v.Kind() != reflect.Ptr && v.Type().Name() != "" && v.CanAddr() {
|
||||
v = v.Addr()
|
||||
}
|
||||
for {
|
||||
if v.Kind() == reflect.Interface && !v.IsNil() {
|
||||
e := v.Elem()
|
||||
if e.Kind() == reflect.Ptr && !e.IsNil() && (!decodingNull || e.Elem().Kind() == reflect.Ptr) {
|
||||
v = e
|
||||
continue
|
||||
}
|
||||
}
|
||||
if v.Kind() != reflect.Ptr {
|
||||
break
|
||||
}
|
||||
if v.Elem().Kind() != reflect.Ptr && decodingNull && v.CanSet() {
|
||||
break
|
||||
}
|
||||
if v.IsNil() {
|
||||
v.Set(reflect.New(v.Type().Elem()))
|
||||
}
|
||||
if v.Type().NumMethod() > 0 {
|
||||
if u, ok := v.Interface().(Unmarshaler); ok {
|
||||
return u, reflect.Value{}
|
||||
}
|
||||
}
|
||||
v = v.Elem()
|
||||
}
|
||||
|
||||
return nil, v
|
||||
}
|
||||
|
||||
// A Number represents a Attributevalue number literal.
|
||||
type Number string
|
||||
|
||||
// Float64 attempts to cast the number ot a float64, returning
|
||||
// the result of the case or error if the case failed.
|
||||
func (n Number) Float64() (float64, error) {
|
||||
return strconv.ParseFloat(string(n), 64)
|
||||
}
|
||||
|
||||
// Int64 attempts to cast the number ot a int64, returning
|
||||
// the result of the case or error if the case failed.
|
||||
func (n Number) Int64() (int64, error) {
|
||||
return strconv.ParseInt(string(n), 10, 64)
|
||||
}
|
||||
|
||||
// Uint64 attempts to cast the number ot a uint64, returning
|
||||
// the result of the case or error if the case failed.
|
||||
func (n Number) Uint64() (uint64, error) {
|
||||
return strconv.ParseUint(string(n), 10, 64)
|
||||
}
|
||||
|
||||
// String returns the raw number represented as a string
|
||||
func (n Number) String() string {
|
||||
return string(n)
|
||||
}
|
||||
|
||||
type emptyOrigError struct{}
|
||||
|
||||
func (e emptyOrigError) OrigErr() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// An UnmarshalTypeError is an error type representing a error
|
||||
// unmarshaling the AttributeValue's element to a Go value type.
|
||||
// Includes details about the AttributeValue type and Go value type.
|
||||
type UnmarshalTypeError struct {
|
||||
emptyOrigError
|
||||
Value string
|
||||
Type reflect.Type
|
||||
}
|
||||
|
||||
// Error returns the string representation of the error.
|
||||
// satisfying the error interface
|
||||
func (e *UnmarshalTypeError) Error() string {
|
||||
return fmt.Sprintf("%s: %s", e.Code(), e.Message())
|
||||
}
|
||||
|
||||
// Code returns the code of the error, satisfying the awserr.Error
|
||||
// interface.
|
||||
func (e *UnmarshalTypeError) Code() string {
|
||||
return "UnmarshalTypeError"
|
||||
}
|
||||
|
||||
// Message returns the detailed message of the error, satisfying
|
||||
// the awserr.Error interface.
|
||||
func (e *UnmarshalTypeError) Message() string {
|
||||
return "cannot unmarshal " + e.Value + " into Go value of type " + e.Type.String()
|
||||
}
|
||||
|
||||
// An InvalidUnmarshalError is an error type representing an invalid type
|
||||
// encountered while unmarshaling a AttributeValue to a Go value type.
|
||||
type InvalidUnmarshalError struct {
|
||||
emptyOrigError
|
||||
Type reflect.Type
|
||||
}
|
||||
|
||||
// Error returns the string representation of the error.
|
||||
// satisfying the error interface
|
||||
func (e *InvalidUnmarshalError) Error() string {
|
||||
return fmt.Sprintf("%s: %s", e.Code(), e.Message())
|
||||
}
|
||||
|
||||
// Code returns the code of the error, satisfying the awserr.Error
|
||||
// interface.
|
||||
func (e *InvalidUnmarshalError) Code() string {
|
||||
return "InvalidUnmarshalError"
|
||||
}
|
||||
|
||||
// Message returns the detailed message of the error, satisfying
|
||||
// the awserr.Error interface.
|
||||
func (e *InvalidUnmarshalError) Message() string {
|
||||
if e.Type == nil {
|
||||
return "cannot unmarshal to nil value"
|
||||
}
|
||||
if e.Type.Kind() != reflect.Ptr {
|
||||
return "cannot unmarshal to non-pointer value, got " + e.Type.String()
|
||||
}
|
||||
return "cannot unmarshal to nil value, " + e.Type.String()
|
||||
}
|
||||
|
||||
// An UnmarshalError wraps an error that occured while unmarshaling a DynamoDB
|
||||
// AttributeValue element into a Go type. This is different from UnmarshalTypeError
|
||||
// in that it wraps the underlying error that occured.
|
||||
type UnmarshalError struct {
|
||||
Err error
|
||||
Value string
|
||||
Type reflect.Type
|
||||
}
|
||||
|
||||
// Error returns the string representation of the error.
|
||||
// satisfying the error interface.
|
||||
func (e *UnmarshalError) Error() string {
|
||||
return fmt.Sprintf("%s: %s\ncaused by: %v", e.Code(), e.Message(), e.Err)
|
||||
}
|
||||
|
||||
// OrigErr returns the original error that caused this issue.
|
||||
func (e UnmarshalError) OrigErr() error {
|
||||
return e.Err
|
||||
}
|
||||
|
||||
// Code returns the code of the error, satisfying the awserr.Error
|
||||
// interface.
|
||||
func (e *UnmarshalError) Code() string {
|
||||
return "UnmarshalError"
|
||||
}
|
||||
|
||||
// Message returns the detailed message of the error, satisfying
|
||||
// the awserr.Error interface.
|
||||
func (e *UnmarshalError) Message() string {
|
||||
return fmt.Sprintf("cannot unmarshal %q into %s.",
|
||||
e.Value, e.Type.String())
|
||||
}
|
529
vendor/github.com/aws/aws-sdk-go/service/dynamodb/dynamodbattribute/decode_test.go
generated
vendored
Normal file
529
vendor/github.com/aws/aws-sdk-go/service/dynamodb/dynamodbattribute/decode_test.go
generated
vendored
Normal file
|
@ -0,0 +1,529 @@
|
|||
package dynamodbattribute
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
"github.com/aws/aws-sdk-go/service/dynamodb"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestUnmarshalErrorTypes(t *testing.T) {
|
||||
var _ awserr.Error = (*UnmarshalTypeError)(nil)
|
||||
var _ awserr.Error = (*InvalidUnmarshalError)(nil)
|
||||
}
|
||||
|
||||
func TestUnmarshalShared(t *testing.T) {
|
||||
for i, c := range sharedTestCases {
|
||||
err := Unmarshal(c.in, c.actual)
|
||||
assertConvertTest(t, i, c.actual, c.expected, err, c.err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnmarshal(t *testing.T) {
|
||||
cases := []struct {
|
||||
in *dynamodb.AttributeValue
|
||||
actual, expected interface{}
|
||||
err error
|
||||
}{
|
||||
//------------
|
||||
// Sets
|
||||
//------------
|
||||
{
|
||||
in: &dynamodb.AttributeValue{BS: [][]byte{
|
||||
{48, 49}, {50, 51},
|
||||
}},
|
||||
actual: &[][]byte{},
|
||||
expected: [][]byte{{48, 49}, {50, 51}},
|
||||
},
|
||||
{
|
||||
in: &dynamodb.AttributeValue{NS: []*string{
|
||||
aws.String("123"), aws.String("321"),
|
||||
}},
|
||||
actual: &[]int{},
|
||||
expected: []int{123, 321},
|
||||
},
|
||||
{
|
||||
in: &dynamodb.AttributeValue{NS: []*string{
|
||||
aws.String("123"), aws.String("321"),
|
||||
}},
|
||||
actual: &[]interface{}{},
|
||||
expected: []interface{}{123., 321.},
|
||||
},
|
||||
{
|
||||
in: &dynamodb.AttributeValue{SS: []*string{
|
||||
aws.String("abc"), aws.String("123"),
|
||||
}},
|
||||
actual: &[]string{},
|
||||
expected: &[]string{"abc", "123"},
|
||||
},
|
||||
{
|
||||
in: &dynamodb.AttributeValue{SS: []*string{
|
||||
aws.String("abc"), aws.String("123"),
|
||||
}},
|
||||
actual: &[]*string{},
|
||||
expected: &[]*string{aws.String("abc"), aws.String("123")},
|
||||
},
|
||||
//------------
|
||||
// Interfaces
|
||||
//------------
|
||||
{
|
||||
in: &dynamodb.AttributeValue{B: []byte{48, 49}},
|
||||
actual: func() interface{} {
|
||||
var v interface{}
|
||||
return &v
|
||||
}(),
|
||||
expected: []byte{48, 49},
|
||||
},
|
||||
{
|
||||
in: &dynamodb.AttributeValue{BS: [][]byte{
|
||||
{48, 49}, {50, 51},
|
||||
}},
|
||||
actual: func() interface{} {
|
||||
var v interface{}
|
||||
return &v
|
||||
}(),
|
||||
expected: [][]byte{{48, 49}, {50, 51}},
|
||||
},
|
||||
{
|
||||
in: &dynamodb.AttributeValue{BOOL: aws.Bool(true)},
|
||||
actual: func() interface{} {
|
||||
var v interface{}
|
||||
return &v
|
||||
}(),
|
||||
expected: bool(true),
|
||||
},
|
||||
{
|
||||
in: &dynamodb.AttributeValue{L: []*dynamodb.AttributeValue{
|
||||
{S: aws.String("abc")}, {S: aws.String("123")},
|
||||
}},
|
||||
actual: func() interface{} {
|
||||
var v interface{}
|
||||
return &v
|
||||
}(),
|
||||
expected: []interface{}{"abc", "123"},
|
||||
},
|
||||
{
|
||||
in: &dynamodb.AttributeValue{M: map[string]*dynamodb.AttributeValue{
|
||||
"123": {S: aws.String("abc")},
|
||||
"abc": {S: aws.String("123")},
|
||||
}},
|
||||
actual: func() interface{} {
|
||||
var v interface{}
|
||||
return &v
|
||||
}(),
|
||||
expected: map[string]interface{}{"123": "abc", "abc": "123"},
|
||||
},
|
||||
{
|
||||
in: &dynamodb.AttributeValue{N: aws.String("123")},
|
||||
actual: func() interface{} {
|
||||
var v interface{}
|
||||
return &v
|
||||
}(),
|
||||
expected: float64(123),
|
||||
},
|
||||
{
|
||||
in: &dynamodb.AttributeValue{NS: []*string{
|
||||
aws.String("123"), aws.String("321"),
|
||||
}},
|
||||
actual: func() interface{} {
|
||||
var v interface{}
|
||||
return &v
|
||||
}(),
|
||||
expected: []float64{123., 321.},
|
||||
},
|
||||
{
|
||||
in: &dynamodb.AttributeValue{S: aws.String("123")},
|
||||
actual: func() interface{} {
|
||||
var v interface{}
|
||||
return &v
|
||||
}(),
|
||||
expected: "123",
|
||||
},
|
||||
{
|
||||
in: &dynamodb.AttributeValue{SS: []*string{
|
||||
aws.String("123"), aws.String("321"),
|
||||
}},
|
||||
actual: func() interface{} {
|
||||
var v interface{}
|
||||
return &v
|
||||
}(),
|
||||
expected: []string{"123", "321"},
|
||||
},
|
||||
{
|
||||
in: &dynamodb.AttributeValue{M: map[string]*dynamodb.AttributeValue{
|
||||
"abc": {S: aws.String("123")},
|
||||
"Cba": {S: aws.String("321")},
|
||||
}},
|
||||
actual: &struct{ Abc, Cba string }{},
|
||||
expected: struct{ Abc, Cba string }{Abc: "123", Cba: "321"},
|
||||
},
|
||||
{
|
||||
in: &dynamodb.AttributeValue{N: aws.String("512")},
|
||||
actual: new(uint8),
|
||||
err: &UnmarshalTypeError{
|
||||
Value: fmt.Sprintf("number overflow, 512"),
|
||||
Type: reflect.TypeOf(uint8(0)),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for i, c := range cases {
|
||||
err := Unmarshal(c.in, c.actual)
|
||||
assertConvertTest(t, i, c.actual, c.expected, err, c.err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestInterfaceInput(t *testing.T) {
|
||||
var v interface{}
|
||||
expected := []interface{}{"abc", "123"}
|
||||
err := Unmarshal(&dynamodb.AttributeValue{L: []*dynamodb.AttributeValue{
|
||||
{S: aws.String("abc")}, {S: aws.String("123")},
|
||||
}}, &v)
|
||||
assertConvertTest(t, 0, v, expected, err, nil)
|
||||
}
|
||||
|
||||
func TestUnmarshalError(t *testing.T) {
|
||||
cases := []struct {
|
||||
in *dynamodb.AttributeValue
|
||||
actual, expected interface{}
|
||||
err error
|
||||
}{
|
||||
{
|
||||
in: &dynamodb.AttributeValue{},
|
||||
actual: int(0),
|
||||
expected: nil,
|
||||
err: &InvalidUnmarshalError{Type: reflect.TypeOf(int(0))},
|
||||
},
|
||||
}
|
||||
|
||||
for i, c := range cases {
|
||||
err := Unmarshal(c.in, c.actual)
|
||||
assertConvertTest(t, i, c.actual, c.expected, err, c.err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnmarshalListShared(t *testing.T) {
|
||||
for i, c := range sharedListTestCases {
|
||||
err := UnmarshalList(c.in, c.actual)
|
||||
assertConvertTest(t, i, c.actual, c.expected, err, c.err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnmarshalListError(t *testing.T) {
|
||||
cases := []struct {
|
||||
in []*dynamodb.AttributeValue
|
||||
actual, expected interface{}
|
||||
err error
|
||||
}{
|
||||
{
|
||||
in: []*dynamodb.AttributeValue{},
|
||||
actual: []interface{}{},
|
||||
expected: nil,
|
||||
err: &InvalidUnmarshalError{Type: reflect.TypeOf([]interface{}{})},
|
||||
},
|
||||
}
|
||||
|
||||
for i, c := range cases {
|
||||
err := UnmarshalList(c.in, c.actual)
|
||||
assertConvertTest(t, i, c.actual, c.expected, err, c.err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnmarshalMapShared(t *testing.T) {
|
||||
for i, c := range sharedMapTestCases {
|
||||
err := UnmarshalMap(c.in, c.actual)
|
||||
assertConvertTest(t, i, c.actual, c.expected, err, c.err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnmarshalMapError(t *testing.T) {
|
||||
cases := []struct {
|
||||
in map[string]*dynamodb.AttributeValue
|
||||
actual, expected interface{}
|
||||
err error
|
||||
}{
|
||||
{
|
||||
in: map[string]*dynamodb.AttributeValue{},
|
||||
actual: map[string]interface{}{},
|
||||
expected: nil,
|
||||
err: &InvalidUnmarshalError{Type: reflect.TypeOf(map[string]interface{}{})},
|
||||
},
|
||||
{
|
||||
in: map[string]*dynamodb.AttributeValue{
|
||||
"BOOL": {BOOL: aws.Bool(true)},
|
||||
},
|
||||
actual: &map[int]interface{}{},
|
||||
expected: nil,
|
||||
err: &UnmarshalTypeError{Value: "map string key", Type: reflect.TypeOf(int(0))},
|
||||
},
|
||||
}
|
||||
|
||||
for i, c := range cases {
|
||||
err := UnmarshalMap(c.in, c.actual)
|
||||
assertConvertTest(t, i, c.actual, c.expected, err, c.err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnmarshalListOfMaps(t *testing.T) {
|
||||
type testItem struct {
|
||||
Value string
|
||||
Value2 int
|
||||
}
|
||||
|
||||
cases := []struct {
|
||||
in []map[string]*dynamodb.AttributeValue
|
||||
actual, expected interface{}
|
||||
err error
|
||||
}{
|
||||
{ // Simple map conversion.
|
||||
in: []map[string]*dynamodb.AttributeValue{
|
||||
{
|
||||
"Value": &dynamodb.AttributeValue{
|
||||
BOOL: aws.Bool(true),
|
||||
},
|
||||
},
|
||||
},
|
||||
actual: &[]map[string]interface{}{},
|
||||
expected: []map[string]interface{}{
|
||||
{
|
||||
"Value": true,
|
||||
},
|
||||
},
|
||||
},
|
||||
{ // attribute to struct.
|
||||
in: []map[string]*dynamodb.AttributeValue{
|
||||
{
|
||||
"Value": &dynamodb.AttributeValue{
|
||||
S: aws.String("abc"),
|
||||
},
|
||||
"Value2": &dynamodb.AttributeValue{
|
||||
N: aws.String("123"),
|
||||
},
|
||||
},
|
||||
},
|
||||
actual: &[]testItem{},
|
||||
expected: []testItem{
|
||||
{
|
||||
Value: "abc",
|
||||
Value2: 123,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for i, c := range cases {
|
||||
err := UnmarshalListOfMaps(c.in, c.actual)
|
||||
assertConvertTest(t, i, c.actual, c.expected, err, c.err)
|
||||
}
|
||||
}
|
||||
|
||||
type unmarshalUnmarshaler struct {
|
||||
Value string
|
||||
Value2 int
|
||||
Value3 bool
|
||||
Value4 time.Time
|
||||
}
|
||||
|
||||
func (u *unmarshalUnmarshaler) UnmarshalDynamoDBAttributeValue(av *dynamodb.AttributeValue) error {
|
||||
if av.M == nil {
|
||||
return fmt.Errorf("expected AttributeValue to be map")
|
||||
}
|
||||
|
||||
if v, ok := av.M["abc"]; !ok {
|
||||
return fmt.Errorf("expected `abc` map key")
|
||||
} else if v.S == nil {
|
||||
return fmt.Errorf("expected `abc` map value string")
|
||||
} else {
|
||||
u.Value = *v.S
|
||||
}
|
||||
|
||||
if v, ok := av.M["def"]; !ok {
|
||||
return fmt.Errorf("expected `def` map key")
|
||||
} else if v.N == nil {
|
||||
return fmt.Errorf("expected `def` map value number")
|
||||
} else {
|
||||
n, err := strconv.ParseInt(*v.N, 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
u.Value2 = int(n)
|
||||
}
|
||||
|
||||
if v, ok := av.M["ghi"]; !ok {
|
||||
return fmt.Errorf("expected `ghi` map key")
|
||||
} else if v.BOOL == nil {
|
||||
return fmt.Errorf("expected `ghi` map value number")
|
||||
} else {
|
||||
u.Value3 = *v.BOOL
|
||||
}
|
||||
|
||||
if v, ok := av.M["jkl"]; !ok {
|
||||
return fmt.Errorf("expected `jkl` map key")
|
||||
} else if v.S == nil {
|
||||
return fmt.Errorf("expected `jkl` map value string")
|
||||
} else {
|
||||
t, err := time.Parse(time.RFC3339, *v.S)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
u.Value4 = t
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestUnmarshalUnmashaler(t *testing.T) {
|
||||
u := &unmarshalUnmarshaler{}
|
||||
av := &dynamodb.AttributeValue{
|
||||
M: map[string]*dynamodb.AttributeValue{
|
||||
"abc": {S: aws.String("value")},
|
||||
"def": {N: aws.String("123")},
|
||||
"ghi": {BOOL: aws.Bool(true)},
|
||||
"jkl": {S: aws.String("2016-05-03T17:06:26.209072Z")},
|
||||
},
|
||||
}
|
||||
|
||||
err := Unmarshal(av, u)
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.Equal(t, "value", u.Value)
|
||||
assert.Equal(t, 123, u.Value2)
|
||||
assert.Equal(t, true, u.Value3)
|
||||
assert.Equal(t, testDate, u.Value4)
|
||||
}
|
||||
|
||||
func TestDecodeUseNumber(t *testing.T) {
|
||||
u := map[string]interface{}{}
|
||||
av := &dynamodb.AttributeValue{
|
||||
M: map[string]*dynamodb.AttributeValue{
|
||||
"abc": {S: aws.String("value")},
|
||||
"def": {N: aws.String("123")},
|
||||
"ghi": {BOOL: aws.Bool(true)},
|
||||
},
|
||||
}
|
||||
|
||||
decoder := NewDecoder(func(d *Decoder) {
|
||||
d.UseNumber = true
|
||||
})
|
||||
err := decoder.Decode(av, &u)
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.Equal(t, "value", u["abc"])
|
||||
n, ok := u["def"].(Number)
|
||||
assert.True(t, ok)
|
||||
assert.Equal(t, "123", n.String())
|
||||
assert.Equal(t, true, u["ghi"])
|
||||
}
|
||||
|
||||
func TestDecodeUseNumberNumberSet(t *testing.T) {
|
||||
u := map[string]interface{}{}
|
||||
av := &dynamodb.AttributeValue{
|
||||
M: map[string]*dynamodb.AttributeValue{
|
||||
"ns": {
|
||||
NS: []*string{
|
||||
aws.String("123"), aws.String("321"),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
decoder := NewDecoder(func(d *Decoder) {
|
||||
d.UseNumber = true
|
||||
})
|
||||
err := decoder.Decode(av, &u)
|
||||
assert.NoError(t, err)
|
||||
|
||||
ns, ok := u["ns"].([]Number)
|
||||
assert.True(t, ok)
|
||||
|
||||
assert.Equal(t, "123", ns[0].String())
|
||||
assert.Equal(t, "321", ns[1].String())
|
||||
}
|
||||
|
||||
func TestDecodeEmbeddedPointerStruct(t *testing.T) {
|
||||
type B struct {
|
||||
Bint int
|
||||
}
|
||||
type C struct {
|
||||
Cint int
|
||||
}
|
||||
type A struct {
|
||||
Aint int
|
||||
*B
|
||||
*C
|
||||
}
|
||||
av := &dynamodb.AttributeValue{
|
||||
M: map[string]*dynamodb.AttributeValue{
|
||||
"Aint": {
|
||||
N: aws.String("321"),
|
||||
},
|
||||
"Bint": {
|
||||
N: aws.String("123"),
|
||||
},
|
||||
},
|
||||
}
|
||||
decoder := NewDecoder()
|
||||
a := A{}
|
||||
err := decoder.Decode(av, &a)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 321, a.Aint)
|
||||
// Embedded pointer struct can be created automatically.
|
||||
assert.Equal(t, 123, a.Bint)
|
||||
// But not for absent fields.
|
||||
assert.Nil(t, a.C)
|
||||
}
|
||||
|
||||
func TestDecodeBooleanOverlay(t *testing.T) {
|
||||
type BooleanOverlay bool
|
||||
|
||||
av := &dynamodb.AttributeValue{
|
||||
BOOL: aws.Bool(true),
|
||||
}
|
||||
|
||||
decoder := NewDecoder()
|
||||
|
||||
var v BooleanOverlay
|
||||
|
||||
err := decoder.Decode(av, &v)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, BooleanOverlay(true), v)
|
||||
}
|
||||
|
||||
func TestDecodeUnixTime(t *testing.T) {
|
||||
type A struct {
|
||||
Normal time.Time
|
||||
Tagged time.Time `dynamodbav:",unixtime"`
|
||||
Typed UnixTime
|
||||
}
|
||||
|
||||
expect := A{
|
||||
Normal: time.Unix(123, 0).UTC(),
|
||||
Tagged: time.Unix(456, 0),
|
||||
Typed: UnixTime(time.Unix(789, 0)),
|
||||
}
|
||||
|
||||
input := &dynamodb.AttributeValue{
|
||||
M: map[string]*dynamodb.AttributeValue{
|
||||
"Normal": {
|
||||
S: aws.String("1970-01-01T00:02:03Z"),
|
||||
},
|
||||
"Tagged": {
|
||||
N: aws.String("456"),
|
||||
},
|
||||
"Typed": {
|
||||
N: aws.String("789"),
|
||||
},
|
||||
},
|
||||
}
|
||||
actual := A{}
|
||||
|
||||
err := Unmarshal(input, &actual)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, expect, actual)
|
||||
}
|
95
vendor/github.com/aws/aws-sdk-go/service/dynamodb/dynamodbattribute/doc.go
generated
vendored
Normal file
95
vendor/github.com/aws/aws-sdk-go/service/dynamodb/dynamodbattribute/doc.go
generated
vendored
Normal file
|
@ -0,0 +1,95 @@
|
|||
// Package dynamodbattribute provides marshaling and unmarshaling utilities to
|
||||
// convert between Go types and dynamodb.AttributeValues.
|
||||
//
|
||||
// These utilities allow you to marshal slices, maps, structs, and scalar values
|
||||
// to and from dynamodb.AttributeValue. These are useful when marshaling
|
||||
// Go value tyes to dynamodb.AttributeValue for DynamoDB requests, or
|
||||
// unmarshaling the dynamodb.AttributeValue back into a Go value type.
|
||||
//
|
||||
// AttributeValue Marshaling
|
||||
//
|
||||
// To marshal a Go type to a dynamodbAttributeValue you can use the Marshal
|
||||
// functions in the dynamodbattribute package. There are specialized versions
|
||||
// of these functions for collections of Attributevalue, such as maps and lists.
|
||||
//
|
||||
// The following example uses MarshalMap to convert the Record Go type to a
|
||||
// dynamodb.AttributeValue type and use the value to make a PutItem API request.
|
||||
//
|
||||
// type Record struct {
|
||||
// ID string
|
||||
// URLs []string
|
||||
// }
|
||||
//
|
||||
// //...
|
||||
//
|
||||
// r := Record{
|
||||
// ID: "ABC123",
|
||||
// URLs: []string{
|
||||
// "https://example.com/first/link",
|
||||
// "https://example.com/second/url",
|
||||
// },
|
||||
// }
|
||||
// av, err := dynamodbattribute.MarshalMap(r)
|
||||
// if err != nil {
|
||||
// panic(fmt.Sprintf("failed to DynamoDB marshal Record, %v", err))
|
||||
// }
|
||||
//
|
||||
// _, err := r.svc.PutItem(&dynamodb.PutItemInput{
|
||||
// TableName: aws.String(myTableName),
|
||||
// Item: av,
|
||||
// })
|
||||
// if err != nil {
|
||||
// panic(fmt.Sprintf("failed to put Record to DynamoDB, %v", err))
|
||||
// }
|
||||
//
|
||||
// AttributeValue Unmarshaling
|
||||
//
|
||||
// To unmarshal a dynamodb.AttributeValue to a Go type you can use the Unmarshal
|
||||
// functions in the dynamodbattribute package. There are specialized versions
|
||||
// of these functions for collections of Attributevalue, such as maps and lists.
|
||||
//
|
||||
// The following example will unmarshal the DynamoDB's Scan API operation. The
|
||||
// Items returned by the operation will be unmarshaled into the slice of Records
|
||||
// Go type.
|
||||
//
|
||||
// type Record struct {
|
||||
// ID string
|
||||
// URLs []string
|
||||
// }
|
||||
//
|
||||
// //...
|
||||
//
|
||||
// var records []Record
|
||||
//
|
||||
// // Use the ScanPages method to perform the scan with pagination. Use
|
||||
// // just Scan method to make the API call without pagination.
|
||||
// err := svc.ScanPages(&dynamodb.ScanInput{
|
||||
// TableName: aws.String(myTableName),
|
||||
// }, func(page *dynamodb.ScanOutput, last bool) bool {
|
||||
// recs := []Record{}
|
||||
//
|
||||
// err := dynamodbattribute.UnmarshalListOfMaps(page.Items, &recs)
|
||||
// if err != nil {
|
||||
// panic(fmt.Sprintf("failed to unmarshal Dynamodb Scan Items, %v", err))
|
||||
// }
|
||||
//
|
||||
// records = append(records, recs...)
|
||||
//
|
||||
// return true // keep paging
|
||||
// })
|
||||
//
|
||||
// The ConvertTo, ConvertToList, ConvertToMap, ConvertFrom, ConvertFromMap
|
||||
// and ConvertFromList methods have been deprecated. The Marshal and Unmarshal
|
||||
// functions should be used instead. The ConvertTo|From marshallers do not
|
||||
// support BinarySet, NumberSet, nor StringSets, and will incorrect marshal
|
||||
// binary data fields in structs as base64 strings.
|
||||
//
|
||||
// The Marshal and Unmarshal functions correct this behavior, and removes
|
||||
// the reliance on encoding.json. `json` struct tags are still supported. In
|
||||
// addition support for a new struct tag `dynamodbav` was added. Support for
|
||||
// the json.Marshaler and json.Unmarshaler interfaces have been removed and
|
||||
// replaced with have been replaced with dynamodbattribute.Marshaler and
|
||||
// dynamodbattribute.Unmarshaler interfaces.
|
||||
//
|
||||
// `time.Time` is marshaled as RFC3339 format.
|
||||
package dynamodbattribute
|
636
vendor/github.com/aws/aws-sdk-go/service/dynamodb/dynamodbattribute/encode.go
generated
vendored
Normal file
636
vendor/github.com/aws/aws-sdk-go/service/dynamodb/dynamodbattribute/encode.go
generated
vendored
Normal file
|
@ -0,0 +1,636 @@
|
|||
package dynamodbattribute
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/service/dynamodb"
|
||||
)
|
||||
|
||||
// An UnixTime provides aliasing of time.Time into a type that when marshaled
|
||||
// and unmarshaled with DynamoDB AttributeValues it will be done so as number
|
||||
// instead of string in seconds since January 1, 1970 UTC.
|
||||
//
|
||||
// This type is useful as an alterntitive to the struct tag `unixtime` when you
|
||||
// want to have your time value marshaled as Unix time in seconds intead of
|
||||
// the default time.RFC3339.
|
||||
//
|
||||
// Important to note that zero value time as unixtime is not 0 seconds
|
||||
// from January 1, 1970 UTC, but -62135596800. Which is seconds between
|
||||
// January 1, 0001 UTC, and January 1, 0001 UTC.
|
||||
type UnixTime time.Time
|
||||
|
||||
// MarshalDynamoDBAttributeValue implements the Marshaler interface so that
|
||||
// the UnixTime can be marshaled from to a DynamoDB AttributeValue number
|
||||
// value encoded in the number of seconds since January 1, 1970 UTC.
|
||||
func (e UnixTime) MarshalDynamoDBAttributeValue(av *dynamodb.AttributeValue) error {
|
||||
t := time.Time(e)
|
||||
s := strconv.FormatInt(t.Unix(), 10)
|
||||
av.N = &s
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// UnmarshalDynamoDBAttributeValue implements the Unmarshaler interface so that
|
||||
// the UnixTime can be unmarshaled from a DynamoDB AttributeValue number representing
|
||||
// the number of seconds since January 1, 1970 UTC.
|
||||
//
|
||||
// If an error parsing the AttributeValue number occurs UnmarshalError will be
|
||||
// returned.
|
||||
func (e *UnixTime) UnmarshalDynamoDBAttributeValue(av *dynamodb.AttributeValue) error {
|
||||
t, err := decodeUnixTime(aws.StringValue(av.N))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*e = UnixTime(t)
|
||||
return nil
|
||||
}
|
||||
|
||||
// A Marshaler is an interface to provide custom marshaling of Go value types
|
||||
// to AttributeValues. Use this to provide custom logic determining how a
|
||||
// Go Value type should be marshaled.
|
||||
//
|
||||
// type ExampleMarshaler struct {
|
||||
// Value int
|
||||
// }
|
||||
// func (m *ExampleMarshaler) MarshalDynamoDBAttributeValue(av *dynamodb.AttributeValue) error {
|
||||
// n := fmt.Sprintf("%v", m.Value)
|
||||
// av.N = &n
|
||||
// return nil
|
||||
// }
|
||||
//
|
||||
type Marshaler interface {
|
||||
MarshalDynamoDBAttributeValue(*dynamodb.AttributeValue) error
|
||||
}
|
||||
|
||||
// Marshal will serialize the passed in Go value type into a DynamoDB AttributeValue
|
||||
// type. This value can be used in DynamoDB API operations to simplify marshaling
|
||||
// your Go value types into AttributeValues.
|
||||
//
|
||||
// Marshal will recursively transverse the passed in value marshaling its
|
||||
// contents into a AttributeValue. Marshal supports basic scalars
|
||||
// (int,uint,float,bool,string), maps, slices, and structs. Anonymous
|
||||
// nested types are flattened based on Go anonymous type visibility.
|
||||
//
|
||||
// Marshaling slices to AttributeValue will default to a List for all
|
||||
// types except for []byte and [][]byte. []byte will be marshaled as
|
||||
// Binary data (B), and [][]byte will be marshaled as binary data set
|
||||
// (BS).
|
||||
//
|
||||
// `dynamodbav` struct tag can be used to control how the value will be
|
||||
// marshaled into a AttributeValue.
|
||||
//
|
||||
// // Field is ignored
|
||||
// Field int `dynamodbav:"-"`
|
||||
//
|
||||
// // Field AttributeValue map key "myName"
|
||||
// Field int `dynamodbav:"myName"`
|
||||
//
|
||||
// // Field AttributeValue map key "myName", and
|
||||
// // Field is omitted if it is empty
|
||||
// Field int `dynamodbav:"myName,omitempty"`
|
||||
//
|
||||
// // Field AttributeValue map key "Field", and
|
||||
// // Field is omitted if it is empty
|
||||
// Field int `dynamodbav:",omitempty"`
|
||||
//
|
||||
// // Field's elems will be omitted if empty
|
||||
// // only valid for slices, and maps.
|
||||
// Field []string `dynamodbav:",omitemptyelem"`
|
||||
//
|
||||
// // Field will be marshaled as a AttributeValue string
|
||||
// // only value for number types, (int,uint,float)
|
||||
// Field int `dynamodbav:",string"`
|
||||
//
|
||||
// // Field will be marshaled as a binary set
|
||||
// Field [][]byte `dynamodbav:",binaryset"`
|
||||
//
|
||||
// // Field will be marshaled as a number set
|
||||
// Field []int `dynamodbav:",numberset"`
|
||||
//
|
||||
// // Field will be marshaled as a string set
|
||||
// Field []string `dynamodbav:",stringset"`
|
||||
//
|
||||
// // Field will be marshaled as Unix time number in seconds.
|
||||
// // This tag is only valid with time.Time typed struct fields.
|
||||
// // Important to note that zero value time as unixtime is not 0 seconds
|
||||
// // from January 1, 1970 UTC, but -62135596800. Which is seconds between
|
||||
// // January 1, 0001 UTC, and January 1, 0001 UTC.
|
||||
// Field time.Time `dynamodbav:",unixtime"`
|
||||
//
|
||||
// The omitempty tag is only used during Marshaling and is ignored for
|
||||
// Unmarshal. Any zero value or a value when marshaled results in a
|
||||
// AttributeValue NULL will be added to AttributeValue Maps during struct
|
||||
// marshal. The omitemptyelem tag works the same as omitempty except it
|
||||
// applies to maps and slices instead of struct fields, and will not be
|
||||
// included in the marshaled AttributeValue Map, List, or Set.
|
||||
//
|
||||
// For convenience and backwards compatibility with ConvertTo functions
|
||||
// json struct tags are supported by the Marshal and Unmarshal. If
|
||||
// both json and dynamodbav struct tags are provided the json tag will
|
||||
// be ignored in favor of dynamodbav.
|
||||
//
|
||||
// All struct fields and with anonymous fields, are marshaled unless the
|
||||
// any of the following conditions are meet.
|
||||
//
|
||||
// - the field is not exported
|
||||
// - json or dynamodbav field tag is "-"
|
||||
// - json or dynamodbav field tag specifies "omitempty", and is empty.
|
||||
//
|
||||
// Pointer and interfaces values encode as the value pointed to or contained
|
||||
// in the interface. A nil value encodes as the AttributeValue NULL value.
|
||||
//
|
||||
// Channel, complex, and function values are not encoded and will be skipped
|
||||
// when walking the value to be marshaled.
|
||||
//
|
||||
// When marshaling any error that occurs will halt the marshal and return
|
||||
// the error.
|
||||
//
|
||||
// Marshal cannot represent cyclic data structures and will not handle them.
|
||||
// Passing cyclic structures to Marshal will result in an infinite recursion.
|
||||
func Marshal(in interface{}) (*dynamodb.AttributeValue, error) {
|
||||
return NewEncoder().Encode(in)
|
||||
}
|
||||
|
||||
// MarshalMap is an alias for Marshal func which marshals Go value
|
||||
// type to a map of AttributeValues.
|
||||
//
|
||||
// This is useful for DynamoDB APIs such as PutItem.
|
||||
func MarshalMap(in interface{}) (map[string]*dynamodb.AttributeValue, error) {
|
||||
av, err := NewEncoder().Encode(in)
|
||||
if err != nil || av == nil || av.M == nil {
|
||||
return map[string]*dynamodb.AttributeValue{}, err
|
||||
}
|
||||
|
||||
return av.M, nil
|
||||
}
|
||||
|
||||
// MarshalList is an alias for Marshal func which marshals Go value
|
||||
// type to a slice of AttributeValues.
|
||||
func MarshalList(in interface{}) ([]*dynamodb.AttributeValue, error) {
|
||||
av, err := NewEncoder().Encode(in)
|
||||
if err != nil || av == nil || av.L == nil {
|
||||
return []*dynamodb.AttributeValue{}, err
|
||||
}
|
||||
|
||||
return av.L, nil
|
||||
}
|
||||
|
||||
// A MarshalOptions is a collection of options shared between marshaling
|
||||
// and unmarshaling
|
||||
type MarshalOptions struct {
|
||||
// States that the encoding/json struct tags should be supported.
|
||||
// if a `dynamodbav` struct tag is also provided the encoding/json
|
||||
// tag will be ignored.
|
||||
//
|
||||
// Enabled by default.
|
||||
SupportJSONTags bool
|
||||
}
|
||||
|
||||
// An Encoder provides marshaling Go value types to AttributeValues.
|
||||
type Encoder struct {
|
||||
MarshalOptions
|
||||
|
||||
// Empty strings, "", will be marked as NULL AttributeValue types.
|
||||
// Empty strings are not valid values for DynamoDB. Will not apply
|
||||
// to lists, sets, or maps. Use the struct tag `omitemptyelem`
|
||||
// to skip empty (zero) values in lists, sets and maps.
|
||||
//
|
||||
// Enabled by default.
|
||||
NullEmptyString bool
|
||||
}
|
||||
|
||||
// NewEncoder creates a new Encoder with default configuration. Use
|
||||
// the `opts` functional options to override the default configuration.
|
||||
func NewEncoder(opts ...func(*Encoder)) *Encoder {
|
||||
e := &Encoder{
|
||||
MarshalOptions: MarshalOptions{
|
||||
SupportJSONTags: true,
|
||||
},
|
||||
NullEmptyString: true,
|
||||
}
|
||||
for _, o := range opts {
|
||||
o(e)
|
||||
}
|
||||
|
||||
return e
|
||||
}
|
||||
|
||||
// Encode will marshal a Go value type to an AttributeValue. Returning
|
||||
// the AttributeValue constructed or error.
|
||||
func (e *Encoder) Encode(in interface{}) (*dynamodb.AttributeValue, error) {
|
||||
av := &dynamodb.AttributeValue{}
|
||||
if err := e.encode(av, reflect.ValueOf(in), tag{}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return av, nil
|
||||
}
|
||||
|
||||
func fieldByIndex(v reflect.Value, index []int,
|
||||
OnEmbeddedNilStruct func(*reflect.Value) bool) reflect.Value {
|
||||
fv := v
|
||||
for i, x := range index {
|
||||
if i > 0 {
|
||||
if fv.Kind() == reflect.Ptr && fv.Type().Elem().Kind() == reflect.Struct {
|
||||
if fv.IsNil() && !OnEmbeddedNilStruct(&fv) {
|
||||
break
|
||||
}
|
||||
fv = fv.Elem()
|
||||
}
|
||||
}
|
||||
fv = fv.Field(x)
|
||||
}
|
||||
return fv
|
||||
}
|
||||
|
||||
func (e *Encoder) encode(av *dynamodb.AttributeValue, v reflect.Value, fieldTag tag) error {
|
||||
// We should check for omitted values first before dereferencing.
|
||||
if fieldTag.OmitEmpty && emptyValue(v) {
|
||||
encodeNull(av)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Handle both pointers and interface conversion into types
|
||||
v = valueElem(v)
|
||||
|
||||
if v.Kind() != reflect.Invalid {
|
||||
if used, err := tryMarshaler(av, v); used {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
switch v.Kind() {
|
||||
case reflect.Invalid:
|
||||
encodeNull(av)
|
||||
case reflect.Struct:
|
||||
return e.encodeStruct(av, v, fieldTag)
|
||||
case reflect.Map:
|
||||
return e.encodeMap(av, v, fieldTag)
|
||||
case reflect.Slice, reflect.Array:
|
||||
return e.encodeSlice(av, v, fieldTag)
|
||||
case reflect.Chan, reflect.Func, reflect.UnsafePointer:
|
||||
// do nothing for unsupported types
|
||||
default:
|
||||
return e.encodeScalar(av, v, fieldTag)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *Encoder) encodeStruct(av *dynamodb.AttributeValue, v reflect.Value, fieldTag tag) 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 {
|
||||
if fieldTag.AsUnixTime {
|
||||
return UnixTime(t).MarshalDynamoDBAttributeValue(av)
|
||||
}
|
||||
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"}
|
||||
}
|
||||
|
||||
found := true
|
||||
fv := fieldByIndex(v, f.Index, func(v *reflect.Value) bool {
|
||||
found = false
|
||||
return false // to break the loop.
|
||||
})
|
||||
if !found {
|
||||
continue
|
||||
}
|
||||
elem := &dynamodb.AttributeValue{}
|
||||
err := e.encode(elem, fv, f.tag)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
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) 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) 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) encodeList(v reflect.Value, fieldTag tag, elemFn func(dynamodb.AttributeValue) error) (int, error) {
|
||||
count := 0
|
||||
for i := 0; i < v.Len(); i++ {
|
||||
elem := dynamodb.AttributeValue{}
|
||||
err := e.encode(&elem, v.Index(i), tag{OmitEmpty: fieldTag.OmitEmptyElem})
|
||||
skip, err := keepOrOmitEmpty(fieldTag.OmitEmptyElem, &elem, err)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
} else if skip {
|
||||
continue
|
||||
}
|
||||
|
||||
if err := elemFn(elem); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
count++
|
||||
}
|
||||
|
||||
return count, nil
|
||||
}
|
||||
|
||||
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) 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) 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 encodeInt(i int64) string {
|
||||
return strconv.FormatInt(i, 10)
|
||||
}
|
||||
func encodeUint(u uint64) string {
|
||||
return strconv.FormatUint(u, 10)
|
||||
}
|
||||
func encodeFloat(f float64) string {
|
||||
return strconv.FormatFloat(f, 'f', -1, 64)
|
||||
}
|
||||
func encodeNull(av *dynamodb.AttributeValue) {
|
||||
t := true
|
||||
*av = dynamodb.AttributeValue{NULL: &t}
|
||||
}
|
||||
|
||||
func valueElem(v reflect.Value) reflect.Value {
|
||||
switch v.Kind() {
|
||||
case reflect.Interface, reflect.Ptr:
|
||||
for v.Kind() == reflect.Interface || v.Kind() == reflect.Ptr {
|
||||
v = v.Elem()
|
||||
}
|
||||
}
|
||||
|
||||
return v
|
||||
}
|
||||
|
||||
func emptyValue(v reflect.Value) bool {
|
||||
switch v.Kind() {
|
||||
case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
|
||||
return v.Len() == 0
|
||||
case reflect.Bool:
|
||||
return !v.Bool()
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
return v.Int() == 0
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
||||
return v.Uint() == 0
|
||||
case reflect.Float32, reflect.Float64:
|
||||
return v.Float() == 0
|
||||
case reflect.Interface, reflect.Ptr:
|
||||
return v.IsNil()
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func tryMarshaler(av *dynamodb.AttributeValue, v reflect.Value) (bool, error) {
|
||||
if v.Kind() != reflect.Ptr && v.Type().Name() != "" && v.CanAddr() {
|
||||
v = v.Addr()
|
||||
}
|
||||
|
||||
if v.Type().NumMethod() == 0 {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
if m, ok := v.Interface().(Marshaler); ok {
|
||||
return true, m.MarshalDynamoDBAttributeValue(av)
|
||||
}
|
||||
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func keepOrOmitEmpty(omitEmpty bool, av *dynamodb.AttributeValue, err error) (bool, error) {
|
||||
if err != nil {
|
||||
if _, ok := err.(*unsupportedMarshalTypeError); ok {
|
||||
return true, nil
|
||||
}
|
||||
return false, err
|
||||
}
|
||||
|
||||
if av.NULL != nil && omitEmpty {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// An InvalidMarshalError is an error type representing an error
|
||||
// occurring when marshaling a Go value type to an AttributeValue.
|
||||
type InvalidMarshalError struct {
|
||||
emptyOrigError
|
||||
msg string
|
||||
}
|
||||
|
||||
// Error returns the string representation of the error.
|
||||
// satisfying the error interface
|
||||
func (e *InvalidMarshalError) Error() string {
|
||||
return fmt.Sprintf("%s: %s", e.Code(), e.Message())
|
||||
}
|
||||
|
||||
// Code returns the code of the error, satisfying the awserr.Error
|
||||
// interface.
|
||||
func (e *InvalidMarshalError) Code() string {
|
||||
return "InvalidMarshalError"
|
||||
}
|
||||
|
||||
// Message returns the detailed message of the error, satisfying
|
||||
// the awserr.Error interface.
|
||||
func (e *InvalidMarshalError) Message() string {
|
||||
return e.msg
|
||||
}
|
||||
|
||||
// An unsupportedMarshalTypeError represents a Go value type
|
||||
// which cannot be marshaled into an AttributeValue and should
|
||||
// be skipped by the marshaler.
|
||||
type unsupportedMarshalTypeError struct {
|
||||
emptyOrigError
|
||||
Type reflect.Type
|
||||
}
|
||||
|
||||
// Error returns the string representation of the error.
|
||||
// satisfying the error interface
|
||||
func (e *unsupportedMarshalTypeError) Error() string {
|
||||
return fmt.Sprintf("%s: %s", e.Code(), e.Message())
|
||||
}
|
||||
|
||||
// Code returns the code of the error, satisfying the awserr.Error
|
||||
// interface.
|
||||
func (e *unsupportedMarshalTypeError) Code() string {
|
||||
return "unsupportedMarshalTypeError"
|
||||
}
|
||||
|
||||
// Message returns the detailed message of the error, satisfying
|
||||
// the awserr.Error interface.
|
||||
func (e *unsupportedMarshalTypeError) Message() string {
|
||||
return "Go value type " + e.Type.String() + " is not supported"
|
||||
}
|
209
vendor/github.com/aws/aws-sdk-go/service/dynamodb/dynamodbattribute/encode_test.go
generated
vendored
Normal file
209
vendor/github.com/aws/aws-sdk-go/service/dynamodb/dynamodbattribute/encode_test.go
generated
vendored
Normal file
|
@ -0,0 +1,209 @@
|
|||
package dynamodbattribute
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
"github.com/aws/aws-sdk-go/service/dynamodb"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestMarshalErrorTypes(t *testing.T) {
|
||||
var _ awserr.Error = (*InvalidMarshalError)(nil)
|
||||
var _ awserr.Error = (*unsupportedMarshalTypeError)(nil)
|
||||
}
|
||||
|
||||
func TestMarshalShared(t *testing.T) {
|
||||
for i, c := range sharedTestCases {
|
||||
av, err := Marshal(c.expected)
|
||||
assertConvertTest(t, i, av, c.in, err, c.err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMarshalListShared(t *testing.T) {
|
||||
for i, c := range sharedListTestCases {
|
||||
av, err := MarshalList(c.expected)
|
||||
assertConvertTest(t, i, av, c.in, err, c.err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMarshalMapShared(t *testing.T) {
|
||||
for i, c := range sharedMapTestCases {
|
||||
av, err := MarshalMap(c.expected)
|
||||
assertConvertTest(t, i, av, c.in, err, c.err)
|
||||
}
|
||||
}
|
||||
|
||||
type marshalMarshaler struct {
|
||||
Value string
|
||||
Value2 int
|
||||
Value3 bool
|
||||
Value4 time.Time
|
||||
}
|
||||
|
||||
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},
|
||||
"jkl": {S: aws.String(m.Value4.Format(time.RFC3339Nano))},
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestMarshalMashaler(t *testing.T) {
|
||||
m := &marshalMarshaler{
|
||||
Value: "value",
|
||||
Value2: 123,
|
||||
Value3: true,
|
||||
Value4: testDate,
|
||||
}
|
||||
|
||||
expect := &dynamodb.AttributeValue{
|
||||
M: map[string]*dynamodb.AttributeValue{
|
||||
"abc": {S: aws.String("value")},
|
||||
"def": {N: aws.String("123")},
|
||||
"ghi": {BOOL: aws.Bool(true)},
|
||||
"jkl": {S: aws.String("2016-05-03T17:06:26.209072Z")},
|
||||
},
|
||||
}
|
||||
|
||||
actual, err := Marshal(m)
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.Equal(t, expect, actual)
|
||||
}
|
||||
|
||||
type testOmitEmptyElemListStruct struct {
|
||||
Values []string `dynamodbav:",omitemptyelem"`
|
||||
}
|
||||
|
||||
type testOmitEmptyElemMapStruct struct {
|
||||
Values map[string]interface{} `dynamodbav:",omitemptyelem"`
|
||||
}
|
||||
|
||||
func TestMarshalListOmitEmptyElem(t *testing.T) {
|
||||
expect := &dynamodb.AttributeValue{
|
||||
M: map[string]*dynamodb.AttributeValue{
|
||||
"Values": {L: []*dynamodb.AttributeValue{
|
||||
{S: aws.String("abc")},
|
||||
{S: aws.String("123")},
|
||||
}},
|
||||
},
|
||||
}
|
||||
|
||||
m := testOmitEmptyElemListStruct{Values: []string{"abc", "", "123"}}
|
||||
|
||||
actual, err := Marshal(m)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, expect, actual)
|
||||
}
|
||||
|
||||
func TestMarshalMapOmitEmptyElem(t *testing.T) {
|
||||
expect := &dynamodb.AttributeValue{
|
||||
M: map[string]*dynamodb.AttributeValue{
|
||||
"Values": {M: map[string]*dynamodb.AttributeValue{
|
||||
"abc": {N: aws.String("123")},
|
||||
"klm": {S: aws.String("abc")},
|
||||
}},
|
||||
},
|
||||
}
|
||||
|
||||
m := testOmitEmptyElemMapStruct{Values: map[string]interface{}{
|
||||
"abc": 123.,
|
||||
"efg": nil,
|
||||
"hij": "",
|
||||
"klm": "abc",
|
||||
}}
|
||||
|
||||
actual, err := Marshal(m)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, expect, actual)
|
||||
}
|
||||
|
||||
type testOmitEmptyScalar struct {
|
||||
IntZero int `dynamodbav:",omitempty"`
|
||||
IntPtrNil *int `dynamodbav:",omitempty"`
|
||||
IntPtrSetZero *int `dynamodbav:",omitempty"`
|
||||
}
|
||||
|
||||
func TestMarshalOmitEmpty(t *testing.T) {
|
||||
expect := &dynamodb.AttributeValue{
|
||||
M: map[string]*dynamodb.AttributeValue{
|
||||
"IntPtrSetZero": {N: aws.String("0")},
|
||||
},
|
||||
}
|
||||
|
||||
m := testOmitEmptyScalar{IntPtrSetZero: aws.Int(0)}
|
||||
|
||||
actual, err := Marshal(m)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, expect, actual)
|
||||
}
|
||||
|
||||
func TestEncodeEmbeddedPointerStruct(t *testing.T) {
|
||||
type B struct {
|
||||
Bint int
|
||||
}
|
||||
type C struct {
|
||||
Cint int
|
||||
}
|
||||
type A struct {
|
||||
Aint int
|
||||
*B
|
||||
*C
|
||||
}
|
||||
a := A{Aint: 321, B: &B{123}}
|
||||
assert.Equal(t, 321, a.Aint)
|
||||
assert.Equal(t, 123, a.Bint)
|
||||
assert.Nil(t, a.C)
|
||||
|
||||
actual, err := Marshal(a)
|
||||
assert.NoError(t, err)
|
||||
expect := &dynamodb.AttributeValue{
|
||||
M: map[string]*dynamodb.AttributeValue{
|
||||
"Aint": {
|
||||
N: aws.String("321"),
|
||||
},
|
||||
"Bint": {
|
||||
N: aws.String("123"),
|
||||
},
|
||||
},
|
||||
}
|
||||
assert.Equal(t, expect, actual)
|
||||
}
|
||||
|
||||
func TestEncodeUnixTime(t *testing.T) {
|
||||
type A struct {
|
||||
Normal time.Time
|
||||
Tagged time.Time `dynamodbav:",unixtime"`
|
||||
Typed UnixTime
|
||||
}
|
||||
|
||||
a := A{
|
||||
Normal: time.Unix(123, 0).UTC(),
|
||||
Tagged: time.Unix(456, 0),
|
||||
Typed: UnixTime(time.Unix(789, 0)),
|
||||
}
|
||||
|
||||
actual, err := Marshal(a)
|
||||
assert.NoError(t, err)
|
||||
expect := &dynamodb.AttributeValue{
|
||||
M: map[string]*dynamodb.AttributeValue{
|
||||
"Normal": {
|
||||
S: aws.String("1970-01-01T00:02:03Z"),
|
||||
},
|
||||
"Tagged": {
|
||||
N: aws.String("456"),
|
||||
},
|
||||
"Typed": {
|
||||
N: aws.String("789"),
|
||||
},
|
||||
},
|
||||
}
|
||||
assert.Equal(t, expect, actual)
|
||||
}
|
269
vendor/github.com/aws/aws-sdk-go/service/dynamodb/dynamodbattribute/field.go
generated
vendored
Normal file
269
vendor/github.com/aws/aws-sdk-go/service/dynamodb/dynamodbattribute/field.go
generated
vendored
Normal file
|
@ -0,0 +1,269 @@
|
|||
package dynamodbattribute
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type field struct {
|
||||
tag
|
||||
|
||||
Name string
|
||||
NameFromTag bool
|
||||
|
||||
Index []int
|
||||
Type reflect.Type
|
||||
}
|
||||
|
||||
func fieldByName(fields []field, name string) (field, bool) {
|
||||
foldExists := false
|
||||
foldField := field{}
|
||||
|
||||
for _, f := range fields {
|
||||
if f.Name == name {
|
||||
return f, true
|
||||
}
|
||||
if !foldExists && strings.EqualFold(f.Name, name) {
|
||||
foldField = f
|
||||
foldExists = true
|
||||
}
|
||||
}
|
||||
|
||||
return foldField, foldExists
|
||||
}
|
||||
|
||||
func buildField(pIdx []int, i int, sf reflect.StructField, fieldTag tag) field {
|
||||
f := field{
|
||||
Name: sf.Name,
|
||||
Type: sf.Type,
|
||||
tag: fieldTag,
|
||||
}
|
||||
if len(fieldTag.Name) != 0 {
|
||||
f.NameFromTag = true
|
||||
f.Name = fieldTag.Name
|
||||
}
|
||||
|
||||
f.Index = make([]int, len(pIdx)+1)
|
||||
copy(f.Index, pIdx)
|
||||
f.Index[len(pIdx)] = i
|
||||
|
||||
return f
|
||||
}
|
||||
|
||||
func unionStructFields(t reflect.Type, opts MarshalOptions) []field {
|
||||
fields := enumFields(t, opts)
|
||||
|
||||
sort.Sort(fieldsByName(fields))
|
||||
|
||||
fields = visibleFields(fields)
|
||||
|
||||
return fields
|
||||
}
|
||||
|
||||
// enumFields will recursively iterate through a structure and its nested
|
||||
// anonymous fields.
|
||||
//
|
||||
// Based on the enoding/json struct field enumeration of the Go Stdlib
|
||||
// https://golang.org/src/encoding/json/encode.go typeField func.
|
||||
func enumFields(t reflect.Type, opts MarshalOptions) []field {
|
||||
// Fields to explore
|
||||
current := []field{}
|
||||
next := []field{{Type: t}}
|
||||
|
||||
// count of queued names
|
||||
count := map[reflect.Type]int{}
|
||||
nextCount := map[reflect.Type]int{}
|
||||
|
||||
visited := map[reflect.Type]struct{}{}
|
||||
fields := []field{}
|
||||
|
||||
for len(next) > 0 {
|
||||
current, next = next, current[:0]
|
||||
count, nextCount = nextCount, map[reflect.Type]int{}
|
||||
|
||||
for _, f := range current {
|
||||
if _, ok := visited[f.Type]; ok {
|
||||
continue
|
||||
}
|
||||
visited[f.Type] = struct{}{}
|
||||
|
||||
for i := 0; i < f.Type.NumField(); i++ {
|
||||
sf := f.Type.Field(i)
|
||||
if sf.PkgPath != "" && !sf.Anonymous {
|
||||
// Ignore unexported and non-anonymous fields
|
||||
// unexported but anonymous field may still be used if
|
||||
// the type has exported nested fields
|
||||
continue
|
||||
}
|
||||
|
||||
fieldTag := tag{}
|
||||
fieldTag.parseAVTag(sf.Tag)
|
||||
if opts.SupportJSONTags && fieldTag == (tag{}) {
|
||||
fieldTag.parseJSONTag(sf.Tag)
|
||||
}
|
||||
|
||||
if fieldTag.Ignore {
|
||||
continue
|
||||
}
|
||||
|
||||
ft := sf.Type
|
||||
if ft.Name() == "" && ft.Kind() == reflect.Ptr {
|
||||
ft = ft.Elem()
|
||||
}
|
||||
|
||||
structField := buildField(f.Index, i, sf, fieldTag)
|
||||
structField.Type = ft
|
||||
|
||||
if !sf.Anonymous || ft.Kind() != reflect.Struct {
|
||||
fields = append(fields, structField)
|
||||
if count[f.Type] > 1 {
|
||||
// If there were multiple instances, add a second,
|
||||
// so that the annihilation code will see a duplicate.
|
||||
// It only cares about the distinction between 1 or 2,
|
||||
// so don't bother generating any more copies.
|
||||
fields = append(fields, structField)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
// Record new anon struct to explore next round
|
||||
nextCount[ft]++
|
||||
if nextCount[ft] == 1 {
|
||||
next = append(next, structField)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return fields
|
||||
}
|
||||
|
||||
// visibleFields will return a slice of fields which are visible based on
|
||||
// Go's standard visiblity rules with the exception of ties being broken
|
||||
// by depth and struct tag naming.
|
||||
//
|
||||
// Based on the enoding/json field filtering of the Go Stdlib
|
||||
// https://golang.org/src/encoding/json/encode.go typeField func.
|
||||
func visibleFields(fields []field) []field {
|
||||
// Delete all fields that are hidden by the Go rules for embedded fields,
|
||||
// except that fields with JSON tags are promoted.
|
||||
|
||||
// The fields are sorted in primary order of name, secondary order
|
||||
// of field index length. Loop over names; for each name, delete
|
||||
// hidden fields by choosing the one dominant field that survives.
|
||||
out := fields[:0]
|
||||
for advance, i := 0, 0; i < len(fields); i += advance {
|
||||
// One iteration per name.
|
||||
// Find the sequence of fields with the name of this first field.
|
||||
fi := fields[i]
|
||||
name := fi.Name
|
||||
for advance = 1; i+advance < len(fields); advance++ {
|
||||
fj := fields[i+advance]
|
||||
if fj.Name != name {
|
||||
break
|
||||
}
|
||||
}
|
||||
if advance == 1 { // Only one field with this name
|
||||
out = append(out, fi)
|
||||
continue
|
||||
}
|
||||
dominant, ok := dominantField(fields[i : i+advance])
|
||||
if ok {
|
||||
out = append(out, dominant)
|
||||
}
|
||||
}
|
||||
|
||||
fields = out
|
||||
sort.Sort(fieldsByIndex(fields))
|
||||
|
||||
return fields
|
||||
}
|
||||
|
||||
// dominantField looks through the fields, all of which are known to
|
||||
// have the same name, to find the single field that dominates the
|
||||
// others using Go's embedding rules, modified by the presence of
|
||||
// JSON tags. If there are multiple top-level fields, the boolean
|
||||
// will be false: This condition is an error in Go and we skip all
|
||||
// the fields.
|
||||
//
|
||||
// Based on the enoding/json field filtering of the Go Stdlib
|
||||
// https://golang.org/src/encoding/json/encode.go dominantField func.
|
||||
func dominantField(fields []field) (field, bool) {
|
||||
// The fields are sorted in increasing index-length order. The winner
|
||||
// must therefore be one with the shortest index length. Drop all
|
||||
// longer entries, which is easy: just truncate the slice.
|
||||
length := len(fields[0].Index)
|
||||
tagged := -1 // Index of first tagged field.
|
||||
for i, f := range fields {
|
||||
if len(f.Index) > length {
|
||||
fields = fields[:i]
|
||||
break
|
||||
}
|
||||
if f.NameFromTag {
|
||||
if tagged >= 0 {
|
||||
// Multiple tagged fields at the same level: conflict.
|
||||
// Return no field.
|
||||
return field{}, false
|
||||
}
|
||||
tagged = i
|
||||
}
|
||||
}
|
||||
if tagged >= 0 {
|
||||
return fields[tagged], true
|
||||
}
|
||||
// All remaining fields have the same length. If there's more than one,
|
||||
// we have a conflict (two fields named "X" at the same level) and we
|
||||
// return no field.
|
||||
if len(fields) > 1 {
|
||||
return field{}, false
|
||||
}
|
||||
return fields[0], true
|
||||
}
|
||||
|
||||
// fieldsByName sorts field by name, breaking ties with depth,
|
||||
// then breaking ties with "name came from json tag", then
|
||||
// breaking ties with index sequence.
|
||||
//
|
||||
// Based on the enoding/json field filtering of the Go Stdlib
|
||||
// https://golang.org/src/encoding/json/encode.go fieldsByName type.
|
||||
type fieldsByName []field
|
||||
|
||||
func (x fieldsByName) Len() int { return len(x) }
|
||||
|
||||
func (x fieldsByName) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
|
||||
|
||||
func (x fieldsByName) Less(i, j int) bool {
|
||||
if x[i].Name != x[j].Name {
|
||||
return x[i].Name < x[j].Name
|
||||
}
|
||||
if len(x[i].Index) != len(x[j].Index) {
|
||||
return len(x[i].Index) < len(x[j].Index)
|
||||
}
|
||||
if x[i].NameFromTag != x[j].NameFromTag {
|
||||
return x[i].NameFromTag
|
||||
}
|
||||
return fieldsByIndex(x).Less(i, j)
|
||||
}
|
||||
|
||||
// fieldsByIndex sorts field by index sequence.
|
||||
//
|
||||
// Based on the enoding/json field filtering of the Go Stdlib
|
||||
// https://golang.org/src/encoding/json/encode.go fieldsByIndex type.
|
||||
type fieldsByIndex []field
|
||||
|
||||
func (x fieldsByIndex) Len() int { return len(x) }
|
||||
|
||||
func (x fieldsByIndex) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
|
||||
|
||||
func (x fieldsByIndex) Less(i, j int) bool {
|
||||
for k, xik := range x[i].Index {
|
||||
if k >= len(x[j].Index) {
|
||||
return false
|
||||
}
|
||||
if xik != x[j].Index[k] {
|
||||
return xik < x[j].Index[k]
|
||||
}
|
||||
}
|
||||
return len(x[i].Index) < len(x[j].Index)
|
||||
}
|
110
vendor/github.com/aws/aws-sdk-go/service/dynamodb/dynamodbattribute/field_test.go
generated
vendored
Normal file
110
vendor/github.com/aws/aws-sdk-go/service/dynamodb/dynamodbattribute/field_test.go
generated
vendored
Normal file
|
@ -0,0 +1,110 @@
|
|||
package dynamodbattribute
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
type testUnionValues struct {
|
||||
Name string
|
||||
Value interface{}
|
||||
}
|
||||
|
||||
type unionSimple struct {
|
||||
A int
|
||||
B string
|
||||
C []string
|
||||
}
|
||||
|
||||
type unionComplex struct {
|
||||
unionSimple
|
||||
A int
|
||||
}
|
||||
|
||||
type unionTagged struct {
|
||||
A int `json:"A"`
|
||||
}
|
||||
|
||||
type unionTaggedComplex struct {
|
||||
unionSimple
|
||||
unionTagged
|
||||
B string
|
||||
}
|
||||
|
||||
func TestUnionStructFields(t *testing.T) {
|
||||
var cases = []struct {
|
||||
in interface{}
|
||||
expect []testUnionValues
|
||||
}{
|
||||
{
|
||||
in: unionSimple{1, "2", []string{"abc"}},
|
||||
expect: []testUnionValues{
|
||||
{"A", 1},
|
||||
{"B", "2"},
|
||||
{"C", []string{"abc"}},
|
||||
},
|
||||
},
|
||||
{
|
||||
in: unionComplex{
|
||||
unionSimple: unionSimple{1, "2", []string{"abc"}},
|
||||
A: 2,
|
||||
},
|
||||
expect: []testUnionValues{
|
||||
{"B", "2"},
|
||||
{"C", []string{"abc"}},
|
||||
{"A", 2},
|
||||
},
|
||||
},
|
||||
{
|
||||
in: unionTaggedComplex{
|
||||
unionSimple: unionSimple{1, "2", []string{"abc"}},
|
||||
unionTagged: unionTagged{3},
|
||||
B: "3",
|
||||
},
|
||||
expect: []testUnionValues{
|
||||
{"C", []string{"abc"}},
|
||||
{"A", 3},
|
||||
{"B", "3"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for i, c := range cases {
|
||||
v := reflect.ValueOf(c.in)
|
||||
|
||||
fields := unionStructFields(v.Type(), MarshalOptions{SupportJSONTags: true})
|
||||
for j, f := range fields {
|
||||
expected := c.expect[j]
|
||||
assert.Equal(t, expected.Name, f.Name, "case %d, field %d", i, j)
|
||||
actual := v.FieldByIndex(f.Index).Interface()
|
||||
assert.EqualValues(t, expected.Value, actual, "case %d, field %d", i, j)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestFieldByName(t *testing.T) {
|
||||
fields := []field{
|
||||
{Name: "Abc"}, {Name: "mixCase"}, {Name: "UPPERCASE"},
|
||||
}
|
||||
|
||||
cases := []struct {
|
||||
Name, FieldName string
|
||||
Found bool
|
||||
}{
|
||||
{"abc", "Abc", true}, {"ABC", "Abc", true}, {"Abc", "Abc", true},
|
||||
{"123", "", false},
|
||||
{"ab", "", false},
|
||||
{"MixCase", "mixCase", true},
|
||||
{"uppercase", "UPPERCASE", true}, {"UPPERCASE", "UPPERCASE", true},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
f, ok := fieldByName(fields, c.Name)
|
||||
assert.Equal(t, c.Found, ok)
|
||||
if ok {
|
||||
assert.Equal(t, c.FieldName, f.Name)
|
||||
}
|
||||
}
|
||||
}
|
104
vendor/github.com/aws/aws-sdk-go/service/dynamodb/dynamodbattribute/marshaler_examples_test.go
generated
vendored
Normal file
104
vendor/github.com/aws/aws-sdk-go/service/dynamodb/dynamodbattribute/marshaler_examples_test.go
generated
vendored
Normal file
|
@ -0,0 +1,104 @@
|
|||
package dynamodbattribute_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/service/dynamodb"
|
||||
"github.com/aws/aws-sdk-go/service/dynamodb/dynamodbattribute"
|
||||
)
|
||||
|
||||
func ExampleMarshal() {
|
||||
type Record struct {
|
||||
Bytes []byte
|
||||
MyField string
|
||||
Letters []string
|
||||
Numbers []int
|
||||
}
|
||||
|
||||
r := Record{
|
||||
Bytes: []byte{48, 49},
|
||||
MyField: "MyFieldValue",
|
||||
Letters: []string{"a", "b", "c", "d"},
|
||||
Numbers: []int{1, 2, 3},
|
||||
}
|
||||
av, err := dynamodbattribute.Marshal(r)
|
||||
fmt.Println("err", err)
|
||||
fmt.Println("Bytes", av.M["Bytes"])
|
||||
fmt.Println("MyField", av.M["MyField"])
|
||||
fmt.Println("Letters", av.M["Letters"])
|
||||
fmt.Println("Numbers", av.M["Numbers"])
|
||||
|
||||
// Output:
|
||||
// err <nil>
|
||||
// Bytes {
|
||||
// B: <binary> len 2
|
||||
// }
|
||||
// MyField {
|
||||
// S: "MyFieldValue"
|
||||
// }
|
||||
// Letters {
|
||||
// L: [
|
||||
// {
|
||||
// S: "a"
|
||||
// },
|
||||
// {
|
||||
// S: "b"
|
||||
// },
|
||||
// {
|
||||
// S: "c"
|
||||
// },
|
||||
// {
|
||||
// S: "d"
|
||||
// }
|
||||
// ]
|
||||
// }
|
||||
// Numbers {
|
||||
// L: [{
|
||||
// N: "1"
|
||||
// },{
|
||||
// N: "2"
|
||||
// },{
|
||||
// N: "3"
|
||||
// }]
|
||||
// }
|
||||
}
|
||||
|
||||
func ExampleUnmarshal() {
|
||||
type Record struct {
|
||||
Bytes []byte
|
||||
MyField string
|
||||
Letters []string
|
||||
A2Num map[string]int
|
||||
}
|
||||
|
||||
expect := Record{
|
||||
Bytes: []byte{48, 49},
|
||||
MyField: "MyFieldValue",
|
||||
Letters: []string{"a", "b", "c", "d"},
|
||||
A2Num: map[string]int{"a": 1, "b": 2, "c": 3},
|
||||
}
|
||||
|
||||
av := &dynamodb.AttributeValue{
|
||||
M: map[string]*dynamodb.AttributeValue{
|
||||
"Bytes": {B: []byte{48, 49}},
|
||||
"MyField": {S: aws.String("MyFieldValue")},
|
||||
"Letters": {L: []*dynamodb.AttributeValue{
|
||||
{S: aws.String("a")}, {S: aws.String("b")}, {S: aws.String("c")}, {S: aws.String("d")},
|
||||
}},
|
||||
"A2Num": {M: map[string]*dynamodb.AttributeValue{
|
||||
"a": {N: aws.String("1")},
|
||||
"b": {N: aws.String("2")},
|
||||
"c": {N: aws.String("3")},
|
||||
}},
|
||||
},
|
||||
}
|
||||
|
||||
actual := Record{}
|
||||
err := dynamodbattribute.Unmarshal(av, &actual)
|
||||
fmt.Println(err, reflect.DeepEqual(expect, actual))
|
||||
|
||||
// Output:
|
||||
// <nil> true
|
||||
}
|
526
vendor/github.com/aws/aws-sdk-go/service/dynamodb/dynamodbattribute/marshaler_test.go
generated
vendored
Normal file
526
vendor/github.com/aws/aws-sdk-go/service/dynamodb/dynamodbattribute/marshaler_test.go
generated
vendored
Normal file
|
@ -0,0 +1,526 @@
|
|||
package dynamodbattribute
|
||||
|
||||
import (
|
||||
"math"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
"github.com/aws/aws-sdk-go/aws/awsutil"
|
||||
"github.com/aws/aws-sdk-go/service/dynamodb"
|
||||
)
|
||||
|
||||
type simpleMarshalStruct struct {
|
||||
Byte []byte
|
||||
String string
|
||||
Int int
|
||||
Uint uint
|
||||
Float32 float32
|
||||
Float64 float64
|
||||
Bool bool
|
||||
Null *interface{}
|
||||
}
|
||||
|
||||
type complexMarshalStruct struct {
|
||||
Simple []simpleMarshalStruct
|
||||
}
|
||||
|
||||
type myByteStruct struct {
|
||||
Byte []byte
|
||||
}
|
||||
|
||||
type myByteSetStruct struct {
|
||||
ByteSet [][]byte
|
||||
}
|
||||
|
||||
type marshallerTestInput struct {
|
||||
input interface{}
|
||||
expected interface{}
|
||||
err awserr.Error
|
||||
}
|
||||
|
||||
var marshalerScalarInputs = []marshallerTestInput{
|
||||
{
|
||||
input: nil,
|
||||
expected: &dynamodb.AttributeValue{NULL: &trueValue},
|
||||
},
|
||||
{
|
||||
input: "some string",
|
||||
expected: &dynamodb.AttributeValue{S: aws.String("some string")},
|
||||
},
|
||||
{
|
||||
input: true,
|
||||
expected: &dynamodb.AttributeValue{BOOL: &trueValue},
|
||||
},
|
||||
{
|
||||
input: false,
|
||||
expected: &dynamodb.AttributeValue{BOOL: &falseValue},
|
||||
},
|
||||
{
|
||||
input: 3.14,
|
||||
expected: &dynamodb.AttributeValue{N: aws.String("3.14")},
|
||||
},
|
||||
{
|
||||
input: math.MaxFloat32,
|
||||
expected: &dynamodb.AttributeValue{N: aws.String("340282346638528860000000000000000000000")},
|
||||
},
|
||||
{
|
||||
input: math.MaxFloat64,
|
||||
expected: &dynamodb.AttributeValue{N: aws.String("179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")},
|
||||
},
|
||||
{
|
||||
input: 12,
|
||||
expected: &dynamodb.AttributeValue{N: aws.String("12")},
|
||||
},
|
||||
{
|
||||
input: Number("12"),
|
||||
expected: &dynamodb.AttributeValue{N: aws.String("12")},
|
||||
},
|
||||
{
|
||||
input: simpleMarshalStruct{},
|
||||
expected: &dynamodb.AttributeValue{
|
||||
M: map[string]*dynamodb.AttributeValue{
|
||||
"Byte": {NULL: &trueValue},
|
||||
"Bool": {BOOL: &falseValue},
|
||||
"Float32": {N: aws.String("0")},
|
||||
"Float64": {N: aws.String("0")},
|
||||
"Int": {N: aws.String("0")},
|
||||
"Null": {NULL: &trueValue},
|
||||
"String": {NULL: &trueValue},
|
||||
"Uint": {N: aws.String("0")},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
var marshallerMapTestInputs = []marshallerTestInput{
|
||||
// Scalar tests
|
||||
{
|
||||
input: nil,
|
||||
expected: map[string]*dynamodb.AttributeValue{},
|
||||
},
|
||||
{
|
||||
input: map[string]interface{}{"string": "some string"},
|
||||
expected: map[string]*dynamodb.AttributeValue{"string": {S: aws.String("some string")}},
|
||||
},
|
||||
{
|
||||
input: map[string]interface{}{"bool": true},
|
||||
expected: map[string]*dynamodb.AttributeValue{"bool": {BOOL: &trueValue}},
|
||||
},
|
||||
{
|
||||
input: map[string]interface{}{"bool": false},
|
||||
expected: map[string]*dynamodb.AttributeValue{"bool": {BOOL: &falseValue}},
|
||||
},
|
||||
{
|
||||
input: map[string]interface{}{"null": nil},
|
||||
expected: map[string]*dynamodb.AttributeValue{"null": {NULL: &trueValue}},
|
||||
},
|
||||
{
|
||||
input: map[string]interface{}{"float": 3.14},
|
||||
expected: map[string]*dynamodb.AttributeValue{"float": {N: aws.String("3.14")}},
|
||||
},
|
||||
{
|
||||
input: map[string]interface{}{"float": math.MaxFloat32},
|
||||
expected: map[string]*dynamodb.AttributeValue{"float": {N: aws.String("340282346638528860000000000000000000000")}},
|
||||
},
|
||||
{
|
||||
input: map[string]interface{}{"float": math.MaxFloat64},
|
||||
expected: map[string]*dynamodb.AttributeValue{"float": {N: aws.String("179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")}},
|
||||
},
|
||||
{
|
||||
input: map[string]interface{}{"num": 12.},
|
||||
expected: map[string]*dynamodb.AttributeValue{"num": {N: aws.String("12")}},
|
||||
},
|
||||
{
|
||||
input: map[string]interface{}{"byte": []byte{48, 49}},
|
||||
expected: map[string]*dynamodb.AttributeValue{"byte": {B: []byte{48, 49}}},
|
||||
},
|
||||
{
|
||||
input: struct{ Byte []byte }{Byte: []byte{48, 49}},
|
||||
expected: map[string]*dynamodb.AttributeValue{"Byte": {B: []byte{48, 49}}},
|
||||
},
|
||||
{
|
||||
input: map[string]interface{}{"byte_set": [][]byte{{48, 49}, {50, 51}}},
|
||||
expected: map[string]*dynamodb.AttributeValue{"byte_set": {BS: [][]byte{{48, 49}, {50, 51}}}},
|
||||
},
|
||||
{
|
||||
input: struct{ ByteSet [][]byte }{ByteSet: [][]byte{{48, 49}, {50, 51}}},
|
||||
expected: map[string]*dynamodb.AttributeValue{"ByteSet": {BS: [][]byte{{48, 49}, {50, 51}}}},
|
||||
},
|
||||
// List
|
||||
{
|
||||
input: map[string]interface{}{"list": []interface{}{"a string", 12., 3.14, true, nil, false}},
|
||||
expected: map[string]*dynamodb.AttributeValue{
|
||||
"list": {
|
||||
L: []*dynamodb.AttributeValue{
|
||||
{S: aws.String("a string")},
|
||||
{N: aws.String("12")},
|
||||
{N: aws.String("3.14")},
|
||||
{BOOL: &trueValue},
|
||||
{NULL: &trueValue},
|
||||
{BOOL: &falseValue},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
// Map
|
||||
{
|
||||
input: map[string]interface{}{"map": map[string]interface{}{"nestednum": 12.}},
|
||||
expected: map[string]*dynamodb.AttributeValue{
|
||||
"map": {
|
||||
M: map[string]*dynamodb.AttributeValue{
|
||||
"nestednum": {
|
||||
N: aws.String("12"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
// Structs
|
||||
{
|
||||
input: simpleMarshalStruct{},
|
||||
expected: map[string]*dynamodb.AttributeValue{
|
||||
"Byte": {NULL: &trueValue},
|
||||
"Bool": {BOOL: &falseValue},
|
||||
"Float32": {N: aws.String("0")},
|
||||
"Float64": {N: aws.String("0")},
|
||||
"Int": {N: aws.String("0")},
|
||||
"Null": {NULL: &trueValue},
|
||||
"String": {NULL: &trueValue},
|
||||
"Uint": {N: aws.String("0")},
|
||||
},
|
||||
},
|
||||
{
|
||||
input: complexMarshalStruct{},
|
||||
expected: map[string]*dynamodb.AttributeValue{
|
||||
"Simple": {NULL: &trueValue},
|
||||
},
|
||||
},
|
||||
{
|
||||
input: struct {
|
||||
Simple []string `json:"simple"`
|
||||
}{},
|
||||
expected: map[string]*dynamodb.AttributeValue{
|
||||
"simple": {NULL: &trueValue},
|
||||
},
|
||||
},
|
||||
{
|
||||
input: struct {
|
||||
Simple []string `json:"simple,omitempty"`
|
||||
}{},
|
||||
expected: map[string]*dynamodb.AttributeValue{},
|
||||
},
|
||||
{
|
||||
input: struct {
|
||||
Simple []string `json:"-"`
|
||||
}{},
|
||||
expected: map[string]*dynamodb.AttributeValue{},
|
||||
},
|
||||
{
|
||||
input: complexMarshalStruct{Simple: []simpleMarshalStruct{{Int: -2}, {Uint: 5}}},
|
||||
expected: map[string]*dynamodb.AttributeValue{
|
||||
"Simple": {
|
||||
L: []*dynamodb.AttributeValue{
|
||||
{
|
||||
M: map[string]*dynamodb.AttributeValue{
|
||||
"Byte": {NULL: &trueValue},
|
||||
"Bool": {BOOL: &falseValue},
|
||||
"Float32": {N: aws.String("0")},
|
||||
"Float64": {N: aws.String("0")},
|
||||
"Int": {N: aws.String("-2")},
|
||||
"Null": {NULL: &trueValue},
|
||||
"String": {NULL: &trueValue},
|
||||
"Uint": {N: aws.String("0")},
|
||||
},
|
||||
},
|
||||
{
|
||||
M: map[string]*dynamodb.AttributeValue{
|
||||
"Byte": {NULL: &trueValue},
|
||||
"Bool": {BOOL: &falseValue},
|
||||
"Float32": {N: aws.String("0")},
|
||||
"Float64": {N: aws.String("0")},
|
||||
"Int": {N: aws.String("0")},
|
||||
"Null": {NULL: &trueValue},
|
||||
"String": {NULL: &trueValue},
|
||||
"Uint": {N: aws.String("5")},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
var marshallerListTestInputs = []marshallerTestInput{
|
||||
{
|
||||
input: nil,
|
||||
expected: []*dynamodb.AttributeValue{},
|
||||
},
|
||||
{
|
||||
input: []interface{}{},
|
||||
expected: []*dynamodb.AttributeValue{},
|
||||
},
|
||||
{
|
||||
input: []simpleMarshalStruct{},
|
||||
expected: []*dynamodb.AttributeValue{},
|
||||
},
|
||||
{
|
||||
input: []interface{}{"a string", 12., 3.14, true, nil, false},
|
||||
expected: []*dynamodb.AttributeValue{
|
||||
{S: aws.String("a string")},
|
||||
{N: aws.String("12")},
|
||||
{N: aws.String("3.14")},
|
||||
{BOOL: &trueValue},
|
||||
{NULL: &trueValue},
|
||||
{BOOL: &falseValue},
|
||||
},
|
||||
},
|
||||
{
|
||||
input: []simpleMarshalStruct{{}},
|
||||
expected: []*dynamodb.AttributeValue{
|
||||
{
|
||||
M: map[string]*dynamodb.AttributeValue{
|
||||
"Byte": {NULL: &trueValue},
|
||||
"Bool": {BOOL: &falseValue},
|
||||
"Float32": {N: aws.String("0")},
|
||||
"Float64": {N: aws.String("0")},
|
||||
"Int": {N: aws.String("0")},
|
||||
"Null": {NULL: &trueValue},
|
||||
"String": {NULL: &trueValue},
|
||||
"Uint": {N: aws.String("0")},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func Test_New_Marshal(t *testing.T) {
|
||||
for _, test := range marshalerScalarInputs {
|
||||
testMarshal(t, test)
|
||||
}
|
||||
}
|
||||
|
||||
func testMarshal(t *testing.T, test marshallerTestInput) {
|
||||
actual, err := Marshal(test.input)
|
||||
if test.err != nil {
|
||||
if err == nil {
|
||||
t.Errorf("Marshal with input %#v retured %#v, expected error `%s`", test.input, actual, test.err)
|
||||
} else if err.Error() != test.err.Error() {
|
||||
t.Errorf("Marshal with input %#v retured error `%s`, expected error `%s`", test.input, err, test.err)
|
||||
}
|
||||
} else {
|
||||
if err != nil {
|
||||
t.Errorf("Marshal with input %#v retured error `%s`", test.input, err)
|
||||
}
|
||||
compareObjects(t, test.expected, actual)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_New_Unmarshal(t *testing.T) {
|
||||
// Using the same inputs from Marshal, test the reverse mapping.
|
||||
for i, test := range marshalerScalarInputs {
|
||||
if test.input == nil {
|
||||
continue
|
||||
}
|
||||
actual := reflect.New(reflect.TypeOf(test.input)).Interface()
|
||||
if err := Unmarshal(test.expected.(*dynamodb.AttributeValue), actual); err != nil {
|
||||
t.Errorf("Unmarshal %d, with input %#v retured error `%s`", i+1, test.expected, err)
|
||||
}
|
||||
compareObjects(t, test.input, reflect.ValueOf(actual).Elem().Interface())
|
||||
}
|
||||
}
|
||||
|
||||
func Test_New_UnmarshalError(t *testing.T) {
|
||||
// Test that we get an error using Unmarshal to convert to a nil value.
|
||||
expected := &InvalidUnmarshalError{Type: reflect.TypeOf(nil)}
|
||||
if err := Unmarshal(nil, nil); err == nil {
|
||||
t.Errorf("Unmarshal with input %T returned no error, expected error `%v`", nil, expected)
|
||||
} else if err.Error() != expected.Error() {
|
||||
t.Errorf("Unmarshal with input %T returned error `%v`, expected error `%v`", nil, err, expected)
|
||||
}
|
||||
|
||||
// Test that we get an error using Unmarshal to convert to a non-pointer value.
|
||||
var actual map[string]interface{}
|
||||
expected = &InvalidUnmarshalError{Type: reflect.TypeOf(actual)}
|
||||
if err := Unmarshal(nil, actual); err == nil {
|
||||
t.Errorf("Unmarshal with input %T returned no error, expected error `%v`", actual, expected)
|
||||
} else if err.Error() != expected.Error() {
|
||||
t.Errorf("Unmarshal with input %T returned error `%v`, expected error `%v`", actual, err, expected)
|
||||
}
|
||||
|
||||
// Test that we get an error using Unmarshal to convert to nil struct.
|
||||
var actual2 *struct{ A int }
|
||||
expected = &InvalidUnmarshalError{Type: reflect.TypeOf(actual2)}
|
||||
if err := Unmarshal(nil, actual2); err == nil {
|
||||
t.Errorf("Unmarshal with input %T returned no error, expected error `%v`", actual2, expected)
|
||||
} else if err.Error() != expected.Error() {
|
||||
t.Errorf("Unmarshal with input %T returned error `%v`, expected error `%v`", actual2, err, expected)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_New_MarshalMap(t *testing.T) {
|
||||
for _, test := range marshallerMapTestInputs {
|
||||
testMarshalMap(t, test)
|
||||
}
|
||||
}
|
||||
|
||||
func testMarshalMap(t *testing.T, test marshallerTestInput) {
|
||||
actual, err := MarshalMap(test.input)
|
||||
if test.err != nil {
|
||||
if err == nil {
|
||||
t.Errorf("MarshalMap with input %#v retured %#v, expected error `%s`", test.input, actual, test.err)
|
||||
} else if err.Error() != test.err.Error() {
|
||||
t.Errorf("MarshalMap with input %#v retured error `%s`, expected error `%s`", test.input, err, test.err)
|
||||
}
|
||||
} else {
|
||||
if err != nil {
|
||||
t.Errorf("MarshalMap with input %#v retured error `%s`", test.input, err)
|
||||
}
|
||||
compareObjects(t, test.expected, actual)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_New_UnmarshalMap(t *testing.T) {
|
||||
// Using the same inputs from MarshalMap, test the reverse mapping.
|
||||
for i, test := range marshallerMapTestInputs {
|
||||
if test.input == nil {
|
||||
continue
|
||||
}
|
||||
actual := reflect.New(reflect.TypeOf(test.input)).Interface()
|
||||
if err := UnmarshalMap(test.expected.(map[string]*dynamodb.AttributeValue), actual); err != nil {
|
||||
t.Errorf("Unmarshal %d, with input %#v retured error `%s`", i+1, test.expected, err)
|
||||
}
|
||||
compareObjects(t, test.input, reflect.ValueOf(actual).Elem().Interface())
|
||||
}
|
||||
}
|
||||
|
||||
func Test_New_UnmarshalMapError(t *testing.T) {
|
||||
// Test that we get an error using UnmarshalMap to convert to a nil value.
|
||||
expected := &InvalidUnmarshalError{Type: reflect.TypeOf(nil)}
|
||||
if err := UnmarshalMap(nil, nil); err == nil {
|
||||
t.Errorf("UnmarshalMap with input %T returned no error, expected error `%v`", nil, expected)
|
||||
} else if err.Error() != expected.Error() {
|
||||
t.Errorf("UnmarshalMap with input %T returned error `%v`, expected error `%v`", nil, err, expected)
|
||||
}
|
||||
|
||||
// Test that we get an error using UnmarshalMap to convert to a non-pointer value.
|
||||
var actual map[string]interface{}
|
||||
expected = &InvalidUnmarshalError{Type: reflect.TypeOf(actual)}
|
||||
if err := UnmarshalMap(nil, actual); err == nil {
|
||||
t.Errorf("UnmarshalMap with input %T returned no error, expected error `%v`", actual, expected)
|
||||
} else if err.Error() != expected.Error() {
|
||||
t.Errorf("UnmarshalMap with input %T returned error `%v`, expected error `%v`", actual, err, expected)
|
||||
}
|
||||
|
||||
// Test that we get an error using UnmarshalMap to convert to nil struct.
|
||||
var actual2 *struct{ A int }
|
||||
expected = &InvalidUnmarshalError{Type: reflect.TypeOf(actual2)}
|
||||
if err := UnmarshalMap(nil, actual2); err == nil {
|
||||
t.Errorf("UnmarshalMap with input %T returned no error, expected error `%v`", actual2, expected)
|
||||
} else if err.Error() != expected.Error() {
|
||||
t.Errorf("UnmarshalMap with input %T returned error `%v`, expected error `%v`", actual2, err, expected)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_New_MarshalList(t *testing.T) {
|
||||
for _, test := range marshallerListTestInputs {
|
||||
testMarshalList(t, test)
|
||||
}
|
||||
}
|
||||
|
||||
func testMarshalList(t *testing.T, test marshallerTestInput) {
|
||||
actual, err := MarshalList(test.input)
|
||||
if test.err != nil {
|
||||
if err == nil {
|
||||
t.Errorf("MarshalList with input %#v retured %#v, expected error `%s`", test.input, actual, test.err)
|
||||
} else if err.Error() != test.err.Error() {
|
||||
t.Errorf("MarshalList with input %#v retured error `%s`, expected error `%s`", test.input, err, test.err)
|
||||
}
|
||||
} else {
|
||||
if err != nil {
|
||||
t.Errorf("MarshalList with input %#v retured error `%s`", test.input, err)
|
||||
}
|
||||
compareObjects(t, test.expected, actual)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_New_UnmarshalList(t *testing.T) {
|
||||
// Using the same inputs from MarshalList, test the reverse mapping.
|
||||
for i, test := range marshallerListTestInputs {
|
||||
if test.input == nil {
|
||||
continue
|
||||
}
|
||||
iv := reflect.ValueOf(test.input)
|
||||
|
||||
actual := reflect.New(iv.Type())
|
||||
if iv.Kind() == reflect.Slice {
|
||||
actual.Elem().Set(reflect.MakeSlice(iv.Type(), iv.Len(), iv.Cap()))
|
||||
}
|
||||
|
||||
if err := UnmarshalList(test.expected.([]*dynamodb.AttributeValue), actual.Interface()); err != nil {
|
||||
t.Errorf("Unmarshal %d, with input %#v retured error `%s`", i+1, test.expected, err)
|
||||
}
|
||||
compareObjects(t, test.input, actual.Elem().Interface())
|
||||
}
|
||||
}
|
||||
|
||||
func Test_New_UnmarshalListError(t *testing.T) {
|
||||
// Test that we get an error using UnmarshalList to convert to a nil value.
|
||||
expected := &InvalidUnmarshalError{Type: reflect.TypeOf(nil)}
|
||||
if err := UnmarshalList(nil, nil); err == nil {
|
||||
t.Errorf("UnmarshalList with input %T returned no error, expected error `%v`", nil, expected)
|
||||
} else if err.Error() != expected.Error() {
|
||||
t.Errorf("UnmarshalList with input %T returned error `%v`, expected error `%v`", nil, err, expected)
|
||||
}
|
||||
|
||||
// Test that we get an error using UnmarshalList to convert to a non-pointer value.
|
||||
var actual map[string]interface{}
|
||||
expected = &InvalidUnmarshalError{Type: reflect.TypeOf(actual)}
|
||||
if err := UnmarshalList(nil, actual); err == nil {
|
||||
t.Errorf("UnmarshalList with input %T returned no error, expected error `%v`", actual, expected)
|
||||
} else if err.Error() != expected.Error() {
|
||||
t.Errorf("UnmarshalList with input %T returned error `%v`, expected error `%v`", actual, err, expected)
|
||||
}
|
||||
|
||||
// Test that we get an error using UnmarshalList to convert to nil struct.
|
||||
var actual2 *struct{ A int }
|
||||
expected = &InvalidUnmarshalError{Type: reflect.TypeOf(actual2)}
|
||||
if err := UnmarshalList(nil, actual2); err == nil {
|
||||
t.Errorf("UnmarshalList with input %T returned no error, expected error `%v`", actual2, expected)
|
||||
} else if err.Error() != expected.Error() {
|
||||
t.Errorf("UnmarshalList with input %T returned error `%v`, expected error `%v`", actual2, err, expected)
|
||||
}
|
||||
}
|
||||
|
||||
func compareObjects(t *testing.T, expected interface{}, actual interface{}) {
|
||||
if !reflect.DeepEqual(expected, actual) {
|
||||
ev := reflect.ValueOf(expected)
|
||||
av := reflect.ValueOf(actual)
|
||||
t.Errorf("\nExpected kind(%s,%T):\n%s\nActual kind(%s,%T):\n%s\n",
|
||||
ev.Kind(),
|
||||
ev.Interface(),
|
||||
awsutil.Prettify(expected),
|
||||
av.Kind(),
|
||||
ev.Interface(),
|
||||
awsutil.Prettify(actual))
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkMarshal(b *testing.B) {
|
||||
d := simpleMarshalStruct{
|
||||
String: "abc",
|
||||
Int: 123,
|
||||
Uint: 123,
|
||||
Float32: 123.321,
|
||||
Float64: 123.321,
|
||||
Bool: true,
|
||||
Null: nil,
|
||||
}
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, err := Marshal(d)
|
||||
if err != nil {
|
||||
b.Fatal("unexpected error", err)
|
||||
}
|
||||
}
|
||||
}
|
402
vendor/github.com/aws/aws-sdk-go/service/dynamodb/dynamodbattribute/shared_test.go
generated
vendored
Normal file
402
vendor/github.com/aws/aws-sdk-go/service/dynamodb/dynamodbattribute/shared_test.go
generated
vendored
Normal file
|
@ -0,0 +1,402 @@
|
|||
package dynamodbattribute
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/service/dynamodb"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
type testBinarySetStruct struct {
|
||||
Binarys [][]byte `dynamodbav:",binaryset"`
|
||||
}
|
||||
type testNumberSetStruct struct {
|
||||
Numbers []int `dynamodbav:",numberset"`
|
||||
}
|
||||
type testStringSetStruct struct {
|
||||
Strings []string `dynamodbav:",stringset"`
|
||||
}
|
||||
|
||||
type testIntAsStringStruct struct {
|
||||
Value int `dynamodbav:",string"`
|
||||
}
|
||||
|
||||
type testOmitEmptyStruct struct {
|
||||
Value string `dynamodbav:",omitempty"`
|
||||
Value2 *string `dynamodbav:",omitempty"`
|
||||
Value3 int
|
||||
}
|
||||
|
||||
type testAliasedString string
|
||||
type testAliasedStringSlice []string
|
||||
type testAliasedInt int
|
||||
type testAliasedIntSlice []int
|
||||
type testAliasedMap map[string]int
|
||||
type testAliasedSlice []string
|
||||
type testAliasedByteSlice []byte
|
||||
type testAliasedBool bool
|
||||
type testAliasedBoolSlice []bool
|
||||
|
||||
type testAliasedStruct struct {
|
||||
Value testAliasedString
|
||||
Value2 testAliasedInt
|
||||
Value3 testAliasedMap
|
||||
Value4 testAliasedSlice
|
||||
|
||||
Value5 testAliasedByteSlice
|
||||
Value6 []testAliasedInt
|
||||
Value7 []testAliasedString
|
||||
|
||||
Value8 []testAliasedByteSlice `dynamodbav:",binaryset"`
|
||||
Value9 []testAliasedInt `dynamodbav:",numberset"`
|
||||
Value10 []testAliasedString `dynamodbav:",stringset"`
|
||||
|
||||
Value11 testAliasedIntSlice
|
||||
Value12 testAliasedStringSlice
|
||||
|
||||
Value13 testAliasedBool
|
||||
Value14 testAliasedBoolSlice
|
||||
}
|
||||
|
||||
type testNamedPointer *int
|
||||
|
||||
var testDate, _ = time.Parse(time.RFC3339, "2016-05-03T17:06:26.209072Z")
|
||||
|
||||
var sharedTestCases = []struct {
|
||||
in *dynamodb.AttributeValue
|
||||
actual, expected interface{}
|
||||
err error
|
||||
}{
|
||||
{ // Binary slice
|
||||
in: &dynamodb.AttributeValue{B: []byte{48, 49}},
|
||||
actual: &[]byte{},
|
||||
expected: []byte{48, 49},
|
||||
},
|
||||
{ // Binary slice
|
||||
in: &dynamodb.AttributeValue{B: []byte{48, 49}},
|
||||
actual: &[]byte{},
|
||||
expected: []byte{48, 49},
|
||||
},
|
||||
{ // Binary slice oversized
|
||||
in: &dynamodb.AttributeValue{B: []byte{48, 49}},
|
||||
actual: func() *[]byte {
|
||||
v := make([]byte, 0, 10)
|
||||
return &v
|
||||
}(),
|
||||
expected: []byte{48, 49},
|
||||
},
|
||||
{ // Binary slice pointer
|
||||
in: &dynamodb.AttributeValue{B: []byte{48, 49}},
|
||||
actual: func() **[]byte {
|
||||
v := make([]byte, 0, 10)
|
||||
v2 := &v
|
||||
return &v2
|
||||
}(),
|
||||
expected: []byte{48, 49},
|
||||
},
|
||||
{ // Bool
|
||||
in: &dynamodb.AttributeValue{BOOL: aws.Bool(true)},
|
||||
actual: new(bool),
|
||||
expected: true,
|
||||
},
|
||||
{ // List
|
||||
in: &dynamodb.AttributeValue{L: []*dynamodb.AttributeValue{
|
||||
{N: aws.String("123")},
|
||||
}},
|
||||
actual: &[]int{},
|
||||
expected: []int{123},
|
||||
},
|
||||
{ // Map, interface
|
||||
in: &dynamodb.AttributeValue{M: map[string]*dynamodb.AttributeValue{
|
||||
"abc": {N: aws.String("123")},
|
||||
}},
|
||||
actual: &map[string]int{},
|
||||
expected: map[string]int{"abc": 123},
|
||||
},
|
||||
{ // Map, struct
|
||||
in: &dynamodb.AttributeValue{M: map[string]*dynamodb.AttributeValue{
|
||||
"Abc": {N: aws.String("123")},
|
||||
}},
|
||||
actual: &struct{ Abc int }{},
|
||||
expected: struct{ Abc int }{Abc: 123},
|
||||
},
|
||||
{ // Map, struct
|
||||
in: &dynamodb.AttributeValue{M: map[string]*dynamodb.AttributeValue{
|
||||
"abc": {N: aws.String("123")},
|
||||
}},
|
||||
actual: &struct {
|
||||
Abc int `json:"abc" dynamodbav:"abc"`
|
||||
}{},
|
||||
expected: struct {
|
||||
Abc int `json:"abc" dynamodbav:"abc"`
|
||||
}{Abc: 123},
|
||||
},
|
||||
{ // Number, int
|
||||
in: &dynamodb.AttributeValue{N: aws.String("123")},
|
||||
actual: new(int),
|
||||
expected: 123,
|
||||
},
|
||||
{ // Number, Float
|
||||
in: &dynamodb.AttributeValue{N: aws.String("123.1")},
|
||||
actual: new(float64),
|
||||
expected: float64(123.1),
|
||||
},
|
||||
{ // Null
|
||||
in: &dynamodb.AttributeValue{NULL: aws.Bool(true)},
|
||||
actual: new(string),
|
||||
expected: "",
|
||||
},
|
||||
{ // Null ptr
|
||||
in: &dynamodb.AttributeValue{NULL: aws.Bool(true)},
|
||||
actual: new(*string),
|
||||
expected: nil,
|
||||
},
|
||||
{ // String
|
||||
in: &dynamodb.AttributeValue{S: aws.String("abc")},
|
||||
actual: new(string),
|
||||
expected: "abc",
|
||||
},
|
||||
{ // Binary Set
|
||||
in: &dynamodb.AttributeValue{
|
||||
M: map[string]*dynamodb.AttributeValue{
|
||||
"Binarys": {BS: [][]byte{{48, 49}, {50, 51}}},
|
||||
},
|
||||
},
|
||||
actual: &testBinarySetStruct{},
|
||||
expected: testBinarySetStruct{Binarys: [][]byte{{48, 49}, {50, 51}}},
|
||||
},
|
||||
{ // Number Set
|
||||
in: &dynamodb.AttributeValue{
|
||||
M: map[string]*dynamodb.AttributeValue{
|
||||
"Numbers": {NS: []*string{aws.String("123"), aws.String("321")}},
|
||||
},
|
||||
},
|
||||
actual: &testNumberSetStruct{},
|
||||
expected: testNumberSetStruct{Numbers: []int{123, 321}},
|
||||
},
|
||||
{ // String Set
|
||||
in: &dynamodb.AttributeValue{
|
||||
M: map[string]*dynamodb.AttributeValue{
|
||||
"Strings": {SS: []*string{aws.String("abc"), aws.String("efg")}},
|
||||
},
|
||||
},
|
||||
actual: &testStringSetStruct{},
|
||||
expected: testStringSetStruct{Strings: []string{"abc", "efg"}},
|
||||
},
|
||||
{ // Int value as string
|
||||
in: &dynamodb.AttributeValue{
|
||||
M: map[string]*dynamodb.AttributeValue{
|
||||
"Value": {S: aws.String("123")},
|
||||
},
|
||||
},
|
||||
actual: &testIntAsStringStruct{},
|
||||
expected: testIntAsStringStruct{Value: 123},
|
||||
},
|
||||
{ // Omitempty
|
||||
in: &dynamodb.AttributeValue{
|
||||
M: map[string]*dynamodb.AttributeValue{
|
||||
"Value3": {N: aws.String("0")},
|
||||
},
|
||||
},
|
||||
actual: &testOmitEmptyStruct{},
|
||||
expected: testOmitEmptyStruct{Value: "", Value2: nil, Value3: 0},
|
||||
},
|
||||
{ // aliased type
|
||||
in: &dynamodb.AttributeValue{
|
||||
M: map[string]*dynamodb.AttributeValue{
|
||||
"Value": {S: aws.String("123")},
|
||||
"Value2": {N: aws.String("123")},
|
||||
"Value3": {M: map[string]*dynamodb.AttributeValue{
|
||||
"Key": {N: aws.String("321")},
|
||||
}},
|
||||
"Value4": {L: []*dynamodb.AttributeValue{
|
||||
{S: aws.String("1")},
|
||||
{S: aws.String("2")},
|
||||
{S: aws.String("3")},
|
||||
}},
|
||||
"Value5": {B: []byte{0, 1, 2}},
|
||||
"Value6": {L: []*dynamodb.AttributeValue{
|
||||
{N: aws.String("1")},
|
||||
{N: aws.String("2")},
|
||||
{N: aws.String("3")},
|
||||
}},
|
||||
"Value7": {L: []*dynamodb.AttributeValue{
|
||||
{S: aws.String("1")},
|
||||
{S: aws.String("2")},
|
||||
{S: aws.String("3")},
|
||||
}},
|
||||
"Value8": {BS: [][]byte{
|
||||
{0, 1, 2}, {3, 4, 5},
|
||||
}},
|
||||
"Value9": {NS: []*string{
|
||||
aws.String("1"),
|
||||
aws.String("2"),
|
||||
aws.String("3"),
|
||||
}},
|
||||
"Value10": {SS: []*string{
|
||||
aws.String("1"),
|
||||
aws.String("2"),
|
||||
aws.String("3"),
|
||||
}},
|
||||
"Value11": {L: []*dynamodb.AttributeValue{
|
||||
{N: aws.String("1")},
|
||||
{N: aws.String("2")},
|
||||
{N: aws.String("3")},
|
||||
}},
|
||||
"Value12": {L: []*dynamodb.AttributeValue{
|
||||
{S: aws.String("1")},
|
||||
{S: aws.String("2")},
|
||||
{S: aws.String("3")},
|
||||
}},
|
||||
"Value13": {BOOL: aws.Bool(true)},
|
||||
"Value14": {L: []*dynamodb.AttributeValue{
|
||||
{BOOL: aws.Bool(true)},
|
||||
{BOOL: aws.Bool(false)},
|
||||
{BOOL: aws.Bool(true)},
|
||||
}},
|
||||
},
|
||||
},
|
||||
actual: &testAliasedStruct{},
|
||||
expected: testAliasedStruct{
|
||||
Value: "123", Value2: 123,
|
||||
Value3: testAliasedMap{
|
||||
"Key": 321,
|
||||
},
|
||||
Value4: testAliasedSlice{"1", "2", "3"},
|
||||
Value5: testAliasedByteSlice{0, 1, 2},
|
||||
Value6: []testAliasedInt{1, 2, 3},
|
||||
Value7: []testAliasedString{"1", "2", "3"},
|
||||
Value8: []testAliasedByteSlice{
|
||||
{0, 1, 2},
|
||||
{3, 4, 5},
|
||||
},
|
||||
Value9: []testAliasedInt{1, 2, 3},
|
||||
Value10: []testAliasedString{"1", "2", "3"},
|
||||
Value11: testAliasedIntSlice{1, 2, 3},
|
||||
Value12: testAliasedStringSlice{"1", "2", "3"},
|
||||
Value13: true,
|
||||
Value14: testAliasedBoolSlice{true, false, true},
|
||||
},
|
||||
},
|
||||
{
|
||||
in: &dynamodb.AttributeValue{N: aws.String("123")},
|
||||
actual: new(testNamedPointer),
|
||||
expected: testNamedPointer(aws.Int(123)),
|
||||
},
|
||||
{ // time.Time
|
||||
in: &dynamodb.AttributeValue{S: aws.String("2016-05-03T17:06:26.209072Z")},
|
||||
actual: new(time.Time),
|
||||
expected: testDate,
|
||||
},
|
||||
{ // time.Time List
|
||||
in: &dynamodb.AttributeValue{L: []*dynamodb.AttributeValue{
|
||||
{S: aws.String("2016-05-03T17:06:26.209072Z")},
|
||||
{S: aws.String("2016-05-04T17:06:26.209072Z")},
|
||||
}},
|
||||
actual: new([]time.Time),
|
||||
expected: []time.Time{testDate, testDate.Add(24 * time.Hour)},
|
||||
},
|
||||
{ // time.Time struct
|
||||
in: &dynamodb.AttributeValue{M: map[string]*dynamodb.AttributeValue{
|
||||
"abc": {S: aws.String("2016-05-03T17:06:26.209072Z")},
|
||||
}},
|
||||
actual: &struct {
|
||||
Abc time.Time `json:"abc" dynamodbav:"abc"`
|
||||
}{},
|
||||
expected: struct {
|
||||
Abc time.Time `json:"abc" dynamodbav:"abc"`
|
||||
}{Abc: testDate},
|
||||
},
|
||||
{ // time.Time ptr struct
|
||||
in: &dynamodb.AttributeValue{M: map[string]*dynamodb.AttributeValue{
|
||||
"abc": {S: aws.String("2016-05-03T17:06:26.209072Z")},
|
||||
}},
|
||||
actual: &struct {
|
||||
Abc *time.Time `json:"abc" dynamodbav:"abc"`
|
||||
}{},
|
||||
expected: struct {
|
||||
Abc *time.Time `json:"abc" dynamodbav:"abc"`
|
||||
}{Abc: &testDate},
|
||||
},
|
||||
}
|
||||
|
||||
var sharedListTestCases = []struct {
|
||||
in []*dynamodb.AttributeValue
|
||||
actual, expected interface{}
|
||||
err error
|
||||
}{
|
||||
{
|
||||
in: []*dynamodb.AttributeValue{
|
||||
{B: []byte{48, 49}},
|
||||
{BOOL: aws.Bool(true)},
|
||||
{N: aws.String("123")},
|
||||
{S: aws.String("123")},
|
||||
},
|
||||
actual: func() *[]interface{} {
|
||||
v := []interface{}{}
|
||||
return &v
|
||||
}(),
|
||||
expected: []interface{}{[]byte{48, 49}, true, 123., "123"},
|
||||
},
|
||||
{
|
||||
in: []*dynamodb.AttributeValue{
|
||||
{N: aws.String("1")},
|
||||
{N: aws.String("2")},
|
||||
{N: aws.String("3")},
|
||||
},
|
||||
actual: &[]interface{}{},
|
||||
expected: []interface{}{1., 2., 3.},
|
||||
},
|
||||
}
|
||||
|
||||
var sharedMapTestCases = []struct {
|
||||
in map[string]*dynamodb.AttributeValue
|
||||
actual, expected interface{}
|
||||
err error
|
||||
}{
|
||||
{
|
||||
in: map[string]*dynamodb.AttributeValue{
|
||||
"B": {B: []byte{48, 49}},
|
||||
"BOOL": {BOOL: aws.Bool(true)},
|
||||
"N": {N: aws.String("123")},
|
||||
"S": {S: aws.String("123")},
|
||||
},
|
||||
actual: &map[string]interface{}{},
|
||||
expected: map[string]interface{}{
|
||||
"B": []byte{48, 49}, "BOOL": true,
|
||||
"N": 123., "S": "123",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func assertConvertTest(t *testing.T, i int, actual, expected interface{}, err, expectedErr error) {
|
||||
i++
|
||||
if expectedErr != nil {
|
||||
if err != nil {
|
||||
assert.Equal(t, expectedErr, err, "case %d", i)
|
||||
} else {
|
||||
assert.Fail(t, "", "case %d, expected error, %v", i)
|
||||
}
|
||||
} else if err != nil {
|
||||
assert.Fail(t, "", "case %d, expect no error, got %v", i, err)
|
||||
} else {
|
||||
assert.Equal(t, ptrToValue(expected), ptrToValue(actual), "case %d", i)
|
||||
}
|
||||
}
|
||||
|
||||
func ptrToValue(in interface{}) interface{} {
|
||||
v := reflect.ValueOf(in)
|
||||
if v.Kind() == reflect.Ptr {
|
||||
v = v.Elem()
|
||||
}
|
||||
if !v.IsValid() {
|
||||
return nil
|
||||
}
|
||||
if v.Kind() == reflect.Ptr {
|
||||
return ptrToValue(v.Interface())
|
||||
}
|
||||
return v.Interface()
|
||||
}
|
68
vendor/github.com/aws/aws-sdk-go/service/dynamodb/dynamodbattribute/tag.go
generated
vendored
Normal file
68
vendor/github.com/aws/aws-sdk-go/service/dynamodb/dynamodbattribute/tag.go
generated
vendored
Normal file
|
@ -0,0 +1,68 @@
|
|||
package dynamodbattribute
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type tag struct {
|
||||
Name string
|
||||
Ignore bool
|
||||
OmitEmpty bool
|
||||
OmitEmptyElem bool
|
||||
AsString bool
|
||||
AsBinSet, AsNumSet, AsStrSet bool
|
||||
AsUnixTime bool
|
||||
}
|
||||
|
||||
func (t *tag) parseAVTag(structTag reflect.StructTag) {
|
||||
tagStr := structTag.Get("dynamodbav")
|
||||
if len(tagStr) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
t.parseTagStr(tagStr)
|
||||
}
|
||||
|
||||
func (t *tag) parseJSONTag(structTag reflect.StructTag) {
|
||||
tagStr := structTag.Get("json")
|
||||
if len(tagStr) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
t.parseTagStr(tagStr)
|
||||
}
|
||||
|
||||
func (t *tag) parseTagStr(tagStr string) {
|
||||
parts := strings.Split(tagStr, ",")
|
||||
if len(parts) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
if name := parts[0]; name == "-" {
|
||||
t.Name = ""
|
||||
t.Ignore = true
|
||||
} else {
|
||||
t.Name = name
|
||||
t.Ignore = false
|
||||
}
|
||||
|
||||
for _, opt := range parts[1:] {
|
||||
switch opt {
|
||||
case "omitempty":
|
||||
t.OmitEmpty = true
|
||||
case "omitemptyelem":
|
||||
t.OmitEmptyElem = true
|
||||
case "string":
|
||||
t.AsString = true
|
||||
case "binaryset":
|
||||
t.AsBinSet = true
|
||||
case "numberset":
|
||||
t.AsNumSet = true
|
||||
case "stringset":
|
||||
t.AsStrSet = true
|
||||
case "unixtime":
|
||||
t.AsUnixTime = true
|
||||
}
|
||||
}
|
||||
}
|
47
vendor/github.com/aws/aws-sdk-go/service/dynamodb/dynamodbattribute/tag_test.go
generated
vendored
Normal file
47
vendor/github.com/aws/aws-sdk-go/service/dynamodb/dynamodbattribute/tag_test.go
generated
vendored
Normal file
|
@ -0,0 +1,47 @@
|
|||
package dynamodbattribute
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestTagParse(t *testing.T) {
|
||||
cases := []struct {
|
||||
in reflect.StructTag
|
||||
json, av bool
|
||||
expect tag
|
||||
}{
|
||||
{`json:""`, true, false, tag{}},
|
||||
{`json:"name"`, true, false, tag{Name: "name"}},
|
||||
{`json:"name,omitempty"`, true, false, tag{Name: "name", OmitEmpty: true}},
|
||||
{`json:"-"`, true, false, tag{Ignore: true}},
|
||||
{`json:",omitempty"`, true, false, tag{OmitEmpty: true}},
|
||||
{`json:",string"`, true, false, tag{AsString: true}},
|
||||
{`dynamodbav:""`, false, true, tag{}},
|
||||
{`dynamodbav:","`, false, true, tag{}},
|
||||
{`dynamodbav:"name"`, false, true, tag{Name: "name"}},
|
||||
{`dynamodbav:"name"`, false, true, tag{Name: "name"}},
|
||||
{`dynamodbav:"-"`, false, true, tag{Ignore: true}},
|
||||
{`dynamodbav:",omitempty"`, false, true, tag{OmitEmpty: true}},
|
||||
{`dynamodbav:",omitemptyelem"`, false, true, tag{OmitEmptyElem: true}},
|
||||
{`dynamodbav:",string"`, false, true, tag{AsString: true}},
|
||||
{`dynamodbav:",binaryset"`, false, true, tag{AsBinSet: true}},
|
||||
{`dynamodbav:",numberset"`, false, true, tag{AsNumSet: true}},
|
||||
{`dynamodbav:",stringset"`, false, true, tag{AsStrSet: true}},
|
||||
{`dynamodbav:",stringset,omitemptyelem"`, false, true, tag{AsStrSet: true, OmitEmptyElem: true}},
|
||||
{`dynamodbav:"name,stringset,omitemptyelem"`, false, true, tag{Name: "name", AsStrSet: true, OmitEmptyElem: true}},
|
||||
}
|
||||
|
||||
for i, c := range cases {
|
||||
actual := tag{}
|
||||
if c.json {
|
||||
actual.parseJSONTag(c.in)
|
||||
}
|
||||
if c.av {
|
||||
actual.parseAVTag(c.in)
|
||||
}
|
||||
assert.Equal(t, c.expect, actual, "case %d", i+1)
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue