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
8906
vendor/github.com/aws/aws-sdk-go/service/dynamodb/api.go
generated
vendored
Normal file
8906
vendor/github.com/aws/aws-sdk-go/service/dynamodb/api.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
109
vendor/github.com/aws/aws-sdk-go/service/dynamodb/customizations.go
generated
vendored
Normal file
109
vendor/github.com/aws/aws-sdk-go/service/dynamodb/customizations.go
generated
vendored
Normal file
|
@ -0,0 +1,109 @@
|
|||
package dynamodb
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"hash/crc32"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"math"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
"github.com/aws/aws-sdk-go/aws/client"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
)
|
||||
|
||||
type retryer struct {
|
||||
client.DefaultRetryer
|
||||
}
|
||||
|
||||
func (d retryer) RetryRules(r *request.Request) time.Duration {
|
||||
delay := time.Duration(math.Pow(2, float64(r.RetryCount))) * 50
|
||||
return delay * time.Millisecond
|
||||
}
|
||||
|
||||
func init() {
|
||||
initClient = func(c *client.Client) {
|
||||
if c.Config.Retryer == nil {
|
||||
// Only override the retryer with a custom one if the config
|
||||
// does not already contain a retryer
|
||||
setCustomRetryer(c)
|
||||
}
|
||||
|
||||
c.Handlers.Build.PushBack(disableCompression)
|
||||
c.Handlers.Unmarshal.PushFront(validateCRC32)
|
||||
}
|
||||
}
|
||||
|
||||
func setCustomRetryer(c *client.Client) {
|
||||
maxRetries := aws.IntValue(c.Config.MaxRetries)
|
||||
if c.Config.MaxRetries == nil || maxRetries == aws.UseServiceDefaultRetries {
|
||||
maxRetries = 10
|
||||
}
|
||||
|
||||
c.Retryer = retryer{
|
||||
DefaultRetryer: client.DefaultRetryer{
|
||||
NumMaxRetries: maxRetries,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func drainBody(b io.ReadCloser, length int64) (out *bytes.Buffer, err error) {
|
||||
if length < 0 {
|
||||
length = 0
|
||||
}
|
||||
buf := bytes.NewBuffer(make([]byte, 0, length))
|
||||
|
||||
if _, err = buf.ReadFrom(b); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = b.Close(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return buf, nil
|
||||
}
|
||||
|
||||
func disableCompression(r *request.Request) {
|
||||
r.HTTPRequest.Header.Set("Accept-Encoding", "identity")
|
||||
}
|
||||
|
||||
func validateCRC32(r *request.Request) {
|
||||
if r.Error != nil {
|
||||
return // already have an error, no need to verify CRC
|
||||
}
|
||||
|
||||
// Checksum validation is off, skip
|
||||
if aws.BoolValue(r.Config.DisableComputeChecksums) {
|
||||
return
|
||||
}
|
||||
|
||||
// Try to get CRC from response
|
||||
header := r.HTTPResponse.Header.Get("X-Amz-Crc32")
|
||||
if header == "" {
|
||||
return // No header, skip
|
||||
}
|
||||
|
||||
expected, err := strconv.ParseUint(header, 10, 32)
|
||||
if err != nil {
|
||||
return // Could not determine CRC value, skip
|
||||
}
|
||||
|
||||
buf, err := drainBody(r.HTTPResponse.Body, r.HTTPResponse.ContentLength)
|
||||
if err != nil { // failed to read the response body, skip
|
||||
return
|
||||
}
|
||||
|
||||
// Reset body for subsequent reads
|
||||
r.HTTPResponse.Body = ioutil.NopCloser(bytes.NewReader(buf.Bytes()))
|
||||
|
||||
// Compute the CRC checksum
|
||||
crc := crc32.ChecksumIEEE(buf.Bytes())
|
||||
|
||||
if crc != uint32(expected) {
|
||||
// CRC does not match, set a retryable error
|
||||
r.Retryable = aws.Bool(true)
|
||||
r.Error = awserr.New("CRC32CheckFailed", "CRC32 integrity check failed", nil)
|
||||
}
|
||||
}
|
153
vendor/github.com/aws/aws-sdk-go/service/dynamodb/customizations_test.go
generated
vendored
Normal file
153
vendor/github.com/aws/aws-sdk-go/service/dynamodb/customizations_test.go
generated
vendored
Normal file
|
@ -0,0 +1,153 @@
|
|||
package dynamodb_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
"github.com/aws/aws-sdk-go/aws/client"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
"github.com/aws/aws-sdk-go/awstesting/unit"
|
||||
"github.com/aws/aws-sdk-go/service/dynamodb"
|
||||
)
|
||||
|
||||
var db *dynamodb.DynamoDB
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
db = dynamodb.New(unit.Session, &aws.Config{
|
||||
MaxRetries: aws.Int(2),
|
||||
})
|
||||
db.Handlers.Send.Clear() // mock sending
|
||||
|
||||
os.Exit(m.Run())
|
||||
}
|
||||
|
||||
func mockCRCResponse(svc *dynamodb.DynamoDB, status int, body, crc string) (req *request.Request) {
|
||||
header := http.Header{}
|
||||
header.Set("x-amz-crc32", crc)
|
||||
|
||||
req, _ = svc.ListTablesRequest(nil)
|
||||
req.Handlers.Send.PushBack(func(*request.Request) {
|
||||
req.HTTPResponse = &http.Response{
|
||||
ContentLength: int64(len(body)),
|
||||
StatusCode: status,
|
||||
Body: ioutil.NopCloser(bytes.NewReader([]byte(body))),
|
||||
Header: header,
|
||||
}
|
||||
})
|
||||
req.Send()
|
||||
return
|
||||
}
|
||||
|
||||
func TestDefaultRetryRules(t *testing.T) {
|
||||
d := dynamodb.New(unit.Session, &aws.Config{MaxRetries: aws.Int(-1)})
|
||||
if e, a := 10, d.MaxRetries(); e != a {
|
||||
t.Errorf("expect %d max retries, got %d", e, a)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCustomRetryRules(t *testing.T) {
|
||||
d := dynamodb.New(unit.Session, &aws.Config{MaxRetries: aws.Int(2)})
|
||||
if e, a := 2, d.MaxRetries(); e != a {
|
||||
t.Errorf("expect %d max retries, got %d", e, a)
|
||||
}
|
||||
}
|
||||
|
||||
type testCustomRetryer struct {
|
||||
client.DefaultRetryer
|
||||
}
|
||||
|
||||
func TestCustomRetry_FromConfig(t *testing.T) {
|
||||
d := dynamodb.New(unit.Session, &aws.Config{
|
||||
Retryer: testCustomRetryer{client.DefaultRetryer{NumMaxRetries: 9}},
|
||||
})
|
||||
|
||||
if _, ok := d.Retryer.(testCustomRetryer); !ok {
|
||||
t.Errorf("expect retryer to be testCustomRetryer, but got %T", d.Retryer)
|
||||
}
|
||||
|
||||
if e, a := 9, d.MaxRetries(); e != a {
|
||||
t.Errorf("expect %d max retries from custom retryer, got %d", e, a)
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateCRC32NoHeaderSkip(t *testing.T) {
|
||||
req := mockCRCResponse(db, 200, "{}", "")
|
||||
if req.Error != nil {
|
||||
t.Errorf("expect no error, got %v", req.Error)
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateCRC32InvalidHeaderSkip(t *testing.T) {
|
||||
req := mockCRCResponse(db, 200, "{}", "ABC")
|
||||
if req.Error != nil {
|
||||
t.Errorf("expect no error, got %v", req.Error)
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateCRC32AlreadyErrorSkip(t *testing.T) {
|
||||
req := mockCRCResponse(db, 400, "{}", "1234")
|
||||
if req.Error == nil {
|
||||
t.Fatalf("expect error, but got none")
|
||||
}
|
||||
|
||||
aerr := req.Error.(awserr.Error)
|
||||
if aerr.Code() == "CRC32CheckFailed" {
|
||||
t.Errorf("expect error code not to be CRC32CheckFailed")
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateCRC32IsValid(t *testing.T) {
|
||||
req := mockCRCResponse(db, 200, `{"TableNames":["A"]}`, "3090163698")
|
||||
if req.Error != nil {
|
||||
t.Fatalf("expect no error, got %v", req.Error)
|
||||
}
|
||||
|
||||
// CRC check does not affect output parsing
|
||||
out := req.Data.(*dynamodb.ListTablesOutput)
|
||||
if e, a := "A", *out.TableNames[0]; e != a {
|
||||
t.Errorf("expect %q table name, got %q", e, a)
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateCRC32DoesNotMatch(t *testing.T) {
|
||||
req := mockCRCResponse(db, 200, "{}", "1234")
|
||||
if req.Error == nil {
|
||||
t.Fatalf("expect error, but got none")
|
||||
}
|
||||
|
||||
aerr := req.Error.(awserr.Error)
|
||||
if e, a := "CRC32CheckFailed", aerr.Code(); e != a {
|
||||
t.Errorf("expect %s error code, got %s", e, a)
|
||||
}
|
||||
if e, a := 2, req.RetryCount; e != a {
|
||||
t.Errorf("expect %d retry count, got %d", e, a)
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateCRC32DoesNotMatchNoComputeChecksum(t *testing.T) {
|
||||
svc := dynamodb.New(unit.Session, &aws.Config{
|
||||
MaxRetries: aws.Int(2),
|
||||
DisableComputeChecksums: aws.Bool(true),
|
||||
})
|
||||
svc.Handlers.Send.Clear() // mock sending
|
||||
|
||||
req := mockCRCResponse(svc, 200, `{"TableNames":["A"]}`, "1234")
|
||||
if req.Error != nil {
|
||||
t.Fatalf("expect no error, got %v", req.Error)
|
||||
}
|
||||
|
||||
if e, a := 0, req.RetryCount; e != a {
|
||||
t.Errorf("expect %d retry count, got %d", e, a)
|
||||
}
|
||||
|
||||
// CRC check disabled. Does not affect output parsing
|
||||
out := req.Data.(*dynamodb.ListTablesOutput)
|
||||
if e, a := "A", *out.TableNames[0]; e != a {
|
||||
t.Errorf("expect %q table name, got %q", e, a)
|
||||
}
|
||||
}
|
97
vendor/github.com/aws/aws-sdk-go/service/dynamodb/doc.go
generated
vendored
Normal file
97
vendor/github.com/aws/aws-sdk-go/service/dynamodb/doc.go
generated
vendored
Normal file
|
@ -0,0 +1,97 @@
|
|||
// Code generated by private/model/cli/gen-api/main.go. DO NOT EDIT.
|
||||
|
||||
// Package dynamodb provides the client and types for making API
|
||||
// requests to Amazon DynamoDB.
|
||||
//
|
||||
// Amazon DynamoDB is a fully managed NoSQL database service that provides fast
|
||||
// and predictable performance with seamless scalability. DynamoDB lets you
|
||||
// offload the administrative burdens of operating and scaling a distributed
|
||||
// database, so that you don't have to worry about hardware provisioning, setup
|
||||
// and configuration, replication, software patching, or cluster scaling.
|
||||
//
|
||||
// With DynamoDB, you can create database tables that can store and retrieve
|
||||
// any amount of data, and serve any level of request traffic. You can scale
|
||||
// up or scale down your tables' throughput capacity without downtime or performance
|
||||
// degradation, and use the AWS Management Console to monitor resource utilization
|
||||
// and performance metrics.
|
||||
//
|
||||
// DynamoDB automatically spreads the data and traffic for your tables over
|
||||
// a sufficient number of servers to handle your throughput and storage requirements,
|
||||
// while maintaining consistent and fast performance. All of your data is stored
|
||||
// on solid state disks (SSDs) and automatically replicated across multiple
|
||||
// Availability Zones in an AWS region, providing built-in high availability
|
||||
// and data durability.
|
||||
//
|
||||
// See https://docs.aws.amazon.com/goto/WebAPI/dynamodb-2012-08-10 for more information on this service.
|
||||
//
|
||||
// See dynamodb package documentation for more information.
|
||||
// https://docs.aws.amazon.com/sdk-for-go/api/service/dynamodb/
|
||||
//
|
||||
// Using the Client
|
||||
//
|
||||
// To use the client for Amazon DynamoDB you will first need
|
||||
// to create a new instance of it.
|
||||
//
|
||||
// When creating a client for an AWS service you'll first need to have a Session
|
||||
// already created. The Session provides configuration that can be shared
|
||||
// between multiple service clients. Additional configuration can be applied to
|
||||
// the Session and service's client when they are constructed. The aws package's
|
||||
// Config type contains several fields such as Region for the AWS Region the
|
||||
// client should make API requests too. The optional Config value can be provided
|
||||
// as the variadic argument for Sessions and client creation.
|
||||
//
|
||||
// Once the service's client is created you can use it to make API requests the
|
||||
// AWS service. These clients are safe to use concurrently.
|
||||
//
|
||||
// // Create a session to share configuration, and load external configuration.
|
||||
// sess := session.Must(session.NewSession())
|
||||
//
|
||||
// // Create the service's client with the session.
|
||||
// svc := dynamodb.New(sess)
|
||||
//
|
||||
// See the SDK's documentation for more information on how to use service clients.
|
||||
// https://docs.aws.amazon.com/sdk-for-go/api/
|
||||
//
|
||||
// See aws package's Config type for more information on configuration options.
|
||||
// https://docs.aws.amazon.com/sdk-for-go/api/aws/#Config
|
||||
//
|
||||
// See the Amazon DynamoDB client DynamoDB for more
|
||||
// information on creating the service's client.
|
||||
// https://docs.aws.amazon.com/sdk-for-go/api/service/dynamodb/#New
|
||||
//
|
||||
// Once the client is created you can make an API request to the service.
|
||||
// Each API method takes a input parameter, and returns the service response
|
||||
// and an error.
|
||||
//
|
||||
// The API method will document which error codes the service can be returned
|
||||
// by the operation if the service models the API operation's errors. These
|
||||
// errors will also be available as const strings prefixed with "ErrCode".
|
||||
//
|
||||
// result, err := svc.BatchGetItem(params)
|
||||
// if err != nil {
|
||||
// // Cast err to awserr.Error to handle specific error codes.
|
||||
// aerr, ok := err.(awserr.Error)
|
||||
// if ok && aerr.Code() == <error code to check for> {
|
||||
// // Specific error code handling
|
||||
// }
|
||||
// return err
|
||||
// }
|
||||
//
|
||||
// fmt.Println("BatchGetItem result:")
|
||||
// fmt.Println(result)
|
||||
//
|
||||
// Using the Client with Context
|
||||
//
|
||||
// The service's client also provides methods to make API requests with a Context
|
||||
// value. This allows you to control the timeout, and cancellation of pending
|
||||
// requests. These methods also take request Option as variadic parameter to apply
|
||||
// additional configuration to the API request.
|
||||
//
|
||||
// ctx := context.Background()
|
||||
//
|
||||
// result, err := svc.BatchGetItemWithContext(ctx, params)
|
||||
//
|
||||
// See the request package documentation for more information on using Context pattern
|
||||
// with the SDK.
|
||||
// https://docs.aws.amazon.com/sdk-for-go/api/aws/request/
|
||||
package dynamodb
|
84
vendor/github.com/aws/aws-sdk-go/service/dynamodb/doc_custom.go
generated
vendored
Normal file
84
vendor/github.com/aws/aws-sdk-go/service/dynamodb/doc_custom.go
generated
vendored
Normal file
|
@ -0,0 +1,84 @@
|
|||
// AttributeValue Marshaling and Unmarshaling Helpers
|
||||
//
|
||||
// Utility helpers to marshal and unmarshal AttributeValue to and
|
||||
// from Go types can be found in the dynamodbattribute sub package. This package
|
||||
// provides has specialized functions for the common ways of working with
|
||||
// AttributeValues. Such as map[string]*AttributeValue, []*AttributeValue, and
|
||||
// directly with *AttributeValue. This is helpful for marshaling Go types for API
|
||||
// operations such as PutItem, and unmarshaling Query and Scan APIs' responses.
|
||||
//
|
||||
// See the dynamodbattribute package documentation for more information.
|
||||
// https://docs.aws.amazon.com/sdk-for-go/api/service/dynamodb/dynamodbattribute/
|
||||
//
|
||||
// AttributeValue Marshaling
|
||||
//
|
||||
// To marshal a Go type to an AttributeValue 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 = 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
|
||||
// })
|
||||
package dynamodb
|
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)
|
||||
}
|
||||
}
|
158
vendor/github.com/aws/aws-sdk-go/service/dynamodb/dynamodbiface/interface.go
generated
vendored
Normal file
158
vendor/github.com/aws/aws-sdk-go/service/dynamodb/dynamodbiface/interface.go
generated
vendored
Normal file
|
@ -0,0 +1,158 @@
|
|||
// Code generated by private/model/cli/gen-api/main.go. DO NOT EDIT.
|
||||
|
||||
// Package dynamodbiface provides an interface to enable mocking the Amazon DynamoDB service client
|
||||
// for testing your code.
|
||||
//
|
||||
// It is important to note that this interface will have breaking changes
|
||||
// when the service model is updated and adds new API operations, paginators,
|
||||
// and waiters.
|
||||
package dynamodbiface
|
||||
|
||||
import (
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
"github.com/aws/aws-sdk-go/service/dynamodb"
|
||||
)
|
||||
|
||||
// DynamoDBAPI provides an interface to enable mocking the
|
||||
// dynamodb.DynamoDB service client's API operation,
|
||||
// paginators, and waiters. This make unit testing your code that calls out
|
||||
// to the SDK's service client's calls easier.
|
||||
//
|
||||
// The best way to use this interface is so the SDK's service client's calls
|
||||
// can be stubbed out for unit testing your code with the SDK without needing
|
||||
// to inject custom request handlers into the the SDK's request pipeline.
|
||||
//
|
||||
// // myFunc uses an SDK service client to make a request to
|
||||
// // Amazon DynamoDB.
|
||||
// func myFunc(svc dynamodbiface.DynamoDBAPI) bool {
|
||||
// // Make svc.BatchGetItem request
|
||||
// }
|
||||
//
|
||||
// func main() {
|
||||
// sess := session.New()
|
||||
// svc := dynamodb.New(sess)
|
||||
//
|
||||
// myFunc(svc)
|
||||
// }
|
||||
//
|
||||
// In your _test.go file:
|
||||
//
|
||||
// // Define a mock struct to be used in your unit tests of myFunc.
|
||||
// type mockDynamoDBClient struct {
|
||||
// dynamodbiface.DynamoDBAPI
|
||||
// }
|
||||
// func (m *mockDynamoDBClient) BatchGetItem(input *dynamodb.BatchGetItemInput) (*dynamodb.BatchGetItemOutput, error) {
|
||||
// // mock response/functionality
|
||||
// }
|
||||
//
|
||||
// func TestMyFunc(t *testing.T) {
|
||||
// // Setup Test
|
||||
// mockSvc := &mockDynamoDBClient{}
|
||||
//
|
||||
// myfunc(mockSvc)
|
||||
//
|
||||
// // Verify myFunc's functionality
|
||||
// }
|
||||
//
|
||||
// It is important to note that this interface will have breaking changes
|
||||
// when the service model is updated and adds new API operations, paginators,
|
||||
// and waiters. Its suggested to use the pattern above for testing, or using
|
||||
// tooling to generate mocks to satisfy the interfaces.
|
||||
type DynamoDBAPI interface {
|
||||
BatchGetItem(*dynamodb.BatchGetItemInput) (*dynamodb.BatchGetItemOutput, error)
|
||||
BatchGetItemWithContext(aws.Context, *dynamodb.BatchGetItemInput, ...request.Option) (*dynamodb.BatchGetItemOutput, error)
|
||||
BatchGetItemRequest(*dynamodb.BatchGetItemInput) (*request.Request, *dynamodb.BatchGetItemOutput)
|
||||
|
||||
BatchGetItemPages(*dynamodb.BatchGetItemInput, func(*dynamodb.BatchGetItemOutput, bool) bool) error
|
||||
BatchGetItemPagesWithContext(aws.Context, *dynamodb.BatchGetItemInput, func(*dynamodb.BatchGetItemOutput, bool) bool, ...request.Option) error
|
||||
|
||||
BatchWriteItem(*dynamodb.BatchWriteItemInput) (*dynamodb.BatchWriteItemOutput, error)
|
||||
BatchWriteItemWithContext(aws.Context, *dynamodb.BatchWriteItemInput, ...request.Option) (*dynamodb.BatchWriteItemOutput, error)
|
||||
BatchWriteItemRequest(*dynamodb.BatchWriteItemInput) (*request.Request, *dynamodb.BatchWriteItemOutput)
|
||||
|
||||
CreateTable(*dynamodb.CreateTableInput) (*dynamodb.CreateTableOutput, error)
|
||||
CreateTableWithContext(aws.Context, *dynamodb.CreateTableInput, ...request.Option) (*dynamodb.CreateTableOutput, error)
|
||||
CreateTableRequest(*dynamodb.CreateTableInput) (*request.Request, *dynamodb.CreateTableOutput)
|
||||
|
||||
DeleteItem(*dynamodb.DeleteItemInput) (*dynamodb.DeleteItemOutput, error)
|
||||
DeleteItemWithContext(aws.Context, *dynamodb.DeleteItemInput, ...request.Option) (*dynamodb.DeleteItemOutput, error)
|
||||
DeleteItemRequest(*dynamodb.DeleteItemInput) (*request.Request, *dynamodb.DeleteItemOutput)
|
||||
|
||||
DeleteTable(*dynamodb.DeleteTableInput) (*dynamodb.DeleteTableOutput, error)
|
||||
DeleteTableWithContext(aws.Context, *dynamodb.DeleteTableInput, ...request.Option) (*dynamodb.DeleteTableOutput, error)
|
||||
DeleteTableRequest(*dynamodb.DeleteTableInput) (*request.Request, *dynamodb.DeleteTableOutput)
|
||||
|
||||
DescribeLimits(*dynamodb.DescribeLimitsInput) (*dynamodb.DescribeLimitsOutput, error)
|
||||
DescribeLimitsWithContext(aws.Context, *dynamodb.DescribeLimitsInput, ...request.Option) (*dynamodb.DescribeLimitsOutput, error)
|
||||
DescribeLimitsRequest(*dynamodb.DescribeLimitsInput) (*request.Request, *dynamodb.DescribeLimitsOutput)
|
||||
|
||||
DescribeTable(*dynamodb.DescribeTableInput) (*dynamodb.DescribeTableOutput, error)
|
||||
DescribeTableWithContext(aws.Context, *dynamodb.DescribeTableInput, ...request.Option) (*dynamodb.DescribeTableOutput, error)
|
||||
DescribeTableRequest(*dynamodb.DescribeTableInput) (*request.Request, *dynamodb.DescribeTableOutput)
|
||||
|
||||
DescribeTimeToLive(*dynamodb.DescribeTimeToLiveInput) (*dynamodb.DescribeTimeToLiveOutput, error)
|
||||
DescribeTimeToLiveWithContext(aws.Context, *dynamodb.DescribeTimeToLiveInput, ...request.Option) (*dynamodb.DescribeTimeToLiveOutput, error)
|
||||
DescribeTimeToLiveRequest(*dynamodb.DescribeTimeToLiveInput) (*request.Request, *dynamodb.DescribeTimeToLiveOutput)
|
||||
|
||||
GetItem(*dynamodb.GetItemInput) (*dynamodb.GetItemOutput, error)
|
||||
GetItemWithContext(aws.Context, *dynamodb.GetItemInput, ...request.Option) (*dynamodb.GetItemOutput, error)
|
||||
GetItemRequest(*dynamodb.GetItemInput) (*request.Request, *dynamodb.GetItemOutput)
|
||||
|
||||
ListTables(*dynamodb.ListTablesInput) (*dynamodb.ListTablesOutput, error)
|
||||
ListTablesWithContext(aws.Context, *dynamodb.ListTablesInput, ...request.Option) (*dynamodb.ListTablesOutput, error)
|
||||
ListTablesRequest(*dynamodb.ListTablesInput) (*request.Request, *dynamodb.ListTablesOutput)
|
||||
|
||||
ListTablesPages(*dynamodb.ListTablesInput, func(*dynamodb.ListTablesOutput, bool) bool) error
|
||||
ListTablesPagesWithContext(aws.Context, *dynamodb.ListTablesInput, func(*dynamodb.ListTablesOutput, bool) bool, ...request.Option) error
|
||||
|
||||
ListTagsOfResource(*dynamodb.ListTagsOfResourceInput) (*dynamodb.ListTagsOfResourceOutput, error)
|
||||
ListTagsOfResourceWithContext(aws.Context, *dynamodb.ListTagsOfResourceInput, ...request.Option) (*dynamodb.ListTagsOfResourceOutput, error)
|
||||
ListTagsOfResourceRequest(*dynamodb.ListTagsOfResourceInput) (*request.Request, *dynamodb.ListTagsOfResourceOutput)
|
||||
|
||||
PutItem(*dynamodb.PutItemInput) (*dynamodb.PutItemOutput, error)
|
||||
PutItemWithContext(aws.Context, *dynamodb.PutItemInput, ...request.Option) (*dynamodb.PutItemOutput, error)
|
||||
PutItemRequest(*dynamodb.PutItemInput) (*request.Request, *dynamodb.PutItemOutput)
|
||||
|
||||
Query(*dynamodb.QueryInput) (*dynamodb.QueryOutput, error)
|
||||
QueryWithContext(aws.Context, *dynamodb.QueryInput, ...request.Option) (*dynamodb.QueryOutput, error)
|
||||
QueryRequest(*dynamodb.QueryInput) (*request.Request, *dynamodb.QueryOutput)
|
||||
|
||||
QueryPages(*dynamodb.QueryInput, func(*dynamodb.QueryOutput, bool) bool) error
|
||||
QueryPagesWithContext(aws.Context, *dynamodb.QueryInput, func(*dynamodb.QueryOutput, bool) bool, ...request.Option) error
|
||||
|
||||
Scan(*dynamodb.ScanInput) (*dynamodb.ScanOutput, error)
|
||||
ScanWithContext(aws.Context, *dynamodb.ScanInput, ...request.Option) (*dynamodb.ScanOutput, error)
|
||||
ScanRequest(*dynamodb.ScanInput) (*request.Request, *dynamodb.ScanOutput)
|
||||
|
||||
ScanPages(*dynamodb.ScanInput, func(*dynamodb.ScanOutput, bool) bool) error
|
||||
ScanPagesWithContext(aws.Context, *dynamodb.ScanInput, func(*dynamodb.ScanOutput, bool) bool, ...request.Option) error
|
||||
|
||||
TagResource(*dynamodb.TagResourceInput) (*dynamodb.TagResourceOutput, error)
|
||||
TagResourceWithContext(aws.Context, *dynamodb.TagResourceInput, ...request.Option) (*dynamodb.TagResourceOutput, error)
|
||||
TagResourceRequest(*dynamodb.TagResourceInput) (*request.Request, *dynamodb.TagResourceOutput)
|
||||
|
||||
UntagResource(*dynamodb.UntagResourceInput) (*dynamodb.UntagResourceOutput, error)
|
||||
UntagResourceWithContext(aws.Context, *dynamodb.UntagResourceInput, ...request.Option) (*dynamodb.UntagResourceOutput, error)
|
||||
UntagResourceRequest(*dynamodb.UntagResourceInput) (*request.Request, *dynamodb.UntagResourceOutput)
|
||||
|
||||
UpdateItem(*dynamodb.UpdateItemInput) (*dynamodb.UpdateItemOutput, error)
|
||||
UpdateItemWithContext(aws.Context, *dynamodb.UpdateItemInput, ...request.Option) (*dynamodb.UpdateItemOutput, error)
|
||||
UpdateItemRequest(*dynamodb.UpdateItemInput) (*request.Request, *dynamodb.UpdateItemOutput)
|
||||
|
||||
UpdateTable(*dynamodb.UpdateTableInput) (*dynamodb.UpdateTableOutput, error)
|
||||
UpdateTableWithContext(aws.Context, *dynamodb.UpdateTableInput, ...request.Option) (*dynamodb.UpdateTableOutput, error)
|
||||
UpdateTableRequest(*dynamodb.UpdateTableInput) (*request.Request, *dynamodb.UpdateTableOutput)
|
||||
|
||||
UpdateTimeToLive(*dynamodb.UpdateTimeToLiveInput) (*dynamodb.UpdateTimeToLiveOutput, error)
|
||||
UpdateTimeToLiveWithContext(aws.Context, *dynamodb.UpdateTimeToLiveInput, ...request.Option) (*dynamodb.UpdateTimeToLiveOutput, error)
|
||||
UpdateTimeToLiveRequest(*dynamodb.UpdateTimeToLiveInput) (*request.Request, *dynamodb.UpdateTimeToLiveOutput)
|
||||
|
||||
WaitUntilTableExists(*dynamodb.DescribeTableInput) error
|
||||
WaitUntilTableExistsWithContext(aws.Context, *dynamodb.DescribeTableInput, ...request.WaiterOption) error
|
||||
|
||||
WaitUntilTableNotExists(*dynamodb.DescribeTableInput) error
|
||||
WaitUntilTableNotExistsWithContext(aws.Context, *dynamodb.DescribeTableInput, ...request.WaiterOption) error
|
||||
}
|
||||
|
||||
var _ DynamoDBAPI = (*dynamodb.DynamoDB)(nil)
|
64
vendor/github.com/aws/aws-sdk-go/service/dynamodb/errors.go
generated
vendored
Normal file
64
vendor/github.com/aws/aws-sdk-go/service/dynamodb/errors.go
generated
vendored
Normal file
|
@ -0,0 +1,64 @@
|
|||
// Code generated by private/model/cli/gen-api/main.go. DO NOT EDIT.
|
||||
|
||||
package dynamodb
|
||||
|
||||
const (
|
||||
|
||||
// ErrCodeConditionalCheckFailedException for service response error code
|
||||
// "ConditionalCheckFailedException".
|
||||
//
|
||||
// A condition specified in the operation could not be evaluated.
|
||||
ErrCodeConditionalCheckFailedException = "ConditionalCheckFailedException"
|
||||
|
||||
// ErrCodeInternalServerError for service response error code
|
||||
// "InternalServerError".
|
||||
//
|
||||
// An error occurred on the server side.
|
||||
ErrCodeInternalServerError = "InternalServerError"
|
||||
|
||||
// ErrCodeItemCollectionSizeLimitExceededException for service response error code
|
||||
// "ItemCollectionSizeLimitExceededException".
|
||||
//
|
||||
// An item collection is too large. This exception is only returned for tables
|
||||
// that have one or more local secondary indexes.
|
||||
ErrCodeItemCollectionSizeLimitExceededException = "ItemCollectionSizeLimitExceededException"
|
||||
|
||||
// ErrCodeLimitExceededException for service response error code
|
||||
// "LimitExceededException".
|
||||
//
|
||||
// The number of concurrent table requests (cumulative number of tables in the
|
||||
// CREATING, DELETING or UPDATING state) exceeds the maximum allowed of 10.
|
||||
//
|
||||
// Also, for tables with secondary indexes, only one of those tables can be
|
||||
// in the CREATING state at any point in time. Do not attempt to create more
|
||||
// than one such table simultaneously.
|
||||
//
|
||||
// The total limit of tables in the ACTIVE state is 250.
|
||||
ErrCodeLimitExceededException = "LimitExceededException"
|
||||
|
||||
// ErrCodeProvisionedThroughputExceededException for service response error code
|
||||
// "ProvisionedThroughputExceededException".
|
||||
//
|
||||
// Your request rate is too high. The AWS SDKs for DynamoDB automatically retry
|
||||
// requests that receive this exception. Your request is eventually successful,
|
||||
// unless your retry queue is too large to finish. Reduce the frequency of requests
|
||||
// and use exponential backoff. For more information, go to Error Retries and
|
||||
// Exponential Backoff (http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Programming.Errors.html#Programming.Errors.RetryAndBackoff)
|
||||
// in the Amazon DynamoDB Developer Guide.
|
||||
ErrCodeProvisionedThroughputExceededException = "ProvisionedThroughputExceededException"
|
||||
|
||||
// ErrCodeResourceInUseException for service response error code
|
||||
// "ResourceInUseException".
|
||||
//
|
||||
// The operation conflicts with the resource's availability. For example, you
|
||||
// attempted to recreate an existing table, or tried to delete a table currently
|
||||
// in the CREATING state.
|
||||
ErrCodeResourceInUseException = "ResourceInUseException"
|
||||
|
||||
// ErrCodeResourceNotFoundException for service response error code
|
||||
// "ResourceNotFoundException".
|
||||
//
|
||||
// The operation tried to access a nonexistent table or index. The resource
|
||||
// might not be specified correctly, or its status might not be ACTIVE.
|
||||
ErrCodeResourceNotFoundException = "ResourceNotFoundException"
|
||||
)
|
1502
vendor/github.com/aws/aws-sdk-go/service/dynamodb/examples_test.go
generated
vendored
Normal file
1502
vendor/github.com/aws/aws-sdk-go/service/dynamodb/examples_test.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
95
vendor/github.com/aws/aws-sdk-go/service/dynamodb/service.go
generated
vendored
Normal file
95
vendor/github.com/aws/aws-sdk-go/service/dynamodb/service.go
generated
vendored
Normal file
|
@ -0,0 +1,95 @@
|
|||
// Code generated by private/model/cli/gen-api/main.go. DO NOT EDIT.
|
||||
|
||||
package dynamodb
|
||||
|
||||
import (
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/client"
|
||||
"github.com/aws/aws-sdk-go/aws/client/metadata"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
"github.com/aws/aws-sdk-go/aws/signer/v4"
|
||||
"github.com/aws/aws-sdk-go/private/protocol/jsonrpc"
|
||||
)
|
||||
|
||||
// DynamoDB provides the API operation methods for making requests to
|
||||
// Amazon DynamoDB. See this package's package overview docs
|
||||
// for details on the service.
|
||||
//
|
||||
// DynamoDB methods are safe to use concurrently. It is not safe to
|
||||
// modify mutate any of the struct's properties though.
|
||||
type DynamoDB struct {
|
||||
*client.Client
|
||||
}
|
||||
|
||||
// Used for custom client initialization logic
|
||||
var initClient func(*client.Client)
|
||||
|
||||
// Used for custom request initialization logic
|
||||
var initRequest func(*request.Request)
|
||||
|
||||
// Service information constants
|
||||
const (
|
||||
ServiceName = "dynamodb" // Service endpoint prefix API calls made to.
|
||||
EndpointsID = ServiceName // Service ID for Regions and Endpoints metadata.
|
||||
)
|
||||
|
||||
// New creates a new instance of the DynamoDB client with a session.
|
||||
// If additional configuration is needed for the client instance use the optional
|
||||
// aws.Config parameter to add your extra config.
|
||||
//
|
||||
// Example:
|
||||
// // Create a DynamoDB client from just a session.
|
||||
// svc := dynamodb.New(mySession)
|
||||
//
|
||||
// // Create a DynamoDB client with additional configuration
|
||||
// svc := dynamodb.New(mySession, aws.NewConfig().WithRegion("us-west-2"))
|
||||
func New(p client.ConfigProvider, cfgs ...*aws.Config) *DynamoDB {
|
||||
c := p.ClientConfig(EndpointsID, cfgs...)
|
||||
return newClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion, c.SigningName)
|
||||
}
|
||||
|
||||
// newClient creates, initializes and returns a new service client instance.
|
||||
func newClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion, signingName string) *DynamoDB {
|
||||
svc := &DynamoDB{
|
||||
Client: client.New(
|
||||
cfg,
|
||||
metadata.ClientInfo{
|
||||
ServiceName: ServiceName,
|
||||
SigningName: signingName,
|
||||
SigningRegion: signingRegion,
|
||||
Endpoint: endpoint,
|
||||
APIVersion: "2012-08-10",
|
||||
JSONVersion: "1.0",
|
||||
TargetPrefix: "DynamoDB_20120810",
|
||||
},
|
||||
handlers,
|
||||
),
|
||||
}
|
||||
|
||||
// Handlers
|
||||
svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler)
|
||||
svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler)
|
||||
svc.Handlers.Unmarshal.PushBackNamed(jsonrpc.UnmarshalHandler)
|
||||
svc.Handlers.UnmarshalMeta.PushBackNamed(jsonrpc.UnmarshalMetaHandler)
|
||||
svc.Handlers.UnmarshalError.PushBackNamed(jsonrpc.UnmarshalErrorHandler)
|
||||
|
||||
// Run custom client initialization if present
|
||||
if initClient != nil {
|
||||
initClient(svc.Client)
|
||||
}
|
||||
|
||||
return svc
|
||||
}
|
||||
|
||||
// newRequest creates a new request for a DynamoDB operation and runs any
|
||||
// custom request initialization.
|
||||
func (c *DynamoDB) newRequest(op *request.Operation, params, data interface{}) *request.Request {
|
||||
req := c.NewRequest(op, params, data)
|
||||
|
||||
// Run custom request initialization if present
|
||||
if initRequest != nil {
|
||||
initRequest(req)
|
||||
}
|
||||
|
||||
return req
|
||||
}
|
107
vendor/github.com/aws/aws-sdk-go/service/dynamodb/waiters.go
generated
vendored
Normal file
107
vendor/github.com/aws/aws-sdk-go/service/dynamodb/waiters.go
generated
vendored
Normal file
|
@ -0,0 +1,107 @@
|
|||
// Code generated by private/model/cli/gen-api/main.go. DO NOT EDIT.
|
||||
|
||||
package dynamodb
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
)
|
||||
|
||||
// WaitUntilTableExists uses the DynamoDB API operation
|
||||
// DescribeTable to wait for a condition to be met before returning.
|
||||
// If the condition is not meet within the max attempt window an error will
|
||||
// be returned.
|
||||
func (c *DynamoDB) WaitUntilTableExists(input *DescribeTableInput) error {
|
||||
return c.WaitUntilTableExistsWithContext(aws.BackgroundContext(), input)
|
||||
}
|
||||
|
||||
// WaitUntilTableExistsWithContext is an extended version of WaitUntilTableExists.
|
||||
// With the support for passing in a context and options to configure the
|
||||
// Waiter and the underlying request options.
|
||||
//
|
||||
// The context must be non-nil and will be used for request cancellation. If
|
||||
// the context is nil a panic will occur. In the future the SDK may create
|
||||
// sub-contexts for http.Requests. See https://golang.org/pkg/context/
|
||||
// for more information on using Contexts.
|
||||
func (c *DynamoDB) WaitUntilTableExistsWithContext(ctx aws.Context, input *DescribeTableInput, opts ...request.WaiterOption) error {
|
||||
w := request.Waiter{
|
||||
Name: "WaitUntilTableExists",
|
||||
MaxAttempts: 25,
|
||||
Delay: request.ConstantWaiterDelay(20 * time.Second),
|
||||
Acceptors: []request.WaiterAcceptor{
|
||||
{
|
||||
State: request.SuccessWaiterState,
|
||||
Matcher: request.PathWaiterMatch, Argument: "Table.TableStatus",
|
||||
Expected: "ACTIVE",
|
||||
},
|
||||
{
|
||||
State: request.RetryWaiterState,
|
||||
Matcher: request.ErrorWaiterMatch,
|
||||
Expected: "ResourceNotFoundException",
|
||||
},
|
||||
},
|
||||
Logger: c.Config.Logger,
|
||||
NewRequest: func(opts []request.Option) (*request.Request, error) {
|
||||
var inCpy *DescribeTableInput
|
||||
if input != nil {
|
||||
tmp := *input
|
||||
inCpy = &tmp
|
||||
}
|
||||
req, _ := c.DescribeTableRequest(inCpy)
|
||||
req.SetContext(ctx)
|
||||
req.ApplyOptions(opts...)
|
||||
return req, nil
|
||||
},
|
||||
}
|
||||
w.ApplyOptions(opts...)
|
||||
|
||||
return w.WaitWithContext(ctx)
|
||||
}
|
||||
|
||||
// WaitUntilTableNotExists uses the DynamoDB API operation
|
||||
// DescribeTable to wait for a condition to be met before returning.
|
||||
// If the condition is not meet within the max attempt window an error will
|
||||
// be returned.
|
||||
func (c *DynamoDB) WaitUntilTableNotExists(input *DescribeTableInput) error {
|
||||
return c.WaitUntilTableNotExistsWithContext(aws.BackgroundContext(), input)
|
||||
}
|
||||
|
||||
// WaitUntilTableNotExistsWithContext is an extended version of WaitUntilTableNotExists.
|
||||
// With the support for passing in a context and options to configure the
|
||||
// Waiter and the underlying request options.
|
||||
//
|
||||
// The context must be non-nil and will be used for request cancellation. If
|
||||
// the context is nil a panic will occur. In the future the SDK may create
|
||||
// sub-contexts for http.Requests. See https://golang.org/pkg/context/
|
||||
// for more information on using Contexts.
|
||||
func (c *DynamoDB) WaitUntilTableNotExistsWithContext(ctx aws.Context, input *DescribeTableInput, opts ...request.WaiterOption) error {
|
||||
w := request.Waiter{
|
||||
Name: "WaitUntilTableNotExists",
|
||||
MaxAttempts: 25,
|
||||
Delay: request.ConstantWaiterDelay(20 * time.Second),
|
||||
Acceptors: []request.WaiterAcceptor{
|
||||
{
|
||||
State: request.SuccessWaiterState,
|
||||
Matcher: request.ErrorWaiterMatch,
|
||||
Expected: "ResourceNotFoundException",
|
||||
},
|
||||
},
|
||||
Logger: c.Config.Logger,
|
||||
NewRequest: func(opts []request.Option) (*request.Request, error) {
|
||||
var inCpy *DescribeTableInput
|
||||
if input != nil {
|
||||
tmp := *input
|
||||
inCpy = &tmp
|
||||
}
|
||||
req, _ := c.DescribeTableRequest(inCpy)
|
||||
req.SetContext(ctx)
|
||||
req.ApplyOptions(opts...)
|
||||
return req, nil
|
||||
},
|
||||
}
|
||||
w.ApplyOptions(opts...)
|
||||
|
||||
return w.WaitWithContext(ctx)
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue