Vendor aws-sdk-go (dep ensure) (#178)
This commit is contained in:
12220
vendor/github.com/aws/aws-sdk-go/service/dynamodb/api.go
generated
vendored
Normal file
12220
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)
|
||||
}
|
||||
}
|
||||
45
vendor/github.com/aws/aws-sdk-go/service/dynamodb/doc.go
generated
vendored
Normal file
45
vendor/github.com/aws/aws-sdk-go/service/dynamodb/doc.go
generated
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
// 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 contact Amazon DynamoDB with the SDK use the New function to create
|
||||
// a new service client. With that client you can make API requests to the service.
|
||||
// These clients are safe to use concurrently.
|
||||
//
|
||||
// See the SDK's documentation for more information on how to use the SDK.
|
||||
// https://docs.aws.amazon.com/sdk-for-go/api/
|
||||
//
|
||||
// See aws.Config documentation for more information on configuring SDK clients.
|
||||
// https://docs.aws.amazon.com/sdk-for-go/api/aws/#Config
|
||||
//
|
||||
// See the Amazon DynamoDB client DynamoDB for more
|
||||
// information on creating client for this service.
|
||||
// https://docs.aws.amazon.com/sdk-for-go/api/service/dynamodb/#New
|
||||
package dynamodb
|
||||
27
vendor/github.com/aws/aws-sdk-go/service/dynamodb/doc_custom.go
generated
vendored
Normal file
27
vendor/github.com/aws/aws-sdk-go/service/dynamodb/doc_custom.go
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
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/
|
||||
|
||||
Expression Builders
|
||||
|
||||
The expression package provides utility types and functions to build DynamoDB
|
||||
expression for type safe construction of API ExpressionAttributeNames, and
|
||||
ExpressionAttribute Values.
|
||||
|
||||
The package represents the various DynamoDB Expressions as structs named
|
||||
accordingly. For example, ConditionBuilder represents a DynamoDB Condition
|
||||
Expression, an UpdateBuilder represents a DynamoDB Update Expression, and so on.
|
||||
|
||||
See the expression package documentation for more information.
|
||||
https://docs.aws.amazon.com/sdk-for-go/api/service/dynamodb/expression/
|
||||
*/
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
761
vendor/github.com/aws/aws-sdk-go/service/dynamodb/dynamodbattribute/decode.go
generated
vendored
Normal file
761
vendor/github.com/aws/aws-sdk-go/service/dynamodb/dynamodbattribute/decode.go
generated
vendored
Normal file
@@ -0,0 +1,761 @@
|
||||
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
|
||||
// }
|
||||
//
|
||||
// func (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(""))
|
||||
var timeType = reflect.TypeOf(time.Time{})
|
||||
|
||||
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 && v.Kind() != reflect.Array {
|
||||
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.Kind() != reflect.Array && (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 {
|
||||
switch v.Type().Elem().Kind() {
|
||||
case reflect.Uint8:
|
||||
reflect.Copy(v, reflect.ValueOf(b))
|
||||
default:
|
||||
return &UnmarshalTypeError{Value: "binary", Type: v.Type()}
|
||||
}
|
||||
|
||||
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 {
|
||||
isArray := false
|
||||
|
||||
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.
|
||||
isArray = true
|
||||
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++ {
|
||||
if !isArray {
|
||||
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 v.Type().ConvertibleTo(timeType) && fieldTag.AsUnixTime {
|
||||
t, err := decodeUnixTime(*n)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
v.Set(reflect.ValueOf(t).Convert(v.Type()))
|
||||
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 {
|
||||
isArray := false
|
||||
|
||||
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.
|
||||
isArray = true
|
||||
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++ {
|
||||
if !isArray {
|
||||
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 {
|
||||
isArray := false
|
||||
|
||||
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.
|
||||
isArray = true
|
||||
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++ {
|
||||
if !isArray {
|
||||
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 v.Type().ConvertibleTo(timeType) {
|
||||
t, err := time.Parse(time.RFC3339, *s)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
v.Set(reflect.ValueOf(t).Convert(v.Type()))
|
||||
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 {
|
||||
isArray := false
|
||||
|
||||
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.
|
||||
isArray = true
|
||||
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++ {
|
||||
if !isArray {
|
||||
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: timeType,
|
||||
}
|
||||
}
|
||||
|
||||
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())
|
||||
}
|
||||
598
vendor/github.com/aws/aws-sdk-go/service/dynamodb/dynamodbattribute/decode_test.go
generated
vendored
Normal file
598
vendor/github.com/aws/aws-sdk-go/service/dynamodb/dynamodbattribute/decode_test.go
generated
vendored
Normal file
@@ -0,0 +1,598 @@
|
||||
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"
|
||||
)
|
||||
|
||||
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)
|
||||
if err != nil {
|
||||
t.Errorf("expect no error, got %v", err)
|
||||
}
|
||||
|
||||
if e, a := "value", u.Value; e != a {
|
||||
t.Errorf("expect %v, got %v", e, a)
|
||||
}
|
||||
if e, a := 123, u.Value2; e != a {
|
||||
t.Errorf("expect %v, got %v", e, a)
|
||||
}
|
||||
if e, a := true, u.Value3; e != a {
|
||||
t.Errorf("expect %v, got %v", e, a)
|
||||
}
|
||||
if e, a := testDate, u.Value4; e != a {
|
||||
t.Errorf("expect %v, got %v", e, a)
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
if err != nil {
|
||||
t.Errorf("expect no error, got %v", err)
|
||||
}
|
||||
|
||||
if e, a := "value", u["abc"]; e != a {
|
||||
t.Errorf("expect %v, got %v", e, a)
|
||||
}
|
||||
n := u["def"].(Number)
|
||||
if e, a := "123", n.String(); e != a {
|
||||
t.Errorf("expect %v, got %v", e, a)
|
||||
}
|
||||
if e, a := true, u["ghi"]; e != a {
|
||||
t.Errorf("expect %v, got %v", e, a)
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
if err != nil {
|
||||
t.Errorf("expect no error, got %v", err)
|
||||
}
|
||||
|
||||
ns := u["ns"].([]Number)
|
||||
|
||||
if e, a := "123", ns[0].String(); e != a {
|
||||
t.Errorf("expect %v, got %v", e, a)
|
||||
}
|
||||
if e, a := "321", ns[1].String(); e != a {
|
||||
t.Errorf("expect %v, got %v", e, a)
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
if err != nil {
|
||||
t.Errorf("expect no error, got %v", err)
|
||||
}
|
||||
if e, a := 321, a.Aint; e != a {
|
||||
t.Errorf("expect %v, got %v", e, a)
|
||||
}
|
||||
// Embedded pointer struct can be created automatically.
|
||||
if e, a := 123, a.Bint; e != a {
|
||||
t.Errorf("expect %v, got %v", e, a)
|
||||
}
|
||||
// But not for absent fields.
|
||||
if a.C != nil {
|
||||
t.Errorf("expect nil, got %v", 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)
|
||||
if err != nil {
|
||||
t.Errorf("expect no error, got %v", err)
|
||||
}
|
||||
if e, a := BooleanOverlay(true), v; e != a {
|
||||
t.Errorf("expect %v, got %v", e, a)
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
if err != nil {
|
||||
t.Errorf("expect no error, got %v", err)
|
||||
}
|
||||
if e, a := expect, actual; e != a {
|
||||
t.Errorf("expect %v, got %v", e, a)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDecodeAliasedUnixTime(t *testing.T) {
|
||||
type A struct {
|
||||
Normal AliasedTime
|
||||
Tagged AliasedTime `dynamodbav:",unixtime"`
|
||||
}
|
||||
|
||||
expect := A{
|
||||
Normal: AliasedTime(time.Unix(123, 0).UTC()),
|
||||
Tagged: AliasedTime(time.Unix(456, 0)),
|
||||
}
|
||||
|
||||
input := &dynamodb.AttributeValue{
|
||||
M: map[string]*dynamodb.AttributeValue{
|
||||
"Normal": {
|
||||
S: aws.String("1970-01-01T00:02:03Z"),
|
||||
},
|
||||
"Tagged": {
|
||||
N: aws.String("456"),
|
||||
},
|
||||
},
|
||||
}
|
||||
actual := A{}
|
||||
|
||||
err := Unmarshal(input, &actual)
|
||||
if err != nil {
|
||||
t.Errorf("expect no error, got %v", err)
|
||||
}
|
||||
if expect != actual {
|
||||
t.Errorf("expect %v, got %v", 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 = 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
|
||||
641
vendor/github.com/aws/aws-sdk-go/service/dynamodb/dynamodbattribute/encode.go
generated
vendored
Normal file
641
vendor/github.com/aws/aws-sdk-go/service/dynamodb/dynamodbattribute/encode.go
generated
vendored
Normal file
@@ -0,0 +1,641 @@
|
||||
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 alternative 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 v.Type().ConvertibleTo(timeType) {
|
||||
var t time.Time
|
||||
t = v.Convert(timeType).Interface().(time.Time)
|
||||
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:
|
||||
slice := reflect.MakeSlice(byteSliceType, v.Len(), v.Len())
|
||||
reflect.Copy(slice, v)
|
||||
|
||||
b := slice.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"
|
||||
}
|
||||
271
vendor/github.com/aws/aws-sdk-go/service/dynamodb/dynamodbattribute/encode_test.go
generated
vendored
Normal file
271
vendor/github.com/aws/aws-sdk-go/service/dynamodb/dynamodbattribute/encode_test.go
generated
vendored
Normal file
@@ -0,0 +1,271 @@
|
||||
package dynamodbattribute
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"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"
|
||||
)
|
||||
|
||||
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)
|
||||
if err != nil {
|
||||
t.Errorf("expect nil, got %v", err)
|
||||
}
|
||||
|
||||
if e, a := expect, actual; !reflect.DeepEqual(e, a) {
|
||||
t.Errorf("expect %v, got %v", e, a)
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
if err != nil {
|
||||
t.Errorf("expect nil, got %v", err)
|
||||
}
|
||||
if e, a := expect, actual; !reflect.DeepEqual(e, a) {
|
||||
t.Errorf("expect %v, got %v", e, a)
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
if err != nil {
|
||||
t.Errorf("expect nil, got %v", err)
|
||||
}
|
||||
if e, a := expect, actual; !reflect.DeepEqual(e, a) {
|
||||
t.Errorf("expect %v, got %v", e, a)
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
if err != nil {
|
||||
t.Errorf("expect nil, got %v", err)
|
||||
}
|
||||
if e, a := expect, actual; !reflect.DeepEqual(e, a) {
|
||||
t.Errorf("expect %v, got %v", e, a)
|
||||
}
|
||||
}
|
||||
|
||||
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}}
|
||||
if e, a := 321, a.Aint; e != a {
|
||||
t.Errorf("expect %v, got %v", e, a)
|
||||
}
|
||||
if e, a := 123, a.Bint; e != a {
|
||||
t.Errorf("expect %v, got %v", e, a)
|
||||
}
|
||||
if a.C != nil {
|
||||
t.Errorf("expect nil, got %v", a.C)
|
||||
}
|
||||
|
||||
actual, err := Marshal(a)
|
||||
if err != nil {
|
||||
t.Errorf("expect nil, got %v", err)
|
||||
}
|
||||
expect := &dynamodb.AttributeValue{
|
||||
M: map[string]*dynamodb.AttributeValue{
|
||||
"Aint": {
|
||||
N: aws.String("321"),
|
||||
},
|
||||
"Bint": {
|
||||
N: aws.String("123"),
|
||||
},
|
||||
},
|
||||
}
|
||||
if e, a := expect, actual; !reflect.DeepEqual(e, a) {
|
||||
t.Errorf("expect %v, got %v", e, a)
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
if err != nil {
|
||||
t.Errorf("expect nil, got %v", 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"),
|
||||
},
|
||||
},
|
||||
}
|
||||
if e, a := expect, actual; !reflect.DeepEqual(e, a) {
|
||||
t.Errorf("expect %v, got %v", e, a)
|
||||
}
|
||||
}
|
||||
|
||||
type AliasedTime time.Time
|
||||
|
||||
func TestEncodeAliasedUnixTime(t *testing.T) {
|
||||
type A struct {
|
||||
Normal AliasedTime
|
||||
Tagged AliasedTime `dynamodbav:",unixtime"`
|
||||
}
|
||||
|
||||
a := A{
|
||||
Normal: AliasedTime(time.Unix(123, 0).UTC()),
|
||||
Tagged: AliasedTime(time.Unix(456, 0)),
|
||||
}
|
||||
|
||||
actual, err := Marshal(a)
|
||||
if err != nil {
|
||||
t.Errorf("expect no err, got %v", err)
|
||||
}
|
||||
expect := &dynamodb.AttributeValue{
|
||||
M: map[string]*dynamodb.AttributeValue{
|
||||
"Normal": {
|
||||
S: aws.String("1970-01-01T00:02:03Z"),
|
||||
},
|
||||
"Tagged": {
|
||||
N: aws.String("456"),
|
||||
},
|
||||
},
|
||||
}
|
||||
if e, a := expect, actual; !reflect.DeepEqual(e, a) {
|
||||
t.Errorf("expect %v, got %v", e, a)
|
||||
}
|
||||
}
|
||||
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)
|
||||
}
|
||||
116
vendor/github.com/aws/aws-sdk-go/service/dynamodb/dynamodbattribute/field_test.go
generated
vendored
Normal file
116
vendor/github.com/aws/aws-sdk-go/service/dynamodb/dynamodbattribute/field_test.go
generated
vendored
Normal file
@@ -0,0 +1,116 @@
|
||||
package dynamodbattribute
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
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]
|
||||
if e, a := expected.Name, f.Name; e != a {
|
||||
t.Errorf("%d:%d expect %v, got %v", i, j, e, f)
|
||||
}
|
||||
actual := v.FieldByIndex(f.Index).Interface()
|
||||
if e, a := expected.Value, actual; !reflect.DeepEqual(e, a) {
|
||||
t.Errorf("%d:%d expect %v, got %v", i, j, e, f)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
if e, a := c.Found, ok; e != a {
|
||||
t.Errorf("expect %v, got %v", e, a)
|
||||
}
|
||||
if ok {
|
||||
if e, a := c.FieldName, f.Name; e != a {
|
||||
t.Errorf("expect %v, got %v", e, a)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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
|
||||
}
|
||||
573
vendor/github.com/aws/aws-sdk-go/service/dynamodb/dynamodbattribute/marshaler_test.go
generated
vendored
Normal file
573
vendor/github.com/aws/aws-sdk-go/service/dynamodb/dynamodbattribute/marshaler_test.go
generated
vendored
Normal file
@@ -0,0 +1,573 @@
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
// see github issue #1594
|
||||
func TestDecodeArrayType(t *testing.T) {
|
||||
cases := []struct {
|
||||
to, from interface{}
|
||||
}{
|
||||
{
|
||||
&[2]int{1, 2},
|
||||
&[2]int{},
|
||||
},
|
||||
{
|
||||
&[2]int64{1, 2},
|
||||
&[2]int64{},
|
||||
},
|
||||
{
|
||||
&[2]byte{1, 2},
|
||||
&[2]byte{},
|
||||
},
|
||||
{
|
||||
&[2]bool{true, false},
|
||||
&[2]bool{},
|
||||
},
|
||||
{
|
||||
&[2]string{"1", "2"},
|
||||
&[2]string{},
|
||||
},
|
||||
{
|
||||
&[2][]string{{"1", "2"}},
|
||||
&[2][]string{},
|
||||
},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
marshaled, err := Marshal(c.to)
|
||||
if err != nil {
|
||||
t.Errorf("expected no error, but received %v", err)
|
||||
}
|
||||
|
||||
if err = Unmarshal(marshaled, c.from); err != nil {
|
||||
t.Errorf("expected no error, but received %v", err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(c.to, c.from) {
|
||||
t.Errorf("expected %v, but received %v", c.to, c.from)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
405
vendor/github.com/aws/aws-sdk-go/service/dynamodb/dynamodbattribute/shared_test.go
generated
vendored
Normal file
405
vendor/github.com/aws/aws-sdk-go/service/dynamodb/dynamodbattribute/shared_test.go
generated
vendored
Normal file
@@ -0,0 +1,405 @@
|
||||
package dynamodbattribute
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/service/dynamodb"
|
||||
)
|
||||
|
||||
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 {
|
||||
if e, a := expectedErr, err; !reflect.DeepEqual(e, a) {
|
||||
t.Errorf("case %d expect %v, got %v", i, e, a)
|
||||
}
|
||||
} else {
|
||||
t.Fatalf("case %d, expected error, %v", i, expectedErr)
|
||||
}
|
||||
} else if err != nil {
|
||||
t.Fatalf("case %d, expect no error, got %v", i, err)
|
||||
} else {
|
||||
if e, a := ptrToValue(expected), ptrToValue(actual); !reflect.DeepEqual(e, a) {
|
||||
t.Errorf("case %d, expect %v, got %v", i, e, a)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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"
|
||||
)
|
||||
|
||||
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)
|
||||
}
|
||||
if e, a := c.expect, actual; !reflect.DeepEqual(e, a) {
|
||||
t.Errorf("case %d, expect %v, got %v", i, e, a)
|
||||
}
|
||||
}
|
||||
}
|
||||
206
vendor/github.com/aws/aws-sdk-go/service/dynamodb/dynamodbiface/interface.go
generated
vendored
Normal file
206
vendor/github.com/aws/aws-sdk-go/service/dynamodb/dynamodbiface/interface.go
generated
vendored
Normal file
@@ -0,0 +1,206 @@
|
||||
// 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 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)
|
||||
|
||||
CreateBackup(*dynamodb.CreateBackupInput) (*dynamodb.CreateBackupOutput, error)
|
||||
CreateBackupWithContext(aws.Context, *dynamodb.CreateBackupInput, ...request.Option) (*dynamodb.CreateBackupOutput, error)
|
||||
CreateBackupRequest(*dynamodb.CreateBackupInput) (*request.Request, *dynamodb.CreateBackupOutput)
|
||||
|
||||
CreateGlobalTable(*dynamodb.CreateGlobalTableInput) (*dynamodb.CreateGlobalTableOutput, error)
|
||||
CreateGlobalTableWithContext(aws.Context, *dynamodb.CreateGlobalTableInput, ...request.Option) (*dynamodb.CreateGlobalTableOutput, error)
|
||||
CreateGlobalTableRequest(*dynamodb.CreateGlobalTableInput) (*request.Request, *dynamodb.CreateGlobalTableOutput)
|
||||
|
||||
CreateTable(*dynamodb.CreateTableInput) (*dynamodb.CreateTableOutput, error)
|
||||
CreateTableWithContext(aws.Context, *dynamodb.CreateTableInput, ...request.Option) (*dynamodb.CreateTableOutput, error)
|
||||
CreateTableRequest(*dynamodb.CreateTableInput) (*request.Request, *dynamodb.CreateTableOutput)
|
||||
|
||||
DeleteBackup(*dynamodb.DeleteBackupInput) (*dynamodb.DeleteBackupOutput, error)
|
||||
DeleteBackupWithContext(aws.Context, *dynamodb.DeleteBackupInput, ...request.Option) (*dynamodb.DeleteBackupOutput, error)
|
||||
DeleteBackupRequest(*dynamodb.DeleteBackupInput) (*request.Request, *dynamodb.DeleteBackupOutput)
|
||||
|
||||
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)
|
||||
|
||||
DescribeBackup(*dynamodb.DescribeBackupInput) (*dynamodb.DescribeBackupOutput, error)
|
||||
DescribeBackupWithContext(aws.Context, *dynamodb.DescribeBackupInput, ...request.Option) (*dynamodb.DescribeBackupOutput, error)
|
||||
DescribeBackupRequest(*dynamodb.DescribeBackupInput) (*request.Request, *dynamodb.DescribeBackupOutput)
|
||||
|
||||
DescribeContinuousBackups(*dynamodb.DescribeContinuousBackupsInput) (*dynamodb.DescribeContinuousBackupsOutput, error)
|
||||
DescribeContinuousBackupsWithContext(aws.Context, *dynamodb.DescribeContinuousBackupsInput, ...request.Option) (*dynamodb.DescribeContinuousBackupsOutput, error)
|
||||
DescribeContinuousBackupsRequest(*dynamodb.DescribeContinuousBackupsInput) (*request.Request, *dynamodb.DescribeContinuousBackupsOutput)
|
||||
|
||||
DescribeGlobalTable(*dynamodb.DescribeGlobalTableInput) (*dynamodb.DescribeGlobalTableOutput, error)
|
||||
DescribeGlobalTableWithContext(aws.Context, *dynamodb.DescribeGlobalTableInput, ...request.Option) (*dynamodb.DescribeGlobalTableOutput, error)
|
||||
DescribeGlobalTableRequest(*dynamodb.DescribeGlobalTableInput) (*request.Request, *dynamodb.DescribeGlobalTableOutput)
|
||||
|
||||
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)
|
||||
|
||||
ListBackups(*dynamodb.ListBackupsInput) (*dynamodb.ListBackupsOutput, error)
|
||||
ListBackupsWithContext(aws.Context, *dynamodb.ListBackupsInput, ...request.Option) (*dynamodb.ListBackupsOutput, error)
|
||||
ListBackupsRequest(*dynamodb.ListBackupsInput) (*request.Request, *dynamodb.ListBackupsOutput)
|
||||
|
||||
ListGlobalTables(*dynamodb.ListGlobalTablesInput) (*dynamodb.ListGlobalTablesOutput, error)
|
||||
ListGlobalTablesWithContext(aws.Context, *dynamodb.ListGlobalTablesInput, ...request.Option) (*dynamodb.ListGlobalTablesOutput, error)
|
||||
ListGlobalTablesRequest(*dynamodb.ListGlobalTablesInput) (*request.Request, *dynamodb.ListGlobalTablesOutput)
|
||||
|
||||
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
|
||||
|
||||
RestoreTableFromBackup(*dynamodb.RestoreTableFromBackupInput) (*dynamodb.RestoreTableFromBackupOutput, error)
|
||||
RestoreTableFromBackupWithContext(aws.Context, *dynamodb.RestoreTableFromBackupInput, ...request.Option) (*dynamodb.RestoreTableFromBackupOutput, error)
|
||||
RestoreTableFromBackupRequest(*dynamodb.RestoreTableFromBackupInput) (*request.Request, *dynamodb.RestoreTableFromBackupOutput)
|
||||
|
||||
RestoreTableToPointInTime(*dynamodb.RestoreTableToPointInTimeInput) (*dynamodb.RestoreTableToPointInTimeOutput, error)
|
||||
RestoreTableToPointInTimeWithContext(aws.Context, *dynamodb.RestoreTableToPointInTimeInput, ...request.Option) (*dynamodb.RestoreTableToPointInTimeOutput, error)
|
||||
RestoreTableToPointInTimeRequest(*dynamodb.RestoreTableToPointInTimeInput) (*request.Request, *dynamodb.RestoreTableToPointInTimeOutput)
|
||||
|
||||
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)
|
||||
|
||||
UpdateContinuousBackups(*dynamodb.UpdateContinuousBackupsInput) (*dynamodb.UpdateContinuousBackupsOutput, error)
|
||||
UpdateContinuousBackupsWithContext(aws.Context, *dynamodb.UpdateContinuousBackupsInput, ...request.Option) (*dynamodb.UpdateContinuousBackupsOutput, error)
|
||||
UpdateContinuousBackupsRequest(*dynamodb.UpdateContinuousBackupsInput) (*request.Request, *dynamodb.UpdateContinuousBackupsOutput)
|
||||
|
||||
UpdateGlobalTable(*dynamodb.UpdateGlobalTableInput) (*dynamodb.UpdateGlobalTableOutput, error)
|
||||
UpdateGlobalTableWithContext(aws.Context, *dynamodb.UpdateGlobalTableInput, ...request.Option) (*dynamodb.UpdateGlobalTableOutput, error)
|
||||
UpdateGlobalTableRequest(*dynamodb.UpdateGlobalTableInput) (*request.Request, *dynamodb.UpdateGlobalTableOutput)
|
||||
|
||||
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)
|
||||
143
vendor/github.com/aws/aws-sdk-go/service/dynamodb/errors.go
generated
vendored
Normal file
143
vendor/github.com/aws/aws-sdk-go/service/dynamodb/errors.go
generated
vendored
Normal file
@@ -0,0 +1,143 @@
|
||||
// Code generated by private/model/cli/gen-api/main.go. DO NOT EDIT.
|
||||
|
||||
package dynamodb
|
||||
|
||||
const (
|
||||
|
||||
// ErrCodeBackupInUseException for service response error code
|
||||
// "BackupInUseException".
|
||||
//
|
||||
// There is another ongoing conflicting backup control plane operation on the
|
||||
// table. The backups is either being created, deleted or restored to a table.
|
||||
ErrCodeBackupInUseException = "BackupInUseException"
|
||||
|
||||
// ErrCodeBackupNotFoundException for service response error code
|
||||
// "BackupNotFoundException".
|
||||
//
|
||||
// Backup not found for the given BackupARN.
|
||||
ErrCodeBackupNotFoundException = "BackupNotFoundException"
|
||||
|
||||
// ErrCodeConditionalCheckFailedException for service response error code
|
||||
// "ConditionalCheckFailedException".
|
||||
//
|
||||
// A condition specified in the operation could not be evaluated.
|
||||
ErrCodeConditionalCheckFailedException = "ConditionalCheckFailedException"
|
||||
|
||||
// ErrCodeContinuousBackupsUnavailableException for service response error code
|
||||
// "ContinuousBackupsUnavailableException".
|
||||
//
|
||||
// Backups have not yet been enabled for this table.
|
||||
ErrCodeContinuousBackupsUnavailableException = "ContinuousBackupsUnavailableException"
|
||||
|
||||
// ErrCodeGlobalTableAlreadyExistsException for service response error code
|
||||
// "GlobalTableAlreadyExistsException".
|
||||
//
|
||||
// The specified global table already exists.
|
||||
ErrCodeGlobalTableAlreadyExistsException = "GlobalTableAlreadyExistsException"
|
||||
|
||||
// ErrCodeGlobalTableNotFoundException for service response error code
|
||||
// "GlobalTableNotFoundException".
|
||||
//
|
||||
// The specified global table does not exist.
|
||||
ErrCodeGlobalTableNotFoundException = "GlobalTableNotFoundException"
|
||||
|
||||
// ErrCodeInternalServerError for service response error code
|
||||
// "InternalServerError".
|
||||
//
|
||||
// An error occurred on the server side.
|
||||
ErrCodeInternalServerError = "InternalServerError"
|
||||
|
||||
// ErrCodeInvalidRestoreTimeException for service response error code
|
||||
// "InvalidRestoreTimeException".
|
||||
//
|
||||
// An invalid restore time was specified. RestoreDateTime must be between EarliestRestorableDateTime
|
||||
// and LatestRestorableDateTime.
|
||||
ErrCodeInvalidRestoreTimeException = "InvalidRestoreTimeException"
|
||||
|
||||
// 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".
|
||||
//
|
||||
// Up to 50 CreateBackup operations are allowed per second, per account. There
|
||||
// is no limit to the number of daily on-demand backups that can be taken.
|
||||
//
|
||||
// Up to 10 simultaneous table operations are allowed per account. These operations
|
||||
// include CreateTable, UpdateTable, DeleteTable,UpdateTimeToLive, RestoreTableFromBackup,
|
||||
// and RestoreTableToPointInTime.
|
||||
//
|
||||
// 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"
|
||||
|
||||
// ErrCodePointInTimeRecoveryUnavailableException for service response error code
|
||||
// "PointInTimeRecoveryUnavailableException".
|
||||
//
|
||||
// Point in time recovery has not yet been enabled for this source table.
|
||||
ErrCodePointInTimeRecoveryUnavailableException = "PointInTimeRecoveryUnavailableException"
|
||||
|
||||
// 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"
|
||||
|
||||
// ErrCodeReplicaAlreadyExistsException for service response error code
|
||||
// "ReplicaAlreadyExistsException".
|
||||
//
|
||||
// The specified replica is already part of the global table.
|
||||
ErrCodeReplicaAlreadyExistsException = "ReplicaAlreadyExistsException"
|
||||
|
||||
// ErrCodeReplicaNotFoundException for service response error code
|
||||
// "ReplicaNotFoundException".
|
||||
//
|
||||
// The specified replica is no longer part of the global table.
|
||||
ErrCodeReplicaNotFoundException = "ReplicaNotFoundException"
|
||||
|
||||
// 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"
|
||||
|
||||
// ErrCodeTableAlreadyExistsException for service response error code
|
||||
// "TableAlreadyExistsException".
|
||||
//
|
||||
// A target table with the specified name already exists.
|
||||
ErrCodeTableAlreadyExistsException = "TableAlreadyExistsException"
|
||||
|
||||
// ErrCodeTableInUseException for service response error code
|
||||
// "TableInUseException".
|
||||
//
|
||||
// A target table with the specified name is either being created or deleted.
|
||||
ErrCodeTableInUseException = "TableInUseException"
|
||||
|
||||
// ErrCodeTableNotFoundException for service response error code
|
||||
// "TableNotFoundException".
|
||||
//
|
||||
// A source table with the name TableName does not currently exist within the
|
||||
// subscriber's account.
|
||||
ErrCodeTableNotFoundException = "TableNotFoundException"
|
||||
)
|
||||
677
vendor/github.com/aws/aws-sdk-go/service/dynamodb/examples_test.go
generated
vendored
Normal file
677
vendor/github.com/aws/aws-sdk-go/service/dynamodb/examples_test.go
generated
vendored
Normal file
@@ -0,0 +1,677 @@
|
||||
// Code generated by private/model/cli/gen-api/main.go. DO NOT EDIT.
|
||||
|
||||
package dynamodb_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
"github.com/aws/aws-sdk-go/aws/session"
|
||||
"github.com/aws/aws-sdk-go/service/dynamodb"
|
||||
)
|
||||
|
||||
var _ time.Duration
|
||||
var _ strings.Reader
|
||||
var _ aws.Config
|
||||
|
||||
func parseTime(layout, value string) *time.Time {
|
||||
t, err := time.Parse(layout, value)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return &t
|
||||
}
|
||||
|
||||
// To retrieve multiple items from a table
|
||||
//
|
||||
// This example reads multiple items from the Music table using a batch of three GetItem
|
||||
// requests. Only the AlbumTitle attribute is returned.
|
||||
func ExampleDynamoDB_BatchGetItem_shared00() {
|
||||
svc := dynamodb.New(session.New())
|
||||
input := &dynamodb.BatchGetItemInput{
|
||||
RequestItems: map[string]*dynamodb.KeysAndAttributes{
|
||||
"Music": {
|
||||
Keys: []map[string]*dynamodb.AttributeValue{
|
||||
{
|
||||
"Artist": &dynamodb.AttributeValue{
|
||||
S: aws.String("No One You Know"),
|
||||
},
|
||||
"SongTitle": &dynamodb.AttributeValue{
|
||||
S: aws.String("Call Me Today"),
|
||||
},
|
||||
},
|
||||
{
|
||||
"Artist": &dynamodb.AttributeValue{
|
||||
S: aws.String("Acme Band"),
|
||||
},
|
||||
"SongTitle": &dynamodb.AttributeValue{
|
||||
S: aws.String("Happy Day"),
|
||||
},
|
||||
},
|
||||
{
|
||||
"Artist": &dynamodb.AttributeValue{
|
||||
S: aws.String("No One You Know"),
|
||||
},
|
||||
"SongTitle": &dynamodb.AttributeValue{
|
||||
S: aws.String("Scared of My Shadow"),
|
||||
},
|
||||
},
|
||||
},
|
||||
ProjectionExpression: aws.String("AlbumTitle"),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
result, err := svc.BatchGetItem(input)
|
||||
if err != nil {
|
||||
if aerr, ok := err.(awserr.Error); ok {
|
||||
switch aerr.Code() {
|
||||
case dynamodb.ErrCodeProvisionedThroughputExceededException:
|
||||
fmt.Println(dynamodb.ErrCodeProvisionedThroughputExceededException, aerr.Error())
|
||||
case dynamodb.ErrCodeResourceNotFoundException:
|
||||
fmt.Println(dynamodb.ErrCodeResourceNotFoundException, aerr.Error())
|
||||
case dynamodb.ErrCodeInternalServerError:
|
||||
fmt.Println(dynamodb.ErrCodeInternalServerError, aerr.Error())
|
||||
default:
|
||||
fmt.Println(aerr.Error())
|
||||
}
|
||||
} else {
|
||||
// Print the error, cast err to awserr.Error to get the Code and
|
||||
// Message from an error.
|
||||
fmt.Println(err.Error())
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(result)
|
||||
}
|
||||
|
||||
// To add multiple items to a table
|
||||
//
|
||||
// This example adds three new items to the Music table using a batch of three PutItem
|
||||
// requests.
|
||||
func ExampleDynamoDB_BatchWriteItem_shared00() {
|
||||
svc := dynamodb.New(session.New())
|
||||
input := &dynamodb.BatchWriteItemInput{
|
||||
RequestItems: map[string][]*dynamodb.WriteRequest{
|
||||
"Music": {
|
||||
{
|
||||
PutRequest: &dynamodb.PutRequest{
|
||||
Item: map[string]*dynamodb.AttributeValue{
|
||||
"AlbumTitle": {
|
||||
S: aws.String("Somewhat Famous"),
|
||||
},
|
||||
"Artist": {
|
||||
S: aws.String("No One You Know"),
|
||||
},
|
||||
"SongTitle": {
|
||||
S: aws.String("Call Me Today"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
PutRequest: &dynamodb.PutRequest{
|
||||
Item: map[string]*dynamodb.AttributeValue{
|
||||
"AlbumTitle": {
|
||||
S: aws.String("Songs About Life"),
|
||||
},
|
||||
"Artist": {
|
||||
S: aws.String("Acme Band"),
|
||||
},
|
||||
"SongTitle": {
|
||||
S: aws.String("Happy Day"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
PutRequest: &dynamodb.PutRequest{
|
||||
Item: map[string]*dynamodb.AttributeValue{
|
||||
"AlbumTitle": {
|
||||
S: aws.String("Blue Sky Blues"),
|
||||
},
|
||||
"Artist": {
|
||||
S: aws.String("No One You Know"),
|
||||
},
|
||||
"SongTitle": {
|
||||
S: aws.String("Scared of My Shadow"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
result, err := svc.BatchWriteItem(input)
|
||||
if err != nil {
|
||||
if aerr, ok := err.(awserr.Error); ok {
|
||||
switch aerr.Code() {
|
||||
case dynamodb.ErrCodeProvisionedThroughputExceededException:
|
||||
fmt.Println(dynamodb.ErrCodeProvisionedThroughputExceededException, aerr.Error())
|
||||
case dynamodb.ErrCodeResourceNotFoundException:
|
||||
fmt.Println(dynamodb.ErrCodeResourceNotFoundException, aerr.Error())
|
||||
case dynamodb.ErrCodeItemCollectionSizeLimitExceededException:
|
||||
fmt.Println(dynamodb.ErrCodeItemCollectionSizeLimitExceededException, aerr.Error())
|
||||
case dynamodb.ErrCodeInternalServerError:
|
||||
fmt.Println(dynamodb.ErrCodeInternalServerError, aerr.Error())
|
||||
default:
|
||||
fmt.Println(aerr.Error())
|
||||
}
|
||||
} else {
|
||||
// Print the error, cast err to awserr.Error to get the Code and
|
||||
// Message from an error.
|
||||
fmt.Println(err.Error())
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(result)
|
||||
}
|
||||
|
||||
// To create a table
|
||||
//
|
||||
// This example creates a table named Music.
|
||||
func ExampleDynamoDB_CreateTable_shared00() {
|
||||
svc := dynamodb.New(session.New())
|
||||
input := &dynamodb.CreateTableInput{
|
||||
AttributeDefinitions: []*dynamodb.AttributeDefinition{
|
||||
{
|
||||
AttributeName: aws.String("Artist"),
|
||||
AttributeType: aws.String("S"),
|
||||
},
|
||||
{
|
||||
AttributeName: aws.String("SongTitle"),
|
||||
AttributeType: aws.String("S"),
|
||||
},
|
||||
},
|
||||
KeySchema: []*dynamodb.KeySchemaElement{
|
||||
{
|
||||
AttributeName: aws.String("Artist"),
|
||||
KeyType: aws.String("HASH"),
|
||||
},
|
||||
{
|
||||
AttributeName: aws.String("SongTitle"),
|
||||
KeyType: aws.String("RANGE"),
|
||||
},
|
||||
},
|
||||
ProvisionedThroughput: &dynamodb.ProvisionedThroughput{
|
||||
ReadCapacityUnits: aws.Int64(5),
|
||||
WriteCapacityUnits: aws.Int64(5),
|
||||
},
|
||||
TableName: aws.String("Music"),
|
||||
}
|
||||
|
||||
result, err := svc.CreateTable(input)
|
||||
if err != nil {
|
||||
if aerr, ok := err.(awserr.Error); ok {
|
||||
switch aerr.Code() {
|
||||
case dynamodb.ErrCodeResourceInUseException:
|
||||
fmt.Println(dynamodb.ErrCodeResourceInUseException, aerr.Error())
|
||||
case dynamodb.ErrCodeLimitExceededException:
|
||||
fmt.Println(dynamodb.ErrCodeLimitExceededException, aerr.Error())
|
||||
case dynamodb.ErrCodeInternalServerError:
|
||||
fmt.Println(dynamodb.ErrCodeInternalServerError, aerr.Error())
|
||||
default:
|
||||
fmt.Println(aerr.Error())
|
||||
}
|
||||
} else {
|
||||
// Print the error, cast err to awserr.Error to get the Code and
|
||||
// Message from an error.
|
||||
fmt.Println(err.Error())
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(result)
|
||||
}
|
||||
|
||||
// To delete an item
|
||||
//
|
||||
// This example deletes an item from the Music table.
|
||||
func ExampleDynamoDB_DeleteItem_shared00() {
|
||||
svc := dynamodb.New(session.New())
|
||||
input := &dynamodb.DeleteItemInput{
|
||||
Key: map[string]*dynamodb.AttributeValue{
|
||||
"Artist": {
|
||||
S: aws.String("No One You Know"),
|
||||
},
|
||||
"SongTitle": {
|
||||
S: aws.String("Scared of My Shadow"),
|
||||
},
|
||||
},
|
||||
TableName: aws.String("Music"),
|
||||
}
|
||||
|
||||
result, err := svc.DeleteItem(input)
|
||||
if err != nil {
|
||||
if aerr, ok := err.(awserr.Error); ok {
|
||||
switch aerr.Code() {
|
||||
case dynamodb.ErrCodeConditionalCheckFailedException:
|
||||
fmt.Println(dynamodb.ErrCodeConditionalCheckFailedException, aerr.Error())
|
||||
case dynamodb.ErrCodeProvisionedThroughputExceededException:
|
||||
fmt.Println(dynamodb.ErrCodeProvisionedThroughputExceededException, aerr.Error())
|
||||
case dynamodb.ErrCodeResourceNotFoundException:
|
||||
fmt.Println(dynamodb.ErrCodeResourceNotFoundException, aerr.Error())
|
||||
case dynamodb.ErrCodeItemCollectionSizeLimitExceededException:
|
||||
fmt.Println(dynamodb.ErrCodeItemCollectionSizeLimitExceededException, aerr.Error())
|
||||
case dynamodb.ErrCodeInternalServerError:
|
||||
fmt.Println(dynamodb.ErrCodeInternalServerError, aerr.Error())
|
||||
default:
|
||||
fmt.Println(aerr.Error())
|
||||
}
|
||||
} else {
|
||||
// Print the error, cast err to awserr.Error to get the Code and
|
||||
// Message from an error.
|
||||
fmt.Println(err.Error())
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(result)
|
||||
}
|
||||
|
||||
// To delete a table
|
||||
//
|
||||
// This example deletes the Music table.
|
||||
func ExampleDynamoDB_DeleteTable_shared00() {
|
||||
svc := dynamodb.New(session.New())
|
||||
input := &dynamodb.DeleteTableInput{
|
||||
TableName: aws.String("Music"),
|
||||
}
|
||||
|
||||
result, err := svc.DeleteTable(input)
|
||||
if err != nil {
|
||||
if aerr, ok := err.(awserr.Error); ok {
|
||||
switch aerr.Code() {
|
||||
case dynamodb.ErrCodeResourceInUseException:
|
||||
fmt.Println(dynamodb.ErrCodeResourceInUseException, aerr.Error())
|
||||
case dynamodb.ErrCodeResourceNotFoundException:
|
||||
fmt.Println(dynamodb.ErrCodeResourceNotFoundException, aerr.Error())
|
||||
case dynamodb.ErrCodeLimitExceededException:
|
||||
fmt.Println(dynamodb.ErrCodeLimitExceededException, aerr.Error())
|
||||
case dynamodb.ErrCodeInternalServerError:
|
||||
fmt.Println(dynamodb.ErrCodeInternalServerError, aerr.Error())
|
||||
default:
|
||||
fmt.Println(aerr.Error())
|
||||
}
|
||||
} else {
|
||||
// Print the error, cast err to awserr.Error to get the Code and
|
||||
// Message from an error.
|
||||
fmt.Println(err.Error())
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(result)
|
||||
}
|
||||
|
||||
// To determine capacity limits per table and account, in the current AWS region
|
||||
//
|
||||
// The following example returns the maximum read and write capacity units per table,
|
||||
// and for the AWS account, in the current AWS region.
|
||||
func ExampleDynamoDB_DescribeLimits_shared00() {
|
||||
svc := dynamodb.New(session.New())
|
||||
input := &dynamodb.DescribeLimitsInput{}
|
||||
|
||||
result, err := svc.DescribeLimits(input)
|
||||
if err != nil {
|
||||
if aerr, ok := err.(awserr.Error); ok {
|
||||
switch aerr.Code() {
|
||||
case dynamodb.ErrCodeInternalServerError:
|
||||
fmt.Println(dynamodb.ErrCodeInternalServerError, aerr.Error())
|
||||
default:
|
||||
fmt.Println(aerr.Error())
|
||||
}
|
||||
} else {
|
||||
// Print the error, cast err to awserr.Error to get the Code and
|
||||
// Message from an error.
|
||||
fmt.Println(err.Error())
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(result)
|
||||
}
|
||||
|
||||
// To describe a table
|
||||
//
|
||||
// This example describes the Music table.
|
||||
func ExampleDynamoDB_DescribeTable_shared00() {
|
||||
svc := dynamodb.New(session.New())
|
||||
input := &dynamodb.DescribeTableInput{
|
||||
TableName: aws.String("Music"),
|
||||
}
|
||||
|
||||
result, err := svc.DescribeTable(input)
|
||||
if err != nil {
|
||||
if aerr, ok := err.(awserr.Error); ok {
|
||||
switch aerr.Code() {
|
||||
case dynamodb.ErrCodeResourceNotFoundException:
|
||||
fmt.Println(dynamodb.ErrCodeResourceNotFoundException, aerr.Error())
|
||||
case dynamodb.ErrCodeInternalServerError:
|
||||
fmt.Println(dynamodb.ErrCodeInternalServerError, aerr.Error())
|
||||
default:
|
||||
fmt.Println(aerr.Error())
|
||||
}
|
||||
} else {
|
||||
// Print the error, cast err to awserr.Error to get the Code and
|
||||
// Message from an error.
|
||||
fmt.Println(err.Error())
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(result)
|
||||
}
|
||||
|
||||
// To read an item from a table
|
||||
//
|
||||
// This example retrieves an item from the Music table. The table has a partition key
|
||||
// and a sort key (Artist and SongTitle), so you must specify both of these attributes.
|
||||
func ExampleDynamoDB_GetItem_shared00() {
|
||||
svc := dynamodb.New(session.New())
|
||||
input := &dynamodb.GetItemInput{
|
||||
Key: map[string]*dynamodb.AttributeValue{
|
||||
"Artist": {
|
||||
S: aws.String("Acme Band"),
|
||||
},
|
||||
"SongTitle": {
|
||||
S: aws.String("Happy Day"),
|
||||
},
|
||||
},
|
||||
TableName: aws.String("Music"),
|
||||
}
|
||||
|
||||
result, err := svc.GetItem(input)
|
||||
if err != nil {
|
||||
if aerr, ok := err.(awserr.Error); ok {
|
||||
switch aerr.Code() {
|
||||
case dynamodb.ErrCodeProvisionedThroughputExceededException:
|
||||
fmt.Println(dynamodb.ErrCodeProvisionedThroughputExceededException, aerr.Error())
|
||||
case dynamodb.ErrCodeResourceNotFoundException:
|
||||
fmt.Println(dynamodb.ErrCodeResourceNotFoundException, aerr.Error())
|
||||
case dynamodb.ErrCodeInternalServerError:
|
||||
fmt.Println(dynamodb.ErrCodeInternalServerError, aerr.Error())
|
||||
default:
|
||||
fmt.Println(aerr.Error())
|
||||
}
|
||||
} else {
|
||||
// Print the error, cast err to awserr.Error to get the Code and
|
||||
// Message from an error.
|
||||
fmt.Println(err.Error())
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(result)
|
||||
}
|
||||
|
||||
// To list tables
|
||||
//
|
||||
// This example lists all of the tables associated with the current AWS account and
|
||||
// endpoint.
|
||||
func ExampleDynamoDB_ListTables_shared00() {
|
||||
svc := dynamodb.New(session.New())
|
||||
input := &dynamodb.ListTablesInput{}
|
||||
|
||||
result, err := svc.ListTables(input)
|
||||
if err != nil {
|
||||
if aerr, ok := err.(awserr.Error); ok {
|
||||
switch aerr.Code() {
|
||||
case dynamodb.ErrCodeInternalServerError:
|
||||
fmt.Println(dynamodb.ErrCodeInternalServerError, aerr.Error())
|
||||
default:
|
||||
fmt.Println(aerr.Error())
|
||||
}
|
||||
} else {
|
||||
// Print the error, cast err to awserr.Error to get the Code and
|
||||
// Message from an error.
|
||||
fmt.Println(err.Error())
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(result)
|
||||
}
|
||||
|
||||
// To add an item to a table
|
||||
//
|
||||
// This example adds a new item to the Music table.
|
||||
func ExampleDynamoDB_PutItem_shared00() {
|
||||
svc := dynamodb.New(session.New())
|
||||
input := &dynamodb.PutItemInput{
|
||||
Item: map[string]*dynamodb.AttributeValue{
|
||||
"AlbumTitle": {
|
||||
S: aws.String("Somewhat Famous"),
|
||||
},
|
||||
"Artist": {
|
||||
S: aws.String("No One You Know"),
|
||||
},
|
||||
"SongTitle": {
|
||||
S: aws.String("Call Me Today"),
|
||||
},
|
||||
},
|
||||
ReturnConsumedCapacity: aws.String("TOTAL"),
|
||||
TableName: aws.String("Music"),
|
||||
}
|
||||
|
||||
result, err := svc.PutItem(input)
|
||||
if err != nil {
|
||||
if aerr, ok := err.(awserr.Error); ok {
|
||||
switch aerr.Code() {
|
||||
case dynamodb.ErrCodeConditionalCheckFailedException:
|
||||
fmt.Println(dynamodb.ErrCodeConditionalCheckFailedException, aerr.Error())
|
||||
case dynamodb.ErrCodeProvisionedThroughputExceededException:
|
||||
fmt.Println(dynamodb.ErrCodeProvisionedThroughputExceededException, aerr.Error())
|
||||
case dynamodb.ErrCodeResourceNotFoundException:
|
||||
fmt.Println(dynamodb.ErrCodeResourceNotFoundException, aerr.Error())
|
||||
case dynamodb.ErrCodeItemCollectionSizeLimitExceededException:
|
||||
fmt.Println(dynamodb.ErrCodeItemCollectionSizeLimitExceededException, aerr.Error())
|
||||
case dynamodb.ErrCodeInternalServerError:
|
||||
fmt.Println(dynamodb.ErrCodeInternalServerError, aerr.Error())
|
||||
default:
|
||||
fmt.Println(aerr.Error())
|
||||
}
|
||||
} else {
|
||||
// Print the error, cast err to awserr.Error to get the Code and
|
||||
// Message from an error.
|
||||
fmt.Println(err.Error())
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(result)
|
||||
}
|
||||
|
||||
// To query an item
|
||||
//
|
||||
// This example queries items in the Music table. The table has a partition key and
|
||||
// sort key (Artist and SongTitle), but this query only specifies the partition key
|
||||
// value. It returns song titles by the artist named "No One You Know".
|
||||
func ExampleDynamoDB_Query_shared00() {
|
||||
svc := dynamodb.New(session.New())
|
||||
input := &dynamodb.QueryInput{
|
||||
ExpressionAttributeValues: map[string]*dynamodb.AttributeValue{
|
||||
":v1": {
|
||||
S: aws.String("No One You Know"),
|
||||
},
|
||||
},
|
||||
KeyConditionExpression: aws.String("Artist = :v1"),
|
||||
ProjectionExpression: aws.String("SongTitle"),
|
||||
TableName: aws.String("Music"),
|
||||
}
|
||||
|
||||
result, err := svc.Query(input)
|
||||
if err != nil {
|
||||
if aerr, ok := err.(awserr.Error); ok {
|
||||
switch aerr.Code() {
|
||||
case dynamodb.ErrCodeProvisionedThroughputExceededException:
|
||||
fmt.Println(dynamodb.ErrCodeProvisionedThroughputExceededException, aerr.Error())
|
||||
case dynamodb.ErrCodeResourceNotFoundException:
|
||||
fmt.Println(dynamodb.ErrCodeResourceNotFoundException, aerr.Error())
|
||||
case dynamodb.ErrCodeInternalServerError:
|
||||
fmt.Println(dynamodb.ErrCodeInternalServerError, aerr.Error())
|
||||
default:
|
||||
fmt.Println(aerr.Error())
|
||||
}
|
||||
} else {
|
||||
// Print the error, cast err to awserr.Error to get the Code and
|
||||
// Message from an error.
|
||||
fmt.Println(err.Error())
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(result)
|
||||
}
|
||||
|
||||
// To scan a table
|
||||
//
|
||||
// This example scans the entire Music table, and then narrows the results to songs
|
||||
// by the artist "No One You Know". For each item, only the album title and song title
|
||||
// are returned.
|
||||
func ExampleDynamoDB_Scan_shared00() {
|
||||
svc := dynamodb.New(session.New())
|
||||
input := &dynamodb.ScanInput{
|
||||
ExpressionAttributeNames: map[string]*string{
|
||||
"AT": aws.String("AlbumTitle"),
|
||||
"ST": aws.String("SongTitle"),
|
||||
},
|
||||
ExpressionAttributeValues: map[string]*dynamodb.AttributeValue{
|
||||
":a": {
|
||||
S: aws.String("No One You Know"),
|
||||
},
|
||||
},
|
||||
FilterExpression: aws.String("Artist = :a"),
|
||||
ProjectionExpression: aws.String("#ST, #AT"),
|
||||
TableName: aws.String("Music"),
|
||||
}
|
||||
|
||||
result, err := svc.Scan(input)
|
||||
if err != nil {
|
||||
if aerr, ok := err.(awserr.Error); ok {
|
||||
switch aerr.Code() {
|
||||
case dynamodb.ErrCodeProvisionedThroughputExceededException:
|
||||
fmt.Println(dynamodb.ErrCodeProvisionedThroughputExceededException, aerr.Error())
|
||||
case dynamodb.ErrCodeResourceNotFoundException:
|
||||
fmt.Println(dynamodb.ErrCodeResourceNotFoundException, aerr.Error())
|
||||
case dynamodb.ErrCodeInternalServerError:
|
||||
fmt.Println(dynamodb.ErrCodeInternalServerError, aerr.Error())
|
||||
default:
|
||||
fmt.Println(aerr.Error())
|
||||
}
|
||||
} else {
|
||||
// Print the error, cast err to awserr.Error to get the Code and
|
||||
// Message from an error.
|
||||
fmt.Println(err.Error())
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(result)
|
||||
}
|
||||
|
||||
// To update an item in a table
|
||||
//
|
||||
// This example updates an item in the Music table. It adds a new attribute (Year) and
|
||||
// modifies the AlbumTitle attribute. All of the attributes in the item, as they appear
|
||||
// after the update, are returned in the response.
|
||||
func ExampleDynamoDB_UpdateItem_shared00() {
|
||||
svc := dynamodb.New(session.New())
|
||||
input := &dynamodb.UpdateItemInput{
|
||||
ExpressionAttributeNames: map[string]*string{
|
||||
"#AT": aws.String("AlbumTitle"),
|
||||
"#Y": aws.String("Year"),
|
||||
},
|
||||
ExpressionAttributeValues: map[string]*dynamodb.AttributeValue{
|
||||
":t": {
|
||||
S: aws.String("Louder Than Ever"),
|
||||
},
|
||||
":y": {
|
||||
N: aws.String("2015"),
|
||||
},
|
||||
},
|
||||
Key: map[string]*dynamodb.AttributeValue{
|
||||
"Artist": {
|
||||
S: aws.String("Acme Band"),
|
||||
},
|
||||
"SongTitle": {
|
||||
S: aws.String("Happy Day"),
|
||||
},
|
||||
},
|
||||
ReturnValues: aws.String("ALL_NEW"),
|
||||
TableName: aws.String("Music"),
|
||||
UpdateExpression: aws.String("SET #Y = :y, #AT = :t"),
|
||||
}
|
||||
|
||||
result, err := svc.UpdateItem(input)
|
||||
if err != nil {
|
||||
if aerr, ok := err.(awserr.Error); ok {
|
||||
switch aerr.Code() {
|
||||
case dynamodb.ErrCodeConditionalCheckFailedException:
|
||||
fmt.Println(dynamodb.ErrCodeConditionalCheckFailedException, aerr.Error())
|
||||
case dynamodb.ErrCodeProvisionedThroughputExceededException:
|
||||
fmt.Println(dynamodb.ErrCodeProvisionedThroughputExceededException, aerr.Error())
|
||||
case dynamodb.ErrCodeResourceNotFoundException:
|
||||
fmt.Println(dynamodb.ErrCodeResourceNotFoundException, aerr.Error())
|
||||
case dynamodb.ErrCodeItemCollectionSizeLimitExceededException:
|
||||
fmt.Println(dynamodb.ErrCodeItemCollectionSizeLimitExceededException, aerr.Error())
|
||||
case dynamodb.ErrCodeInternalServerError:
|
||||
fmt.Println(dynamodb.ErrCodeInternalServerError, aerr.Error())
|
||||
default:
|
||||
fmt.Println(aerr.Error())
|
||||
}
|
||||
} else {
|
||||
// Print the error, cast err to awserr.Error to get the Code and
|
||||
// Message from an error.
|
||||
fmt.Println(err.Error())
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(result)
|
||||
}
|
||||
|
||||
// To modify a table's provisioned throughput
|
||||
//
|
||||
// This example increases the provisioned read and write capacity on the Music table.
|
||||
func ExampleDynamoDB_UpdateTable_shared00() {
|
||||
svc := dynamodb.New(session.New())
|
||||
input := &dynamodb.UpdateTableInput{
|
||||
ProvisionedThroughput: &dynamodb.ProvisionedThroughput{
|
||||
ReadCapacityUnits: aws.Int64(10),
|
||||
WriteCapacityUnits: aws.Int64(10),
|
||||
},
|
||||
TableName: aws.String("MusicCollection"),
|
||||
}
|
||||
|
||||
result, err := svc.UpdateTable(input)
|
||||
if err != nil {
|
||||
if aerr, ok := err.(awserr.Error); ok {
|
||||
switch aerr.Code() {
|
||||
case dynamodb.ErrCodeResourceInUseException:
|
||||
fmt.Println(dynamodb.ErrCodeResourceInUseException, aerr.Error())
|
||||
case dynamodb.ErrCodeResourceNotFoundException:
|
||||
fmt.Println(dynamodb.ErrCodeResourceNotFoundException, aerr.Error())
|
||||
case dynamodb.ErrCodeLimitExceededException:
|
||||
fmt.Println(dynamodb.ErrCodeLimitExceededException, aerr.Error())
|
||||
case dynamodb.ErrCodeInternalServerError:
|
||||
fmt.Println(dynamodb.ErrCodeInternalServerError, aerr.Error())
|
||||
default:
|
||||
fmt.Println(aerr.Error())
|
||||
}
|
||||
} else {
|
||||
// Print the error, cast err to awserr.Error to get the Code and
|
||||
// Message from an error.
|
||||
fmt.Println(err.Error())
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(result)
|
||||
}
|
||||
1577
vendor/github.com/aws/aws-sdk-go/service/dynamodb/expression/condition.go
generated
vendored
Normal file
1577
vendor/github.com/aws/aws-sdk-go/service/dynamodb/expression/condition.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1615
vendor/github.com/aws/aws-sdk-go/service/dynamodb/expression/condition_test.go
generated
vendored
Normal file
1615
vendor/github.com/aws/aws-sdk-go/service/dynamodb/expression/condition_test.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
48
vendor/github.com/aws/aws-sdk-go/service/dynamodb/expression/doc.go
generated
vendored
Normal file
48
vendor/github.com/aws/aws-sdk-go/service/dynamodb/expression/doc.go
generated
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
Package expression provides types and functions to create Amazon DynamoDB
|
||||
Expression strings, ExpressionAttributeNames maps, and ExpressionAttributeValues
|
||||
maps.
|
||||
|
||||
Using the Package
|
||||
|
||||
The package represents the various DynamoDB Expressions as structs named
|
||||
accordingly. For example, ConditionBuilder represents a DynamoDB Condition
|
||||
Expression, an UpdateBuilder represents a DynamoDB Update Expression, and so on.
|
||||
The following example shows a sample ConditionExpression and how to build an
|
||||
equilvalent ConditionBuilder
|
||||
|
||||
// Let :a be an ExpressionAttributeValue representing the string "No One You
|
||||
// Know"
|
||||
condExpr := "Artist = :a"
|
||||
condBuilder := expression.Name("Artist").Equal(expression.Value("No One You Know"))
|
||||
|
||||
In order to retrieve the formatted DynamoDB Expression strings, call the getter
|
||||
methods on the Expression struct. To create the Expression struct, call the
|
||||
Build() method on the Builder struct. Because some input structs, such as
|
||||
QueryInput, can have multiple DynamoDB Expressions, multiple structs
|
||||
representing various DynamoDB Expressions can be added to the Builder struct.
|
||||
The following example shows a generic usage of the whole package.
|
||||
|
||||
filt := expression.Name("Artist").Equal(expression.Value("No One You Know"))
|
||||
proj := expression.NamesList(expression.Name("SongTitle"), expression.Name("AlbumTitle"))
|
||||
expr, err := expression.NewBuilder().WithFilter(filt).WithProjection(proj).Build()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
|
||||
input := &dynamodb.ScanInput{
|
||||
ExpressionAttributeNames: expr.Names(),
|
||||
ExpressionAttributeValues: expr.Values(),
|
||||
FilterExpression: expr.Filter(),
|
||||
ProjectionExpression: expr.Projection(),
|
||||
TableName: aws.String("Music"),
|
||||
}
|
||||
|
||||
The ExpressionAttributeNames and ExpressionAttributeValues member of the input
|
||||
struct must always be assigned when using the Expression struct because all item
|
||||
attribute names and values are aliased. That means that if the
|
||||
ExpressionAttributeNames and ExpressionAttributeValues member is not assigned
|
||||
with the corresponding Names() and Values() methods, the DynamoDB operation will
|
||||
run into a logic error.
|
||||
*/
|
||||
package expression
|
||||
59
vendor/github.com/aws/aws-sdk-go/service/dynamodb/expression/error.go
generated
vendored
Normal file
59
vendor/github.com/aws/aws-sdk-go/service/dynamodb/expression/error.go
generated
vendored
Normal file
@@ -0,0 +1,59 @@
|
||||
package expression
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// InvalidParameterError is returned if invalid parameters are encountered. This
|
||||
// error specifically refers to situations where parameters are non-empty but
|
||||
// have an invalid syntax/format. The error message includes the function
|
||||
// that returned the error originally and the parameter type that was deemed
|
||||
// invalid.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// // err is of type InvalidParameterError
|
||||
// _, err := expression.Name("foo..bar").BuildOperand()
|
||||
type InvalidParameterError struct {
|
||||
parameterType string
|
||||
functionName string
|
||||
}
|
||||
|
||||
func (ipe InvalidParameterError) Error() string {
|
||||
return fmt.Sprintf("%s error: invalid parameter: %s", ipe.functionName, ipe.parameterType)
|
||||
}
|
||||
|
||||
func newInvalidParameterError(funcName, paramType string) InvalidParameterError {
|
||||
return InvalidParameterError{
|
||||
parameterType: paramType,
|
||||
functionName: funcName,
|
||||
}
|
||||
}
|
||||
|
||||
// UnsetParameterError is returned if parameters are empty and uninitialized.
|
||||
// This error is returned if opaque structs (ConditionBuilder, NameBuilder,
|
||||
// Builder, etc) are initialized outside of functions in the package, since all
|
||||
// structs in the package are designed to be initialized with functions.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// // err is of type UnsetParameterError
|
||||
// _, err := expression.Builder{}.Build()
|
||||
// _, err := expression.NewBuilder().
|
||||
// WithCondition(expression.ConditionBuilder{}).
|
||||
// Build()
|
||||
type UnsetParameterError struct {
|
||||
parameterType string
|
||||
functionName string
|
||||
}
|
||||
|
||||
func (upe UnsetParameterError) Error() string {
|
||||
return fmt.Sprintf("%s error: unset parameter: %s", upe.functionName, upe.parameterType)
|
||||
}
|
||||
|
||||
func newUnsetParameterError(funcName, paramType string) UnsetParameterError {
|
||||
return UnsetParameterError{
|
||||
parameterType: paramType,
|
||||
functionName: funcName,
|
||||
}
|
||||
}
|
||||
51
vendor/github.com/aws/aws-sdk-go/service/dynamodb/expression/error_test.go
generated
vendored
Normal file
51
vendor/github.com/aws/aws-sdk-go/service/dynamodb/expression/error_test.go
generated
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
// +build go1.7
|
||||
|
||||
package expression
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestInvalidParameterError(t *testing.T) {
|
||||
cases := []struct {
|
||||
name string
|
||||
input InvalidParameterError
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
name: "invalid error",
|
||||
input: newInvalidParameterError("func", "param"),
|
||||
expected: "func error: invalid parameter: param",
|
||||
},
|
||||
}
|
||||
for _, c := range cases {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
actual := c.input.Error()
|
||||
if e, a := c.expected, actual; e != a {
|
||||
t.Errorf("expect %v, got %v", e, a)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnsetParameterError(t *testing.T) {
|
||||
cases := []struct {
|
||||
name string
|
||||
input UnsetParameterError
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
name: "unset error",
|
||||
input: newUnsetParameterError("func", "param"),
|
||||
expected: "func error: unset parameter: param",
|
||||
},
|
||||
}
|
||||
for _, c := range cases {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
actual := c.input.Error()
|
||||
if e, a := c.expected, actual; e != a {
|
||||
t.Errorf("expect %v, got %v", e, a)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
315
vendor/github.com/aws/aws-sdk-go/service/dynamodb/expression/examples_test.go
generated
vendored
Normal file
315
vendor/github.com/aws/aws-sdk-go/service/dynamodb/expression/examples_test.go
generated
vendored
Normal file
@@ -0,0 +1,315 @@
|
||||
package expression_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
"github.com/aws/aws-sdk-go/aws/session"
|
||||
"github.com/aws/aws-sdk-go/service/dynamodb"
|
||||
"github.com/aws/aws-sdk-go/service/dynamodb/expression"
|
||||
)
|
||||
|
||||
// Using Projection Expression
|
||||
//
|
||||
// This example queries items in the Music table. The table has a partition key and
|
||||
// sort key (Artist and SongTitle), but this query only specifies the partition key
|
||||
// value. It returns song titles by the artist named "No One You Know".
|
||||
func ExampleBuilder_WithProjection() {
|
||||
svc := dynamodb.New(session.New())
|
||||
|
||||
// Construct the Key condition builder
|
||||
keyCond := expression.Key("Artist").Equal(expression.Value("No One You Know"))
|
||||
|
||||
// Create the project expression builder with a names list.
|
||||
proj := expression.NamesList(expression.Name("SongTitle"))
|
||||
|
||||
// Combine the key condition, and projection together as a DynamoDB expression
|
||||
// builder.
|
||||
expr, err := expression.NewBuilder().
|
||||
WithKeyCondition(keyCond).
|
||||
WithProjection(proj).
|
||||
Build()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
|
||||
// Use the built expression to populate the DynamoDB Query's API input
|
||||
// parameters.
|
||||
input := &dynamodb.QueryInput{
|
||||
ExpressionAttributeValues: expr.Values(),
|
||||
KeyConditionExpression: expr.KeyCondition(),
|
||||
ProjectionExpression: expr.Projection(),
|
||||
TableName: aws.String("Music"),
|
||||
}
|
||||
|
||||
result, err := svc.Query(input)
|
||||
if err != nil {
|
||||
if aerr, ok := err.(awserr.Error); ok {
|
||||
switch aerr.Code() {
|
||||
case dynamodb.ErrCodeProvisionedThroughputExceededException:
|
||||
fmt.Println(dynamodb.ErrCodeProvisionedThroughputExceededException, aerr.Error())
|
||||
case dynamodb.ErrCodeResourceNotFoundException:
|
||||
fmt.Println(dynamodb.ErrCodeResourceNotFoundException, aerr.Error())
|
||||
case dynamodb.ErrCodeInternalServerError:
|
||||
fmt.Println(dynamodb.ErrCodeInternalServerError, aerr.Error())
|
||||
default:
|
||||
fmt.Println(aerr.Error())
|
||||
}
|
||||
} else {
|
||||
// Print the error, cast err to awserr.Error to get the Code and
|
||||
// Message from an error.
|
||||
fmt.Println(err.Error())
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(result)
|
||||
}
|
||||
|
||||
// Using Key Condition Expression
|
||||
//
|
||||
// This example queries items in the Music table. The table has a partition key and
|
||||
// sort key (Artist and SongTitle), but this query only specifies the partition key
|
||||
// value. It returns song titles by the artist named "No One You Know".
|
||||
func ExampleBuilder_WithKeyCondition() {
|
||||
svc := dynamodb.New(session.New())
|
||||
|
||||
// Construct the Key condition builder
|
||||
keyCond := expression.Key("Artist").Equal(expression.Value("No One You Know"))
|
||||
|
||||
// Create the project expression builder with a names list.
|
||||
proj := expression.NamesList(expression.Name("SongTitle"))
|
||||
|
||||
// Combine the key condition, and projection together as a DynamoDB expression
|
||||
// builder.
|
||||
expr, err := expression.NewBuilder().
|
||||
WithKeyCondition(keyCond).
|
||||
WithProjection(proj).
|
||||
Build()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
|
||||
// Use the built expression to populate the DynamoDB Query's API input
|
||||
// parameters.
|
||||
input := &dynamodb.QueryInput{
|
||||
ExpressionAttributeValues: expr.Values(),
|
||||
KeyConditionExpression: expr.KeyCondition(),
|
||||
ProjectionExpression: expr.Projection(),
|
||||
TableName: aws.String("Music"),
|
||||
}
|
||||
|
||||
result, err := svc.Query(input)
|
||||
if err != nil {
|
||||
if aerr, ok := err.(awserr.Error); ok {
|
||||
switch aerr.Code() {
|
||||
case dynamodb.ErrCodeProvisionedThroughputExceededException:
|
||||
fmt.Println(dynamodb.ErrCodeProvisionedThroughputExceededException, aerr.Error())
|
||||
case dynamodb.ErrCodeResourceNotFoundException:
|
||||
fmt.Println(dynamodb.ErrCodeResourceNotFoundException, aerr.Error())
|
||||
case dynamodb.ErrCodeInternalServerError:
|
||||
fmt.Println(dynamodb.ErrCodeInternalServerError, aerr.Error())
|
||||
default:
|
||||
fmt.Println(aerr.Error())
|
||||
}
|
||||
} else {
|
||||
// Print the error, cast err to awserr.Error to get the Code and
|
||||
// Message from an error.
|
||||
fmt.Println(err.Error())
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(result)
|
||||
}
|
||||
|
||||
// Using Filter Expression
|
||||
//
|
||||
// This example scans the entire Music table, and then narrows the results to songs
|
||||
// by the artist "No One You Know". For each item, only the album title and song title
|
||||
// are returned.
|
||||
func ExampleBuilder_WithFilter() {
|
||||
svc := dynamodb.New(session.New())
|
||||
|
||||
// Construct the filter builder with a name and value.
|
||||
filt := expression.Name("Artist").Equal(expression.Value("No One You Know"))
|
||||
|
||||
// Create the names list projection of names to project.
|
||||
proj := expression.NamesList(
|
||||
expression.Name("AlbumTitle"),
|
||||
expression.Name("SongTitle"),
|
||||
)
|
||||
|
||||
// Using the filter and projections create a DynamoDB expression from the two.
|
||||
expr, err := expression.NewBuilder().
|
||||
WithFilter(filt).
|
||||
WithProjection(proj).
|
||||
Build()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
|
||||
// Use the built expression to populate the DynamoDB Scan API input parameters.
|
||||
input := &dynamodb.ScanInput{
|
||||
ExpressionAttributeNames: expr.Names(),
|
||||
ExpressionAttributeValues: expr.Values(),
|
||||
FilterExpression: expr.Filter(),
|
||||
ProjectionExpression: expr.Projection(),
|
||||
TableName: aws.String("Music"),
|
||||
}
|
||||
|
||||
result, err := svc.Scan(input)
|
||||
if err != nil {
|
||||
if aerr, ok := err.(awserr.Error); ok {
|
||||
switch aerr.Code() {
|
||||
case dynamodb.ErrCodeProvisionedThroughputExceededException:
|
||||
fmt.Println(dynamodb.ErrCodeProvisionedThroughputExceededException, aerr.Error())
|
||||
case dynamodb.ErrCodeResourceNotFoundException:
|
||||
fmt.Println(dynamodb.ErrCodeResourceNotFoundException, aerr.Error())
|
||||
case dynamodb.ErrCodeInternalServerError:
|
||||
fmt.Println(dynamodb.ErrCodeInternalServerError, aerr.Error())
|
||||
default:
|
||||
fmt.Println(aerr.Error())
|
||||
}
|
||||
} else {
|
||||
// Print the error, cast err to awserr.Error to get the Code and
|
||||
// Message from an error.
|
||||
fmt.Println(err.Error())
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(result)
|
||||
}
|
||||
|
||||
// Using Update Expression
|
||||
//
|
||||
// This example updates an item in the Music table. It adds a new attribute (Year) and
|
||||
// modifies the AlbumTitle attribute. All of the attributes in the item, as they appear
|
||||
// after the update, are returned in the response.
|
||||
func ExampleBuilder_WithUpdate() {
|
||||
svc := dynamodb.New(session.New())
|
||||
|
||||
// Create an update to set two fields in the table.
|
||||
update := expression.Set(
|
||||
expression.Name("Year"),
|
||||
expression.Value(2015),
|
||||
).Set(
|
||||
expression.Name("AlbumTitle"),
|
||||
expression.Value("Louder Than Ever"),
|
||||
)
|
||||
|
||||
// Create the DynamoDB expression from the Update.
|
||||
expr, err := expression.NewBuilder().
|
||||
WithUpdate(update).
|
||||
Build()
|
||||
|
||||
// Use the built expression to populate the DynamoDB UpdateItem API
|
||||
// input parameters.
|
||||
input := &dynamodb.UpdateItemInput{
|
||||
ExpressionAttributeNames: expr.Names(),
|
||||
ExpressionAttributeValues: expr.Values(),
|
||||
Key: map[string]*dynamodb.AttributeValue{
|
||||
"Artist": {
|
||||
S: aws.String("Acme Band"),
|
||||
},
|
||||
"SongTitle": {
|
||||
S: aws.String("Happy Day"),
|
||||
},
|
||||
},
|
||||
ReturnValues: aws.String("ALL_NEW"),
|
||||
TableName: aws.String("Music"),
|
||||
UpdateExpression: expr.Update(),
|
||||
}
|
||||
|
||||
result, err := svc.UpdateItem(input)
|
||||
if err != nil {
|
||||
if aerr, ok := err.(awserr.Error); ok {
|
||||
switch aerr.Code() {
|
||||
case dynamodb.ErrCodeConditionalCheckFailedException:
|
||||
fmt.Println(dynamodb.ErrCodeConditionalCheckFailedException, aerr.Error())
|
||||
case dynamodb.ErrCodeProvisionedThroughputExceededException:
|
||||
fmt.Println(dynamodb.ErrCodeProvisionedThroughputExceededException, aerr.Error())
|
||||
case dynamodb.ErrCodeResourceNotFoundException:
|
||||
fmt.Println(dynamodb.ErrCodeResourceNotFoundException, aerr.Error())
|
||||
case dynamodb.ErrCodeItemCollectionSizeLimitExceededException:
|
||||
fmt.Println(dynamodb.ErrCodeItemCollectionSizeLimitExceededException, aerr.Error())
|
||||
case dynamodb.ErrCodeInternalServerError:
|
||||
fmt.Println(dynamodb.ErrCodeInternalServerError, aerr.Error())
|
||||
default:
|
||||
fmt.Println(aerr.Error())
|
||||
}
|
||||
} else {
|
||||
// Print the error, cast err to awserr.Error to get the Code and
|
||||
// Message from an error.
|
||||
fmt.Println(err.Error())
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(result)
|
||||
}
|
||||
|
||||
// Using Condition Expression
|
||||
//
|
||||
// This example deletes an item from the Music table if the rating is lower than
|
||||
// 7.
|
||||
func ExampleBuilder_WithCondition() {
|
||||
svc := dynamodb.New(session.New())
|
||||
|
||||
// Create a condition where the Rating field must be less than 7.
|
||||
cond := expression.Name("Rating").LessThan(expression.Value(7))
|
||||
|
||||
// Create a DynamoDB expression from the condition.
|
||||
expr, err := expression.NewBuilder().
|
||||
WithCondition(cond).
|
||||
Build()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
|
||||
// Use the built expression to populate the DeleteItem API operation with the
|
||||
// condition expression.
|
||||
input := &dynamodb.DeleteItemInput{
|
||||
Key: map[string]*dynamodb.AttributeValue{
|
||||
"Artist": {
|
||||
S: aws.String("No One You Know"),
|
||||
},
|
||||
"SongTitle": {
|
||||
S: aws.String("Scared of My Shadow"),
|
||||
},
|
||||
},
|
||||
ExpressionAttributeNames: expr.Names(),
|
||||
ExpressionAttributeValues: expr.Values(),
|
||||
ConditionExpression: expr.Condition(),
|
||||
TableName: aws.String("Music"),
|
||||
}
|
||||
|
||||
result, err := svc.DeleteItem(input)
|
||||
if err != nil {
|
||||
if aerr, ok := err.(awserr.Error); ok {
|
||||
switch aerr.Code() {
|
||||
case dynamodb.ErrCodeConditionalCheckFailedException:
|
||||
fmt.Println(dynamodb.ErrCodeConditionalCheckFailedException, aerr.Error())
|
||||
case dynamodb.ErrCodeProvisionedThroughputExceededException:
|
||||
fmt.Println(dynamodb.ErrCodeProvisionedThroughputExceededException, aerr.Error())
|
||||
case dynamodb.ErrCodeResourceNotFoundException:
|
||||
fmt.Println(dynamodb.ErrCodeResourceNotFoundException, aerr.Error())
|
||||
case dynamodb.ErrCodeItemCollectionSizeLimitExceededException:
|
||||
fmt.Println(dynamodb.ErrCodeItemCollectionSizeLimitExceededException, aerr.Error())
|
||||
case dynamodb.ErrCodeInternalServerError:
|
||||
fmt.Println(dynamodb.ErrCodeInternalServerError, aerr.Error())
|
||||
default:
|
||||
fmt.Println(aerr.Error())
|
||||
}
|
||||
} else {
|
||||
// Print the error, cast err to awserr.Error to get the Code and
|
||||
// Message from an error.
|
||||
fmt.Println(err.Error())
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(result)
|
||||
}
|
||||
635
vendor/github.com/aws/aws-sdk-go/service/dynamodb/expression/expression.go
generated
vendored
Normal file
635
vendor/github.com/aws/aws-sdk-go/service/dynamodb/expression/expression.go
generated
vendored
Normal file
@@ -0,0 +1,635 @@
|
||||
package expression
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/service/dynamodb"
|
||||
)
|
||||
|
||||
// expressionType specifies the type of Expression. Declaring this type is used
|
||||
// to eliminate magic strings
|
||||
type expressionType string
|
||||
|
||||
const (
|
||||
projection expressionType = "projection"
|
||||
keyCondition = "keyCondition"
|
||||
condition = "condition"
|
||||
filter = "filter"
|
||||
update = "update"
|
||||
)
|
||||
|
||||
// Implement the Sort interface
|
||||
type typeList []expressionType
|
||||
|
||||
func (l typeList) Len() int {
|
||||
return len(l)
|
||||
}
|
||||
|
||||
func (l typeList) Less(i, j int) bool {
|
||||
return string(l[i]) < string(l[j])
|
||||
}
|
||||
|
||||
func (l typeList) Swap(i, j int) {
|
||||
l[i], l[j] = l[j], l[i]
|
||||
}
|
||||
|
||||
// Builder represents the struct that builds the Expression struct. Methods such
|
||||
// as WithProjection() and WithCondition() can add different kinds of DynamoDB
|
||||
// Expressions to the Builder. The method Build() creates an Expression struct
|
||||
// with the specified types of DynamoDB Expressions.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// keyCond := expression.Key("someKey").Equal(expression.Value("someValue"))
|
||||
// proj := expression.NamesList(expression.Name("aName"), expression.Name("anotherName"), expression.Name("oneOtherName"))
|
||||
//
|
||||
// builder := expression.NewBuilder().WithKeyCondition(keyCond).WithProjection(proj)
|
||||
// expression := builder.Build()
|
||||
//
|
||||
// queryInput := dynamodb.QueryInput{
|
||||
// KeyConditionExpression: expression.KeyCondition(),
|
||||
// ProjectionExpression: expression.Projection(),
|
||||
// ExpressionAttributeNames: expression.Names(),
|
||||
// ExpressionAttributeValues: expression.Values(),
|
||||
// TableName: aws.String("SomeTable"),
|
||||
// }
|
||||
type Builder struct {
|
||||
expressionMap map[expressionType]treeBuilder
|
||||
}
|
||||
|
||||
// NewBuilder returns an empty Builder struct. Methods such as WithProjection()
|
||||
// and WithCondition() can add different kinds of DynamoDB Expressions to the
|
||||
// Builder. The method Build() creates an Expression struct with the specified
|
||||
// types of DynamoDB Expressions.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// keyCond := expression.Key("someKey").Equal(expression.Value("someValue"))
|
||||
// proj := expression.NamesList(expression.Name("aName"), expression.Name("anotherName"), expression.Name("oneOtherName"))
|
||||
// builder := expression.NewBuilder().WithKeyCondition(keyCond).WithProjection(proj)
|
||||
func NewBuilder() Builder {
|
||||
return Builder{}
|
||||
}
|
||||
|
||||
// Build builds an Expression struct representing multiple types of DynamoDB
|
||||
// Expressions. Getter methods on the resulting Expression struct returns the
|
||||
// DynamoDB Expression strings as well as the maps that correspond to
|
||||
// ExpressionAttributeNames and ExpressionAttributeValues. Calling Build() on an
|
||||
// empty Builder returns the typed error EmptyParameterError.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// // keyCond represents the Key Condition Expression
|
||||
// keyCond := expression.Key("someKey").Equal(expression.Value("someValue"))
|
||||
// // proj represents the Projection Expression
|
||||
// proj := expression.NamesList(expression.Name("aName"), expression.Name("anotherName"), expression.Name("oneOtherName"))
|
||||
//
|
||||
// // Add keyCond and proj to builder as a Key Condition and Projection
|
||||
// // respectively
|
||||
// builder := expression.NewBuilder().WithKeyCondition(keyCond).WithProjection(proj)
|
||||
// expression := builder.Build()
|
||||
//
|
||||
// queryInput := dynamodb.QueryInput{
|
||||
// KeyConditionExpression: expression.KeyCondition(),
|
||||
// ProjectionExpression: expression.Projection(),
|
||||
// ExpressionAttributeNames: expression.Names(),
|
||||
// ExpressionAttributeValues: expression.Values(),
|
||||
// TableName: aws.String("SomeTable"),
|
||||
// }
|
||||
func (b Builder) Build() (Expression, error) {
|
||||
if b.expressionMap == nil {
|
||||
return Expression{}, newUnsetParameterError("Build", "Builder")
|
||||
}
|
||||
|
||||
aliasList, expressionMap, err := b.buildChildTrees()
|
||||
if err != nil {
|
||||
return Expression{}, err
|
||||
}
|
||||
|
||||
expression := Expression{
|
||||
expressionMap: expressionMap,
|
||||
}
|
||||
|
||||
if len(aliasList.namesList) != 0 {
|
||||
namesMap := map[string]*string{}
|
||||
for ind, val := range aliasList.namesList {
|
||||
namesMap[fmt.Sprintf("#%v", ind)] = aws.String(val)
|
||||
}
|
||||
expression.namesMap = namesMap
|
||||
}
|
||||
|
||||
if len(aliasList.valuesList) != 0 {
|
||||
valuesMap := map[string]*dynamodb.AttributeValue{}
|
||||
for i := 0; i < len(aliasList.valuesList); i++ {
|
||||
valuesMap[fmt.Sprintf(":%v", i)] = &aliasList.valuesList[i]
|
||||
}
|
||||
expression.valuesMap = valuesMap
|
||||
}
|
||||
|
||||
return expression, nil
|
||||
}
|
||||
|
||||
// buildChildTrees compiles the list of treeBuilders that are the children of
|
||||
// the argument Builder. The returned aliasList represents all the alias tokens
|
||||
// used in the expression strings. The returned map[string]string maps the type
|
||||
// of expression (i.e. "condition", "update") to the appropriate expression
|
||||
// string.
|
||||
func (b Builder) buildChildTrees() (aliasList, map[expressionType]string, error) {
|
||||
aList := aliasList{}
|
||||
formattedExpressions := map[expressionType]string{}
|
||||
keys := typeList{}
|
||||
|
||||
for expressionType := range b.expressionMap {
|
||||
keys = append(keys, expressionType)
|
||||
}
|
||||
|
||||
sort.Sort(keys)
|
||||
|
||||
for _, key := range keys {
|
||||
node, err := b.expressionMap[key].buildTree()
|
||||
if err != nil {
|
||||
return aliasList{}, nil, err
|
||||
}
|
||||
formattedExpression, err := node.buildExpressionString(&aList)
|
||||
if err != nil {
|
||||
return aliasList{}, nil, err
|
||||
}
|
||||
formattedExpressions[key] = formattedExpression
|
||||
}
|
||||
|
||||
return aList, formattedExpressions, nil
|
||||
}
|
||||
|
||||
// WithCondition method adds the argument ConditionBuilder as a Condition
|
||||
// Expression to the argument Builder. If the argument Builder already has a
|
||||
// ConditionBuilder representing a Condition Expression, WithCondition()
|
||||
// overwrites the existing ConditionBuilder.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// // let builder be an existing Builder{} and cond be an existing
|
||||
// // ConditionBuilder{}
|
||||
// builder = builder.WithCondition(cond)
|
||||
//
|
||||
// // add other DynamoDB Expressions to the builder. let proj be an already
|
||||
// // existing ProjectionBuilder
|
||||
// builder = builder.WithProjection(proj)
|
||||
// // create an Expression struct
|
||||
// expression := builder.Build()
|
||||
func (b Builder) WithCondition(conditionBuilder ConditionBuilder) Builder {
|
||||
if b.expressionMap == nil {
|
||||
b.expressionMap = map[expressionType]treeBuilder{}
|
||||
}
|
||||
b.expressionMap[condition] = conditionBuilder
|
||||
return b
|
||||
}
|
||||
|
||||
// WithProjection method adds the argument ProjectionBuilder as a Projection
|
||||
// Expression to the argument Builder. If the argument Builder already has a
|
||||
// ProjectionBuilder representing a Projection Expression, WithProjection()
|
||||
// overwrites the existing ProjectionBuilder.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// // let builder be an existing Builder{} and proj be an existing
|
||||
// // ProjectionBuilder{}
|
||||
// builder = builder.WithProjection(proj)
|
||||
//
|
||||
// // add other DynamoDB Expressions to the builder. let cond be an already
|
||||
// // existing ConditionBuilder
|
||||
// builder = builder.WithCondition(cond)
|
||||
// // create an Expression struct
|
||||
// expression := builder.Build()
|
||||
func (b Builder) WithProjection(projectionBuilder ProjectionBuilder) Builder {
|
||||
if b.expressionMap == nil {
|
||||
b.expressionMap = map[expressionType]treeBuilder{}
|
||||
}
|
||||
b.expressionMap[projection] = projectionBuilder
|
||||
return b
|
||||
}
|
||||
|
||||
// WithKeyCondition method adds the argument KeyConditionBuilder as a Key
|
||||
// Condition Expression to the argument Builder. If the argument Builder already
|
||||
// has a KeyConditionBuilder representing a Key Condition Expression,
|
||||
// WithKeyCondition() overwrites the existing KeyConditionBuilder.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// // let builder be an existing Builder{} and keyCond be an existing
|
||||
// // KeyConditionBuilder{}
|
||||
// builder = builder.WithKeyCondition(keyCond)
|
||||
//
|
||||
// // add other DynamoDB Expressions to the builder. let cond be an already
|
||||
// // existing ConditionBuilder
|
||||
// builder = builder.WithCondition(cond)
|
||||
// // create an Expression struct
|
||||
// expression := builder.Build()
|
||||
func (b Builder) WithKeyCondition(keyConditionBuilder KeyConditionBuilder) Builder {
|
||||
if b.expressionMap == nil {
|
||||
b.expressionMap = map[expressionType]treeBuilder{}
|
||||
}
|
||||
b.expressionMap[keyCondition] = keyConditionBuilder
|
||||
return b
|
||||
}
|
||||
|
||||
// WithFilter method adds the argument ConditionBuilder as a Filter Expression
|
||||
// to the argument Builder. If the argument Builder already has a
|
||||
// ConditionBuilder representing a Filter Expression, WithFilter()
|
||||
// overwrites the existing ConditionBuilder.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// // let builder be an existing Builder{} and filt be an existing
|
||||
// // ConditionBuilder{}
|
||||
// builder = builder.WithFilter(filt)
|
||||
//
|
||||
// // add other DynamoDB Expressions to the builder. let cond be an already
|
||||
// // existing ConditionBuilder
|
||||
// builder = builder.WithCondition(cond)
|
||||
// // create an Expression struct
|
||||
// expression := builder.Build()
|
||||
func (b Builder) WithFilter(filterBuilder ConditionBuilder) Builder {
|
||||
if b.expressionMap == nil {
|
||||
b.expressionMap = map[expressionType]treeBuilder{}
|
||||
}
|
||||
b.expressionMap[filter] = filterBuilder
|
||||
return b
|
||||
}
|
||||
|
||||
// WithUpdate method adds the argument UpdateBuilder as an Update Expression
|
||||
// to the argument Builder. If the argument Builder already has a UpdateBuilder
|
||||
// representing a Update Expression, WithUpdate() overwrites the existing
|
||||
// UpdateBuilder.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// // let builder be an existing Builder{} and update be an existing
|
||||
// // UpdateBuilder{}
|
||||
// builder = builder.WithUpdate(update)
|
||||
//
|
||||
// // add other DynamoDB Expressions to the builder. let cond be an already
|
||||
// // existing ConditionBuilder
|
||||
// builder = builder.WithCondition(cond)
|
||||
// // create an Expression struct
|
||||
// expression := builder.Build()
|
||||
func (b Builder) WithUpdate(updateBuilder UpdateBuilder) Builder {
|
||||
if b.expressionMap == nil {
|
||||
b.expressionMap = map[expressionType]treeBuilder{}
|
||||
}
|
||||
b.expressionMap[update] = updateBuilder
|
||||
return b
|
||||
}
|
||||
|
||||
// Expression represents a collection of DynamoDB Expressions. The getter
|
||||
// methods of the Expression struct retrieves the formatted DynamoDB
|
||||
// Expressions, ExpressionAttributeNames, and ExpressionAttributeValues.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// // keyCond represents the Key Condition Expression
|
||||
// keyCond := expression.Key("someKey").Equal(expression.Value("someValue"))
|
||||
// // proj represents the Projection Expression
|
||||
// proj := expression.NamesList(expression.Name("aName"), expression.Name("anotherName"), expression.Name("oneOtherName"))
|
||||
//
|
||||
// // Add keyCond and proj to builder as a Key Condition and Projection
|
||||
// // respectively
|
||||
// builder := expression.NewBuilder().WithKeyCondition(keyCond).WithProjection(proj)
|
||||
// expression := builder.Build()
|
||||
//
|
||||
// queryInput := dynamodb.QueryInput{
|
||||
// KeyConditionExpression: expression.KeyCondition(),
|
||||
// ProjectionExpression: expression.Projection(),
|
||||
// ExpressionAttributeNames: expression.Names(),
|
||||
// ExpressionAttributeValues: expression.Values(),
|
||||
// TableName: aws.String("SomeTable"),
|
||||
// }
|
||||
type Expression struct {
|
||||
expressionMap map[expressionType]string
|
||||
namesMap map[string]*string
|
||||
valuesMap map[string]*dynamodb.AttributeValue
|
||||
}
|
||||
|
||||
// treeBuilder interface is fulfilled by builder structs that represent
|
||||
// different types of Expressions.
|
||||
type treeBuilder interface {
|
||||
// buildTree creates the tree structure of exprNodes. The tree structure
|
||||
// of exprNodes are traversed in order to build the string representing
|
||||
// different types of Expressions as well as the maps that represent
|
||||
// ExpressionAttributeNames and ExpressionAttributeValues.
|
||||
buildTree() (exprNode, error)
|
||||
}
|
||||
|
||||
// Condition returns the *string corresponding to the Condition Expression
|
||||
// of the argument Expression. This method is used to satisfy the members of
|
||||
// DynamoDB input structs. If the Expression does not have a condition
|
||||
// expression this method returns nil.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// // let expression be an instance of Expression{}
|
||||
//
|
||||
// deleteInput := dynamodb.DeleteItemInput{
|
||||
// ConditionExpression: expression.Condition(),
|
||||
// ExpressionAttributeNames: expression.Names(),
|
||||
// ExpressionAttributeValues: expression.Values(),
|
||||
// Key: map[string]*dynamodb.AttributeValue{
|
||||
// "PartitionKey": &dynamodb.AttributeValue{
|
||||
// S: aws.String("SomeKey"),
|
||||
// },
|
||||
// },
|
||||
// TableName: aws.String("SomeTable"),
|
||||
// }
|
||||
func (e Expression) Condition() *string {
|
||||
return e.returnExpression(condition)
|
||||
}
|
||||
|
||||
// Filter returns the *string corresponding to the Filter Expression of the
|
||||
// argument Expression. This method is used to satisfy the members of DynamoDB
|
||||
// input structs. If the Expression does not have a filter expression this
|
||||
// method returns nil.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// // let expression be an instance of Expression{}
|
||||
//
|
||||
// queryInput := dynamodb.QueryInput{
|
||||
// KeyConditionExpression: expression.KeyCondition(),
|
||||
// FilterExpression: expression.Filter(),
|
||||
// ExpressionAttributeNames: expression.Names(),
|
||||
// ExpressionAttributeValues: expression.Values(),
|
||||
// TableName: aws.String("SomeTable"),
|
||||
// }
|
||||
func (e Expression) Filter() *string {
|
||||
return e.returnExpression(filter)
|
||||
}
|
||||
|
||||
// Projection returns the *string corresponding to the Projection Expression
|
||||
// of the argument Expression. This method is used to satisfy the members of
|
||||
// DynamoDB input structs. If the Expression does not have a projection
|
||||
// expression this method returns nil.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// // let expression be an instance of Expression{}
|
||||
//
|
||||
// queryInput := dynamodb.QueryInput{
|
||||
// KeyConditionExpression: expression.KeyCondition(),
|
||||
// ProjectionExpression: expression.Projection(),
|
||||
// ExpressionAttributeNames: expression.Names(),
|
||||
// ExpressionAttributeValues: expression.Values(),
|
||||
// TableName: aws.String("SomeTable"),
|
||||
// }
|
||||
func (e Expression) Projection() *string {
|
||||
return e.returnExpression(projection)
|
||||
}
|
||||
|
||||
// KeyCondition returns the *string corresponding to the Key Condition
|
||||
// Expression of the argument Expression. This method is used to satisfy the
|
||||
// members of DynamoDB input structs. If the argument Expression does not have a
|
||||
// KeyConditionExpression, KeyCondition() returns nil.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// // let expression be an instance of Expression{}
|
||||
//
|
||||
// queryInput := dynamodb.QueryInput{
|
||||
// KeyConditionExpression: expression.KeyCondition(),
|
||||
// ProjectionExpression: expression.Projection(),
|
||||
// ExpressionAttributeNames: expression.Names(),
|
||||
// ExpressionAttributeValues: expression.Values(),
|
||||
// TableName: aws.String("SomeTable"),
|
||||
// }
|
||||
func (e Expression) KeyCondition() *string {
|
||||
return e.returnExpression(keyCondition)
|
||||
}
|
||||
|
||||
// Update returns the *string corresponding to the Update Expression of the
|
||||
// argument Expression. This method is used to satisfy the members of DynamoDB
|
||||
// input structs. If the argument Expression does not have a UpdateExpression,
|
||||
// Update() returns nil.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// // let expression be an instance of Expression{}
|
||||
//
|
||||
// updateInput := dynamodb.UpdateInput{
|
||||
// Key: map[string]*dynamodb.AttributeValue{
|
||||
// "PartitionKey": {
|
||||
// S: aws.String("someKey"),
|
||||
// },
|
||||
// },
|
||||
// UpdateExpression: expression.Update(),
|
||||
// ExpressionAttributeNames: expression.Names(),
|
||||
// ExpressionAttributeValues: expression.Values(),
|
||||
// TableName: aws.String("SomeTable"),
|
||||
// }
|
||||
func (e Expression) Update() *string {
|
||||
return e.returnExpression(update)
|
||||
}
|
||||
|
||||
// Names returns the map[string]*string corresponding to the
|
||||
// ExpressionAttributeNames of the argument Expression. This method is used to
|
||||
// satisfy the members of DynamoDB input structs. If Expression does not use
|
||||
// ExpressionAttributeNames, this method returns nil. The
|
||||
// ExpressionAttributeNames and ExpressionAttributeValues member of the input
|
||||
// struct must always be assigned when using the Expression struct since all
|
||||
// item attribute names and values are aliased. That means that if the
|
||||
// ExpressionAttributeNames and ExpressionAttributeValues member is not assigned
|
||||
// with the corresponding Names() and Values() methods, the DynamoDB operation
|
||||
// will run into a logic error.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// // let expression be an instance of Expression{}
|
||||
//
|
||||
// queryInput := dynamodb.QueryInput{
|
||||
// KeyConditionExpression: expression.KeyCondition(),
|
||||
// ProjectionExpression: expression.Projection(),
|
||||
// ExpressionAttributeNames: expression.Names(),
|
||||
// ExpressionAttributeValues: expression.Values(),
|
||||
// TableName: aws.String("SomeTable"),
|
||||
// }
|
||||
func (e Expression) Names() map[string]*string {
|
||||
return e.namesMap
|
||||
}
|
||||
|
||||
// Values returns the map[string]*dynamodb.AttributeValue corresponding to
|
||||
// the ExpressionAttributeValues of the argument Expression. This method is used
|
||||
// to satisfy the members of DynamoDB input structs. If Expression does not use
|
||||
// ExpressionAttributeValues, this method returns nil. The
|
||||
// ExpressionAttributeNames and ExpressionAttributeValues member of the input
|
||||
// struct must always be assigned when using the Expression struct since all
|
||||
// item attribute names and values are aliased. That means that if the
|
||||
// ExpressionAttributeNames and ExpressionAttributeValues member is not assigned
|
||||
// with the corresponding Names() and Values() methods, the DynamoDB operation
|
||||
// will run into a logic error.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// // let expression be an instance of Expression{}
|
||||
//
|
||||
// queryInput := dynamodb.QueryInput{
|
||||
// KeyConditionExpression: expression.KeyCondition(),
|
||||
// ProjectionExpression: expression.Projection(),
|
||||
// ExpressionAttributeNames: expression.Names(),
|
||||
// ExpressionAttributeValues: expression.Values(),
|
||||
// TableName: aws.String("SomeTable"),
|
||||
// }
|
||||
func (e Expression) Values() map[string]*dynamodb.AttributeValue {
|
||||
return e.valuesMap
|
||||
}
|
||||
|
||||
// returnExpression returns *string corresponding to the type of Expression
|
||||
// string specified by the expressionType. If there is no corresponding
|
||||
// expression available in Expression, the method returns nil
|
||||
func (e Expression) returnExpression(expressionType expressionType) *string {
|
||||
if e.expressionMap == nil {
|
||||
return nil
|
||||
}
|
||||
return aws.String(e.expressionMap[expressionType])
|
||||
}
|
||||
|
||||
// exprNode are the generic nodes that represents both Operands and
|
||||
// Conditions. The purpose of exprNode is to be able to call an generic
|
||||
// recursive function on the top level exprNode to be able to determine a root
|
||||
// node in order to deduplicate name aliases.
|
||||
// fmtExpr is a string that has escaped characters to refer to
|
||||
// names/values/children which needs to be aliased at runtime in order to avoid
|
||||
// duplicate values. The rules are as follows:
|
||||
// $n: Indicates that an alias of a name needs to be inserted. The
|
||||
// corresponding name to be alias is in the []names slice.
|
||||
// $v: Indicates that an alias of a value needs to be inserted. The
|
||||
// corresponding value to be alias is in the []values slice.
|
||||
// $c: Indicates that the fmtExpr of a child exprNode needs to be inserted.
|
||||
// The corresponding child node is in the []children slice.
|
||||
type exprNode struct {
|
||||
names []string
|
||||
values []dynamodb.AttributeValue
|
||||
children []exprNode
|
||||
fmtExpr string
|
||||
}
|
||||
|
||||
// aliasList keeps track of all the names we need to alias in the nested
|
||||
// struct of conditions and operands. This allows each alias to be unique.
|
||||
// aliasList is passed in as a pointer when buildChildTrees is called in
|
||||
// order to deduplicate all names within the tree strcuture of the exprNodes.
|
||||
type aliasList struct {
|
||||
namesList []string
|
||||
valuesList []dynamodb.AttributeValue
|
||||
}
|
||||
|
||||
// buildExpressionString returns a string with aliasing for names/values
|
||||
// specified by aliasList. The string corresponds to the expression that the
|
||||
// exprNode tree represents.
|
||||
func (en exprNode) buildExpressionString(aliasList *aliasList) (string, error) {
|
||||
// Since each exprNode contains a slice of names, values, and children that
|
||||
// correspond to the escaped characters, we an index to traverse the slices
|
||||
index := struct {
|
||||
name, value, children int
|
||||
}{}
|
||||
|
||||
formattedExpression := en.fmtExpr
|
||||
|
||||
for i := 0; i < len(formattedExpression); {
|
||||
if formattedExpression[i] != '$' {
|
||||
i++
|
||||
continue
|
||||
}
|
||||
|
||||
if i == len(formattedExpression)-1 {
|
||||
return "", fmt.Errorf("buildexprNode error: invalid escape character")
|
||||
}
|
||||
|
||||
var alias string
|
||||
var err error
|
||||
// if an escaped character is found, substitute it with the proper alias
|
||||
// TODO consider AST instead of string in the future
|
||||
switch formattedExpression[i+1] {
|
||||
case 'n':
|
||||
alias, err = substitutePath(index.name, en, aliasList)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
index.name++
|
||||
|
||||
case 'v':
|
||||
alias, err = substituteValue(index.value, en, aliasList)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
index.value++
|
||||
|
||||
case 'c':
|
||||
alias, err = substituteChild(index.children, en, aliasList)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
index.children++
|
||||
|
||||
default:
|
||||
return "", fmt.Errorf("buildexprNode error: invalid escape rune %#v", formattedExpression[i+1])
|
||||
}
|
||||
formattedExpression = formattedExpression[:i] + alias + formattedExpression[i+2:]
|
||||
i += len(alias)
|
||||
}
|
||||
|
||||
return formattedExpression, nil
|
||||
}
|
||||
|
||||
// substitutePath substitutes the escaped character $n with the appropriate
|
||||
// alias.
|
||||
func substitutePath(index int, node exprNode, aliasList *aliasList) (string, error) {
|
||||
if index >= len(node.names) {
|
||||
return "", fmt.Errorf("substitutePath error: exprNode []names out of range")
|
||||
}
|
||||
str, err := aliasList.aliasPath(node.names[index])
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return str, nil
|
||||
}
|
||||
|
||||
// substituteValue substitutes the escaped character $v with the appropriate
|
||||
// alias.
|
||||
func substituteValue(index int, node exprNode, aliasList *aliasList) (string, error) {
|
||||
if index >= len(node.values) {
|
||||
return "", fmt.Errorf("substituteValue error: exprNode []values out of range")
|
||||
}
|
||||
str, err := aliasList.aliasValue(node.values[index])
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return str, nil
|
||||
}
|
||||
|
||||
// substituteChild substitutes the escaped character $c with the appropriate
|
||||
// alias.
|
||||
func substituteChild(index int, node exprNode, aliasList *aliasList) (string, error) {
|
||||
if index >= len(node.children) {
|
||||
return "", fmt.Errorf("substituteChild error: exprNode []children out of range")
|
||||
}
|
||||
return node.children[index].buildExpressionString(aliasList)
|
||||
}
|
||||
|
||||
// aliasValue returns the corresponding alias to the dav value argument. Since
|
||||
// values are not deduplicated as of now, all values are just appended to the
|
||||
// aliasList and given the index as the alias.
|
||||
func (al *aliasList) aliasValue(dav dynamodb.AttributeValue) (string, error) {
|
||||
al.valuesList = append(al.valuesList, dav)
|
||||
return fmt.Sprintf(":%d", len(al.valuesList)-1), nil
|
||||
}
|
||||
|
||||
// aliasPath returns the corresponding alias to the argument string. The
|
||||
// argument is checked against all existing aliasList names in order to avoid
|
||||
// duplicate strings getting two different aliases.
|
||||
func (al *aliasList) aliasPath(nm string) (string, error) {
|
||||
for ind, name := range al.namesList {
|
||||
if nm == name {
|
||||
return fmt.Sprintf("#%d", ind), nil
|
||||
}
|
||||
}
|
||||
al.namesList = append(al.namesList, nm)
|
||||
return fmt.Sprintf("#%d", len(al.namesList)-1), nil
|
||||
}
|
||||
1082
vendor/github.com/aws/aws-sdk-go/service/dynamodb/expression/expression_test.go
generated
vendored
Normal file
1082
vendor/github.com/aws/aws-sdk-go/service/dynamodb/expression/expression_test.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
557
vendor/github.com/aws/aws-sdk-go/service/dynamodb/expression/key_condition.go
generated
vendored
Normal file
557
vendor/github.com/aws/aws-sdk-go/service/dynamodb/expression/key_condition.go
generated
vendored
Normal file
@@ -0,0 +1,557 @@
|
||||
package expression
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// keyConditionMode specifies the types of the struct KeyConditionBuilder,
|
||||
// representing the different types of KeyConditions (i.e. And, Or, Between, ...)
|
||||
type keyConditionMode int
|
||||
|
||||
const (
|
||||
// unsetKeyCond catches errors for unset KeyConditionBuilder structs
|
||||
unsetKeyCond keyConditionMode = iota
|
||||
// equalKeyCond represents the Equals KeyCondition
|
||||
equalKeyCond
|
||||
// lessThanKeyCond represents the Less Than KeyCondition
|
||||
lessThanKeyCond
|
||||
// lessThanEqualKeyCond represents the Less Than Or Equal To KeyCondition
|
||||
lessThanEqualKeyCond
|
||||
// greaterThanKeyCond represents the Greater Than KeyCondition
|
||||
greaterThanKeyCond
|
||||
// greaterThanEqualKeyCond represents the Greater Than Or Equal To KeyCondition
|
||||
greaterThanEqualKeyCond
|
||||
// andKeyCond represents the Logical And KeyCondition
|
||||
andKeyCond
|
||||
// betweenKeyCond represents the Between KeyCondition
|
||||
betweenKeyCond
|
||||
// beginsWithKeyCond represents the Begins With KeyCondition
|
||||
beginsWithKeyCond
|
||||
)
|
||||
|
||||
// KeyConditionBuilder represents Key Condition Expressions in DynamoDB.
|
||||
// KeyConditionBuilders are the building blocks of Expressions.
|
||||
// More Information at: http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Query.html#Query.KeyConditionExpressions
|
||||
type KeyConditionBuilder struct {
|
||||
operandList []OperandBuilder
|
||||
keyConditionList []KeyConditionBuilder
|
||||
mode keyConditionMode
|
||||
}
|
||||
|
||||
// KeyEqual returns a KeyConditionBuilder representing the equality clause
|
||||
// of the two argument OperandBuilders. The resulting KeyConditionBuilder can be
|
||||
// used as a part of other Key Condition Expressions or as an argument to the
|
||||
// WithKeyCondition() method for the Builder struct.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// // keyCondition represents the equal clause of the key "foo" and the
|
||||
// // value 5
|
||||
// keyCondition := expression.KeyEqual(expression.Key("foo"), expression.Value(5))
|
||||
//
|
||||
// // Used in another Key Condition Expression
|
||||
// anotherKeyCondition := expression.Key("partitionKey").Equal(expression.Value("aValue")).And(keyCondition)
|
||||
// // Used to make an Builder
|
||||
// builder := expression.NewBuilder().WithKeyCondition(keyCondition)
|
||||
//
|
||||
// Expression Equivalent:
|
||||
//
|
||||
// expression.KeyEqual(expression.Key("foo"), expression.Value(5))
|
||||
// // Let :five be an ExpressionAttributeValue representing the value 5
|
||||
// "foo = :five"
|
||||
func KeyEqual(keyBuilder KeyBuilder, valueBuilder ValueBuilder) KeyConditionBuilder {
|
||||
return KeyConditionBuilder{
|
||||
operandList: []OperandBuilder{keyBuilder, valueBuilder},
|
||||
mode: equalKeyCond,
|
||||
}
|
||||
}
|
||||
|
||||
// Equal returns a KeyConditionBuilder representing the equality clause of
|
||||
// the two argument OperandBuilders. The resulting KeyConditionBuilder can be
|
||||
// used as a part of other Key Condition Expressions or as an argument to the
|
||||
// WithKeyCondition() method for the Builder struct.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// // keyCondition represents the equal clause of the key "foo" and the
|
||||
// // value 5
|
||||
// keyCondition := expression.Key("foo").Equal(expression.Value(5))
|
||||
//
|
||||
// // Used in another Key Condition Expression
|
||||
// anotherKeyCondition := expression.Key("partitionKey").Equal(expression.Value("aValue")).And(keyCondition)
|
||||
// // Used to make an Builder
|
||||
// builder := expression.NewBuilder().WithKeyCondition(keyCondition)
|
||||
//
|
||||
// Expression Equivalent:
|
||||
//
|
||||
// expression.Key("foo").Equal(expression.Value(5))
|
||||
// // Let :five be an ExpressionAttributeValue representing the value 5
|
||||
// "foo = :five"
|
||||
func (kb KeyBuilder) Equal(valueBuilder ValueBuilder) KeyConditionBuilder {
|
||||
return KeyEqual(kb, valueBuilder)
|
||||
}
|
||||
|
||||
// KeyLessThan returns a KeyConditionBuilder representing the less than
|
||||
// clause of the two argument OperandBuilders. The resulting KeyConditionBuilder
|
||||
// can be used as a part of other Key Condition Expressions.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// // keyCondition represents the less than clause of the key "foo" and the
|
||||
// // value 5
|
||||
// keyCondition := expression.KeyLessThan(expression.Key("foo"), expression.Value(5))
|
||||
//
|
||||
// // Used in another Key Condition Expression
|
||||
// anotherKeyCondition := expression.Key("partitionKey").Equal(expression.Value("aValue")).And(keyCondition)
|
||||
//
|
||||
// Expression Equivalent:
|
||||
//
|
||||
// expression.KeyLessThan(expression.Key("foo"), expression.Value(5))
|
||||
// // Let :five be an ExpressionAttributeValue representing the value 5
|
||||
// "foo < :five"
|
||||
func KeyLessThan(keyBuilder KeyBuilder, valueBuilder ValueBuilder) KeyConditionBuilder {
|
||||
return KeyConditionBuilder{
|
||||
operandList: []OperandBuilder{keyBuilder, valueBuilder},
|
||||
mode: lessThanKeyCond,
|
||||
}
|
||||
}
|
||||
|
||||
// LessThan returns a KeyConditionBuilder representing the less than clause
|
||||
// of the two argument OperandBuilders. The resulting KeyConditionBuilder can be
|
||||
// used as a part of other Key Condition Expressions.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// // keyCondition represents the less than clause of the key "foo" and the
|
||||
// // value 5
|
||||
// keyCondition := expression.Key("foo").LessThan(expression.Value(5))
|
||||
//
|
||||
// // Used in another Key Condition Expression
|
||||
// anotherKeyCondition := expression.Key("partitionKey").Equal(expression.Value("aValue")).And(keyCondition)
|
||||
//
|
||||
// Expression Equivalent:
|
||||
//
|
||||
// expression.Key("foo").LessThan(expression.Value(5))
|
||||
// // Let :five be an ExpressionAttributeValue representing the value 5
|
||||
// "foo < :five"
|
||||
func (kb KeyBuilder) LessThan(valueBuilder ValueBuilder) KeyConditionBuilder {
|
||||
return KeyLessThan(kb, valueBuilder)
|
||||
}
|
||||
|
||||
// KeyLessThanEqual returns a KeyConditionBuilder representing the less than
|
||||
// equal to clause of the two argument OperandBuilders. The resulting
|
||||
// KeyConditionBuilder can be used as a part of other Key Condition Expressions.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// // keyCondition represents the less than equal to clause of the key
|
||||
// // "foo" and the value 5
|
||||
// keyCondition := expression.KeyLessThanEqual(expression.Key("foo"), expression.Value(5))
|
||||
//
|
||||
// // Used in another Key Condition Expression
|
||||
// anotherKeyCondition := expression.Key("partitionKey").Equal(expression.Value("aValue")).And(keyCondition)
|
||||
//
|
||||
// Expression Equivalent:
|
||||
//
|
||||
// expression.KeyLessThanEqual(expression.Key("foo"), expression.Value(5))
|
||||
// // Let :five be an ExpressionAttributeValue representing the value 5
|
||||
// "foo <= :five"
|
||||
func KeyLessThanEqual(keyBuilder KeyBuilder, valueBuilder ValueBuilder) KeyConditionBuilder {
|
||||
return KeyConditionBuilder{
|
||||
operandList: []OperandBuilder{keyBuilder, valueBuilder},
|
||||
mode: lessThanEqualKeyCond,
|
||||
}
|
||||
}
|
||||
|
||||
// LessThanEqual returns a KeyConditionBuilder representing the less than
|
||||
// equal to clause of the two argument OperandBuilders. The resulting
|
||||
// KeyConditionBuilder can be used as a part of other Key Condition Expressions.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// // keyCondition represents the less than equal to clause of the key
|
||||
// // "foo" and the value 5
|
||||
// keyCondition := expression.Key("foo").LessThanEqual(expression.Value(5))
|
||||
//
|
||||
// // Used in another Key Condition Expression
|
||||
// anotherKeyCondition := expression.Key("partitionKey").Equal(expression.Value("aValue")).And(keyCondition)
|
||||
//
|
||||
// Expression Equivalent:
|
||||
//
|
||||
// expression.Key("foo").LessThanEqual(expression.Value(5))
|
||||
// // Let :five be an ExpressionAttributeValue representing the value 5
|
||||
// "foo <= :five"
|
||||
func (kb KeyBuilder) LessThanEqual(valueBuilder ValueBuilder) KeyConditionBuilder {
|
||||
return KeyLessThanEqual(kb, valueBuilder)
|
||||
}
|
||||
|
||||
// KeyGreaterThan returns a KeyConditionBuilder representing the greater
|
||||
// than clause of the two argument OperandBuilders. The resulting
|
||||
// KeyConditionBuilder can be used as a part of other Key Condition Expressions.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// // keyCondition represents the greater than clause of the key "foo" and
|
||||
// // the value 5
|
||||
// keyCondition := expression.KeyGreaterThan(expression.Key("foo"), expression.Value(5))
|
||||
//
|
||||
// // Used in another Key Condition Expression
|
||||
// anotherKeyCondition := expression.Key("partitionKey").Equal(expression.Value("aValue")).And(keyCondition)
|
||||
//
|
||||
// Expression Equivalent:
|
||||
//
|
||||
// expression.KeyGreaterThan(expression.Key("foo"), expression.Value(5))
|
||||
// // Let :five be an ExpressionAttributeValue representing the value 5
|
||||
// "foo > :five"
|
||||
func KeyGreaterThan(keyBuilder KeyBuilder, valueBuilder ValueBuilder) KeyConditionBuilder {
|
||||
return KeyConditionBuilder{
|
||||
operandList: []OperandBuilder{keyBuilder, valueBuilder},
|
||||
mode: greaterThanKeyCond,
|
||||
}
|
||||
}
|
||||
|
||||
// GreaterThan returns a KeyConditionBuilder representing the greater than
|
||||
// clause of the two argument OperandBuilders. The resulting KeyConditionBuilder
|
||||
// can be used as a part of other Key Condition Expressions.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// // key condition represents the greater than clause of the key "foo" and
|
||||
// // the value 5
|
||||
// keyCondition := expression.Key("foo").GreaterThan(expression.Value(5))
|
||||
//
|
||||
// // Used in another Key Condition Expression
|
||||
// anotherKeyCondition := expression.Key("partitionKey").Equal(expression.Value("aValue")).And(keyCondition)
|
||||
//
|
||||
// Expression Equivalent:
|
||||
//
|
||||
// expression.Key("foo").GreaterThan(expression.Value(5))
|
||||
// // Let :five be an ExpressionAttributeValue representing the value 5
|
||||
// "foo > :five"
|
||||
func (kb KeyBuilder) GreaterThan(valueBuilder ValueBuilder) KeyConditionBuilder {
|
||||
return KeyGreaterThan(kb, valueBuilder)
|
||||
}
|
||||
|
||||
// KeyGreaterThanEqual returns a KeyConditionBuilder representing the
|
||||
// greater than equal to clause of the two argument OperandBuilders. The
|
||||
// resulting KeyConditionBuilder can be used as a part of other Key Condition
|
||||
// Expressions.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// // keyCondition represents the greater than equal to clause of the key
|
||||
// // "foo" and the value 5
|
||||
// keyCondition := expression.KeyGreaterThanEqual(expression.Key("foo"), expression.Value(5))
|
||||
//
|
||||
// // Used in another Key Condition Expression
|
||||
// anotherKeyCondition := expression.Key("partitionKey").Equal(expression.Value("aValue")).And(keyCondition)
|
||||
//
|
||||
// Expression Equivalent:
|
||||
//
|
||||
// expression.KeyGreaterThanEqual(expression.Key("foo"), expression.Value(5))
|
||||
// // Let :five be an ExpressionAttributeValue representing the value 5
|
||||
// "foo >= :five"
|
||||
func KeyGreaterThanEqual(keyBuilder KeyBuilder, valueBuilder ValueBuilder) KeyConditionBuilder {
|
||||
return KeyConditionBuilder{
|
||||
operandList: []OperandBuilder{keyBuilder, valueBuilder},
|
||||
mode: greaterThanEqualKeyCond,
|
||||
}
|
||||
}
|
||||
|
||||
// GreaterThanEqual returns a KeyConditionBuilder representing the greater
|
||||
// than equal to clause of the two argument OperandBuilders. The resulting
|
||||
// KeyConditionBuilder can be used as a part of other Key Condition Expressions.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// // keyCondition represents the greater than equal to clause of the key
|
||||
// // "foo" and the value 5
|
||||
// keyCondition := expression.Key("foo").GreaterThanEqual(expression.Value(5))
|
||||
//
|
||||
// // Used in another Key Condition Expression
|
||||
// anotherKeyCondition := expression.Key("partitionKey").Equal(expression.Value("aValue")).And(keyCondition)
|
||||
//
|
||||
// Expression Equivalent:
|
||||
//
|
||||
// expression.Key("foo").GreaterThanEqual(expression.Value(5))
|
||||
// // Let :five be an ExpressionAttributeValue representing the value 5
|
||||
// "foo >= :five"
|
||||
func (kb KeyBuilder) GreaterThanEqual(valueBuilder ValueBuilder) KeyConditionBuilder {
|
||||
return KeyGreaterThanEqual(kb, valueBuilder)
|
||||
}
|
||||
|
||||
// KeyAnd returns a KeyConditionBuilder representing the logical AND clause
|
||||
// of the two argument KeyConditionBuilders. The resulting KeyConditionBuilder
|
||||
// can be used as an argument to the WithKeyCondition() method for the Builder
|
||||
// struct.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// // keyCondition represents the key condition where the partition key
|
||||
// // "TeamName" is equal to value "Wildcats" and sort key "Number" is equal
|
||||
// // to value 1
|
||||
// keyCondition := expression.KeyAnd(expression.Key("TeamName").Equal(expression.Value("Wildcats")), expression.Key("Number").Equal(expression.Value(1)))
|
||||
//
|
||||
// // Used to make an Builder
|
||||
// builder := expression.NewBuilder().WithKeyCondition(keyCondition)
|
||||
//
|
||||
// Expression Equivalent:
|
||||
//
|
||||
// expression.KeyAnd(expression.Key("TeamName").Equal(expression.Value("Wildcats")), expression.Key("Number").Equal(expression.Value(1)))
|
||||
// // Let #NUMBER, :teamName, and :one be ExpressionAttributeName and
|
||||
// // ExpressionAttributeValues representing the item attribute "Number",
|
||||
// // the value "Wildcats", and the value 1
|
||||
// "(TeamName = :teamName) AND (#NUMBER = :one)"
|
||||
func KeyAnd(left, right KeyConditionBuilder) KeyConditionBuilder {
|
||||
if left.mode != equalKeyCond {
|
||||
return KeyConditionBuilder{
|
||||
mode: andKeyCond,
|
||||
}
|
||||
}
|
||||
if right.mode == andKeyCond {
|
||||
return KeyConditionBuilder{
|
||||
mode: andKeyCond,
|
||||
}
|
||||
}
|
||||
return KeyConditionBuilder{
|
||||
keyConditionList: []KeyConditionBuilder{left, right},
|
||||
mode: andKeyCond,
|
||||
}
|
||||
}
|
||||
|
||||
// And returns a KeyConditionBuilder representing the logical AND clause of
|
||||
// the two argument KeyConditionBuilders. The resulting KeyConditionBuilder can
|
||||
// be used as an argument to the WithKeyCondition() method for the Builder
|
||||
// struct.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// // keyCondition represents the key condition where the partition key
|
||||
// // "TeamName" is equal to value "Wildcats" and sort key "Number" is equal
|
||||
// // to value 1
|
||||
// keyCondition := expression.Key("TeamName").Equal(expression.Value("Wildcats")).And(expression.Key("Number").Equal(expression.Value(1)))
|
||||
//
|
||||
// // Used to make an Builder
|
||||
// builder := expression.NewBuilder().WithKeyCondition(keyCondition)
|
||||
//
|
||||
// Expression Equivalent:
|
||||
//
|
||||
// expression.Key("TeamName").Equal(expression.Value("Wildcats")).And(expression.Key("Number").Equal(expression.Value(1)))
|
||||
// // Let #NUMBER, :teamName, and :one be ExpressionAttributeName and
|
||||
// // ExpressionAttributeValues representing the item attribute "Number",
|
||||
// // the value "Wildcats", and the value 1
|
||||
// "(TeamName = :teamName) AND (#NUMBER = :one)"
|
||||
func (kcb KeyConditionBuilder) And(right KeyConditionBuilder) KeyConditionBuilder {
|
||||
return KeyAnd(kcb, right)
|
||||
}
|
||||
|
||||
// KeyBetween returns a KeyConditionBuilder representing the result of the
|
||||
// BETWEEN function in DynamoDB Key Condition Expressions. The resulting
|
||||
// KeyConditionBuilder can be used as a part of other Key Condition Expressions.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// // keyCondition represents the boolean key condition of whether the value
|
||||
// // of the key "foo" is between values 5 and 10
|
||||
// keyCondition := expression.KeyBetween(expression.Key("foo"), expression.Value(5), expression.Value(10))
|
||||
//
|
||||
// // Used in another Key Condition Expression
|
||||
// anotherKeyCondition := expression.Key("partitionKey").Equal(expression.Value("aValue")).And(keyCondition)
|
||||
//
|
||||
// Expression Equivalent:
|
||||
//
|
||||
// expression.KeyBetween(expression.Key("foo"), expression.Value(5), expression.Value(10))
|
||||
// // Let :five and :ten be ExpressionAttributeValues representing the
|
||||
// // values 5 and 10 respectively
|
||||
// "foo BETWEEN :five AND :ten"
|
||||
func KeyBetween(keyBuilder KeyBuilder, lower, upper ValueBuilder) KeyConditionBuilder {
|
||||
return KeyConditionBuilder{
|
||||
operandList: []OperandBuilder{keyBuilder, lower, upper},
|
||||
mode: betweenKeyCond,
|
||||
}
|
||||
}
|
||||
|
||||
// Between returns a KeyConditionBuilder representing the result of the
|
||||
// BETWEEN function in DynamoDB Key Condition Expressions. The resulting
|
||||
// KeyConditionBuilder can be used as a part of other Key Condition Expressions.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// // keyCondition represents the boolean key condition of whether the value
|
||||
// // of the key "foo" is between values 5 and 10
|
||||
// keyCondition := expression.Key("foo").Between(expression.Value(5), expression.Value(10))
|
||||
//
|
||||
// // Used in another Key Condition Expression
|
||||
// anotherKeyCondition := expression.Key("partitionKey").Equal(expression.Value("aValue")).And(keyCondition)
|
||||
//
|
||||
// Expression Equivalent:
|
||||
//
|
||||
// expression.Key("foo").Between(expression.Value(5), expression.Value(10))
|
||||
// // Let :five and :ten be ExpressionAttributeValues representing the
|
||||
// // values 5 and 10 respectively
|
||||
// "foo BETWEEN :five AND :ten"
|
||||
func (kb KeyBuilder) Between(lower, upper ValueBuilder) KeyConditionBuilder {
|
||||
return KeyBetween(kb, lower, upper)
|
||||
}
|
||||
|
||||
// KeyBeginsWith returns a KeyConditionBuilder representing the result of
|
||||
// the begins_with function in DynamoDB Key Condition Expressions. The resulting
|
||||
// KeyConditionBuilder can be used as a part of other Key Condition Expressions.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// // keyCondition represents the boolean key condition of whether the value
|
||||
// // of the key "foo" is begins with the prefix "bar"
|
||||
// keyCondition := expression.KeyBeginsWith(expression.Key("foo"), "bar")
|
||||
//
|
||||
// // Used in another Key Condition Expression
|
||||
// anotherKeyCondition := expression.Key("partitionKey").Equal(expression.Value("aValue")).And(keyCondition)
|
||||
//
|
||||
// Expression Equivalent:
|
||||
//
|
||||
// expression.KeyBeginsWith(expression.Key("foo"), "bar")
|
||||
// // Let :bar be an ExpressionAttributeValue representing the value "bar"
|
||||
// "begins_with(foo, :bar)"
|
||||
func KeyBeginsWith(keyBuilder KeyBuilder, prefix string) KeyConditionBuilder {
|
||||
valueBuilder := ValueBuilder{
|
||||
value: prefix,
|
||||
}
|
||||
return KeyConditionBuilder{
|
||||
operandList: []OperandBuilder{keyBuilder, valueBuilder},
|
||||
mode: beginsWithKeyCond,
|
||||
}
|
||||
}
|
||||
|
||||
// BeginsWith returns a KeyConditionBuilder representing the result of the
|
||||
// begins_with function in DynamoDB Key Condition Expressions. The resulting
|
||||
// KeyConditionBuilder can be used as a part of other Key Condition Expressions.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// // keyCondition represents the boolean key condition of whether the value
|
||||
// // of the key "foo" is begins with the prefix "bar"
|
||||
// keyCondition := expression.Key("foo").BeginsWith("bar")
|
||||
//
|
||||
// // Used in another Key Condition Expression
|
||||
// anotherKeyCondition := expression.Key("partitionKey").Equal(expression.Value("aValue")).And(keyCondition)
|
||||
//
|
||||
// Expression Equivalent:
|
||||
//
|
||||
// expression.Key("foo").BeginsWith("bar")
|
||||
// // Let :bar be an ExpressionAttributeValue representing the value "bar"
|
||||
// "begins_with(foo, :bar)"
|
||||
func (kb KeyBuilder) BeginsWith(prefix string) KeyConditionBuilder {
|
||||
return KeyBeginsWith(kb, prefix)
|
||||
}
|
||||
|
||||
// buildTree builds a tree structure of exprNodes based on the tree
|
||||
// structure of the input KeyConditionBuilder's child KeyConditions/Operands.
|
||||
// buildTree() satisfies the treeBuilder interface so KeyConditionBuilder can be
|
||||
// a part of Expression struct.
|
||||
func (kcb KeyConditionBuilder) buildTree() (exprNode, error) {
|
||||
childNodes, err := kcb.buildChildNodes()
|
||||
if err != nil {
|
||||
return exprNode{}, err
|
||||
}
|
||||
ret := exprNode{
|
||||
children: childNodes,
|
||||
}
|
||||
|
||||
switch kcb.mode {
|
||||
case equalKeyCond, lessThanKeyCond, lessThanEqualKeyCond, greaterThanKeyCond, greaterThanEqualKeyCond:
|
||||
return compareBuildKeyCondition(kcb.mode, ret)
|
||||
case andKeyCond:
|
||||
return andBuildKeyCondition(kcb, ret)
|
||||
case betweenKeyCond:
|
||||
return betweenBuildKeyCondition(ret)
|
||||
case beginsWithKeyCond:
|
||||
return beginsWithBuildKeyCondition(ret)
|
||||
case unsetKeyCond:
|
||||
return exprNode{}, newUnsetParameterError("buildTree", "KeyConditionBuilder")
|
||||
default:
|
||||
return exprNode{}, fmt.Errorf("buildKeyCondition error: unsupported mode: %v", kcb.mode)
|
||||
}
|
||||
}
|
||||
|
||||
// compareBuildKeyCondition is the function to make exprNodes from Compare
|
||||
// KeyConditionBuilders. compareBuildKeyCondition is only called by the
|
||||
// buildKeyCondition method. This function assumes that the argument
|
||||
// KeyConditionBuilder has the right format.
|
||||
func compareBuildKeyCondition(keyConditionMode keyConditionMode, node exprNode) (exprNode, error) {
|
||||
// Create a string with special characters that can be substituted later: $c
|
||||
switch keyConditionMode {
|
||||
case equalKeyCond:
|
||||
node.fmtExpr = "$c = $c"
|
||||
case lessThanKeyCond:
|
||||
node.fmtExpr = "$c < $c"
|
||||
case lessThanEqualKeyCond:
|
||||
node.fmtExpr = "$c <= $c"
|
||||
case greaterThanKeyCond:
|
||||
node.fmtExpr = "$c > $c"
|
||||
case greaterThanEqualKeyCond:
|
||||
node.fmtExpr = "$c >= $c"
|
||||
default:
|
||||
return exprNode{}, fmt.Errorf("build compare key condition error: unsupported mode: %v", keyConditionMode)
|
||||
}
|
||||
|
||||
return node, nil
|
||||
}
|
||||
|
||||
// andBuildKeyCondition is the function to make exprNodes from And
|
||||
// KeyConditionBuilders. andBuildKeyCondition is only called by the
|
||||
// buildKeyCondition method. This function assumes that the argument
|
||||
// KeyConditionBuilder has the right format.
|
||||
func andBuildKeyCondition(keyConditionBuilder KeyConditionBuilder, node exprNode) (exprNode, error) {
|
||||
if len(keyConditionBuilder.keyConditionList) == 0 && len(keyConditionBuilder.operandList) == 0 {
|
||||
return exprNode{}, newInvalidParameterError("andBuildKeyCondition", "KeyConditionBuilder")
|
||||
}
|
||||
// create a string with escaped characters to substitute them with proper
|
||||
// aliases during runtime
|
||||
node.fmtExpr = "($c) AND ($c)"
|
||||
|
||||
return node, nil
|
||||
}
|
||||
|
||||
// betweenBuildKeyCondition is the function to make exprNodes from Between
|
||||
// KeyConditionBuilders. betweenBuildKeyCondition is only called by the
|
||||
// buildKeyCondition method. This function assumes that the argument
|
||||
// KeyConditionBuilder has the right format.
|
||||
func betweenBuildKeyCondition(node exprNode) (exprNode, error) {
|
||||
// Create a string with special characters that can be substituted later: $c
|
||||
node.fmtExpr = "$c BETWEEN $c AND $c"
|
||||
|
||||
return node, nil
|
||||
}
|
||||
|
||||
// beginsWithBuildKeyCondition is the function to make exprNodes from
|
||||
// BeginsWith KeyConditionBuilders. beginsWithBuildKeyCondition is only
|
||||
// called by the buildKeyCondition method. This function assumes that the argument
|
||||
// KeyConditionBuilder has the right format.
|
||||
func beginsWithBuildKeyCondition(node exprNode) (exprNode, error) {
|
||||
// Create a string with special characters that can be substituted later: $c
|
||||
node.fmtExpr = "begins_with ($c, $c)"
|
||||
|
||||
return node, nil
|
||||
}
|
||||
|
||||
// buildChildNodes creates the list of the child exprNodes. This avoids
|
||||
// duplication of code amongst the various buildConditions.
|
||||
func (kcb KeyConditionBuilder) buildChildNodes() ([]exprNode, error) {
|
||||
childNodes := make([]exprNode, 0, len(kcb.keyConditionList)+len(kcb.operandList))
|
||||
for _, keyCondition := range kcb.keyConditionList {
|
||||
node, err := keyCondition.buildTree()
|
||||
if err != nil {
|
||||
return []exprNode{}, err
|
||||
}
|
||||
childNodes = append(childNodes, node)
|
||||
}
|
||||
for _, operand := range kcb.operandList {
|
||||
ope, err := operand.BuildOperand()
|
||||
if err != nil {
|
||||
return []exprNode{}, err
|
||||
}
|
||||
childNodes = append(childNodes, ope.exprNode)
|
||||
}
|
||||
|
||||
return childNodes, nil
|
||||
}
|
||||
446
vendor/github.com/aws/aws-sdk-go/service/dynamodb/expression/key_condition_test.go
generated
vendored
Normal file
446
vendor/github.com/aws/aws-sdk-go/service/dynamodb/expression/key_condition_test.go
generated
vendored
Normal file
@@ -0,0 +1,446 @@
|
||||
// +build go1.7
|
||||
|
||||
package expression
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/service/dynamodb"
|
||||
)
|
||||
|
||||
// keyCondErrorMode will help with error cases and checking error types
|
||||
type keyCondErrorMode string
|
||||
|
||||
const (
|
||||
noKeyConditionError keyCondErrorMode = ""
|
||||
// unsetKeyCondition error will occur when buildTree() is called on an empty
|
||||
// KeyConditionBuilder
|
||||
unsetKeyCondition = "unset parameter: KeyConditionBuilder"
|
||||
// invalidKeyConditionOperand error will occur when an invalid OperandBuilder is used as
|
||||
// an argument
|
||||
invalidKeyConditionOperand = "BuildOperand error"
|
||||
// invalidAndFormat error will occur when the first key condition is not an equal
|
||||
// clause or if the second key condition is an and condition.
|
||||
invalidAndFormat = "invalid parameter: KeyConditionBuilder"
|
||||
)
|
||||
|
||||
func TestKeyCompare(t *testing.T) {
|
||||
cases := []struct {
|
||||
name string
|
||||
input KeyConditionBuilder
|
||||
expectedNode exprNode
|
||||
err keyCondErrorMode
|
||||
}{
|
||||
{
|
||||
name: "key equal",
|
||||
input: Key("foo").Equal(Value(5)),
|
||||
expectedNode: exprNode{
|
||||
children: []exprNode{
|
||||
{
|
||||
names: []string{"foo"},
|
||||
fmtExpr: "$n",
|
||||
},
|
||||
{
|
||||
values: []dynamodb.AttributeValue{
|
||||
{
|
||||
N: aws.String("5"),
|
||||
},
|
||||
},
|
||||
fmtExpr: "$v",
|
||||
},
|
||||
},
|
||||
fmtExpr: "$c = $c",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "key less than",
|
||||
input: Key("foo").LessThan(Value(5)),
|
||||
expectedNode: exprNode{
|
||||
children: []exprNode{
|
||||
{
|
||||
names: []string{"foo"},
|
||||
fmtExpr: "$n",
|
||||
},
|
||||
{
|
||||
values: []dynamodb.AttributeValue{
|
||||
{
|
||||
N: aws.String("5"),
|
||||
},
|
||||
},
|
||||
fmtExpr: "$v",
|
||||
},
|
||||
},
|
||||
fmtExpr: "$c < $c",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "key less than equal",
|
||||
input: Key("foo").LessThanEqual(Value(5)),
|
||||
expectedNode: exprNode{
|
||||
children: []exprNode{
|
||||
{
|
||||
names: []string{"foo"},
|
||||
fmtExpr: "$n",
|
||||
},
|
||||
{
|
||||
values: []dynamodb.AttributeValue{
|
||||
{
|
||||
N: aws.String("5"),
|
||||
},
|
||||
},
|
||||
fmtExpr: "$v",
|
||||
},
|
||||
},
|
||||
fmtExpr: "$c <= $c",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "key greater than",
|
||||
input: Key("foo").GreaterThan(Value(5)),
|
||||
expectedNode: exprNode{
|
||||
children: []exprNode{
|
||||
{
|
||||
names: []string{"foo"},
|
||||
fmtExpr: "$n",
|
||||
},
|
||||
{
|
||||
values: []dynamodb.AttributeValue{
|
||||
{
|
||||
N: aws.String("5"),
|
||||
},
|
||||
},
|
||||
fmtExpr: "$v",
|
||||
},
|
||||
},
|
||||
fmtExpr: "$c > $c",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "key greater than equal",
|
||||
input: Key("foo").GreaterThanEqual(Value(5)),
|
||||
expectedNode: exprNode{
|
||||
children: []exprNode{
|
||||
{
|
||||
names: []string{"foo"},
|
||||
fmtExpr: "$n",
|
||||
},
|
||||
{
|
||||
values: []dynamodb.AttributeValue{
|
||||
{
|
||||
N: aws.String("5"),
|
||||
},
|
||||
},
|
||||
fmtExpr: "$v",
|
||||
},
|
||||
},
|
||||
fmtExpr: "$c >= $c",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "unset KeyConditionBuilder",
|
||||
input: KeyConditionBuilder{},
|
||||
err: unsetKeyCondition,
|
||||
},
|
||||
}
|
||||
for _, c := range cases {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
actual, err := c.input.buildTree()
|
||||
if c.err != noKeyConditionError {
|
||||
if err == nil {
|
||||
t.Errorf("expect error %q, got no error", c.err)
|
||||
} else {
|
||||
if e, a := string(c.err), err.Error(); !strings.Contains(a, e) {
|
||||
t.Errorf("expect %q error message to be in %q", e, a)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if err != nil {
|
||||
t.Errorf("expect no error, got unexpected Error %q", err)
|
||||
}
|
||||
|
||||
if e, a := c.expectedNode, actual; !reflect.DeepEqual(a, e) {
|
||||
t.Errorf("expect %v, got %v", e, a)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestKeyBetween(t *testing.T) {
|
||||
cases := []struct {
|
||||
name string
|
||||
input KeyConditionBuilder
|
||||
expectedNode exprNode
|
||||
err keyCondErrorMode
|
||||
}{
|
||||
{
|
||||
name: "key between",
|
||||
input: Key("foo").Between(Value(5), Value(10)),
|
||||
expectedNode: exprNode{
|
||||
children: []exprNode{
|
||||
{
|
||||
names: []string{"foo"},
|
||||
fmtExpr: "$n",
|
||||
},
|
||||
{
|
||||
values: []dynamodb.AttributeValue{
|
||||
{
|
||||
N: aws.String("5"),
|
||||
},
|
||||
},
|
||||
fmtExpr: "$v",
|
||||
},
|
||||
{
|
||||
values: []dynamodb.AttributeValue{
|
||||
{
|
||||
N: aws.String("10"),
|
||||
},
|
||||
},
|
||||
fmtExpr: "$v",
|
||||
},
|
||||
},
|
||||
fmtExpr: "$c BETWEEN $c AND $c",
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, c := range cases {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
actual, err := c.input.buildTree()
|
||||
if c.err != noKeyConditionError {
|
||||
if err == nil {
|
||||
t.Errorf("expect error %q, got no error", c.err)
|
||||
} else {
|
||||
if e, a := string(c.err), err.Error(); !strings.Contains(a, e) {
|
||||
t.Errorf("expect %q error message to be in %q", e, a)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if err != nil {
|
||||
t.Errorf("expect no error, got unexpected Error %q", err)
|
||||
}
|
||||
|
||||
if e, a := c.expectedNode, actual; !reflect.DeepEqual(a, e) {
|
||||
t.Errorf("expect %v, got %v", e, a)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestKeyBeginsWith(t *testing.T) {
|
||||
cases := []struct {
|
||||
name string
|
||||
input KeyConditionBuilder
|
||||
expectedNode exprNode
|
||||
err keyCondErrorMode
|
||||
}{
|
||||
{
|
||||
name: "key begins with",
|
||||
input: Key("foo").BeginsWith("bar"),
|
||||
expectedNode: exprNode{
|
||||
children: []exprNode{
|
||||
{
|
||||
names: []string{"foo"},
|
||||
fmtExpr: "$n",
|
||||
},
|
||||
{
|
||||
values: []dynamodb.AttributeValue{
|
||||
{
|
||||
S: aws.String("bar"),
|
||||
},
|
||||
},
|
||||
fmtExpr: "$v",
|
||||
},
|
||||
},
|
||||
fmtExpr: "begins_with ($c, $c)",
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, c := range cases {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
actual, err := c.input.buildTree()
|
||||
if c.err != noKeyConditionError {
|
||||
if err == nil {
|
||||
t.Errorf("expect error %q, got no error", c.err)
|
||||
} else {
|
||||
if e, a := string(c.err), err.Error(); !strings.Contains(a, e) {
|
||||
t.Errorf("expect %q error message to be in %q", e, a)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if err != nil {
|
||||
t.Errorf("expect no error, got unexpected Error %q", err)
|
||||
}
|
||||
|
||||
if e, a := c.expectedNode, actual; !reflect.DeepEqual(a, e) {
|
||||
t.Errorf("expect %v, got %v", e, a)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestKeyAnd(t *testing.T) {
|
||||
cases := []struct {
|
||||
name string
|
||||
input KeyConditionBuilder
|
||||
expectedNode exprNode
|
||||
err keyCondErrorMode
|
||||
}{
|
||||
{
|
||||
name: "key and",
|
||||
input: Key("foo").Equal(Value(5)).And(Key("bar").BeginsWith("baz")),
|
||||
expectedNode: exprNode{
|
||||
children: []exprNode{
|
||||
{
|
||||
children: []exprNode{
|
||||
{
|
||||
names: []string{"foo"},
|
||||
fmtExpr: "$n",
|
||||
},
|
||||
{
|
||||
values: []dynamodb.AttributeValue{
|
||||
{
|
||||
N: aws.String("5"),
|
||||
},
|
||||
},
|
||||
fmtExpr: "$v",
|
||||
},
|
||||
},
|
||||
fmtExpr: "$c = $c",
|
||||
},
|
||||
{
|
||||
children: []exprNode{
|
||||
{
|
||||
names: []string{"bar"},
|
||||
fmtExpr: "$n",
|
||||
},
|
||||
{
|
||||
values: []dynamodb.AttributeValue{
|
||||
{
|
||||
S: aws.String("baz"),
|
||||
},
|
||||
},
|
||||
fmtExpr: "$v",
|
||||
},
|
||||
},
|
||||
fmtExpr: "begins_with ($c, $c)",
|
||||
},
|
||||
},
|
||||
fmtExpr: "($c) AND ($c)",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "first condition is not equal",
|
||||
input: Key("foo").LessThan(Value(5)).And(Key("bar").BeginsWith("baz")),
|
||||
err: invalidAndFormat,
|
||||
},
|
||||
{
|
||||
name: "second condition is and",
|
||||
input: Key("foo").Equal(Value(5)).And(Key("bar").Equal(Value(1)).And(Key("baz").BeginsWith("yar"))),
|
||||
err: invalidAndFormat,
|
||||
},
|
||||
{
|
||||
name: "operand error",
|
||||
input: Key("").Equal(Value("yikes")),
|
||||
err: invalidKeyConditionOperand,
|
||||
},
|
||||
}
|
||||
for _, c := range cases {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
actual, err := c.input.buildTree()
|
||||
if c.err != noKeyConditionError {
|
||||
if err == nil {
|
||||
t.Errorf("expect error %q, got no error", c.err)
|
||||
} else {
|
||||
if e, a := string(c.err), err.Error(); !strings.Contains(a, e) {
|
||||
t.Errorf("expect %q error message to be in %q", e, a)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if err != nil {
|
||||
t.Errorf("expect no error, got unexpected Error %q", err)
|
||||
}
|
||||
|
||||
if e, a := c.expectedNode, actual; !reflect.DeepEqual(a, e) {
|
||||
t.Errorf("expect %v, got %v", e, a)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestKeyConditionBuildChildNodes(t *testing.T) {
|
||||
cases := []struct {
|
||||
name string
|
||||
input KeyConditionBuilder
|
||||
expected []exprNode
|
||||
err keyCondErrorMode
|
||||
}{
|
||||
{
|
||||
name: "build child nodes",
|
||||
input: Key("foo").Equal(Value("bar")).And(Key("baz").LessThan(Value(10))),
|
||||
expected: []exprNode{
|
||||
{
|
||||
children: []exprNode{
|
||||
{
|
||||
names: []string{"foo"},
|
||||
fmtExpr: "$n",
|
||||
},
|
||||
{
|
||||
values: []dynamodb.AttributeValue{
|
||||
{
|
||||
S: aws.String("bar"),
|
||||
},
|
||||
},
|
||||
fmtExpr: "$v",
|
||||
},
|
||||
},
|
||||
fmtExpr: "$c = $c",
|
||||
},
|
||||
{
|
||||
children: []exprNode{
|
||||
{
|
||||
names: []string{"baz"},
|
||||
fmtExpr: "$n",
|
||||
},
|
||||
{
|
||||
values: []dynamodb.AttributeValue{
|
||||
{
|
||||
N: aws.String("10"),
|
||||
},
|
||||
},
|
||||
fmtExpr: "$v",
|
||||
},
|
||||
},
|
||||
fmtExpr: "$c < $c",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, c := range cases {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
actual, err := c.input.buildChildNodes()
|
||||
if c.err != noKeyConditionError {
|
||||
if err == nil {
|
||||
t.Errorf("expect error %q, got no error", c.err)
|
||||
} else {
|
||||
if e, a := string(c.err), err.Error(); !strings.Contains(a, e) {
|
||||
t.Errorf("expect %q error message to be in %q", e, a)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if err != nil {
|
||||
t.Errorf("expect no error, got unexpected Error %q", err)
|
||||
}
|
||||
|
||||
if e, a := c.expected, actual; !reflect.DeepEqual(a, e) {
|
||||
t.Errorf("expect %#v, got %#v", e, a)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
620
vendor/github.com/aws/aws-sdk-go/service/dynamodb/expression/operand.go
generated
vendored
Normal file
620
vendor/github.com/aws/aws-sdk-go/service/dynamodb/expression/operand.go
generated
vendored
Normal file
@@ -0,0 +1,620 @@
|
||||
package expression
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/aws/aws-sdk-go/service/dynamodb"
|
||||
"github.com/aws/aws-sdk-go/service/dynamodb/dynamodbattribute"
|
||||
)
|
||||
|
||||
// ValueBuilder represents an item attribute value operand and implements the
|
||||
// OperandBuilder interface. Methods and functions in the package take
|
||||
// ValueBuilder as an argument and establishes relationships between operands.
|
||||
// ValueBuilder should only be initialized using the function Value().
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// // Create a ValueBuilder representing the string "aValue"
|
||||
// valueBuilder := expression.Value("aValue")
|
||||
type ValueBuilder struct {
|
||||
value interface{}
|
||||
}
|
||||
|
||||
// NameBuilder represents a name of a top level item attribute or a nested
|
||||
// attribute. Since NameBuilder represents a DynamoDB Operand, it implements the
|
||||
// OperandBuilder interface. Methods and functions in the package take
|
||||
// NameBuilder as an argument and establishes relationships between operands.
|
||||
// NameBuilder should only be initialized using the function Name().
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// // Create a NameBuilder representing the item attribute "aName"
|
||||
// nameBuilder := expression.Name("aName")
|
||||
type NameBuilder struct {
|
||||
name string
|
||||
}
|
||||
|
||||
// SizeBuilder represents the output of the function size ("someName"), which
|
||||
// evaluates to the size of the item attribute defined by "someName". Since
|
||||
// SizeBuilder represents an operand, SizeBuilder implements the OperandBuilder
|
||||
// interface. Methods and functions in the package take SizeBuilder as an
|
||||
// argument and establishes relationships between operands. SizeBuilder should
|
||||
// only be initialized using the function Size().
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// // Create a SizeBuilder representing the size of the item attribute
|
||||
// // "aName"
|
||||
// sizeBuilder := expression.Name("aName").Size()
|
||||
type SizeBuilder struct {
|
||||
nameBuilder NameBuilder
|
||||
}
|
||||
|
||||
// KeyBuilder represents either the partition key or the sort key, both of which
|
||||
// are top level attributes to some item in DynamoDB. Since KeyBuilder
|
||||
// represents an operand, KeyBuilder implements the OperandBuilder interface.
|
||||
// Methods and functions in the package take KeyBuilder as an argument and
|
||||
// establishes relationships between operands. However, KeyBuilder should only
|
||||
// be used to describe Key Condition Expressions. KeyBuilder should only be
|
||||
// initialized using the function Key().
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// // Create a KeyBuilder representing the item key "aKey"
|
||||
// keyBuilder := expression.Key("aKey")
|
||||
type KeyBuilder struct {
|
||||
key string
|
||||
}
|
||||
|
||||
// setValueMode specifies the type of SetValueBuilder. The default value is
|
||||
// unsetValue so that an UnsetParameterError when BuildOperand() is called on an
|
||||
// empty SetValueBuilder.
|
||||
type setValueMode int
|
||||
|
||||
const (
|
||||
unsetValue setValueMode = iota
|
||||
plusValueMode
|
||||
minusValueMode
|
||||
listAppendValueMode
|
||||
ifNotExistsValueMode
|
||||
)
|
||||
|
||||
// SetValueBuilder represents the outcome of operator functions supported by the
|
||||
// DynamoDB Set operation. The operator functions are the following:
|
||||
// Plus() // Represents the "+" operator
|
||||
// Minus() // Represents the "-" operator
|
||||
// ListAppend()
|
||||
// IfNotExists()
|
||||
// For documentation on the above functions,
|
||||
// see: http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.UpdateExpressions.html#Expressions.UpdateExpressions.SET
|
||||
// Since SetValueBuilder represents an operand, it implements the OperandBuilder
|
||||
// interface. SetValueBuilder structs are used as arguments to the Set()
|
||||
// function. SetValueBuilders should only initialize a SetValueBuilder using the
|
||||
// functions listed above.
|
||||
type SetValueBuilder struct {
|
||||
leftOperand OperandBuilder
|
||||
rightOperand OperandBuilder
|
||||
mode setValueMode
|
||||
}
|
||||
|
||||
// Operand represents an item attribute name or value in DynamoDB. The
|
||||
// relationship between Operands specified by various builders such as
|
||||
// ConditionBuilders and UpdateBuilders for example is processed internally to
|
||||
// write Condition Expressions and Update Expressions respectively.
|
||||
type Operand struct {
|
||||
exprNode exprNode
|
||||
}
|
||||
|
||||
// OperandBuilder represents the idea of Operand which are building blocks to
|
||||
// DynamoDB Expressions. Package methods and functions can establish
|
||||
// relationships between operands, representing DynamoDB Expressions. The method
|
||||
// BuildOperand() is called recursively when the Build() method on the type
|
||||
// Builder is called. BuildOperand() should never be called externally.
|
||||
// OperandBuilder and BuildOperand() are exported to allow package functions to
|
||||
// take an interface as an argument.
|
||||
type OperandBuilder interface {
|
||||
BuildOperand() (Operand, error)
|
||||
}
|
||||
|
||||
// Name creates a NameBuilder. The argument should represent the desired item
|
||||
// attribute. It is possible to reference nested item attributes by using
|
||||
// square brackets for lists and dots for maps. For documentation on specifying
|
||||
// item attributes,
|
||||
// see: http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.Attributes.html
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// // Specify a top-level attribute
|
||||
// name := expression.Name("TopLevel")
|
||||
// // Specify a nested attribute
|
||||
// nested := expression.Name("Record[6].SongList")
|
||||
// // Use Name() to create a condition expression
|
||||
// condition := expression.Name("foo").Equal(expression.Name("bar"))
|
||||
func Name(name string) NameBuilder {
|
||||
return NameBuilder{
|
||||
name: name,
|
||||
}
|
||||
}
|
||||
|
||||
// Value creates a ValueBuilder. The argument should represent the desired item
|
||||
// attribute. The value is marshalled using the dynamodbattribute package by the
|
||||
// Build() method for type Builder.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// // Use Value() to create a condition expression
|
||||
// condition := expression.Name("foo").Equal(expression.Value(10))
|
||||
func Value(value interface{}) ValueBuilder {
|
||||
return ValueBuilder{
|
||||
value: value,
|
||||
}
|
||||
}
|
||||
|
||||
// Size creates a SizeBuilder representing the size of the item attribute
|
||||
// specified by the argument NameBuilder. Size() is only valid for certain types
|
||||
// of item attributes. For documentation,
|
||||
// see: http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.OperatorsAndFunctions.html
|
||||
// SizeBuilder is only a valid operand in Condition Expressions and Filter
|
||||
// Expressions.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// // Use Size() to create a condition expression
|
||||
// condition := expression.Name("foo").Size().Equal(expression.Value(10))
|
||||
//
|
||||
// Expression Equivalent:
|
||||
//
|
||||
// expression.Name("aName").Size()
|
||||
// "size (aName)"
|
||||
func (nb NameBuilder) Size() SizeBuilder {
|
||||
return SizeBuilder{
|
||||
nameBuilder: nb,
|
||||
}
|
||||
}
|
||||
|
||||
// Size creates a SizeBuilder representing the size of the item attribute
|
||||
// specified by the argument NameBuilder. Size() is only valid for certain types
|
||||
// of item attributes. For documentation,
|
||||
// see: http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.OperatorsAndFunctions.html
|
||||
// SizeBuilder is only a valid operand in Condition Expressions and Filter
|
||||
// Expressions.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// // Use Size() to create a condition expression
|
||||
// condition := expression.Size(expression.Name("foo")).Equal(expression.Value(10))
|
||||
//
|
||||
// Expression Equivalent:
|
||||
//
|
||||
// expression.Size(expression.Name("aName"))
|
||||
// "size (aName)"
|
||||
func Size(nameBuilder NameBuilder) SizeBuilder {
|
||||
return nameBuilder.Size()
|
||||
}
|
||||
|
||||
// Key creates a KeyBuilder. The argument should represent the desired partition
|
||||
// key or sort key value. KeyBuilders should only be used to specify
|
||||
// relationships for Key Condition Expressions. When referring to the partition
|
||||
// key or sort key in any other Expression, use Name().
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// // Use Key() to create a key condition expression
|
||||
// keyCondition := expression.Key("foo").Equal(expression.Value("bar"))
|
||||
func Key(key string) KeyBuilder {
|
||||
return KeyBuilder{
|
||||
key: key,
|
||||
}
|
||||
}
|
||||
|
||||
// Plus creates a SetValueBuilder to be used in as an argument to Set(). The
|
||||
// arguments can either be NameBuilders or ValueBuilders. Plus() only supports
|
||||
// DynamoDB Number types, so the ValueBuilder must be a Number and the
|
||||
// NameBuilder must specify an item attribute of type Number.
|
||||
// More information: http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.UpdateExpressions.html#Expressions.UpdateExpressions.SET.IncrementAndDecrement
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// // Use Plus() to set the value of the item attribute "someName" to 5 + 10
|
||||
// update, err := expression.Set(expression.Name("someName"), expression.Plus(expression.Value(5), expression.Value(10)))
|
||||
//
|
||||
// Expression Equivalent:
|
||||
//
|
||||
// expression.Plus(expression.Value(5), expression.Value(10))
|
||||
// // let :five and :ten be ExpressionAttributeValues for the values 5 and
|
||||
// // 10 respectively.
|
||||
// ":five + :ten"
|
||||
func Plus(leftOperand, rightOperand OperandBuilder) SetValueBuilder {
|
||||
return SetValueBuilder{
|
||||
leftOperand: leftOperand,
|
||||
rightOperand: rightOperand,
|
||||
mode: plusValueMode,
|
||||
}
|
||||
}
|
||||
|
||||
// Plus creates a SetValueBuilder to be used in as an argument to Set(). The
|
||||
// arguments can either be NameBuilders or ValueBuilders. Plus() only supports
|
||||
// DynamoDB Number types, so the ValueBuilder must be a Number and the
|
||||
// NameBuilder must specify an item attribute of type Number.
|
||||
// More information: http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.UpdateExpressions.html#Expressions.UpdateExpressions.SET.IncrementAndDecrement
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// // Use Plus() to set the value of the item attribute "someName" to the
|
||||
// // numeric value of item attribute "aName" incremented by 10
|
||||
// update, err := expression.Set(expression.Name("someName"), expression.Name("aName").Plus(expression.Value(10)))
|
||||
//
|
||||
// Expression Equivalent:
|
||||
//
|
||||
// expression.Name("aName").Plus(expression.Value(10))
|
||||
// // let :ten be ExpressionAttributeValues representing the value 10
|
||||
// "aName + :ten"
|
||||
func (nb NameBuilder) Plus(rightOperand OperandBuilder) SetValueBuilder {
|
||||
return Plus(nb, rightOperand)
|
||||
}
|
||||
|
||||
// Plus creates a SetValueBuilder to be used in as an argument to Set(). The
|
||||
// arguments can either be NameBuilders or ValueBuilders. Plus() only supports
|
||||
// DynamoDB Number types, so the ValueBuilder must be a Number and the
|
||||
// NameBuilder must specify an item attribute of type Number.
|
||||
// More information: http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.UpdateExpressions.html#Expressions.UpdateExpressions.SET.IncrementAndDecrement
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// // Use Plus() to set the value of the item attribute "someName" to 5 + 10
|
||||
// update, err := expression.Set(expression.Name("someName"), expression.Value(5).Plus(expression.Value(10)))
|
||||
//
|
||||
// Expression Equivalent:
|
||||
//
|
||||
// expression.Value(5).Plus(expression.Value(10))
|
||||
// // let :five and :ten be ExpressionAttributeValues representing the value
|
||||
// // 5 and 10 respectively
|
||||
// ":five + :ten"
|
||||
func (vb ValueBuilder) Plus(rightOperand OperandBuilder) SetValueBuilder {
|
||||
return Plus(vb, rightOperand)
|
||||
}
|
||||
|
||||
// Minus creates a SetValueBuilder to be used in as an argument to Set(). The
|
||||
// arguments can either be NameBuilders or ValueBuilders. Minus() only supports
|
||||
// DynamoDB Number types, so the ValueBuilder must be a Number and the
|
||||
// NameBuilder must specify an item attribute of type Number.
|
||||
// More information: http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.UpdateExpressions.html#Expressions.UpdateExpressions.SET.IncrementAndDecrement
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// // Use Minus() to set the value of item attribute "someName" to 5 - 10
|
||||
// update, err := expression.Set(expression.Name("someName"), expression.Minus(expression.Value(5), expression.Value(10)))
|
||||
//
|
||||
// Expression Equivalent:
|
||||
//
|
||||
// expression.Minus(expression.Value(5), expression.Value(10))
|
||||
// // let :five and :ten be ExpressionAttributeValues for the values 5 and
|
||||
// // 10 respectively.
|
||||
// ":five - :ten"
|
||||
func Minus(leftOperand, rightOperand OperandBuilder) SetValueBuilder {
|
||||
return SetValueBuilder{
|
||||
leftOperand: leftOperand,
|
||||
rightOperand: rightOperand,
|
||||
mode: minusValueMode,
|
||||
}
|
||||
}
|
||||
|
||||
// Minus creates a SetValueBuilder to be used in as an argument to Set(). The
|
||||
// arguments can either be NameBuilders or ValueBuilders. Minus() only supports
|
||||
// DynamoDB Number types, so the ValueBuilder must be a Number and the
|
||||
// NameBuilder must specify an item attribute of type Number.
|
||||
// More information: http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.UpdateExpressions.html#Expressions.UpdateExpressions.SET.IncrementAndDecrement
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// // Use Minus() to set the value of item attribute "someName" to the
|
||||
// // numeric value of "aName" decremented by 10
|
||||
// update, err := expression.Set(expression.Name("someName"), expression.Name("aName").Minus(expression.Value(10)))
|
||||
//
|
||||
// Expression Equivalent:
|
||||
//
|
||||
// expression.Name("aName").Minus(expression.Value(10)))
|
||||
// // let :ten be ExpressionAttributeValues represent the value 10
|
||||
// "aName - :ten"
|
||||
func (nb NameBuilder) Minus(rightOperand OperandBuilder) SetValueBuilder {
|
||||
return Minus(nb, rightOperand)
|
||||
}
|
||||
|
||||
// Minus creates a SetValueBuilder to be used in as an argument to Set(). The
|
||||
// arguments can either be NameBuilders or ValueBuilders. Minus() only supports
|
||||
// DynamoDB Number types, so the ValueBuilder must be a Number and the
|
||||
// NameBuilder must specify an item attribute of type Number.
|
||||
// More information: http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.UpdateExpressions.html#Expressions.UpdateExpressions.SET.IncrementAndDecrement
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// // Use Minus() to set the value of item attribute "someName" to 5 - 10
|
||||
// update, err := expression.Set(expression.Name("someName"), expression.Value(5).Minus(expression.Value(10)))
|
||||
//
|
||||
// Expression Equivalent:
|
||||
//
|
||||
// expression.Value(5).Minus(expression.Value(10))
|
||||
// // let :five and :ten be ExpressionAttributeValues for the values 5 and
|
||||
// // 10 respectively.
|
||||
// ":five - :ten"
|
||||
func (vb ValueBuilder) Minus(rightOperand OperandBuilder) SetValueBuilder {
|
||||
return Minus(vb, rightOperand)
|
||||
}
|
||||
|
||||
// ListAppend creates a SetValueBuilder to be used in as an argument to Set().
|
||||
// The arguments can either be NameBuilders or ValueBuilders. ListAppend() only
|
||||
// supports DynamoDB List types, so the ValueBuilder must be a List and the
|
||||
// NameBuilder must specify an item attribute of type List.
|
||||
// More information: http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.UpdateExpressions.html#Expressions.UpdateExpressions.SET.UpdatingListElements
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// // Use ListAppend() to set item attribute "someName" to the item
|
||||
// // attribute "nameOfList" with "some" and "list" appended to it
|
||||
// update, err := expression.Set(expression.Name("someName"), expression.ListAppend(expression.Name("nameOfList"), expression.Value([]string{"some", "list"})))
|
||||
//
|
||||
// Expression Equivalent:
|
||||
//
|
||||
// expression.ListAppend(expression.Name("nameOfList"), expression.Value([]string{"some", "list"})
|
||||
// // let :list be a ExpressionAttributeValue representing the list
|
||||
// // containing "some" and "list".
|
||||
// "list_append (nameOfList, :list)"
|
||||
func ListAppend(leftOperand, rightOperand OperandBuilder) SetValueBuilder {
|
||||
return SetValueBuilder{
|
||||
leftOperand: leftOperand,
|
||||
rightOperand: rightOperand,
|
||||
mode: listAppendValueMode,
|
||||
}
|
||||
}
|
||||
|
||||
// ListAppend creates a SetValueBuilder to be used in as an argument to Set().
|
||||
// The arguments can either be NameBuilders or ValueBuilders. ListAppend() only
|
||||
// supports DynamoDB List types, so the ValueBuilder must be a List and the
|
||||
// NameBuilder must specify an item attribute of type List.
|
||||
// More information: http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.UpdateExpressions.html#Expressions.UpdateExpressions.SET.UpdatingListElements
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// // Use ListAppend() to set item attribute "someName" to the item
|
||||
// // attribute "nameOfList" with "some" and "list" appended to it
|
||||
// update, err := expression.Set(expression.Name("someName"), expression.Name("nameOfList").ListAppend(expression.Value([]string{"some", "list"})))
|
||||
//
|
||||
// Expression Equivalent:
|
||||
//
|
||||
// expression.Name("nameOfList").ListAppend(expression.Value([]string{"some", "list"})
|
||||
// // let :list be a ExpressionAttributeValue representing the list
|
||||
// // containing "some" and "list".
|
||||
// "list_append (nameOfList, :list)"
|
||||
func (nb NameBuilder) ListAppend(rightOperand OperandBuilder) SetValueBuilder {
|
||||
return ListAppend(nb, rightOperand)
|
||||
}
|
||||
|
||||
// ListAppend creates a SetValueBuilder to be used in as an argument to Set().
|
||||
// The arguments can either be NameBuilders or ValueBuilders. ListAppend() only
|
||||
// supports DynamoDB List types, so the ValueBuilder must be a List and the
|
||||
// NameBuilder must specify an item attribute of type List.
|
||||
// More information: http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.UpdateExpressions.html#Expressions.UpdateExpressions.SET.UpdatingListElements
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// // Use ListAppend() to set item attribute "someName" to a string list
|
||||
// // equal to {"a", "list", "some", "list"}
|
||||
// update, err := expression.Set(expression.Name("someName"), expression.Value([]string{"a", "list"}).ListAppend(expression.Value([]string{"some", "list"})))
|
||||
//
|
||||
// Expression Equivalent:
|
||||
//
|
||||
// expression.Name([]string{"a", "list"}).ListAppend(expression.Value([]string{"some", "list"})
|
||||
// // let :list1 and :list2 be a ExpressionAttributeValue representing the
|
||||
// // list {"a", "list"} and {"some", "list"} respectively
|
||||
// "list_append (:list1, :list2)"
|
||||
func (vb ValueBuilder) ListAppend(rightOperand OperandBuilder) SetValueBuilder {
|
||||
return ListAppend(vb, rightOperand)
|
||||
}
|
||||
|
||||
// IfNotExists creates a SetValueBuilder to be used in as an argument to Set().
|
||||
// The first argument must be a NameBuilder representing the name where the new
|
||||
// item attribute is created. The second argument can either be a NameBuilder or
|
||||
// a ValueBuilder. In the case that it is a NameBuilder, the value of the item
|
||||
// attribute at the name specified becomes the value of the new item attribute.
|
||||
// More information: http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.UpdateExpressions.html#Expressions.UpdateExpressions.SET.PreventingAttributeOverwrites
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// // Use IfNotExists() to set item attribute "someName" to value 5 if
|
||||
// // "someName" does not exist yet. (Prevents overwrite)
|
||||
// update, err := expression.Set(expression.Name("someName"), expression.IfNotExists(expression.Name("someName"), expression.Value(5)))
|
||||
//
|
||||
// Expression Equivalent:
|
||||
//
|
||||
// expression.IfNotExists(expression.Name("someName"), expression.Value(5))
|
||||
// // let :five be a ExpressionAttributeValue representing the value 5
|
||||
// "if_not_exists (someName, :five)"
|
||||
func IfNotExists(name NameBuilder, setValue OperandBuilder) SetValueBuilder {
|
||||
return SetValueBuilder{
|
||||
leftOperand: name,
|
||||
rightOperand: setValue,
|
||||
mode: ifNotExistsValueMode,
|
||||
}
|
||||
}
|
||||
|
||||
// IfNotExists creates a SetValueBuilder to be used in as an argument to Set().
|
||||
// The first argument must be a NameBuilder representing the name where the new
|
||||
// item attribute is created. The second argument can either be a NameBuilder or
|
||||
// a ValueBuilder. In the case that it is a NameBuilder, the value of the item
|
||||
// attribute at the name specified becomes the value of the new item attribute.
|
||||
// More information: http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.UpdateExpressions.html#Expressions.UpdateExpressions.SET.PreventingAttributeOverwrites
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// // Use IfNotExists() to set item attribute "someName" to value 5 if
|
||||
// // "someName" does not exist yet. (Prevents overwrite)
|
||||
// update, err := expression.Set(expression.Name("someName"), expression.Name("someName").IfNotExists(expression.Value(5)))
|
||||
//
|
||||
// Expression Equivalent:
|
||||
//
|
||||
// expression.Name("someName").IfNotExists(expression.Value(5))
|
||||
// // let :five be a ExpressionAttributeValue representing the value 5
|
||||
// "if_not_exists (someName, :five)"
|
||||
func (nb NameBuilder) IfNotExists(rightOperand OperandBuilder) SetValueBuilder {
|
||||
return IfNotExists(nb, rightOperand)
|
||||
}
|
||||
|
||||
// BuildOperand creates an Operand struct which are building blocks to DynamoDB
|
||||
// Expressions. Package methods and functions can establish relationships
|
||||
// between operands, representing DynamoDB Expressions. The method
|
||||
// BuildOperand() is called recursively when the Build() method on the type
|
||||
// Builder is called. BuildOperand() should never be called externally.
|
||||
// BuildOperand() aliases all strings to avoid stepping over DynamoDB's reserved
|
||||
// words.
|
||||
// More information on reserved words at http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/ReservedWords.html
|
||||
func (nb NameBuilder) BuildOperand() (Operand, error) {
|
||||
if nb.name == "" {
|
||||
return Operand{}, newUnsetParameterError("BuildOperand", "NameBuilder")
|
||||
}
|
||||
|
||||
node := exprNode{
|
||||
names: []string{},
|
||||
}
|
||||
|
||||
nameSplit := strings.Split(nb.name, ".")
|
||||
fmtNames := make([]string, 0, len(nameSplit))
|
||||
|
||||
for _, word := range nameSplit {
|
||||
var substr string
|
||||
if word == "" {
|
||||
return Operand{}, newInvalidParameterError("BuildOperand", "NameBuilder")
|
||||
}
|
||||
|
||||
if word[len(word)-1] == ']' {
|
||||
for j, char := range word {
|
||||
if char == '[' {
|
||||
substr = word[j:]
|
||||
word = word[:j]
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if word == "" {
|
||||
return Operand{}, newInvalidParameterError("BuildOperand", "NameBuilder")
|
||||
}
|
||||
|
||||
// Create a string with special characters that can be substituted later: $p
|
||||
node.names = append(node.names, word)
|
||||
fmtNames = append(fmtNames, "$n"+substr)
|
||||
}
|
||||
node.fmtExpr = strings.Join(fmtNames, ".")
|
||||
return Operand{
|
||||
exprNode: node,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// BuildOperand creates an Operand struct which are building blocks to DynamoDB
|
||||
// Expressions. Package methods and functions can establish relationships
|
||||
// between operands, representing DynamoDB Expressions. The method
|
||||
// BuildOperand() is called recursively when the Build() method on the type
|
||||
// Builder is called. BuildOperand() should never be called externally.
|
||||
// BuildOperand() aliases all strings to avoid stepping over DynamoDB's reserved
|
||||
// words.
|
||||
// More information on reserved words at http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/ReservedWords.html
|
||||
func (vb ValueBuilder) BuildOperand() (Operand, error) {
|
||||
expr, err := dynamodbattribute.Marshal(vb.value)
|
||||
if err != nil {
|
||||
return Operand{}, newInvalidParameterError("BuildOperand", "ValueBuilder")
|
||||
}
|
||||
|
||||
// Create a string with special characters that can be substituted later: $v
|
||||
operand := Operand{
|
||||
exprNode: exprNode{
|
||||
values: []dynamodb.AttributeValue{*expr},
|
||||
fmtExpr: "$v",
|
||||
},
|
||||
}
|
||||
return operand, nil
|
||||
}
|
||||
|
||||
// BuildOperand creates an Operand struct which are building blocks to DynamoDB
|
||||
// Expressions. Package methods and functions can establish relationships
|
||||
// between operands, representing DynamoDB Expressions. The method
|
||||
// BuildOperand() is called recursively when the Build() method on the type
|
||||
// Builder is called. BuildOperand() should never be called externally.
|
||||
// BuildOperand() aliases all strings to avoid stepping over DynamoDB's reserved
|
||||
// words.
|
||||
// More information on reserved words at http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/ReservedWords.html
|
||||
func (sb SizeBuilder) BuildOperand() (Operand, error) {
|
||||
operand, err := sb.nameBuilder.BuildOperand()
|
||||
operand.exprNode.fmtExpr = "size (" + operand.exprNode.fmtExpr + ")"
|
||||
|
||||
return operand, err
|
||||
}
|
||||
|
||||
// BuildOperand creates an Operand struct which are building blocks to DynamoDB
|
||||
// Expressions. Package methods and functions can establish relationships
|
||||
// between operands, representing DynamoDB Expressions. The method
|
||||
// BuildOperand() is called recursively when the Build() method on the type
|
||||
// Builder is called. BuildOperand() should never be called externally.
|
||||
// BuildOperand() aliases all strings to avoid stepping over DynamoDB's reserved
|
||||
// words.
|
||||
// More information on reserved words at http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/ReservedWords.html
|
||||
func (kb KeyBuilder) BuildOperand() (Operand, error) {
|
||||
if kb.key == "" {
|
||||
return Operand{}, newUnsetParameterError("BuildOperand", "KeyBuilder")
|
||||
}
|
||||
|
||||
ret := Operand{
|
||||
exprNode: exprNode{
|
||||
names: []string{kb.key},
|
||||
fmtExpr: "$n",
|
||||
},
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
// BuildOperand creates an Operand struct which are building blocks to DynamoDB
|
||||
// Expressions. Package methods and functions can establish relationships
|
||||
// between operands, representing DynamoDB Expressions. The method
|
||||
// BuildOperand() is called recursively when the Build() method on the type
|
||||
// Builder is called. BuildOperand() should never be called externally.
|
||||
// BuildOperand() aliases all strings to avoid stepping over DynamoDB's reserved
|
||||
// words.
|
||||
// More information on reserved words at http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/ReservedWords.html
|
||||
func (svb SetValueBuilder) BuildOperand() (Operand, error) {
|
||||
if svb.mode == unsetValue {
|
||||
return Operand{}, newUnsetParameterError("BuildOperand", "SetValueBuilder")
|
||||
}
|
||||
|
||||
left, err := svb.leftOperand.BuildOperand()
|
||||
if err != nil {
|
||||
return Operand{}, err
|
||||
}
|
||||
leftNode := left.exprNode
|
||||
|
||||
right, err := svb.rightOperand.BuildOperand()
|
||||
if err != nil {
|
||||
return Operand{}, err
|
||||
}
|
||||
rightNode := right.exprNode
|
||||
|
||||
node := exprNode{
|
||||
children: []exprNode{leftNode, rightNode},
|
||||
}
|
||||
|
||||
switch svb.mode {
|
||||
case plusValueMode:
|
||||
node.fmtExpr = "$c + $c"
|
||||
case minusValueMode:
|
||||
node.fmtExpr = "$c - $c"
|
||||
case listAppendValueMode:
|
||||
node.fmtExpr = "list_append($c, $c)"
|
||||
case ifNotExistsValueMode:
|
||||
node.fmtExpr = "if_not_exists($c, $c)"
|
||||
default:
|
||||
return Operand{}, fmt.Errorf("build operand error: unsupported mode: %v", svb.mode)
|
||||
}
|
||||
|
||||
return Operand{
|
||||
exprNode: node,
|
||||
}, nil
|
||||
}
|
||||
144
vendor/github.com/aws/aws-sdk-go/service/dynamodb/expression/operand_test.go
generated
vendored
Normal file
144
vendor/github.com/aws/aws-sdk-go/service/dynamodb/expression/operand_test.go
generated
vendored
Normal file
@@ -0,0 +1,144 @@
|
||||
// +build go1.7
|
||||
|
||||
package expression
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/service/dynamodb"
|
||||
)
|
||||
|
||||
// opeErrorMode will help with error cases and checking error types
|
||||
type opeErrorMode string
|
||||
|
||||
const (
|
||||
noOperandError opeErrorMode = ""
|
||||
// unsetName error will occur if an empty string is passed into NameBuilder
|
||||
unsetName = "unset parameter: NameBuilder"
|
||||
// invalidName error will occur if a nested name has an empty intermediary
|
||||
// attribute name (i.e. foo.bar..baz)
|
||||
invalidName = "invalid parameter: NameBuilder"
|
||||
// unsetKey error will occur if an empty string is passed into KeyBuilder
|
||||
unsetKey = "unset parameter: KeyBuilder"
|
||||
)
|
||||
|
||||
func TestBuildOperand(t *testing.T) {
|
||||
cases := []struct {
|
||||
name string
|
||||
input OperandBuilder
|
||||
expected exprNode
|
||||
err opeErrorMode
|
||||
}{
|
||||
{
|
||||
name: "basic name",
|
||||
input: Name("foo"),
|
||||
expected: exprNode{
|
||||
names: []string{"foo"},
|
||||
fmtExpr: "$n",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "duplicate name name",
|
||||
input: Name("foo.foo"),
|
||||
expected: exprNode{
|
||||
names: []string{"foo", "foo"},
|
||||
fmtExpr: "$n.$n",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "basic value",
|
||||
input: Value(5),
|
||||
expected: exprNode{
|
||||
values: []dynamodb.AttributeValue{
|
||||
{
|
||||
N: aws.String("5"),
|
||||
},
|
||||
},
|
||||
fmtExpr: "$v",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "nested name",
|
||||
input: Name("foo.bar"),
|
||||
expected: exprNode{
|
||||
names: []string{"foo", "bar"},
|
||||
fmtExpr: "$n.$n",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "nested name with index",
|
||||
input: Name("foo.bar[0].baz"),
|
||||
expected: exprNode{
|
||||
names: []string{"foo", "bar", "baz"},
|
||||
fmtExpr: "$n.$n[0].$n",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "basic size",
|
||||
input: Name("foo").Size(),
|
||||
expected: exprNode{
|
||||
names: []string{"foo"},
|
||||
fmtExpr: "size ($n)",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "key",
|
||||
input: Key("foo"),
|
||||
expected: exprNode{
|
||||
names: []string{"foo"},
|
||||
fmtExpr: "$n",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "unset key error",
|
||||
input: Key(""),
|
||||
expected: exprNode{},
|
||||
err: unsetKey,
|
||||
},
|
||||
{
|
||||
name: "empty name error",
|
||||
input: Name(""),
|
||||
expected: exprNode{},
|
||||
err: unsetName,
|
||||
},
|
||||
{
|
||||
name: "invalid name",
|
||||
input: Name("foo..bar"),
|
||||
expected: exprNode{},
|
||||
err: invalidName,
|
||||
},
|
||||
{
|
||||
name: "invalid index",
|
||||
input: Name("[foo]"),
|
||||
expected: exprNode{},
|
||||
err: invalidName,
|
||||
},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
operand, err := c.input.BuildOperand()
|
||||
|
||||
if c.err != noOperandError {
|
||||
if err == nil {
|
||||
t.Errorf("expect error %q, got no error", c.err)
|
||||
} else {
|
||||
if e, a := string(c.err), err.Error(); !strings.Contains(a, e) {
|
||||
t.Errorf("expect %q error message to be in %q", e, a)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if err != nil {
|
||||
t.Errorf("expect no error, got unexpected Error %q", err)
|
||||
}
|
||||
|
||||
if e, a := c.expected, operand.exprNode; !reflect.DeepEqual(a, e) {
|
||||
t.Errorf("expect %v, got %v", e, a)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
148
vendor/github.com/aws/aws-sdk-go/service/dynamodb/expression/projection.go
generated
vendored
Normal file
148
vendor/github.com/aws/aws-sdk-go/service/dynamodb/expression/projection.go
generated
vendored
Normal file
@@ -0,0 +1,148 @@
|
||||
package expression
|
||||
|
||||
import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ProjectionBuilder represents Projection Expressions in DynamoDB.
|
||||
// ProjectionBuilders are the building blocks of Builders.
|
||||
// More Information at: http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.ProjectionExpressions.html
|
||||
type ProjectionBuilder struct {
|
||||
names []NameBuilder
|
||||
}
|
||||
|
||||
// NamesList returns a ProjectionBuilder representing the list of item
|
||||
// attribute names specified by the argument NameBuilders. The resulting
|
||||
// ProjectionBuilder can be used as a part of other ProjectionBuilders or as an
|
||||
// argument to the WithProjection() method for the Builder struct.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// // projection represents the list of names {"foo", "bar"}
|
||||
// projection := expression.NamesList(expression.Name("foo"), expression.Name("bar"))
|
||||
//
|
||||
// // Used in another Projection Expression
|
||||
// anotherProjection := expression.AddNames(projection, expression.Name("baz"))
|
||||
// // Used to make an Builder
|
||||
// builder := expression.NewBuilder().WithProjection(newProjection)
|
||||
//
|
||||
// Expression Equivalent:
|
||||
//
|
||||
// expression.NamesList(expression.Name("foo"), expression.Name("bar"))
|
||||
// "foo, bar"
|
||||
func NamesList(nameBuilder NameBuilder, namesList ...NameBuilder) ProjectionBuilder {
|
||||
namesList = append([]NameBuilder{nameBuilder}, namesList...)
|
||||
return ProjectionBuilder{
|
||||
names: namesList,
|
||||
}
|
||||
}
|
||||
|
||||
// NamesList returns a ProjectionBuilder representing the list of item
|
||||
// attribute names specified by the argument NameBuilders. The resulting
|
||||
// ProjectionBuilder can be used as a part of other ProjectionBuilders or as an
|
||||
// argument to the WithProjection() method for the Builder struct.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// // projection represents the list of names {"foo", "bar"}
|
||||
// projection := expression.Name("foo").NamesList(expression.Name("bar"))
|
||||
//
|
||||
// // Used in another Projection Expression
|
||||
// anotherProjection := expression.AddNames(projection, expression.Name("baz"))
|
||||
// // Used to make an Builder
|
||||
// builder := expression.NewBuilder().WithProjection(newProjection)
|
||||
//
|
||||
// Expression Equivalent:
|
||||
//
|
||||
// expression.Name("foo").NamesList(expression.Name("bar"))
|
||||
// "foo, bar"
|
||||
func (nb NameBuilder) NamesList(namesList ...NameBuilder) ProjectionBuilder {
|
||||
return NamesList(nb, namesList...)
|
||||
}
|
||||
|
||||
// AddNames returns a ProjectionBuilder representing the list of item
|
||||
// attribute names equivalent to appending all of the argument item attribute
|
||||
// names to the argument ProjectionBuilder. The resulting ProjectionBuilder can
|
||||
// be used as a part of other ProjectionBuilders or as an argument to the
|
||||
// WithProjection() method for the Builder struct.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// // projection represents the list of names {"foo", "bar", "baz", "qux"}
|
||||
// oldProj := expression.NamesList(expression.Name("foo"), expression.Name("bar"))
|
||||
// projection := expression.AddNames(oldProj, expression.Name("baz"), expression.Name("qux"))
|
||||
//
|
||||
// // Used in another Projection Expression
|
||||
// anotherProjection := expression.AddNames(projection, expression.Name("quux"))
|
||||
// // Used to make an Builder
|
||||
// builder := expression.NewBuilder().WithProjection(newProjection)
|
||||
//
|
||||
// Expression Equivalent:
|
||||
//
|
||||
// expression.AddNames(expression.NamesList(expression.Name("foo"), expression.Name("bar")), expression.Name("baz"), expression.Name("qux"))
|
||||
// "foo, bar, baz, qux"
|
||||
func AddNames(projectionBuilder ProjectionBuilder, namesList ...NameBuilder) ProjectionBuilder {
|
||||
projectionBuilder.names = append(projectionBuilder.names, namesList...)
|
||||
return projectionBuilder
|
||||
}
|
||||
|
||||
// AddNames returns a ProjectionBuilder representing the list of item
|
||||
// attribute names equivalent to appending all of the argument item attribute
|
||||
// names to the argument ProjectionBuilder. The resulting ProjectionBuilder can
|
||||
// be used as a part of other ProjectionBuilders or as an argument to the
|
||||
// WithProjection() method for the Builder struct.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// // projection represents the list of names {"foo", "bar", "baz", "qux"}
|
||||
// oldProj := expression.NamesList(expression.Name("foo"), expression.Name("bar"))
|
||||
// projection := oldProj.AddNames(expression.Name("baz"), expression.Name("qux"))
|
||||
//
|
||||
// // Used in another Projection Expression
|
||||
// anotherProjection := expression.AddNames(projection, expression.Name("quux"))
|
||||
// // Used to make an Builder
|
||||
// builder := expression.NewBuilder().WithProjection(newProjection)
|
||||
//
|
||||
// Expression Equivalent:
|
||||
//
|
||||
// expression.NamesList(expression.Name("foo"), expression.Name("bar")).AddNames(expression.Name("baz"), expression.Name("qux"))
|
||||
// "foo, bar, baz, qux"
|
||||
func (pb ProjectionBuilder) AddNames(namesList ...NameBuilder) ProjectionBuilder {
|
||||
return AddNames(pb, namesList...)
|
||||
}
|
||||
|
||||
// buildTree builds a tree structure of exprNodes based on the tree
|
||||
// structure of the input ProjectionBuilder's child NameBuilders. buildTree()
|
||||
// satisfies the treeBuilder interface so ProjectionBuilder can be a part of
|
||||
// Builder and Expression struct.
|
||||
func (pb ProjectionBuilder) buildTree() (exprNode, error) {
|
||||
if len(pb.names) == 0 {
|
||||
return exprNode{}, newUnsetParameterError("buildTree", "ProjectionBuilder")
|
||||
}
|
||||
|
||||
childNodes, err := pb.buildChildNodes()
|
||||
if err != nil {
|
||||
return exprNode{}, err
|
||||
}
|
||||
ret := exprNode{
|
||||
children: childNodes,
|
||||
}
|
||||
|
||||
ret.fmtExpr = "$c" + strings.Repeat(", $c", len(pb.names)-1)
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
// buildChildNodes creates the list of the child exprNodes.
|
||||
func (pb ProjectionBuilder) buildChildNodes() ([]exprNode, error) {
|
||||
childNodes := make([]exprNode, 0, len(pb.names))
|
||||
for _, name := range pb.names {
|
||||
operand, err := name.BuildOperand()
|
||||
if err != nil {
|
||||
return []exprNode{}, err
|
||||
}
|
||||
childNodes = append(childNodes, operand.exprNode)
|
||||
}
|
||||
|
||||
return childNodes, nil
|
||||
}
|
||||
215
vendor/github.com/aws/aws-sdk-go/service/dynamodb/expression/projection_test.go
generated
vendored
Normal file
215
vendor/github.com/aws/aws-sdk-go/service/dynamodb/expression/projection_test.go
generated
vendored
Normal file
@@ -0,0 +1,215 @@
|
||||
// +build go1.7
|
||||
|
||||
package expression
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// projErrorMode will help with error cases and checking error types
|
||||
type projErrorMode string
|
||||
|
||||
const (
|
||||
noProjError projErrorMode = ""
|
||||
// invalidProjectionOperand error will occur when an invalid OperandBuilder is
|
||||
// used as an argument
|
||||
invalidProjectionOperand = "BuildOperand error"
|
||||
// unsetProjection error will occur if the argument ProjectionBuilder is unset
|
||||
unsetProjection = "unset parameter: ProjectionBuilder"
|
||||
)
|
||||
|
||||
func TestProjectionBuilder(t *testing.T) {
|
||||
cases := []struct {
|
||||
name string
|
||||
input ProjectionBuilder
|
||||
expectedNode exprNode
|
||||
err projErrorMode
|
||||
}{
|
||||
{
|
||||
name: "names list function call",
|
||||
input: NamesList(Name("foo"), Name("bar")),
|
||||
expectedNode: exprNode{
|
||||
children: []exprNode{
|
||||
{
|
||||
names: []string{"foo"},
|
||||
fmtExpr: "$n",
|
||||
},
|
||||
{
|
||||
names: []string{"bar"},
|
||||
fmtExpr: "$n",
|
||||
},
|
||||
},
|
||||
fmtExpr: "$c, $c",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "names list method call",
|
||||
input: Name("foo").NamesList(Name("bar")),
|
||||
expectedNode: exprNode{
|
||||
children: []exprNode{
|
||||
{
|
||||
names: []string{"foo"},
|
||||
fmtExpr: "$n",
|
||||
},
|
||||
{
|
||||
names: []string{"bar"},
|
||||
fmtExpr: "$n",
|
||||
},
|
||||
},
|
||||
fmtExpr: "$c, $c",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "add name",
|
||||
input: Name("foo").NamesList(Name("bar")).AddNames(Name("baz"), Name("qux")),
|
||||
expectedNode: exprNode{
|
||||
children: []exprNode{
|
||||
{
|
||||
names: []string{"foo"},
|
||||
fmtExpr: "$n",
|
||||
},
|
||||
{
|
||||
names: []string{"bar"},
|
||||
fmtExpr: "$n",
|
||||
},
|
||||
{
|
||||
names: []string{"baz"},
|
||||
fmtExpr: "$n",
|
||||
}, {
|
||||
names: []string{"qux"},
|
||||
fmtExpr: "$n",
|
||||
},
|
||||
},
|
||||
fmtExpr: "$c, $c, $c, $c",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "invalid operand",
|
||||
input: NamesList(Name("")),
|
||||
err: invalidProjectionOperand,
|
||||
},
|
||||
}
|
||||
for _, c := range cases {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
actual, err := c.input.buildTree()
|
||||
if c.err != noProjError {
|
||||
if err == nil {
|
||||
t.Errorf("expect error %q, got no error", c.err)
|
||||
} else {
|
||||
if e, a := string(c.err), err.Error(); !strings.Contains(a, e) {
|
||||
t.Errorf("expect %q error message to be in %q", e, a)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if err != nil {
|
||||
t.Errorf("expect no error, got unexpected Error %q", err)
|
||||
}
|
||||
if e, a := c.expectedNode, actual; !reflect.DeepEqual(a, e) {
|
||||
t.Errorf("expect %v, got %v", e, a)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildProjection(t *testing.T) {
|
||||
cases := []struct {
|
||||
name string
|
||||
input ProjectionBuilder
|
||||
expected string
|
||||
err projErrorMode
|
||||
}{
|
||||
{
|
||||
name: "build projection 3",
|
||||
input: NamesList(Name("foo"), Name("bar"), Name("baz")),
|
||||
expected: "$c, $c, $c",
|
||||
},
|
||||
{
|
||||
name: "build projection 5",
|
||||
input: NamesList(Name("foo"), Name("bar"), Name("baz")).AddNames(Name("qux"), Name("quux")),
|
||||
expected: "$c, $c, $c, $c, $c",
|
||||
},
|
||||
{
|
||||
name: "empty ProjectionBuilder",
|
||||
input: ProjectionBuilder{},
|
||||
err: unsetProjection,
|
||||
},
|
||||
}
|
||||
for _, c := range cases {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
actual, err := c.input.buildTree()
|
||||
if c.err != noProjError {
|
||||
if err == nil {
|
||||
t.Errorf("expect error %q, got no error", c.err)
|
||||
} else {
|
||||
if e, a := string(c.err), err.Error(); !strings.Contains(a, e) {
|
||||
t.Errorf("expect %q error message to be in %q", e, a)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if err != nil {
|
||||
t.Errorf("expect no error, got unexpected Error %q", err)
|
||||
}
|
||||
if e, a := c.expected, actual.fmtExpr; !reflect.DeepEqual(a, e) {
|
||||
t.Errorf("expect %v, got %v", e, a)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildProjectionChildNodes(t *testing.T) {
|
||||
cases := []struct {
|
||||
name string
|
||||
input ProjectionBuilder
|
||||
expected []exprNode
|
||||
err projErrorMode
|
||||
}{
|
||||
{
|
||||
name: "build child nodes",
|
||||
input: NamesList(Name("foo"), Name("bar"), Name("baz")),
|
||||
expected: []exprNode{
|
||||
{
|
||||
names: []string{"foo"},
|
||||
fmtExpr: "$n",
|
||||
},
|
||||
{
|
||||
names: []string{"bar"},
|
||||
fmtExpr: "$n",
|
||||
},
|
||||
{
|
||||
names: []string{"baz"},
|
||||
fmtExpr: "$n",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "operand error",
|
||||
input: NamesList(Name("")),
|
||||
err: invalidProjectionOperand,
|
||||
},
|
||||
}
|
||||
for _, c := range cases {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
actual, err := c.input.buildTree()
|
||||
if c.err != noProjError {
|
||||
if err == nil {
|
||||
t.Errorf("expect error %q, got no error", c.err)
|
||||
} else {
|
||||
if e, a := string(c.err), err.Error(); !strings.Contains(a, e) {
|
||||
t.Errorf("expect %q error message to be in %q", e, a)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if err != nil {
|
||||
t.Errorf("expect no error, got unexpected Error %q", err)
|
||||
}
|
||||
if e, a := c.expected, actual.children; !reflect.DeepEqual(a, e) {
|
||||
t.Errorf("expect %v, got %v", e, a)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
391
vendor/github.com/aws/aws-sdk-go/service/dynamodb/expression/update.go
generated
vendored
Normal file
391
vendor/github.com/aws/aws-sdk-go/service/dynamodb/expression/update.go
generated
vendored
Normal file
@@ -0,0 +1,391 @@
|
||||
package expression
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// operationMode specifies the types of update operations that the
|
||||
// updateBuilder is going to represent. The const is in a string to use the
|
||||
// const value as a map key and as a string when creating the formatted
|
||||
// expression for the exprNodes.
|
||||
type operationMode string
|
||||
|
||||
const (
|
||||
setOperation operationMode = "SET"
|
||||
removeOperation = "REMOVE"
|
||||
addOperation = "ADD"
|
||||
deleteOperation = "DELETE"
|
||||
)
|
||||
|
||||
// Implementing the Sort interface
|
||||
type modeList []operationMode
|
||||
|
||||
func (ml modeList) Len() int {
|
||||
return len(ml)
|
||||
}
|
||||
|
||||
func (ml modeList) Less(i, j int) bool {
|
||||
return string(ml[i]) < string(ml[j])
|
||||
}
|
||||
|
||||
func (ml modeList) Swap(i, j int) {
|
||||
ml[i], ml[j] = ml[j], ml[i]
|
||||
}
|
||||
|
||||
// UpdateBuilder represents Update Expressions in DynamoDB. UpdateBuilders
|
||||
// are the building blocks of the Builder struct. Note that there are different
|
||||
// update operations in DynamoDB and an UpdateBuilder can represent multiple
|
||||
// update operations.
|
||||
// More Information at: http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.UpdateExpressions.html
|
||||
type UpdateBuilder struct {
|
||||
operationList map[operationMode][]operationBuilder
|
||||
}
|
||||
|
||||
// operationBuilder represents specific update actions (SET, REMOVE, ADD,
|
||||
// DELETE). The mode specifies what type of update action the
|
||||
// operationBuilder represents.
|
||||
type operationBuilder struct {
|
||||
name NameBuilder
|
||||
value OperandBuilder
|
||||
mode operationMode
|
||||
}
|
||||
|
||||
// buildOperation builds an exprNode from an operationBuilder. buildOperation
|
||||
// is called recursively by buildTree in order to create a tree structure
|
||||
// of exprNodes representing the parent/child relationships between
|
||||
// UpdateBuilders and operationBuilders.
|
||||
func (ob operationBuilder) buildOperation() (exprNode, error) {
|
||||
pathChild, err := ob.name.BuildOperand()
|
||||
if err != nil {
|
||||
return exprNode{}, err
|
||||
}
|
||||
|
||||
node := exprNode{
|
||||
children: []exprNode{pathChild.exprNode},
|
||||
fmtExpr: "$c",
|
||||
}
|
||||
|
||||
if ob.mode == removeOperation {
|
||||
return node, nil
|
||||
}
|
||||
|
||||
valueChild, err := ob.value.BuildOperand()
|
||||
if err != nil {
|
||||
return exprNode{}, err
|
||||
}
|
||||
node.children = append(node.children, valueChild.exprNode)
|
||||
|
||||
switch ob.mode {
|
||||
case setOperation:
|
||||
node.fmtExpr += " = $c"
|
||||
case addOperation, deleteOperation:
|
||||
node.fmtExpr += " $c"
|
||||
default:
|
||||
return exprNode{}, fmt.Errorf("build update error: build operation error: unsupported mode: %v", ob.mode)
|
||||
}
|
||||
|
||||
return node, nil
|
||||
}
|
||||
|
||||
// Delete returns an UpdateBuilder representing one Delete operation for
|
||||
// DynamoDB Update Expressions. The argument name should specify the item
|
||||
// attribute and the argument value should specify the value to be deleted. The
|
||||
// resulting UpdateBuilder can be used as an argument to the WithUpdate() method
|
||||
// for the Builder struct.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// // update represents the delete operation to delete the string value
|
||||
// // "subsetToDelete" from the item attribute "pathToList"
|
||||
// update := expression.Delete(expression.Name("pathToList"), expression.Value("subsetToDelete"))
|
||||
//
|
||||
// // Adding more update methods
|
||||
// anotherUpdate := update.Remove(expression.Name("someName"))
|
||||
// // Creating a Builder
|
||||
// builder := Update(update)
|
||||
//
|
||||
// Expression Equivalent:
|
||||
//
|
||||
// expression.Delete(expression.Name("pathToList"), expression.Value("subsetToDelete"))
|
||||
// // let :del be an ExpressionAttributeValue representing the value
|
||||
// // "subsetToDelete"
|
||||
// "DELETE pathToList :del"
|
||||
func Delete(name NameBuilder, value ValueBuilder) UpdateBuilder {
|
||||
emptyUpdateBuilder := UpdateBuilder{}
|
||||
return emptyUpdateBuilder.Delete(name, value)
|
||||
}
|
||||
|
||||
// Delete adds a Delete operation to the argument UpdateBuilder. The
|
||||
// argument name should specify the item attribute and the argument value should
|
||||
// specify the value to be deleted. The resulting UpdateBuilder can be used as
|
||||
// an argument to the WithUpdate() method for the Builder struct.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// // Let update represent an already existing update expression. Delete()
|
||||
// // adds the operation to delete the value "subsetToDelete" from the item
|
||||
// // attribute "pathToList"
|
||||
// update := update.Delete(expression.Name("pathToList"), expression.Value("subsetToDelete"))
|
||||
//
|
||||
// // Adding more update methods
|
||||
// anotherUpdate := update.Remove(expression.Name("someName"))
|
||||
// // Creating a Builder
|
||||
// builder := Update(update)
|
||||
//
|
||||
// Expression Equivalent:
|
||||
//
|
||||
// Delete(expression.Name("pathToList"), expression.Value("subsetToDelete"))
|
||||
// // let :del be an ExpressionAttributeValue representing the value
|
||||
// // "subsetToDelete"
|
||||
// "DELETE pathToList :del"
|
||||
func (ub UpdateBuilder) Delete(name NameBuilder, value ValueBuilder) UpdateBuilder {
|
||||
if ub.operationList == nil {
|
||||
ub.operationList = map[operationMode][]operationBuilder{}
|
||||
}
|
||||
ub.operationList[deleteOperation] = append(ub.operationList[deleteOperation], operationBuilder{
|
||||
name: name,
|
||||
value: value,
|
||||
mode: deleteOperation,
|
||||
})
|
||||
return ub
|
||||
}
|
||||
|
||||
// Add returns an UpdateBuilder representing the Add operation for DynamoDB
|
||||
// Update Expressions. The argument name should specify the item attribute and
|
||||
// the argument value should specify the value to be added. The resulting
|
||||
// UpdateBuilder can be used as an argument to the WithUpdate() method for the
|
||||
// Builder struct.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// // update represents the add operation to add the value 5 to the item
|
||||
// // attribute "aPath"
|
||||
// update := expression.Add(expression.Name("aPath"), expression.Value(5))
|
||||
//
|
||||
// // Adding more update methods
|
||||
// anotherUpdate := update.Remove(expression.Name("someName"))
|
||||
// // Creating a Builder
|
||||
// builder := Update(update)
|
||||
//
|
||||
// Expression Equivalent:
|
||||
//
|
||||
// expression.Add(expression.Name("aPath"), expression.Value(5))
|
||||
// // Let :five be an ExpressionAttributeValue representing the value 5
|
||||
// "ADD aPath :5"
|
||||
func Add(name NameBuilder, value ValueBuilder) UpdateBuilder {
|
||||
emptyUpdateBuilder := UpdateBuilder{}
|
||||
return emptyUpdateBuilder.Add(name, value)
|
||||
}
|
||||
|
||||
// Add adds an Add operation to the argument UpdateBuilder. The argument
|
||||
// name should specify the item attribute and the argument value should specify
|
||||
// the value to be added. The resulting UpdateBuilder can be used as an argument
|
||||
// to the WithUpdate() method for the Builder struct.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// // Let update represent an already existing update expression. Add() adds
|
||||
// // the operation to add the value 5 to the item attribute "aPath"
|
||||
// update := update.Add(expression.Name("aPath"), expression.Value(5))
|
||||
//
|
||||
// // Adding more update methods
|
||||
// anotherUpdate := update.Remove(expression.Name("someName"))
|
||||
// // Creating a Builder
|
||||
// builder := Update(update)
|
||||
//
|
||||
// Expression Equivalent:
|
||||
//
|
||||
// Add(expression.Name("aPath"), expression.Value(5))
|
||||
// // Let :five be an ExpressionAttributeValue representing the value 5
|
||||
// "ADD aPath :5"
|
||||
func (ub UpdateBuilder) Add(name NameBuilder, value ValueBuilder) UpdateBuilder {
|
||||
if ub.operationList == nil {
|
||||
ub.operationList = map[operationMode][]operationBuilder{}
|
||||
}
|
||||
ub.operationList[addOperation] = append(ub.operationList[addOperation], operationBuilder{
|
||||
name: name,
|
||||
value: value,
|
||||
mode: addOperation,
|
||||
})
|
||||
return ub
|
||||
}
|
||||
|
||||
// Remove returns an UpdateBuilder representing the Remove operation for
|
||||
// DynamoDB Update Expressions. The argument name should specify the item
|
||||
// attribute to delete. The resulting UpdateBuilder can be used as an argument
|
||||
// to the WithUpdate() method for the Builder struct.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// // update represents the remove operation to remove the item attribute
|
||||
// // "itemToRemove"
|
||||
// update := expression.Remove(expression.Name("itemToRemove"))
|
||||
//
|
||||
// // Adding more update methods
|
||||
// anotherUpdate := update.Remove(expression.Name("someName"))
|
||||
// // Creating a Builder
|
||||
// builder := Update(update)
|
||||
//
|
||||
// Expression Equivalent:
|
||||
//
|
||||
// expression.Remove(expression.Name("itemToRemove"))
|
||||
// "REMOVE itemToRemove"
|
||||
func Remove(name NameBuilder) UpdateBuilder {
|
||||
emptyUpdateBuilder := UpdateBuilder{}
|
||||
return emptyUpdateBuilder.Remove(name)
|
||||
}
|
||||
|
||||
// Remove adds a Remove operation to the argument UpdateBuilder. The
|
||||
// argument name should specify the item attribute to delete. The resulting
|
||||
// UpdateBuilder can be used as an argument to the WithUpdate() method for the
|
||||
// Builder struct.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// // Let update represent an already existing update expression. Remove()
|
||||
// // adds the operation to remove the item attribute "itemToRemove"
|
||||
// update := update.Remove(expression.Name("itemToRemove"))
|
||||
//
|
||||
// // Adding more update methods
|
||||
// anotherUpdate := update.Remove(expression.Name("someName"))
|
||||
// // Creating a Builder
|
||||
// builder := Update(update)
|
||||
//
|
||||
// Expression Equivalent:
|
||||
//
|
||||
// Remove(expression.Name("itemToRemove"))
|
||||
// "REMOVE itemToRemove"
|
||||
func (ub UpdateBuilder) Remove(name NameBuilder) UpdateBuilder {
|
||||
if ub.operationList == nil {
|
||||
ub.operationList = map[operationMode][]operationBuilder{}
|
||||
}
|
||||
ub.operationList[removeOperation] = append(ub.operationList[removeOperation], operationBuilder{
|
||||
name: name,
|
||||
mode: removeOperation,
|
||||
})
|
||||
return ub
|
||||
}
|
||||
|
||||
// Set returns an UpdateBuilder representing the Set operation for DynamoDB
|
||||
// Update Expressions. The argument name should specify the item attribute to
|
||||
// modify. The argument OperandBuilder should specify the value to modify the
|
||||
// the item attribute to. The resulting UpdateBuilder can be used as an argument
|
||||
// to the WithUpdate() method for the Builder struct.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// // update represents the set operation to set the item attribute
|
||||
// // "itemToSet" to the value "setValue" if the item attribute does not
|
||||
// // exist yet. (conditional write)
|
||||
// update := expression.Set(expression.Name("itemToSet"), expression.IfNotExists(expression.Name("itemToSet"), expression.Value("setValue")))
|
||||
//
|
||||
// // Adding more update methods
|
||||
// anotherUpdate := update.Remove(expression.Name("someName"))
|
||||
// // Creating a Builder
|
||||
// builder := Update(update)
|
||||
//
|
||||
// Expression Equivalent:
|
||||
//
|
||||
// expression.Set(expression.Name("itemToSet"), expression.IfNotExists(expression.Name("itemToSet"), expression.Value("setValue")))
|
||||
// // Let :val be an ExpressionAttributeValue representing the value
|
||||
// // "setValue"
|
||||
// "SET itemToSet = :val"
|
||||
func Set(name NameBuilder, operandBuilder OperandBuilder) UpdateBuilder {
|
||||
emptyUpdateBuilder := UpdateBuilder{}
|
||||
return emptyUpdateBuilder.Set(name, operandBuilder)
|
||||
}
|
||||
|
||||
// Set adds a Set operation to the argument UpdateBuilder. The argument name
|
||||
// should specify the item attribute to modify. The argument OperandBuilder
|
||||
// should specify the value to modify the the item attribute to. The resulting
|
||||
// UpdateBuilder can be used as an argument to the WithUpdate() method for the
|
||||
// Builder struct.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// // Let update represent an already existing update expression. Set() adds
|
||||
// // the operation to to set the item attribute "itemToSet" to the value
|
||||
// // "setValue" if the item attribute does not exist yet. (conditional
|
||||
// // write)
|
||||
// update := update.Set(expression.Name("itemToSet"), expression.IfNotExists(expression.Name("itemToSet"), expression.Value("setValue")))
|
||||
//
|
||||
// // Adding more update methods
|
||||
// anotherUpdate := update.Remove(expression.Name("someName"))
|
||||
// // Creating a Builder
|
||||
// builder := Update(update)
|
||||
//
|
||||
// Expression Equivalent:
|
||||
//
|
||||
// Set(expression.Name("itemToSet"), expression.IfNotExists(expression.Name("itemToSet"), expression.Value("setValue")))
|
||||
// // Let :val be an ExpressionAttributeValue representing the value
|
||||
// // "setValue"
|
||||
// "SET itemToSet = :val"
|
||||
func (ub UpdateBuilder) Set(name NameBuilder, operandBuilder OperandBuilder) UpdateBuilder {
|
||||
if ub.operationList == nil {
|
||||
ub.operationList = map[operationMode][]operationBuilder{}
|
||||
}
|
||||
ub.operationList[setOperation] = append(ub.operationList[setOperation], operationBuilder{
|
||||
name: name,
|
||||
value: operandBuilder,
|
||||
mode: setOperation,
|
||||
})
|
||||
return ub
|
||||
}
|
||||
|
||||
// buildTree builds a tree structure of exprNodes based on the tree
|
||||
// structure of the input UpdateBuilder's child UpdateBuilders/Operands.
|
||||
// buildTree() satisfies the TreeBuilder interface so ProjectionBuilder can be a
|
||||
// part of Expression struct.
|
||||
func (ub UpdateBuilder) buildTree() (exprNode, error) {
|
||||
if ub.operationList == nil {
|
||||
return exprNode{}, newUnsetParameterError("buildTree", "UpdateBuilder")
|
||||
}
|
||||
ret := exprNode{
|
||||
children: []exprNode{},
|
||||
}
|
||||
|
||||
modes := modeList{}
|
||||
|
||||
for mode := range ub.operationList {
|
||||
modes = append(modes, mode)
|
||||
}
|
||||
|
||||
sort.Sort(modes)
|
||||
|
||||
for _, key := range modes {
|
||||
ret.fmtExpr += string(key) + " $c\n"
|
||||
|
||||
childNode, err := buildChildNodes(ub.operationList[key])
|
||||
if err != nil {
|
||||
return exprNode{}, err
|
||||
}
|
||||
|
||||
ret.children = append(ret.children, childNode)
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
// buildChildNodes creates the list of the child exprNodes.
|
||||
func buildChildNodes(operationBuilderList []operationBuilder) (exprNode, error) {
|
||||
if len(operationBuilderList) == 0 {
|
||||
return exprNode{}, fmt.Errorf("buildChildNodes error: operationBuilder list is empty")
|
||||
}
|
||||
|
||||
node := exprNode{
|
||||
children: make([]exprNode, 0, len(operationBuilderList)),
|
||||
fmtExpr: "$c" + strings.Repeat(", $c", len(operationBuilderList)-1),
|
||||
}
|
||||
|
||||
for _, val := range operationBuilderList {
|
||||
valNode, err := val.buildOperation()
|
||||
if err != nil {
|
||||
return exprNode{}, err
|
||||
}
|
||||
node.children = append(node.children, valNode)
|
||||
}
|
||||
|
||||
return node, nil
|
||||
}
|
||||
771
vendor/github.com/aws/aws-sdk-go/service/dynamodb/expression/update_test.go
generated
vendored
Normal file
771
vendor/github.com/aws/aws-sdk-go/service/dynamodb/expression/update_test.go
generated
vendored
Normal file
@@ -0,0 +1,771 @@
|
||||
// +build go1.7
|
||||
|
||||
package expression
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/service/dynamodb"
|
||||
)
|
||||
|
||||
// updateErrorMode will help with error cases and checking error types
|
||||
type updateErrorMode string
|
||||
|
||||
const (
|
||||
noUpdateError updateErrorMode = ""
|
||||
invalidUpdateOperand = "BuildOperand error"
|
||||
unsetSetValue = "unset parameter: SetValueBuilder"
|
||||
unsetUpdate = "unset parameter: UpdateBuilder"
|
||||
emptyOperationBuilderList = "operationBuilder list is empty"
|
||||
)
|
||||
|
||||
func TestBuildOperation(t *testing.T) {
|
||||
cases := []struct {
|
||||
name string
|
||||
input operationBuilder
|
||||
expected exprNode
|
||||
err updateErrorMode
|
||||
}{
|
||||
{
|
||||
name: "set operation",
|
||||
input: operationBuilder{
|
||||
name: Name("foo"),
|
||||
value: Value(5),
|
||||
mode: setOperation,
|
||||
},
|
||||
expected: exprNode{
|
||||
children: []exprNode{
|
||||
{
|
||||
names: []string{"foo"},
|
||||
fmtExpr: "$n",
|
||||
},
|
||||
{
|
||||
values: []dynamodb.AttributeValue{
|
||||
{
|
||||
N: aws.String("5"),
|
||||
},
|
||||
},
|
||||
fmtExpr: "$v",
|
||||
},
|
||||
},
|
||||
fmtExpr: "$c = $c",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "add operation",
|
||||
input: operationBuilder{
|
||||
name: Name("foo"),
|
||||
value: Value(5),
|
||||
mode: addOperation,
|
||||
},
|
||||
expected: exprNode{
|
||||
children: []exprNode{
|
||||
{
|
||||
names: []string{"foo"},
|
||||
fmtExpr: "$n",
|
||||
},
|
||||
{
|
||||
values: []dynamodb.AttributeValue{
|
||||
{
|
||||
N: aws.String("5"),
|
||||
},
|
||||
},
|
||||
fmtExpr: "$v",
|
||||
},
|
||||
},
|
||||
fmtExpr: "$c $c",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "remove operation",
|
||||
input: operationBuilder{
|
||||
name: Name("foo"),
|
||||
mode: removeOperation,
|
||||
},
|
||||
expected: exprNode{
|
||||
children: []exprNode{
|
||||
{
|
||||
names: []string{"foo"},
|
||||
fmtExpr: "$n",
|
||||
},
|
||||
},
|
||||
fmtExpr: "$c",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "invalid operand",
|
||||
input: operationBuilder{
|
||||
name: Name(""),
|
||||
mode: removeOperation,
|
||||
},
|
||||
err: invalidUpdateOperand,
|
||||
},
|
||||
}
|
||||
for _, c := range cases {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
actual, err := c.input.buildOperation()
|
||||
if c.err != noUpdateError {
|
||||
if err == nil {
|
||||
t.Errorf("expect error %q, got no error", c.err)
|
||||
} else {
|
||||
if e, a := string(c.err), err.Error(); !strings.Contains(a, e) {
|
||||
t.Errorf("expect %q error message to be in %q", e, a)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if err != nil {
|
||||
t.Errorf("expect no error, got unexpected Error %q", err)
|
||||
}
|
||||
|
||||
if e, a := c.expected, actual; !reflect.DeepEqual(a, e) {
|
||||
t.Errorf("expect %v, got %v", e, a)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdateTree(t *testing.T) {
|
||||
cases := []struct {
|
||||
name string
|
||||
input UpdateBuilder
|
||||
expectedNode exprNode
|
||||
err updateErrorMode
|
||||
}{
|
||||
{
|
||||
name: "set update",
|
||||
input: Set(Name("foo"), Value(5)),
|
||||
expectedNode: exprNode{
|
||||
children: []exprNode{
|
||||
{
|
||||
children: []exprNode{
|
||||
{
|
||||
children: []exprNode{
|
||||
{
|
||||
names: []string{"foo"},
|
||||
fmtExpr: "$n",
|
||||
},
|
||||
{
|
||||
values: []dynamodb.AttributeValue{
|
||||
{
|
||||
N: aws.String("5"),
|
||||
},
|
||||
},
|
||||
fmtExpr: "$v",
|
||||
},
|
||||
},
|
||||
fmtExpr: "$c = $c",
|
||||
},
|
||||
},
|
||||
fmtExpr: "$c",
|
||||
},
|
||||
},
|
||||
fmtExpr: "SET $c\n",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "remove update",
|
||||
input: Remove(Name("foo")),
|
||||
expectedNode: exprNode{
|
||||
children: []exprNode{
|
||||
{
|
||||
children: []exprNode{
|
||||
{
|
||||
children: []exprNode{
|
||||
{
|
||||
names: []string{"foo"},
|
||||
fmtExpr: "$n",
|
||||
},
|
||||
},
|
||||
fmtExpr: "$c",
|
||||
},
|
||||
},
|
||||
fmtExpr: "$c",
|
||||
},
|
||||
},
|
||||
fmtExpr: "REMOVE $c\n",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "add update",
|
||||
input: Add(Name("foo"), Value(5)),
|
||||
expectedNode: exprNode{
|
||||
children: []exprNode{
|
||||
{
|
||||
children: []exprNode{
|
||||
{
|
||||
children: []exprNode{
|
||||
{
|
||||
names: []string{"foo"},
|
||||
fmtExpr: "$n",
|
||||
},
|
||||
{
|
||||
values: []dynamodb.AttributeValue{
|
||||
{
|
||||
N: aws.String("5"),
|
||||
},
|
||||
},
|
||||
fmtExpr: "$v",
|
||||
},
|
||||
},
|
||||
fmtExpr: "$c $c",
|
||||
},
|
||||
},
|
||||
fmtExpr: "$c",
|
||||
},
|
||||
},
|
||||
fmtExpr: "ADD $c\n",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "delete update",
|
||||
input: Delete(Name("foo"), Value(5)),
|
||||
expectedNode: exprNode{
|
||||
children: []exprNode{
|
||||
{
|
||||
children: []exprNode{
|
||||
{
|
||||
children: []exprNode{
|
||||
{
|
||||
names: []string{"foo"},
|
||||
fmtExpr: "$n",
|
||||
},
|
||||
{
|
||||
values: []dynamodb.AttributeValue{
|
||||
{
|
||||
N: aws.String("5"),
|
||||
},
|
||||
},
|
||||
fmtExpr: "$v",
|
||||
},
|
||||
},
|
||||
fmtExpr: "$c $c",
|
||||
},
|
||||
},
|
||||
fmtExpr: "$c",
|
||||
},
|
||||
},
|
||||
fmtExpr: "DELETE $c\n",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "multiple sets",
|
||||
input: Set(Name("foo"), Value(5)).Set(Name("bar"), Value(6)).Set(Name("baz"), Name("qux")),
|
||||
expectedNode: exprNode{
|
||||
fmtExpr: "SET $c\n",
|
||||
children: []exprNode{
|
||||
{
|
||||
fmtExpr: "$c, $c, $c",
|
||||
children: []exprNode{
|
||||
{
|
||||
fmtExpr: "$c = $c",
|
||||
children: []exprNode{
|
||||
{
|
||||
fmtExpr: "$n",
|
||||
names: []string{"foo"},
|
||||
},
|
||||
{
|
||||
fmtExpr: "$v",
|
||||
values: []dynamodb.AttributeValue{
|
||||
{
|
||||
N: aws.String("5"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
fmtExpr: "$c = $c",
|
||||
children: []exprNode{
|
||||
{
|
||||
fmtExpr: "$n",
|
||||
names: []string{"bar"},
|
||||
},
|
||||
{
|
||||
fmtExpr: "$v",
|
||||
values: []dynamodb.AttributeValue{
|
||||
{
|
||||
N: aws.String("6"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
fmtExpr: "$c = $c",
|
||||
children: []exprNode{
|
||||
{
|
||||
fmtExpr: "$n",
|
||||
names: []string{"baz"},
|
||||
},
|
||||
{
|
||||
fmtExpr: "$n",
|
||||
names: []string{"qux"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "compound update",
|
||||
input: Add(Name("foo"), Value(5)).Set(Name("foo"), Value(5)).Delete(Name("foo"), Value(5)).Remove(Name("foo")),
|
||||
expectedNode: exprNode{
|
||||
children: []exprNode{
|
||||
{
|
||||
children: []exprNode{
|
||||
{
|
||||
children: []exprNode{
|
||||
{
|
||||
names: []string{"foo"},
|
||||
fmtExpr: "$n",
|
||||
},
|
||||
{
|
||||
values: []dynamodb.AttributeValue{
|
||||
{
|
||||
N: aws.String("5"),
|
||||
},
|
||||
},
|
||||
fmtExpr: "$v",
|
||||
},
|
||||
},
|
||||
fmtExpr: "$c $c",
|
||||
},
|
||||
},
|
||||
fmtExpr: "$c",
|
||||
},
|
||||
{
|
||||
children: []exprNode{
|
||||
{
|
||||
children: []exprNode{
|
||||
{
|
||||
names: []string{"foo"},
|
||||
fmtExpr: "$n",
|
||||
},
|
||||
{
|
||||
values: []dynamodb.AttributeValue{
|
||||
{
|
||||
N: aws.String("5"),
|
||||
},
|
||||
},
|
||||
fmtExpr: "$v",
|
||||
},
|
||||
},
|
||||
fmtExpr: "$c $c",
|
||||
},
|
||||
},
|
||||
fmtExpr: "$c",
|
||||
},
|
||||
{
|
||||
children: []exprNode{
|
||||
{
|
||||
children: []exprNode{
|
||||
{
|
||||
names: []string{"foo"},
|
||||
fmtExpr: "$n",
|
||||
},
|
||||
},
|
||||
fmtExpr: "$c",
|
||||
},
|
||||
},
|
||||
fmtExpr: "$c",
|
||||
},
|
||||
{
|
||||
children: []exprNode{
|
||||
{
|
||||
children: []exprNode{
|
||||
{
|
||||
names: []string{"foo"},
|
||||
fmtExpr: "$n",
|
||||
},
|
||||
{
|
||||
values: []dynamodb.AttributeValue{
|
||||
{
|
||||
N: aws.String("5"),
|
||||
},
|
||||
},
|
||||
fmtExpr: "$v",
|
||||
},
|
||||
},
|
||||
fmtExpr: "$c = $c",
|
||||
},
|
||||
},
|
||||
fmtExpr: "$c",
|
||||
},
|
||||
},
|
||||
fmtExpr: "ADD $c\nDELETE $c\nREMOVE $c\nSET $c\n",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "empty UpdateBuilder",
|
||||
input: UpdateBuilder{},
|
||||
err: unsetUpdate,
|
||||
},
|
||||
}
|
||||
for _, c := range cases {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
actual, err := c.input.buildTree()
|
||||
if c.err != noUpdateError {
|
||||
if err == nil {
|
||||
t.Errorf("expect error %q, got no error", c.err)
|
||||
} else {
|
||||
if e, a := string(c.err), err.Error(); !strings.Contains(a, e) {
|
||||
t.Errorf("expect %q error message to be in %q", e, a)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if err != nil {
|
||||
t.Errorf("expect no error, got unexpected Error %q", err)
|
||||
}
|
||||
|
||||
if e, a := c.expectedNode, actual; !reflect.DeepEqual(a, e) {
|
||||
t.Errorf("expect %v, got %v", e, a)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetValueBuilder(t *testing.T) {
|
||||
cases := []struct {
|
||||
name string
|
||||
input SetValueBuilder
|
||||
expected exprNode
|
||||
err updateErrorMode
|
||||
}{
|
||||
{
|
||||
name: "name plus name",
|
||||
input: Name("foo").Plus(Name("bar")),
|
||||
expected: exprNode{
|
||||
children: []exprNode{
|
||||
{
|
||||
names: []string{"foo"},
|
||||
fmtExpr: "$n",
|
||||
},
|
||||
{
|
||||
names: []string{"bar"},
|
||||
fmtExpr: "$n",
|
||||
},
|
||||
},
|
||||
fmtExpr: "$c + $c",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "name minus name",
|
||||
input: Name("foo").Minus(Name("bar")),
|
||||
expected: exprNode{
|
||||
children: []exprNode{
|
||||
{
|
||||
names: []string{"foo"},
|
||||
fmtExpr: "$n",
|
||||
},
|
||||
{
|
||||
names: []string{"bar"},
|
||||
fmtExpr: "$n",
|
||||
},
|
||||
},
|
||||
fmtExpr: "$c - $c",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "list append name and name",
|
||||
input: Name("foo").ListAppend(Name("bar")),
|
||||
expected: exprNode{
|
||||
children: []exprNode{
|
||||
{
|
||||
names: []string{"foo"},
|
||||
fmtExpr: "$n",
|
||||
},
|
||||
{
|
||||
names: []string{"bar"},
|
||||
fmtExpr: "$n",
|
||||
},
|
||||
},
|
||||
fmtExpr: "list_append($c, $c)",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "if not exists name and name",
|
||||
input: Name("foo").IfNotExists(Name("bar")),
|
||||
expected: exprNode{
|
||||
children: []exprNode{
|
||||
{
|
||||
names: []string{"foo"},
|
||||
fmtExpr: "$n",
|
||||
},
|
||||
{
|
||||
names: []string{"bar"},
|
||||
fmtExpr: "$n",
|
||||
},
|
||||
},
|
||||
fmtExpr: "if_not_exists($c, $c)",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "value plus name",
|
||||
input: Value(5).Plus(Name("bar")),
|
||||
expected: exprNode{
|
||||
children: []exprNode{
|
||||
{
|
||||
values: []dynamodb.AttributeValue{
|
||||
{
|
||||
N: aws.String("5"),
|
||||
},
|
||||
},
|
||||
fmtExpr: "$v",
|
||||
},
|
||||
{
|
||||
names: []string{"bar"},
|
||||
fmtExpr: "$n",
|
||||
},
|
||||
},
|
||||
fmtExpr: "$c + $c",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "value minus name",
|
||||
input: Value(5).Minus(Name("bar")),
|
||||
expected: exprNode{
|
||||
children: []exprNode{
|
||||
{
|
||||
values: []dynamodb.AttributeValue{
|
||||
{
|
||||
N: aws.String("5"),
|
||||
},
|
||||
},
|
||||
fmtExpr: "$v",
|
||||
},
|
||||
{
|
||||
names: []string{"bar"},
|
||||
fmtExpr: "$n",
|
||||
},
|
||||
},
|
||||
fmtExpr: "$c - $c",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "list append list and name",
|
||||
input: Value([]int{1, 2, 3}).ListAppend(Name("bar")),
|
||||
expected: exprNode{
|
||||
children: []exprNode{
|
||||
{
|
||||
values: []dynamodb.AttributeValue{
|
||||
{
|
||||
L: []*dynamodb.AttributeValue{
|
||||
{
|
||||
N: aws.String("1"),
|
||||
},
|
||||
{
|
||||
N: aws.String("2"),
|
||||
},
|
||||
{
|
||||
N: aws.String("3"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
fmtExpr: "$v",
|
||||
},
|
||||
{
|
||||
names: []string{"bar"},
|
||||
fmtExpr: "$n",
|
||||
},
|
||||
},
|
||||
fmtExpr: "list_append($c, $c)",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "unset SetValueBuilder",
|
||||
input: SetValueBuilder{},
|
||||
err: unsetSetValue,
|
||||
},
|
||||
{
|
||||
name: "invalid operand error",
|
||||
input: Name("").Plus(Name("foo")),
|
||||
err: invalidUpdateOperand,
|
||||
},
|
||||
{
|
||||
name: "invalid operand error",
|
||||
input: Name("foo").Plus(Name("")),
|
||||
err: invalidUpdateOperand,
|
||||
},
|
||||
}
|
||||
for _, c := range cases {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
actual, err := c.input.BuildOperand()
|
||||
if c.err != noUpdateError {
|
||||
if err == nil {
|
||||
t.Errorf("expect error %q, got no error", c.err)
|
||||
} else {
|
||||
if e, a := string(c.err), err.Error(); !strings.Contains(a, e) {
|
||||
t.Errorf("expect %q error message to be in %q", e, a)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if err != nil {
|
||||
t.Errorf("expect no error, got unexpected Error %q", err)
|
||||
}
|
||||
|
||||
if e, a := c.expected, actual.exprNode; !reflect.DeepEqual(a, e) {
|
||||
t.Errorf("expect %v, got %v", e, a)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdateBuildChildNodes(t *testing.T) {
|
||||
cases := []struct {
|
||||
name string
|
||||
input []operationBuilder
|
||||
expected exprNode
|
||||
err updateErrorMode
|
||||
}{
|
||||
{
|
||||
name: "set operand builder",
|
||||
input: []operationBuilder{
|
||||
{
|
||||
mode: setOperation,
|
||||
name: NameBuilder{
|
||||
name: "foo",
|
||||
},
|
||||
value: ValueBuilder{
|
||||
value: 5,
|
||||
},
|
||||
},
|
||||
{
|
||||
mode: setOperation,
|
||||
name: NameBuilder{
|
||||
name: "bar",
|
||||
},
|
||||
value: ValueBuilder{
|
||||
value: 6,
|
||||
},
|
||||
},
|
||||
{
|
||||
mode: setOperation,
|
||||
name: NameBuilder{
|
||||
name: "baz",
|
||||
},
|
||||
value: ValueBuilder{
|
||||
value: 7,
|
||||
},
|
||||
},
|
||||
{
|
||||
mode: setOperation,
|
||||
name: NameBuilder{
|
||||
name: "qux",
|
||||
},
|
||||
value: ValueBuilder{
|
||||
value: 8,
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: exprNode{
|
||||
fmtExpr: "$c, $c, $c, $c",
|
||||
children: []exprNode{
|
||||
{
|
||||
fmtExpr: "$c = $c",
|
||||
children: []exprNode{
|
||||
{
|
||||
fmtExpr: "$n",
|
||||
names: []string{"foo"},
|
||||
},
|
||||
{
|
||||
fmtExpr: "$v",
|
||||
values: []dynamodb.AttributeValue{
|
||||
{
|
||||
N: aws.String("5"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
fmtExpr: "$c = $c",
|
||||
children: []exprNode{
|
||||
{
|
||||
fmtExpr: "$n",
|
||||
names: []string{"bar"},
|
||||
},
|
||||
{
|
||||
fmtExpr: "$v",
|
||||
values: []dynamodb.AttributeValue{
|
||||
{
|
||||
N: aws.String("6"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
fmtExpr: "$c = $c",
|
||||
children: []exprNode{
|
||||
{
|
||||
fmtExpr: "$n",
|
||||
names: []string{"baz"},
|
||||
},
|
||||
{
|
||||
fmtExpr: "$v",
|
||||
values: []dynamodb.AttributeValue{
|
||||
{
|
||||
N: aws.String("7"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
fmtExpr: "$c = $c",
|
||||
children: []exprNode{
|
||||
{
|
||||
fmtExpr: "$n",
|
||||
names: []string{"qux"},
|
||||
},
|
||||
{
|
||||
fmtExpr: "$v",
|
||||
values: []dynamodb.AttributeValue{
|
||||
{
|
||||
N: aws.String("8"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "empty operationBuilder list",
|
||||
input: []operationBuilder{},
|
||||
err: emptyOperationBuilderList,
|
||||
},
|
||||
}
|
||||
for _, c := range cases {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
actual, err := buildChildNodes(c.input)
|
||||
if c.err != noUpdateError {
|
||||
if err == nil {
|
||||
t.Errorf("expect error %q, got no error", c.err)
|
||||
} else {
|
||||
if e, a := string(c.err), err.Error(); !strings.Contains(a, e) {
|
||||
t.Errorf("expect %q error message to be in %q", e, a)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if err != nil {
|
||||
t.Errorf("expect no error, got unexpected Error %q", err)
|
||||
}
|
||||
|
||||
if e, a := c.expected, actual; !reflect.DeepEqual(a, e) {
|
||||
t.Errorf("expect %v, got %v", e, a)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
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 met 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 met 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)
|
||||
}
|
||||
Reference in New Issue
Block a user