diff --git a/dax/api.go b/dax/api.go index ae4354f..0b9994f 100644 --- a/dax/api.go +++ b/dax/api.go @@ -16,943 +16,338 @@ package dax import ( + "context" "errors" "io" "github.com/aws/aws-dax-go/dax/internal/client" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/request" - "github.com/aws/aws-sdk-go/service/dynamodb" + "github.com/aws/aws-sdk-go-v2/service/dynamodb" ) -func (d *Dax) PutItem(input *dynamodb.PutItemInput) (*dynamodb.PutItemOutput, error) { - return d.PutItemWithContext(nil, input) +// DynamoDBAPI is compatible to aws-sdk-go-v2/service/dynamodb.Client +type DynamoDBAPI interface { + PutItem(ctx context.Context, params *dynamodb.PutItemInput, optFns ...func(*dynamodb.Options)) (*dynamodb.PutItemOutput, error) + DeleteItem(ctx context.Context, params *dynamodb.DeleteItemInput, optFns ...func(*dynamodb.Options)) (*dynamodb.DeleteItemOutput, error) + UpdateItem(ctx context.Context, params *dynamodb.UpdateItemInput, optFns ...func(*dynamodb.Options)) (*dynamodb.UpdateItemOutput, error) + GetItem(ctx context.Context, params *dynamodb.GetItemInput, optFns ...func(*dynamodb.Options)) (*dynamodb.GetItemOutput, error) + Scan(ctx context.Context, params *dynamodb.ScanInput, optFns ...func(*dynamodb.Options)) (*dynamodb.ScanOutput, error) + Query(ctx context.Context, params *dynamodb.QueryInput, optFns ...func(*dynamodb.Options)) (*dynamodb.QueryOutput, error) + BatchWriteItem(ctx context.Context, params *dynamodb.BatchWriteItemInput, optFns ...func(*dynamodb.Options)) (*dynamodb.BatchWriteItemOutput, error) + BatchGetItem(ctx context.Context, params *dynamodb.BatchGetItemInput, optFns ...func(*dynamodb.Options)) (*dynamodb.BatchGetItemOutput, error) + TransactWriteItems(ctx context.Context, params *dynamodb.TransactWriteItemsInput, optFns ...func(*dynamodb.Options)) (*dynamodb.TransactWriteItemsOutput, error) + TransactGetItems(ctx context.Context, params *dynamodb.TransactGetItemsInput, optFns ...func(*dynamodb.Options)) (*dynamodb.TransactGetItemsOutput, error) + + BatchExecuteStatement(ctx context.Context, params *dynamodb.BatchExecuteStatementInput, optFns ...func(*dynamodb.Options)) (*dynamodb.BatchExecuteStatementOutput, error) + CreateBackup(ctx context.Context, params *dynamodb.CreateBackupInput, optFns ...func(*dynamodb.Options)) (*dynamodb.CreateBackupOutput, error) + CreateGlobalTable(ctx context.Context, params *dynamodb.CreateGlobalTableInput, optFns ...func(*dynamodb.Options)) (*dynamodb.CreateGlobalTableOutput, error) + CreateTable(ctx context.Context, params *dynamodb.CreateTableInput, optFns ...func(*dynamodb.Options)) (*dynamodb.CreateTableOutput, error) + DeleteBackup(ctx context.Context, params *dynamodb.DeleteBackupInput, optFns ...func(*dynamodb.Options)) (*dynamodb.DeleteBackupOutput, error) + DeleteTable(ctx context.Context, params *dynamodb.DeleteTableInput, optFns ...func(*dynamodb.Options)) (*dynamodb.DeleteTableOutput, error) + DescribeBackup(ctx context.Context, params *dynamodb.DescribeBackupInput, optFns ...func(*dynamodb.Options)) (*dynamodb.DescribeBackupOutput, error) + DescribeContinuousBackups(ctx context.Context, params *dynamodb.DescribeContinuousBackupsInput, optFns ...func(*dynamodb.Options)) (*dynamodb.DescribeContinuousBackupsOutput, error) + DescribeContributorInsights(ctx context.Context, params *dynamodb.DescribeContributorInsightsInput, optFns ...func(*dynamodb.Options)) (*dynamodb.DescribeContributorInsightsOutput, error) + DescribeEndpoints(ctx context.Context, params *dynamodb.DescribeEndpointsInput, optFns ...func(*dynamodb.Options)) (*dynamodb.DescribeEndpointsOutput, error) + DescribeExport(ctx context.Context, params *dynamodb.DescribeExportInput, optFns ...func(*dynamodb.Options)) (*dynamodb.DescribeExportOutput, error) + DescribeGlobalTable(ctx context.Context, params *dynamodb.DescribeGlobalTableInput, optFns ...func(*dynamodb.Options)) (*dynamodb.DescribeGlobalTableOutput, error) + DescribeGlobalTableSettings(ctx context.Context, params *dynamodb.DescribeGlobalTableSettingsInput, optFns ...func(*dynamodb.Options)) (*dynamodb.DescribeGlobalTableSettingsOutput, error) + DescribeImport(ctx context.Context, params *dynamodb.DescribeImportInput, optFns ...func(*dynamodb.Options)) (*dynamodb.DescribeImportOutput, error) + DescribeKinesisStreamingDestination(ctx context.Context, params *dynamodb.DescribeKinesisStreamingDestinationInput, optFns ...func(*dynamodb.Options)) (*dynamodb.DescribeKinesisStreamingDestinationOutput, error) + DescribeLimits(ctx context.Context, params *dynamodb.DescribeLimitsInput, optFns ...func(*dynamodb.Options)) (*dynamodb.DescribeLimitsOutput, error) + DescribeTable(ctx context.Context, params *dynamodb.DescribeTableInput, optFns ...func(*dynamodb.Options)) (*dynamodb.DescribeTableOutput, error) + DescribeTableReplicaAutoScaling(ctx context.Context, params *dynamodb.DescribeTableReplicaAutoScalingInput, optFns ...func(*dynamodb.Options)) (*dynamodb.DescribeTableReplicaAutoScalingOutput, error) + DescribeTimeToLive(ctx context.Context, params *dynamodb.DescribeTimeToLiveInput, optFns ...func(*dynamodb.Options)) (*dynamodb.DescribeTimeToLiveOutput, error) + DisableKinesisStreamingDestination(ctx context.Context, params *dynamodb.DisableKinesisStreamingDestinationInput, optFns ...func(*dynamodb.Options)) (*dynamodb.DisableKinesisStreamingDestinationOutput, error) + EnableKinesisStreamingDestination(ctx context.Context, params *dynamodb.EnableKinesisStreamingDestinationInput, optFns ...func(*dynamodb.Options)) (*dynamodb.EnableKinesisStreamingDestinationOutput, error) + ExecuteStatement(ctx context.Context, params *dynamodb.ExecuteStatementInput, optFns ...func(*dynamodb.Options)) (*dynamodb.ExecuteStatementOutput, error) + ExecuteTransaction(ctx context.Context, params *dynamodb.ExecuteTransactionInput, optFns ...func(*dynamodb.Options)) (*dynamodb.ExecuteTransactionOutput, error) + ExportTableToPointInTime(ctx context.Context, params *dynamodb.ExportTableToPointInTimeInput, optFns ...func(*dynamodb.Options)) (*dynamodb.ExportTableToPointInTimeOutput, error) + ImportTable(ctx context.Context, params *dynamodb.ImportTableInput, optFns ...func(*dynamodb.Options)) (*dynamodb.ImportTableOutput, error) + ListBackups(ctx context.Context, params *dynamodb.ListBackupsInput, optFns ...func(*dynamodb.Options)) (*dynamodb.ListBackupsOutput, error) + ListContributorInsights(ctx context.Context, params *dynamodb.ListContributorInsightsInput, optFns ...func(*dynamodb.Options)) (*dynamodb.ListContributorInsightsOutput, error) + ListExports(ctx context.Context, params *dynamodb.ListExportsInput, optFns ...func(*dynamodb.Options)) (*dynamodb.ListExportsOutput, error) + ListGlobalTables(ctx context.Context, params *dynamodb.ListGlobalTablesInput, optFns ...func(*dynamodb.Options)) (*dynamodb.ListGlobalTablesOutput, error) + ListImports(ctx context.Context, params *dynamodb.ListImportsInput, optFns ...func(*dynamodb.Options)) (*dynamodb.ListImportsOutput, error) + ListTables(ctx context.Context, params *dynamodb.ListTablesInput, optFns ...func(*dynamodb.Options)) (*dynamodb.ListTablesOutput, error) + ListTagsOfResource(ctx context.Context, params *dynamodb.ListTagsOfResourceInput, optFns ...func(*dynamodb.Options)) (*dynamodb.ListTagsOfResourceOutput, error) + RestoreTableFromBackup(ctx context.Context, params *dynamodb.RestoreTableFromBackupInput, optFns ...func(*dynamodb.Options)) (*dynamodb.RestoreTableFromBackupOutput, error) + RestoreTableToPointInTime(ctx context.Context, params *dynamodb.RestoreTableToPointInTimeInput, optFns ...func(*dynamodb.Options)) (*dynamodb.RestoreTableToPointInTimeOutput, error) + TagResource(ctx context.Context, params *dynamodb.TagResourceInput, optFns ...func(*dynamodb.Options)) (*dynamodb.TagResourceOutput, error) + UntagResource(ctx context.Context, params *dynamodb.UntagResourceInput, optFns ...func(*dynamodb.Options)) (*dynamodb.UntagResourceOutput, error) + UpdateContinuousBackups(ctx context.Context, params *dynamodb.UpdateContinuousBackupsInput, optFns ...func(*dynamodb.Options)) (*dynamodb.UpdateContinuousBackupsOutput, error) + UpdateContributorInsights(ctx context.Context, params *dynamodb.UpdateContributorInsightsInput, optFns ...func(*dynamodb.Options)) (*dynamodb.UpdateContributorInsightsOutput, error) + UpdateGlobalTable(ctx context.Context, params *dynamodb.UpdateGlobalTableInput, optFns ...func(*dynamodb.Options)) (*dynamodb.UpdateGlobalTableOutput, error) + UpdateGlobalTableSettings(ctx context.Context, params *dynamodb.UpdateGlobalTableSettingsInput, optFns ...func(*dynamodb.Options)) (*dynamodb.UpdateGlobalTableSettingsOutput, error) + UpdateTable(ctx context.Context, params *dynamodb.UpdateTableInput, optFns ...func(*dynamodb.Options)) (*dynamodb.UpdateTableOutput, error) + UpdateTableReplicaAutoScaling(ctx context.Context, params *dynamodb.UpdateTableReplicaAutoScalingInput, optFns ...func(*dynamodb.Options)) (*dynamodb.UpdateTableReplicaAutoScalingOutput, error) + UpdateTimeToLive(ctx context.Context, params *dynamodb.UpdateTimeToLiveInput, optFns ...func(*dynamodb.Options)) (*dynamodb.UpdateTimeToLiveOutput, error) +} + +func (d *Dax) PutItem(ctx context.Context, input *dynamodb.PutItemInput, opts ...func(*dynamodb.Options)) (*dynamodb.PutItemOutput, error) { + o := d.config.requestOptions(false, opts...) + return d.client.PutItemWithOptions(ctx, input, o) +} + +func (d *Dax) DeleteItem(ctx context.Context, input *dynamodb.DeleteItemInput, opts ...func(*dynamodb.Options)) (*dynamodb.DeleteItemOutput, error) { + o := d.config.requestOptions(false, opts...) + return d.client.DeleteItemWithOptions(ctx, input, o) +} + +func (d *Dax) UpdateItem(ctx context.Context, input *dynamodb.UpdateItemInput, opts ...func(*dynamodb.Options)) (*dynamodb.UpdateItemOutput, error) { + o := d.config.requestOptions(false, opts...) + return d.client.UpdateItemWithOptions(ctx, input, o) +} + +func (d *Dax) GetItem(ctx context.Context, input *dynamodb.GetItemInput, opts ...func(*dynamodb.Options)) (*dynamodb.GetItemOutput, error) { + o := d.config.requestOptions(true, opts...) + return d.client.GetItemWithOptions(ctx, input, o) } -func (d *Dax) PutItemWithContext(ctx aws.Context, input *dynamodb.PutItemInput, opts ...request.Option) (*dynamodb.PutItemOutput, error) { - o, cfn, err := d.config.requestOptions(false, ctx, opts...) - if err != nil { - return nil, err - } - if cfn != nil { - defer cfn() - } - return d.client.PutItemWithOptions(input, &dynamodb.PutItemOutput{}, o) -} - -func (d *Dax) PutItemRequest(input *dynamodb.PutItemInput) (*request.Request, *dynamodb.PutItemOutput) { - op := &request.Operation{Name: client.OpPutItem} - if input == nil { - input = &dynamodb.PutItemInput{} - } - output := &dynamodb.PutItemOutput{} - opt := client.RequestOptions{Context: aws.BackgroundContext()} - req := d.client.NewDaxRequest(op, input, output, opt) - return req, output -} - -func (d *Dax) DeleteItem(input *dynamodb.DeleteItemInput) (*dynamodb.DeleteItemOutput, error) { - return d.DeleteItemWithContext(nil, input) -} - -func (d *Dax) DeleteItemWithContext(ctx aws.Context, input *dynamodb.DeleteItemInput, opts ...request.Option) (*dynamodb.DeleteItemOutput, error) { - o, cfn, err := d.config.requestOptions(false, ctx, opts...) - if err != nil { - return nil, err - } - if cfn != nil { - defer cfn() - } - return d.client.DeleteItemWithOptions(input, &dynamodb.DeleteItemOutput{}, o) -} - -func (d *Dax) DeleteItemRequest(input *dynamodb.DeleteItemInput) (*request.Request, *dynamodb.DeleteItemOutput) { - op := &request.Operation{Name: client.OpDeleteItem} - if input == nil { - input = &dynamodb.DeleteItemInput{} - } - output := &dynamodb.DeleteItemOutput{} - opt := client.RequestOptions{Context: aws.BackgroundContext()} - req := d.client.NewDaxRequest(op, input, output, opt) - return req, output -} - -func (d *Dax) UpdateItem(input *dynamodb.UpdateItemInput) (*dynamodb.UpdateItemOutput, error) { - return d.UpdateItemWithContext(nil, input) -} - -func (d *Dax) UpdateItemWithContext(ctx aws.Context, input *dynamodb.UpdateItemInput, opts ...request.Option) (*dynamodb.UpdateItemOutput, error) { - o, cfn, err := d.config.requestOptions(false, ctx, opts...) - if err != nil { - return nil, err - } - if cfn != nil { - defer cfn() - } - return d.client.UpdateItemWithOptions(input, &dynamodb.UpdateItemOutput{}, o) -} - -func (d *Dax) UpdateItemRequest(input *dynamodb.UpdateItemInput) (*request.Request, *dynamodb.UpdateItemOutput) { - op := &request.Operation{Name: client.OpUpdateItem} - if input == nil { - input = &dynamodb.UpdateItemInput{} - } - output := &dynamodb.UpdateItemOutput{} - opt := client.RequestOptions{Context: aws.BackgroundContext()} - req := d.client.NewDaxRequest(op, input, output, opt) - return req, output -} - -func (d *Dax) GetItem(input *dynamodb.GetItemInput) (*dynamodb.GetItemOutput, error) { - return d.GetItemWithContext(nil, input) -} - -func (d *Dax) GetItemWithContext(ctx aws.Context, input *dynamodb.GetItemInput, opts ...request.Option) (*dynamodb.GetItemOutput, error) { - o, cfn, err := d.config.requestOptions(true, ctx, opts...) - if err != nil { - return nil, err - } - if cfn != nil { - defer cfn() - } - return d.client.GetItemWithOptions(input, &dynamodb.GetItemOutput{}, o) -} - -func (d *Dax) GetItemRequest(input *dynamodb.GetItemInput) (*request.Request, *dynamodb.GetItemOutput) { - op := &request.Operation{Name: client.OpGetItem} - if input == nil { - input = &dynamodb.GetItemInput{} - } - output := &dynamodb.GetItemOutput{} - opt := client.RequestOptions{Context: aws.BackgroundContext()} - req := d.client.NewDaxRequest(op, input, output, opt) - return req, output -} - -func (d *Dax) Scan(input *dynamodb.ScanInput) (*dynamodb.ScanOutput, error) { - return d.ScanWithContext(nil, input) -} - -func (d *Dax) ScanWithContext(ctx aws.Context, input *dynamodb.ScanInput, opts ...request.Option) (*dynamodb.ScanOutput, error) { - o, cfn, err := d.config.requestOptions(true, ctx, opts...) - if err != nil { - return nil, err - } - if cfn != nil { - defer cfn() - } - return d.client.ScanWithOptions(input, &dynamodb.ScanOutput{}, o) -} - -func (d *Dax) ScanRequest(input *dynamodb.ScanInput) (*request.Request, *dynamodb.ScanOutput) { - op := &request.Operation{ - Name: client.OpScan, - Paginator: &request.Paginator{ - InputTokens: []string{"ExclusiveStartKey"}, - OutputTokens: []string{"LastEvaluatedKey"}, - LimitToken: "Limit", - TruncationToken: "", - }, - } - if input == nil { - input = &dynamodb.ScanInput{} - } - output := &dynamodb.ScanOutput{} - opt := client.RequestOptions{Context: aws.BackgroundContext()} - req := d.client.NewDaxRequest(op, input, output, opt) - return req, output -} - -func (d *Dax) Query(input *dynamodb.QueryInput) (*dynamodb.QueryOutput, error) { - return d.QueryWithContext(nil, input) -} - -func (d *Dax) QueryWithContext(ctx aws.Context, input *dynamodb.QueryInput, opts ...request.Option) (*dynamodb.QueryOutput, error) { - o, cfn, err := d.config.requestOptions(true, ctx, opts...) - if err != nil { - return nil, err - } - if cfn != nil { - defer cfn() - } - return d.client.QueryWithOptions(input, &dynamodb.QueryOutput{}, o) -} - -func (d *Dax) QueryRequest(input *dynamodb.QueryInput) (*request.Request, *dynamodb.QueryOutput) { - op := &request.Operation{ - Name: client.OpQuery, - Paginator: &request.Paginator{ - InputTokens: []string{"ExclusiveStartKey"}, - OutputTokens: []string{"LastEvaluatedKey"}, - LimitToken: "Limit", - TruncationToken: "", - }, - } - if input == nil { - input = &dynamodb.QueryInput{} - } - output := &dynamodb.QueryOutput{} - opt := client.RequestOptions{Context: aws.BackgroundContext()} - req := d.client.NewDaxRequest(op, input, output, opt) - return req, output -} - -func (d *Dax) BatchWriteItem(input *dynamodb.BatchWriteItemInput) (*dynamodb.BatchWriteItemOutput, error) { - return d.BatchWriteItemWithContext(nil, input) -} - -func (d *Dax) BatchWriteItemWithContext(ctx aws.Context, input *dynamodb.BatchWriteItemInput, opts ...request.Option) (*dynamodb.BatchWriteItemOutput, error) { - o, cfn, err := d.config.requestOptions(false, ctx, opts...) - if err != nil { - return nil, err - } - if cfn != nil { - defer cfn() - } - return d.client.BatchWriteItemWithOptions(input, &dynamodb.BatchWriteItemOutput{}, o) -} - -func (d *Dax) BatchWriteItemRequest(input *dynamodb.BatchWriteItemInput) (*request.Request, *dynamodb.BatchWriteItemOutput) { - op := &request.Operation{Name: client.OpBatchWriteItem} - if input == nil { - input = &dynamodb.BatchWriteItemInput{} - } - output := &dynamodb.BatchWriteItemOutput{} - opt := client.RequestOptions{Context: aws.BackgroundContext()} - req := d.client.NewDaxRequest(op, input, output, opt) - return req, output -} - -func (d *Dax) BatchGetItem(input *dynamodb.BatchGetItemInput) (*dynamodb.BatchGetItemOutput, error) { - return d.BatchGetItemWithContext(nil, input) -} - -func (d *Dax) BatchGetItemWithContext(ctx aws.Context, input *dynamodb.BatchGetItemInput, opts ...request.Option) (*dynamodb.BatchGetItemOutput, error) { - o, cfn, err := d.config.requestOptions(true, ctx, opts...) - if err != nil { - return nil, err - } - if cfn != nil { - defer cfn() - } - return d.client.BatchGetItemWithOptions(input, &dynamodb.BatchGetItemOutput{}, o) -} - -func (d *Dax) BatchGetItemRequest(input *dynamodb.BatchGetItemInput) (*request.Request, *dynamodb.BatchGetItemOutput) { - op := &request.Operation{ - Name: client.OpBatchGetItem, - Paginator: &request.Paginator{ - InputTokens: []string{"RequestItems"}, - OutputTokens: []string{"UnprocessedKeys"}, - LimitToken: "", - TruncationToken: "", - }, - } - if input == nil { - input = &dynamodb.BatchGetItemInput{} - } - output := &dynamodb.BatchGetItemOutput{} - opt := client.RequestOptions{Context: aws.BackgroundContext()} - req := d.client.NewDaxRequest(op, input, output, opt) - return req, output -} - -func (d *Dax) TransactWriteItems(input *dynamodb.TransactWriteItemsInput) (*dynamodb.TransactWriteItemsOutput, error) { - return d.TransactWriteItemsWithContext(nil, input) -} - -func (d *Dax) TransactWriteItemsWithContext(ctx aws.Context, input *dynamodb.TransactWriteItemsInput, opts ...request.Option) (*dynamodb.TransactWriteItemsOutput, error) { - o, cfn, err := d.config.requestOptions(false, ctx, opts...) - if err != nil { - return nil, err - } - if cfn != nil { - defer cfn() - } - return d.client.TransactWriteItemsWithOptions(input, &dynamodb.TransactWriteItemsOutput{}, o) -} - -func (d *Dax) TransactWriteItemsRequest(input *dynamodb.TransactWriteItemsInput) (*request.Request, *dynamodb.TransactWriteItemsOutput) { - op := &request.Operation{Name: client.OpTransactWriteItems} - if input == nil { - input = &dynamodb.TransactWriteItemsInput{} - } - output := &dynamodb.TransactWriteItemsOutput{} - opt := client.RequestOptions{Context: aws.BackgroundContext()} - req := d.client.NewDaxRequest(op, input, output, opt) - return req, output -} - -func (d *Dax) TransactGetItems(input *dynamodb.TransactGetItemsInput) (*dynamodb.TransactGetItemsOutput, error) { - return d.TransactGetItemsWithContext(nil, input) -} - -func (d *Dax) TransactGetItemsWithContext(ctx aws.Context, input *dynamodb.TransactGetItemsInput, opts ...request.Option) (*dynamodb.TransactGetItemsOutput, error) { - o, cfn, err := d.config.requestOptions(true, ctx, opts...) - if err != nil { - return nil, err - } - if cfn != nil { - defer cfn() - } - return d.client.TransactGetItemsWithOptions(input, &dynamodb.TransactGetItemsOutput{}, o) -} - -func (d *Dax) TransactGetItemsRequest(input *dynamodb.TransactGetItemsInput) (*request.Request, *dynamodb.TransactGetItemsOutput) { - op := &request.Operation{Name: client.OpTransactGetItems} - if input == nil { - input = &dynamodb.TransactGetItemsInput{} - } - output := &dynamodb.TransactGetItemsOutput{} - opt := client.RequestOptions{Context: aws.BackgroundContext()} - req := d.client.NewDaxRequest(op, input, output, opt) - return req, output -} - -func (d *Dax) BatchGetItemPages(input *dynamodb.BatchGetItemInput, fn func(*dynamodb.BatchGetItemOutput, bool) bool) error { - return d.BatchGetItemPagesWithContext(aws.BackgroundContext(), input, fn) -} - -func (d *Dax) BatchGetItemPagesWithContext(ctx aws.Context, input *dynamodb.BatchGetItemInput, fn func(*dynamodb.BatchGetItemOutput, bool) bool, opts ...request.Option) error { - p := request.Pagination{ - NewRequest: func() (*request.Request, error) { - var inCpy *dynamodb.BatchGetItemInput - if input != nil { - tmp := *input - inCpy = &tmp - } - req, _ := d.BatchGetItemRequest(inCpy) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return req, nil - }, - } - - for p.Next() { - if !fn(p.Page().(*dynamodb.BatchGetItemOutput), !p.HasNextPage()) { - break - } - } - - return p.Err() -} - -func (d *Dax) QueryPages(input *dynamodb.QueryInput, fn func(*dynamodb.QueryOutput, bool) bool) error { - return d.QueryPagesWithContext(aws.BackgroundContext(), input, fn) -} - -func (d *Dax) QueryPagesWithContext(ctx aws.Context, input *dynamodb.QueryInput, fn func(*dynamodb.QueryOutput, bool) bool, opts ...request.Option) error { - p := request.Pagination{ - NewRequest: func() (*request.Request, error) { - var inCpy *dynamodb.QueryInput - if input != nil { - tmp := *input - inCpy = &tmp - } - req, _ := d.QueryRequest(inCpy) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return req, nil - }, - } - for p.Next() { - if !fn(p.Page().(*dynamodb.QueryOutput), !p.HasNextPage()) { - break - } - } - return p.Err() -} - -func (d *Dax) ScanPages(input *dynamodb.ScanInput, fn func(*dynamodb.ScanOutput, bool) bool) error { - return d.ScanPagesWithContext(aws.BackgroundContext(), input, fn) -} - -func (d *Dax) ScanPagesWithContext(ctx aws.Context, input *dynamodb.ScanInput, fn func(*dynamodb.ScanOutput, bool) bool, opts ...request.Option) error { - p := request.Pagination{ - NewRequest: func() (*request.Request, error) { - var inCpy *dynamodb.ScanInput - if input != nil { - tmp := *input - inCpy = &tmp - } - req, _ := d.ScanRequest(inCpy) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return req, nil - }, - } - for p.Next() { - if !fn(p.Page().(*dynamodb.ScanOutput), !p.HasNextPage()) { - break - } - } - return p.Err() -} - -func (d *Dax) CreateBackup(*dynamodb.CreateBackupInput) (*dynamodb.CreateBackupOutput, error) { - return nil, d.unImpl() -} - -func (d *Dax) CreateBackupWithContext(aws.Context, *dynamodb.CreateBackupInput, ...request.Option) (*dynamodb.CreateBackupOutput, error) { - return nil, d.unImpl() -} - -func (d *Dax) CreateBackupRequest(*dynamodb.CreateBackupInput) (*request.Request, *dynamodb.CreateBackupOutput) { - return newRequestForUnimplementedOperation(), &dynamodb.CreateBackupOutput{} -} - -func (d *Dax) CreateGlobalTable(*dynamodb.CreateGlobalTableInput) (*dynamodb.CreateGlobalTableOutput, error) { - return nil, d.unImpl() -} - -func (d *Dax) CreateGlobalTableWithContext(aws.Context, *dynamodb.CreateGlobalTableInput, ...request.Option) (*dynamodb.CreateGlobalTableOutput, error) { - return nil, d.unImpl() -} - -func (d *Dax) CreateGlobalTableRequest(*dynamodb.CreateGlobalTableInput) (*request.Request, *dynamodb.CreateGlobalTableOutput) { - return newRequestForUnimplementedOperation(), &dynamodb.CreateGlobalTableOutput{} -} - -func (d *Dax) CreateTable(*dynamodb.CreateTableInput) (*dynamodb.CreateTableOutput, error) { - return nil, d.unImpl() -} - -func (d *Dax) CreateTableWithContext(aws.Context, *dynamodb.CreateTableInput, ...request.Option) (*dynamodb.CreateTableOutput, error) { - return nil, d.unImpl() -} - -func (d *Dax) CreateTableRequest(*dynamodb.CreateTableInput) (*request.Request, *dynamodb.CreateTableOutput) { - return newRequestForUnimplementedOperation(), &dynamodb.CreateTableOutput{} -} - -func (d *Dax) DeleteBackup(*dynamodb.DeleteBackupInput) (*dynamodb.DeleteBackupOutput, error) { - return nil, d.unImpl() -} - -func (d *Dax) DeleteBackupWithContext(aws.Context, *dynamodb.DeleteBackupInput, ...request.Option) (*dynamodb.DeleteBackupOutput, error) { - return nil, d.unImpl() -} - -func (d *Dax) DeleteBackupRequest(*dynamodb.DeleteBackupInput) (*request.Request, *dynamodb.DeleteBackupOutput) { - return newRequestForUnimplementedOperation(), &dynamodb.DeleteBackupOutput{} -} - -func (d *Dax) DeleteTable(*dynamodb.DeleteTableInput) (*dynamodb.DeleteTableOutput, error) { - return nil, d.unImpl() -} - -func (d *Dax) DeleteTableWithContext(aws.Context, *dynamodb.DeleteTableInput, ...request.Option) (*dynamodb.DeleteTableOutput, error) { - return nil, d.unImpl() -} - -func (d *Dax) DeleteTableRequest(*dynamodb.DeleteTableInput) (*request.Request, *dynamodb.DeleteTableOutput) { - return newRequestForUnimplementedOperation(), &dynamodb.DeleteTableOutput{} -} - -func (d *Dax) DescribeBackup(*dynamodb.DescribeBackupInput) (*dynamodb.DescribeBackupOutput, error) { - return nil, d.unImpl() -} - -func (d *Dax) DescribeBackupWithContext(aws.Context, *dynamodb.DescribeBackupInput, ...request.Option) (*dynamodb.DescribeBackupOutput, error) { - return nil, d.unImpl() -} - -func (d *Dax) DescribeBackupRequest(*dynamodb.DescribeBackupInput) (*request.Request, *dynamodb.DescribeBackupOutput) { - return newRequestForUnimplementedOperation(), &dynamodb.DescribeBackupOutput{} -} - -func (d *Dax) DescribeContinuousBackups(*dynamodb.DescribeContinuousBackupsInput) (*dynamodb.DescribeContinuousBackupsOutput, error) { - return nil, d.unImpl() -} - -func (d *Dax) DescribeContinuousBackupsWithContext(aws.Context, *dynamodb.DescribeContinuousBackupsInput, ...request.Option) (*dynamodb.DescribeContinuousBackupsOutput, error) { - return nil, d.unImpl() -} - -func (d *Dax) DescribeContinuousBackupsRequest(*dynamodb.DescribeContinuousBackupsInput) (*request.Request, *dynamodb.DescribeContinuousBackupsOutput) { - return newRequestForUnimplementedOperation(), &dynamodb.DescribeContinuousBackupsOutput{} -} - -func (d *Dax) DescribeContributorInsights(*dynamodb.DescribeContributorInsightsInput) (*dynamodb.DescribeContributorInsightsOutput, error) { - return nil, d.unImpl() -} - -func (d *Dax) DescribeContributorInsightsWithContext(aws.Context, *dynamodb.DescribeContributorInsightsInput, ...request.Option) (*dynamodb.DescribeContributorInsightsOutput, error) { - return nil, d.unImpl() -} - -func (d *Dax) DescribeContributorInsightsRequest(*dynamodb.DescribeContributorInsightsInput) (*request.Request, *dynamodb.DescribeContributorInsightsOutput) { - return newRequestForUnimplementedOperation(), &dynamodb.DescribeContributorInsightsOutput{} -} - -func (d *Dax) DescribeEndpoints(*dynamodb.DescribeEndpointsInput) (*dynamodb.DescribeEndpointsOutput, error) { - return nil, d.unImpl() +func (d *Dax) Scan(ctx context.Context, input *dynamodb.ScanInput, opts ...func(*dynamodb.Options)) (*dynamodb.ScanOutput, error) { + o := d.config.requestOptions(true, opts...) + return d.client.ScanWithOptions(ctx, input, o) } -func (d *Dax) DescribeEndpointsWithContext(aws.Context, *dynamodb.DescribeEndpointsInput, ...request.Option) (*dynamodb.DescribeEndpointsOutput, error) { - return nil, d.unImpl() +func (d *Dax) Query(ctx context.Context, input *dynamodb.QueryInput, opts ...func(*dynamodb.Options)) (*dynamodb.QueryOutput, error) { + o := d.config.requestOptions(true, opts...) + return d.client.QueryWithOptions(ctx, input, o) } -func (d *Dax) DescribeEndpointsRequest(*dynamodb.DescribeEndpointsInput) (*request.Request, *dynamodb.DescribeEndpointsOutput) { - return newRequestForUnimplementedOperation(), &dynamodb.DescribeEndpointsOutput{} +func (d *Dax) BatchWriteItem(ctx context.Context, input *dynamodb.BatchWriteItemInput, opts ...func(*dynamodb.Options)) (*dynamodb.BatchWriteItemOutput, error) { + o := d.config.requestOptions(false, opts...) + return d.client.BatchWriteItemWithOptions(ctx, input, o) } -func (d *Dax) DescribeGlobalTable(*dynamodb.DescribeGlobalTableInput) (*dynamodb.DescribeGlobalTableOutput, error) { - return nil, d.unImpl() +func (d *Dax) BatchGetItem(ctx context.Context, input *dynamodb.BatchGetItemInput, opts ...func(*dynamodb.Options)) (*dynamodb.BatchGetItemOutput, error) { + o := d.config.requestOptions(true, opts...) + return d.client.BatchGetItemWithOptions(ctx, input, o) } -func (d *Dax) DescribeGlobalTableWithContext(aws.Context, *dynamodb.DescribeGlobalTableInput, ...request.Option) (*dynamodb.DescribeGlobalTableOutput, error) { - return nil, d.unImpl() +func (d *Dax) TransactWriteItems(ctx context.Context, input *dynamodb.TransactWriteItemsInput, opts ...func(*dynamodb.Options)) (*dynamodb.TransactWriteItemsOutput, error) { + o := d.config.requestOptions(false, opts...) + return d.client.TransactWriteItemsWithOptions(ctx, input, o) } -func (d *Dax) DescribeGlobalTableRequest(*dynamodb.DescribeGlobalTableInput) (*request.Request, *dynamodb.DescribeGlobalTableOutput) { - return newRequestForUnimplementedOperation(), &dynamodb.DescribeGlobalTableOutput{} +func (d *Dax) TransactGetItems(ctx context.Context, input *dynamodb.TransactGetItemsInput, opts ...func(*dynamodb.Options)) (*dynamodb.TransactGetItemsOutput, error) { + o := d.config.requestOptions(true, opts...) + return d.client.TransactGetItemsWithOptions(ctx, input, o) } -func (d *Dax) DescribeGlobalTableSettings(*dynamodb.DescribeGlobalTableSettingsInput) (*dynamodb.DescribeGlobalTableSettingsOutput, error) { - return nil, d.unImpl() -} +//func (d *Dax) QueryPages(ctx context.Context, input *dynamodb.QueryInput, fn func(*dynamodb.QueryOutput, bool) bool, opts ...func(*dynamodb.Options)) error { +// p := request.Pagination{ +// NewRequest: func() (*request.Request, error) { +// var inCpy *dynamodb.QueryInput +// if input != nil { +// tmp := *input +// inCpy = &tmp +// } +// req, _ := d.QueryRequest(inCpy) +// req.SetContext(ctx) +// req.ApplyOptions(opts...) +// return req, nil +// }, +// } +// for p.Next() { +// if !fn(p.Page().(*dynamodb.QueryOutput), !p.HasNextPage()) { +// break +// } +// } +// return p.Err() +//} -func (d *Dax) DescribeGlobalTableSettingsWithContext(aws.Context, *dynamodb.DescribeGlobalTableSettingsInput, ...request.Option) (*dynamodb.DescribeGlobalTableSettingsOutput, error) { - return nil, d.unImpl() -} +//func (d *Dax) ScanPages(ctx context.Context, input *dynamodb.ScanInput, fn func(*dynamodb.ScanOutput, bool) bool, opts ...func(*dynamodb.Options)) error { +// p := request.Pagination{ +// NewRequest: func() (*request.Request, error) { +// var inCpy *dynamodb.ScanInput +// if input != nil { +// tmp := *input +// inCpy = &tmp +// } +// req, _ := d.ScanRequest(inCpy) +// req.SetContext(ctx) +// req.ApplyOptions(opts...) +// return req, nil +// }, +// } +// for p.Next() { +// if !fn(p.Page().(*dynamodb.ScanOutput), !p.HasNextPage()) { +// break +// } +// } +// return p.Err() +//} -func (d *Dax) DescribeGlobalTableSettingsRequest(*dynamodb.DescribeGlobalTableSettingsInput) (*request.Request, *dynamodb.DescribeGlobalTableSettingsOutput) { - return newRequestForUnimplementedOperation(), &dynamodb.DescribeGlobalTableSettingsOutput{} -} - -func (d *Dax) DescribeImport(*dynamodb.DescribeImportInput) (*dynamodb.DescribeImportOutput, error) { +func (d *Dax) BatchExecuteStatement(context.Context, *dynamodb.BatchExecuteStatementInput, ...func(*dynamodb.Options)) (*dynamodb.BatchExecuteStatementOutput, error) { return nil, d.unImpl() } -func (d *Dax) DescribeImportWithContext(aws.Context, *dynamodb.DescribeImportInput, ...request.Option) (*dynamodb.DescribeImportOutput, error) { +func (d *Dax) CreateBackup(context.Context, *dynamodb.CreateBackupInput, ...func(*dynamodb.Options)) (*dynamodb.CreateBackupOutput, error) { return nil, d.unImpl() } -func (d *Dax) DescribeImportRequest(*dynamodb.DescribeImportInput) (*request.Request, *dynamodb.DescribeImportOutput) { - return newRequestForUnimplementedOperation(), &dynamodb.DescribeImportOutput{} -} - -func (d *Dax) DescribeLimits(*dynamodb.DescribeLimitsInput) (*dynamodb.DescribeLimitsOutput, error) { +func (d *Dax) CreateGlobalTable(context.Context, *dynamodb.CreateGlobalTableInput, ...func(*dynamodb.Options)) (*dynamodb.CreateGlobalTableOutput, error) { return nil, d.unImpl() } -func (d *Dax) DescribeLimitsWithContext(aws.Context, *dynamodb.DescribeLimitsInput, ...request.Option) (*dynamodb.DescribeLimitsOutput, error) { +func (d *Dax) CreateTable(context.Context, *dynamodb.CreateTableInput, ...func(*dynamodb.Options)) (*dynamodb.CreateTableOutput, error) { return nil, d.unImpl() } -func (d *Dax) DescribeLimitsRequest(*dynamodb.DescribeLimitsInput) (*request.Request, *dynamodb.DescribeLimitsOutput) { - return newRequestForUnimplementedOperation(), &dynamodb.DescribeLimitsOutput{} -} - -func (d *Dax) DescribeTable(*dynamodb.DescribeTableInput) (*dynamodb.DescribeTableOutput, error) { +func (d *Dax) DeleteBackup(context.Context, *dynamodb.DeleteBackupInput, ...func(*dynamodb.Options)) (*dynamodb.DeleteBackupOutput, error) { return nil, d.unImpl() } -func (d *Dax) DescribeTableWithContext(aws.Context, *dynamodb.DescribeTableInput, ...request.Option) (*dynamodb.DescribeTableOutput, error) { +func (d *Dax) DeleteTable(context.Context, *dynamodb.DeleteTableInput, ...func(*dynamodb.Options)) (*dynamodb.DeleteTableOutput, error) { return nil, d.unImpl() } -func (d *Dax) DescribeTableRequest(*dynamodb.DescribeTableInput) (*request.Request, *dynamodb.DescribeTableOutput) { - return newRequestForUnimplementedOperation(), &dynamodb.DescribeTableOutput{} -} - -func (d *Dax) DescribeTableReplicaAutoScaling(*dynamodb.DescribeTableReplicaAutoScalingInput) (*dynamodb.DescribeTableReplicaAutoScalingOutput, error) { +func (d *Dax) DescribeBackup(context.Context, *dynamodb.DescribeBackupInput, ...func(*dynamodb.Options)) (*dynamodb.DescribeBackupOutput, error) { return nil, d.unImpl() } -func (d *Dax) DescribeTableReplicaAutoScalingWithContext(aws.Context, *dynamodb.DescribeTableReplicaAutoScalingInput, ...request.Option) (*dynamodb.DescribeTableReplicaAutoScalingOutput, error) { +func (d *Dax) DescribeContinuousBackups(context.Context, *dynamodb.DescribeContinuousBackupsInput, ...func(*dynamodb.Options)) (*dynamodb.DescribeContinuousBackupsOutput, error) { return nil, d.unImpl() } -func (d *Dax) DescribeTableReplicaAutoScalingRequest(*dynamodb.DescribeTableReplicaAutoScalingInput) (*request.Request, *dynamodb.DescribeTableReplicaAutoScalingOutput) { - return newRequestForUnimplementedOperation(), &dynamodb.DescribeTableReplicaAutoScalingOutput{} -} - -func (d *Dax) DescribeTimeToLive(*dynamodb.DescribeTimeToLiveInput) (*dynamodb.DescribeTimeToLiveOutput, error) { +func (d *Dax) DescribeContributorInsights(context.Context, *dynamodb.DescribeContributorInsightsInput, ...func(*dynamodb.Options)) (*dynamodb.DescribeContributorInsightsOutput, error) { return nil, d.unImpl() } -func (d *Dax) DescribeTimeToLiveWithContext(aws.Context, *dynamodb.DescribeTimeToLiveInput, ...request.Option) (*dynamodb.DescribeTimeToLiveOutput, error) { +func (d *Dax) DescribeEndpoints(context.Context, *dynamodb.DescribeEndpointsInput, ...func(*dynamodb.Options)) (*dynamodb.DescribeEndpointsOutput, error) { return nil, d.unImpl() } -func (d *Dax) DescribeTimeToLiveRequest(*dynamodb.DescribeTimeToLiveInput) (*request.Request, *dynamodb.DescribeTimeToLiveOutput) { - return newRequestForUnimplementedOperation(), &dynamodb.DescribeTimeToLiveOutput{} -} - -func (d *Dax) BatchExecuteStatement(*dynamodb.BatchExecuteStatementInput) (*dynamodb.BatchExecuteStatementOutput, error) { +func (d *Dax) DescribeGlobalTable(context.Context, *dynamodb.DescribeGlobalTableInput, ...func(*dynamodb.Options)) (*dynamodb.DescribeGlobalTableOutput, error) { return nil, d.unImpl() } -func (d *Dax) BatchExecuteStatementRequest(*dynamodb.BatchExecuteStatementInput) (*request.Request, *dynamodb.BatchExecuteStatementOutput) { - return newRequestForUnimplementedOperation(), &dynamodb.BatchExecuteStatementOutput{} -} - -func (d *Dax) BatchExecuteStatementWithContext(aws.Context, *dynamodb.BatchExecuteStatementInput, ...request.Option) (*dynamodb.BatchExecuteStatementOutput, error) { +func (d *Dax) DescribeGlobalTableSettings(context.Context, *dynamodb.DescribeGlobalTableSettingsInput, ...func(*dynamodb.Options)) (*dynamodb.DescribeGlobalTableSettingsOutput, error) { return nil, d.unImpl() } -func (d *Dax) DescribeExport(*dynamodb.DescribeExportInput) (*dynamodb.DescribeExportOutput, error) { +func (d *Dax) DescribeImport(context.Context, *dynamodb.DescribeImportInput, ...func(*dynamodb.Options)) (*dynamodb.DescribeImportOutput, error) { return nil, d.unImpl() } -func (d *Dax) DescribeExportWithContext(aws.Context, *dynamodb.DescribeExportInput, ...request.Option) (*dynamodb.DescribeExportOutput, error) { +func (d *Dax) DescribeLimits(context.Context, *dynamodb.DescribeLimitsInput, ...func(*dynamodb.Options)) (*dynamodb.DescribeLimitsOutput, error) { return nil, d.unImpl() } -func (d *Dax) DescribeExportRequest(*dynamodb.DescribeExportInput) (*request.Request, *dynamodb.DescribeExportOutput) { - return newRequestForUnimplementedOperation(), &dynamodb.DescribeExportOutput{} -} - -func (d *Dax) DescribeKinesisStreamingDestination(*dynamodb.DescribeKinesisStreamingDestinationInput) (*dynamodb.DescribeKinesisStreamingDestinationOutput, error) { +func (d *Dax) DescribeTable(context.Context, *dynamodb.DescribeTableInput, ...func(*dynamodb.Options)) (*dynamodb.DescribeTableOutput, error) { return nil, d.unImpl() } -func (d *Dax) DescribeKinesisStreamingDestinationWithContext(aws.Context, *dynamodb.DescribeKinesisStreamingDestinationInput, ...request.Option) (*dynamodb.DescribeKinesisStreamingDestinationOutput, error) { +func (d *Dax) DescribeTableReplicaAutoScaling(context.Context, *dynamodb.DescribeTableReplicaAutoScalingInput, ...func(*dynamodb.Options)) (*dynamodb.DescribeTableReplicaAutoScalingOutput, error) { return nil, d.unImpl() } -func (d *Dax) DescribeKinesisStreamingDestinationRequest(*dynamodb.DescribeKinesisStreamingDestinationInput) (*request.Request, *dynamodb.DescribeKinesisStreamingDestinationOutput) { - return newRequestForUnimplementedOperation(), &dynamodb.DescribeKinesisStreamingDestinationOutput{} -} - -func (d *Dax) DisableKinesisStreamingDestination(*dynamodb.DisableKinesisStreamingDestinationInput) (*dynamodb.DisableKinesisStreamingDestinationOutput, error) { +func (d *Dax) DescribeTimeToLive(context.Context, *dynamodb.DescribeTimeToLiveInput, ...func(*dynamodb.Options)) (*dynamodb.DescribeTimeToLiveOutput, error) { return nil, d.unImpl() } -func (d *Dax) DisableKinesisStreamingDestinationWithContext(aws.Context, *dynamodb.DisableKinesisStreamingDestinationInput, ...request.Option) (*dynamodb.DisableKinesisStreamingDestinationOutput, error) { +func (d *Dax) DescribeExport(context.Context, *dynamodb.DescribeExportInput, ...func(*dynamodb.Options)) (*dynamodb.DescribeExportOutput, error) { return nil, d.unImpl() } -func (d *Dax) DisableKinesisStreamingDestinationRequest(*dynamodb.DisableKinesisStreamingDestinationInput) (*request.Request, *dynamodb.DisableKinesisStreamingDestinationOutput) { - return newRequestForUnimplementedOperation(), &dynamodb.DisableKinesisStreamingDestinationOutput{} -} - -func (d *Dax) EnableKinesisStreamingDestination(*dynamodb.EnableKinesisStreamingDestinationInput) (*dynamodb.EnableKinesisStreamingDestinationOutput, error) { +func (d *Dax) DescribeKinesisStreamingDestination(context.Context, *dynamodb.DescribeKinesisStreamingDestinationInput, ...func(*dynamodb.Options)) (*dynamodb.DescribeKinesisStreamingDestinationOutput, error) { return nil, d.unImpl() } -func (d *Dax) EnableKinesisStreamingDestinationWithContext(aws.Context, *dynamodb.EnableKinesisStreamingDestinationInput, ...request.Option) (*dynamodb.EnableKinesisStreamingDestinationOutput, error) { +func (d *Dax) DisableKinesisStreamingDestination(context.Context, *dynamodb.DisableKinesisStreamingDestinationInput, ...func(*dynamodb.Options)) (*dynamodb.DisableKinesisStreamingDestinationOutput, error) { return nil, d.unImpl() } -func (d *Dax) EnableKinesisStreamingDestinationRequest(*dynamodb.EnableKinesisStreamingDestinationInput) (*request.Request, *dynamodb.EnableKinesisStreamingDestinationOutput) { - return newRequestForUnimplementedOperation(), &dynamodb.EnableKinesisStreamingDestinationOutput{} -} - -func (d *Dax) ExecuteStatement(*dynamodb.ExecuteStatementInput) (*dynamodb.ExecuteStatementOutput, error) { +func (d *Dax) EnableKinesisStreamingDestination(context.Context, *dynamodb.EnableKinesisStreamingDestinationInput, ...func(*dynamodb.Options)) (*dynamodb.EnableKinesisStreamingDestinationOutput, error) { return nil, d.unImpl() } -func (d *Dax) ExecuteStatementWithContext(aws.Context, *dynamodb.ExecuteStatementInput, ...request.Option) (*dynamodb.ExecuteStatementOutput, error) { +func (d *Dax) ExecuteStatement(context.Context, *dynamodb.ExecuteStatementInput, ...func(*dynamodb.Options)) (*dynamodb.ExecuteStatementOutput, error) { return nil, d.unImpl() } -func (d *Dax) ExecuteStatementRequest(*dynamodb.ExecuteStatementInput) (*request.Request, *dynamodb.ExecuteStatementOutput) { - return newRequestForUnimplementedOperation(), &dynamodb.ExecuteStatementOutput{} -} - -func (d *Dax) ExecuteTransaction(*dynamodb.ExecuteTransactionInput) (*dynamodb.ExecuteTransactionOutput, error) { +func (d *Dax) ExecuteTransaction(context.Context, *dynamodb.ExecuteTransactionInput, ...func(*dynamodb.Options)) (*dynamodb.ExecuteTransactionOutput, error) { return nil, d.unImpl() } -func (d *Dax) ExecuteTransactionWithContext(aws.Context, *dynamodb.ExecuteTransactionInput, ...request.Option) (*dynamodb.ExecuteTransactionOutput, error) { +func (d *Dax) ExportTableToPointInTime(context.Context, *dynamodb.ExportTableToPointInTimeInput, ...func(*dynamodb.Options)) (*dynamodb.ExportTableToPointInTimeOutput, error) { return nil, d.unImpl() } -func (d *Dax) ExecuteTransactionRequest(*dynamodb.ExecuteTransactionInput) (*request.Request, *dynamodb.ExecuteTransactionOutput) { - return newRequestForUnimplementedOperation(), &dynamodb.ExecuteTransactionOutput{} -} - -func (d *Dax) ExportTableToPointInTime(*dynamodb.ExportTableToPointInTimeInput) (*dynamodb.ExportTableToPointInTimeOutput, error) { +func (d *Dax) ListBackups(context.Context, *dynamodb.ListBackupsInput, ...func(*dynamodb.Options)) (*dynamodb.ListBackupsOutput, error) { return nil, d.unImpl() } -func (d *Dax) ExportTableToPointInTimeWithContext(aws.Context, *dynamodb.ExportTableToPointInTimeInput, ...request.Option) (*dynamodb.ExportTableToPointInTimeOutput, error) { +func (d *Dax) ImportTable(context.Context, *dynamodb.ImportTableInput, ...func(*dynamodb.Options)) (*dynamodb.ImportTableOutput, error) { return nil, d.unImpl() } -func (d *Dax) ExportTableToPointInTimeRequest(*dynamodb.ExportTableToPointInTimeInput) (*request.Request, *dynamodb.ExportTableToPointInTimeOutput) { - return newRequestForUnimplementedOperation(), &dynamodb.ExportTableToPointInTimeOutput{} -} - -func (d *Dax) ListBackups(*dynamodb.ListBackupsInput) (*dynamodb.ListBackupsOutput, error) { +func (d *Dax) ListContributorInsights(context.Context, *dynamodb.ListContributorInsightsInput, ...func(*dynamodb.Options)) (*dynamodb.ListContributorInsightsOutput, error) { return nil, d.unImpl() } -func (d *Dax) ListBackupsWithContext(aws.Context, *dynamodb.ListBackupsInput, ...request.Option) (*dynamodb.ListBackupsOutput, error) { +func (d *Dax) ListExports(context.Context, *dynamodb.ListExportsInput, ...func(*dynamodb.Options)) (*dynamodb.ListExportsOutput, error) { return nil, d.unImpl() } -func (d *Dax) ListBackupsRequest(*dynamodb.ListBackupsInput) (*request.Request, *dynamodb.ListBackupsOutput) { - return newRequestForUnimplementedOperation(), &dynamodb.ListBackupsOutput{} -} - -func (d *Dax) ImportTable(*dynamodb.ImportTableInput) (*dynamodb.ImportTableOutput, error) { +func (d *Dax) ListGlobalTables(context.Context, *dynamodb.ListGlobalTablesInput, ...func(*dynamodb.Options)) (*dynamodb.ListGlobalTablesOutput, error) { return nil, d.unImpl() } -func (d *Dax) ImportTableWithContext(aws.Context, *dynamodb.ImportTableInput, ...request.Option) (*dynamodb.ImportTableOutput, error) { +func (d *Dax) ListImports(context.Context, *dynamodb.ListImportsInput, ...func(*dynamodb.Options)) (*dynamodb.ListImportsOutput, error) { return nil, d.unImpl() } -func (d *Dax) ImportTableRequest(*dynamodb.ImportTableInput) (*request.Request, *dynamodb.ImportTableOutput) { - return newRequestForUnimplementedOperation(), &dynamodb.ImportTableOutput{} -} - -func (d *Dax) ListContributorInsights(*dynamodb.ListContributorInsightsInput) (*dynamodb.ListContributorInsightsOutput, error) { +func (d *Dax) ListTables(context.Context, *dynamodb.ListTablesInput, ...func(*dynamodb.Options)) (*dynamodb.ListTablesOutput, error) { return nil, d.unImpl() } -func (d *Dax) ListContributorInsightsWithContext(aws.Context, *dynamodb.ListContributorInsightsInput, ...request.Option) (*dynamodb.ListContributorInsightsOutput, error) { +func (d *Dax) ListTagsOfResource(context.Context, *dynamodb.ListTagsOfResourceInput, ...func(*dynamodb.Options)) (*dynamodb.ListTagsOfResourceOutput, error) { return nil, d.unImpl() } -func (d *Dax) ListContributorInsightsRequest(*dynamodb.ListContributorInsightsInput) (*request.Request, *dynamodb.ListContributorInsightsOutput) { - return newRequestForUnimplementedOperation(), &dynamodb.ListContributorInsightsOutput{} -} - -func (d *Dax) ListContributorInsightsPages(*dynamodb.ListContributorInsightsInput, func(*dynamodb.ListContributorInsightsOutput, bool) bool) error { - return d.unImpl() -} - -func (d *Dax) ListContributorInsightsPagesWithContext(aws.Context, *dynamodb.ListContributorInsightsInput, func(*dynamodb.ListContributorInsightsOutput, bool) bool, ...request.Option) error { - return d.unImpl() -} - -func (d *Dax) ListExports(*dynamodb.ListExportsInput) (*dynamodb.ListExportsOutput, error) { - return nil, d.unImpl() -} - -func (d *Dax) ListExportsWithContext(aws.Context, *dynamodb.ListExportsInput, ...request.Option) (*dynamodb.ListExportsOutput, error) { - return nil, d.unImpl() -} - -func (d *Dax) ListExportsRequest(*dynamodb.ListExportsInput) (*request.Request, *dynamodb.ListExportsOutput) { - return newRequestForUnimplementedOperation(), &dynamodb.ListExportsOutput{} -} - -func (d *Dax) ListExportsPages(*dynamodb.ListExportsInput, func(*dynamodb.ListExportsOutput, bool) bool) error { - return d.unImpl() -} - -func (d *Dax) ListExportsPagesWithContext(aws.Context, *dynamodb.ListExportsInput, func(*dynamodb.ListExportsOutput, bool) bool, ...request.Option) error { - return d.unImpl() -} - -func (d *Dax) ListGlobalTables(*dynamodb.ListGlobalTablesInput) (*dynamodb.ListGlobalTablesOutput, error) { - return nil, d.unImpl() -} - -func (d *Dax) ListGlobalTablesWithContext(aws.Context, *dynamodb.ListGlobalTablesInput, ...request.Option) (*dynamodb.ListGlobalTablesOutput, error) { +func (d *Dax) RestoreTableFromBackup(context.Context, *dynamodb.RestoreTableFromBackupInput, ...func(*dynamodb.Options)) (*dynamodb.RestoreTableFromBackupOutput, error) { return nil, d.unImpl() } -func (d *Dax) ListGlobalTablesRequest(*dynamodb.ListGlobalTablesInput) (*request.Request, *dynamodb.ListGlobalTablesOutput) { - return newRequestForUnimplementedOperation(), &dynamodb.ListGlobalTablesOutput{} -} - -func (d *Dax) ListImports(*dynamodb.ListImportsInput) (*dynamodb.ListImportsOutput, error) { +func (d *Dax) RestoreTableToPointInTime(context.Context, *dynamodb.RestoreTableToPointInTimeInput, ...func(*dynamodb.Options)) (*dynamodb.RestoreTableToPointInTimeOutput, error) { return nil, d.unImpl() } -func (d *Dax) ListImportsWithContext(aws.Context, *dynamodb.ListImportsInput, ...request.Option) (*dynamodb.ListImportsOutput, error) { +func (d *Dax) TagResource(context.Context, *dynamodb.TagResourceInput, ...func(*dynamodb.Options)) (*dynamodb.TagResourceOutput, error) { return nil, d.unImpl() } -func (d *Dax) ListImportsRequest(*dynamodb.ListImportsInput) (*request.Request, *dynamodb.ListImportsOutput) { - return newRequestForUnimplementedOperation(), &dynamodb.ListImportsOutput{} -} - -func (d *Dax) ListImportsPages(*dynamodb.ListImportsInput, func(*dynamodb.ListImportsOutput, bool) bool) error { - return d.unImpl() -} - -func (d *Dax) ListImportsPagesWithContext(aws.Context, *dynamodb.ListImportsInput, func(*dynamodb.ListImportsOutput, bool) bool, ...request.Option) error { - return d.unImpl() -} - -func (d *Dax) ListTables(*dynamodb.ListTablesInput) (*dynamodb.ListTablesOutput, error) { +func (d *Dax) UntagResource(context.Context, *dynamodb.UntagResourceInput, ...func(*dynamodb.Options)) (*dynamodb.UntagResourceOutput, error) { return nil, d.unImpl() } -func (d *Dax) ListTablesWithContext(aws.Context, *dynamodb.ListTablesInput, ...request.Option) (*dynamodb.ListTablesOutput, error) { +func (d *Dax) UpdateContinuousBackups(context.Context, *dynamodb.UpdateContinuousBackupsInput, ...func(*dynamodb.Options)) (*dynamodb.UpdateContinuousBackupsOutput, error) { return nil, d.unImpl() } -func (d *Dax) ListTablesRequest(*dynamodb.ListTablesInput) (*request.Request, *dynamodb.ListTablesOutput) { - return newRequestForUnimplementedOperation(), &dynamodb.ListTablesOutput{} -} - -func (d *Dax) ListTablesPages(*dynamodb.ListTablesInput, func(*dynamodb.ListTablesOutput, bool) bool) error { - return d.unImpl() -} - -func (d *Dax) ListTablesPagesWithContext(aws.Context, *dynamodb.ListTablesInput, func(*dynamodb.ListTablesOutput, bool) bool, ...request.Option) error { - return d.unImpl() -} - -func (d *Dax) ListTagsOfResource(*dynamodb.ListTagsOfResourceInput) (*dynamodb.ListTagsOfResourceOutput, error) { +func (d *Dax) UpdateContributorInsights(context.Context, *dynamodb.UpdateContributorInsightsInput, ...func(*dynamodb.Options)) (*dynamodb.UpdateContributorInsightsOutput, error) { return nil, d.unImpl() } -func (d *Dax) ListTagsOfResourceWithContext(aws.Context, *dynamodb.ListTagsOfResourceInput, ...request.Option) (*dynamodb.ListTagsOfResourceOutput, error) { +func (d *Dax) UpdateGlobalTable(context.Context, *dynamodb.UpdateGlobalTableInput, ...func(*dynamodb.Options)) (*dynamodb.UpdateGlobalTableOutput, error) { return nil, d.unImpl() } -func (d *Dax) ListTagsOfResourceRequest(*dynamodb.ListTagsOfResourceInput) (*request.Request, *dynamodb.ListTagsOfResourceOutput) { - return newRequestForUnimplementedOperation(), &dynamodb.ListTagsOfResourceOutput{} -} - -func (d *Dax) RestoreTableFromBackup(*dynamodb.RestoreTableFromBackupInput) (*dynamodb.RestoreTableFromBackupOutput, error) { +func (d *Dax) UpdateGlobalTableSettings(context.Context, *dynamodb.UpdateGlobalTableSettingsInput, ...func(*dynamodb.Options)) (*dynamodb.UpdateGlobalTableSettingsOutput, error) { return nil, d.unImpl() } -func (d *Dax) RestoreTableFromBackupWithContext(aws.Context, *dynamodb.RestoreTableFromBackupInput, ...request.Option) (*dynamodb.RestoreTableFromBackupOutput, error) { +func (d *Dax) UpdateTable(context.Context, *dynamodb.UpdateTableInput, ...func(*dynamodb.Options)) (*dynamodb.UpdateTableOutput, error) { return nil, d.unImpl() } -func (d *Dax) RestoreTableFromBackupRequest(*dynamodb.RestoreTableFromBackupInput) (*request.Request, *dynamodb.RestoreTableFromBackupOutput) { - return newRequestForUnimplementedOperation(), &dynamodb.RestoreTableFromBackupOutput{} -} - -func (d *Dax) RestoreTableToPointInTime(*dynamodb.RestoreTableToPointInTimeInput) (*dynamodb.RestoreTableToPointInTimeOutput, error) { +func (d *Dax) UpdateTableReplicaAutoScaling(context.Context, *dynamodb.UpdateTableReplicaAutoScalingInput, ...func(*dynamodb.Options)) (*dynamodb.UpdateTableReplicaAutoScalingOutput, error) { return nil, d.unImpl() } -func (d *Dax) RestoreTableToPointInTimeWithContext(aws.Context, *dynamodb.RestoreTableToPointInTimeInput, ...request.Option) (*dynamodb.RestoreTableToPointInTimeOutput, error) { +func (d *Dax) UpdateTimeToLive(context.Context, *dynamodb.UpdateTimeToLiveInput, ...func(*dynamodb.Options)) (*dynamodb.UpdateTimeToLiveOutput, error) { return nil, d.unImpl() } -func (d *Dax) RestoreTableToPointInTimeRequest(*dynamodb.RestoreTableToPointInTimeInput) (*request.Request, *dynamodb.RestoreTableToPointInTimeOutput) { - return newRequestForUnimplementedOperation(), &dynamodb.RestoreTableToPointInTimeOutput{} -} - -func (d *Dax) TagResource(*dynamodb.TagResourceInput) (*dynamodb.TagResourceOutput, error) { - return nil, d.unImpl() -} - -func (d *Dax) TagResourceWithContext(aws.Context, *dynamodb.TagResourceInput, ...request.Option) (*dynamodb.TagResourceOutput, error) { - return nil, d.unImpl() -} - -func (d *Dax) TagResourceRequest(*dynamodb.TagResourceInput) (*request.Request, *dynamodb.TagResourceOutput) { - return newRequestForUnimplementedOperation(), &dynamodb.TagResourceOutput{} -} - -func (d *Dax) UntagResource(*dynamodb.UntagResourceInput) (*dynamodb.UntagResourceOutput, error) { - return nil, d.unImpl() -} - -func (d *Dax) UntagResourceWithContext(aws.Context, *dynamodb.UntagResourceInput, ...request.Option) (*dynamodb.UntagResourceOutput, error) { - return nil, d.unImpl() -} - -func (d *Dax) UntagResourceRequest(*dynamodb.UntagResourceInput) (*request.Request, *dynamodb.UntagResourceOutput) { - return newRequestForUnimplementedOperation(), &dynamodb.UntagResourceOutput{} -} - -func (d *Dax) UpdateContinuousBackups(*dynamodb.UpdateContinuousBackupsInput) (*dynamodb.UpdateContinuousBackupsOutput, error) { - return nil, d.unImpl() -} - -func (d *Dax) UpdateContinuousBackupsWithContext(aws.Context, *dynamodb.UpdateContinuousBackupsInput, ...request.Option) (*dynamodb.UpdateContinuousBackupsOutput, error) { - return nil, d.unImpl() -} - -func (d *Dax) UpdateContinuousBackupsRequest(*dynamodb.UpdateContinuousBackupsInput) (*request.Request, *dynamodb.UpdateContinuousBackupsOutput) { - return newRequestForUnimplementedOperation(), &dynamodb.UpdateContinuousBackupsOutput{} -} - -func (d *Dax) UpdateContributorInsights(*dynamodb.UpdateContributorInsightsInput) (*dynamodb.UpdateContributorInsightsOutput, error) { - return nil, d.unImpl() -} - -func (d *Dax) UpdateContributorInsightsWithContext(aws.Context, *dynamodb.UpdateContributorInsightsInput, ...request.Option) (*dynamodb.UpdateContributorInsightsOutput, error) { - return nil, d.unImpl() -} - -func (d *Dax) UpdateContributorInsightsRequest(*dynamodb.UpdateContributorInsightsInput) (*request.Request, *dynamodb.UpdateContributorInsightsOutput) { - return newRequestForUnimplementedOperation(), &dynamodb.UpdateContributorInsightsOutput{} -} - -func (d *Dax) UpdateGlobalTable(*dynamodb.UpdateGlobalTableInput) (*dynamodb.UpdateGlobalTableOutput, error) { - return nil, d.unImpl() -} - -func (d *Dax) UpdateGlobalTableWithContext(aws.Context, *dynamodb.UpdateGlobalTableInput, ...request.Option) (*dynamodb.UpdateGlobalTableOutput, error) { - return nil, d.unImpl() -} - -func (d *Dax) UpdateGlobalTableRequest(*dynamodb.UpdateGlobalTableInput) (*request.Request, *dynamodb.UpdateGlobalTableOutput) { - return newRequestForUnimplementedOperation(), &dynamodb.UpdateGlobalTableOutput{} -} - -func (d *Dax) UpdateGlobalTableSettings(*dynamodb.UpdateGlobalTableSettingsInput) (*dynamodb.UpdateGlobalTableSettingsOutput, error) { - return nil, d.unImpl() -} - -func (d *Dax) UpdateGlobalTableSettingsWithContext(aws.Context, *dynamodb.UpdateGlobalTableSettingsInput, ...request.Option) (*dynamodb.UpdateGlobalTableSettingsOutput, error) { - return nil, d.unImpl() -} - -func (d *Dax) UpdateGlobalTableSettingsRequest(*dynamodb.UpdateGlobalTableSettingsInput) (*request.Request, *dynamodb.UpdateGlobalTableSettingsOutput) { - return newRequestForUnimplementedOperation(), &dynamodb.UpdateGlobalTableSettingsOutput{} -} - -func (d *Dax) UpdateTable(*dynamodb.UpdateTableInput) (*dynamodb.UpdateTableOutput, error) { - return nil, d.unImpl() -} - -func (d *Dax) UpdateTableWithContext(aws.Context, *dynamodb.UpdateTableInput, ...request.Option) (*dynamodb.UpdateTableOutput, error) { - return nil, d.unImpl() -} - -func (d *Dax) UpdateTableRequest(*dynamodb.UpdateTableInput) (*request.Request, *dynamodb.UpdateTableOutput) { - return newRequestForUnimplementedOperation(), &dynamodb.UpdateTableOutput{} -} - -func (d *Dax) UpdateTableReplicaAutoScaling(*dynamodb.UpdateTableReplicaAutoScalingInput) (*dynamodb.UpdateTableReplicaAutoScalingOutput, error) { - return nil, d.unImpl() -} - -func (d *Dax) UpdateTableReplicaAutoScalingWithContext(aws.Context, *dynamodb.UpdateTableReplicaAutoScalingInput, ...request.Option) (*dynamodb.UpdateTableReplicaAutoScalingOutput, error) { - return nil, d.unImpl() -} - -func (d *Dax) UpdateTableReplicaAutoScalingRequest(*dynamodb.UpdateTableReplicaAutoScalingInput) (*request.Request, *dynamodb.UpdateTableReplicaAutoScalingOutput) { - return newRequestForUnimplementedOperation(), &dynamodb.UpdateTableReplicaAutoScalingOutput{} -} - -func (d *Dax) UpdateTimeToLive(*dynamodb.UpdateTimeToLiveInput) (*dynamodb.UpdateTimeToLiveOutput, error) { - return nil, d.unImpl() -} - -func (d *Dax) UpdateTimeToLiveWithContext(aws.Context, *dynamodb.UpdateTimeToLiveInput, ...request.Option) (*dynamodb.UpdateTimeToLiveOutput, error) { - return nil, d.unImpl() -} - -func (d *Dax) UpdateTimeToLiveRequest(*dynamodb.UpdateTimeToLiveInput) (*request.Request, *dynamodb.UpdateTimeToLiveOutput) { - return newRequestForUnimplementedOperation(), &dynamodb.UpdateTimeToLiveOutput{} -} - -func (d *Dax) WaitUntilTableExists(*dynamodb.DescribeTableInput) error { - return d.unImpl() -} - -func (d *Dax) WaitUntilTableExistsWithContext(aws.Context, *dynamodb.DescribeTableInput, ...request.WaiterOption) error { - return d.unImpl() -} - -func (d *Dax) WaitUntilTableNotExists(*dynamodb.DescribeTableInput) error { - return d.unImpl() -} - -func (d *Dax) WaitUntilTableNotExistsWithContext(aws.Context, *dynamodb.DescribeTableInput, ...request.WaiterOption) error { - return d.unImpl() -} - func (d *Dax) unImpl() error { return errors.New(client.ErrCodeNotImplemented) } diff --git a/dax/api_test.go b/dax/api_test.go index bae104d..5636591 100644 --- a/dax/api_test.go +++ b/dax/api_test.go @@ -1,10 +1,10 @@ package dax import ( + "context" "testing" "github.com/aws/aws-dax-go/dax/internal/client" - "github.com/aws/aws-sdk-go/service/dynamodb" ) // https://github.com/aws/aws-dax-go/issues/27 @@ -12,7 +12,7 @@ func TestUnimplementedBehavior(t *testing.T) { dax := createClient(t) // CreateBackup is not implemented by DAX - o, err := dax.CreateBackup(nil) + o, err := dax.CreateBackup(context.Background(), nil) if o != nil { t.Errorf("expect nil from unimplemented method, got %v", o) @@ -22,40 +22,11 @@ func TestUnimplementedBehavior(t *testing.T) { } } -func TestUnimplementedRequestBehavior(t *testing.T) { - dax := createClient(t) - - // CreateGlobalTable is not implemented by DAX - params := &dynamodb.CreateGlobalTableInput{ - GlobalTableName: nil, - ReplicationGroup: []*dynamodb.Replica{}, - } - req, o := dax.CreateGlobalTableRequest(params) - - // Build() should return an error - err := req.Build() - if err == nil || err.Error() != client.ErrCodeNotImplemented { - t.Errorf("expect not implemented error, got %v", err) - } - if o.GlobalTableDescription != nil { - t.Errorf("expect unfilled response from unimplemented method, got %v", o) - } - - // Send() should return an error - err = req.Send() - if err == nil || err.Error() != client.ErrCodeNotImplemented { - t.Errorf("expect not implemented error, got %v", err) - } - if o.GlobalTableDescription != nil { - t.Errorf("expect unfilled response from unimplemented method, got %v", o) - } -} - func createClient(t *testing.T) *Dax { cfg := DefaultConfig() cfg.HostPorts = []string{"127.0.0.1:8111"} cfg.Region = "us-west-2" - dax, err := New(cfg) + dax, err := New(context.Background(), cfg) if err != nil { t.Errorf("expect no error, got %v", err) } diff --git a/dax/internal/cbor/attrval.go b/dax/internal/cbor/attrval.go index 80d3bb6..a25c73b 100644 --- a/dax/internal/cbor/attrval.go +++ b/dax/internal/cbor/attrval.go @@ -16,14 +16,14 @@ package cbor import ( + "errors" "fmt" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/aws/request" - "github.com/aws/aws-sdk-go/service/dynamodb" "math/big" "strconv" "strings" + + "github.com/aws/aws-sdk-go-v2/service/dynamodb/types" + "github.com/aws/smithy-go" ) const ( @@ -33,69 +33,69 @@ const ( tagDocumentPathOrdinal ) -func EncodeAttributeValue(value *dynamodb.AttributeValue, writer *Writer) error { +func EncodeAttributeValue(value types.AttributeValue, writer *Writer) error { if value == nil { - return awserr.New(request.InvalidParameterErrCode, "invalid attribute value: nil", nil) + return &smithy.SerializationError{Err: errors.New("invalid attribute value: nil")} } var err error - switch { - case value.S != nil: - err = writer.WriteString(*value.S) - case value.N != nil: - err = writeStringNumber(*value.N, writer) - case value.B != nil: - err = writer.WriteBytes(value.B) - case value.SS != nil: + switch v := value.(type) { + case *types.AttributeValueMemberS: + err = writer.WriteString(v.Value) + case *types.AttributeValueMemberN: + err = writeStringNumber(v.Value, writer) + case *types.AttributeValueMemberB: + err = writer.WriteBytes(v.Value) + case *types.AttributeValueMemberSS: if err = writer.writeType(Tag, tagStringSet); err != nil { return err } - if err = writer.WriteArrayHeader(len(value.SS)); err != nil { + if err = writer.WriteArrayHeader(len(v.Value)); err != nil { return err } - for _, sp := range value.SS { - if err := writer.WriteString(*sp); err != nil { + for _, sp := range v.Value { + if err := writer.WriteString(sp); err != nil { return err } } - case value.NS != nil: + case *types.AttributeValueMemberNS: if err = writer.writeType(Tag, tagNumberSet); err != nil { return err } - if err = writer.WriteArrayHeader(len(value.NS)); err != nil { + if err = writer.WriteArrayHeader(len(v.Value)); err != nil { return err } - for _, sp := range value.NS { - if err := writeStringNumber(*sp, writer); err != nil { + for _, sp := range v.Value { + if err := writeStringNumber(sp, writer); err != nil { return err } } - case value.BS != nil: + case *types.AttributeValueMemberBS: if err = writer.writeType(Tag, tagBinarySet); err != nil { return err } - if err = writer.WriteArrayHeader(len(value.BS)); err != nil { + if err = writer.WriteArrayHeader(len(v.Value)); err != nil { return err } - for _, bp := range value.BS { + for _, bp := range v.Value { if err := writer.WriteBytes(bp); err != nil { return err } } - case value.L != nil: - if err = writer.WriteArrayHeader(len(value.L)); err != nil { + case *types.AttributeValueMemberL: + if err = writer.WriteArrayHeader(len(v.Value)); err != nil { return err } - for _, v := range value.L { + for _, v := range v.Value { if err := EncodeAttributeValue(v, writer); err != nil { return err } } - case value.M != nil: - if err = writer.WriteMapHeader(len(value.M)); err != nil { + case *types.AttributeValueMemberM: + if err = writer.WriteMapHeader(len(v.Value)); err != nil { return err } - for k, v := range value.M { + for k, v := range v.Value { if err := writer.WriteString(k); err != nil { return err } @@ -103,11 +103,11 @@ func EncodeAttributeValue(value *dynamodb.AttributeValue, writer *Writer) error return err } } - case value.BOOL != nil: - err = writer.WriteBoolean(*value.BOOL) - case value.NULL != nil: - if !(*value.NULL) { - return awserr.New(request.InvalidParameterErrCode, "invalid null attribute value", nil) // DaxJavaClient suppress this error + case *types.AttributeValueMemberBOOL: + err = writer.WriteBoolean(v.Value) + case *types.AttributeValueMemberNULL: + if !v.Value { + return &smithy.SerializationError{Err: errors.New("invalid null attribute value")} // DaxJavaClient suppress this error } err = writer.WriteNull() } @@ -118,7 +118,7 @@ func writeStringNumber(val string, writer *Writer) error { if strings.IndexAny(val, ".eE") >= 0 { dec := new(Decimal) if _, ok := dec.SetString(val); !ok { - return awserr.New(request.InvalidParameterErrCode, fmt.Sprintf("invalid number %v", val), nil) + return &smithy.SerializationError{Err: fmt.Errorf("invalid number %v", val)} } err := writer.WriteDecimal(dec) return err @@ -131,13 +131,13 @@ func writeStringNumber(val string, writer *Writer) error { } i, err := strconv.ParseInt(val, 10, 64) if err != nil { - return awserr.New(request.InvalidParameterErrCode, fmt.Sprintf("invalid number %v", val), err) + return &smithy.SerializationError{Err: fmt.Errorf("invalid number %v", val)} } err = writer.WriteInt64(i) return err } -func DecodeAttributeValue(reader *Reader) (*dynamodb.AttributeValue, error) { +func DecodeAttributeValue(reader *Reader) (types.AttributeValue, error) { hdr, err := reader.PeekHeader() if err != nil { return nil, err @@ -151,34 +151,34 @@ func DecodeAttributeValue(reader *Reader) (*dynamodb.AttributeValue, error) { if err != nil { return nil, err } - return &dynamodb.AttributeValue{S: &s}, nil + return &types.AttributeValueMemberS{Value: s}, nil case Bytes: b, err := reader.ReadBytes() if err != nil { return nil, err } - return &dynamodb.AttributeValue{B: b}, nil + return &types.AttributeValueMemberB{Value: b}, nil case Array: - len, err := reader.ReadArrayLength() + length, err := reader.ReadArrayLength() if err != nil { return nil, err } - as := make([]*dynamodb.AttributeValue, len) - for i := 0; i < len; i++ { + as := make([]types.AttributeValue, length) + for i := 0; i < length; i++ { a, err := DecodeAttributeValue(reader) if err != nil { return nil, err } as[i] = a } - return &dynamodb.AttributeValue{L: as}, nil + return &types.AttributeValueMemberL{Value: as}, nil case Map: - len, err := reader.ReadMapLength() + length, err := reader.ReadMapLength() if err != nil { return nil, err } - m := make(map[string]*dynamodb.AttributeValue, len) - for i := 0; i < len; i++ { + m := make(map[string]types.AttributeValue, length) + for i := 0; i < length; i++ { k, err := reader.ReadString() if err != nil { return nil, err @@ -189,26 +189,26 @@ func DecodeAttributeValue(reader *Reader) (*dynamodb.AttributeValue, error) { } m[k] = v } - return &dynamodb.AttributeValue{M: m}, nil + return &types.AttributeValueMemberM{Value: m}, nil case PosInt, NegInt: s, err := reader.ReadCborIntegerToString() if err != nil { return nil, err } - return &dynamodb.AttributeValue{N: &s}, nil + return &types.AttributeValueMemberN{Value: s}, nil case Simple: if _, _, err := reader.readTypeHeader(); err != nil { return nil, err } switch hdr { case False: - return &dynamodb.AttributeValue{BOOL: aws.Bool(false)}, nil + return &types.AttributeValueMemberBOOL{Value: false}, nil case True: - return &dynamodb.AttributeValue{BOOL: aws.Bool(true)}, nil + return &types.AttributeValueMemberBOOL{Value: true}, nil case Nil: - return &dynamodb.AttributeValue{NULL: aws.Bool(true)}, nil + return &types.AttributeValueMemberNULL{Value: true}, nil default: - return nil, awserr.New(request.ErrCodeSerialization, fmt.Sprintf("unknown minor type %d for simple major type", minor), nil) + return nil, &smithy.DeserializationError{Err: fmt.Errorf("unknown minor type %d for simple major type", minor)} } case Tag: switch minor { @@ -217,13 +217,13 @@ func DecodeAttributeValue(reader *Reader) (*dynamodb.AttributeValue, error) { if err != nil { return nil, err } - return &dynamodb.AttributeValue{N: aws.String(i.String())}, nil + return &types.AttributeValueMemberN{Value: i.String()}, nil case TagDecimal: d, err := reader.ReadDecimal() if err != nil { return nil, err } - return &dynamodb.AttributeValue{N: aws.String(d.String())}, nil + return &types.AttributeValueMemberN{Value: d.String()}, nil default: _, tag, err := reader.readTypeHeader() if err != nil { @@ -231,52 +231,56 @@ func DecodeAttributeValue(reader *Reader) (*dynamodb.AttributeValue, error) { } switch tag { case tagStringSet: - len, err := reader.ReadArrayLength() + length, err := reader.ReadArrayLength() if err != nil { return nil, err } - ss := make([]*string, len) - for i := 0; i < len; i++ { + ss := make([]string, length) + for i := 0; i < length; i++ { s, err := reader.ReadString() if err != nil { return nil, err } - ss[i] = &s + ss[i] = s } - return &dynamodb.AttributeValue{SS: ss}, nil + return &types.AttributeValueMemberSS{Value: ss}, nil case tagNumberSet: - len, err := reader.ReadArrayLength() + length, err := reader.ReadArrayLength() if err != nil { return nil, err } - ss := make([]*string, len) - for i := 0; i < len; i++ { + ss := make([]string, length) + for i := 0; i < length; i++ { av, err := DecodeAttributeValue(reader) if err != nil { return nil, err } - ss[i] = av.N + n, ok := av.(*types.AttributeValueMemberN) + if !ok { + return nil, &smithy.DeserializationError{Err: fmt.Errorf("attribute type is not number. type: %T", av)} + } + ss[i] = n.Value } - return &dynamodb.AttributeValue{NS: ss}, nil + return &types.AttributeValueMemberNS{Value: ss}, nil case tagBinarySet: - len, err := reader.ReadArrayLength() + length, err := reader.ReadArrayLength() if err != nil { return nil, err } - bs := make([][]byte, len) - for i := 0; i < len; i++ { + bs := make([][]byte, length) + for i := 0; i < length; i++ { b, err := reader.ReadBytes() if err != nil { return nil, err } bs[i] = b } - return &dynamodb.AttributeValue{BS: bs}, nil + return &types.AttributeValueMemberBS{Value: bs}, nil default: - return nil, awserr.New(request.ErrCodeSerialization, fmt.Sprintf("unknown minor type %d or tag %d", minor, tag), nil) + return nil, &smithy.DeserializationError{Err: fmt.Errorf("unknown minor type %d or tag %d", minor, tag)} } } default: - return nil, awserr.New(request.ErrCodeSerialization, fmt.Sprintf("unknown major type %d", major), nil) + return nil, &smithy.DeserializationError{Err: fmt.Errorf("unknown major type %d", major)} } } diff --git a/dax/internal/cbor/attrval_test.go b/dax/internal/cbor/attrval_test.go index 681af36..ac51f0b 100644 --- a/dax/internal/cbor/attrval_test.go +++ b/dax/internal/cbor/attrval_test.go @@ -17,42 +17,42 @@ package cbor import ( "bytes" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/dynamodb" "reflect" "testing" + + "github.com/aws/aws-sdk-go-v2/service/dynamodb/types" ) func TestAttrVal(t *testing.T) { cases := []struct { - val dynamodb.AttributeValue + val types.AttributeValue enc []byte }{ - {val: dynamodb.AttributeValue{S: aws.String("abc")}}, - {val: dynamodb.AttributeValue{S: aws.String("abcdefghijklmnopqrstuvwxyz0123456789")}}, - {val: dynamodb.AttributeValue{N: aws.String("123")}}, - {val: dynamodb.AttributeValue{N: aws.String("-123")}}, - {val: dynamodb.AttributeValue{N: aws.String("123456789012345678901234567890")}}, - {val: dynamodb.AttributeValue{N: aws.String("-123456789012345678901234567890")}}, - {val: dynamodb.AttributeValue{N: aws.String("314E-2")}}, - {val: dynamodb.AttributeValue{N: aws.String("-314E-2")}}, - //{val: dynamodb.AttributeValue{N: stringptr("3.14")}}, // Decimal.String() return 314E-2 - {val: dynamodb.AttributeValue{B: fromHex("0x010203")}}, - {val: dynamodb.AttributeValue{SS: []*string{aws.String("abc"), aws.String("def"), aws.String("xyz")}}}, - {val: dynamodb.AttributeValue{NS: []*string{aws.String("123"), aws.String("456"), aws.String("789")}}}, - {val: dynamodb.AttributeValue{BS: [][]byte{fromHex("0x010203"), fromHex("0x040506")}}}, - {val: dynamodb.AttributeValue{L: []*dynamodb.AttributeValue{&dynamodb.AttributeValue{S: aws.String("abc")}, &dynamodb.AttributeValue{N: aws.String("123")}}}}, - {val: dynamodb.AttributeValue{M: map[string]*dynamodb.AttributeValue{"s": &dynamodb.AttributeValue{S: aws.String("abc")}, "n": &dynamodb.AttributeValue{N: aws.String("123")}}}}, - {val: dynamodb.AttributeValue{BOOL: aws.Bool(true)}}, - {val: dynamodb.AttributeValue{BOOL: aws.Bool(false)}}, - {val: dynamodb.AttributeValue{NULL: aws.Bool(true)}}, + {val: &types.AttributeValueMemberS{Value: "abc"}}, + {val: &types.AttributeValueMemberS{Value: "abcdefghijklmnopqrstuvwxyz0123456789"}}, + {val: &types.AttributeValueMemberN{Value: "123"}}, + {val: &types.AttributeValueMemberN{Value: "-123"}}, + {val: &types.AttributeValueMemberN{Value: "123456789012345678901234567890"}}, + {val: &types.AttributeValueMemberN{Value: "-123456789012345678901234567890"}}, + {val: &types.AttributeValueMemberN{Value: "314E-2"}}, + {val: &types.AttributeValueMemberN{Value: "-314E-2"}}, + //{val: types.AttributeValue{N: stringptr("3.14")}}, // Decimal.String() return 314E-2 + {val: &types.AttributeValueMemberB{Value: fromHex("0x010203")}}, + {val: &types.AttributeValueMemberSS{Value: []string{"abc", "def", "xyz"}}}, + {val: &types.AttributeValueMemberNS{Value: []string{"123", "456", "789"}}}, + {val: &types.AttributeValueMemberBS{Value: [][]byte{fromHex("0x010203"), fromHex("0x040506")}}}, + {val: &types.AttributeValueMemberL{Value: []types.AttributeValue{&types.AttributeValueMemberS{Value: "abc"}, &types.AttributeValueMemberN{Value: "123"}}}}, + {val: &types.AttributeValueMemberM{Value: map[string]types.AttributeValue{"s": &types.AttributeValueMemberS{Value: "abc"}, "n": &types.AttributeValueMemberN{Value: "123"}}}}, + {val: &types.AttributeValueMemberBOOL{Value: true}}, + {val: &types.AttributeValueMemberBOOL{Value: false}}, + {val: &types.AttributeValueMemberNULL{Value: true}}, } for _, c := range cases { lval := c.val var buf bytes.Buffer w := NewWriter(&buf) - if err := EncodeAttributeValue(&lval, w); err != nil { + if err := EncodeAttributeValue(lval, w); err != nil { t.Errorf("unexpected error %v for %v", err, lval) continue } @@ -61,8 +61,8 @@ func TestAttrVal(t *testing.T) { continue } - bytes := buf.Bytes() - if c.enc != nil && !reflect.DeepEqual(c.enc, bytes) { + bufBytes := buf.Bytes() + if c.enc != nil && !reflect.DeepEqual(c.enc, bufBytes) { t.Errorf("incorrect encoding for %v", c.val) } @@ -73,7 +73,7 @@ func TestAttrVal(t *testing.T) { continue } - if !reflect.DeepEqual(lval, *rval) { + if !reflect.DeepEqual(lval, rval) { t.Errorf("expected: %v, actual: %v", lval, rval) } } @@ -101,7 +101,7 @@ func TestDecodeIntBoundariesFromCbor(t *testing.T) { if err != nil { t.Errorf("unexpected error %v for %s", err, e.name) } - if eAttr := (dynamodb.AttributeValue{N: aws.String(e.value.String())}); !reflect.DeepEqual(eAttr, *a) { + if eAttr := types.AttributeValue(&types.AttributeValueMemberN{Value: e.value.String()}); !reflect.DeepEqual(eAttr, a) { t.Errorf("test %s expected: %v, actual: %v", e.name, eAttr, a) } } diff --git a/dax/internal/cbor/cbor.go b/dax/internal/cbor/cbor.go index 2ef9d15..1705c7c 100644 --- a/dax/internal/cbor/cbor.go +++ b/dax/internal/cbor/cbor.go @@ -19,13 +19,13 @@ import ( "bufio" "encoding/binary" "fmt" - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/aws/request" "io" "math" "math/big" "strconv" "sync" + + "github.com/aws/smithy-go" ) const ( @@ -33,9 +33,9 @@ const ( maxObjLenBytes = 1024 * 1024 * 1024 ) -var ErrNaN = awserr.New(request.InvalidParameterErrCode, "cbor: not a number", nil) -var ErrObjTooBig = awserr.New(request.ErrCodeSerialization, "cbor: object too big", nil) -var ErrNegLength = awserr.New(request.ErrCodeSerialization, "cbor: negative length", nil) +var ErrNaN = &smithy.InvalidParamsError{Context: "cbor: not a number"} // awserr.New(request.InvalidParameterErrCode, "cbor: not a number", nil) +var ErrObjTooBig = &smithy.DeserializationError{Err: fmt.Errorf("cbor: object too big")} //awserr.New(request.ErrCodeSerialization, "cbor: object too big", nil) +var ErrNegLength = &smithy.DeserializationError{Err: fmt.Errorf("cbor: negative length")} //awserr.New(request.ErrCodeSerialization, "cbor: negative length", nil) // A Writer writes cbor-encoded data. type Writer struct { @@ -483,7 +483,8 @@ func (r *Reader) readTypeHeader() (hdr int, value uint64, err error) { func (r *Reader) verifyMajorType(hdr, exp int) error { if (hdr & MajorTypeMask) != exp { - return awserr.New(request.ErrCodeSerialization, fmt.Sprintf("cbor: expected major type %d, got %d", exp, hdr&MajorTypeMask), nil) + //return awserr.New(request.ErrCodeSerialization, fmt.Sprintf("cbor: expected major type %d, got %d", exp, hdr&MajorTypeMask), nil) + return &smithy.DeserializationError{Err: fmt.Errorf("cbor: expected major type %d, got %d", exp, hdr&MajorTypeMask)} } return nil } diff --git a/dax/internal/cbor/cbor_test.go b/dax/internal/cbor/cbor_test.go index a03e1ef..8ed12bf 100644 --- a/dax/internal/cbor/cbor_test.go +++ b/dax/internal/cbor/cbor_test.go @@ -26,8 +26,7 @@ import ( "strings" "testing" - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/aws/request" + "github.com/aws/smithy-go" ) type IntBoundary struct { @@ -208,7 +207,8 @@ func TestCborType(t *testing.T) { if rt == PosInt || rt == NegInt { exp = ErrNaN } else { - exp = awserr.New(request.ErrCodeSerialization, fmt.Sprintf("cbor: expected major type %d, got %d", rt, wt&MajorTypeMask), nil) + exp = &smithy.DeserializationError{Err: fmt.Errorf("cbor: expected major type %d, got %d", rt, wt&MajorTypeMask)} + //exp = awserr.New(request.ErrCodeSerialization, fmt.Sprintf("cbor: expected major type %d, got %d", rt, wt&MajorTypeMask), nil) } if !reflect.DeepEqual(exp, err) { t.Errorf("expected %v, got %v", exp, err) diff --git a/dax/internal/cbor/item.go b/dax/internal/cbor/item.go index 3d4014f..d2a5b1c 100644 --- a/dax/internal/cbor/item.go +++ b/dax/internal/cbor/item.go @@ -17,18 +17,18 @@ package cbor import ( "bytes" + "context" + "errors" "fmt" - "github.com/aws/aws-dax-go/dax/internal/lru" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/aws/request" - "github.com/aws/aws-sdk-go/service/dynamodb" "sort" + + "github.com/aws/aws-dax-go/dax/internal/lru" + "github.com/aws/aws-sdk-go-v2/service/dynamodb/types" ) -var ErrMissingKey = awserr.New(request.ParamRequiredErrCode, "One of the required keys was not given a value", nil) +var ErrMissingKey = errors.New("one of the required keys was not given a value") -func EncodeItemKey(item map[string]*dynamodb.AttributeValue, keydef []dynamodb.AttributeDefinition, writer *Writer) error { +func EncodeItemKey(item map[string]types.AttributeValue, keydef []types.AttributeDefinition, writer *Writer) error { keyBytes, err := GetEncodedItemKey(item, keydef) if err != nil { return err @@ -36,14 +36,14 @@ func EncodeItemKey(item map[string]*dynamodb.AttributeValue, keydef []dynamodb.A return writer.WriteBytes(keyBytes) } -func GetEncodedItemKey(item map[string]*dynamodb.AttributeValue, keydef []dynamodb.AttributeDefinition) ([]byte, error) { +func GetEncodedItemKey(item map[string]types.AttributeValue, keydef []types.AttributeDefinition) ([]byte, error) { if item == nil { - return nil, awserr.New(request.InvalidParameterErrCode, "item cannot be nil", nil) + return nil, errors.New("item cannot be nil") } hk := keydef[0] - hkval, ok := item[*hk.AttributeName] - if !ok { + hkval, found := item[*hk.AttributeName] + if !found { return nil, ErrMissingKey } @@ -52,99 +52,101 @@ func GetEncodedItemKey(item map[string]*dynamodb.AttributeValue, keydef []dynamo defer w.Close() if len(keydef) == 1 { - switch *hk.AttributeType { - case dynamodb.ScalarAttributeTypeS: - sp := hkval.S - if sp == nil { + switch hk.AttributeType { + case types.ScalarAttributeTypeS: + sp, ok := hkval.(*types.AttributeValueMemberS) + if !ok { return nil, ErrMissingKey } - if err := w.Write([]byte(*sp)); err != nil { + if err := w.Write([]byte(sp.Value)); err != nil { return nil, err } - case dynamodb.ScalarAttributeTypeN: - if hkval.N == nil { + case types.ScalarAttributeTypeN: + _, ok := hkval.(*types.AttributeValueMemberN) + if !ok { return nil, ErrMissingKey } if err := EncodeAttributeValue(hkval, w); err != nil { return nil, err } - case dynamodb.ScalarAttributeTypeB: - b := hkval.B - if b == nil { + case types.ScalarAttributeTypeB: + b, ok := hkval.(*types.AttributeValueMemberB) + if !ok { return nil, ErrMissingKey } - if err := w.Write(b); err != nil { + if err := w.Write(b.Value); err != nil { return nil, err } default: - return nil, awserr.New(request.InvalidParameterErrCode, fmt.Sprintf("Unsupported KeyType encountered in Hash Attribute: "+*hk.AttributeType), nil) + return nil, fmt.Errorf("unsupported KeyType encountered in Hash Attribute: %s", hk.AttributeType) } } else { - switch *hk.AttributeType { - case dynamodb.ScalarAttributeTypeS: - sp := hkval.S - if sp == nil { + switch hk.AttributeType { + case types.ScalarAttributeTypeS: + sp, ok := hkval.(*types.AttributeValueMemberS) + if !ok { return nil, ErrMissingKey } - if err := w.WriteString(*sp); err != nil { + if err := w.WriteString(sp.Value); err != nil { return nil, err } - case dynamodb.ScalarAttributeTypeN: - if hkval.N == nil { + case types.ScalarAttributeTypeN: + _, ok := hkval.(*types.AttributeValueMemberN) + if !ok { return nil, ErrMissingKey } if err := EncodeAttributeValue(hkval, w); err != nil { return nil, err } - case dynamodb.ScalarAttributeTypeB: - b := hkval.B - if b == nil { + case types.ScalarAttributeTypeB: + b, ok := hkval.(*types.AttributeValueMemberB) + if !ok { return nil, ErrMissingKey } - if err := w.WriteBytes(b); err != nil { + if err := w.WriteBytes(b.Value); err != nil { return nil, err } default: - return nil, awserr.New(request.InvalidParameterErrCode, fmt.Sprintf("Unsupported KeyType encountered in Hash Attribute: "+*hk.AttributeType), nil) + return nil, fmt.Errorf("unsupported KeyType encountered in Hash Attribute: %s", hk.AttributeType) } rk := keydef[1] - rkval, ok := item[*rk.AttributeName] - if !ok { + rkval, found := item[*rk.AttributeName] + if !found { return nil, ErrMissingKey } - switch *rk.AttributeType { - case dynamodb.ScalarAttributeTypeS: - sp := rkval.S - if sp == nil { + switch rk.AttributeType { + case types.ScalarAttributeTypeS: + sp, ok := rkval.(*types.AttributeValueMemberS) + if !ok { return nil, ErrMissingKey } - if err := w.Write([]byte(*sp)); err != nil { + if err := w.Write([]byte(sp.Value)); err != nil { return nil, err } - case dynamodb.ScalarAttributeTypeN: - n := rkval.N - if n == nil { + case types.ScalarAttributeTypeN: + n, ok := rkval.(*types.AttributeValueMemberN) + if !ok { return nil, ErrMissingKey } d := new(Decimal) - d, ok := d.SetString(*n) + d, ok = d.SetString(n.Value) if !ok { - return nil, awserr.New(request.InvalidParameterErrCode, fmt.Sprintf("invalid number "+*n), nil) + return nil, errors.New("invalid number " + n.Value) } if _, err := EncodeLexDecimal(d, w.bw); err != nil { return nil, err } - case dynamodb.ScalarAttributeTypeB: - b := rkval.B - if b == nil { + case types.ScalarAttributeTypeB: + b, ok := rkval.(*types.AttributeValueMemberB) + if !ok { return nil, ErrMissingKey } - if err := w.Write(b); err != nil { + if err := w.Write(b.Value); err != nil { return nil, err } default: - return nil, awserr.New(request.InvalidParameterErrCode, fmt.Sprintf("Unsupported KeyType encountered in Range Attribute: "+*rk.AttributeType), nil) + return nil, fmt.Errorf("unsupported KeyType encountered in Range Attribute: %s", rk.AttributeType) } } @@ -154,20 +156,20 @@ func GetEncodedItemKey(item map[string]*dynamodb.AttributeValue, keydef []dynamo return buf.Bytes(), nil } -func DecodeItemKey(reader *Reader, keydef []dynamodb.AttributeDefinition) (map[string]*dynamodb.AttributeValue, error) { +func DecodeItemKey(reader *Reader, keydef []types.AttributeDefinition) (map[string]types.AttributeValue, error) { hk := keydef[0] - keys := make(map[string]*dynamodb.AttributeValue) + keys := make(map[string]types.AttributeValue) if len(keydef) == 1 { - switch *hk.AttributeType { - case dynamodb.ScalarAttributeTypeS: + switch hk.AttributeType { + case types.ScalarAttributeTypeS: kb, err := reader.ReadBytes() if err != nil { return nil, err } s := string(kb) - keys[*hk.AttributeName] = &dynamodb.AttributeValue{S: &s} - case dynamodb.ScalarAttributeTypeN: + keys[*hk.AttributeName] = &types.AttributeValueMemberS{Value: s} + case types.ScalarAttributeTypeN: r, err := reader.BytesReader() if err != nil { return nil, err @@ -177,18 +179,19 @@ func DecodeItemKey(reader *Reader, keydef []dynamodb.AttributeDefinition) (map[s if err != nil { return nil, err } - if av.N == nil { + _, ok := av.(*types.AttributeValueMemberN) + if !ok { return nil, ErrMissingKey } keys[*hk.AttributeName] = av - case dynamodb.ScalarAttributeTypeB: + case types.ScalarAttributeTypeB: kb, err := reader.ReadBytes() if err != nil { return nil, err } - keys[*hk.AttributeName] = &dynamodb.AttributeValue{B: kb} + keys[*hk.AttributeName] = &types.AttributeValueMemberB{Value: kb} default: - return nil, awserr.New(request.InvalidParameterErrCode, fmt.Sprintf("Unsupported KeyType encountered in Hash Attribute: "+*hk.AttributeType), nil) + return nil, fmt.Errorf("unsupported KeyType encountered in Hash Attribute: %s", hk.AttributeType) } } else { r, err := reader.BytesReader() @@ -196,75 +199,76 @@ func DecodeItemKey(reader *Reader, keydef []dynamodb.AttributeDefinition) (map[s return nil, err } defer r.Close() - switch *hk.AttributeType { - case dynamodb.ScalarAttributeTypeS: + switch hk.AttributeType { + case types.ScalarAttributeTypeS: s, err := r.ReadString() if err != nil { return nil, err } - keys[*hk.AttributeName] = &dynamodb.AttributeValue{S: &s} - case dynamodb.ScalarAttributeTypeN: + keys[*hk.AttributeName] = &types.AttributeValueMemberS{Value: s} + case types.ScalarAttributeTypeN: av, err := DecodeAttributeValue(r) if err != nil { return nil, err } - if av.N == nil { + _, ok := av.(*types.AttributeValueMemberN) + if !ok { return nil, ErrMissingKey } keys[*hk.AttributeName] = av - case dynamodb.ScalarAttributeTypeB: + case types.ScalarAttributeTypeB: b, err := r.ReadBytes() if err != nil { return nil, err } - keys[*hk.AttributeName] = &dynamodb.AttributeValue{B: b} + keys[*hk.AttributeName] = &types.AttributeValueMemberB{Value: b} default: - return nil, awserr.New(request.InvalidParameterErrCode, fmt.Sprintf("Unsupported KeyType encountered in Hash Attribute: "+*hk.AttributeType), nil) + return nil, fmt.Errorf("unsupported KeyType encountered in Hash Attribute: %s", hk.AttributeType) } rk := keydef[1] - switch *rk.AttributeType { - case dynamodb.ScalarAttributeTypeS: + switch rk.AttributeType { + case types.ScalarAttributeTypeS: var buf bytes.Buffer if _, err := r.br.WriteTo(&buf); err != nil { return nil, err } s := string(buf.Bytes()) - keys[*rk.AttributeName] = &dynamodb.AttributeValue{S: &s} - case dynamodb.ScalarAttributeTypeN: + keys[*rk.AttributeName] = &types.AttributeValueMemberS{Value: s} + case types.ScalarAttributeTypeN: d, err := DecodeLexDecimal(r.br) if err != nil { return nil, err } s := d.String() - keys[*rk.AttributeName] = &dynamodb.AttributeValue{N: &s} - case dynamodb.ScalarAttributeTypeB: + keys[*rk.AttributeName] = &types.AttributeValueMemberN{Value: s} + case types.ScalarAttributeTypeB: var buf bytes.Buffer if _, err := r.br.WriteTo(&buf); err != nil { return nil, err } - keys[*rk.AttributeName] = &dynamodb.AttributeValue{B: buf.Bytes()} + keys[*rk.AttributeName] = &types.AttributeValueMemberB{Value: buf.Bytes()} default: - return nil, awserr.New(request.InvalidParameterErrCode, fmt.Sprintf("Unsupported KeyType encountered in Range Attribute: "+*rk.AttributeType), nil) + return nil, fmt.Errorf("unsupported KeyType encountered in Range Attribute: %s", rk.AttributeType) } } return keys, nil } -func EncodeItemNonKeyAttributes(ctx aws.Context, item map[string]*dynamodb.AttributeValue, keydef []dynamodb.AttributeDefinition, +func EncodeItemNonKeyAttributes(ctx context.Context, item map[string]types.AttributeValue, keydef []types.AttributeDefinition, attrNamesListToId *lru.Lru, writer *Writer) error { keydeflen := len(keydef) nonKeyAttrNames := make([]string, 0, len(item)-keydeflen) - for k, _ := range item { + for k := range item { if k != *keydef[0].AttributeName && (keydeflen == 1 || k != *keydef[1].AttributeName) { nonKeyAttrNames = append(nonKeyAttrNames, k) } } sort.Strings(nonKeyAttrNames) - nonKeyAttrValues := make([]*dynamodb.AttributeValue, len(nonKeyAttrNames)) + nonKeyAttrValues := make([]types.AttributeValue, len(nonKeyAttrNames)) for i, k := range nonKeyAttrNames { nonKeyAttrValues[i] = item[k] } @@ -286,7 +290,7 @@ func EncodeItemNonKeyAttributes(ctx aws.Context, item map[string]*dynamodb.Attri return nil } -func DecodeItemNonKeyAttributes(ctx aws.Context, reader *Reader, attrListIdToNames *lru.Lru) (map[string]*dynamodb.AttributeValue, error) { +func DecodeItemNonKeyAttributes(ctx context.Context, reader *Reader, attrListIdToNames *lru.Lru) (map[string]types.AttributeValue, error) { id, err := reader.ReadInt64() if err != nil { return nil, err @@ -296,7 +300,7 @@ func DecodeItemNonKeyAttributes(ctx aws.Context, reader *Reader, attrListIdToNam return nil, err } - attrs := make(map[string]*dynamodb.AttributeValue) + attrs := make(map[string]types.AttributeValue) for _, n := range attrNames.([]string) { av, err := DecodeAttributeValue(reader) if err != nil { diff --git a/dax/internal/cbor/item_test.go b/dax/internal/cbor/item_test.go index edc62e5..69393c7 100644 --- a/dax/internal/cbor/item_test.go +++ b/dax/internal/cbor/item_test.go @@ -17,139 +17,141 @@ package cbor import ( "bytes" + "context" "errors" "fmt" - "github.com/aws/aws-dax-go/dax/internal/lru" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/dynamodb" "reflect" "strings" "testing" + + "github.com/aws/aws-dax-go/dax/internal/lru" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/dynamodb/types" ) func TestItemKey(t *testing.T) { cases := []struct { - keydef []dynamodb.AttributeDefinition - item map[string]*dynamodb.AttributeValue + keydef []types.AttributeDefinition + item map[string]types.AttributeValue enc []byte }{ { - keydef: []dynamodb.AttributeDefinition{{AttributeName: aws.String("hks"), AttributeType: aws.String(dynamodb.ScalarAttributeTypeS)}}, - item: map[string]*dynamodb.AttributeValue{ - "hks": {S: aws.String("hkv")}, + keydef: []types.AttributeDefinition{{AttributeName: aws.String("hks"), AttributeType: types.ScalarAttributeTypeS}}, + item: map[string]types.AttributeValue{ + "hks": &types.AttributeValueMemberS{Value: "hkv"}, }, enc: fromHex("0x43686b76"), }, { - keydef: []dynamodb.AttributeDefinition{{AttributeName: aws.String("hkn"), AttributeType: aws.String(dynamodb.ScalarAttributeTypeN)}}, - item: map[string]*dynamodb.AttributeValue{ - "hkn": {N: aws.String("5")}, + keydef: []types.AttributeDefinition{{AttributeName: aws.String("hkn"), AttributeType: types.ScalarAttributeTypeN}}, + item: map[string]types.AttributeValue{ + "hkn": &types.AttributeValueMemberN{Value: "5"}, }, enc: fromHex("0x4105"), }, { - keydef: []dynamodb.AttributeDefinition{{AttributeName: aws.String("hkb"), AttributeType: aws.String(dynamodb.ScalarAttributeTypeB)}}, - item: map[string]*dynamodb.AttributeValue{ - "hkb": {B: fromHex("0x010203")}, + keydef: []types.AttributeDefinition{{AttributeName: aws.String("hkb"), AttributeType: types.ScalarAttributeTypeB}}, + item: map[string]types.AttributeValue{ + "hkb": &types.AttributeValueMemberB{Value: fromHex("0x010203")}, }, enc: fromHex("0x43010203"), }, { - keydef: []dynamodb.AttributeDefinition{ - {AttributeName: aws.String("hks"), AttributeType: aws.String(dynamodb.ScalarAttributeTypeS)}, - {AttributeName: aws.String("rks"), AttributeType: aws.String(dynamodb.ScalarAttributeTypeS)}, + keydef: []types.AttributeDefinition{ + {AttributeName: aws.String("hks"), AttributeType: types.ScalarAttributeTypeS}, + {AttributeName: aws.String("rks"), AttributeType: types.ScalarAttributeTypeS}, }, - item: map[string]*dynamodb.AttributeValue{ - "hks": {S: aws.String("hkv")}, - "rks": {S: aws.String("rkv")}, + item: map[string]types.AttributeValue{ + "hks": &types.AttributeValueMemberS{Value: "hkv"}, + "rks": &types.AttributeValueMemberS{Value: "rkv"}, }, enc: fromHex("0x4763686b76726b76"), }, { - keydef: []dynamodb.AttributeDefinition{ - {AttributeName: aws.String("hks"), AttributeType: aws.String(dynamodb.ScalarAttributeTypeS)}, - {AttributeName: aws.String("rkn"), AttributeType: aws.String(dynamodb.ScalarAttributeTypeN)}, + keydef: []types.AttributeDefinition{ + {AttributeName: aws.String("hks"), AttributeType: types.ScalarAttributeTypeS}, + {AttributeName: aws.String("rkn"), AttributeType: types.ScalarAttributeTypeN}, }, - item: map[string]*dynamodb.AttributeValue{ - "hks": {S: aws.String("hkv")}, - "rkn": {N: aws.String("5")}, + item: map[string]types.AttributeValue{ + "hks": &types.AttributeValueMemberS{Value: "hkv"}, + "rkn": &types.AttributeValueMemberN{Value: "5"}, }, //enc:fromHex("0x4563686b76724105"), TODO lex decimal }, { - keydef: []dynamodb.AttributeDefinition{ - {AttributeName: aws.String("hks"), AttributeType: aws.String(dynamodb.ScalarAttributeTypeS)}, - {AttributeName: aws.String("rkb"), AttributeType: aws.String(dynamodb.ScalarAttributeTypeB)}, + keydef: []types.AttributeDefinition{ + {AttributeName: aws.String("hks"), AttributeType: types.ScalarAttributeTypeS}, + {AttributeName: aws.String("rkb"), AttributeType: types.ScalarAttributeTypeB}, }, - item: map[string]*dynamodb.AttributeValue{ - "hks": {S: aws.String("hkv")}, - "rkb": {B: fromHex("0x010203")}, + item: map[string]types.AttributeValue{ + "hks": &types.AttributeValueMemberS{Value: "hkv"}, + "rkb": &types.AttributeValueMemberB{Value: fromHex("0x010203")}, }, enc: fromHex("0x4763686b76010203"), }, { - keydef: []dynamodb.AttributeDefinition{ - {AttributeName: aws.String("hkn"), AttributeType: aws.String(dynamodb.ScalarAttributeTypeN)}, - {AttributeName: aws.String("rks"), AttributeType: aws.String(dynamodb.ScalarAttributeTypeS)}, + keydef: []types.AttributeDefinition{ + {AttributeName: aws.String("hkn"), AttributeType: types.ScalarAttributeTypeN}, + {AttributeName: aws.String("rks"), AttributeType: types.ScalarAttributeTypeS}, }, - item: map[string]*dynamodb.AttributeValue{ - "hkn": {N: aws.String("5")}, - "rks": {S: aws.String("rkv")}, + item: map[string]types.AttributeValue{ + "hkn": &types.AttributeValueMemberN{Value: "5"}, + "rks": &types.AttributeValueMemberS{Value: "rkv"}, }, enc: fromHex("0x4405726b76"), }, { - keydef: []dynamodb.AttributeDefinition{ - {AttributeName: aws.String("hkn"), AttributeType: aws.String(dynamodb.ScalarAttributeTypeN)}, - {AttributeName: aws.String("rkn"), AttributeType: aws.String(dynamodb.ScalarAttributeTypeN)}, + keydef: []types.AttributeDefinition{ + {AttributeName: aws.String("hkn"), AttributeType: types.ScalarAttributeTypeN}, + {AttributeName: aws.String("rkn"), AttributeType: types.ScalarAttributeTypeN}, }, - item: map[string]*dynamodb.AttributeValue{ - "hkn": {N: aws.String("5")}, - "rkn": {N: aws.String("1")}, + item: map[string]types.AttributeValue{ + "hkn": &types.AttributeValueMemberN{Value: "5"}, + "rkn": &types.AttributeValueMemberN{Value: "1"}, }, //enc:fromHex("0x4105726b76"), TODO lex decimal }, { - keydef: []dynamodb.AttributeDefinition{ - {AttributeName: aws.String("hkn"), AttributeType: aws.String(dynamodb.ScalarAttributeTypeN)}, - {AttributeName: aws.String("rkb"), AttributeType: aws.String(dynamodb.ScalarAttributeTypeB)}, + keydef: []types.AttributeDefinition{ + {AttributeName: aws.String("hkn"), AttributeType: types.ScalarAttributeTypeN}, + {AttributeName: aws.String("rkb"), AttributeType: types.ScalarAttributeTypeB}, }, - item: map[string]*dynamodb.AttributeValue{ - "hkn": {N: aws.String("5")}, - "rkb": {B: fromHex("0x010203")}, + item: map[string]types.AttributeValue{ + "hkn": &types.AttributeValueMemberN{Value: "5"}, + "rkb": &types.AttributeValueMemberB{Value: fromHex("0x010203")}, }, enc: fromHex("0x4405010203"), }, { - keydef: []dynamodb.AttributeDefinition{ - {AttributeName: aws.String("hkb"), AttributeType: aws.String(dynamodb.ScalarAttributeTypeB)}, - {AttributeName: aws.String("rks"), AttributeType: aws.String(dynamodb.ScalarAttributeTypeS)}, + keydef: []types.AttributeDefinition{ + {AttributeName: aws.String("hkb"), AttributeType: types.ScalarAttributeTypeB}, + {AttributeName: aws.String("rks"), AttributeType: types.ScalarAttributeTypeS}, }, - item: map[string]*dynamodb.AttributeValue{ - "hkb": {B: fromHex("0x040506")}, - "rks": {S: aws.String("rkv")}, + item: map[string]types.AttributeValue{ + "hkb": &types.AttributeValueMemberB{Value: fromHex("0x040506")}, + "rks": &types.AttributeValueMemberS{Value: "rkv"}, }, enc: fromHex("0x4743040506726b76"), }, { - keydef: []dynamodb.AttributeDefinition{ - {AttributeName: aws.String("hkb"), AttributeType: aws.String(dynamodb.ScalarAttributeTypeB)}, - {AttributeName: aws.String("rkn"), AttributeType: aws.String(dynamodb.ScalarAttributeTypeN)}, + keydef: []types.AttributeDefinition{ + {AttributeName: aws.String("hkb"), AttributeType: types.ScalarAttributeTypeB}, + {AttributeName: aws.String("rkn"), AttributeType: types.ScalarAttributeTypeN}, }, - item: map[string]*dynamodb.AttributeValue{ - "hkb": {B: fromHex("0x040506")}, - "rkn": {N: aws.String("123")}, + item: map[string]types.AttributeValue{ + "hkb": &types.AttributeValueMemberB{Value: fromHex("0x040506")}, + "rkn": &types.AttributeValueMemberN{Value: "123"}, }, //enc:fromHex("0x4743040506726b76"), TODO lex decimal }, { - keydef: []dynamodb.AttributeDefinition{ - {AttributeName: aws.String("hkb"), AttributeType: aws.String(dynamodb.ScalarAttributeTypeB)}, - {AttributeName: aws.String("rkb"), AttributeType: aws.String(dynamodb.ScalarAttributeTypeB)}, + keydef: []types.AttributeDefinition{ + {AttributeName: aws.String("hkb"), AttributeType: types.ScalarAttributeTypeB}, + {AttributeName: aws.String("rkb"), AttributeType: types.ScalarAttributeTypeB}, }, - item: map[string]*dynamodb.AttributeValue{ - "hkb": {B: fromHex("0x040506")}, - "rkb": {B: fromHex("0x010203")}, + item: map[string]types.AttributeValue{ + "hkb": &types.AttributeValueMemberB{Value: fromHex("0x040506")}, + "rkb": &types.AttributeValueMemberB{Value: fromHex("0x010203")}, }, enc: fromHex("0x4743040506010203"), }, @@ -192,16 +194,16 @@ func TestItemKey(t *testing.T) { } func TestItemNonKeyAttributes(t *testing.T) { - keydef := []dynamodb.AttributeDefinition{ - {AttributeName: aws.String("hks"), AttributeType: aws.String(dynamodb.ScalarAttributeTypeS)}, - {AttributeName: aws.String("rkn"), AttributeType: aws.String(dynamodb.ScalarAttributeTypeN)}, + keydef := []types.AttributeDefinition{ + {AttributeName: aws.String("hks"), AttributeType: types.ScalarAttributeTypeS}, + {AttributeName: aws.String("rkn"), AttributeType: types.ScalarAttributeTypeN}, } - item := map[string]*dynamodb.AttributeValue{ - "hks": &dynamodb.AttributeValue{S: aws.String("hkv")}, - "rkn": &dynamodb.AttributeValue{N: aws.String("123")}, - "av1": &dynamodb.AttributeValue{S: aws.String("avs")}, - "av2": &dynamodb.AttributeValue{N: aws.String("456")}, - "av3": &dynamodb.AttributeValue{B: fromHex("0x010203")}, + item := map[string]types.AttributeValue{ + "hks": &types.AttributeValueMemberS{Value: "hkv"}, + "rkn": &types.AttributeValueMemberN{Value: "123"}, + "av1": &types.AttributeValueMemberS{Value: "avs"}, + "av2": &types.AttributeValueMemberN{Value: "456"}, + "av3": &types.AttributeValueMemberB{Value: fromHex("0x010203")}, } attrNames := []string{"av1", "av2", "av3"} var attrListId int64 = 1 @@ -209,7 +211,7 @@ func TestItemNonKeyAttributes(t *testing.T) { return fmt.Sprintf("%q", key) } attrNamesListToId := &lru.Lru{ - LoadFunc: func(ctx aws.Context, key lru.Key) (interface{}, error) { + LoadFunc: func(ctx context.Context, key lru.Key) (interface{}, error) { an := key.([]string) if !reflect.DeepEqual(an, attrNames) { return nil, errors.New(fmt.Sprintf("unknown attribute list %v %v", an, strings.Join(an, ","))) @@ -219,7 +221,7 @@ func TestItemNonKeyAttributes(t *testing.T) { KeyMarshaller: km, } attrListIdToNames := &lru.Lru{ - LoadFunc: func(ctx aws.Context, key lru.Key) (interface{}, error) { + LoadFunc: func(ctx context.Context, key lru.Key) (interface{}, error) { id := key.(int64) if id != attrListId { return nil, errors.New(fmt.Sprintf("unknown attribute list id %v", id)) @@ -243,7 +245,7 @@ func TestItemNonKeyAttributes(t *testing.T) { t.Fatalf("unexpected error %v", err) } - expected := make(map[string]*dynamodb.AttributeValue) + expected := make(map[string]types.AttributeValue) for k, v := range item { if k != *keydef[0].AttributeName && k != *keydef[1].AttributeName { expected[k] = v diff --git a/dax/internal/cbor/lexdecimal.go b/dax/internal/cbor/lexdecimal.go index 612b143..779c90a 100644 --- a/dax/internal/cbor/lexdecimal.go +++ b/dax/internal/cbor/lexdecimal.go @@ -17,11 +17,12 @@ package cbor import ( "encoding/binary" - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/aws/request" + "errors" "io" "math" "math/big" + + "github.com/aws/smithy-go" ) /* Encoding of header: @@ -353,7 +354,7 @@ func decodeInt32BE(reader BytesReader) (int, error) { return len, nil } if len != 4 { - return len, awserr.New(request.ErrCodeSerialization, "incomplete lexdecimal", nil) + return len, &smithy.SerializationError{Err: errors.New("incomplete lexdecimal")} } v := int32(binary.BigEndian.Uint32(bytes[:])) return int(v), nil diff --git a/dax/internal/client/client.go b/dax/internal/client/client.go new file mode 100644 index 0000000..b5106f0 --- /dev/null +++ b/dax/internal/client/client.go @@ -0,0 +1,24 @@ +package client + +import ( + "errors" + + "github.com/aws/smithy-go" +) + +func operationError(op string, err error) error { + // nil error + if err == nil { + return nil + } + // already smithy.OperationError + var smithyErr *smithy.OperationError + if errors.As(err, &smithyErr) { + return err + } + return &smithy.OperationError{ + ServiceID: service, + OperationName: op, + Err: err, + } +} diff --git a/dax/internal/client/cluster.go b/dax/internal/client/cluster.go index d62fa8a..7f932d0 100644 --- a/dax/internal/client/cluster.go +++ b/dax/internal/client/cluster.go @@ -17,6 +17,7 @@ package client import ( "context" + "errors" "fmt" "io" "math/rand" @@ -29,12 +30,16 @@ import ( "sync/atomic" "time" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/aws/credentials" - "github.com/aws/aws-sdk-go/aws/defaults" - "github.com/aws/aws-sdk-go/aws/request" - "github.com/aws/aws-sdk-go/service/dynamodb" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/config" + "github.com/aws/aws-sdk-go-v2/service/dynamodb" + "github.com/aws/smithy-go" + "github.com/aws/smithy-go/logging" +) + +const ( + schemeDax = "dax" + schemeDaxs = "daxs" ) type serviceEndpoint struct { @@ -63,15 +68,15 @@ type Config struct { IdleConnectionReapDelay time.Duration ClientHealthCheckInterval time.Duration - HostPorts []string - Region string - Credentials *credentials.Credentials - DialContext func(ctx context.Context, network string, address string) (net.Conn, error) - connConfig connConfig + HostPorts []string + Region string + EndpointResolver aws.EndpointResolverWithOptions + Credentials aws.CredentialsProvider + DialContext func(ctx context.Context, network string, address string) (net.Conn, error) + connConfig connConfig SkipHostnameVerification bool - logger aws.Logger - logLevel aws.LogLevelType + logger logging.Logger } type connConfig struct { @@ -80,75 +85,91 @@ type connConfig struct { skipHostnameVerification bool } -func (cfg *Config) validate() error { - if cfg.HostPorts == nil || len(cfg.HostPorts) == 0 { - return awserr.New(request.ParamRequiredErrCode, "HostPorts is required", nil) +func (cfg *Config) validate(op string) error { + if len(cfg.HostPorts) == 0 && cfg.EndpointResolver == nil { + return &smithy.OperationError{ + ServiceID: service, + OperationName: op, + Err: errors.New("config.HostPorts or config.EndpointResolver is required"), + } } if len(cfg.Region) == 0 { - return awserr.New(request.ParamRequiredErrCode, "Region is required", nil) + return &smithy.OperationError{ + ServiceID: service, + OperationName: op, + Err: errors.New("config.Region is required"), + } } if cfg.Credentials == nil { - return awserr.New(request.ParamRequiredErrCode, "Credentials is required", nil) + return &smithy.OperationError{ + ServiceID: service, + OperationName: op, + Err: errors.New("config.Credentials is required"), + } } if cfg.MaxPendingConnectionsPerHost < 0 { - return awserr.New(request.InvalidParameterErrCode, "MaxPendingConnectionsPerHost cannot be negative", nil) + return &smithy.OperationError{ + ServiceID: service, + OperationName: op, + Err: errors.New("config.MaxPendingConnectionsPerHost cannot be negative"), + } } + return nil } func (cfg *Config) validateConnConfig() { if cfg.connConfig.isEncrypted && cfg.SkipHostnameVerification { - cfg.logger.Log(fmt.Sprintf("WARN: Skip hostname verification of TLS connections. The default is to perform hostname verification, setting this to True will skip verification. Be sure you understand the implication of doing so, which is the inability to authenticate the cluster that you are connecting to.")) + cfg.logger.Logf(ClassificationWarn, "Skip hostname verification of TLS connections. The default is to perform hostname verification, setting this to True will skip verification. Be sure you understand the implication of doing so, which is the inability to authenticate the cluster that you are connecting to.") } } -func (cfg *Config) SetLogger(logger aws.Logger, logLevelType aws.LogLevelType) { +func (cfg *Config) SetLogger(logger logging.Logger) { cfg.logger = logger - cfg.logLevel = logLevelType -} - -var defaultConfig = Config{ - MaxPendingConnectionsPerHost: 10, - ClusterUpdateInterval: time.Second * 4, - ClusterUpdateThreshold: time.Millisecond * 125, - ClientHealthCheckInterval: time.Second * 5, - - Credentials: defaults.CredChain(defaults.Config(), defaults.Handlers()), - - connConfig: connConfig{}, - SkipHostnameVerification: false, - logger: aws.NewDefaultLogger(), - logLevel: aws.LogOff, - IdleConnectionReapDelay: 30 * time.Second, } var defaultPorts = map[string]int{ - "dax": 8111, - "daxs": 9111, + schemeDax: 8111, + schemeDaxs: 9111, } func DefaultConfig() Config { - return defaultConfig + cfg := Config{ + MaxPendingConnectionsPerHost: 10, + ClusterUpdateInterval: time.Second * 4, + ClusterUpdateThreshold: time.Millisecond * 125, + ClientHealthCheckInterval: time.Second * 5, + + connConfig: connConfig{}, + SkipHostnameVerification: false, + logger: &logging.Nop{}, + IdleConnectionReapDelay: 30 * time.Second, + } + if cfg.Credentials == nil { + conf, err := config.LoadDefaultConfig(context.Background()) + if err != nil { + panic(fmt.Sprintf("unexpected error: %+v", err)) + } + cfg.Credentials = conf.Credentials + } + return cfg } type ClusterDaxClient struct { config Config cluster *cluster - - handlers *request.Handlers } -func New(config Config) (*ClusterDaxClient, error) { +func New(ctx context.Context, config Config) (*ClusterDaxClient, error) { cluster, err := newCluster(config) if err != nil { return nil, err } - err = cluster.start() + err = cluster.start(ctx) if err != nil { return nil, err } client := &ClusterDaxClient{config: config, cluster: cluster} - client.handlers = client.buildHandlers() return client, nil } @@ -156,268 +177,197 @@ func (cc *ClusterDaxClient) Close() error { return cc.cluster.Close() } -func (cc *ClusterDaxClient) endpoints(opt RequestOptions) ([]serviceEndpoint, error) { +func (cc *ClusterDaxClient) endpoints(ctx context.Context, opt RequestOptions) ([]serviceEndpoint, error) { var out []serviceEndpoint var err error action := func(client DaxAPI, o RequestOptions) error { - out, err = client.endpoints(o) + out, err = client.endpoints(ctx, o) return err } - if err = cc.retry(opEndpoints, action, opt); err != nil { - return nil, err + if err = cc.retry(ctx, opEndpoints, action, opt); err != nil { + return nil, operationError(opEndpoints, err) } return out, nil } -func (cc *ClusterDaxClient) PutItemWithOptions(input *dynamodb.PutItemInput, output *dynamodb.PutItemOutput, opt RequestOptions) (*dynamodb.PutItemOutput, error) { - var err error +func (cc *ClusterDaxClient) PutItemWithOptions(ctx context.Context, input *dynamodb.PutItemInput, opt RequestOptions) (*dynamodb.PutItemOutput, error) { + var output *dynamodb.PutItemOutput action := func(client DaxAPI, o RequestOptions) error { - output, err = client.PutItemWithOptions(input, output, o) + var err error + output, err = client.PutItemWithOptions(ctx, input, o) return err } - if err = cc.retry(OpPutItem, action, opt); err != nil { - return output, err + if err := cc.retry(ctx, OpPutItem, action, opt); err != nil { + return nil, operationError(OpPutItem, err) } return output, nil } -func (cc *ClusterDaxClient) DeleteItemWithOptions(input *dynamodb.DeleteItemInput, output *dynamodb.DeleteItemOutput, opt RequestOptions) (*dynamodb.DeleteItemOutput, error) { - var err error +func (cc *ClusterDaxClient) DeleteItemWithOptions(ctx context.Context, input *dynamodb.DeleteItemInput, opt RequestOptions) (*dynamodb.DeleteItemOutput, error) { + var output *dynamodb.DeleteItemOutput action := func(client DaxAPI, o RequestOptions) error { - output, err = client.DeleteItemWithOptions(input, output, o) + var err error + output, err = client.DeleteItemWithOptions(ctx, input, o) return err } - if err = cc.retry(OpDeleteItem, action, opt); err != nil { - return output, err + if err := cc.retry(ctx, OpDeleteItem, action, opt); err != nil { + return nil, operationError(OpDeleteItem, err) } return output, nil } -func (cc *ClusterDaxClient) UpdateItemWithOptions(input *dynamodb.UpdateItemInput, output *dynamodb.UpdateItemOutput, opt RequestOptions) (*dynamodb.UpdateItemOutput, error) { - var err error +func (cc *ClusterDaxClient) UpdateItemWithOptions(ctx context.Context, input *dynamodb.UpdateItemInput, opt RequestOptions) (*dynamodb.UpdateItemOutput, error) { + var output *dynamodb.UpdateItemOutput action := func(client DaxAPI, o RequestOptions) error { - output, err = client.UpdateItemWithOptions(input, output, o) + var err error + output, err = client.UpdateItemWithOptions(ctx, input, o) return err } - if err = cc.retry(OpUpdateItem, action, opt); err != nil { - return output, err + if err := cc.retry(ctx, OpUpdateItem, action, opt); err != nil { + return nil, operationError(OpUpdateItem, err) } return output, nil } -func (cc *ClusterDaxClient) BatchWriteItemWithOptions(input *dynamodb.BatchWriteItemInput, output *dynamodb.BatchWriteItemOutput, opt RequestOptions) (*dynamodb.BatchWriteItemOutput, error) { - var err error +func (cc *ClusterDaxClient) BatchWriteItemWithOptions(ctx context.Context, input *dynamodb.BatchWriteItemInput, opt RequestOptions) (*dynamodb.BatchWriteItemOutput, error) { + var output *dynamodb.BatchWriteItemOutput action := func(client DaxAPI, o RequestOptions) error { - output, err = client.BatchWriteItemWithOptions(input, output, o) + var err error + output, err = client.BatchWriteItemWithOptions(ctx, input, o) return err } - if err = cc.retry(OpBatchWriteItem, action, opt); err != nil { - return output, err + if err := cc.retry(ctx, OpBatchWriteItem, action, opt); err != nil { + return nil, operationError(OpBatchWriteItem, err) } return output, nil } -func (cc *ClusterDaxClient) TransactWriteItemsWithOptions(input *dynamodb.TransactWriteItemsInput, output *dynamodb.TransactWriteItemsOutput, opt RequestOptions) (*dynamodb.TransactWriteItemsOutput, error) { - var err error +func (cc *ClusterDaxClient) TransactWriteItemsWithOptions(ctx context.Context, input *dynamodb.TransactWriteItemsInput, opt RequestOptions) (*dynamodb.TransactWriteItemsOutput, error) { + var output *dynamodb.TransactWriteItemsOutput action := func(client DaxAPI, o RequestOptions) error { - output, err = client.TransactWriteItemsWithOptions(input, output, o) + var err error + output, err = client.TransactWriteItemsWithOptions(ctx, input, o) return err } - if err = cc.retry(OpTransactWriteItems, action, opt); err != nil { - return output, err + if err := cc.retry(ctx, OpTransactWriteItems, action, opt); err != nil { + return nil, operationError(OpTransactWriteItems, err) } return output, nil } -func (cc *ClusterDaxClient) TransactGetItemsWithOptions(input *dynamodb.TransactGetItemsInput, output *dynamodb.TransactGetItemsOutput, opt RequestOptions) (*dynamodb.TransactGetItemsOutput, error) { - var err error +func (cc *ClusterDaxClient) TransactGetItemsWithOptions(ctx context.Context, input *dynamodb.TransactGetItemsInput, opt RequestOptions) (*dynamodb.TransactGetItemsOutput, error) { + var output *dynamodb.TransactGetItemsOutput action := func(client DaxAPI, o RequestOptions) error { - output, err = client.TransactGetItemsWithOptions(input, output, o) + var err error + output, err = client.TransactGetItemsWithOptions(ctx, input, o) return err } - if err = cc.retry(OpTransactGetItems, action, opt); err != nil { - return output, err + if err := cc.retry(ctx, OpTransactGetItems, action, opt); err != nil { + return nil, operationError(OpTransactGetItems, err) } return output, nil } -func (cc *ClusterDaxClient) GetItemWithOptions(input *dynamodb.GetItemInput, output *dynamodb.GetItemOutput, opt RequestOptions) (*dynamodb.GetItemOutput, error) { - var err error +func (cc *ClusterDaxClient) GetItemWithOptions(ctx context.Context, input *dynamodb.GetItemInput, opt RequestOptions) (*dynamodb.GetItemOutput, error) { + var output *dynamodb.GetItemOutput action := func(client DaxAPI, o RequestOptions) error { - output, err = client.GetItemWithOptions(input, output, o) + var err error + output, err = client.GetItemWithOptions(ctx, input, o) return err } - if err = cc.retry(OpGetItem, action, opt); err != nil { - return output, err + if err := cc.retry(ctx, OpGetItem, action, opt); err != nil { + return nil, operationError(OpGetItem, err) } return output, nil } -func (cc *ClusterDaxClient) QueryWithOptions(input *dynamodb.QueryInput, output *dynamodb.QueryOutput, opt RequestOptions) (*dynamodb.QueryOutput, error) { - var err error +func (cc *ClusterDaxClient) QueryWithOptions(ctx context.Context, input *dynamodb.QueryInput, opt RequestOptions) (*dynamodb.QueryOutput, error) { + var output *dynamodb.QueryOutput action := func(client DaxAPI, o RequestOptions) error { - output, err = client.QueryWithOptions(input, output, o) + var err error + output, err = client.QueryWithOptions(ctx, input, o) return err } - if err = cc.retry(OpQuery, action, opt); err != nil { - return output, err + if err := cc.retry(ctx, OpQuery, action, opt); err != nil { + return nil, operationError(OpQuery, err) } return output, nil } -func (cc *ClusterDaxClient) ScanWithOptions(input *dynamodb.ScanInput, output *dynamodb.ScanOutput, opt RequestOptions) (*dynamodb.ScanOutput, error) { - var err error +func (cc *ClusterDaxClient) ScanWithOptions(ctx context.Context, input *dynamodb.ScanInput, opt RequestOptions) (*dynamodb.ScanOutput, error) { + var output *dynamodb.ScanOutput action := func(client DaxAPI, o RequestOptions) error { - output, err = client.ScanWithOptions(input, output, o) + var err error + output, err = client.ScanWithOptions(ctx, input, o) return err } - if err = cc.retry(OpScan, action, opt); err != nil { - return output, err + if err := cc.retry(ctx, OpScan, action, opt); err != nil { + return nil, operationError(OpScan, err) } return output, nil } -func (cc *ClusterDaxClient) BatchGetItemWithOptions(input *dynamodb.BatchGetItemInput, output *dynamodb.BatchGetItemOutput, opt RequestOptions) (*dynamodb.BatchGetItemOutput, error) { - var err error +func (cc *ClusterDaxClient) BatchGetItemWithOptions(ctx context.Context, input *dynamodb.BatchGetItemInput, opt RequestOptions) (*dynamodb.BatchGetItemOutput, error) { + var output *dynamodb.BatchGetItemOutput action := func(client DaxAPI, o RequestOptions) error { - output, err = client.BatchGetItemWithOptions(input, output, o) + var err error + output, err = client.BatchGetItemWithOptions(ctx, input, o) return err } - if err = cc.retry(OpBatchGetItem, action, opt); err != nil { - return output, err + if err := cc.retry(ctx, OpBatchGetItem, action, opt); err != nil { + return nil, operationError(OpBatchGetItem, err) } return output, nil } -func (cc *ClusterDaxClient) NewDaxRequest(op *request.Operation, input, output interface{}, opt RequestOptions) *request.Request { - req := request.New(aws.Config{}, clientInfo, *cc.handlers, nil, op, input, output) - opt.applyTo(req) - return req -} - -func (cc *ClusterDaxClient) buildHandlers() *request.Handlers { - h := &request.Handlers{} - h.Build.PushFrontNamed(request.NamedHandler{Name: "dax.BuildHandler", Fn: cc.build}) - h.Send.PushFrontNamed(request.NamedHandler{Name: "dax.SendHandler", Fn: cc.send}) - return h -} - -func (cc *ClusterDaxClient) build(req *request.Request) { - // Do not involve IO. Safe to retry on same client - c, err := cc.cluster.client(nil) - if err != nil { - req.Error = err - } else { - c.build(req) - } -} - -func (cc *ClusterDaxClient) send(req *request.Request) { - opt := RequestOptions{} - if err := opt.mergeFromRequest(req, true); err != nil { - req.Error = err - return - } - action := func(client DaxAPI, o RequestOptions) error { - o.applyTo(req) - client.send(req) - return req.Error - } - if err := cc.retry(req.Operation.Name, action, opt); err != nil { - req.Error = err - } -} - -func (cc *ClusterDaxClient) retry(op string, action func(client DaxAPI, o RequestOptions) error, opt RequestOptions) (err error) { +func (cc *ClusterDaxClient) retry(ctx context.Context, op string, action func(client DaxAPI, o RequestOptions) error, opt RequestOptions) (err error) { defer func() { if daxErr, ok := err.(daxError); ok { err = convertDaxError(daxErr) } }() - ctx := cc.newContext(opt) - - var sleepFun func() error - if opt.RetryDelay > 0 { - retryDelay := opt.RetryDelay - if opt.SleepDelayFn == nil { - sleepFun = func() error { - return aws.SleepWithContext(ctx, retryDelay) - } - } else { - sleepFun = func() error { - opt.SleepDelayFn(retryDelay) - return nil - } - } - } - - attempts := opt.MaxRetries - opt.MaxRetries = 0 // disable retries on single node client + attempts := opt.RetryMaxAttempts + opt.RetryMaxAttempts = 0 // disable retries on single node client - var req request.Request - var ok bool var client DaxAPI // Start from 0 to accomodate for the initial request for i := 0; i <= attempts; i++ { - if i > 0 && opt.Logger != nil && opt.LogLevel.Matches(aws.LogDebugWithRequestRetries) { - opt.Logger.Log(fmt.Sprintf("DEBUG: Retrying Request %s/%s, attempt %d", service, op, i)) + if i > 0 && opt.Logger != nil { + opt.Logger.Logf(ClassificationDebug, "Retrying Request %s/%s, attempt %d", service, op, i) } - client, err = cc.cluster.client(client) + client, err = cc.cluster.client(client, op) if err != nil { - if req, ok = cc.shouldRetry(opt, err); !ok { + if !isRetryable(opt, i+1, err) { return err } + continue } + err = action(client, opt) if err == nil { - if err = action(client, opt); err == nil { - return nil - } else if req, ok = cc.shouldRetry(opt, err); !ok { - return err - } + // success + return nil + } + if !isRetryable(opt, i+1, err) { + return err } - if i != attempts { - req.RetryCount = i + 1 - delay := opt.Retryer.RetryRules(&req) - if delay != 0 { - if opt.SleepDelayFn == nil { - aws.SleepWithContext(ctx, delay) - } else { - opt.SleepDelayFn(delay) - } - } else if sleepFun != nil { - if err := sleepFun(); err != nil { - return awserr.New(request.CanceledErrorCode, "request context canceled", err) - } - } + d, err := opt.Retryer.RetryDelay(i+1, err) + if err != nil { + return &smithy.OperationError{Err: err, OperationName: op} + } + if err = Sleep(ctx, op, d); err != nil { + return err + } - if err != nil && opt.Logger != nil && opt.LogLevel.Matches(aws.LogDebugWithRequestRetries) { - opt.Logger.Log(fmt.Sprintf("DEBUG: Error in executing request %s/%s. : %s", service, op, err)) - } + if opt.Logger != nil { + opt.Logger.Logf(ClassificationDebug, "Error in executing request %s/%s. : %s", service, op, err) } } return err } -func (cc *ClusterDaxClient) newContext(o RequestOptions) aws.Context { - if o.Context != nil { - return o.Context - } - return aws.BackgroundContext() -} - -func (cc *ClusterDaxClient) shouldRetry(o RequestOptions, err error) (request.Request, bool) { - req := request.Request{} - req.Error = err - if _, ok := err.(daxError); ok { - retry := o.Retryer.ShouldRetry(&req) - return req, retry - } - return req, true -} - type cluster struct { lock sync.RWMutex active map[hostPort]clientAndConfig // protected by lock @@ -439,10 +389,19 @@ type clientAndConfig struct { } func newCluster(cfg Config) (*cluster, error) { - if err := cfg.validate(); err != nil { + const op = "NewClient" + if err := cfg.validate(op); err != nil { return nil, err } - seeds, hostname, isEncrypted, err := getHostPorts(cfg.HostPorts) + hostPorts := cfg.HostPorts + if cfg.EndpointResolver != nil { + endpoint, err := cfg.EndpointResolver.ResolveEndpoint(serviceName, cfg.Region) + if err != nil { + return nil, err + } + hostPorts = append(hostPorts, endpoint.URL) + } + seeds, hostname, isEncrypted, err := getHostPorts(hostPorts, op) if err != nil { return nil, err } @@ -453,7 +412,7 @@ func newCluster(cfg Config) (*cluster, error) { return &cluster{seeds: seeds, config: cfg, executor: newExecutor(), clientBuilder: &singleClientBuilder{}}, nil } -func getHostPorts(hosts []string) (hostPorts []hostPort, hostname string, isEncrypted bool, err error) { +func getHostPorts(hosts []string, op string) (hostPorts []hostPort, hostname string, isEncrypted bool, err error) { out := make([]hostPort, len(hosts)) handle := func(e error) (hostPorts []hostPort, hostname string, isEncrypted bool, err error) { @@ -461,20 +420,28 @@ func getHostPorts(hosts []string) (hostPorts []hostPort, hostname string, isEncr } for i, hp := range hosts { - host, port, scheme, err := parseHostPort(hp) + host, port, scheme, err := parseHostPort(hp, op) if err != nil { return handle(err) } - if isEncrypted != (scheme == "daxs") { + if isEncrypted != (scheme == schemeDaxs) { if i == 0 { isEncrypted = true } else { - return handle(awserr.New(request.ErrCodeRequestError, "Inconsistency between the schemes of provided endpoints.", nil)) + return handle(&smithy.OperationError{ + ServiceID: service, + OperationName: op, + Err: errors.New("inconsistency between the schemes of provided endpoints"), + }) } } - if scheme == "daxs" && i > 0 { - return handle(awserr.New(request.InvalidParameterErrCode, "Only one cluster discovery endpoint may be provided for encrypted cluster", nil)) + if scheme == schemeDaxs && i > 0 { + return handle(&smithy.OperationError{ + ServiceID: service, + OperationName: op, + Err: errors.New("only one cluster discovery endpoint may be provided for encrypted cluster"), + }) } out[i] = hostPort{host, port} hostname = host @@ -482,7 +449,7 @@ func getHostPorts(hosts []string) (hostPorts []hostPort, hostname string, isEncr return out, hostname, isEncrypted, nil } -func parseHostPort(hostPort string) (host string, port int, scheme string, err error) { +func parseHostPort(hostPort string, op string) (host string, port int, scheme string, err error) { uriString := hostPort colon := strings.Index(hostPort, "://") @@ -492,7 +459,11 @@ func parseHostPort(hostPort string) (host string, port int, scheme string, err e if colon == -1 { if strings.Index(hostPort, ":") == -1 { - return handle(awserr.New(request.ErrCodeRequestError, "Invalid hostport", nil)) + return handle(&smithy.OperationError{ + ServiceID: service, + OperationName: op, + Err: errors.New(hostPort + "is invalid host port."), + }) } uriString = "dax://" + hostPort } @@ -505,7 +476,11 @@ func parseHostPort(hostPort string) (host string, port int, scheme string, err e scheme = u.Scheme portStr := u.Port() if host == "" { - return handle(awserr.New(request.ErrCodeRequestError, "Invalid hostport", nil)) + return handle(&smithy.OperationError{ + ServiceID: service, + OperationName: op, + Err: errors.New("invalid host port"), + }) } port, err = strconv.Atoi(portStr) @@ -515,19 +490,23 @@ func parseHostPort(hostPort string) (host string, port int, scheme string, err e if _, ok := defaultPorts[scheme]; !ok { schemes := strings.Join(strings.Fields(fmt.Sprint(reflect.ValueOf(defaultPorts).MapKeys())), ",") - return handle(awserr.New(request.ErrCodeRequestError, "URL scheme must be one of "+schemes, nil)) + return handle(&smithy.OperationError{ + ServiceID: service, + OperationName: op, + Err: errors.New("URL scheme must be one of " + schemes), + }) } return host, port, scheme, nil } -func (c *cluster) start() error { +func (c *cluster) start(ctx context.Context) error { c.executor.start(c.config.ClusterUpdateInterval, func() error { - c.safeRefresh(false) + c.safeRefresh(ctx, false) return nil }) c.executor.start(c.config.IdleConnectionReapDelay, c.reapIdleConnections) - c.safeRefresh(false) + c.safeRefresh(ctx, false) return nil } @@ -558,13 +537,17 @@ func (c *cluster) reapIdleConnections() error { return nil } -func (c *cluster) client(prev DaxAPI) (DaxAPI, error) { +func (c *cluster) client(prev DaxAPI, op string) (DaxAPI, error) { c.lock.RLock() defer c.lock.RUnlock() n := len(c.routes) if n == 0 { - return nil, awserr.New(ErrCodeServiceUnavailable, "No routes found", c.lastRefreshError()) + return nil, &smithy.OperationError{ + ServiceID: service, + OperationName: op, + Err: fmt.Errorf("no routes found. lastRefreshError: %v", c.lastRefreshError()), + } } if n == 1 { return c.routes[0], nil @@ -579,8 +562,8 @@ func (c *cluster) client(prev DaxAPI) (DaxAPI, error) { return c.routes[r], nil } -func (c *cluster) safeRefresh(force bool) { - err := c.refresh(force) +func (c *cluster) safeRefresh(ctx context.Context, force bool) { + err := c.refresh(ctx, force) c.lock.Lock() defer c.lock.Unlock() c.lastRefreshErr = err @@ -592,32 +575,33 @@ func (c *cluster) lastRefreshError() error { return c.lastRefreshErr } -func (c *cluster) refresh(force bool) error { +func (c *cluster) refresh(ctx context.Context, force bool) error { last := atomic.LoadInt64(&c.lastUpdateNs) now := time.Now().UnixNano() if now-last > c.config.ClusterUpdateThreshold.Nanoseconds() || force { if atomic.CompareAndSwapInt64(&c.lastUpdateNs, last, now) { - return c.refreshNow() + return c.refreshNow(ctx) } } return nil } -func (c *cluster) refreshNow() error { - cfg, err := c.pullEndpoints() +func (c *cluster) refreshNow(ctx context.Context) error { + cfg, err := c.pullEndpoints(ctx) if err != nil { - c.debugLog(fmt.Sprintf("ERROR: Failed to refresh endpoint : %s", err)) + c.debugLog("ERROR: Failed to refresh endpoint : %s", err) return err } if !c.hasChanged(cfg) { return nil } - return c.update(cfg) + c.update(ctx, cfg) + return nil } // This method is responsible for updating the set of active routes tracked by // the clsuter-dax-client in response to updates in the roster. -func (c *cluster) update(config []serviceEndpoint) error { +func (c *cluster) update(ctx context.Context, config []serviceEndpoint) { newEndpoints := make(map[hostPort]struct{}, len(config)) for _, cfg := range config { newEndpoints[cfg.hostPort()] = struct{}{} @@ -642,7 +626,7 @@ func (c *cluster) update(config []serviceEndpoint) error { for ep, clicfg := range oldActive { _, isPartOfUpdatedEndpointsConfig := newEndpoints[ep] if !isPartOfUpdatedEndpointsConfig { - c.debugLog(fmt.Sprintf("Found updated endpoint configs, will close inactive endpoint client : %s", ep.host)) + c.debugLog("Found updated endpoint configs, will close inactive endpoint client : %s", ep.host) toClose = append(toClose, clicfg) } } @@ -660,8 +644,8 @@ func (c *cluster) update(config []serviceEndpoint) error { newCliCfg = append(newCliCfg, cliAndCfg) } - if singleCli, ok := cli.(HealthCheckDaxAPI); ok { - singleCli.startHealthChecks(c, ep.hostPort()) + if sc, ok := cli.(HealthCheckDaxAPI); ok { + sc.startHealthChecks(ctx, c, ep.hostPort()) } } newActive[ep.hostPort()] = cliAndCfg @@ -680,24 +664,21 @@ func (c *cluster) update(config []serviceEndpoint) error { go func() { for _, client := range toClose { - c.debugLog(fmt.Sprintf("Closing client for : %s", client.cfg.hostname)) + c.debugLog("Closing client for : %s", client.cfg.hostname) c.closeClient(client.client) } }() - return nil } -func (c *cluster) onHealthCheckFailed(host hostPort) { +func (c *cluster) onHealthCheckFailed(ctx context.Context, host hostPort) { c.lock.Lock() c.debugLog("DEBUG: Refreshing cache for host: " + host.host) shouldCloseOldClient := true var oldClientConfig, ok = c.active[host] if ok { - var err error - var cli DaxAPI - cli, err = c.newSingleClient(oldClientConfig.cfg) - if singleCli, ok := cli.(HealthCheckDaxAPI); ok { - singleCli.startHealthChecks(c, host) + cli, err := c.newSingleClient(oldClientConfig.cfg) + if sc, ok := cli.(HealthCheckDaxAPI); ok { + sc.startHealthChecks(ctx, c, host) } if err == nil { @@ -712,15 +693,15 @@ func (c *cluster) onHealthCheckFailed(host hostPort) { c.routes = newRoutes } else { shouldCloseOldClient = false - c.debugLog(fmt.Sprintf("DEBUG: Failed to refresh cache for host: " + host.host)) + c.debugLog("DEBUG: Failed to refresh cache for host: " + host.host) } } else { - c.debugLog(fmt.Sprintf("DEBUG: The node is not part of active routes. Ignoring the health check failure for host: " + host.host)) + c.debugLog("DEBUG: The node is not part of active routes. Ignoring the health check failure for host: " + host.host) } c.lock.Unlock() if shouldCloseOldClient { - c.debugLog(fmt.Sprintf("DEBUG: Closing old instance of a replaced client for endpoint: %s", oldClientConfig.cfg.hostPort().host)) + c.debugLog("DEBUG: Closing old instance of a replaced client for endpoint: %s", oldClientConfig.cfg.hostPort().host) c.closeClient(oldClientConfig.client) } } @@ -737,7 +718,7 @@ func (c *cluster) hasChanged(cfg []serviceEndpoint) bool { return len(cfg) != len(c.active) } -func (c *cluster) pullEndpoints() ([]serviceEndpoint, error) { +func (c *cluster) pullEndpoints(ctx context.Context) ([]serviceEndpoint, error) { var lastErr error // TODO chain errors? for _, s := range c.seeds { ips, err := net.LookupIP(s.host) @@ -755,12 +736,12 @@ func (c *cluster) pullEndpoints() ([]serviceEndpoint, error) { } for _, ip := range ips { - endpoints, err := c.pullEndpointsFrom(ip, s.port) + endpoints, err := c.pullEndpointsFrom(ctx, ip, s.port) if err != nil { lastErr = err continue } - c.debugLog(fmt.Sprintf("DEBUG: Pulled endpoints from %s : %v", ip, endpoints)) + c.debugLog("DEBUG: Pulled endpoints from %s : %v", ip, endpoints) if len(endpoints) > 0 { return endpoints, nil } @@ -769,15 +750,17 @@ func (c *cluster) pullEndpoints() ([]serviceEndpoint, error) { return nil, lastErr } -func (c *cluster) pullEndpointsFrom(ip net.IP, port int) ([]serviceEndpoint, error) { +func (c *cluster) pullEndpointsFrom(ctx context.Context, ip net.IP, port int) ([]serviceEndpoint, error) { client, err := c.clientBuilder.newClient(ip, port, c.config.connConfig, c.config.Region, c.config.Credentials, c.config.MaxPendingConnectionsPerHost, c.config.DialContext) if err != nil { return nil, err } defer c.closeClient(client) - ctx, cfn := context.WithTimeout(aws.BackgroundContext(), 5*time.Second) + ctx, cfn := context.WithTimeout(ctx, 5*time.Second) defer cfn() - return client.endpoints(RequestOptions{MaxRetries: 2, Context: ctx}) + opts := RequestOptions{} + opts.RetryMaxAttempts = 2 + return client.endpoints(ctx, opts) } func (c *cluster) closeClient(client DaxAPI) { @@ -786,10 +769,10 @@ func (c *cluster) closeClient(client DaxAPI) { } } -func (c *cluster) debugLog(args ...interface{}) { - if c.config.logger != nil && c.config.logLevel.AtLeast(aws.LogDebug) { +func (c *cluster) debugLog(format string, args ...interface{}) { + if c.config.logger != nil { { - c.config.logger.Log(args) + c.config.logger.Logf(ClassificationDebug, format, args) } } } @@ -799,12 +782,14 @@ func (c *cluster) newSingleClient(cfg serviceEndpoint) (DaxAPI, error) { } type clientBuilder interface { - newClient(net.IP, int, connConfig, string, *credentials.Credentials, int, dialContext) (DaxAPI, error) + newClient(net.IP, int, connConfig, string, aws.CredentialsProvider, int, dialContext) (DaxAPI, error) } type singleClientBuilder struct{} -func (*singleClientBuilder) newClient(ip net.IP, port int, connConfigData connConfig, region string, credentials *credentials.Credentials, maxPendingConnects int, dialContextFn dialContext) (DaxAPI, error) { +var _ clientBuilder = (*singleClientBuilder)(nil) + +func (*singleClientBuilder) newClient(ip net.IP, port int, connConfigData connConfig, region string, credentials aws.CredentialsProvider, maxPendingConnects int, dialContextFn dialContext) (DaxAPI, error) { endpoint := fmt.Sprintf("%s:%d", ip, port) return newSingleClientWithOptions(endpoint, connConfigData, region, credentials, maxPendingConnects, dialContextFn) } diff --git a/dax/internal/client/cluster_test.go b/dax/internal/client/cluster_test.go index a5e0aba..53aa617 100644 --- a/dax/internal/client/cluster_test.go +++ b/dax/internal/client/cluster_test.go @@ -26,15 +26,41 @@ import ( "testing" "time" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/aws/credentials" - "github.com/aws/aws-sdk-go/aws/request" - "github.com/aws/aws-sdk-go/service/dynamodb" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/dynamodb" + "github.com/aws/aws-sdk-go-v2/service/dynamodb/types" + "github.com/aws/smithy-go" + "github.com/aws/smithy-go/logging" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) +type testRetryer struct { + Attemps int + Duration time.Duration + CalledCount int +} + +var _ aws.Retryer = (*testRetryer)(nil) + +func (r *testRetryer) IsErrorRetryable(_ error) bool { + return true +} +func (r *testRetryer) MaxAttempts() int { + return r.Attemps +} + +func (r *testRetryer) RetryDelay(_ int, _ error) (time.Duration, error) { + r.CalledCount++ + return r.Duration, nil +} +func (r *testRetryer) GetRetryToken(ctx context.Context, opErr error) (releaseToken func(error) error, err error) { + return releaseToken, nil +} +func (r *testRetryer) GetInitialToken() (releaseToken func(error) error) { + return releaseToken +} + func testTaskExecutor(t *testing.T) { // disabled as test is time sensitive executor := newExecutor() @@ -82,15 +108,15 @@ func testTaskExecutor(t *testing.T) { // disabled as test is time sensitive func TestClusterDaxClient_retry(t *testing.T) { cluster, _ := newTestCluster([]string{"127.0.0.1:8111"}) - cluster.update([]serviceEndpoint{{hostname: "localhost", port: 8121}}) + cluster.update(context.Background(), []serviceEndpoint{{hostname: "localhost", port: 8121}}) cc := ClusterDaxClient{config: DefaultConfig(), cluster: cluster} retries := 3 for successfulAttempt := 1; successfulAttempt < retries+5; successfulAttempt++ { calls := 0 action := func(client DaxAPI, o RequestOptions) error { - if o.MaxRetries != 0 { - t.Errorf("expected 0 retries, found %v", o.MaxRetries) + if o.RetryMaxAttempts != 0 { + t.Errorf("expected 0 retries, found %v", o.RetryMaxAttempts) } calls++ if calls == successfulAttempt { @@ -99,8 +125,11 @@ func TestClusterDaxClient_retry(t *testing.T) { return errors.New("error") } - opt := RequestOptions{MaxRetries: retries} - err := cc.retry("op ", action, opt) + opt := RequestOptions{} + opt.RetryMaxAttempts = retries + opt.Retryer = &testRetryer{Attemps: retries} + + err := cc.retry(context.Background(), "op ", action, opt) maxAttempts := retries + 1 if successfulAttempt <= maxAttempts { if calls != successfulAttempt { @@ -122,39 +151,38 @@ func TestClusterDaxClient_retry(t *testing.T) { func TestClusterDaxClient_retrySleepCycleCount(t *testing.T) { cluster, _ := newTestCluster([]string{"127.0.0.1:8111"}) - cluster.update([]serviceEndpoint{{hostname: "localhost", port: 8121}}) + cluster.update(context.Background(), []serviceEndpoint{{hostname: "localhost", port: 8121}}) cc := ClusterDaxClient{config: DefaultConfig(), cluster: cluster} action := func(client DaxAPI, o RequestOptions) error { return errors.New("error") } - var sleepCallCount int - opt := RequestOptions{ - MaxRetries: 0, - RetryDelay: 0, - SleepDelayFn: func(d time.Duration) { sleepCallCount++ }, + tr := &testRetryer{ + Duration: time.Millisecond * 100, } + opt := RequestOptions{} + opt.Retryer = tr - cc.retry("op", action, opt) + cc.retry(context.Background(), "op", action, opt) - if sleepCallCount != 0 { - t.Fatalf("Sleep was called %d times, but expected none", sleepCallCount) + if tr.CalledCount != 0 { + t.Fatalf("Sleep was called %d times, but expected none", tr.CalledCount) } - opt.MaxRetries = 3 - opt.RetryDelay = 1 + opt.RetryMaxAttempts = 3 + tr.Attemps = opt.RetryMaxAttempts - cc.retry("op", action, opt) + cc.retry(context.Background(), "op", action, opt) - if sleepCallCount != opt.MaxRetries { - t.Fatalf("Sleep was called %d times, but expected %d", sleepCallCount, opt.MaxRetries) + if tr.CalledCount != opt.RetryMaxAttempts { + t.Fatalf("Sleep was called %d times, but expected %d", tr.CalledCount, opt.RetryMaxAttempts) } } func TestClusterDaxClient_retryReturnsLastError(t *testing.T) { cluster, _ := newTestCluster([]string{"127.0.0.1:8111"}) - cluster.update([]serviceEndpoint{{hostname: "localhost", port: 8121}}) + cluster.update(context.Background(), []serviceEndpoint{{hostname: "localhost", port: 8121}}) cc := ClusterDaxClient{config: DefaultConfig(), cluster: cluster} callCount := 0 @@ -163,12 +191,10 @@ func TestClusterDaxClient_retryReturnsLastError(t *testing.T) { return fmt.Errorf("Error_%d", callCount) } - opt := RequestOptions{ - MaxRetries: 2, - RetryDelay: 1, - } + opt := RequestOptions{} + opt.RetryMaxAttempts = 2 - err := cc.retry("op", action, opt) + err := cc.retry(context.Background(), "op", action, opt) expectedError := fmt.Errorf("Error_%d", callCount) if err.Error() != expectedError.Error() { t.Fatalf("Wrong error. Expected %v, but got %v", expectedError, err) @@ -177,7 +203,7 @@ func TestClusterDaxClient_retryReturnsLastError(t *testing.T) { func TestClusterDaxClient_retryReturnsCorrectErrorType(t *testing.T) { cluster, _ := newTestCluster([]string{"127.0.0.1:8111"}) - cluster.update([]serviceEndpoint{{hostname: "localhost", port: 8121}}) + cluster.update(context.Background(), []serviceEndpoint{{hostname: "localhost", port: 8121}}) cc := ClusterDaxClient{config: DefaultConfig(), cluster: cluster} message := "Message" @@ -195,120 +221,115 @@ func TestClusterDaxClient_retryReturnsCorrectErrorType(t *testing.T) { }{ { codes: []int{4, 23, 24}, - errCode: dynamodb.ErrCodeResourceNotFoundException, - class: reflect.TypeOf(&dynamodb.ResourceNotFoundException{}), + errCode: (&types.ResourceNotFoundException{}).ErrorCode(), + class: reflect.TypeOf(&types.ResourceNotFoundException{}), }, { codes: []int{4, 23, 35}, - errCode: dynamodb.ErrCodeResourceInUseException, - class: reflect.TypeOf(&dynamodb.ResourceInUseException{}), + errCode: (&types.ResourceInUseException{}).ErrorCode(), + class: reflect.TypeOf(&types.ResourceInUseException{}), }, { codes: []int{4, 37, 38, 39, 40}, - errCode: dynamodb.ErrCodeProvisionedThroughputExceededException, - class: reflect.TypeOf(&dynamodb.ProvisionedThroughputExceededException{}), + errCode: (&types.ProvisionedThroughputExceededException{}).ErrorCode(), + class: reflect.TypeOf(&types.ProvisionedThroughputExceededException{}), }, { codes: []int{4, 37, 38, 39, 40}, - errCode: dynamodb.ErrCodeProvisionedThroughputExceededException, - class: reflect.TypeOf(&dynamodb.ProvisionedThroughputExceededException{}), + errCode: (&types.ProvisionedThroughputExceededException{}).ErrorCode(), + class: reflect.TypeOf(&types.ProvisionedThroughputExceededException{}), }, { codes: []int{4, 37, 38, 39, 41}, - errCode: dynamodb.ErrCodeResourceNotFoundException, - class: reflect.TypeOf(&dynamodb.ResourceNotFoundException{}), + errCode: (&types.ResourceNotFoundException{}).ErrorCode(), + class: reflect.TypeOf(&types.ResourceNotFoundException{}), }, { codes: []int{4, 37, 38, 39, 43}, - errCode: dynamodb.ErrCodeConditionalCheckFailedException, - class: reflect.TypeOf(&dynamodb.ConditionalCheckFailedException{}), + errCode: (&types.ConditionalCheckFailedException{}).ErrorCode(), + class: reflect.TypeOf(&types.ConditionalCheckFailedException{}), }, { codes: []int{4, 37, 38, 39, 45}, - errCode: dynamodb.ErrCodeResourceInUseException, - class: reflect.TypeOf(&dynamodb.ResourceInUseException{}), + errCode: (&types.ResourceInUseException{}).ErrorCode(), + class: reflect.TypeOf(&types.ResourceInUseException{}), }, { codes: []int{4, 37, 38, 39, 46}, errCode: ErrCodeValidationException, - class: reflect.TypeOf(awserr.NewRequestFailure(nil, 0, "")), + class: reflect.TypeOf(&smithy.GenericAPIError{}), }, { codes: []int{4, 37, 38, 39, 47}, - errCode: dynamodb.ErrCodeInternalServerError, - class: reflect.TypeOf(&dynamodb.InternalServerError{}), + errCode: (&types.InternalServerError{}).ErrorCode(), + class: reflect.TypeOf(&types.InternalServerError{}), }, { codes: []int{4, 37, 38, 39, 48}, - errCode: dynamodb.ErrCodeItemCollectionSizeLimitExceededException, - class: reflect.TypeOf(&dynamodb.ItemCollectionSizeLimitExceededException{}), + errCode: (&types.ItemCollectionSizeLimitExceededException{}).ErrorCode(), + class: reflect.TypeOf(&types.ItemCollectionSizeLimitExceededException{}), }, { codes: []int{4, 37, 38, 39, 49}, - errCode: dynamodb.ErrCodeLimitExceededException, - class: reflect.TypeOf(&dynamodb.LimitExceededException{}), + errCode: (&types.LimitExceededException{}).ErrorCode(), + class: reflect.TypeOf(&types.LimitExceededException{}), }, { codes: []int{4, 37, 38, 39, 50}, errCode: ErrCodeThrottlingException, - class: reflect.TypeOf(awserr.NewRequestFailure(nil, 0, "")), + class: reflect.TypeOf(&smithy.GenericAPIError{}), }, { codes: []int{4, 37, 38, 39, 57}, - errCode: dynamodb.ErrCodeTransactionConflictException, - class: reflect.TypeOf(&dynamodb.TransactionConflictException{}), + errCode: (&types.TransactionConflictException{}).ErrorCode(), + class: reflect.TypeOf(&types.TransactionConflictException{}), }, { codes: []int{4, 37, 38, 39, 58}, - errCode: dynamodb.ErrCodeTransactionCanceledException, - class: reflect.TypeOf(&dynamodb.TransactionCanceledException{}), + errCode: (&types.TransactionCanceledException{}).ErrorCode(), + class: reflect.TypeOf(&types.TransactionCanceledException{}), }, { codes: []int{4, 37, 38, 39, 59}, - errCode: dynamodb.ErrCodeTransactionInProgressException, - class: reflect.TypeOf(&dynamodb.TransactionInProgressException{}), + errCode: (&types.TransactionInProgressException{}).ErrorCode(), + class: reflect.TypeOf(&types.TransactionInProgressException{}), }, { codes: []int{4, 37, 38, 39, 60}, - errCode: dynamodb.ErrCodeIdempotentParameterMismatchException, - class: reflect.TypeOf(&dynamodb.IdempotentParameterMismatchException{}), + errCode: (&types.IdempotentParameterMismatchException{}).ErrorCode(), + class: reflect.TypeOf(&types.IdempotentParameterMismatchException{}), }, { codes: []int{4, 37, 38, 44}, errCode: ErrCodeNotImplemented, - class: reflect.TypeOf(awserr.NewRequestFailure(nil, 0, "")), + class: reflect.TypeOf(&smithy.GenericAPIError{}), }, } for _, c := range cases { action := func(client DaxAPI, o RequestOptions) error { - if c.errCode == dynamodb.ErrCodeTransactionCanceledException { + if c.errCode == (&types.TransactionCanceledException{}).ErrorCode() { return newDaxTransactionCanceledFailure(c.codes, defaultErrCode, message, requestID, statusCode, nil, nil, nil) } return newDaxRequestFailure(c.codes, defaultErrCode, message, requestID, statusCode) } - opt := RequestOptions{ - MaxRetries: 0, - } + opt := RequestOptions{} - err := cc.retry("op", action, opt) + err := cc.retry(context.Background(), "op", action, opt) actualClass := reflect.TypeOf(err) if actualClass != c.class { t.Errorf("conversion of code sequence %v failed: expected %s, but got %s", c.codes, c.class.String(), actualClass.String()) } - f, _ := err.(awserr.RequestFailure) - require.NotNilf(t, f, "conversion of code sequence %v failed: expected implement awserr.Error", c.codes) - require.Equal(t, c.errCode, f.Code()) - require.Equal(t, statusCode, f.StatusCode()) - require.Equal(t, requestID, f.RequestID()) - require.Equal(t, message, f.Message()) + f, _ := err.(smithy.APIError) + require.NotNilf(t, f, "conversion of code sequence %v failed: expected implement smithy.APIError", c.codes) + assert.Equal(t, c.errCode, f.ErrorCode()) } } func TestCluster_parseHostPorts(t *testing.T) { endpoints := []string{"dax.us-east-1.amazonaws.com:8111"} - hostPorts, _, _, err := getHostPorts(endpoints) + hostPorts, _, _, err := getHostPorts(endpoints, "op") if err != nil { t.Errorf("unexpected error %v", err) } @@ -327,7 +348,7 @@ func TestCluster_pullFromNextSeed(t *testing.T) { cluster, clientBuilder := newTestCluster([]string{"non-existent-host:8888", "127.0.0.1:8111"}) setExpectation(cluster, []serviceEndpoint{{hostname: "localhost", port: 8121}}) - if err := cluster.refresh(false); err != nil { + if err := cluster.refresh(context.Background(), false); err != nil { t.Errorf("unexpected error %v", err) } if len(clientBuilder.clients) != 2 { @@ -346,12 +367,12 @@ func TestCluster_refreshEmpty(t *testing.T) { cluster, clientBuilder := newTestCluster([]string{"127.0.0.1:8111"}) setExpectation(cluster, []serviceEndpoint{}) - if err := cluster.refresh(false); err != nil { + if err := cluster.refresh(context.Background(), false); err != nil { t.Errorf("unexpected error %v", err) } assertNumRoutes(cluster, 0, t) - if _, err := cluster.client(nil); err == nil { + if _, err := cluster.client(nil, "op"); err == nil { t.Errorf("expected err, got nil") } if len(clientBuilder.clients) != 1 { @@ -368,7 +389,9 @@ func TestCluster_refreshThreshold(t *testing.T) { cluster, clientBuilder := newTestClusterWithConfig(cfg) for i := 0; i < 10; i++ { - cluster.refresh(false) + if err := cluster.refresh(context.Background(), false); err != nil { + t.Fatalf("unexpected error: %v", err) + } } if 1 != len(clientBuilder.clients) { t.Errorf("expected 1, got %d", len(clientBuilder.clients)) @@ -377,7 +400,9 @@ func TestCluster_refreshThreshold(t *testing.T) { <-time.After(cfg.ClusterUpdateThreshold) for i := 0; i < 10; i++ { - cluster.refresh(false) + if err := cluster.refresh(context.Background(), false); err != nil { + t.Fatalf("unexpected error: %v", err) + } } if 2 != len(clientBuilder.clients) { t.Errorf("expected 2, got %d", len(clientBuilder.clients)) @@ -389,11 +414,11 @@ func TestCluster_refreshDup(t *testing.T) { cluster, clientBuilder := newTestCluster([]string{"127.0.0.1:8111"}) setExpectation(cluster, []serviceEndpoint{{hostname: "localhost", port: 8121}}) - if err := cluster.refreshNow(); err != nil { + if err := cluster.refreshNow(context.Background()); err != nil { t.Errorf("unpexected error %v", err) } assertNumRoutes(cluster, 1, t) - if _, err := cluster.client(nil); err != nil { + if _, err := cluster.client(nil, "op"); err != nil { t.Errorf("unexpected error %v", err) } if len(clientBuilder.clients) != 2 { @@ -404,11 +429,11 @@ func TestCluster_refreshDup(t *testing.T) { oldActive := cluster.active oldRoutes := cluster.routes - if err := cluster.refreshNow(); err != nil { + if err := cluster.refreshNow(context.Background()); err != nil { t.Errorf("unpexected error %v", err) } assertNumRoutes(cluster, 1, t) - if _, err := cluster.client(nil); err != nil { + if _, err := cluster.client(nil, "op"); err != nil { t.Errorf("unexpected error %v", err) } if fmt.Sprintf("%p", cluster.active) != fmt.Sprintf("%p", oldActive) { @@ -427,11 +452,11 @@ func TestCluster_refreshUpdate(t *testing.T) { cluster, clientBuilder := newTestCluster([]string{"127.0.0.1:8111"}) setExpectation(cluster, []serviceEndpoint{{hostname: "localhost", port: 8121}}) - if err := cluster.refreshNow(); err != nil { + if err := cluster.refreshNow(context.Background()); err != nil { t.Errorf("unpexected error %v", err) } assertNumRoutes(cluster, 1, t) - if _, err := cluster.client(nil); err != nil { + if _, err := cluster.client(nil, "op"); err != nil { t.Errorf("unexpected error %v", err) } if len(clientBuilder.clients) != 2 { @@ -441,11 +466,11 @@ func TestCluster_refreshUpdate(t *testing.T) { assertActiveClient(clientBuilder.clients[1], t) setExpectation(cluster, []serviceEndpoint{{hostname: "localhost", port: 8121}, {hostname: "localhost", port: 8122}}) - if err := cluster.refreshNow(); err != nil { + if err := cluster.refreshNow(context.Background()); err != nil { t.Errorf("unpexected error %v", err) } assertNumRoutes(cluster, 2, t) - if _, err := cluster.client(nil); err != nil { + if _, err := cluster.client(nil, "op"); err != nil { t.Errorf("unexpected error %v", err) } @@ -463,9 +488,7 @@ func TestCluster_update(t *testing.T) { if !cluster.hasChanged(first) { t.Errorf("expected config change") } - if err := cluster.update(first); err != nil { - t.Errorf("unexpected error %v", err) - } + cluster.update(context.Background(), first) assertNumRoutes(cluster, 1, t) assertConnections(cluster, first, t) assertHealthCheckCalls(cluster, t) @@ -475,9 +498,7 @@ func TestCluster_update(t *testing.T) { if !cluster.hasChanged(second) { t.Errorf("expected config change") } - if err := cluster.update(second); err != nil { - t.Errorf("unexpected error %v", err) - } + cluster.update(context.Background(), second) assertNumRoutes(cluster, 3, t) assertConnections(cluster, second, t) assertHealthCheckCalls(cluster, t) @@ -487,9 +508,7 @@ func TestCluster_update(t *testing.T) { if !cluster.hasChanged(third) { t.Errorf("expected config change") } - if err := cluster.update(third); err != nil { - t.Errorf("unexpected error %v", err) - } + cluster.update(context.Background(), third) assertNumRoutes(cluster, 3, t) assertConnections(cluster, third, t) assertHealthCheckCalls(cluster, t) @@ -499,9 +518,7 @@ func TestCluster_update(t *testing.T) { if !cluster.hasChanged(fourth) { t.Errorf("expected config change") } - if err := cluster.update(fourth); err != nil { - t.Errorf("unexpected error %v", err) - } + cluster.update(context.Background(), fourth) assertNumRoutes(cluster, 2, t) assertConnections(cluster, fourth, t) assertHealthCheckCalls(cluster, t) @@ -511,9 +528,7 @@ func TestCluster_update(t *testing.T) { if cluster.hasChanged(fifth) { t.Errorf("unexpected config change") } - if err := cluster.update(fifth); err != nil { - t.Errorf("unexpected error %v", err) - } + cluster.update(context.Background(), fifth) assertNumRoutes(cluster, 2, t) assertConnections(cluster, fifth, t) assertHealthCheckCalls(cluster, t) @@ -523,7 +538,7 @@ func TestCluster_onHealthCheckFailed(t *testing.T) { cluster, clientBuilder := newTestCluster([]string{"127.0.0.1:8888"}) endpoint := serviceEndpoint{hostname: "localhost", port: 8123} first := []serviceEndpoint{endpoint, {hostname: "localhost", port: 8124}, {hostname: "localhost", port: 8125}} - cluster.update(first) + cluster.update(context.Background(), first) assertNumRoutes(cluster, 3, t) assertConnections(cluster, first, t) @@ -532,7 +547,7 @@ func TestCluster_onHealthCheckFailed(t *testing.T) { assert.Equal(t, 3, len(clientBuilder.clients)) assertCloseCalls(cluster, 0, t) - cluster.onHealthCheckFailed(endpoint.hostPort()) + cluster.onHealthCheckFailed(context.Background(), endpoint.hostPort()) assertNumRoutes(cluster, 3, t) assertConnections(cluster, first, t) assertHealthCheckCalls(cluster, t) @@ -541,7 +556,7 @@ func TestCluster_onHealthCheckFailed(t *testing.T) { assertCloseCalls(cluster, 1, t) // Another failure - cluster.onHealthCheckFailed(endpoint.hostPort()) + cluster.onHealthCheckFailed(context.Background(), endpoint.hostPort()) assertNumRoutes(cluster, 3, t) assertConnections(cluster, first, t) assertHealthCheckCalls(cluster, t) @@ -554,16 +569,14 @@ func TestCluster_client(t *testing.T) { cluster, _ := newTestCluster([]string{"127.0.0.1:8888"}) endpoints := []serviceEndpoint{{hostname: "localhost", port: 8121}, {hostname: "localhost", port: 8122}, {hostname: "localhost", port: 8123}} - if err := cluster.update(endpoints); err != nil { - t.Errorf("unexpected error %v", err) - } + cluster.update(context.Background(), endpoints) assertNumRoutes(cluster, 3, t) - prev, err := cluster.client(nil) + prev, err := cluster.client(nil, "op") if err != nil { t.Errorf("unexpected error %v", err) } for i := 0; i < 100; i++ { - next, err := cluster.client(prev) + next, err := cluster.client(prev, "op") if err != nil { t.Errorf("unexpected error %v", err) } @@ -578,11 +591,11 @@ func TestCluster_Close(t *testing.T) { cluster, clientBuilder := newTestCluster([]string{"127.0.0.1:8111"}) setExpectation(cluster, []serviceEndpoint{{hostname: "localhost", port: 8121}}) - if err := cluster.refreshNow(); err != nil { + if err := cluster.refreshNow(context.Background()); err != nil { t.Errorf("unpexected error %v", err) } assertNumRoutes(cluster, 1, t) - if _, err := cluster.client(nil); err != nil { + if _, err := cluster.client(nil, "op"); err != nil { t.Errorf("unexpected error %v", err) } if len(clientBuilder.clients) != 2 { @@ -599,7 +612,7 @@ func TestCluster_Close(t *testing.T) { func Test_CorrectHostPortUrlFormat(t *testing.T) { hostPort := "dax://test.nds.clustercfg.dax.usw2integ.cache.amazonaws.com:1234" - host, port, scheme, _ := parseHostPort(hostPort) + host, port, scheme, _ := parseHostPort(hostPort, "op") assertEqual(t, "test.nds.clustercfg.dax.usw2integ.cache.amazonaws.com", host, "") assertEqual(t, 1234, port, "") assertEqual(t, "dax", scheme, "") @@ -607,7 +620,7 @@ func Test_CorrectHostPortUrlFormat(t *testing.T) { func Test_MissingScheme(t *testing.T) { hostPort := "test.nds.clustercfg.dax.usw2integ.cache.amazonaws.com:8111" - host, port, scheme, _ := parseHostPort(hostPort) + host, port, scheme, _ := parseHostPort(hostPort, "op") assertEqual(t, "test.nds.clustercfg.dax.usw2integ.cache.amazonaws.com", host, "") assertEqual(t, 8111, port, "") assertEqual(t, "dax", scheme, "") @@ -615,7 +628,7 @@ func Test_MissingScheme(t *testing.T) { func Test_MissingPortForDax(t *testing.T) { hostPort := "dax://test.nds.clustercfg.dax.usw2integ.cache.amazonaws.com" - host, port, scheme, _ := parseHostPort(hostPort) + host, port, scheme, _ := parseHostPort(hostPort, "op") assertEqual(t, "test.nds.clustercfg.dax.usw2integ.cache.amazonaws.com", host, "") assertEqual(t, 8111, port, "") assertEqual(t, "dax", scheme, "") @@ -623,7 +636,7 @@ func Test_MissingPortForDax(t *testing.T) { func Test_MissingPortForDaxs(t *testing.T) { hostPort := "daxs://test.nds.clustercfg.dax.usw2integ.cache.amazonaws.com" - host, port, scheme, _ := parseHostPort(hostPort) + host, port, scheme, _ := parseHostPort(hostPort, "op") assertEqual(t, "test.nds.clustercfg.dax.usw2integ.cache.amazonaws.com", host, "") assertEqual(t, 9111, port, "") assertEqual(t, "daxs", scheme, "") @@ -631,13 +644,13 @@ func Test_MissingPortForDaxs(t *testing.T) { func Test_UnsupportedScheme(t *testing.T) { hostPort := "sample://test.nds.clustercfg.dax.usw2integ.cache.amazonaws.com" - _, _, _, err := parseHostPort(hostPort) - assertEqual(t, reflect.TypeOf(err), reflect.TypeOf(awserr.New(request.ErrCodeRequestError, "", nil)), "") + _, _, _, err := parseHostPort(hostPort, "op") + assertEqual(t, reflect.TypeOf(err), reflect.TypeOf(&smithy.OperationError{}), "") } func Test_DaxsCorrectUrlFormat(t *testing.T) { hostPort := "daxs://test.nds.clustercfg.dax.usw2integ.cache.amazonaws.com:1234" - host, port, scheme, _ := parseHostPort(hostPort) + host, port, scheme, _ := parseHostPort(hostPort, "op") assertEqual(t, "test.nds.clustercfg.dax.usw2integ.cache.amazonaws.com", host, "") assertEqual(t, 1234, port, "") assertEqual(t, "daxs", scheme, "") @@ -649,19 +662,19 @@ var encEp = "daxs://cluster2.random.alpha-dax-clusters.us-east-1.amazonaws.com" var encNodeEp = "daxs://cluster2-a.random.nodes.alpha-dax-clusters.us-east-1.amazonaws.com:9111" func Test_InconsistentScheme(t *testing.T) { - _, _, _, err := getHostPorts([]string{nonEncEp, encEp}) - assertEqual(t, reflect.TypeOf(err), reflect.TypeOf(awserr.New(request.ErrCodeRequestError, "", nil)), "") + _, _, _, err := getHostPorts([]string{nonEncEp, encEp}, "op") + assertEqual(t, reflect.TypeOf(err), reflect.TypeOf(&smithy.OperationError{}), "") } func Test_MultipleUnEncryptedEndpoints(t *testing.T) { - hps, _, _, _ := getHostPorts([]string{nonEncEp, nonEncNodeEp}) + hps, _, _, _ := getHostPorts([]string{nonEncEp, nonEncNodeEp}, "op") assert.Contains(t, hps, hostPort{"cluster.random.alpha-dax-clusters.us-east-1.amazonaws.com", 8111}) assert.Contains(t, hps, hostPort{"cluster-a.random.nodes.alpha-dax-clusters.us-east-1.amazonaws.com", 8111}) } func Test_MultipleEncryptedEndpoints(t *testing.T) { - _, _, _, err := getHostPorts([]string{encEp, encNodeEp}) - assertEqual(t, reflect.TypeOf(err), reflect.TypeOf(awserr.New(request.ErrCodeRequestError, "", nil)), "") + _, _, _, err := getHostPorts([]string{encEp, encNodeEp}, "op") + assertEqual(t, reflect.TypeOf(err), reflect.TypeOf(&smithy.OperationError{}), "") } func assertConnections(cluster *cluster, endpoints []serviceEndpoint, t *testing.T) { @@ -684,6 +697,7 @@ func assertConnections(cluster *cluster, endpoints []serviceEndpoint, t *testing } func assertNumRoutes(cluster *cluster, num int, t *testing.T) { + t.Helper() if len(cluster.active) != num { t.Errorf("expected %d, got %d", num, len(cluster.active)) } @@ -693,6 +707,7 @@ func assertNumRoutes(cluster *cluster, num int, t *testing.T) { } func assertHealthCheckCalls(cluster *cluster, t *testing.T) { + t.Helper() for _, cliAndCfg := range cluster.active { healtCheckCalls := cliAndCfg.client.(*testClient).healthCheckCalls if healtCheckCalls != 1 { @@ -702,6 +717,7 @@ func assertHealthCheckCalls(cluster *cluster, t *testing.T) { } func assertCloseCalls(cluster *cluster, num int, t *testing.T) { + t.Helper() cnt := 0 for _, client := range cluster.clientBuilder.(*testClientBuilder).clients { if client.closeCalls == 1 { @@ -712,6 +728,7 @@ func assertCloseCalls(cluster *cluster, num int, t *testing.T) { } func assertDiscoveryClient(client *testClient, t *testing.T) { + t.Helper() if client.endpointsCalls != 1 { t.Errorf("expected 1, got %d", client.endpointsCalls) } @@ -721,6 +738,7 @@ func assertDiscoveryClient(client *testClient, t *testing.T) { } func assertActiveClient(client *testClient, t *testing.T) { + t.Helper() if client.endpointsCalls != 0 { t.Errorf("expected 0, got %d", client.endpointsCalls) } @@ -730,6 +748,7 @@ func assertActiveClient(client *testClient, t *testing.T) { } func assertEqual(t *testing.T, a interface{}, b interface{}, message string) { + t.Helper() if a == b { return } @@ -780,17 +799,16 @@ func TestCluster_customDialer(t *testing.T) { cfg := Config{ MaxPendingConnectionsPerHost: 1, ClusterUpdateInterval: 1 * time.Second, - Credentials: credentials.NewStaticCredentials("id", "secret", "tok"), + Credentials: &testCredentialProvider{}, DialContext: dialContextFn, Region: "us-west-2", HostPorts: []string{"localhost:9121"}, - logger: aws.NewDefaultLogger(), - logLevel: aws.LogDebugWithRequestRetries, + logger: &logging.Nop{}, IdleConnectionReapDelay: 30 * time.Second, } - cc, err := New(cfg) + cc, err := New(context.Background(), cfg) require.NoError(t, err) - cc.GetItemWithOptions(&dynamodb.GetItemInput{TableName: aws.String("MyTable")}, &dynamodb.GetItemOutput{}, RequestOptions{}) + cc.GetItemWithOptions(context.Background(), &dynamodb.GetItemInput{TableName: aws.String("MyTable")}, RequestOptions{}) wg.Wait() @@ -802,7 +820,9 @@ type testClientBuilder struct { clients []*testClient } -func (b *testClientBuilder) newClient(ip net.IP, port int, connConfigData connConfig, region string, credentials *credentials.Credentials, maxConns int, dialContextFn dialContext) (DaxAPI, error) { +var _ clientBuilder = (*testClientBuilder)(nil) + +func (b *testClientBuilder) newClient(ip net.IP, port int, _ connConfig, _ string, _ aws.CredentialsProvider, _ int, _ dialContext) (DaxAPI, error) { t := &testClient{ep: b.ep, hp: hostPort{ip.String(), port}} b.clients = append(b.clients, []*testClient{t}...) return t, nil @@ -814,11 +834,13 @@ type testClient struct { endpointsCalls, closeCalls, healthCheckCalls int } -func (c *testClient) startHealthChecks(cc *cluster, host hostPort) { +var _ DaxAPI = (*testClient)(nil) + +func (c *testClient) startHealthChecks(_ context.Context, _ *cluster, _ hostPort) { c.healthCheckCalls++ } -func (c *testClient) endpoints(opt RequestOptions) ([]serviceEndpoint, error) { +func (c *testClient) endpoints(_ context.Context, _ RequestOptions) ([]serviceEndpoint, error) { c.endpointsCalls++ return c.ep, nil } @@ -828,42 +850,53 @@ func (c *testClient) Close() error { return nil } -func (c *testClient) PutItemWithOptions(input *dynamodb.PutItemInput, output *dynamodb.PutItemOutput, opt RequestOptions) (*dynamodb.PutItemOutput, error) { - panic("unimpl") +func (c *testClient) PutItemWithOptions(_ context.Context, _ *dynamodb.PutItemInput, _ RequestOptions) (*dynamodb.PutItemOutput, error) { + panic("not implemented") } -func (c *testClient) DeleteItemWithOptions(input *dynamodb.DeleteItemInput, output *dynamodb.DeleteItemOutput, opt RequestOptions) (*dynamodb.DeleteItemOutput, error) { - panic("unimpl") + +func (c *testClient) DeleteItemWithOptions(_ context.Context, _ *dynamodb.DeleteItemInput, _ RequestOptions) (*dynamodb.DeleteItemOutput, error) { + panic("not implemented") } -func (c *testClient) UpdateItemWithOptions(input *dynamodb.UpdateItemInput, output *dynamodb.UpdateItemOutput, opt RequestOptions) (*dynamodb.UpdateItemOutput, error) { - panic("unimpl") + +func (c *testClient) UpdateItemWithOptions(_ context.Context, _ *dynamodb.UpdateItemInput, _ RequestOptions) (*dynamodb.UpdateItemOutput, error) { + panic("not implemented") } -func (c *testClient) GetItemWithOptions(input *dynamodb.GetItemInput, output *dynamodb.GetItemOutput, opt RequestOptions) (*dynamodb.GetItemOutput, error) { - panic("unimpl") +func (c *testClient) GetItemWithOptions(_ context.Context, _ *dynamodb.GetItemInput, _ RequestOptions) (*dynamodb.GetItemOutput, error) { + panic("not implemented") } -func (c *testClient) ScanWithOptions(input *dynamodb.ScanInput, output *dynamodb.ScanOutput, opt RequestOptions) (*dynamodb.ScanOutput, error) { - panic("unimpl") + +func (c *testClient) ScanWithOptions(_ context.Context, _ *dynamodb.ScanInput, _ RequestOptions) (*dynamodb.ScanOutput, error) { + panic("not implemented") } -func (c *testClient) QueryWithOptions(input *dynamodb.QueryInput, output *dynamodb.QueryOutput, opt RequestOptions) (*dynamodb.QueryOutput, error) { - panic("unimpl") + +func (c *testClient) QueryWithOptions(_ context.Context, _ *dynamodb.QueryInput, _ RequestOptions) (*dynamodb.QueryOutput, error) { + panic("not implemented") } -func (c *testClient) BatchWriteItemWithOptions(input *dynamodb.BatchWriteItemInput, output *dynamodb.BatchWriteItemOutput, opt RequestOptions) (*dynamodb.BatchWriteItemOutput, error) { - panic("unimpl") +func (c *testClient) BatchWriteItemWithOptions(_ context.Context, _ *dynamodb.BatchWriteItemInput, _ RequestOptions) (*dynamodb.BatchWriteItemOutput, error) { + panic("not implemented") } -func (c *testClient) BatchGetItemWithOptions(input *dynamodb.BatchGetItemInput, output *dynamodb.BatchGetItemOutput, opt RequestOptions) (*dynamodb.BatchGetItemOutput, error) { - panic("unimpl") + +func (c *testClient) BatchGetItemWithOptions(_ context.Context, _ *dynamodb.BatchGetItemInput, _ RequestOptions) (*dynamodb.BatchGetItemOutput, error) { + panic("not implemented") } -func (c *testClient) NewDaxRequest(op *request.Operation, input, output interface{}, opt RequestOptions) *request.Request { - panic("unimpl") + +func (c *testClient) TransactWriteItemsWithOptions(_ context.Context, _ *dynamodb.TransactWriteItemsInput, _ RequestOptions) (*dynamodb.TransactWriteItemsOutput, error) { + panic("not implemented") } -func (c *testClient) TransactWriteItemsWithOptions(input *dynamodb.TransactWriteItemsInput, output *dynamodb.TransactWriteItemsOutput, opt RequestOptions) (*dynamodb.TransactWriteItemsOutput, error) { - panic("unimpl") +func (c *testClient) TransactGetItemsWithOptions(_ context.Context, _ *dynamodb.TransactGetItemsInput, _ RequestOptions) (*dynamodb.TransactGetItemsOutput, error) { + panic("not implemented") } -func (c *testClient) TransactGetItemsWithOptions(input *dynamodb.TransactGetItemsInput, output *dynamodb.TransactGetItemsOutput, opt RequestOptions) (*dynamodb.TransactGetItemsOutput, error) { - panic("unimpl") + +type testCredentialProvider struct { } -func (c *testClient) build(req *request.Request) { panic("unimpl") } -func (c *testClient) send(req *request.Request) { panic("unimpl") } +func (p *testCredentialProvider) Retrieve(_ context.Context) (aws.Credentials, error) { + return aws.Credentials{ + AccessKeyID: "id", + SecretAccessKey: "secret", + SessionToken: "token", + }, nil +} diff --git a/dax/internal/client/dax_retryer.go b/dax/internal/client/dax_retryer.go index c5f40ce..ca83b7c 100644 --- a/dax/internal/client/dax_retryer.go +++ b/dax/internal/client/dax_retryer.go @@ -16,64 +16,61 @@ package client import ( - "math/rand" + "context" + "errors" "time" - "github.com/aws/aws-sdk-go/aws/request" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/smithy-go" ) -//DaxRetryer implements EqualJitterBackoffStratergy for throttled requests -type DaxRetryer struct { - BaseThrottleDelay time.Duration - MaxBackoffDelay time.Duration -} - -const ( - //DefaultBaseRetryDelay is base delay for throttled requests - DefaultBaseRetryDelay = 70 * time.Millisecond - //DefaultMaxBackoffDelay is max backoff delay for throttled requests - DefaultMaxBackoffDelay = 20 * time.Second -) - -func (r *DaxRetryer) setRetryerDefaults() { - if r.BaseThrottleDelay == 0 { - r.BaseThrottleDelay = DefaultBaseRetryDelay +// IsErrorRetryable returns if the error is daxError +// if code sequences correct any condition return a value other than unknown. +func IsErrorRetryable(err error) aws.Ternary { + de, ok := err.(daxError) + if !ok { + return aws.UnknownTernary + } + codes := de.CodeSequence() + if len(codes) > 0 && (codes[0] == 1 || codes[0] == 2) { + return aws.TrueTernary } - if r.MaxBackoffDelay == 0 { - r.MaxBackoffDelay = DefaultMaxBackoffDelay + // Error code [4.23.31.33] is for AuthenticationRequiredException + if len(codes) == 4 && codes[0] == 4 && codes[1] == 23 && codes[2] == 31 && codes[3] == 33 { + return aws.TrueTernary } + return aws.FalseTernary } -//RetryRules returns the delay duration before retrying this request again -func (r DaxRetryer) RetryRules(req *request.Request) time.Duration { - if req.IsErrorThrottle() { - r.setRetryerDefaults() - attempt := req.RetryCount - minDelay := time.Duration(1< r.MaxBackoffDelay { - minDelay = r.MaxBackoffDelay - } - jitter := time.Duration(rand.Intn(int(minDelay)/2 + 1)) +// Sleep will wait for the timer duration to expire, or the context +// is canceled. Which ever happens first. If the context is canceled the Context's +// error will be returned. +// +// Expects Context to always return a non-nil error if the Done channel is closed. +func Sleep(ctx context.Context, op string, dur time.Duration) error { + t := time.NewTimer(dur) + defer t.Stop() - return minDelay/2 + jitter + select { + case <-t.C: + break + case <-ctx.Done(): + err := ctx.Err() + if errors.Is(err, context.Canceled) { + return &smithy.CanceledError{Err: err} + } + return &smithy.OperationError{Err: err, OperationName: op} } - return 0 -} - -//ShouldRetry returns true if the request should be retried. -func (r DaxRetryer) ShouldRetry(req *request.Request) bool { - daxErr := req.Error.(daxError) - codes := daxErr.CodeSequence() - return len(codes) > 0 && (codes[0] == 1 || codes[0] == 2) || req.IsErrorThrottle() || isAuthCRequiredException(codes) -} -// Error code [4.23.31.33] is for AuthenticationRequiredException -func isAuthCRequiredException(codes []int) bool { - return len(codes) == 4 && codes[0] == 4 && codes[1] == 23 && codes[2] == 31 && codes[3] == 33 + return nil } -// MaxRetries returns the number of maximum retries the service will use to make -// an individual API request. -func (r DaxRetryer) MaxRetries() int { - return 0 +func isRetryable(o RequestOptions, attempt int, err error) bool { + if o.Retryer == nil { + return false + } + if attempt > o.Retryer.MaxAttempts() { + return false + } + return o.Retryer.IsErrorRetryable(err) } diff --git a/dax/internal/client/dax_retryer_test.go b/dax/internal/client/dax_retryer_test.go index 65cb661..541607e 100644 --- a/dax/internal/client/dax_retryer_test.go +++ b/dax/internal/client/dax_retryer_test.go @@ -16,89 +16,64 @@ package client import ( + "context" + "errors" + "fmt" "testing" "time" - "github.com/aws/aws-sdk-go/aws/request" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/smithy-go" ) -func TestRetryThrottleCodes(t *testing.T) { - - req := request.Request{} - retryer := DaxRetryer{} - attempt := 2 - req.RetryCount = attempt - baseThrottleDelay := 70 * time.Millisecond - //for throttling exception - req.Error = newDaxRequestFailure([]int{0}, "ThrottlingException", "", "", 400) - - if !retryer.ShouldRetry(&req) { - t.Errorf("expected retry on throttling") - } - delay := retryer.RetryRules(&req) - maxDelay := time.Duration(1< maxDelay { - t.Errorf("delay more than expected, expected upto %d, got %d ", maxDelay, delay) - } - if delay <= 0 { - t.Errorf("delay for throttled error should be greater than 0, got %d", delay) +func TestIsErrorRetryable(t *testing.T) { + err := fmt.Errorf("fmt error") + te := IsErrorRetryable(err) + if te != aws.UnknownTernary { + t.Fatalf("ternary is wrong: %v", te) } - //for non throttling exception - req.Error = newDaxRequestFailure([]int{0}, "AccessDeniedException", "", "", 400) - if retryer.ShouldRetry(&req) || retryer.RetryRules(&req) != 0 { - t.Errorf("no retry expected") - } -} - -func TestRetryOnThrottlingException(t *testing.T) { - cluster, _ := newTestCluster([]string{"127.0.0.1:8111"}) - cluster.update([]serviceEndpoint{{hostname: "localhost", port: 8121}}) - cc := ClusterDaxClient{config: DefaultConfig(), cluster: cluster} - - flag := 0 - action := func(client DaxAPI, o RequestOptions) error { - if flag == 0 { - flag = 1 - return newDaxRequestFailure([]int{0}, "ThrottlingException", "", "", 400) + for _, code := range []int{1, 2} { + err = newDaxRequestFailure([]int{code}, "", "", "", 500) + te = IsErrorRetryable(err) + if te != aws.TrueTernary { + t.Fatalf("ternary is wrong: %v", te) } - return nil } - opt := RequestOptions{ - MaxRetries: 2, + err = newDaxRequestFailure([]int{4, 23, 31, 33}, "", "", "", 500) + te = IsErrorRetryable(err) + if te != aws.TrueTernary { + t.Fatalf("ternary is wrong: %v", te) } - err := cc.retry("op", action, opt) - - if err != nil { - t.Errorf("error %v", err) + err = newDaxRequestFailure([]int{0}, "", "", "", 500) + te = IsErrorRetryable(err) + if te != aws.FalseTernary { + t.Fatalf("ternary is wrong: %v", te) } } -func TestRetryOnAuthenticationRequiredException(t *testing.T) { - cluster, _ := newTestCluster([]string{"127.0.0.1:8111"}) - cluster.update([]serviceEndpoint{{hostname: "localhost", port: 8121}}) - cc := ClusterDaxClient{config: DefaultConfig(), cluster: cluster} +func TestSleep(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + cancel() - flag := 0 - codes := []int{4, 23, 31, 33} - action := func(client DaxAPI, o RequestOptions) error { - if flag == 0 { - flag = 1 - return newDaxRequestFailure(codes, "AuthenticationRequiredException", "", "", 400) - } - return nil + err := Sleep(ctx, "op", time.Millisecond*100) + if !errors.Is(err, context.Canceled) { + t.Fatalf("error is not context.Canceled, but %T", err) } - opt := RequestOptions{ - MaxRetries: 2, - } + ctx, _ = context.WithTimeout(context.Background(), time.Millisecond*100) + err = Sleep(ctx, "op", time.Millisecond*200) - err := cc.retry("op", action, opt) + var opErr *smithy.OperationError + if !errors.As(err, &opErr) { + t.Fatalf("error is not OperationError, but %T", err) + } + ctx, _ = context.WithTimeout(context.Background(), time.Millisecond*200) + err = Sleep(ctx, "op", time.Millisecond*100) if err != nil { - t.Errorf("error %v", err) + t.Fatalf("err must be nil, but %T", err) } - -} \ No newline at end of file +} diff --git a/dax/internal/client/error.go b/dax/internal/client/error.go index b209e18..448aa01 100644 --- a/dax/internal/client/error.go +++ b/dax/internal/client/error.go @@ -17,16 +17,15 @@ package client import ( "bytes" + "context" + "errors" "fmt" - "net" "github.com/aws/aws-dax-go/dax/internal/cbor" "github.com/aws/aws-dax-go/dax/internal/lru" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/aws/request" - "github.com/aws/aws-sdk-go/private/protocol" - "github.com/aws/aws-sdk-go/service/dynamodb" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/dynamodb/types" + "github.com/aws/smithy-go" ) const ( @@ -38,27 +37,39 @@ const ( ) type daxError interface { - awserr.RequestFailure + smithy.APIError CodeSequence() []int + RequestID() string + StatusCode() int } type daxRequestFailure struct { - awserr.RequestFailure - codes []int + *smithy.GenericAPIError + codes []int + requestID string + statusCode int } +var _ daxError = (*daxRequestFailure)(nil) + type daxTransactionCanceledFailure struct { *daxRequestFailure cancellationReasonCodes []*string cancellationReasonMsgs []*string cancellationReasonItems []byte - cancellationReasons []*dynamodb.CancellationReason + cancellationReasons []types.CancellationReason } func newDaxRequestFailure(codes []int, errorCode, message, requestId string, statusCode int) *daxRequestFailure { return &daxRequestFailure{ - RequestFailure: awserr.NewRequestFailure(awserr.New(errorCode, message, nil), statusCode, requestId), - codes: codes, + GenericAPIError: &smithy.GenericAPIError{ + Code: errorCode, + Message: message, + Fault: smithy.FaultServer, + }, + codes: codes, + requestID: requestId, + statusCode: statusCode, } } @@ -76,6 +87,14 @@ func (f *daxRequestFailure) CodeSequence() []int { return f.codes } +func (f *daxRequestFailure) RequestID() string { + return f.requestID +} + +func (f *daxRequestFailure) StatusCode() int { + return f.statusCode +} + func (f *daxRequestFailure) recoverable() bool { return len(f.codes) > 0 && f.codes[0] == 2 } @@ -85,27 +104,7 @@ func (f *daxRequestFailure) authError() bool { (f.codes[3] == 32 || f.codes[3] == 33 || f.codes[3] == 34)) } -func translateError(err error) awserr.Error { - if err == nil { - return nil - } - switch err.(type) { - case awserr.Error: - e := err.(awserr.Error) - return e - case net.Error: - e := err.(net.Error) - code := dynamodb.ErrCodeInternalServerError - if e.Timeout() { - code = request.ErrCodeResponseTimeout - } - return awserr.New(code, "network error", e) - default: - return awserr.New("UnknownError", "unknown error", err) - } -} - -func decodeError(reader *cbor.Reader) (awserr.Error, error) { +func decodeError(reader *cbor.Reader) (error, error) { length, err := reader.ReadArrayLength() if err != nil { return nil, err @@ -145,7 +144,7 @@ func decodeError(reader *cbor.Reader) (awserr.Error, error) { return nil, err } if (length < 3) || (length > 4) { - return nil, awserr.New(request.ErrCodeSerialization, fmt.Sprintf("expected 3 or 4 elements for error info, got %d", length), nil) + return nil, &smithy.DeserializationError{Err: fmt.Errorf("expected 3 or 4 elements for error info, got %d", length)} } if hdr, err = reader.PeekHeader(); err != nil { return nil, err @@ -183,7 +182,7 @@ func decodeError(reader *cbor.Reader) (awserr.Error, error) { return nil, err } if arrLen%3 != 0 { - return nil, awserr.New(request.ErrCodeSerialization, "error found when parsing CancellationReasons", nil) + return nil, &smithy.DeserializationError{Err: fmt.Errorf("error found when parsing CancellationReasons")} } cancellationReasonsLen := arrLen / 3 cancellationReasonCodes = make([]*string, cancellationReasonsLen) @@ -226,6 +225,7 @@ func decodeError(reader *cbor.Reader) (awserr.Error, error) { statusCode = inferStatusCode(codes) } + // user or server error if cancellationReasonCodes != nil && len(cancellationReasonCodes) > 0 { return newDaxTransactionCanceledFailure(codes, errorCode, msg, requestId, statusCode, cancellationReasonCodes, cancellationReasonMsgs, cancellationReasonItems), nil @@ -233,29 +233,23 @@ func decodeError(reader *cbor.Reader) (awserr.Error, error) { return newDaxRequestFailure(codes, errorCode, msg, requestId, statusCode), nil } -// convertDAXError converts DAX error to specific error type based on error code sequense returned from server. +// convertDAXError converts DAX error to specific error type based on error code sequence returned from server. func convertDaxError(e daxError) error { codes := e.CodeSequence() if len(codes) < 2 { return e } - md := protocol.ResponseMetadata{ - StatusCode: e.StatusCode(), - RequestID: e.RequestID(), - } switch codes[1] { case 23: if len(codes) > 2 { switch codes[2] { case 24: - return &dynamodb.ResourceNotFoundException{ - RespMetadata: md, - Message_: aws.String(e.Message()), + return &types.ResourceNotFoundException{ + Message: aws.String(e.Error()), } case 35: - return &dynamodb.ResourceInUseException{ - RespMetadata: md, - Message_: aws.String(e.Message()), + return &types.ResourceInUseException{ + Message: aws.String(e.Error()), } } } @@ -266,90 +260,99 @@ func convertDaxError(e daxError) error { if len(codes) > 4 { switch codes[4] { case 40: - return &dynamodb.ProvisionedThroughputExceededException{ - RespMetadata: md, - Message_: aws.String(e.Message()), + return &types.ProvisionedThroughputExceededException{ + Message: aws.String(e.Error()), } case 41: - return &dynamodb.ResourceNotFoundException{ - RespMetadata: md, - Message_: aws.String(e.Message()), + return &types.ResourceNotFoundException{ + Message: aws.String(e.Error()), } case 43: - return &dynamodb.ConditionalCheckFailedException{ - RespMetadata: md, - Message_: aws.String(e.Message()), + return &types.ConditionalCheckFailedException{ + Message: aws.String(e.Error()), } case 45: - return &dynamodb.ResourceInUseException{ - RespMetadata: md, - Message_: aws.String(e.Message())} + return &types.ResourceInUseException{ + Message: aws.String(e.Error())} case 46: // there's no dynamodb.ValidationException type - return awserr.NewRequestFailure(awserr.New(ErrCodeValidationException, e.Message(), nil), e.StatusCode(), e.RequestID()) + return &smithy.GenericAPIError{ + Code: ErrCodeValidationException, + Message: e.Error(), + Fault: smithy.FaultServer, + } case 47: - return &dynamodb.InternalServerError{ - RespMetadata: md, - Message_: aws.String(e.Message()), + return &types.InternalServerError{ + Message: aws.String(e.Error()), } case 48: - return &dynamodb.ItemCollectionSizeLimitExceededException{ - RespMetadata: md, - Message_: aws.String(e.Message()), + return &types.ItemCollectionSizeLimitExceededException{ + Message: aws.String(e.Error()), } case 49: - return &dynamodb.LimitExceededException{ - RespMetadata: md, - Message_: aws.String(e.Message()), + return &types.LimitExceededException{ + Message: aws.String(e.Error()), } case 50: // there's no dynamodb.ThrottlingException type - return awserr.NewRequestFailure(awserr.New(ErrCodeThrottlingException, e.Message(), nil), e.StatusCode(), e.RequestID()) + return &smithy.GenericAPIError{ + Code: ErrCodeThrottlingException, + Message: e.Error(), + Fault: smithy.FaultServer, + } case 57: - return &dynamodb.TransactionConflictException{ - RespMetadata: md, - Message_: aws.String(e.Message()), + return &types.TransactionConflictException{ + Message: aws.String(e.Error()), } case 58: tcFailure, ok := e.(*daxTransactionCanceledFailure) if ok { - return &dynamodb.TransactionCanceledException{ - RespMetadata: md, - Message_: aws.String(e.Message()), + return &types.TransactionCanceledException{ + Message: aws.String(e.Error()), CancellationReasons: tcFailure.cancellationReasons, } + } else { + return &types.TransactionCanceledException{ + Message: aws.String(e.Error()), + } } case 59: - return &dynamodb.TransactionInProgressException{ - RespMetadata: md, - Message_: aws.String(e.Message()), + return &types.TransactionInProgressException{ + Message: aws.String(e.Error()), } case 60: - return &dynamodb.IdempotentParameterMismatchException{ - RespMetadata: md, - Message_: aws.String(e.Message()), + return &types.IdempotentParameterMismatchException{ + Message: aws.String(e.Error()), } } } case 44: - return awserr.NewRequestFailure(awserr.New(ErrCodeNotImplemented, e.Message(), nil), e.StatusCode(), e.RequestID()) + return &smithy.GenericAPIError{ + Code: ErrCodeNotImplemented, + Message: e.Error(), + Fault: smithy.FaultServer, + } } } } - return awserr.NewRequestFailure(awserr.New(ErrCodeUnknown, e.Message(), nil), e.StatusCode(), e.RequestID()) + return &smithy.GenericAPIError{ + Code: ErrCodeUnknown, + Message: e.Error(), + Fault: smithy.FaultServer, + } } -func decodeTransactionCancellationReasons(ctx aws.Context, failure *daxTransactionCanceledFailure, - keys []map[string]*dynamodb.AttributeValue, attrListIdToNames *lru.Lru) ([]*dynamodb.CancellationReason, error) { +func decodeTransactionCancellationReasons(ctx context.Context, failure *daxTransactionCanceledFailure, + keys []map[string]types.AttributeValue, attrListIdToNames *lru.Lru) ([]types.CancellationReason, error) { inputL := len(keys) outputL := len(failure.cancellationReasonCodes) if inputL != outputL { - return nil, awserr.New(request.ErrCodeSerialization, "Cancellation reasons must be the same length as transact items in the request", nil) + return nil, &smithy.DeserializationError{Err: errors.New("cancellation reasons must be the same length as transact items in the request")} } - reasons := make([]*dynamodb.CancellationReason, outputL) + reasons := make([]types.CancellationReason, outputL) r := cbor.NewReader(bytes.NewReader(failure.cancellationReasonItems)) for i := 0; i < outputL; i++ { - reason := new(dynamodb.CancellationReason) + reason := types.CancellationReason{} reason.Code = failure.cancellationReasonCodes[i] reason.Message = failure.cancellationReasonMsgs[i] if consumed, err := consumeNil(r); err != nil { diff --git a/dax/internal/client/error_test.go b/dax/internal/client/error_test.go index 9becc61..fabb070 100644 --- a/dax/internal/client/error_test.go +++ b/dax/internal/client/error_test.go @@ -17,35 +17,38 @@ package client import ( "bytes" - "errors" - "net" + "context" "reflect" "testing" "github.com/aws/aws-dax-go/dax/internal/cbor" "github.com/aws/aws-dax-go/dax/internal/lru" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/service/dynamodb" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/dynamodb/types" + "github.com/aws/smithy-go" ) func TestDecodeError(t *testing.T) { var b bytes.Buffer - errcode := []int{4, 37, 38, 39, 40} - awserr := awserr.NewRequestFailure(awserr.New(dynamodb.ErrCodeProvisionedThroughputExceededException, "ProvisionedThroughputExceededException Message", nil), 400, "request-1") + errCodes := []int{4, 37, 38, 39, 40} + requestID := "request-1" + statusCode := 400 + exception := types.ProvisionedThroughputExceededException{ + Message: aws.String("ProvisionedThroughputExceededException Message"), + } w := cbor.NewWriter(&b) - w.WriteArrayHeader(len(errcode)) - for _, c := range errcode { - w.WriteInt(c) + _ = w.WriteArrayHeader(len(errCodes)) + for _, c := range errCodes { + _ = w.WriteInt(c) } - w.WriteString(awserr.Message()) + _ = w.WriteString(exception.ErrorMessage()) - w.WriteArrayHeader(3) - w.WriteString(awserr.RequestID()) - w.WriteString(awserr.Code()) - w.WriteInt(awserr.StatusCode()) - w.Flush() + _ = w.WriteArrayHeader(3) + _ = w.WriteString(requestID) + _ = w.WriteString(exception.ErrorCode()) + _ = w.WriteInt(statusCode) + _ = w.Flush() r := cbor.NewReader(&b) e, err := decodeError(r) @@ -59,8 +62,14 @@ func TestDecodeError(t *testing.T) { } expected := &daxRequestFailure{ - RequestFailure: awserr, - codes: errcode, + GenericAPIError: &smithy.GenericAPIError{ + Code: exception.ErrorCode(), + Message: exception.ErrorMessage(), + Fault: smithy.FaultServer, + }, + codes: errCodes, + requestID: requestID, + statusCode: statusCode, } if !reflect.DeepEqual(expected, d) { @@ -69,44 +78,49 @@ func TestDecodeError(t *testing.T) { } func TestDecodeTransactionCanceledException(t *testing.T) { - errcode := []int{4, 37, 38, 39, 58} - awserr := awserr.NewRequestFailure(awserr.New(dynamodb.ErrCodeTransactionCanceledException, "TransactionCanceledException Message", nil), 400, "request-1") - reasonLen := 2 - reasonCodes := []*string{aws.String("reasonCode1"), aws.String("reasonCode2")} - reasonMsgs := []*string{aws.String("reasonMsg1"), aws.String("reasonMsg2")} + errCodes := []int{4, 37, 38, 39, 58} + requestID := "request-1" + statusCode := 400 + exception := types.TransactionCanceledException{ + Message: aws.String("TransactionCanceledException Message"), + CancellationReasons: []types.CancellationReason{ + {Code: aws.String("reasonCode1"), Item: map[string]types.AttributeValue{}, Message: aws.String("reasonMsg1")}, + {Code: aws.String("reasonCode2"), Item: map[string]types.AttributeValue{}, Message: aws.String("reasonMsg2")}, + }, + } items := []byte{} var expItems []byte var b bytes.Buffer w := cbor.NewWriter(&b) - w.WriteArrayHeader(len(errcode)) - for _, c := range errcode { - w.WriteInt(c) + _ = w.WriteArrayHeader(len(errCodes)) + for _, c := range errCodes { + _ = w.WriteInt(c) } - w.WriteString(awserr.Message()) - - w.WriteArrayHeader(4) - w.WriteString(awserr.RequestID()) - w.WriteString(awserr.Code()) - w.WriteInt(awserr.StatusCode()) - w.WriteArrayHeader(3 * reasonLen) - for i := 0; i < reasonLen; i++ { - w.WriteString(*reasonCodes[i]) - w.WriteString(*reasonMsgs[i]) - w.WriteBytes(items) + _ = w.WriteString(exception.ErrorMessage()) + + _ = w.WriteArrayHeader(4) + _ = w.WriteString(requestID) + _ = w.WriteString(exception.ErrorCode()) + _ = w.WriteInt(statusCode) + _ = w.WriteArrayHeader(3 * len(exception.CancellationReasons)) + for i := 0; i < len(exception.CancellationReasons); i++ { + _ = w.WriteString(*exception.CancellationReasons[i].Code) + _ = w.WriteString(*exception.CancellationReasons[i].Message) + _ = w.WriteBytes(items) buf := bytes.Buffer{} nw := cbor.NewWriter(&buf) - nw.WriteBytes(items) - nw.Flush() + _ = nw.WriteBytes(items) + _ = nw.Flush() r := cbor.NewReader(&buf) obuf := bytes.Buffer{} - r.ReadRawBytes(&obuf) + _ = r.ReadRawBytes(&obuf) expItems = append(expItems, obuf.Bytes()...) } - w.Flush() + _ = w.Flush() r := cbor.NewReader(&b) e, err := decodeError(r) @@ -119,10 +133,23 @@ func TestDecodeTransactionCanceledException(t *testing.T) { t.Errorf("expected daxTransactionCanceledFailure type") } + reasonCodes := make([]*string, 0, len(exception.CancellationReasons)) + reasonMsgs := make([]*string, 0, len(exception.CancellationReasons)) + for _, r := range exception.CancellationReasons { + reasonCodes = append(reasonCodes, r.Code) + reasonMsgs = append(reasonMsgs, r.Message) + } + expected := &daxTransactionCanceledFailure{ daxRequestFailure: &daxRequestFailure{ - RequestFailure: awserr, - codes: errcode, + GenericAPIError: &smithy.GenericAPIError{ + Code: exception.ErrorCode(), + Message: exception.ErrorMessage(), + Fault: smithy.FaultServer, + }, + codes: errCodes, + requestID: requestID, + statusCode: statusCode, }, cancellationReasonCodes: reasonCodes, cancellationReasonMsgs: reasonMsgs, @@ -137,41 +164,42 @@ func TestDecodeTransactionCanceledException(t *testing.T) { // TestDecodeTransactionCancellationReasons tests decoding transaction cancellations reasons in daxTransactionCanceledFailure. // // Specifically, the decoding of items in cancellation reasons are being testing here. It covers three situations: -// 1. transact item didn't fail conditional check -// 2. transact item failed conditional check and was configured to return ALL_OLD item -// 3. transact item failed conditional check and was configured to return NONE item +// 1. transact item didn't fail conditional check +// 2. transact item failed conditional check and was configured to return ALL_OLD item +// 3. transact item failed conditional check and was configured to return NONE item func TestDecodeTransactionCancellationReasons(t *testing.T) { expCodes := []int{1, 2, 3, 4} - expErrCode := dynamodb.ErrCodeTransactionCanceledException + + expErrCode := (&types.TransactionCanceledException{}).ErrorCode() expMsg := "Transaction was cancelled." expReqID := "134213414395861" expStatusCode := 400 expCanceledCodes := []*string{ aws.String("NONE"), - aws.String(dynamodb.ErrCodeConditionalCheckFailedException), - aws.String(dynamodb.ErrCodeTransactionInProgressException), + aws.String((&types.ConditionalCheckFailedException{}).ErrorCode()), + aws.String((&types.TransactionInProgressException{}).ErrorCode()), } expCanceledReasons := []*string{ nil, aws.String("first reason"), aws.String("second reason"), } - keyDef := []dynamodb.AttributeDefinition{ + keyDef := []types.AttributeDefinition{ {AttributeName: aws.String("hk")}, } - keys := []map[string]*dynamodb.AttributeValue{ - {"hk": &dynamodb.AttributeValue{N: aws.String("0")}}, - {"hk": &dynamodb.AttributeValue{N: aws.String("0")}}, - {"hk": &dynamodb.AttributeValue{N: aws.String("0")}}, + keys := []map[string]types.AttributeValue{ + {"hk": &types.AttributeValueMemberN{Value: "0"}}, + {"hk": &types.AttributeValueMemberN{Value: "0"}}, + {"hk": &types.AttributeValueMemberN{Value: "0"}}, } - canceledItems := []map[string]*dynamodb.AttributeValue{ + canceledItems := []map[string]types.AttributeValue{ nil, - {"attr": &dynamodb.AttributeValue{N: aws.String("0")}}, + {"attr": &types.AttributeValueMemberN{Value: "0"}}, nil, } attrs := []string{"attr"} attrsToID := &lru.Lru{ - LoadFunc: func(ctx aws.Context, key lru.Key) (interface{}, error) { + LoadFunc: func(ctx context.Context, key lru.Key) (interface{}, error) { return int64(12345), nil }, KeyMarshaller: func(key lru.Key) lru.Key { @@ -179,14 +207,14 @@ func TestDecodeTransactionCancellationReasons(t *testing.T) { w := cbor.NewWriter(&buf) defer w.Close() for _, v := range key.([]string) { - w.WriteString(v) + _ = w.WriteString(v) } - w.Flush() + _ = w.Flush() return string(buf.Bytes()) }, } idToAttrs := &lru.Lru{ - LoadFunc: func(ctx aws.Context, key lru.Key) (interface{}, error) { + LoadFunc: func(ctx context.Context, key lru.Key) (interface{}, error) { return attrs, nil }, } @@ -195,29 +223,29 @@ func TestDecodeTransactionCancellationReasons(t *testing.T) { buf := bytes.Buffer{} w := cbor.NewWriter(&buf) cbor.EncodeItemNonKeyAttributes(nil, canceledItems[1], keyDef, attrsToID, w) - w.Flush() + _ = w.Flush() nbuf := bytes.Buffer{} nw := cbor.NewWriter(&nbuf) - nw.WriteNull() - nw.WriteBytes(buf.Bytes()) - nw.WriteNull() - nw.Flush() + _ = nw.WriteNull() + _ = nw.WriteBytes(buf.Bytes()) + _ = nw.WriteNull() + _ = nw.Flush() for k, v := range keys[1] { canceledItems[1][k] = v } - expCancellationReason := []*dynamodb.CancellationReason{ - &dynamodb.CancellationReason{ + expCancellationReason := []types.CancellationReason{ + { Code: expCanceledCodes[0], }, - &dynamodb.CancellationReason{ + { Code: expCanceledCodes[1], Message: expCanceledReasons[1], Item: canceledItems[1], }, - &dynamodb.CancellationReason{ + { Code: expCanceledCodes[2], Message: expCanceledReasons[2], }, @@ -245,21 +273,24 @@ func TestDecodeTransactionCancellationReasons(t *testing.T) { func TestDecodeNilErrorDetail(t *testing.T) { var b bytes.Buffer - errcode := []int{4, 37, 38, 39, 43} - awserr := awserr.NewRequestFailure(awserr.New(dynamodb.ErrCodeConditionalCheckFailedException, "ConditionalCheckFailedException Message", nil), 400, "") + errCodes := []int{4, 37, 38, 39, 43} + exception := types.ConditionalCheckFailedException{ + Message: aws.String("ConditionalCheckFailedException Message"), + } + //awserr := awserr.NewRequestFailure(awserr.New(dynamodb.ErrCodeConditionalCheckFailedException, "ConditionalCheckFailedException Message", nil), 400, "") w := cbor.NewWriter(&b) - w.WriteArrayHeader(len(errcode)) - for _, c := range errcode { - w.WriteInt(c) + _ = w.WriteArrayHeader(len(errCodes)) + for _, c := range errCodes { + _ = w.WriteInt(c) } - w.WriteString(awserr.Message()) + _ = w.WriteString(exception.ErrorMessage()) - w.WriteArrayHeader(3) - w.WriteNull() - w.WriteString(awserr.Code()) - w.WriteNull() // status code will be inferred from error code - w.Flush() + _ = w.WriteArrayHeader(3) + _ = w.WriteNull() + _ = w.WriteString(exception.ErrorCode()) + _ = w.WriteNull() // status code will be inferred from error code + _ = w.Flush() r := cbor.NewReader(&b) e, err := decodeError(r) @@ -273,8 +304,14 @@ func TestDecodeNilErrorDetail(t *testing.T) { } expected := &daxRequestFailure{ - RequestFailure: awserr, - codes: errcode, + GenericAPIError: &smithy.GenericAPIError{ + Code: exception.ErrorCode(), + Message: exception.ErrorMessage(), + Fault: smithy.FaultServer, + }, + codes: errCodes, + requestID: "", + statusCode: 400, } if !reflect.DeepEqual(expected, d) { @@ -282,38 +319,3 @@ func TestDecodeNilErrorDetail(t *testing.T) { } } - -func TestTranslateError(t *testing.T) { - cases := []struct { - input error - output error - }{ - { - input: newDaxRequestFailure([]int{1, 2, 3}, "ec", "msg", "rid", 500), - output: newDaxRequestFailure([]int{1, 2, 3}, "ec", "msg", "rid", 500), - }, - { - input: awserr.NewRequestFailure(awserr.New("ec", "msg", nil), 500, "rid"), - output: awserr.NewRequestFailure(awserr.New("ec", "msg", nil), 500, "rid"), - }, - { - input: awserr.New("ec", "msg", nil), - output: awserr.New("ec", "msg", nil), - }, - { - input: new(net.UnknownNetworkError), - output: awserr.New(dynamodb.ErrCodeInternalServerError, "network error", new(net.UnknownNetworkError)), - }, - { - input: errors.New("ex"), - output: awserr.New("UnknownError", "unknown error", errors.New("ex")), - }, - } - - for _, c := range cases { - actual := translateError(c.input) - if !reflect.DeepEqual(c.output, actual) { - t.Errorf("expected %v, got %v", c.output, actual) - } - } -} diff --git a/dax/internal/client/interface.go b/dax/internal/client/interface.go index 53790e8..ade2dd3 100644 --- a/dax/internal/client/interface.go +++ b/dax/internal/client/interface.go @@ -16,28 +16,25 @@ package client import ( - "github.com/aws/aws-sdk-go/aws/request" - "github.com/aws/aws-sdk-go/service/dynamodb" + "context" + + "github.com/aws/aws-sdk-go-v2/service/dynamodb" ) type DaxAPI interface { - PutItemWithOptions(input *dynamodb.PutItemInput, output *dynamodb.PutItemOutput, opt RequestOptions) (*dynamodb.PutItemOutput, error) - DeleteItemWithOptions(input *dynamodb.DeleteItemInput, output *dynamodb.DeleteItemOutput, opt RequestOptions) (*dynamodb.DeleteItemOutput, error) - UpdateItemWithOptions(input *dynamodb.UpdateItemInput, output *dynamodb.UpdateItemOutput, opt RequestOptions) (*dynamodb.UpdateItemOutput, error) - - GetItemWithOptions(input *dynamodb.GetItemInput, output *dynamodb.GetItemOutput, opt RequestOptions) (*dynamodb.GetItemOutput, error) - ScanWithOptions(input *dynamodb.ScanInput, output *dynamodb.ScanOutput, opt RequestOptions) (*dynamodb.ScanOutput, error) - QueryWithOptions(input *dynamodb.QueryInput, output *dynamodb.QueryOutput, opt RequestOptions) (*dynamodb.QueryOutput, error) + PutItemWithOptions(ctx context.Context, input *dynamodb.PutItemInput, opt RequestOptions) (*dynamodb.PutItemOutput, error) + DeleteItemWithOptions(ctx context.Context, input *dynamodb.DeleteItemInput, opt RequestOptions) (*dynamodb.DeleteItemOutput, error) + UpdateItemWithOptions(ctx context.Context, input *dynamodb.UpdateItemInput, opt RequestOptions) (*dynamodb.UpdateItemOutput, error) - BatchWriteItemWithOptions(input *dynamodb.BatchWriteItemInput, output *dynamodb.BatchWriteItemOutput, opt RequestOptions) (*dynamodb.BatchWriteItemOutput, error) - BatchGetItemWithOptions(input *dynamodb.BatchGetItemInput, output *dynamodb.BatchGetItemOutput, opt RequestOptions) (*dynamodb.BatchGetItemOutput, error) + GetItemWithOptions(ctx context.Context, input *dynamodb.GetItemInput, opt RequestOptions) (*dynamodb.GetItemOutput, error) + ScanWithOptions(ctx context.Context, input *dynamodb.ScanInput, opt RequestOptions) (*dynamodb.ScanOutput, error) + QueryWithOptions(ctx context.Context, input *dynamodb.QueryInput, opt RequestOptions) (*dynamodb.QueryOutput, error) - TransactWriteItemsWithOptions(input *dynamodb.TransactWriteItemsInput, output *dynamodb.TransactWriteItemsOutput, opt RequestOptions) (*dynamodb.TransactWriteItemsOutput, error) - TransactGetItemsWithOptions(input *dynamodb.TransactGetItemsInput, output *dynamodb.TransactGetItemsOutput, opt RequestOptions) (*dynamodb.TransactGetItemsOutput, error) + BatchWriteItemWithOptions(ctx context.Context, input *dynamodb.BatchWriteItemInput, opt RequestOptions) (*dynamodb.BatchWriteItemOutput, error) + BatchGetItemWithOptions(ctx context.Context, input *dynamodb.BatchGetItemInput, opt RequestOptions) (*dynamodb.BatchGetItemOutput, error) - NewDaxRequest(op *request.Operation, input, output interface{}, opt RequestOptions) *request.Request - build(req *request.Request) - send(req *request.Request) + TransactWriteItemsWithOptions(ctx context.Context, input *dynamodb.TransactWriteItemsInput, opt RequestOptions) (*dynamodb.TransactWriteItemsOutput, error) + TransactGetItemsWithOptions(ctx context.Context, input *dynamodb.TransactGetItemsInput, opt RequestOptions) (*dynamodb.TransactGetItemsOutput, error) - endpoints(opt RequestOptions) ([]serviceEndpoint, error) + endpoints(ctx context.Context, opt RequestOptions) ([]serviceEndpoint, error) } diff --git a/dax/internal/client/legacy.go b/dax/internal/client/legacy.go index 3b047b1..703e3b6 100644 --- a/dax/internal/client/legacy.go +++ b/dax/internal/client/legacy.go @@ -19,9 +19,10 @@ import ( "fmt" "strings" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/service/dynamodb" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/dynamodb" + "github.com/aws/aws-sdk-go-v2/service/dynamodb/types" + "github.com/aws/smithy-go" ) const ( @@ -56,7 +57,7 @@ func translateLegacyPutItemInput(input *dynamodb.PutItemInput) (*dynamodb.PutIte if err != nil { return input, err } - output.ConditionalOperator = nil + output.ConditionalOperator = "" output.Expected = nil return output, err } @@ -70,7 +71,7 @@ func translateLegacyDeleteItemInput(input *dynamodb.DeleteItemInput) (*dynamodb. output := input output.ConditionExpression, output.ExpressionAttributeNames, output.ExpressionAttributeValues, err = translateExpected(output.ConditionalOperator, output.Expected, input.ExpressionAttributeNames, output.ExpressionAttributeValues) - output.ConditionalOperator = nil + output.ConditionalOperator = "" output.Expected = nil if err != nil { return input, err @@ -98,7 +99,7 @@ func translateLegacyUpdateItemInput(input *dynamodb.UpdateItemInput) (*dynamodb. if err != nil { return input, err } - output.ConditionalOperator = nil + output.ConditionalOperator = "" output.Expected = nil } if uf { @@ -111,8 +112,11 @@ func translateLegacyUpdateItemInput(input *dynamodb.UpdateItemInput) (*dynamodb. } return output, nil } - func translateLegacyScanInput(input *dynamodb.ScanInput) (*dynamodb.ScanInput, error) { + // if ProjectionExpression is not nil, Should set Select type. + if input.ProjectionExpression != nil { + input.Select = types.SelectSpecificAttributes + } pf, err := hasAttributesToGet(input.AttributesToGet, input.ProjectionExpression) if err != nil { return input, err @@ -140,7 +144,7 @@ func translateLegacyScanInput(input *dynamodb.ScanInput) (*dynamodb.ScanInput, e if err != nil { return input, err } - output.ConditionalOperator = nil + output.ConditionalOperator = "" output.ScanFilter = nil } @@ -179,12 +183,12 @@ func translateLegacyQueryInput(input *dynamodb.QueryInput) (*dynamodb.QueryInput if err != nil { return input, err } - output.ConditionalOperator = nil + output.ConditionalOperator = "" output.QueryFilter = nil } if kf { output.KeyConditionExpression, output.ExpressionAttributeNames, output.ExpressionAttributeValues, err = - translateFilter(aws.String(dynamodb.ConditionalOperatorAnd), output.KeyConditions, output.ExpressionAttributeNames, output.ExpressionAttributeValues, true) + translateFilter(types.ConditionalOperatorAnd, output.KeyConditions, output.ExpressionAttributeNames, output.ExpressionAttributeValues, true) if err != nil { return input, err } @@ -199,7 +203,7 @@ func translateLegacyBatchGetItemInput(input *dynamodb.BatchGetItemInput) (*dynam return input, nil } - for _, kaas := range input.RequestItems { + for i, kaas := range input.RequestItems { f, err := hasAttributesToGet(kaas.AttributesToGet, kaas.ProjectionExpression) if err != nil { return input, err @@ -211,57 +215,74 @@ func translateLegacyBatchGetItemInput(input *dynamodb.BatchGetItemInput) (*dynam if err != nil { return input, err } + input.RequestItems[i] = kaas } return input, nil } -func hasAttributesToGet(a []*string, p *string) (bool, error) { +func hasAttributesToGet(a []string, p *string) (bool, error) { af := len(a) != 0 pf := p != nil if af && pf { - return false, awserr.New(ErrCodeValidationException, "Cannot specify both AttributesToGet and ProjectionExpression", nil) + return false, &smithy.GenericAPIError{ + Code: ErrCodeValidationException, + Message: "Cannot specify both AttributesToGet and ProjectionExpression", + Fault: smithy.FaultClient, + } } return af, nil } -func hasExpected(e map[string]*dynamodb.ExpectedAttributeValue, c *string) (bool, error) { +func hasExpected(e map[string]types.ExpectedAttributeValue, c *string) (bool, error) { ef := len(e) != 0 cf := c != nil if ef && cf { - return false, awserr.New(ErrCodeValidationException, "Cannot specify both Expected and ConditionExpression", nil) + return false, &smithy.GenericAPIError{ + Code: ErrCodeValidationException, + Message: "Cannot specify both Expected and ConditionExpression", + Fault: smithy.FaultClient, + } } return ef, nil } -func hasAttributeUpdates(u map[string]*dynamodb.AttributeValueUpdate, e *string) (bool, error) { +func hasAttributeUpdates(u map[string]types.AttributeValueUpdate, e *string) (bool, error) { uf := len(u) > 0 ef := e != nil if uf && ef { - return false, awserr.New(ErrCodeValidationException, "Cannot specify both AttributeUpdates and UpdateExpression", nil) + return false, &smithy.GenericAPIError{ + Code: ErrCodeValidationException, + Message: "Cannot specify both AttributeUpdates and UpdateExpression", + Fault: smithy.FaultClient, + } } return uf, nil } -func hasFilter(c map[string]*dynamodb.Condition, e *string) (bool, error) { +func hasFilter(c map[string]types.Condition, e *string) (bool, error) { cf := len(c) > 0 ef := e != nil if cf && ef { - return false, awserr.New(ErrCodeValidationException, "Cannot specify both [Scan|Query]Filter and [Scan|Query]FilterExpression", nil) + return false, &smithy.GenericAPIError{ + Code: ErrCodeValidationException, + Message: "Cannot specify both [Scan|Query]Filter and [Scan|Query]FilterExpression", + Fault: smithy.FaultClient, + } } return cf, nil } -func translateAttributesToGet(attrs []*string, subs map[string]*string) (*string, map[string]*string, error) { +func translateAttributesToGet(attrs []string, subs map[string]string) (*string, map[string]string, error) { out, sub := appendAttributeNames(nil, attrs, subs) return aws.String(string(out)), sub, nil } -func translateExpected(o *string, e map[string]*dynamodb.ExpectedAttributeValue, subs map[string]*string, vars map[string]*dynamodb.AttributeValue) (*string, map[string]*string, map[string]*dynamodb.AttributeValue, error) { - op := dynamodb.ConditionalOperatorAnd - if o != nil && len(*o) > 0 { - op = *o +func translateExpected(o types.ConditionalOperator, e map[string]types.ExpectedAttributeValue, subs map[string]string, vars map[string]types.AttributeValue) (*string, map[string]string, map[string]types.AttributeValue, error) { + op := types.ConditionalOperatorAnd + if len(o) > 0 { + op = o } - ops := fmt.Sprintf(" %s ", strings.TrimSpace(op)) + ops := fmt.Sprintf(" %s ", strings.TrimSpace(string(op))) var out []byte var err error @@ -280,12 +301,12 @@ func translateExpected(o *string, e map[string]*dynamodb.ExpectedAttributeValue, return aws.String(string(out)), subs, vars, err } -func translateFilter(o *string, c map[string]*dynamodb.Condition, subs map[string]*string, vars map[string]*dynamodb.AttributeValue, keyCondition bool) (*string, map[string]*string, map[string]*dynamodb.AttributeValue, error) { - op := dynamodb.ConditionalOperatorAnd - if o != nil && len(*o) > 0 { - op = *o +func translateFilter(o types.ConditionalOperator, c map[string]types.Condition, subs map[string]string, vars map[string]types.AttributeValue, keyCondition bool) (*string, map[string]string, map[string]types.AttributeValue, error) { + op := types.ConditionalOperatorAnd + if len(o) > 0 { + op = o } - ops := fmt.Sprintf(" %s ", strings.TrimSpace(op)) + ops := fmt.Sprintf(" %s ", strings.TrimSpace(string(op))) var out []byte var err error @@ -304,40 +325,45 @@ func translateFilter(o *string, c map[string]*dynamodb.Condition, subs map[strin return aws.String(string(out)), subs, vars, err } -func translateAttributeUpdates(avus map[string]*dynamodb.AttributeValueUpdate, subs map[string]*string, vars map[string]*dynamodb.AttributeValue) (*string, map[string]*string, map[string]*dynamodb.AttributeValue, error) { +func translateAttributeUpdates(avus map[string]types.AttributeValueUpdate, subs map[string]string, vars map[string]types.AttributeValue) (*string, map[string]string, map[string]types.AttributeValue, error) { var sets, adds, dels, rems []string for a, avu := range avus { - if avu == nil { - continue - } - act := dynamodb.AttributeActionPut - if avu.Action != nil { - act = *avu.Action - } - if avu.Value == nil && act != dynamodb.AttributeActionDelete { - return nil, subs, vars, awserr.New(ErrCodeValidationException, "only DELETE action is allowed when no attribute value is specified", nil) + act := types.AttributeActionPut + if avu.Action != "" { + act = avu.Action + } + if avu.Value == nil && act != types.AttributeActionDelete { + return nil, subs, vars, &smithy.GenericAPIError{ + Code: ErrCodeValidationException, + Message: "only DELETE action is allowed when no attribute value is specified", + Fault: smithy.FaultClient, + } } var an, av string subs, an = appendAttributeName(subs, a) if avu.Value != nil { - vars, av = appendAttributeValue(vars, *avu.Value) + vars, av = appendAttributeValue(vars, avu.Value) } switch act { - case dynamodb.AttributeActionPut: + case types.AttributeActionPut: sets = append(sets, fmt.Sprintf("%s=%s", an, av)) - case dynamodb.AttributeActionAdd: + case types.AttributeActionAdd: adds = append(adds, fmt.Sprintf("%s %s", an, av)) - case dynamodb.AttributeActionDelete: + case types.AttributeActionDelete: if len(av) == 0 { rems = append(rems, an) } else { dels = append(dels, fmt.Sprintf("%s %s", an, av)) } default: - return nil, subs, vars, awserr.New(ErrCodeValidationException, fmt.Sprintf("unknown AttributeValueUpdate Action: %s", act), nil) + return nil, subs, vars, &smithy.GenericAPIError{ + Code: ErrCodeValidationException, + Message: fmt.Sprintf("unknown AttributeValueUpdate Action: %s", act), + Fault: smithy.FaultClient, + } } } @@ -357,10 +383,10 @@ func translateAttributeUpdates(avus map[string]*dynamodb.AttributeValueUpdate, s return aws.String(strings.Join(all, " ")), subs, vars, nil } -func appendAttributeNames(in []byte, attrs []*string, sub map[string]*string) ([]byte, map[string]*string) { +func appendAttributeNames(in []byte, attrs []string, sub map[string]string) ([]byte, map[string]string) { f := true for _, a := range attrs { - if a == nil || len(*a) == 0 { + if len(a) == 0 { continue } if f { @@ -369,13 +395,13 @@ func appendAttributeNames(in []byte, attrs []*string, sub map[string]*string) ([ in = append(in, []byte(",")...) } var an string - sub, an = appendAttributeName(sub, *a) + sub, an = appendAttributeName(sub, a) in = append(in, []byte(an)...) } return in, sub } -func appendAttributeValues(in []byte, avl []*dynamodb.AttributeValue, vars map[string]*dynamodb.AttributeValue) ([]byte, map[string]*dynamodb.AttributeValue) { +func appendAttributeValues(in []byte, avl []types.AttributeValue, vars map[string]types.AttributeValue) ([]byte, map[string]types.AttributeValue) { f := true for _, v := range avl { if v == nil { @@ -387,50 +413,57 @@ func appendAttributeValues(in []byte, avl []*dynamodb.AttributeValue, vars map[s in = append(in, []byte(",")...) } var av string - vars, av = appendAttributeValue(vars, *v) + vars, av = appendAttributeValue(vars, v) in = append(in, []byte(av)...) } return in, vars } -func appendCondition(in []byte, a string, eav *dynamodb.ExpectedAttributeValue, subs map[string]*string, vars map[string]*dynamodb.AttributeValue) ([]byte, map[string]*string, map[string]*dynamodb.AttributeValue, error) { - if eav == nil { - return in, subs, vars, nil - } +func appendCondition(in []byte, a string, eav types.ExpectedAttributeValue, subs map[string]string, vars map[string]types.AttributeValue) ([]byte, map[string]string, map[string]types.AttributeValue, error) { if eav.Value != nil && len(eav.AttributeValueList) > 0 { - return in, subs, vars, awserr.New(ErrCodeValidationException, fmt.Sprintf("One or more parameter values were invalid: Value and AttributeValueList cannot be used together for Attribute: %s", a), nil) + return in, subs, vars, &smithy.GenericAPIError{ + Code: ErrCodeValidationException, + Message: fmt.Sprintf("One or more parameter values were invalid: Value and AttributeValueList cannot be used together for Attribute: %s", a), + Fault: smithy.FaultClient, + } } op := eav.ComparisonOperator - if op == nil || len(*op) == 0 { + if len(op) == 0 { return appendExistsCondition(in, a, eav, subs, vars) } else if eav.Exists != nil && *eav.Exists { - return in, subs, vars, awserr.New(ErrCodeValidationException, fmt.Sprintf("One or more parameter values were invalid: Exists and ComparisonOperator cannot be used together for Attribute: %s", a), nil) + return in, subs, vars, &smithy.GenericAPIError{ + Code: ErrCodeValidationException, + Message: fmt.Sprintf("One or more parameter values were invalid: Exists and ComparisonOperator cannot be used together for Attribute: %s", a), + Fault: smithy.FaultClient, + } } avl := eav.AttributeValueList if len(avl) == 0 && eav.Value != nil { - avl = []*dynamodb.AttributeValue{eav.Value} + avl = []types.AttributeValue{eav.Value} } - return appendComparisonCondition(in, a, *op, avl, subs, vars, false) + return appendComparisonCondition(in, a, op, avl, subs, vars, false) } -func appendFilterCondition(in []byte, a string, c *dynamodb.Condition, subs map[string]*string, vars map[string]*dynamodb.AttributeValue, keyCondition bool) ([]byte, map[string]*string, map[string]*dynamodb.AttributeValue, error) { - if c == nil { - if keyCondition { - return in, subs, vars, awserr.New(ErrCodeValidationException, fmt.Sprintf("KeyCondition cannot be nil for key: %s", a), nil) - } - return in, subs, vars, nil - } +func appendFilterCondition(in []byte, a string, c types.Condition, subs map[string]string, vars map[string]types.AttributeValue, keyCondition bool) ([]byte, map[string]string, map[string]types.AttributeValue, error) { op := c.ComparisonOperator - if op == nil || len(*op) == 0 { - return in, subs, vars, awserr.New(ErrCodeValidationException, fmt.Sprintf("One or more parameter values were invalid: AttributeValueList can only be used with a ComparisonOperator for Attribute: %s", a), nil) + if len(op) == 0 { + return in, subs, vars, &smithy.GenericAPIError{ + Code: ErrCodeValidationException, + Message: fmt.Sprintf("One or more parameter values were invalid: AttributeValueList can only be used with a ComparisonOperator for Attribute: %s", a), + Fault: smithy.FaultClient, + } } - return appendComparisonCondition(in, a, *op, c.AttributeValueList, subs, vars, keyCondition) + return appendComparisonCondition(in, a, op, c.AttributeValueList, subs, vars, keyCondition) } -func appendExistsCondition(in []byte, a string, eav *dynamodb.ExpectedAttributeValue, subs map[string]*string, vars map[string]*dynamodb.AttributeValue) ([]byte, map[string]*string, map[string]*dynamodb.AttributeValue, error) { +func appendExistsCondition(in []byte, a string, eav types.ExpectedAttributeValue, subs map[string]string, vars map[string]types.AttributeValue) ([]byte, map[string]string, map[string]types.AttributeValue, error) { if len(eav.AttributeValueList) != 0 { - return in, subs, vars, awserr.New(ErrCodeValidationException, fmt.Sprintf("One or more parameter values were invalid: AttributeValueList can only be used with a ComparisonOperator for Attribute: %s", a), nil) + return in, subs, vars, &smithy.GenericAPIError{ + Code: ErrCodeValidationException, + Message: fmt.Sprintf("One or more parameter values were invalid: AttributeValueList can only be used with a ComparisonOperator for Attribute: %s", a), + Fault: smithy.FaultClient, + } } if eav.Exists == nil || *eav.Exists { if eav.Value == nil { @@ -440,18 +473,26 @@ func appendExistsCondition(in []byte, a string, eav *dynamodb.ExpectedAttributeV } else { s = fmt.Sprintf("%v", *eav.Exists) } - return in, subs, vars, awserr.New(ErrCodeValidationException, fmt.Sprintf("One or more parameter values were invalid: Value must be provided when Exists is %s for Attribute: %s", s, a), nil) + return in, subs, vars, &smithy.GenericAPIError{ + Code: ErrCodeValidationException, + Message: fmt.Sprintf("One or more parameter values were invalid: Value must be provided when Exists is %s for Attribute: %s", s, a), + Fault: smithy.FaultClient, + } } var an, av string subs, an = appendAttributeName(subs, a) - vars, av = appendAttributeValue(vars, *eav.Value) + vars, av = appendAttributeValue(vars, eav.Value) in = append(in, []byte(an)...) in = append(in, []byte(" = ")...) in = append(in, []byte(av)...) } else { if eav.Value != nil { - return in, subs, vars, awserr.New(ErrCodeValidationException, fmt.Sprintf("One or more parameter values were invalid: Value cannot be used when Exists is false for Attribute: %s", a), nil) + return in, subs, vars, &smithy.GenericAPIError{ + Code: ErrCodeValidationException, + Message: fmt.Sprintf("One or more parameter values were invalid: Value cannot be used when Exists is false for Attribute: %s", a), + Fault: smithy.FaultClient, + } } var an string @@ -463,67 +504,69 @@ func appendExistsCondition(in []byte, a string, eav *dynamodb.ExpectedAttributeV return in, subs, vars, nil } -func appendComparisonCondition(in []byte, a string, op string, avl []*dynamodb.AttributeValue, subs map[string]*string, vars map[string]*dynamodb.AttributeValue, keyCondition bool) ([]byte, map[string]*string, map[string]*dynamodb.AttributeValue, error) { +func appendComparisonCondition(in []byte, a string, op types.ComparisonOperator, avl []types.AttributeValue, subs map[string]string, vars map[string]types.AttributeValue, keyCondition bool) ([]byte, map[string]string, map[string]types.AttributeValue, error) { switch op { - case dynamodb.ComparisonOperatorBetween: + case types.ComparisonOperatorBetween: return appendBetweenCondition(in, a, op, avl, subs, vars) - case dynamodb.ComparisonOperatorBeginsWith: + case types.ComparisonOperatorBeginsWith: return appendBeginsWithCondition(in, a, op, avl, subs, vars) - case dynamodb.ComparisonOperatorContains: + case types.ComparisonOperatorContains: if err := validateNotKeyCondition(keyCondition, op); err != nil { return in, subs, vars, err } return appendContainsCondition(in, a, op, avl, subs, vars, true) - case dynamodb.ComparisonOperatorNotContains: + case types.ComparisonOperatorNotContains: if err := validateNotKeyCondition(keyCondition, op); err != nil { return in, subs, vars, err } return appendContainsCondition(in, a, op, avl, subs, vars, false) - case dynamodb.ComparisonOperatorNull: + case types.ComparisonOperatorNull: if err := validateNotKeyCondition(keyCondition, op); err != nil { return in, subs, vars, err } var err error in, subs, err = appendNullCondition(in, a, op, avl, subs, true) return in, subs, vars, err - case dynamodb.ComparisonOperatorNotNull: + case types.ComparisonOperatorNotNull: if err := validateNotKeyCondition(keyCondition, op); err != nil { return in, subs, vars, err } var err error in, subs, err = appendNullCondition(in, a, op, avl, subs, false) return in, subs, vars, err - case dynamodb.ComparisonOperatorIn: + case types.ComparisonOperatorIn: if err := validateNotKeyCondition(keyCondition, op); err != nil { return in, subs, vars, err } return appendInCondition(in, a, op, avl, subs, vars) default: - var eop string switch op { - case dynamodb.ComparisonOperatorEq: - eop = "=" - case dynamodb.ComparisonOperatorNe: + case types.ComparisonOperatorEq: + // do nothing + case types.ComparisonOperatorNe: if err := validateNotKeyCondition(keyCondition, op); err != nil { return in, subs, vars, err } - eop = "<>" - case dynamodb.ComparisonOperatorLe: - eop = "<=" - case dynamodb.ComparisonOperatorGe: - eop = ">=" - case dynamodb.ComparisonOperatorLt: - eop = "<" - case dynamodb.ComparisonOperatorGt: - eop = ">" + case types.ComparisonOperatorLe: + // do nothing + case types.ComparisonOperatorGe: + // do nothing + case types.ComparisonOperatorLt: + // do nothing + case types.ComparisonOperatorGt: + // do nothing default: - return in, subs, vars, awserr.New(ErrCodeValidationException, fmt.Sprintf("Unknown comparison operator: %s", op), nil) + return in, subs, vars, &smithy.GenericAPIError{ + Code: ErrCodeValidationException, + Message: fmt.Sprintf("Unknown comparison operator: %s", op), + Fault: smithy.FaultClient, + } } - return appendArithmeticComparisonCondition(in, a, eop, avl, subs, vars) + return appendArithmeticComparisonCondition(in, a, op, avl, subs, vars) } } -func appendBetweenCondition(in []byte, a string, op string, avl []*dynamodb.AttributeValue, subs map[string]*string, vars map[string]*dynamodb.AttributeValue) ([]byte, map[string]*string, map[string]*dynamodb.AttributeValue, error) { +func appendBetweenCondition(in []byte, a string, op types.ComparisonOperator, avl []types.AttributeValue, subs map[string]string, vars map[string]types.AttributeValue) ([]byte, map[string]string, map[string]types.AttributeValue, error) { if err := validateArgCount(2, avl, op, a); err != nil { return in, subs, vars, err } @@ -533,8 +576,8 @@ func appendBetweenCondition(in []byte, a string, op string, avl []*dynamodb.Attr var an, av0, av1 string subs, an = appendAttributeName(subs, a) - vars, av0 = appendAttributeValue(vars, *avl[0]) - vars, av1 = appendAttributeValue(vars, *avl[1]) + vars, av0 = appendAttributeValue(vars, avl[0]) + vars, av1 = appendAttributeValue(vars, avl[1]) in = append(in, []byte(an)...) in = append(in, []byte(" between ")...) in = append(in, []byte(av0)...) @@ -543,7 +586,7 @@ func appendBetweenCondition(in []byte, a string, op string, avl []*dynamodb.Attr return in, subs, vars, nil } -func appendBeginsWithCondition(in []byte, a string, op string, avl []*dynamodb.AttributeValue, subs map[string]*string, vars map[string]*dynamodb.AttributeValue) ([]byte, map[string]*string, map[string]*dynamodb.AttributeValue, error) { +func appendBeginsWithCondition(in []byte, a string, op types.ComparisonOperator, avl []types.AttributeValue, subs map[string]string, vars map[string]types.AttributeValue) ([]byte, map[string]string, map[string]types.AttributeValue, error) { if err := validateArgCount(1, avl, op, a); err != nil { return in, subs, vars, err } @@ -553,7 +596,7 @@ func appendBeginsWithCondition(in []byte, a string, op string, avl []*dynamodb.A var an, av0 string subs, an = appendAttributeName(subs, a) - vars, av0 = appendAttributeValue(vars, *avl[0]) + vars, av0 = appendAttributeValue(vars, avl[0]) in = append(in, []byte("begins_with(")...) in = append(in, []byte(an)...) in = append(in, []byte(",")...) @@ -562,7 +605,7 @@ func appendBeginsWithCondition(in []byte, a string, op string, avl []*dynamodb.A return in, subs, vars, nil } -func appendContainsCondition(in []byte, a string, op string, avl []*dynamodb.AttributeValue, subs map[string]*string, vars map[string]*dynamodb.AttributeValue, p bool) ([]byte, map[string]*string, map[string]*dynamodb.AttributeValue, error) { +func appendContainsCondition(in []byte, a string, op types.ComparisonOperator, avl []types.AttributeValue, subs map[string]string, vars map[string]types.AttributeValue, p bool) ([]byte, map[string]string, map[string]types.AttributeValue, error) { if err := validateArgCount(1, avl, op, a); err != nil { return in, subs, vars, err } @@ -572,7 +615,7 @@ func appendContainsCondition(in []byte, a string, op string, avl []*dynamodb.Att var an, av0 string subs, an = appendAttributeName(subs, a) - vars, av0 = appendAttributeValue(vars, *avl[0]) + vars, av0 = appendAttributeValue(vars, avl[0]) if !p { in = append(in, []byte("not ")...) @@ -585,7 +628,7 @@ func appendContainsCondition(in []byte, a string, op string, avl []*dynamodb.Att return in, subs, vars, nil } -func appendNullCondition(in []byte, a string, op string, avl []*dynamodb.AttributeValue, subs map[string]*string, p bool) ([]byte, map[string]*string, error) { +func appendNullCondition(in []byte, a string, op types.ComparisonOperator, avl []types.AttributeValue, subs map[string]string, p bool) ([]byte, map[string]string, error) { if err := validateArgCount(0, avl, op, a); err != nil { return in, subs, err } @@ -603,12 +646,20 @@ func appendNullCondition(in []byte, a string, op string, avl []*dynamodb.Attribu return in, subs, nil } -func appendInCondition(in []byte, a string, op string, avl []*dynamodb.AttributeValue, subs map[string]*string, vars map[string]*dynamodb.AttributeValue) ([]byte, map[string]*string, map[string]*dynamodb.AttributeValue, error) { +func appendInCondition(in []byte, a string, op types.ComparisonOperator, avl []types.AttributeValue, subs map[string]string, vars map[string]types.AttributeValue) ([]byte, map[string]string, map[string]types.AttributeValue, error) { if avl == nil { - return in, subs, vars, awserr.New(ErrCodeValidationException, fmt.Sprintf("One or more parameter values were invalid: AttributeValueList must be used with ComparisonOperator: %s for Attribute: %s", op, a), nil) + return in, subs, vars, &smithy.GenericAPIError{ + Code: ErrCodeValidationException, + Message: fmt.Sprintf("One or more parameter values were invalid: AttributeValueList must be used with ComparisonOperator: %s for Attribute: %s", op, a), + Fault: smithy.FaultClient, + } } if len(avl) == 0 { - return in, subs, vars, awserr.New(ErrCodeValidationException, fmt.Sprintf("One or more parameter values were invalid: Invalid number of argument(s)0 for the %s ComparisonOperator", op), nil) + return in, subs, vars, &smithy.GenericAPIError{ + Code: ErrCodeValidationException, + Message: fmt.Sprintf("One or more parameter values were invalid: Invalid number of argument(s)0 for the %s ComparisonOperator", op), + Fault: smithy.FaultClient, + } } if err := validateScalarAttribute(avl, op); err != nil { return in, subs, vars, err @@ -623,32 +674,36 @@ func appendInCondition(in []byte, a string, op string, avl []*dynamodb.Attribute return in, subs, vars, nil } -func appendArithmeticComparisonCondition(in []byte, a string, op string, avl []*dynamodb.AttributeValue, subs map[string]*string, vars map[string]*dynamodb.AttributeValue) ([]byte, map[string]*string, map[string]*dynamodb.AttributeValue, error) { +func appendArithmeticComparisonCondition(in []byte, a string, op types.ComparisonOperator, avl []types.AttributeValue, subs map[string]string, vars map[string]types.AttributeValue) ([]byte, map[string]string, map[string]types.AttributeValue, error) { if err := validateArgCount(1, avl, op, a); err != nil { return in, subs, vars, err } if err := validateScalarAttribute(avl, op); err != nil { return in, subs, vars, err } + eop, err := convertArithmeticComparisonOperator(op) + if err != nil { + return in, subs, vars, err + } var an, av0 string subs, an = appendAttributeName(subs, a) - vars, av0 = appendAttributeValue(vars, *avl[0]) + vars, av0 = appendAttributeValue(vars, avl[0]) in = append(in, []byte(an)...) in = append(in, []byte(" ")...) - in = append(in, []byte(op)...) + in = append(in, []byte(eop)...) in = append(in, []byte(" ")...) in = append(in, []byte(av0)...) return in, subs, vars, nil } -func appendAttributeName(subs map[string]*string, a string) (map[string]*string, string) { +func appendAttributeName(subs map[string]string, a string) (map[string]string, string) { if len(a) == 0 { return subs, "" } if subs == nil { - subs = make(map[string]*string) + subs = make(map[string]string) } l := len(subs) k := fmt.Sprintf("%s%d", attributeNamesKeyPrefix, l) @@ -656,13 +711,13 @@ func appendAttributeName(subs map[string]*string, a string) (map[string]*string, l++ k = fmt.Sprintf("%s%d", attributeNamesKeyPrefix, l) } - subs[k] = &a + subs[k] = a return subs, k } -func appendAttributeValue(vars map[string]*dynamodb.AttributeValue, av dynamodb.AttributeValue) (map[string]*dynamodb.AttributeValue, string) { +func appendAttributeValue(vars map[string]types.AttributeValue, av types.AttributeValue) (map[string]types.AttributeValue, string) { if vars == nil { - vars = make(map[string]*dynamodb.AttributeValue) + vars = make(map[string]types.AttributeValue) } l := len(vars) k := fmt.Sprintf("%s%d", attributeValuesKeyPrefix, l) @@ -670,69 +725,115 @@ func appendAttributeValue(vars map[string]*dynamodb.AttributeValue, av dynamodb. l++ k = fmt.Sprintf("%s%d", attributeValuesKeyPrefix, l) } - vars[k] = &av + vars[k] = av return vars, k } -func validateArgCount(e int, a []*dynamodb.AttributeValue, op, n string) error { +func validateArgCount(e int, a []types.AttributeValue, op types.ComparisonOperator, n string) error { if a == nil && e > 0 { - return awserr.New(ErrCodeValidationException, fmt.Sprintf("One or more parameter values were invalid: Value or AttributeValueList must be used with ComparisonOperator: %s for Attribute %s", op, n), nil) + return &smithy.GenericAPIError{ + Code: ErrCodeValidationException, + Message: fmt.Sprintf("One or more parameter values were invalid: Value or AttributeValueList must be used with ComparisonOperator: %s for Attribute %s", op, n), + Fault: smithy.FaultClient, + } } if len(a) != e { - return awserr.New(ErrCodeValidationException, fmt.Sprintf("One or more parameter values were invalid: Invalid number of argument(s) for the %s ComparisonOperator", op), nil) + return &smithy.GenericAPIError{ + Code: ErrCodeValidationException, + Message: fmt.Sprintf("One or more parameter values were invalid: Invalid number of argument(s) for the %s ComparisonOperator", op), + Fault: smithy.FaultClient, + } } for _, i := range a { if i == nil { - return awserr.New(ErrCodeValidationException, fmt.Sprintf("One or more parameter values were invalid: Invalid number of argument(s) for the %s ComparisonOperator", op), nil) + return &smithy.GenericAPIError{ + Code: ErrCodeValidationException, + Message: fmt.Sprintf("One or more parameter values were invalid: Invalid number of argument(s) for the %s ComparisonOperator", op), + Fault: smithy.FaultClient, + } } } return nil } -func validateScalarAttribute(avl []*dynamodb.AttributeValue, op string) error { - if op == "=" || op == "<>" { +func validateScalarAttribute(avl []types.AttributeValue, op types.ComparisonOperator) error { + if op == types.ComparisonOperatorEq || op == types.ComparisonOperatorNe { return nil } for _, v := range avl { if v != nil { - if v.S == nil && v.N == nil && v.B == nil { - return awserr.New(ErrCodeValidationException, fmt.Sprintf("One or more parameter values were invalid: ComparisonOperator %s is not valid for %s AttributeValue type", op, attributeTypeName(*v)), nil) + switch v.(type) { + case *types.AttributeValueMemberS, *types.AttributeValueMemberN, *types.AttributeValueMemberB: + // ok + default: + return &smithy.GenericAPIError{ + Code: ErrCodeValidationException, + Message: fmt.Sprintf("One or more parameter values were invalid: ComparisonOperator %s is not valid for %s AttributeValue type", op, attributeTypeName(v)), + Fault: smithy.FaultClient, + } } } } return nil } -func validateNotKeyCondition(kc bool, op string) error { +func validateNotKeyCondition(kc bool, op types.ComparisonOperator) error { if kc { - return awserr.New(ErrCodeValidationException, fmt.Sprintf("Unsupported operator on KeyCondition: %s", op), nil) + return &smithy.GenericAPIError{ + Code: ErrCodeValidationException, + Message: fmt.Sprintf("Unsupported operator on KeyCondition: %s", op), + Fault: smithy.FaultClient, + } } return nil } -func attributeTypeName(v dynamodb.AttributeValue) string { - switch { - case v.S != nil: - return dynamodb.ScalarAttributeTypeS - case v.N != nil: - return dynamodb.ScalarAttributeTypeN - case v.B != nil: - return dynamodb.ScalarAttributeTypeB - case len(v.SS) > 0: +func attributeTypeName(v types.AttributeValue) string { + switch v.(type) { + case *types.AttributeValueMemberS: + return string(types.ScalarAttributeTypeS) + case *types.AttributeValueMemberN: + return string(types.ScalarAttributeTypeN) + case *types.AttributeValueMemberB: + return string(types.ScalarAttributeTypeB) + case *types.AttributeValueMemberSS: return "SS" - case len(v.NS) > 0: + case *types.AttributeValueMemberNS: return "NS" - case len(v.BS) > 0: + case *types.AttributeValueMemberBS: return "BS" - case len(v.M) > 0: + case *types.AttributeValueMemberM: return "M" - case len(v.L) > 0: + case *types.AttributeValueMemberL: return "L" - case v.BOOL != nil: + case *types.AttributeValueMemberBOOL: return "BOOL" - case v.NULL != nil: + case *types.AttributeValueMemberNULL: return "NULL" default: return "" } } + +func convertArithmeticComparisonOperator(op types.ComparisonOperator) (string, error) { + // convert inequality operator + switch op { + case types.ComparisonOperatorEq: + return "=", nil + case types.ComparisonOperatorNe: + return "<>", nil + case types.ComparisonOperatorLe: + return "<=", nil + case types.ComparisonOperatorGe: + return ">=", nil + case types.ComparisonOperatorLt: + return "<", nil + case types.ComparisonOperatorGt: + return ">", nil + } + return "", &smithy.GenericAPIError{ + Code: ErrCodeValidationException, + Message: fmt.Sprintf("Unknown arithmetic comparison operator: %s", op), + Fault: smithy.FaultClient, + } +} diff --git a/dax/internal/client/legacy_test.go b/dax/internal/client/legacy_test.go index 0bb7b30..a0d7df8 100644 --- a/dax/internal/client/legacy_test.go +++ b/dax/internal/client/legacy_test.go @@ -16,11 +16,13 @@ package client import ( - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/service/dynamodb" "reflect" "testing" + + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/dynamodb" + "github.com/aws/aws-sdk-go-v2/service/dynamodb/types" + "github.com/aws/smithy-go" ) var functions = map[reflect.Type]interface{}{ @@ -40,304 +42,339 @@ func TestTranslateLegacyPositive(t *testing.T) { }{ { &dynamodb.GetItemInput{ - AttributesToGet: []*string{aws.String("a1"), aws.String("a2")}, + AttributesToGet: []string{"a1", "a2"}, }, &dynamodb.GetItemInput{ ProjectionExpression: aws.String("#key0,#key1"), - ExpressionAttributeNames: map[string]*string{"#key0": aws.String("a1"), "#key1": aws.String("a2")}, + ExpressionAttributeNames: map[string]string{"#key0": "a1", "#key1": "a2"}, }, }, { &dynamodb.PutItemInput{ - Expected: map[string]*dynamodb.ExpectedAttributeValue{ - "a": {Exists: aws.Bool(true), Value: &dynamodb.AttributeValue{N: aws.String("5")}}, + Expected: map[string]types.ExpectedAttributeValue{ + "a": {Exists: aws.Bool(true), Value: &types.AttributeValueMemberN{Value: "5"}}, }, }, &dynamodb.PutItemInput{ ConditionExpression: aws.String("#key0 = :val0"), - ExpressionAttributeNames: map[string]*string{"#key0": aws.String("a")}, - ExpressionAttributeValues: map[string]*dynamodb.AttributeValue{":val0": {N: aws.String("5")}}, + ExpressionAttributeNames: map[string]string{"#key0": "a"}, + ExpressionAttributeValues: map[string]types.AttributeValue{":val0": &types.AttributeValueMemberN{Value: "5"}}, }, }, { &dynamodb.PutItemInput{ - Expected: map[string]*dynamodb.ExpectedAttributeValue{ + Expected: map[string]types.ExpectedAttributeValue{ "a": {Exists: aws.Bool(false)}, }, }, &dynamodb.PutItemInput{ ConditionExpression: aws.String("attribute_not_exists(#key0)"), - ExpressionAttributeNames: map[string]*string{"#key0": aws.String("a")}, + ExpressionAttributeNames: map[string]string{"#key0": "a"}, }, }, { &dynamodb.PutItemInput{ - Expected: map[string]*dynamodb.ExpectedAttributeValue{ - "a": {ComparisonOperator: aws.String(dynamodb.ComparisonOperatorBetween), - AttributeValueList: []*dynamodb.AttributeValue{{N: aws.String("5")}, {N: aws.String("6")}}}, + Expected: map[string]types.ExpectedAttributeValue{ + "a": {ComparisonOperator: types.ComparisonOperatorBetween, + AttributeValueList: []types.AttributeValue{ + &types.AttributeValueMemberN{Value: "5"}, + &types.AttributeValueMemberN{Value: "6"}, + }}, }, }, &dynamodb.PutItemInput{ - ConditionExpression: aws.String("#key0 between :val0 and :val1"), - ExpressionAttributeNames: map[string]*string{"#key0": aws.String("a")}, - ExpressionAttributeValues: map[string]*dynamodb.AttributeValue{":val0": {N: aws.String("5")}, ":val1": {N: aws.String("6")}}, + ConditionExpression: aws.String("#key0 between :val0 and :val1"), + ExpressionAttributeNames: map[string]string{"#key0": "a"}, + ExpressionAttributeValues: map[string]types.AttributeValue{ + ":val0": &types.AttributeValueMemberN{Value: "5"}, + ":val1": &types.AttributeValueMemberN{Value: "6"}}, }, }, { &dynamodb.PutItemInput{ - Expected: map[string]*dynamodb.ExpectedAttributeValue{ - "a": {ComparisonOperator: aws.String(dynamodb.ComparisonOperatorBeginsWith), - AttributeValueList: []*dynamodb.AttributeValue{{S: aws.String("abc")}}}, + Expected: map[string]types.ExpectedAttributeValue{ + "a": {ComparisonOperator: types.ComparisonOperatorBeginsWith, + AttributeValueList: []types.AttributeValue{&types.AttributeValueMemberS{Value: "abc"}}}, }, }, &dynamodb.PutItemInput{ - ConditionExpression: aws.String("begins_with(#key0,:val0)"), - ExpressionAttributeNames: map[string]*string{"#key0": aws.String("a")}, - ExpressionAttributeValues: map[string]*dynamodb.AttributeValue{":val0": {S: aws.String("abc")}}, + ConditionExpression: aws.String("begins_with(#key0,:val0)"), + ExpressionAttributeNames: map[string]string{"#key0": "a"}, + ExpressionAttributeValues: map[string]types.AttributeValue{ + ":val0": &types.AttributeValueMemberS{Value: "abc"}, + }, }, }, { &dynamodb.PutItemInput{ - Expected: map[string]*dynamodb.ExpectedAttributeValue{ - "a": {ComparisonOperator: aws.String(dynamodb.ComparisonOperatorContains), - AttributeValueList: []*dynamodb.AttributeValue{{S: aws.String("abc")}}}, + Expected: map[string]types.ExpectedAttributeValue{ + "a": {ComparisonOperator: types.ComparisonOperatorContains, + AttributeValueList: []types.AttributeValue{&types.AttributeValueMemberS{Value: "abc"}}}, }, }, &dynamodb.PutItemInput{ - ConditionExpression: aws.String("contains(#key0,:val0)"), - ExpressionAttributeNames: map[string]*string{"#key0": aws.String("a")}, - ExpressionAttributeValues: map[string]*dynamodb.AttributeValue{":val0": {S: aws.String("abc")}}, + ConditionExpression: aws.String("contains(#key0,:val0)"), + ExpressionAttributeNames: map[string]string{"#key0": "a"}, + ExpressionAttributeValues: map[string]types.AttributeValue{ + ":val0": &types.AttributeValueMemberS{Value: "abc"}, + }, }, }, { &dynamodb.PutItemInput{ - Expected: map[string]*dynamodb.ExpectedAttributeValue{ - "a": {ComparisonOperator: aws.String(dynamodb.ComparisonOperatorNotContains), - AttributeValueList: []*dynamodb.AttributeValue{{S: aws.String("abc")}}}, + Expected: map[string]types.ExpectedAttributeValue{ + "a": {ComparisonOperator: types.ComparisonOperatorNotContains, + AttributeValueList: []types.AttributeValue{&types.AttributeValueMemberS{Value: "abc"}}}, }, }, &dynamodb.PutItemInput{ - ConditionExpression: aws.String("not contains(#key0,:val0)"), - ExpressionAttributeNames: map[string]*string{"#key0": aws.String("a")}, - ExpressionAttributeValues: map[string]*dynamodb.AttributeValue{":val0": {S: aws.String("abc")}}, + ConditionExpression: aws.String("not contains(#key0,:val0)"), + ExpressionAttributeNames: map[string]string{"#key0": "a"}, + ExpressionAttributeValues: map[string]types.AttributeValue{ + ":val0": &types.AttributeValueMemberS{Value: "abc"}, + }, }, }, { &dynamodb.PutItemInput{ - Expected: map[string]*dynamodb.ExpectedAttributeValue{ - "a": {ComparisonOperator: aws.String(dynamodb.ComparisonOperatorNull)}, + Expected: map[string]types.ExpectedAttributeValue{ + "a": {ComparisonOperator: types.ComparisonOperatorNull}, }, }, &dynamodb.PutItemInput{ ConditionExpression: aws.String("attribute_not_exists(#key0)"), - ExpressionAttributeNames: map[string]*string{"#key0": aws.String("a")}, + ExpressionAttributeNames: map[string]string{"#key0": "a"}, }, }, { &dynamodb.PutItemInput{ - Expected: map[string]*dynamodb.ExpectedAttributeValue{ - "a": {ComparisonOperator: aws.String(dynamodb.ComparisonOperatorNotNull)}, + Expected: map[string]types.ExpectedAttributeValue{ + "a": {ComparisonOperator: types.ComparisonOperatorNotNull}, }, }, &dynamodb.PutItemInput{ ConditionExpression: aws.String("attribute_exists(#key0)"), - ExpressionAttributeNames: map[string]*string{"#key0": aws.String("a")}, + ExpressionAttributeNames: map[string]string{"#key0": "a"}, }, }, { &dynamodb.PutItemInput{ - Expected: map[string]*dynamodb.ExpectedAttributeValue{ - "a": {ComparisonOperator: aws.String(dynamodb.ComparisonOperatorIn), - AttributeValueList: []*dynamodb.AttributeValue{{S: aws.String("abc")}, {S: aws.String("def")}, {S: aws.String("ghi")}}}, + Expected: map[string]types.ExpectedAttributeValue{ + "a": {ComparisonOperator: types.ComparisonOperatorIn, + AttributeValueList: []types.AttributeValue{ + &types.AttributeValueMemberS{Value: "abc"}, + &types.AttributeValueMemberS{Value: "def"}, + &types.AttributeValueMemberS{Value: "ghi"}, + }, + }, }, }, &dynamodb.PutItemInput{ - ConditionExpression: aws.String("#key0 in (:val0,:val1,:val2)"), - ExpressionAttributeNames: map[string]*string{"#key0": aws.String("a")}, - ExpressionAttributeValues: map[string]*dynamodb.AttributeValue{":val0": {S: aws.String("abc")}, ":val1": {S: aws.String("def")}, ":val2": {S: aws.String("ghi")}}, + ConditionExpression: aws.String("#key0 in (:val0,:val1,:val2)"), + ExpressionAttributeNames: map[string]string{"#key0": "a"}, + ExpressionAttributeValues: map[string]types.AttributeValue{ + ":val0": &types.AttributeValueMemberS{Value: "abc"}, + ":val1": &types.AttributeValueMemberS{Value: "def"}, + ":val2": &types.AttributeValueMemberS{Value: "ghi"}}, }, }, { &dynamodb.PutItemInput{ - Expected: map[string]*dynamodb.ExpectedAttributeValue{ - "a": {ComparisonOperator: aws.String(dynamodb.ComparisonOperatorNe), - AttributeValueList: []*dynamodb.AttributeValue{{S: aws.String("abc")}}}, + Expected: map[string]types.ExpectedAttributeValue{ + "a": {ComparisonOperator: types.ComparisonOperatorNe, + AttributeValueList: []types.AttributeValue{&types.AttributeValueMemberS{Value: "abc"}}}, }, }, &dynamodb.PutItemInput{ - ConditionExpression: aws.String("#key0 <> :val0"), - ExpressionAttributeNames: map[string]*string{"#key0": aws.String("a")}, - ExpressionAttributeValues: map[string]*dynamodb.AttributeValue{":val0": {S: aws.String("abc")}}, + ConditionExpression: aws.String("#key0 <> :val0"), + ExpressionAttributeNames: map[string]string{"#key0": "a"}, + ExpressionAttributeValues: map[string]types.AttributeValue{ + ":val0": &types.AttributeValueMemberS{Value: "abc"}, + }, }, }, { &dynamodb.DeleteItemInput{ - Expected: map[string]*dynamodb.ExpectedAttributeValue{ - "a": {ComparisonOperator: aws.String(dynamodb.ComparisonOperatorEq), - AttributeValueList: []*dynamodb.AttributeValue{{S: aws.String("abc")}}}, + Expected: map[string]types.ExpectedAttributeValue{ + "a": {ComparisonOperator: types.ComparisonOperatorEq, + AttributeValueList: []types.AttributeValue{&types.AttributeValueMemberS{Value: "abc"}}}, }, }, &dynamodb.DeleteItemInput{ - ConditionExpression: aws.String("#key0 = :val0"), - ExpressionAttributeNames: map[string]*string{"#key0": aws.String("a")}, - ExpressionAttributeValues: map[string]*dynamodb.AttributeValue{":val0": {S: aws.String("abc")}}, + ConditionExpression: aws.String("#key0 = :val0"), + ExpressionAttributeNames: map[string]string{"#key0": "a"}, + ExpressionAttributeValues: map[string]types.AttributeValue{ + ":val0": &types.AttributeValueMemberS{Value: "abc"}, + }, }, }, { &dynamodb.UpdateItemInput{ - Expected: map[string]*dynamodb.ExpectedAttributeValue{ - "a": {ComparisonOperator: aws.String(dynamodb.ComparisonOperatorLe), - AttributeValueList: []*dynamodb.AttributeValue{{S: aws.String("abc")}}}, + Expected: map[string]types.ExpectedAttributeValue{ + "a": {ComparisonOperator: types.ComparisonOperatorLe, + AttributeValueList: []types.AttributeValue{&types.AttributeValueMemberS{Value: "abc"}}}, }, - AttributeUpdates: map[string]*dynamodb.AttributeValueUpdate{ - "b": {Value: &dynamodb.AttributeValue{S: aws.String("def")}}, + AttributeUpdates: map[string]types.AttributeValueUpdate{ + "b": {Value: &types.AttributeValueMemberS{Value: "def"}}, }, }, &dynamodb.UpdateItemInput{ ConditionExpression: aws.String("#key0 <= :val0"), UpdateExpression: aws.String("set #key1=:val1"), - ExpressionAttributeNames: map[string]*string{ - "#key0": aws.String("a"), - "#key1": aws.String("b"), + ExpressionAttributeNames: map[string]string{ + "#key0": "a", + "#key1": "b", }, - ExpressionAttributeValues: map[string]*dynamodb.AttributeValue{ - ":val0": {S: aws.String("abc")}, - ":val1": {S: aws.String("def")}, + ExpressionAttributeValues: map[string]types.AttributeValue{ + ":val0": &types.AttributeValueMemberS{Value: "abc"}, + ":val1": &types.AttributeValueMemberS{Value: "def"}, }, }, }, { &dynamodb.UpdateItemInput{ - AttributeUpdates: map[string]*dynamodb.AttributeValueUpdate{ - "a": {Action: aws.String(dynamodb.AttributeActionPut), Value: &dynamodb.AttributeValue{S: aws.String("def")}}, + AttributeUpdates: map[string]types.AttributeValueUpdate{ + "a": {Action: types.AttributeActionPut, Value: &types.AttributeValueMemberS{Value: "def"}}, }, }, &dynamodb.UpdateItemInput{ UpdateExpression: aws.String("set #key0=:val0"), - ExpressionAttributeNames: map[string]*string{ - "#key0": aws.String("a"), + ExpressionAttributeNames: map[string]string{ + "#key0": "a", }, - ExpressionAttributeValues: map[string]*dynamodb.AttributeValue{ - ":val0": {S: aws.String("def")}, + ExpressionAttributeValues: map[string]types.AttributeValue{ + ":val0": &types.AttributeValueMemberS{Value: "def"}, }, }, }, { &dynamodb.UpdateItemInput{ - AttributeUpdates: map[string]*dynamodb.AttributeValueUpdate{ - "a": {Action: aws.String(dynamodb.AttributeActionAdd), Value: &dynamodb.AttributeValue{S: aws.String("def")}}, + AttributeUpdates: map[string]types.AttributeValueUpdate{ + "a": { + Action: types.AttributeActionAdd, + Value: &types.AttributeValueMemberS{Value: "def"}}, }, }, &dynamodb.UpdateItemInput{ UpdateExpression: aws.String("add #key0 :val0"), - ExpressionAttributeNames: map[string]*string{ - "#key0": aws.String("a"), + ExpressionAttributeNames: map[string]string{ + "#key0": "a", }, - ExpressionAttributeValues: map[string]*dynamodb.AttributeValue{ - ":val0": {S: aws.String("def")}, + ExpressionAttributeValues: map[string]types.AttributeValue{ + ":val0": &types.AttributeValueMemberS{Value: "def"}, }, }, }, { &dynamodb.UpdateItemInput{ - AttributeUpdates: map[string]*dynamodb.AttributeValueUpdate{ - "a": {Action: aws.String(dynamodb.AttributeActionDelete), Value: &dynamodb.AttributeValue{S: aws.String("def")}}, + AttributeUpdates: map[string]types.AttributeValueUpdate{ + "a": { + Action: types.AttributeActionDelete, + Value: &types.AttributeValueMemberS{Value: "def"}}, }, }, &dynamodb.UpdateItemInput{ UpdateExpression: aws.String("delete #key0 :val0"), - ExpressionAttributeNames: map[string]*string{ - "#key0": aws.String("a"), + ExpressionAttributeNames: map[string]string{ + "#key0": "a", }, - ExpressionAttributeValues: map[string]*dynamodb.AttributeValue{ - ":val0": {S: aws.String("def")}, + ExpressionAttributeValues: map[string]types.AttributeValue{ + ":val0": &types.AttributeValueMemberS{Value: "def"}, }, }, }, { &dynamodb.UpdateItemInput{ - AttributeUpdates: map[string]*dynamodb.AttributeValueUpdate{ - "a": {Action: aws.String(dynamodb.AttributeActionDelete)}, + AttributeUpdates: map[string]types.AttributeValueUpdate{ + "a": {Action: types.AttributeActionDelete}, }, }, &dynamodb.UpdateItemInput{ UpdateExpression: aws.String("remove #key0"), - ExpressionAttributeNames: map[string]*string{ - "#key0": aws.String("a"), + ExpressionAttributeNames: map[string]string{ + "#key0": "a", }, }, }, { &dynamodb.ScanInput{ - AttributesToGet: []*string{aws.String("a1"), aws.String("a2")}, - ConditionalOperator: aws.String(dynamodb.ConditionalOperatorOr), - ScanFilter: map[string]*dynamodb.Condition{ - "a": {ComparisonOperator: aws.String(dynamodb.ComparisonOperatorGe), AttributeValueList: []*dynamodb.AttributeValue{{N: aws.String("5")}}}, + AttributesToGet: []string{"a1", "a2"}, + ConditionalOperator: types.ConditionalOperatorOr, + ScanFilter: map[string]types.Condition{ + "a": { + ComparisonOperator: types.ComparisonOperatorGe, + AttributeValueList: []types.AttributeValue{&types.AttributeValueMemberN{Value: "5"}}}, }, }, &dynamodb.ScanInput{ ProjectionExpression: aws.String("#key0,#key1"), FilterExpression: aws.String("#key2 >= :val0"), - ExpressionAttributeNames: map[string]*string{ - "#key0": aws.String("a1"), - "#key1": aws.String("a2"), - "#key2": aws.String("a"), + ExpressionAttributeNames: map[string]string{ + "#key0": "a1", + "#key1": "a2", + "#key2": "a", }, - ExpressionAttributeValues: map[string]*dynamodb.AttributeValue{ - ":val0": {N: aws.String("5")}, + ExpressionAttributeValues: map[string]types.AttributeValue{ + ":val0": &types.AttributeValueMemberN{Value: "5"}, }, }, }, { &dynamodb.QueryInput{ - AttributesToGet: []*string{aws.String("a1"), aws.String("a2")}, - ConditionalOperator: aws.String(dynamodb.ConditionalOperatorOr), - QueryFilter: map[string]*dynamodb.Condition{ - "a": {ComparisonOperator: aws.String(dynamodb.ComparisonOperatorGe), AttributeValueList: []*dynamodb.AttributeValue{{N: aws.String("5")}}}, + AttributesToGet: []string{"a1", "a2"}, + ConditionalOperator: types.ConditionalOperatorOr, + QueryFilter: map[string]types.Condition{ + "a": { + ComparisonOperator: types.ComparisonOperatorGe, + AttributeValueList: []types.AttributeValue{&types.AttributeValueMemberN{Value: "5"}}, + }, }, - KeyConditions: map[string]*dynamodb.Condition{ - "k": {ComparisonOperator: aws.String(dynamodb.ComparisonOperatorEq), AttributeValueList: []*dynamodb.AttributeValue{{S: aws.String("abc")}}}, + KeyConditions: map[string]types.Condition{ + "k": { + ComparisonOperator: types.ComparisonOperatorEq, + AttributeValueList: []types.AttributeValue{&types.AttributeValueMemberS{Value: "abc"}}, + }, }, }, &dynamodb.QueryInput{ ProjectionExpression: aws.String("#key0,#key1"), FilterExpression: aws.String("#key2 >= :val0"), KeyConditionExpression: aws.String("#key3 = :val1"), - ExpressionAttributeNames: map[string]*string{ - "#key0": aws.String("a1"), - "#key1": aws.String("a2"), - "#key2": aws.String("a"), - "#key3": aws.String("k"), + ExpressionAttributeNames: map[string]string{ + "#key0": "a1", + "#key1": "a2", + "#key2": "a", + "#key3": "k", }, - ExpressionAttributeValues: map[string]*dynamodb.AttributeValue{ - ":val0": {N: aws.String("5")}, - ":val1": {S: aws.String("abc")}, + ExpressionAttributeValues: map[string]types.AttributeValue{ + ":val0": &types.AttributeValueMemberN{Value: "5"}, + ":val1": &types.AttributeValueMemberS{Value: "abc"}, }, }, }, { - &dynamodb.BatchGetItemInput{ - RequestItems: map[string]*dynamodb.KeysAndAttributes{ - "table1": {AttributesToGet: []*string{aws.String("a1"), aws.String("a2")}}, - "table2": {AttributesToGet: []*string{aws.String("a3"), aws.String("a4")}}, + inp: &dynamodb.BatchGetItemInput{ + RequestItems: map[string]types.KeysAndAttributes{ + "table1": {AttributesToGet: []string{"a1", "a2"}}, + "table2": {AttributesToGet: []string{"a3", "a4"}}, }, }, - &dynamodb.BatchGetItemInput{ - RequestItems: map[string]*dynamodb.KeysAndAttributes{ + exp: &dynamodb.BatchGetItemInput{ + RequestItems: map[string]types.KeysAndAttributes{ "table1": { - AttributesToGet: []*string{aws.String("a1"), aws.String("a2")}, + AttributesToGet: []string{"a1", "a2"}, ProjectionExpression: aws.String("#key0,#key1"), - ExpressionAttributeNames: map[string]*string{ - "#key0": aws.String("a1"), - "#key1": aws.String("a2"), + ExpressionAttributeNames: map[string]string{ + "#key0": "a1", + "#key1": "a2", }, }, "table2": { - AttributesToGet: []*string{aws.String("a3"), aws.String("a4")}, + AttributesToGet: []string{"a3", "a4"}, ProjectionExpression: aws.String("#key0,#key1"), - ExpressionAttributeNames: map[string]*string{ - "#key0": aws.String("a3"), - "#key1": aws.String("a4"), + ExpressionAttributeNames: map[string]string{ + "#key0": "a3", + "#key1": "a4", }, }, }, @@ -361,95 +398,148 @@ func TestTranslateLegacyPositive(t *testing.T) { func TestTranslateLegacyNegative(t *testing.T) { cases := []struct { inp interface{} - err awserr.Error + err error }{ { &dynamodb.GetItemInput{ - AttributesToGet: []*string{aws.String("a1"), aws.String("a2")}, + AttributesToGet: []string{"a1", "a2"}, ProjectionExpression: aws.String("a1, a2"), }, - awserr.New(ErrCodeValidationException, "Cannot specify both AttributesToGet and ProjectionExpression", nil), + &smithy.GenericAPIError{ + Code: ErrCodeValidationException, + Message: "Cannot specify both AttributesToGet and ProjectionExpression", + Fault: smithy.FaultClient, + }, }, { &dynamodb.PutItemInput{ - ConditionExpression: aws.String("a < :v"), - Expected: map[string]*dynamodb.ExpectedAttributeValue{"a": {Exists: aws.Bool(true), Value: &dynamodb.AttributeValue{N: aws.String("5")}}}, - ExpressionAttributeValues: map[string]*dynamodb.AttributeValue{":v": {N: aws.String("5")}}, + ConditionExpression: aws.String("a < :v"), + Expected: map[string]types.ExpectedAttributeValue{ + "a": {Exists: aws.Bool(true), Value: &types.AttributeValueMemberN{Value: "5"}}, + }, + ExpressionAttributeValues: map[string]types.AttributeValue{":v": &types.AttributeValueMemberN{Value: "5"}}, + }, + &smithy.GenericAPIError{ + Code: ErrCodeValidationException, + Message: "Cannot specify both Expected and ConditionExpression", + Fault: smithy.FaultClient, }, - awserr.New(ErrCodeValidationException, "Cannot specify both Expected and ConditionExpression", nil), }, { &dynamodb.PutItemInput{ - Expected: map[string]*dynamodb.ExpectedAttributeValue{ + Expected: map[string]types.ExpectedAttributeValue{ "a": { - Value: &dynamodb.AttributeValue{N: aws.String("5")}, - AttributeValueList: []*dynamodb.AttributeValue{{N: aws.String("5")}}, + Value: &types.AttributeValueMemberN{Value: "5"}, + AttributeValueList: []types.AttributeValue{&types.AttributeValueMemberN{Value: "5"}}, }, }, }, - awserr.New(ErrCodeValidationException, "One or more parameter values were invalid: Value and AttributeValueList cannot be used together for Attribute: a", nil), + &smithy.GenericAPIError{ + Code: ErrCodeValidationException, + Message: "One or more parameter values were invalid: Value and AttributeValueList cannot be used together for Attribute: a", + Fault: smithy.FaultClient, + }, }, { &dynamodb.PutItemInput{ - Expected: map[string]*dynamodb.ExpectedAttributeValue{ - "a": {AttributeValueList: []*dynamodb.AttributeValue{{N: aws.String("5")}}}, + Expected: map[string]types.ExpectedAttributeValue{ + "a": {AttributeValueList: []types.AttributeValue{&types.AttributeValueMemberN{Value: "5"}}}, }, }, - awserr.New(ErrCodeValidationException, "One or more parameter values were invalid: AttributeValueList can only be used with a ComparisonOperator for Attribute: a", nil), + &smithy.GenericAPIError{ + Code: ErrCodeValidationException, + Message: "One or more parameter values were invalid: AttributeValueList can only be used with a ComparisonOperator for Attribute: a", + Fault: smithy.FaultClient, + }, }, { &dynamodb.PutItemInput{ - Expected: map[string]*dynamodb.ExpectedAttributeValue{ + Expected: map[string]types.ExpectedAttributeValue{ "a": {Exists: aws.Bool(true)}, }, }, - awserr.New(ErrCodeValidationException, "One or more parameter values were invalid: Value must be provided when Exists is true for Attribute: a", nil), + &smithy.GenericAPIError{ + Code: ErrCodeValidationException, + Message: "One or more parameter values were invalid: Value must be provided when Exists is true for Attribute: a", + Fault: smithy.FaultClient, + }, }, { &dynamodb.PutItemInput{ - Expected: map[string]*dynamodb.ExpectedAttributeValue{ - "a": {Exists: aws.Bool(false), Value: &dynamodb.AttributeValue{N: aws.String("5")}}, + Expected: map[string]types.ExpectedAttributeValue{ + "a": {Exists: aws.Bool(false), Value: &types.AttributeValueMemberN{Value: "5"}}, }, }, - awserr.New(ErrCodeValidationException, "One or more parameter values were invalid: Value cannot be used when Exists is false for Attribute: a", nil), + &smithy.GenericAPIError{ + Code: ErrCodeValidationException, + Message: "One or more parameter values were invalid: Value cannot be used when Exists is false for Attribute: a", + Fault: smithy.FaultClient, + }, }, { &dynamodb.PutItemInput{ - Expected: map[string]*dynamodb.ExpectedAttributeValue{ - "a": {ComparisonOperator: aws.String(dynamodb.ComparisonOperatorBetween), AttributeValueList: []*dynamodb.AttributeValue{{N: aws.String("5")}, {NULL: aws.Bool(true)}}}, + Expected: map[string]types.ExpectedAttributeValue{ + "a": { + ComparisonOperator: types.ComparisonOperatorBetween, + AttributeValueList: []types.AttributeValue{ + &types.AttributeValueMemberN{Value: "5"}, + &types.AttributeValueMemberNULL{Value: true}}}, }, }, - awserr.New(ErrCodeValidationException, "One or more parameter values were invalid: ComparisonOperator BETWEEN is not valid for NULL AttributeValue type", nil), + &smithy.GenericAPIError{ + Code: ErrCodeValidationException, + Message: "One or more parameter values were invalid: ComparisonOperator BETWEEN is not valid for NULL AttributeValue type", + Fault: smithy.FaultClient, + }, }, { &dynamodb.UpdateItemInput{ UpdateExpression: aws.String("a < :v"), - AttributeUpdates: map[string]*dynamodb.AttributeValueUpdate{ - "a": {Action: aws.String(dynamodb.AttributeActionDelete)}, + AttributeUpdates: map[string]types.AttributeValueUpdate{ + "a": {Action: types.AttributeActionDelete}, }, - ExpressionAttributeValues: map[string]*dynamodb.AttributeValue{":v": {N: aws.String("5")}}, + ExpressionAttributeValues: map[string]types.AttributeValue{":v": &types.AttributeValueMemberN{Value: "5"}}, + }, + &smithy.GenericAPIError{ + Code: ErrCodeValidationException, + Message: "Cannot specify both AttributeUpdates and UpdateExpression", + Fault: smithy.FaultClient, }, - awserr.New(ErrCodeValidationException, "Cannot specify both AttributeUpdates and UpdateExpression", nil), }, { &dynamodb.UpdateItemInput{ ConditionExpression: aws.String("a < :v"), - Expected: map[string]*dynamodb.ExpectedAttributeValue{"a": {Exists: aws.Bool(true), Value: &dynamodb.AttributeValue{N: aws.String("5")}}}, - ExpressionAttributeValues: map[string]*dynamodb.AttributeValue{":v": {N: aws.String("5")}}, + Expected: map[string]types.ExpectedAttributeValue{"a": {Exists: aws.Bool(true), Value: &types.AttributeValueMemberN{Value: "5"}}}, + ExpressionAttributeValues: map[string]types.AttributeValue{":v": &types.AttributeValueMemberN{Value: "5"}}, + }, + &smithy.GenericAPIError{ + Code: ErrCodeValidationException, + Message: "Cannot specify both Expected and ConditionExpression", + Fault: smithy.FaultClient, }, - awserr.New(ErrCodeValidationException, "Cannot specify both Expected and ConditionExpression", nil), }, { &dynamodb.ScanInput{ - ScanFilter: map[string]*dynamodb.Condition{"a": {}}, + ScanFilter: map[string]types.Condition{"a": {}}, + }, + &smithy.GenericAPIError{ + Code: ErrCodeValidationException, + Message: "One or more parameter values were invalid: AttributeValueList can only be used with a ComparisonOperator for Attribute: a", + Fault: smithy.FaultClient, }, - awserr.New(ErrCodeValidationException, "One or more parameter values were invalid: AttributeValueList can only be used with a ComparisonOperator for Attribute: a", nil), }, { &dynamodb.QueryInput{ - KeyConditions: map[string]*dynamodb.Condition{"a": {ComparisonOperator: aws.String(dynamodb.ComparisonOperatorContains), AttributeValueList: []*dynamodb.AttributeValue{{N: aws.String("5")}}}}, + KeyConditions: map[string]types.Condition{ + "a": { + ComparisonOperator: types.ComparisonOperatorContains, + AttributeValueList: []types.AttributeValue{&types.AttributeValueMemberN{Value: "5"}}}}, + }, + &smithy.GenericAPIError{ + Code: ErrCodeValidationException, + Message: "Unsupported operator on KeyCondition: CONTAINS", + Fault: smithy.FaultClient, }, - awserr.New(ErrCodeValidationException, "Unsupported operator on KeyCondition: CONTAINS", nil), }, } diff --git a/dax/internal/client/logger.go b/dax/internal/client/logger.go new file mode 100644 index 0000000..e4723d0 --- /dev/null +++ b/dax/internal/client/logger.go @@ -0,0 +1,11 @@ +package client + +import ( + "github.com/aws/smithy-go/logging" +) + +const ( + ClassificationDebug = logging.Debug + ClassificationWarn = logging.Warn + ClassificationError logging.Classification = "ERROR" +) diff --git a/dax/internal/client/projection.go b/dax/internal/client/projection.go index 5cc3293..f276f46 100644 --- a/dax/internal/client/projection.go +++ b/dax/internal/client/projection.go @@ -16,12 +16,12 @@ package client import ( - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/aws/request" - "github.com/aws/aws-sdk-go/service/dynamodb" + "errors" "sort" "strconv" "strings" + + "github.com/aws/aws-sdk-go-v2/service/dynamodb/types" ) type documentPathElement struct { @@ -41,7 +41,7 @@ func documentPathElementFromName(nm string) documentPathElement { return documentPathElement{index: -1, name: nm} } -func buildProjectionOrdinals(projectionExpression *string, expressionAttributeNames map[string]*string) ([]documentPath, error) { +func buildProjectionOrdinals(projectionExpression *string, expressionAttributeNames map[string]string) ([]documentPath, error) { if projectionExpression == nil || *projectionExpression == "" { return nil, nil } @@ -57,8 +57,8 @@ func buildProjectionOrdinals(projectionExpression *string, expressionAttributeNa return dps, nil } -func buildDocumentPath(path string, expressionAttributeNames map[string]*string) (documentPath, error) { - var substitutes map[string]*string +func buildDocumentPath(path string, expressionAttributeNames map[string]string) (documentPath, error) { + var substitutes map[string]string if expressionAttributeNames != nil { substitutes = expressionAttributeNames } @@ -74,7 +74,7 @@ func buildDocumentPath(path string, expressionAttributeNames map[string]*string) } if idx == 0 { - return documentPath{}, awserr.New(request.InvalidParameterErrCode, "invalid path: "+path, nil) + return documentPath{}, errors.New("invalid path: " + path) } pre := re[0:idx] @@ -85,7 +85,7 @@ func buildDocumentPath(path string, expressionAttributeNames map[string]*string) idx = strings.Index(re, "]") if idx == -1 { - return documentPath{}, awserr.New(request.InvalidParameterErrCode, "invalid path: "+path, nil) + return documentPath{}, errors.New("invalid path: " + path) } lidx, err := strconv.Atoi(re[:idx]) @@ -97,22 +97,22 @@ func buildDocumentPath(path string, expressionAttributeNames map[string]*string) re = re[idx+1:] idx = strings.Index(re, "[") if idx > 0 { - return documentPath{}, awserr.New(request.InvalidParameterErrCode, "invalid path: "+path, nil) + return documentPath{}, errors.New("invalid path: " + path) } } if len(elements) == 0 { - return documentPath{}, awserr.New(request.InvalidParameterErrCode, "invalid path: "+path, nil) + return documentPath{}, errors.New("invalid path: " + path) } } return documentPath{elements: elements}, nil } -func getOrDefault(m map[string]*string, key, value string) string { +func getOrDefault(m map[string]string, key, value string) string { v, ok := m[key] if ok { - return *v + return v } else { return value } @@ -120,17 +120,17 @@ func getOrDefault(m map[string]*string, key, value string) string { type itemNode struct { children map[documentPathElement]*itemNode - value *dynamodb.AttributeValue + value types.AttributeValue } -func (in *itemNode) toAttribute() *dynamodb.AttributeValue { +func (in *itemNode) toAttribute() types.AttributeValue { if in == nil { return nil } if in.value != nil { return in.value } - val := dynamodb.AttributeValue{} + var val types.AttributeValue if len(in.children) != 0 { m := in.children keys := make([]documentPathElement, 0, len(m)) @@ -139,28 +139,34 @@ func (in *itemNode) toAttribute() *dynamodb.AttributeValue { } // it is safe to assume keys do not have a mix of array and map indexes as the request succeeded in DynamoDB at this point if keys[0].index < 0 { - val.M = make(map[string]*dynamodb.AttributeValue, len(keys)) + attr := types.AttributeValueMemberM{ + Value: make(map[string]types.AttributeValue, len(keys)), + } for k, v := range m { - val.M[k.name] = v.toAttribute() + attr.Value[k.name] = v.toAttribute() } + val = &attr } else { // order in the response item should be same as order in actual item, not the one in projection expression // eg: projection expression "list[1],list[0]" returns "list[valAt(0),valAt(1)] sort.Slice(keys, func(i, j int) bool { return keys[i].index < keys[j].index }) - val.L = make([]*dynamodb.AttributeValue, 0, len(keys)) + attr := types.AttributeValueMemberL{ + Value: make([]types.AttributeValue, 0, len(keys)), + } for _, k := range keys { - val.L = append(val.L, m[k].toAttribute()) + attr.Value = append(attr.Value, m[k].toAttribute()) } + val = &attr } } - return &val + return val } type itemBuilder struct { root *itemNode } -func (ib *itemBuilder) insert(path documentPath, value *dynamodb.AttributeValue) { +func (ib *itemBuilder) insert(path documentPath, value types.AttributeValue) { if ib.root == nil { var children map[documentPathElement]*itemNode ib.root = &itemNode{children: children} @@ -168,20 +174,20 @@ func (ib *itemBuilder) insert(path documentPath, value *dynamodb.AttributeValue) ib.insertNode(ib.root, path.elements, value) } -func (ib *itemBuilder) toItem() map[string]*dynamodb.AttributeValue { - item := make(map[string]*dynamodb.AttributeValue) +func (ib *itemBuilder) toItem() map[string]types.AttributeValue { + items := make(map[string]types.AttributeValue) if ib.root == nil { - return item + return items } c := ib.root.children for k, v := range c { // top level attribute names are strings - item[k.name] = v.toAttribute() + items[k.name] = v.toAttribute() } - return item + return items } -func (ib *itemBuilder) insertNode(node *itemNode, elements []documentPathElement, value *dynamodb.AttributeValue) { +func (ib *itemBuilder) insertNode(node *itemNode, elements []documentPathElement, value types.AttributeValue) { if len(elements) == 0 { node.value = value return diff --git a/dax/internal/client/projection_test.go b/dax/internal/client/projection_test.go index b78f636..4a78b3f 100644 --- a/dax/internal/client/projection_test.go +++ b/dax/internal/client/projection_test.go @@ -17,50 +17,51 @@ package client import ( "fmt" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/dynamodb" "reflect" "testing" + + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/dynamodb/types" ) func TestBuildDocumentPath(t *testing.T) { cases := []struct { projectionExpression string - expressionAttributeNames map[string]*string + expressionAttributeNames map[string]string documentPath documentPath }{ { "a", nil, - documentPath{[]documentPathElement{documentPathElement{name: "a", index: -1}}}, + documentPath{[]documentPathElement{{name: "a", index: -1}}}, }, { "a.b", nil, documentPath{[]documentPathElement{ - documentPathElement{name: "a", index: -1}, - documentPathElement{name: "b", index: -1}, + {name: "a", index: -1}, + {name: "b", index: -1}, }}, }, { "a[3]", nil, documentPath{[]documentPathElement{ - documentPathElement{name: "a", index: -1}, - documentPathElement{name: "", index: 3}, + {name: "a", index: -1}, + {name: "", index: 3}, }}, }, { - "a.#s.c", map[string]*string{"#s": aws.String("b")}, + "a.#s.c", map[string]string{"#s": "b"}, documentPath{[]documentPathElement{ - documentPathElement{name: "a", index: -1}, - documentPathElement{name: "b", index: -1}, - documentPathElement{name: "c", index: -1}, + {name: "a", index: -1}, + {name: "b", index: -1}, + {name: "c", index: -1}, }}, }, { - "#a[1].#b", map[string]*string{"#a": aws.String("with.dot"), "#b": aws.String("sub.field")}, + "#a[1].#b", map[string]string{"#a": "with.dot", "#b": "sub.field"}, documentPath{[]documentPathElement{ - documentPathElement{name: "with.dot", index: -1}, - documentPathElement{name: "", index: 1}, - documentPathElement{name: "sub.field", index: -1}, + {name: "with.dot", index: -1}, + {name: "", index: 1}, + {name: "sub.field", index: -1}, }}, }, } @@ -79,17 +80,17 @@ func TestBuildDocumentPath(t *testing.T) { func TestBuildProjectionOrdinals(t *testing.T) { cases := []struct { projectionExpression string - expressionAttributeNames map[string]*string + expressionAttributeNames map[string]string documentPaths []documentPath }{ { "#1", - map[string]*string{"#1": aws.String("a")}, + map[string]string{"#1": "a"}, []documentPath{{[]documentPathElement{{name: "a", index: -1}}}}, }, { "#1, #2", - map[string]*string{"#1": aws.String("a"), "#2": aws.String("b")}, + map[string]string{"#1": "a", "#2": "b"}, []documentPath{{[]documentPathElement{{name: "a", index: -1}}}, {[]documentPathElement{{name: "b", index: -1}}}}, }, } @@ -109,103 +110,110 @@ func TestBuildProjectionOrdinals(t *testing.T) { func TestItemBuilder(t *testing.T) { cases := []struct { projectionExpression string - expressionAttributeNames map[string]*string - values map[int]*dynamodb.AttributeValue - item map[string]*dynamodb.AttributeValue + expressionAttributeNames map[string]string + values map[int]types.AttributeValue + item map[string]types.AttributeValue }{ { - "a", nil, - map[int]*dynamodb.AttributeValue{ - 0: &dynamodb.AttributeValue{S: aws.String("av")}, + projectionExpression: "a", + expressionAttributeNames: nil, + values: map[int]types.AttributeValue{ + 0: &types.AttributeValueMemberS{Value: "av"}, }, - map[string]*dynamodb.AttributeValue{ - "a": &dynamodb.AttributeValue{S: aws.String("av")}, + item: map[string]types.AttributeValue{ + "a": &types.AttributeValueMemberS{Value: "av"}, }, }, { - "a,b[2],c.d", nil, - map[int]*dynamodb.AttributeValue{}, - map[string]*dynamodb.AttributeValue{}, + projectionExpression: "a,b[2],c.d", + expressionAttributeNames: nil, + values: map[int]types.AttributeValue{}, + item: map[string]types.AttributeValue{}, }, { - "a.b", nil, - map[int]*dynamodb.AttributeValue{ - 0: &dynamodb.AttributeValue{S: aws.String("av")}, + projectionExpression: "a.b", + expressionAttributeNames: nil, + values: map[int]types.AttributeValue{ + 0: &types.AttributeValueMemberS{Value: "av"}, }, - map[string]*dynamodb.AttributeValue{ - "a": &dynamodb.AttributeValue{ - M: map[string]*dynamodb.AttributeValue{ - "b": &dynamodb.AttributeValue{S: aws.String("av")}, + item: map[string]types.AttributeValue{ + "a": &types.AttributeValueMemberM{ + Value: map[string]types.AttributeValue{ + "b": &types.AttributeValueMemberS{Value: "av"}, }, }, }, }, { - "a[3]", nil, - map[int]*dynamodb.AttributeValue{ - 0: &dynamodb.AttributeValue{S: aws.String("av")}, + projectionExpression: "a[3]", + expressionAttributeNames: nil, + values: map[int]types.AttributeValue{ + 0: &types.AttributeValueMemberS{Value: "av"}, }, - map[string]*dynamodb.AttributeValue{ - "a": &dynamodb.AttributeValue{ - L: []*dynamodb.AttributeValue{ - &dynamodb.AttributeValue{S: aws.String("av")}, + item: map[string]types.AttributeValue{ + "a": &types.AttributeValueMemberL{ + Value: []types.AttributeValue{ + &types.AttributeValueMemberS{Value: "av"}, }, }, }, }, { - "a[3],a[2]", nil, - map[int]*dynamodb.AttributeValue{ - 0: &dynamodb.AttributeValue{S: aws.String("av3")}, - 1: &dynamodb.AttributeValue{S: aws.String("av2")}, + projectionExpression: "a[3],a[2]", + expressionAttributeNames: nil, + values: map[int]types.AttributeValue{ + 0: &types.AttributeValueMemberS{Value: "av3"}, + 1: &types.AttributeValueMemberS{Value: "av2"}, }, - map[string]*dynamodb.AttributeValue{ - "a": &dynamodb.AttributeValue{ - L: []*dynamodb.AttributeValue{ - &dynamodb.AttributeValue{S: aws.String("av2")}, - &dynamodb.AttributeValue{S: aws.String("av3")}, + item: map[string]types.AttributeValue{ + "a": &types.AttributeValueMemberL{ + Value: []types.AttributeValue{ + &types.AttributeValueMemberS{Value: "av2"}, + &types.AttributeValueMemberS{Value: "av3"}, }, }, }, }, { - "a[2],a[3]", nil, - map[int]*dynamodb.AttributeValue{ - 0: &dynamodb.AttributeValue{S: aws.String("av2")}, - 1: &dynamodb.AttributeValue{S: aws.String("av3")}, + projectionExpression: "a[2],a[3]", + expressionAttributeNames: nil, + values: map[int]types.AttributeValue{ + 0: &types.AttributeValueMemberS{Value: "av2"}, + 1: &types.AttributeValueMemberS{Value: "av3"}, }, - map[string]*dynamodb.AttributeValue{ - "a": &dynamodb.AttributeValue{ - L: []*dynamodb.AttributeValue{ - &dynamodb.AttributeValue{S: aws.String("av2")}, - &dynamodb.AttributeValue{S: aws.String("av3")}, + item: map[string]types.AttributeValue{ + "a": &types.AttributeValueMemberL{ + Value: []types.AttributeValue{ + &types.AttributeValueMemberS{Value: "av2"}, + &types.AttributeValueMemberS{Value: "av3"}, }, }, }, }, { - "a[2].b.c,a[2].b.d,a[1].b.e", nil, - map[int]*dynamodb.AttributeValue{ - 2: &dynamodb.AttributeValue{M: map[string]*dynamodb.AttributeValue{ - "field": &dynamodb.AttributeValue{S: aws.String("value")}, + projectionExpression: "a[2].b.c,a[2].b.d,a[1].b.e", + expressionAttributeNames: nil, + values: map[int]types.AttributeValue{ + 2: &types.AttributeValueMemberM{Value: map[string]types.AttributeValue{ + "field": &types.AttributeValueMemberS{Value: "value"}, }}, - 0: &dynamodb.AttributeValue{N: aws.String("4")}, - 1: &dynamodb.AttributeValue{N: aws.String("2")}, + 0: &types.AttributeValueMemberN{Value: "4"}, + 1: &types.AttributeValueMemberN{Value: "2"}, }, - map[string]*dynamodb.AttributeValue{ - "a": &dynamodb.AttributeValue{ - L: []*dynamodb.AttributeValue{ - &dynamodb.AttributeValue{M: map[string]*dynamodb.AttributeValue{ - "b": &dynamodb.AttributeValue{M: map[string]*dynamodb.AttributeValue{ - "e": &dynamodb.AttributeValue{M: map[string]*dynamodb.AttributeValue{ - "field": &dynamodb.AttributeValue{S: aws.String("value")}, + item: map[string]types.AttributeValue{ + "a": &types.AttributeValueMemberL{ + Value: []types.AttributeValue{ + &types.AttributeValueMemberM{Value: map[string]types.AttributeValue{ + "b": &types.AttributeValueMemberM{Value: map[string]types.AttributeValue{ + "e": &types.AttributeValueMemberM{Value: map[string]types.AttributeValue{ + "field": &types.AttributeValueMemberS{Value: "value"}, }}, }}, }}, - &dynamodb.AttributeValue{M: map[string]*dynamodb.AttributeValue{ - "b": &dynamodb.AttributeValue{M: map[string]*dynamodb.AttributeValue{ - "c": &dynamodb.AttributeValue{N: aws.String("4")}, - "d": &dynamodb.AttributeValue{N: aws.String("2")}, + &types.AttributeValueMemberM{Value: map[string]types.AttributeValue{ + "b": &types.AttributeValueMemberM{Value: map[string]types.AttributeValue{ + "c": &types.AttributeValueMemberN{Value: "4"}, + "d": &types.AttributeValueMemberN{Value: "2"}, }}, }}, }, @@ -213,28 +221,29 @@ func TestItemBuilder(t *testing.T) { }, }, { - "a[4],a[2],b.c[12]", nil, - map[int]*dynamodb.AttributeValue{ - 2: &dynamodb.AttributeValue{L: []*dynamodb.AttributeValue{ - &dynamodb.AttributeValue{S: aws.String("elem")}, + projectionExpression: "a[4],a[2],b.c[12]", + expressionAttributeNames: nil, + values: map[int]types.AttributeValue{ + 2: &types.AttributeValueMemberL{Value: []types.AttributeValue{ + &types.AttributeValueMemberS{Value: "elem"}, }}, - 0: &dynamodb.AttributeValue{N: aws.String("4")}, - 1: &dynamodb.AttributeValue{N: aws.String("2")}, + 0: &types.AttributeValueMemberN{Value: "4"}, + 1: &types.AttributeValueMemberN{Value: "2"}, }, - map[string]*dynamodb.AttributeValue{ - "a": &dynamodb.AttributeValue{ - L: []*dynamodb.AttributeValue{ - &dynamodb.AttributeValue{N: aws.String("2")}, - &dynamodb.AttributeValue{N: aws.String("4")}, + item: map[string]types.AttributeValue{ + "a": &types.AttributeValueMemberL{ + Value: []types.AttributeValue{ + &types.AttributeValueMemberN{Value: "2"}, + &types.AttributeValueMemberN{Value: "4"}, }, }, - "b": &dynamodb.AttributeValue{ - M: map[string]*dynamodb.AttributeValue{ - "c": &dynamodb.AttributeValue{ - L: []*dynamodb.AttributeValue{ - &dynamodb.AttributeValue{ - L: []*dynamodb.AttributeValue{ - &dynamodb.AttributeValue{S: aws.String("elem")}, + "b": &types.AttributeValueMemberM{ + Value: map[string]types.AttributeValue{ + "c": &types.AttributeValueMemberL{ + Value: []types.AttributeValue{ + &types.AttributeValueMemberL{ + Value: []types.AttributeValue{ + &types.AttributeValueMemberS{Value: "elem"}, }, }, }, @@ -244,20 +253,20 @@ func TestItemBuilder(t *testing.T) { }, }, { - "#a[1].#b", - map[string]*string{ - "#a": aws.String("with.dot"), - "#b": aws.String("sub.field"), + projectionExpression: "#a[1].#b", + expressionAttributeNames: map[string]string{ + "#a": "with.dot", + "#b": "sub.field", }, - map[int]*dynamodb.AttributeValue{ - 0: &dynamodb.AttributeValue{N: aws.String("4")}, + values: map[int]types.AttributeValue{ + 0: &types.AttributeValueMemberN{Value: "4"}, }, - map[string]*dynamodb.AttributeValue{ - "with.dot": &dynamodb.AttributeValue{ - L: []*dynamodb.AttributeValue{ - &dynamodb.AttributeValue{ - M: map[string]*dynamodb.AttributeValue{ - "sub.field": &dynamodb.AttributeValue{N: aws.String("4")}, + item: map[string]types.AttributeValue{ + "with.dot": &types.AttributeValueMemberL{ + Value: []types.AttributeValue{ + &types.AttributeValueMemberM{ + Value: map[string]types.AttributeValue{ + "sub.field": &types.AttributeValueMemberN{Value: "4"}, }, }, }, diff --git a/dax/internal/client/request.go b/dax/internal/client/request.go index 9b31718..397c274 100644 --- a/dax/internal/client/request.go +++ b/dax/internal/client/request.go @@ -17,6 +17,8 @@ package client import ( "bytes" + "context" + "errors" "fmt" "sort" "strings" @@ -24,10 +26,10 @@ import ( "github.com/aws/aws-dax-go/dax/internal/cbor" "github.com/aws/aws-dax-go/dax/internal/lru" "github.com/aws/aws-dax-go/dax/internal/parser" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/aws/request" - "github.com/aws/aws-sdk-go/service/dynamodb" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/dynamodb" + "github.com/aws/aws-sdk-go-v2/service/dynamodb/types" + "github.com/aws/smithy-go" "github.com/gofrs/uuid" ) @@ -214,14 +216,11 @@ func encodeDefineKeySchemaInput(table string, writer *cbor.Writer) error { return writer.WriteBytes([]byte(table)) } -func encodePutItemInput(ctx aws.Context, input *dynamodb.PutItemInput, keySchema *lru.Lru, attrNamesListToId *lru.Lru, writer *cbor.Writer) error { +func encodePutItemInput(ctx context.Context, input *dynamodb.PutItemInput, keySchema *lru.Lru, attrNamesListToId *lru.Lru, writer *cbor.Writer) error { if input == nil { - return awserr.New(request.ParamRequiredErrCode, fmt.Sprintf("input cannot be nil"), nil) + return smithy.NewErrParamRequired("input") } var err error - if err = input.Validate(); err != nil { - return err - } if input, err = translateLegacyPutItemInput(input); err != nil { return err } @@ -245,18 +244,19 @@ func encodePutItemInput(ctx aws.Context, input *dynamodb.PutItemInput, keySchema return err } - return encodeItemOperationOptionalParams(input.ReturnValues, input.ReturnConsumedCapacity, input.ReturnItemCollectionMetrics, nil, + return encodeItemOperationOptionalParams( + input.ReturnValues, + input.ReturnConsumedCapacity, + input.ReturnItemCollectionMetrics, + nil, nil, input.ConditionExpression, nil, input.ExpressionAttributeNames, input.ExpressionAttributeValues, writer) } -func encodeDeleteItemInput(ctx aws.Context, input *dynamodb.DeleteItemInput, keySchema *lru.Lru, writer *cbor.Writer) error { +func encodeDeleteItemInput(ctx context.Context, input *dynamodb.DeleteItemInput, keySchema *lru.Lru, writer *cbor.Writer) error { if input == nil { - return awserr.New(request.ParamRequiredErrCode, fmt.Sprintf("input cannot be nil"), nil) + return smithy.NewErrParamRequired("input") } var err error - if err = input.Validate(); err != nil { - return err - } if input, err = translateLegacyDeleteItemInput(input); err != nil { return err } @@ -277,18 +277,19 @@ func encodeDeleteItemInput(ctx aws.Context, input *dynamodb.DeleteItemInput, key return err } - return encodeItemOperationOptionalParams(input.ReturnValues, input.ReturnConsumedCapacity, input.ReturnItemCollectionMetrics, nil, + return encodeItemOperationOptionalParams( + input.ReturnValues, + input.ReturnConsumedCapacity, + input.ReturnItemCollectionMetrics, + nil, nil, input.ConditionExpression, nil, input.ExpressionAttributeNames, input.ExpressionAttributeValues, writer) } -func encodeUpdateItemInput(ctx aws.Context, input *dynamodb.UpdateItemInput, keySchema *lru.Lru, writer *cbor.Writer) error { +func encodeUpdateItemInput(ctx context.Context, input *dynamodb.UpdateItemInput, keySchema *lru.Lru, writer *cbor.Writer) error { if input == nil { - return awserr.New(request.ParamRequiredErrCode, fmt.Sprintf("input cannot be nil"), nil) + return smithy.NewErrParamRequired("input") } var err error - if err = input.Validate(); err != nil { - return err - } if input, err = translateLegacyUpdateItemInput(input); err != nil { return err } @@ -309,18 +310,19 @@ func encodeUpdateItemInput(ctx aws.Context, input *dynamodb.UpdateItemInput, key return err } - return encodeItemOperationOptionalParams(input.ReturnValues, input.ReturnConsumedCapacity, input.ReturnItemCollectionMetrics, nil, + return encodeItemOperationOptionalParams( + input.ReturnValues, + input.ReturnConsumedCapacity, + input.ReturnItemCollectionMetrics, + nil, nil, input.ConditionExpression, input.UpdateExpression, input.ExpressionAttributeNames, input.ExpressionAttributeValues, writer) } -func encodeGetItemInput(ctx aws.Context, input *dynamodb.GetItemInput, keySchema *lru.Lru, writer *cbor.Writer) error { +func encodeGetItemInput(ctx context.Context, input *dynamodb.GetItemInput, keySchema *lru.Lru, writer *cbor.Writer) error { if input == nil { - return awserr.New(request.ParamRequiredErrCode, fmt.Sprintf("input cannot be nil"), nil) + return smithy.NewErrParamRequired("input") } var err error - if err = input.Validate(); err != nil { - return err - } if input, err = translateLegacyGetItemInput(input); err != nil { return err } @@ -339,18 +341,19 @@ func encodeGetItemInput(ctx aws.Context, input *dynamodb.GetItemInput, keySchema if err := cbor.EncodeItemKey(input.Key, keys, writer); err != nil { return err } - return encodeItemOperationOptionalParams(nil, input.ReturnConsumedCapacity, nil, input.ConsistentRead, + return encodeItemOperationOptionalParams( + types.ReturnValueNone, + input.ReturnConsumedCapacity, + types.ReturnItemCollectionMetricsNone, + input.ConsistentRead, input.ProjectionExpression, nil, nil, input.ExpressionAttributeNames, nil, writer) } -func encodeScanInput(ctx aws.Context, input *dynamodb.ScanInput, keySchema *lru.Lru, writer *cbor.Writer) error { +func encodeScanInput(ctx context.Context, input *dynamodb.ScanInput, keySchema *lru.Lru, writer *cbor.Writer) error { if input == nil { - return awserr.New(request.ParamRequiredErrCode, fmt.Sprintf("input cannot be nil"), nil) + return smithy.NewErrParamRequired("input") } var err error - if err = input.Validate(); err != nil { - return err - } if input, err = translateLegacyScanInput(input); err != nil { return err } @@ -364,23 +367,25 @@ func encodeScanInput(ctx aws.Context, input *dynamodb.ScanInput, keySchema *lru. if err != nil { return err } - return encodeScanQueryOptionalParams(ctx, input.IndexName, input.Select, input.ReturnConsumedCapacity, input.ConsistentRead, + return encodeScanQueryOptionalParams( + ctx, + input.IndexName, + input.Select, + input.ReturnConsumedCapacity, + input.ConsistentRead, expressions, input.Segment, input.TotalSegments, input.Limit, nil, input.ExclusiveStartKey, keySchema, *input.TableName, writer) } -func encodeQueryInput(ctx aws.Context, input *dynamodb.QueryInput, keySchema *lru.Lru, writer *cbor.Writer) error { +func encodeQueryInput(ctx context.Context, input *dynamodb.QueryInput, keySchema *lru.Lru, writer *cbor.Writer) error { if input == nil { - return awserr.New(request.ParamRequiredErrCode, fmt.Sprintf("input cannot be nil"), nil) + return smithy.NewErrParamRequired("input") } var err error - if err = input.Validate(); err != nil { - return err - } if input, err = translateLegacyQueryInput(input); err != nil { return err } if input.KeyConditionExpression == nil { - return awserr.New(request.ParamRequiredErrCode, "KeyConditionExpression cannot be nil", nil) + return smithy.NewErrParamRequired("input.KeyConditionExpression") } if err := encodeServiceAndMethod(query_N931250863_1_Id, writer); err != nil { return err @@ -395,18 +400,20 @@ func encodeQueryInput(ctx aws.Context, input *dynamodb.QueryInput, keySchema *lr if err = writer.WriteBytes(expressions[parser.KeyConditionExpr]); err != nil { return err } - return encodeScanQueryOptionalParams(ctx, input.IndexName, input.Select, input.ReturnConsumedCapacity, input.ConsistentRead, + return encodeScanQueryOptionalParams( + ctx, + input.IndexName, + input.Select, + input.ReturnConsumedCapacity, + input.ConsistentRead, expressions, nil, nil, input.Limit, input.ScanIndexForward, input.ExclusiveStartKey, keySchema, *input.TableName, writer) } -func encodeBatchWriteItemInput(ctx aws.Context, input *dynamodb.BatchWriteItemInput, keySchema *lru.Lru, attrNamesListToId *lru.Lru, writer *cbor.Writer) error { +func encodeBatchWriteItemInput(ctx context.Context, input *dynamodb.BatchWriteItemInput, keySchema *lru.Lru, attrNamesListToId *lru.Lru, writer *cbor.Writer) error { if input == nil { - return awserr.New(request.ParamRequiredErrCode, fmt.Sprintf("input cannot be nil"), nil) + return smithy.NewErrParamRequired("input") } var err error - if err = input.Validate(); err != nil { - return err - } if err = encodeServiceAndMethod(batchWriteItem_116217951_1_Id, writer); err != nil { return err } @@ -422,13 +429,13 @@ func encodeBatchWriteItemInput(ctx aws.Context, input *dynamodb.BatchWriteItemIn l := len(wrs) if l == 0 { - return awserr.New(request.InvalidParameterErrCode, fmt.Sprintf("1 validation error detected: Value '{%s=%d}' at 'requestItems' failed to satisfy constraint:"+ - " Map value must satisfy constraint: [Member must have length less than or equal to 25, Member must have length greater than or equal to 1", table, l), nil) + return fmt.Errorf("1 validation error detected: Value '{%s=%d}' at 'requestItems' failed to satisfy constraint:"+ + " Map value must satisfy constraint: [Member must have length less than or equal to 25, Member must have length greater than or equal to 1", table, l) } totalRequests = totalRequests + l if totalRequests > maxWriteBatchSize { - return awserr.New(request.InvalidParameterErrCode, fmt.Sprintf("1 validation error detected: Value '{%s=%d}' at 'requestItems' failed to satisfy constraint:"+ - " Map value must satisfy constraint: [Member must have length less than or equal to 25, Member must have length greater than or equal to 1", table, totalRequests), nil) + return fmt.Errorf("1 validation error detected: Value '{%s=%d}' at 'requestItems' failed to satisfy constraint:"+ + " Map value must satisfy constraint: [Member must have length less than or equal to 25, Member must have length greater than or equal to 1", table, totalRequests) } if err = writer.WriteString(table); err != nil { @@ -439,7 +446,7 @@ func encodeBatchWriteItemInput(ctx aws.Context, input *dynamodb.BatchWriteItemIn } if hasDuplicatesWriteRequests(wrs, keys) { - return awserr.New(request.InvalidParameterErrCode, "Provided list of item keys contains duplicates", nil) + return errors.New("provided list of item keys contains duplicates") } for _, wr := range wrs { if pr := wr.PutRequest; pr != nil { @@ -458,21 +465,22 @@ func encodeBatchWriteItemInput(ctx aws.Context, input *dynamodb.BatchWriteItemIn return err } } else { - return awserr.New(request.ParamRequiredErrCode, "Both PutRequest and DeleteRequest cannot be empty", nil) + return errors.New("both PutRequest and DeleteRequest cannot be empty") } } } - return encodeItemOperationOptionalParams(nil, input.ReturnConsumedCapacity, input.ReturnItemCollectionMetrics, nil, nil, nil, nil, nil, nil, writer) + return encodeItemOperationOptionalParams( + types.ReturnValueNone, + input.ReturnConsumedCapacity, + input.ReturnItemCollectionMetrics, + nil, nil, nil, nil, nil, nil, writer) } -func encodeBatchGetItemInput(ctx aws.Context, input *dynamodb.BatchGetItemInput, keySchema *lru.Lru, writer *cbor.Writer) error { +func encodeBatchGetItemInput(ctx context.Context, input *dynamodb.BatchGetItemInput, keySchema *lru.Lru, writer *cbor.Writer) error { if input == nil { - return awserr.New(request.ParamRequiredErrCode, fmt.Sprintf("input cannot be nil"), nil) + return smithy.NewErrParamRequired("input") } var err error - if err = input.Validate(); err != nil { - return err - } if input, err = translateLegacyBatchGetItemInput(input); err != nil { return err } @@ -526,7 +534,7 @@ func encodeBatchGetItemInput(ctx aws.Context, input *dynamodb.BatchGetItemInput, return err } if hasDuplicateKeysAndAttributes(kaas, tableKeys) { - return awserr.New(request.InvalidParameterErrCode, "Provided list of item keys contains duplicates", nil) + return errors.New("provided list of item keys contains duplicates") } for _, keys := range kaas.Keys { if err = cbor.EncodeItemKey(keys, tableKeys, writer); err != nil { @@ -535,18 +543,23 @@ func encodeBatchGetItemInput(ctx aws.Context, input *dynamodb.BatchGetItemInput, } } - return encodeItemOperationOptionalParams(nil, input.ReturnConsumedCapacity, nil, nil, nil, nil, nil, nil, nil, writer) + return encodeItemOperationOptionalParams( + types.ReturnValueNone, + input.ReturnConsumedCapacity, + types.ReturnItemCollectionMetricsNone, + nil, nil, nil, nil, nil, nil, writer) } -func encodeTransactWriteItemsInput(ctx aws.Context, input *dynamodb.TransactWriteItemsInput, keySchema *lru.Lru, attrNamesListToId *lru.Lru, writer *cbor.Writer, extractedKeys []map[string]*dynamodb.AttributeValue) error { +func encodeTransactWriteItemsInput( + ctx context.Context, + input *dynamodb.TransactWriteItemsInput, + keySchema *lru.Lru, attrNamesListToId *lru.Lru, writer *cbor.Writer, + extractedKeys []map[string]types.AttributeValue, +) error { if input == nil { - return awserr.New(request.ParamRequiredErrCode, "input cannot be nil", nil) + return smithy.NewErrParamRequired("input") } var err error - if err = input.Validate(); err != nil { - return err - } - if err = encodeServiceAndMethod(transactWriteItems_N1160037738_1_Id, writer); err != nil { return err } @@ -597,19 +610,16 @@ func encodeTransactWriteItemsInput(ctx aws.Context, input *dynamodb.TransactWrit tableKeySet := make(map[string]bool) for i, twi := range input.TransactItems { - if twi == nil { - return awserr.New(request.ParamRequiredErrCode, "TransactWriteItem cannot be nil", nil) - } var operation int var tableName *string - var key map[string]*dynamodb.AttributeValue - var item map[string]*dynamodb.AttributeValue + var key map[string]types.AttributeValue + var item map[string]types.AttributeValue var isItem bool = false var conditionExpression *string var updateExpression *string - var expressionAttributeNames map[string]*string - var expressionAttributeValues map[string]*dynamodb.AttributeValue - var rvOnConditionCheckFailure *string + var expressionAttributeNames map[string]string + var expressionAttributeValues map[string]types.AttributeValue + var rvOnConditionCheckFailure types.ReturnValuesOnConditionCheckFailure opCount := 0 if check := twi.ConditionCheck; check != nil { opCount++ @@ -655,10 +665,10 @@ func encodeTransactWriteItemsInput(ctx aws.Context, input *dynamodb.TransactWrit } if opCount == 0 { - return awserr.New(request.ParamRequiredErrCode, "Invalid Request: TransactWriteItemsInput should contain Delete or Put or Update request", nil) + return errors.New("invalid request: TransactWriteItemsInput should contain Delete or Put or Update request") } if opCount > 1 { - return awserr.New(request.ParamRequiredErrCode, "TransactItems can only contain one of ConditionalCheck, Put, Update or Delete", nil) + return errors.New("TransactItems can only contain one of ConditionalCheck, Put, Update or Delete") } if err := operationWriter.WriteInt(operation); err != nil { @@ -688,7 +698,7 @@ func encodeTransactWriteItemsInput(ctx aws.Context, input *dynamodb.TransactWrit tableKey := string(keyBytes) _, ok := tableKeySet[tableKey] if ok { - return awserr.New(request.ParamRequiredErrCode, "Transaction request cannot include multiple operations on one item", nil) + return errors.New("transaction request cannot include multiple operations on one item") } else { tableKeySet[tableKey] = true } @@ -702,7 +712,7 @@ func encodeTransactWriteItemsInput(ctx aws.Context, input *dynamodb.TransactWrit if err := encodeNonKeyAttributes(ctx, item, keydef, attrNamesListToId, valuesWriter); err != nil { return err } - key = map[string]*dynamodb.AttributeValue{} + key = map[string]types.AttributeValue{} for _, attrDef := range keydef { key[*attrDef.AttributeName] = item[*attrDef.AttributeName] } @@ -734,7 +744,7 @@ func encodeTransactWriteItemsInput(ctx aws.Context, input *dynamodb.TransactWrit } } - if rvOnConditionCheckFailure != nil && *rvOnConditionCheckFailure == dynamodb.ReturnValuesOnConditionCheckFailureAllOld { + if rvOnConditionCheckFailure == types.ReturnValuesOnConditionCheckFailureAllOld { if err := rvOnConditionCheckFailureWriter.WriteInt(returnValueOnConditionCheckFailureAllOld); err != nil { return err } @@ -799,18 +809,23 @@ func encodeTransactWriteItemsInput(ctx aws.Context, input *dynamodb.TransactWrit } input.ClientRequestToken = aws.String(id.String()) } - return encodeItemOperationOptionalParamsWithToken(nil, input.ReturnConsumedCapacity, input.ReturnItemCollectionMetrics, nil, nil, nil, nil, nil, nil, input.ClientRequestToken, writer) + return encodeItemOperationOptionalParamsWithToken( + types.ReturnValueNone, + input.ReturnConsumedCapacity, + input.ReturnItemCollectionMetrics, + nil, nil, nil, nil, nil, nil, input.ClientRequestToken, writer) } -func encodeTransactGetItemsInput(ctx aws.Context, input *dynamodb.TransactGetItemsInput, keySchema *lru.Lru, writer *cbor.Writer, extractedKeys []map[string]*dynamodb.AttributeValue) error { +func encodeTransactGetItemsInput( + ctx context.Context, + input *dynamodb.TransactGetItemsInput, + keySchema *lru.Lru, writer *cbor.Writer, + extractedKeys []map[string]types.AttributeValue, +) error { if input == nil { - return awserr.New(request.ParamRequiredErrCode, "input cannot be nil", nil) + return smithy.NewErrParamRequired("input") } var err error - if err = input.Validate(); err != nil { - return err - } - if err = encodeServiceAndMethod(transactGetItems_1866287579_1_Id, writer); err != nil { return err } @@ -839,13 +854,10 @@ func encodeTransactGetItemsInput(ctx aws.Context, input *dynamodb.TransactGetIte }() for i, tgi := range input.TransactItems { - if tgi == nil { - return awserr.New(request.ParamRequiredErrCode, "TransactGetItem cannot be nil", nil) - } var tableName *string - var key map[string]*dynamodb.AttributeValue + var key map[string]types.AttributeValue var projectionExpression *string - var expressionAttributeNames map[string]*string + var expressionAttributeNames map[string]string get := tgi.Get tableName = get.TableName key = get.Key @@ -902,10 +914,14 @@ func encodeTransactGetItemsInput(ctx aws.Context, input *dynamodb.TransactGetIte return err } - return encodeItemOperationOptionalParams(nil, input.ReturnConsumedCapacity, nil, nil, nil, nil, nil, nil, nil, writer) + return encodeItemOperationOptionalParams( + types.ReturnValueNone, + input.ReturnConsumedCapacity, + types.ReturnItemCollectionMetricsNone, + nil, nil, nil, nil, nil, nil, writer) } -func encodeCompoundKey(key map[string]*dynamodb.AttributeValue, writer *cbor.Writer) error { +func encodeCompoundKey(key map[string]types.AttributeValue, writer *cbor.Writer) error { var buf bytes.Buffer w := cbor.NewWriter(&buf) defer w.Close() @@ -931,7 +947,7 @@ func encodeCompoundKey(key map[string]*dynamodb.AttributeValue, writer *cbor.Wri return writer.WriteBytes(buf.Bytes()) } -func encodeNonKeyAttributes(ctx aws.Context, item map[string]*dynamodb.AttributeValue, keys []dynamodb.AttributeDefinition, +func encodeNonKeyAttributes(ctx context.Context, item map[string]types.AttributeValue, keys []types.AttributeDefinition, attrNamesListToId *lru.Lru, writer *cbor.Writer) error { var buf bytes.Buffer w := cbor.NewWriter(&buf) @@ -945,9 +961,14 @@ func encodeNonKeyAttributes(ctx aws.Context, item map[string]*dynamodb.Attribute return writer.WriteBytes(buf.Bytes()) } -func encodeScanQueryOptionalParams(ctx aws.Context, index, selection, returnConsumedCapacity *string, consistentRead *bool, - encodedExpressions map[int][]byte, segment, totalSegment, limit *int64, forward *bool, - startKey map[string]*dynamodb.AttributeValue, keySchema *lru.Lru, table string, writer *cbor.Writer) error { +func encodeScanQueryOptionalParams( + ctx context.Context, + index *string, + selection types.Select, + returnConsumedCapacity types.ReturnConsumedCapacity, + consistentRead *bool, + encodedExpressions map[int][]byte, segment, totalSegment, limit *int32, forward *bool, + startKey map[string]types.AttributeValue, keySchema *lru.Lru, table string, writer *cbor.Writer) error { var err error if err = writer.WriteMapStreamHeader(); err != nil { @@ -961,7 +982,7 @@ func encodeScanQueryOptionalParams(ctx aws.Context, index, selection, returnCons return err } } - if selection != nil { + if selection != types.SelectAllAttributes { if err = writer.WriteInt(requestParamSelect); err != nil { return err } @@ -969,7 +990,7 @@ func encodeScanQueryOptionalParams(ctx aws.Context, index, selection, returnCons return err } } - if returnConsumedCapacity != nil { + if returnConsumedCapacity != types.ReturnConsumedCapacityNone { if err = writer.WriteInt(requestParamReturnConsumedCapacity); err != nil { return err } @@ -1012,7 +1033,7 @@ func encodeScanQueryOptionalParams(ctx aws.Context, index, selection, returnCons if err = writer.WriteInt(requestParamSegment); err != nil { return err } - if err = writer.WriteInt64(*segment); err != nil { + if err = writer.WriteInt64(int64(*segment)); err != nil { return err } } @@ -1020,7 +1041,7 @@ func encodeScanQueryOptionalParams(ctx aws.Context, index, selection, returnCons if err = writer.WriteInt(requestParamTotalSegments); err != nil { return err } - if err = writer.WriteInt64(*totalSegment); err != nil { + if err = writer.WriteInt64(int64(*totalSegment)); err != nil { return err } } @@ -1028,7 +1049,7 @@ func encodeScanQueryOptionalParams(ctx aws.Context, index, selection, returnCons if err = writer.WriteInt(requestParamLimit); err != nil { return err } - if err = writer.WriteInt64(*limit); err != nil { + if err = writer.WriteInt64(int64(*limit)); err != nil { return err } } @@ -1064,8 +1085,14 @@ func encodeScanQueryOptionalParams(ctx aws.Context, index, selection, returnCons return writer.WriteStreamBreak() } -func encodeItemOperationOptionalParamsWithToken(returnValues, returnConsumedCapacity, returnItemCollectionMetrics *string, consistentRead *bool, - projectionExp, conditionalExpr, updateExpr *string, exprAttrNames map[string]*string, exprAttrValues map[string]*dynamodb.AttributeValue, clientRequestToken *string, writer *cbor.Writer) error { +func encodeItemOperationOptionalParamsWithToken( + returnValues types.ReturnValue, + returnConsumedCapacity types.ReturnConsumedCapacity, + returnItemCollectionMetrics types.ReturnItemCollectionMetrics, + consistentRead *bool, + projectionExp, conditionalExpr, updateExpr *string, + exprAttrNames map[string]string, + exprAttrValues map[string]types.AttributeValue, clientRequestToken *string, writer *cbor.Writer) error { if err := writer.WriteMapStreamHeader(); err != nil { return err } @@ -1144,13 +1171,25 @@ func encodeItemOperationOptionalParamsWithToken(returnValues, returnConsumedCapa return writer.WriteStreamBreak() } -func encodeItemOperationOptionalParams(returnValues, returnConsumedCapacity, returnItemCollectionMetrics *string, consistentRead *bool, - projectionExp, conditionalExpr, updateExpr *string, exprAttrNames map[string]*string, exprAttrValues map[string]*dynamodb.AttributeValue, writer *cbor.Writer) error { - return encodeItemOperationOptionalParamsWithToken(returnValues, returnConsumedCapacity, returnItemCollectionMetrics, consistentRead, +func encodeItemOperationOptionalParams( + returnValues types.ReturnValue, + returnConsumedCapacity types.ReturnConsumedCapacity, + returnItemCollectionMetrics types.ReturnItemCollectionMetrics, + consistentRead *bool, + projectionExp, conditionalExpr, updateExpr *string, + exprAttrNames map[string]string, + exprAttrValues map[string]types.AttributeValue, writer *cbor.Writer) error { + return encodeItemOperationOptionalParamsWithToken( + returnValues, + returnConsumedCapacity, + returnItemCollectionMetrics, + consistentRead, projectionExp, conditionalExpr, updateExpr, exprAttrNames, exprAttrValues, nil, writer) } -func parseExpressions(conditionalExpr, updateExpr, projectionExp *string, exprAttrNames map[string]*string, exprAttrValues map[string]*dynamodb.AttributeValue) (map[int][]byte, error) { +func parseExpressions( + conditionalExpr, updateExpr, projectionExp *string, exprAttrNames map[string]string, exprAttrValues map[string]types.AttributeValue, +) (map[int][]byte, error) { expressions := make(map[int]string) if conditionalExpr != nil { expressions[parser.ConditionExpr] = *conditionalExpr @@ -1176,7 +1215,7 @@ func encodeServiceAndMethod(method int, writer *cbor.Writer) error { return writer.WriteInt(method) } -func encodeExpressions(projection, filter, keyCondition *string, exprAttrNames map[string]*string, exprAttrValues map[string]*dynamodb.AttributeValue) (map[int][]byte, error) { +func encodeExpressions(projection, filter, keyCondition *string, exprAttrNames map[string]string, exprAttrValues map[string]types.AttributeValue) (map[int][]byte, error) { expressions := make(map[int]string) if projection != nil { expressions[parser.ProjectionExpr] = *projection @@ -1191,61 +1230,49 @@ func encodeExpressions(projection, filter, keyCondition *string, exprAttrNames m return encoder.Parse() } -func translateReturnValues(returnValues *string) int { - if returnValues == nil { - return returnValueNone - } - switch *returnValues { - case dynamodb.ReturnValueAllOld: +func translateReturnValues(returnValues types.ReturnValue) int { + switch returnValues { + case types.ReturnValueAllOld: return returnValueAllOld - case dynamodb.ReturnValueUpdatedOld: + case types.ReturnValueUpdatedOld: return returnValueUpdatedOld - case dynamodb.ReturnValueAllNew: + case types.ReturnValueAllNew: return returnValueAllNew - case dynamodb.ReturnValueUpdatedNew: + case types.ReturnValueUpdatedNew: return returnValueUpdatedNew default: return returnValueNone } } -func translateReturnConsumedCapacity(returnConsumedCapacity *string) int { - if returnConsumedCapacity == nil { - return returnConsumedCapacityNone - } - switch *returnConsumedCapacity { - case dynamodb.ReturnConsumedCapacityTotal: +func translateReturnConsumedCapacity(returnConsumedCapacity types.ReturnConsumedCapacity) int { + switch returnConsumedCapacity { + case types.ReturnConsumedCapacityTotal: return returnConsumedCapacityTotal - case dynamodb.ReturnConsumedCapacityIndexes: + case types.ReturnConsumedCapacityIndexes: return returnConsumedCapacityIndexes default: - return returnItemCollectionMetricsNone + return returnConsumedCapacityNone } } -func translateReturnItemCollectionMetrics(returnItemCollectionMetrics *string) int { - if returnItemCollectionMetrics == nil { - return returnItemCollectionMetricsNone - } - if dynamodb.ReturnItemCollectionMetricsSize == *returnItemCollectionMetrics { +func translateReturnItemCollectionMetrics(returnItemCollectionMetrics types.ReturnItemCollectionMetrics) int { + if types.ReturnItemCollectionMetricsSize == returnItemCollectionMetrics { return returnItemCollectionMetricsSize } return returnItemCollectionMetricsNone } -func translateSelect(selection *string) int { - if selection == nil { - return selectAllAttributes - } - switch *selection { - case dynamodb.SelectAllAttributes: - return selectAllAttributes - case dynamodb.SelectAllProjectedAttributes: +func translateSelect(selection types.Select) int { + switch selection { + case types.SelectAllProjectedAttributes: return selectAllProjectedAttributes - case dynamodb.SelectCount: + case types.SelectCount: return selectCount - case dynamodb.SelectSpecificAttributes: + case types.SelectSpecificAttributes: return selectSpecificAttributes + case types.SelectAllAttributes: + return selectAllAttributes default: return selectAllAttributes } @@ -1261,16 +1288,13 @@ func translateScanIndexForward(b *bool) int { return 0 } -func hasDuplicatesWriteRequests(wrs []*dynamodb.WriteRequest, d []dynamodb.AttributeDefinition) bool { +func hasDuplicatesWriteRequests(wrs []types.WriteRequest, d []types.AttributeDefinition) bool { if len(wrs) <= 1 { return false } face := make([]item, len(wrs)) for i, v := range wrs { - if v == nil { - return false // continue with request processing, will fail later with proper error msg - } - face[i] = (*writeItem)(v) + face[i] = (writeItem)(v) } var err error @@ -1290,8 +1314,8 @@ func hasDuplicatesWriteRequests(wrs []*dynamodb.WriteRequest, d []dynamodb.Attri return err != nil } -func hasDuplicateKeysAndAttributes(kaas *dynamodb.KeysAndAttributes, d []dynamodb.AttributeDefinition) bool { - if kaas == nil || len(kaas.Keys) <= 1 { +func hasDuplicateKeysAndAttributes(kaas types.KeysAndAttributes, d []types.AttributeDefinition) bool { + if len(kaas.Keys) <= 1 { return false } face := make([]item, len(kaas.Keys)) @@ -1320,34 +1344,39 @@ func hasDuplicateKeysAndAttributes(kaas *dynamodb.KeysAndAttributes, d []dynamod } type item interface { - key(def dynamodb.AttributeDefinition) string + key(def types.AttributeDefinition) string } -type itemKey dynamodb.AttributeDefinition +type itemKey types.AttributeDefinition -func (i itemKey) extract(v *dynamodb.AttributeValue) string { +func (i itemKey) extract(v types.AttributeValue) string { if v == nil { return "" } - switch *i.AttributeType { - case dynamodb.ScalarAttributeTypeS: - if v.S != nil { - return *v.S + switch i.AttributeType { + case types.ScalarAttributeTypeS: + vv, ok := v.(*types.AttributeValueMemberS) + if ok { + return vv.Value } - case dynamodb.ScalarAttributeTypeN: - if v.N != nil { - return *v.N + case types.ScalarAttributeTypeN: + vv, ok := v.(*types.AttributeValueMemberN) + if ok { + return vv.Value + } + case types.ScalarAttributeTypeB: + vv, ok := v.(*types.AttributeValueMemberB) + if ok { + return string(vv.Value) } - case dynamodb.ScalarAttributeTypeB: - return string(v.B) } return "" } -type writeItem dynamodb.WriteRequest +type writeItem types.WriteRequest -func (w writeItem) key(def dynamodb.AttributeDefinition) string { - var v *dynamodb.AttributeValue +func (w writeItem) key(def types.AttributeDefinition) string { + var v types.AttributeValue if w.PutRequest != nil && w.PutRequest.Item != nil { v = w.PutRequest.Item[*def.AttributeName] } else if w.DeleteRequest != nil && w.DeleteRequest.Key != nil { @@ -1356,20 +1385,21 @@ func (w writeItem) key(def dynamodb.AttributeDefinition) string { return itemKey(def).extract(v) } -type attrItem map[string]*dynamodb.AttributeValue +type attrItem map[string]types.AttributeValue -func (w attrItem) key(def dynamodb.AttributeDefinition) string { +func (w attrItem) key(def types.AttributeDefinition) string { v := w[*def.AttributeName] return itemKey(def).extract(v) } type dupKeys struct { - defs []dynamodb.AttributeDefinition + defs []types.AttributeDefinition items []item eq func(a, b item) int } // Implements sort.Interface + func (d dupKeys) Len() int { return len(d.items) } func (d dupKeys) Swap(i, j int) { d.items[i], d.items[j] = d.items[j], d.items[i] } func (d dupKeys) Less(i, j int) bool { return d.eq(d.items[i], d.items[j]) <= 0 } diff --git a/dax/internal/client/request_options.go b/dax/internal/client/request_options.go index b6e6ec4..61119a6 100644 --- a/dax/internal/client/request_options.go +++ b/dax/internal/client/request_options.go @@ -16,166 +16,9 @@ package client import ( - "time" - - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/aws/client/metadata" - "github.com/aws/aws-sdk-go/aws/request" + "github.com/aws/aws-sdk-go-v2/service/dynamodb" ) type RequestOptions struct { - LogLevel aws.LogLevelType - Logger aws.Logger - - RetryDelay time.Duration - //Retryer implements equal jitter backoff stratergy for throttled requests - Retryer DaxRetryer - MaxRetries int - //SleepDelayFn is used for non-throttled retryable requests - SleepDelayFn func(time.Duration) - Context aws.Context -} - -func (o *RequestOptions) applyTo(r *request.Request) { - if r != nil { - r.Config.LogLevel = aws.LogLevel(o.LogLevel) - r.Config.Logger = o.Logger - - r.RetryDelay = o.RetryDelay - r.Config.MaxRetries = aws.Int(o.MaxRetries) - r.Config.SleepDelay = o.SleepDelayFn - if o.Context != nil { - r.SetContext(o.Context) - } - } -} - -func (o *RequestOptions) MergeFromRequestOptions(ctx aws.Context, opts ...request.Option) error { - if len(opts) == 0 { - if ctx != nil { - o.Context = ctx - } - return nil - } - - // New request has to be created to avoid panics when setting fields - r := request.New(aws.Config{}, metadata.ClientInfo{}, request.Handlers{}, nil, &request.Operation{}, nil, nil) - r.ApplyOptions(opts...) - if err := o.mergeFromRequest(r, true); err != nil { - return err - } - if ctx != nil { - o.Context = ctx - } - return nil -} - -func (o *RequestOptions) mergeFromRequest(r *request.Request, validate bool) error { - if r == nil { - return nil - } - if validate { - if err := ValidateRequest(r); err != nil { - return err - } - } - if r.Config.LogLevel != nil { - o.LogLevel = *r.Config.LogLevel - } - if r.Config.Logger != nil { - o.Logger = r.Config.Logger - } - if r.RetryDelay >= 0 { - o.RetryDelay = r.RetryDelay - } - if r.Config.MaxRetries != nil { - o.MaxRetries = *r.Config.MaxRetries - } - if r.Config.SleepDelay != nil { - o.SleepDelayFn = r.Config.SleepDelay - } - if r.Context() != nil { // TODO Should the Context() from Request override the one in RequestOptions - o.Context = r.Context() - } - return nil -} - -func ValidateRequest(r *request.Request) error { - if r == nil { - return nil - } - if err := ValidateHandlers(r.Handlers, true); err != nil { - return err - } - if r.Retryable != nil { - return awserr.New(request.InvalidParameterErrCode, "unsupported config: Retryable", nil) - } - if len(r.SignedHeaderVals) > 0 { - return awserr.New(request.InvalidParameterErrCode, "custom signed headers not supported", nil) - } - - return ValidateConfig(r.Config, true) -} - -func ValidateHandlers(h request.Handlers, expectDaxHandlers bool) error { - if h.Validate.Len() > 0 || h.Sign.Len() > 0 || h.ValidateResponse.Len() > 0 || - h.Unmarshal.Len() > 0 || h.UnmarshalMeta.Len() > 0 || h.UnmarshalError.Len() > 0 || - h.Retry.Len() > 0 || h.AfterRetry.Len() > 0 || h.Complete.Len() > 0 { - return awserr.New(request.InvalidParameterErrCode, "custom handlers not supported", nil) - } - e := 0 - if expectDaxHandlers { - e = 1 - } - if h.Build.Len() > e || h.Send.Len() > e { - return awserr.New(request.InvalidParameterErrCode, "custom build or send handlers not supported", nil) - } - return nil -} - -func ValidateConfig(c aws.Config, isRequestConfig bool) error { - if c.CredentialsChainVerboseErrors != nil { - return awserr.New(request.InvalidParameterErrCode, "unsupported config: CredentialsChainVerboseErrors", nil) - } - if c.EndpointResolver != nil { - return awserr.New(request.InvalidParameterErrCode, "unsupported config: EndpointResolver", nil) - } - if c.EnforceShouldRetryCheck != nil { - return awserr.New(request.InvalidParameterErrCode, "unsupported config: EnforceShouldRetryCheck", nil) - } - if c.DisableSSL != nil { - return awserr.New(request.InvalidParameterErrCode, "unsupported config: DisableSSL", nil) - } - if c.HTTPClient != nil { - return awserr.New(request.InvalidParameterErrCode, "unsupported config: HTTPClient", nil) - } - if c.Retryer != nil { - return awserr.New(request.InvalidParameterErrCode, "unsupported config: Retryer", nil) - } - if c.DisableParamValidation != nil && *c.DisableParamValidation { - return awserr.New(request.InvalidParameterErrCode, "unsupported config: DisableParamValidation", nil) - } - if c.DisableComputeChecksums != nil && *c.DisableComputeChecksums { - return awserr.New(request.InvalidParameterErrCode, "unsupported config: DisableComputeChecksums", nil) - } - if c.UseDualStack != nil { - return awserr.New(request.InvalidParameterErrCode, "unsupported config: UseDualStack", nil) - } - if c.DisableRestProtocolURICleaning != nil { - return awserr.New(request.InvalidParameterErrCode, "unsupported config: DisableRestProtocolURICleaning", nil) - } - // Skip validation of S3* and EC2* options - if isRequestConfig { - if c.Credentials != nil { - return awserr.New(request.InvalidParameterErrCode, "unsupported config: Credentials per request. Set Credentials at client init", nil) - } - if c.Endpoint != nil { - return awserr.New(request.InvalidParameterErrCode, "unsupported config: Endpoint per request. Set Endpoint at client init", nil) - } - if c.Region != nil { - return awserr.New(request.InvalidParameterErrCode, "unsupported config: Region per request. Set Region at client init", nil) - } - } - return nil + dynamodb.Options } diff --git a/dax/internal/client/request_options_test.go b/dax/internal/client/request_options_test.go deleted file mode 100644 index 8c406b9..0000000 --- a/dax/internal/client/request_options_test.go +++ /dev/null @@ -1,61 +0,0 @@ -/* - Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. - - Licensed under the Apache License, Version 2.0 (the "License"). - You may not use this file except in compliance with the License. - A copy of the License is located at - - http://www.apache.org/licenses/LICENSE-2.0 - - or in the "license" file accompanying this file. This file is distributed - on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - express or implied. See the License for the specific language governing - permissions and limitations under the License. -*/ - -package client - -import ( - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/client/metadata" - "github.com/aws/aws-sdk-go/aws/request" - "reflect" - "testing" - "time" -) - -func TestRequestOptions(t *testing.T) { - e := RequestOptions{ - Logger: aws.NewDefaultLogger(), - LogLevel: aws.LogDebug, - RetryDelay: 1 * time.Second, - MaxRetries: 5, - Context: aws.BackgroundContext(), - } - - r := request.New(aws.Config{}, metadata.ClientInfo{}, request.Handlers{}, nil, &request.Operation{Name: OpPutItem}, nil, nil) - e.applyTo(r) - - a := RequestOptions{} - if err := a.mergeFromRequest(r, true); err != nil { - t.Errorf("unexpected error %v", err) - } - if !reflect.DeepEqual(e, a) { - t.Errorf("expected %v, got %v", e, a) - } - -} - -func TestRequestOptions_MergeFromRequestOptions(t *testing.T) { - in := request.WithLogLevel(aws.LogDebugWithHTTPBody) - out := RequestOptions{} - if err := out.MergeFromRequestOptions(aws.BackgroundContext(), in); err != nil { - t.Errorf("unexpected error %v", err) - } - if aws.LogDebugWithHTTPBody != out.LogLevel { - t.Errorf("expected %v, got %v", aws.LogDebugWithHTTPBody, out.LogLevel) - } - if aws.BackgroundContext() != out.Context { - t.Errorf("expected %v, got %v", aws.BackgroundContext(), out.Context) - } -} diff --git a/dax/internal/client/request_test.go b/dax/internal/client/request_test.go index 3fc2195..87b0b0a 100644 --- a/dax/internal/client/request_test.go +++ b/dax/internal/client/request_test.go @@ -1,18 +1,19 @@ package client import ( - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/dynamodb" "testing" + + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/dynamodb/types" ) func TestHasDuplicatesWriteRequests(t *testing.T) { hk := "hk" - d := []dynamodb.AttributeDefinition{ - {AttributeName: aws.String(hk), AttributeType: aws.String(dynamodb.ScalarAttributeTypeS)}, + d := []types.AttributeDefinition{ + {AttributeName: aws.String(hk), AttributeType: types.ScalarAttributeTypeS}, } cases := []struct { - w []*dynamodb.WriteRequest + w []types.WriteRequest e bool }{ { @@ -20,57 +21,49 @@ func TestHasDuplicatesWriteRequests(t *testing.T) { e: false, }, { - w: []*dynamodb.WriteRequest{}, + w: []types.WriteRequest{}, e: false, }, { - w: []*dynamodb.WriteRequest{nil}, - e: false, - }, - { - w: []*dynamodb.WriteRequest{nil, nil, nil}, - e: false, // continue with request processing - }, - { - w: []*dynamodb.WriteRequest{ - {PutRequest: &dynamodb.PutRequest{Item: map[string]*dynamodb.AttributeValue{hk: {S: aws.String("abc")}}}}, + w: []types.WriteRequest{ + {PutRequest: &types.PutRequest{Item: map[string]types.AttributeValue{hk: &types.AttributeValueMemberS{Value: "abc"}}}}, }, e: false, }, { - w: []*dynamodb.WriteRequest{ - {PutRequest: &dynamodb.PutRequest{Item: map[string]*dynamodb.AttributeValue{hk: {S: aws.String("abc")}}}}, - {PutRequest: &dynamodb.PutRequest{Item: map[string]*dynamodb.AttributeValue{hk: {S: aws.String("abc")}}}}, + w: []types.WriteRequest{ + {PutRequest: &types.PutRequest{Item: map[string]types.AttributeValue{hk: &types.AttributeValueMemberS{Value: "abc"}}}}, + {PutRequest: &types.PutRequest{Item: map[string]types.AttributeValue{hk: &types.AttributeValueMemberS{Value: "abc"}}}}, }, e: true, }, { - w: []*dynamodb.WriteRequest{ - {PutRequest: &dynamodb.PutRequest{Item: map[string]*dynamodb.AttributeValue{hk: {S: aws.String("abc")}}}}, - {PutRequest: &dynamodb.PutRequest{Item: map[string]*dynamodb.AttributeValue{hk: {S: aws.String("def")}}}}, + w: []types.WriteRequest{ + {PutRequest: &types.PutRequest{Item: map[string]types.AttributeValue{hk: &types.AttributeValueMemberS{Value: "abc"}}}}, + {PutRequest: &types.PutRequest{Item: map[string]types.AttributeValue{hk: &types.AttributeValueMemberS{Value: "def"}}}}, }, e: false, }, { - w: []*dynamodb.WriteRequest{ - {PutRequest: &dynamodb.PutRequest{Item: map[string]*dynamodb.AttributeValue{hk: {S: aws.String("abc")}}}}, - {DeleteRequest: &dynamodb.DeleteRequest{Key: map[string]*dynamodb.AttributeValue{hk: {S: aws.String("abc")}}}}, + w: []types.WriteRequest{ + {PutRequest: &types.PutRequest{Item: map[string]types.AttributeValue{hk: &types.AttributeValueMemberS{Value: "abc"}}}}, + {DeleteRequest: &types.DeleteRequest{Key: map[string]types.AttributeValue{hk: &types.AttributeValueMemberS{Value: "abc"}}}}, }, e: true, }, { - w: []*dynamodb.WriteRequest{ - {PutRequest: &dynamodb.PutRequest{Item: map[string]*dynamodb.AttributeValue{hk: {S: aws.String("abc")}}}}, - {DeleteRequest: &dynamodb.DeleteRequest{Key: map[string]*dynamodb.AttributeValue{hk: {S: aws.String("def")}}}}, + w: []types.WriteRequest{ + {PutRequest: &types.PutRequest{Item: map[string]types.AttributeValue{hk: &types.AttributeValueMemberS{Value: "abc"}}}}, + {DeleteRequest: &types.DeleteRequest{Key: map[string]types.AttributeValue{hk: &types.AttributeValueMemberS{Value: "def"}}}}, }, e: false, }, { - w: []*dynamodb.WriteRequest{ - {DeleteRequest: &dynamodb.DeleteRequest{Key: map[string]*dynamodb.AttributeValue{hk: {S: aws.String("abc")}}}}, - {PutRequest: &dynamodb.PutRequest{Item: map[string]*dynamodb.AttributeValue{hk: {S: aws.String("def")}}}}, - {PutRequest: &dynamodb.PutRequest{Item: map[string]*dynamodb.AttributeValue{hk: {S: aws.String("xyz")}}}}, - {DeleteRequest: &dynamodb.DeleteRequest{Key: map[string]*dynamodb.AttributeValue{hk: {S: aws.String("def")}}}}, + w: []types.WriteRequest{ + {DeleteRequest: &types.DeleteRequest{Key: map[string]types.AttributeValue{hk: &types.AttributeValueMemberS{Value: "abc"}}}}, + {PutRequest: &types.PutRequest{Item: map[string]types.AttributeValue{hk: &types.AttributeValueMemberS{Value: "def"}}}}, + {PutRequest: &types.PutRequest{Item: map[string]types.AttributeValue{hk: &types.AttributeValueMemberS{Value: "xyz"}}}}, + {DeleteRequest: &types.DeleteRequest{Key: map[string]types.AttributeValue{hk: &types.AttributeValueMemberS{Value: "def"}}}}, }, e: true, }, @@ -86,58 +79,54 @@ func TestHasDuplicatesWriteRequests(t *testing.T) { func TestHasDuplicateKeysAndAttributes(t *testing.T) { hk := "hk" - d := []dynamodb.AttributeDefinition{ - {AttributeName: aws.String(hk), AttributeType: aws.String(dynamodb.ScalarAttributeTypeS)}, + d := []types.AttributeDefinition{ + {AttributeName: aws.String(hk), AttributeType: types.ScalarAttributeTypeS}, } cases := []struct { - kaas *dynamodb.KeysAndAttributes + kaas types.KeysAndAttributes e bool }{ { - kaas: nil, - e: false, - }, - { - kaas: &dynamodb.KeysAndAttributes{}, + kaas: types.KeysAndAttributes{}, e: false, }, { - kaas: &dynamodb.KeysAndAttributes{Keys: []map[string]*dynamodb.AttributeValue{}}, + kaas: types.KeysAndAttributes{Keys: []map[string]types.AttributeValue{}}, e: false, }, { - kaas: &dynamodb.KeysAndAttributes{Keys: []map[string]*dynamodb.AttributeValue{nil}}, + kaas: types.KeysAndAttributes{Keys: []map[string]types.AttributeValue{nil}}, e: false, }, { - kaas: &dynamodb.KeysAndAttributes{Keys: []map[string]*dynamodb.AttributeValue{nil, nil, nil}}, + kaas: types.KeysAndAttributes{Keys: []map[string]types.AttributeValue{nil, nil, nil}}, e: false, // continue with request processing }, { - kaas: &dynamodb.KeysAndAttributes{Keys: []map[string]*dynamodb.AttributeValue{ - {hk: {S: aws.String("abc")}}, + kaas: types.KeysAndAttributes{Keys: []map[string]types.AttributeValue{ + {hk: &types.AttributeValueMemberS{Value: "abc"}}, }}, e: false, }, { - kaas: &dynamodb.KeysAndAttributes{Keys: []map[string]*dynamodb.AttributeValue{ - {hk: {S: aws.String("abc")}}, - {hk: {S: aws.String("def")}}, + kaas: types.KeysAndAttributes{Keys: []map[string]types.AttributeValue{ + {hk: &types.AttributeValueMemberS{Value: "abc"}}, + {hk: &types.AttributeValueMemberS{Value: "def"}}, }}, e: false, }, { - kaas: &dynamodb.KeysAndAttributes{Keys: []map[string]*dynamodb.AttributeValue{ - {hk: {S: aws.String("abc")}}, - {hk: {S: aws.String("abc")}}, + kaas: types.KeysAndAttributes{Keys: []map[string]types.AttributeValue{ + {hk: &types.AttributeValueMemberS{Value: "abc"}}, + {hk: &types.AttributeValueMemberS{Value: "abc"}}, }}, e: true, }, { - kaas: &dynamodb.KeysAndAttributes{Keys: []map[string]*dynamodb.AttributeValue{ - {hk: {S: aws.String("abc")}}, - {hk: {S: aws.String("def")}}, - {hk: {S: aws.String("abc")}}, + kaas: types.KeysAndAttributes{Keys: []map[string]types.AttributeValue{ + {hk: &types.AttributeValueMemberS{Value: "abc"}}, + {hk: &types.AttributeValueMemberS{Value: "def"}}, + {hk: &types.AttributeValueMemberS{Value: "abc"}}, }}, e: true, }, diff --git a/dax/internal/client/response.go b/dax/internal/client/response.go index e082679..0fb1e3d 100644 --- a/dax/internal/client/response.go +++ b/dax/internal/client/response.go @@ -16,14 +16,16 @@ package client import ( + "context" + "errors" "fmt" "github.com/aws/aws-dax-go/dax/internal/cbor" "github.com/aws/aws-dax-go/dax/internal/lru" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/aws/request" - "github.com/aws/aws-sdk-go/service/dynamodb" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/dynamodb" + "github.com/aws/aws-sdk-go-v2/service/dynamodb/types" + "github.com/aws/smithy-go" ) const ( @@ -67,15 +69,15 @@ const ( ) func decodeEndpointsOutput(reader *cbor.Reader) ([]serviceEndpoint, error) { - len, err := reader.ReadArrayLength() + length, err := reader.ReadArrayLength() if err != nil { return nil, err } - if len <= 0 { + if length <= 0 { return []serviceEndpoint{}, nil } - o := make([]serviceEndpoint, len) - for i := 0; i < len; i++ { + o := make([]serviceEndpoint, length) + for i := 0; i < length; i++ { o[i], err = decodeEndpoint(reader) if err != nil { return nil, err @@ -110,7 +112,7 @@ func decodeEndpoint(reader *cbor.Reader) (serviceEndpoint, error) { return err } else { if role != roleLeader && role != roleReplica { - return awserr.New(request.ErrCodeSerialization, fmt.Sprintf("unknown role %d", role), nil) + return &smithy.SerializationError{Err: fmt.Errorf("unknown role %d", role)} } se.role = role } @@ -139,12 +141,12 @@ func decodeDefineAttributeListIdOutput(reader *cbor.Reader) (int64, error) { } func decodeDefineAttributeListOutput(reader *cbor.Reader) ([]string, error) { - len, err := reader.ReadArrayLength() + length, err := reader.ReadArrayLength() if err != nil { return nil, err } - attrNames := make([]string, len) - for i := 0; i < len; i++ { + attrNames := make([]string, length) + for i := 0; i < length; i++ { an, err := reader.ReadString() if err != nil { return nil, err @@ -154,13 +156,13 @@ func decodeDefineAttributeListOutput(reader *cbor.Reader) ([]string, error) { return attrNames, nil } -func decodeDefineKeySchemaOutput(reader *cbor.Reader) ([]dynamodb.AttributeDefinition, error) { - len, err := reader.ReadMapLength() +func decodeDefineKeySchemaOutput(reader *cbor.Reader) ([]types.AttributeDefinition, error) { + length, err := reader.ReadMapLength() if err != nil { return nil, err } - keys := make([]dynamodb.AttributeDefinition, len) - for i := 0; i < len; i++ { + keys := make([]types.AttributeDefinition, length) + for i := 0; i < length; i++ { name, err := reader.ReadString() if err != nil { return nil, err @@ -169,12 +171,13 @@ func decodeDefineKeySchemaOutput(reader *cbor.Reader) ([]dynamodb.AttributeDefin if err != nil { return nil, err } - keys[i] = dynamodb.AttributeDefinition{AttributeName: &name, AttributeType: &typ} + keys[i] = types.AttributeDefinition{AttributeName: &name, AttributeType: types.ScalarAttributeType(typ)} } return keys, nil } -func decodePutItemOutput(ctx aws.Context, reader *cbor.Reader, input *dynamodb.PutItemInput, keySchemaCache *lru.Lru, attrListIdToNames *lru.Lru, output *dynamodb.PutItemOutput) (*dynamodb.PutItemOutput, error) { +func decodePutItemOutput(ctx context.Context, reader *cbor.Reader, input *dynamodb.PutItemInput, keySchemaCache *lru.Lru, attrListIdToNames *lru.Lru) (*dynamodb.PutItemOutput, error) { + output := &dynamodb.PutItemOutput{} if consumed, err := consumeNil(reader); err != nil { return output, err } else if consumed { @@ -182,13 +185,11 @@ func decodePutItemOutput(ctx aws.Context, reader *cbor.Reader, input *dynamodb.P } tableName := *input.TableName - if output == nil { - output = &dynamodb.PutItemOutput{} - } - var err error - err = consumeMap(reader, func(key int, reader *cbor.Reader) error { + + err := consumeMap(reader, func(key int, reader *cbor.Reader) error { switch key { case responseParamConsumedCapacity: + var err error if output.ConsumedCapacity, err = decodeConsumedCapacity(reader); err != nil { return err } @@ -215,7 +216,7 @@ func decodePutItemOutput(ctx aws.Context, reader *cbor.Reader, input *dynamodb.P } output.Attributes = attrs default: - return awserr.New(request.ErrCodeSerialization, fmt.Sprintf("unknown response param key %d", key), nil) + return &smithy.SerializationError{Err: fmt.Errorf("unknown response param key %d", key)} } return nil }) @@ -226,7 +227,8 @@ func decodePutItemOutput(ctx aws.Context, reader *cbor.Reader, input *dynamodb.P return output, nil } -func decodeDeleteItemOutput(ctx aws.Context, reader *cbor.Reader, input *dynamodb.DeleteItemInput, keySchemaCache *lru.Lru, attrListIdToNames *lru.Lru, output *dynamodb.DeleteItemOutput) (*dynamodb.DeleteItemOutput, error) { +func decodeDeleteItemOutput(ctx context.Context, reader *cbor.Reader, input *dynamodb.DeleteItemInput, keySchemaCache *lru.Lru, attrListIdToNames *lru.Lru) (*dynamodb.DeleteItemOutput, error) { + output := &dynamodb.DeleteItemOutput{} if consumed, err := consumeNil(reader); err != nil { return output, err } else if consumed { @@ -234,13 +236,11 @@ func decodeDeleteItemOutput(ctx aws.Context, reader *cbor.Reader, input *dynamod } tableName := *input.TableName - if output == nil { - output = &dynamodb.DeleteItemOutput{} - } - var err error - err = consumeMap(reader, func(key int, reader *cbor.Reader) error { + + err := consumeMap(reader, func(key int, reader *cbor.Reader) error { switch key { case responseParamConsumedCapacity: + var err error if output.ConsumedCapacity, err = decodeConsumedCapacity(reader); err != nil { return err } @@ -262,7 +262,7 @@ func decodeDeleteItemOutput(ctx aws.Context, reader *cbor.Reader, input *dynamod } output.Attributes = attrs default: - return awserr.New(request.ErrCodeSerialization, fmt.Sprintf("unknown response param key %d", key), nil) + return &smithy.SerializationError{Err: fmt.Errorf("unknown response param key %d", key)} } return nil }) @@ -273,7 +273,11 @@ func decodeDeleteItemOutput(ctx aws.Context, reader *cbor.Reader, input *dynamod return output, nil } -func decodeUpdateItemOutput(ctx aws.Context, reader *cbor.Reader, input *dynamodb.UpdateItemInput, keySchemaCache *lru.Lru, attrListIdToNames *lru.Lru, output *dynamodb.UpdateItemOutput) (*dynamodb.UpdateItemOutput, error) { +func decodeUpdateItemOutput( + ctx context.Context, reader *cbor.Reader, input *dynamodb.UpdateItemInput, + keySchemaCache *lru.Lru, attrListIdToNames *lru.Lru, +) (*dynamodb.UpdateItemOutput, error) { + output := &dynamodb.UpdateItemOutput{} if consumed, err := consumeNil(reader); err != nil { return output, err } else if consumed { @@ -281,13 +285,11 @@ func decodeUpdateItemOutput(ctx aws.Context, reader *cbor.Reader, input *dynamod } tableName := *input.TableName - if output == nil { - output = &dynamodb.UpdateItemOutput{} - } - var err error - err = consumeMap(reader, func(key int, reader *cbor.Reader) error { + + err := consumeMap(reader, func(key int, reader *cbor.Reader) error { switch key { case responseParamConsumedCapacity: + var err error if output.ConsumedCapacity, err = decodeConsumedCapacity(reader); err != nil { return err } @@ -301,11 +303,8 @@ func decodeUpdateItemOutput(ctx aws.Context, reader *cbor.Reader, input *dynamod } case responseParamAttributes: rv := input.ReturnValues - if rv == nil { - return awserr.New(request.ErrCodeSerialization, "unexpected return values", nil) - } - switch *rv { - case dynamodb.ReturnValueAllNew, dynamodb.ReturnValueAllOld: + switch rv { + case types.ReturnValueAllNew, types.ReturnValueAllOld: attrs, err := decodeNonKeyAttributes(ctx, reader, attrListIdToNames, nil) if err != nil { return err @@ -314,15 +313,16 @@ func decodeUpdateItemOutput(ctx aws.Context, reader *cbor.Reader, input *dynamod attrs[k] = v } output.Attributes = attrs - case dynamodb.ReturnValueUpdatedNew, dynamodb.ReturnValueUpdatedOld: + case types.ReturnValueUpdatedNew, types.ReturnValueUpdatedOld: + var err error if output.Attributes, err = decodeAttributeProjection(ctx, reader, attrListIdToNames); err != nil { return err } default: - return awserr.New(request.ErrCodeSerialization, fmt.Sprintf("unexpected return value %s", *rv), nil) + return &smithy.SerializationError{Err: fmt.Errorf("unexpected return value %s", rv)} } default: - return awserr.New(request.ErrCodeSerialization, fmt.Sprintf("unknown response param key %d", key), nil) + return &smithy.SerializationError{Err: fmt.Errorf("unknown response param key %d", key)} } return nil }) @@ -333,7 +333,8 @@ func decodeUpdateItemOutput(ctx aws.Context, reader *cbor.Reader, input *dynamod return output, nil } -func decodeGetItemOutput(ctx aws.Context, reader *cbor.Reader, input *dynamodb.GetItemInput, attrListIdToNames *lru.Lru, output *dynamodb.GetItemOutput) (*dynamodb.GetItemOutput, error) { +func decodeGetItemOutput(ctx context.Context, reader *cbor.Reader, input *dynamodb.GetItemInput, attrListIdToNames *lru.Lru) (*dynamodb.GetItemOutput, error) { + output := &dynamodb.GetItemOutput{} if consumed, err := consumeNil(reader); err != nil { return output, err } else if consumed { @@ -344,9 +345,7 @@ func decodeGetItemOutput(ctx aws.Context, reader *cbor.Reader, input *dynamodb.G if err != nil { return output, err } - if output == nil { - output = &dynamodb.GetItemOutput{} - } + err = consumeMap(reader, func(key int, reader *cbor.Reader) error { switch key { case responseParamConsumedCapacity: @@ -365,7 +364,7 @@ func decodeGetItemOutput(ctx aws.Context, reader *cbor.Reader, input *dynamodb.G } output.Item = item default: - return awserr.New(request.ErrCodeSerialization, fmt.Sprintf("unknown response param key %d", key), nil) + return &smithy.SerializationError{Err: fmt.Errorf("unknown response param key %d", key)} } return nil }) @@ -376,7 +375,8 @@ func decodeGetItemOutput(ctx aws.Context, reader *cbor.Reader, input *dynamodb.G return output, nil } -func decodeScanOutput(ctx aws.Context, reader *cbor.Reader, input *dynamodb.ScanInput, keySchemaCache *lru.Lru, attrNamesListToId *lru.Lru, output *dynamodb.ScanOutput) (*dynamodb.ScanOutput, error) { +func decodeScanOutput(ctx context.Context, reader *cbor.Reader, input *dynamodb.ScanInput, keySchemaCache *lru.Lru, attrNamesListToId *lru.Lru) (*dynamodb.ScanOutput, error) { + output := &dynamodb.ScanOutput{} out, err := decodeScanQueryOutput(ctx, reader, *input.TableName, input.IndexName != nil, input.ProjectionExpression, input.ExpressionAttributeNames, keySchemaCache, attrNamesListToId) if err != nil { return output, err @@ -387,7 +387,8 @@ func decodeScanOutput(ctx aws.Context, reader *cbor.Reader, input *dynamodb.Scan return out.scanOutput(output), nil } -func decodeQueryOutput(ctx aws.Context, reader *cbor.Reader, input *dynamodb.QueryInput, keySchemaCache *lru.Lru, attrNamesListToId *lru.Lru, output *dynamodb.QueryOutput) (*dynamodb.QueryOutput, error) { +func decodeQueryOutput(ctx context.Context, reader *cbor.Reader, input *dynamodb.QueryInput, keySchemaCache *lru.Lru, attrNamesListToId *lru.Lru) (*dynamodb.QueryOutput, error) { + output := &dynamodb.QueryOutput{} out, err := decodeScanQueryOutput(ctx, reader, *input.TableName, input.IndexName != nil, input.ProjectionExpression, input.ExpressionAttributeNames, keySchemaCache, attrNamesListToId) if err != nil { return output, err @@ -432,7 +433,7 @@ func (o *scanQueryOutput) queryOutput(output *dynamodb.QueryOutput) *dynamodb.Qu } } -func decodeScanQueryOutput(ctx aws.Context, reader *cbor.Reader, table string, indexed bool, projection *string, exprAttrNames map[string]*string, keySchemaCache *lru.Lru, attrNamesListToId *lru.Lru) (*scanQueryOutput, error) { +func decodeScanQueryOutput(ctx context.Context, reader *cbor.Reader, table string, indexed bool, projection *string, exprAttrNames map[string]string, keySchemaCache *lru.Lru, attrNamesListToId *lru.Lru) (*scanQueryOutput, error) { if consumed, err := consumeNil(reader); err != nil { return nil, err } else if consumed { @@ -440,7 +441,7 @@ func decodeScanQueryOutput(ctx aws.Context, reader *cbor.Reader, table string, i } out := &scanQueryOutput{} - out.Items = []map[string]*dynamodb.AttributeValue{} + out.Items = []map[string]types.AttributeValue{} var err error err = consumeMap(reader, func(key int, reader *cbor.Reader) error { switch key { @@ -461,13 +462,13 @@ func decodeScanQueryOutput(ctx aws.Context, reader *cbor.Reader, table string, i if err != nil { return err } - out.Count = &c + out.Count = int32(c) case responseParamScannedCount: c, err := reader.ReadInt64() if err != nil { return err } - out.ScannedCount = &c + out.ScannedCount = int32(c) case responseParamLastEvaluatedKey: k, err := decodeLastEvaluatedKey(ctx, reader, table, indexed, keySchemaCache) if err != nil { @@ -477,7 +478,7 @@ func decodeScanQueryOutput(ctx aws.Context, reader *cbor.Reader, table string, i out.LastEvaluatedKey = k } default: - return awserr.New(request.ErrCodeSerialization, fmt.Sprintf("unknown response param key %d", key), nil) + return &smithy.SerializationError{Err: fmt.Errorf("unknown response param key %d", key)} } return nil }) @@ -487,9 +488,9 @@ func decodeScanQueryOutput(ctx aws.Context, reader *cbor.Reader, table string, i return out, nil } -func decodeBatchWriteItemOutput(ctx aws.Context, reader *cbor.Reader, keySchemaCache *lru.Lru, attrNamesListToId *lru.Lru, output *dynamodb.BatchWriteItemOutput) (*dynamodb.BatchWriteItemOutput, error) { +func decodeBatchWriteItemOutput(ctx context.Context, reader *cbor.Reader, keySchemaCache *lru.Lru, attrNamesListToId *lru.Lru, output *dynamodb.BatchWriteItemOutput) (*dynamodb.BatchWriteItemOutput, error) { if output != nil { - output.UnprocessedItems = map[string][]*dynamodb.WriteRequest{} + output.UnprocessedItems = map[string][]types.WriteRequest{} } if consumed, err := consumeNil(reader); err != nil { return output, err @@ -501,10 +502,10 @@ func decodeBatchWriteItemOutput(ctx aws.Context, reader *cbor.Reader, keySchemaC return output, err } if output == nil { - output = &dynamodb.BatchWriteItemOutput{UnprocessedItems: map[string][]*dynamodb.WriteRequest{}} + output = &dynamodb.BatchWriteItemOutput{UnprocessedItems: map[string][]types.WriteRequest{}} } if numTables > 0 { - unprocessed := make(map[string][]*dynamodb.WriteRequest, numTables) + unprocessed := make(map[string][]types.WriteRequest, numTables) for i := 0; i < numTables; i++ { table, err := reader.ReadString() if err != nil { @@ -519,7 +520,7 @@ func decodeBatchWriteItemOutput(ctx aws.Context, reader *cbor.Reader, keySchemaC return output, err } numItems := numObjs / 2 - wrs := make([]*dynamodb.WriteRequest, numItems) + wrs := make([]types.WriteRequest, numItems) for j := 0; j < numItems; j++ { keys, err := decodeKey(reader, tableKeys) if err != nil { @@ -529,16 +530,16 @@ func decodeBatchWriteItemOutput(ctx aws.Context, reader *cbor.Reader, keySchemaC if err != nil { return output, err } - wr := dynamodb.WriteRequest{} + wr := types.WriteRequest{} if item == nil { - wr.DeleteRequest = &dynamodb.DeleteRequest{Key: keys} + wr.DeleteRequest = &types.DeleteRequest{Key: keys} } else { for k, v := range keys { item[k] = v } - wr.PutRequest = &dynamodb.PutRequest{Item: item} + wr.PutRequest = &types.PutRequest{Item: item} } - wrs[j] = &wr + wrs[j] = wr } unprocessed[table] = wrs } @@ -552,11 +553,13 @@ func decodeBatchWriteItemOutput(ctx aws.Context, reader *cbor.Reader, keySchemaC return output, err } if numCC > 0 { - output.ConsumedCapacity = make([]*dynamodb.ConsumedCapacity, numCC) + output.ConsumedCapacity = make([]types.ConsumedCapacity, numCC) for i := 0; i < numCC; i++ { - if output.ConsumedCapacity[i], err = decodeConsumedCapacity(reader); err != nil { + capacity, err := decodeConsumedCapacity(reader) + if err != nil { return output, err } + output.ConsumedCapacity[i] = *capacity } } @@ -565,7 +568,7 @@ func decodeBatchWriteItemOutput(ctx aws.Context, reader *cbor.Reader, keySchemaC return output, err } if icmLen > 0 { - output.ItemCollectionMetrics = make(map[string][]*dynamodb.ItemCollectionMetrics, icmLen) + output.ItemCollectionMetrics = make(map[string][]types.ItemCollectionMetrics, icmLen) for i := 0; i < icmLen; i++ { table, err := reader.ReadString() if err != nil { @@ -580,12 +583,13 @@ func decodeBatchWriteItemOutput(ctx aws.Context, reader *cbor.Reader, keySchemaC if err != nil { return output, err } - metrics := make([]*dynamodb.ItemCollectionMetrics, numMetrics) + metrics := make([]types.ItemCollectionMetrics, numMetrics) for j := 0; j < numMetrics; j++ { - metrics[j], err = decodeItemCollectionMetrics(reader, pkey) + m, err := decodeItemCollectionMetrics(reader, pkey) if err != nil { return output, err } + metrics[j] = *m } output.ItemCollectionMetrics[table] = metrics } @@ -594,7 +598,10 @@ func decodeBatchWriteItemOutput(ctx aws.Context, reader *cbor.Reader, keySchemaC return output, nil } -func decodeBatchGetItemOutput(ctx aws.Context, reader *cbor.Reader, input *dynamodb.BatchGetItemInput, keySchemaCache *lru.Lru, attrNamesListToId *lru.Lru, output *dynamodb.BatchGetItemOutput) (*dynamodb.BatchGetItemOutput, error) { +func decodeBatchGetItemOutput( + ctx context.Context, reader *cbor.Reader, input *dynamodb.BatchGetItemInput, + keySchemaCache *lru.Lru, attrNamesListToId *lru.Lru, output *dynamodb.BatchGetItemOutput, +) (*dynamodb.BatchGetItemOutput, error) { if consumed, err := consumeNil(reader); err != nil { return output, err } else if consumed { @@ -606,12 +613,12 @@ func decodeBatchGetItemOutput(ctx aws.Context, reader *cbor.Reader, input *dynam return output, err } if l != 2 { - return output, awserr.New(request.ErrCodeSerialization, fmt.Sprintf("Unexpected number of objects %d in BatchGetItemOutput", l), nil) + return output, &smithy.SerializationError{Err: fmt.Errorf("Unexpected number of objects %d in BatchGetItemOutput", l)} } projectionsByTable := make(map[string][]documentPath, len(input.RequestItems)) for table, kaas := range input.RequestItems { - if kaas != nil && kaas.ProjectionExpression != nil { + if kaas.ProjectionExpression != nil { dp, err := buildProjectionOrdinals(kaas.ProjectionExpression, kaas.ExpressionAttributeNames) if err != nil { return output, err @@ -629,7 +636,7 @@ func decodeBatchGetItemOutput(ctx aws.Context, reader *cbor.Reader, input *dynam output = &dynamodb.BatchGetItemOutput{} } if numTables > 0 { - output.Responses = make(map[string][]map[string]*dynamodb.AttributeValue, numTables) + output.Responses = make(map[string][]map[string]types.AttributeValue, numTables) for i := 0; i < numTables; i++ { table, err := reader.ReadString() if err != nil { @@ -642,7 +649,7 @@ func decodeBatchGetItemOutput(ctx aws.Context, reader *cbor.Reader, input *dynam if err != nil { return output, err } - items := make([]map[string]*dynamodb.AttributeValue, numItems) + items := make([]map[string]types.AttributeValue, numItems) for j := 0; j < numItems; j++ { if items[j], err = decodeNonKeyAttributes(ctx, reader, attrNamesListToId, projections); err != nil { return output, err @@ -659,7 +666,7 @@ func decodeBatchGetItemOutput(ctx aws.Context, reader *cbor.Reader, input *dynam return output, err } numItems := numObjs / 2 - items := make([]map[string]*dynamodb.AttributeValue, numItems) + items := make([]map[string]types.AttributeValue, numItems) for j := 0; j < numItems; j++ { keys, err := decodeKey(reader, tableKeys) if err != nil { @@ -684,7 +691,7 @@ func decodeBatchGetItemOutput(ctx aws.Context, reader *cbor.Reader, input *dynam return output, err } if numUnprocessed > 0 { - unprocessed := make(map[string]*dynamodb.KeysAndAttributes, numUnprocessed) + unprocessed := make(map[string]types.KeysAndAttributes, numUnprocessed) for i := 0; i < numUnprocessed; i++ { table, err := reader.ReadString() if err != nil { @@ -701,13 +708,13 @@ func decodeBatchGetItemOutput(ctx aws.Context, reader *cbor.Reader, input *dynam if numKeys <= 0 { continue } - keys := make([]map[string]*dynamodb.AttributeValue, numKeys) + keys := make([]map[string]types.AttributeValue, numKeys) for j := 0; j < numKeys; j++ { if keys[j], err = decodeKey(reader, tableKeys); err != nil { return output, err } } - outKaas := &dynamodb.KeysAndAttributes{Keys: keys} + outKaas := types.KeysAndAttributes{Keys: keys} if inKaas, ok := input.RequestItems[table]; ok { outKaas.AttributesToGet = inKaas.AttributesToGet outKaas.ConsistentRead = inKaas.ConsistentRead @@ -727,18 +734,20 @@ func decodeBatchGetItemOutput(ctx aws.Context, reader *cbor.Reader, input *dynam return output, err } if numCC > 0 { - output.ConsumedCapacity = make([]*dynamodb.ConsumedCapacity, numCC) + output.ConsumedCapacity = make([]types.ConsumedCapacity, numCC) for i := 0; i < numCC; i++ { - if output.ConsumedCapacity[i], err = decodeConsumedCapacity(reader); err != nil { + capacity, err := decodeConsumedCapacity(reader) + if err != nil { return output, err } + output.ConsumedCapacity[i] = *capacity } } return output, nil } -func decodeTransactWriteItemsOutput(ctx aws.Context, reader *cbor.Reader, input *dynamodb.TransactWriteItemsInput, keySchemaCache *lru.Lru, attrListIdToNames *lru.Lru, output *dynamodb.TransactWriteItemsOutput) (*dynamodb.TransactWriteItemsOutput, error) { +func decodeTransactWriteItemsOutput(ctx context.Context, reader *cbor.Reader, input *dynamodb.TransactWriteItemsInput, keySchemaCache *lru.Lru, attrListIdToNames *lru.Lru, output *dynamodb.TransactWriteItemsOutput) (*dynamodb.TransactWriteItemsOutput, error) { len, err := reader.ReadArrayLength() if err != nil { return output, err @@ -746,7 +755,7 @@ func decodeTransactWriteItemsOutput(ctx aws.Context, reader *cbor.Reader, input if len != 3 { // returnValues still in the tube even though it's not being returned // But user shouldn't be able to see it. - return output, awserr.New(request.ErrCodeSerialization, fmt.Sprintf("TransactWriteResponse needs to have 2 elements, instead had: %d", len), nil) + return output, &smithy.SerializationError{Err: fmt.Errorf("TransactWriteResponse needs to have 2 elements, instead had: %d", len)} } _, err = reader.ReadArrayLength() if err != nil { @@ -761,11 +770,13 @@ func decodeTransactWriteItemsOutput(ctx aws.Context, reader *cbor.Reader, input return output, err } if numCC > 0 { - output.ConsumedCapacity = make([]*dynamodb.ConsumedCapacity, numCC) + output.ConsumedCapacity = make([]types.ConsumedCapacity, numCC) for i := 0; i < numCC; i++ { - if output.ConsumedCapacity[i], err = decodeConsumedCapacityExtended(reader); err != nil { + capacity, err := decodeConsumedCapacityExtended(reader) + if err != nil { return output, err } + output.ConsumedCapacity[i] = *capacity } } @@ -774,7 +785,7 @@ func decodeTransactWriteItemsOutput(ctx aws.Context, reader *cbor.Reader, input return output, err } if icmLen > 0 { - output.ItemCollectionMetrics = make(map[string][]*dynamodb.ItemCollectionMetrics, icmLen) + output.ItemCollectionMetrics = make(map[string][]types.ItemCollectionMetrics, icmLen) for i := 0; i < icmLen; i++ { table, err := reader.ReadString() if err != nil { @@ -789,12 +800,13 @@ func decodeTransactWriteItemsOutput(ctx aws.Context, reader *cbor.Reader, input if err != nil { return output, err } - metrics := make([]*dynamodb.ItemCollectionMetrics, numMetrics) + metrics := make([]types.ItemCollectionMetrics, numMetrics) for j := 0; j < numMetrics; j++ { - metrics[j], err = decodeItemCollectionMetrics(reader, pkey) + m, err := decodeItemCollectionMetrics(reader, pkey) if err != nil { return output, err } + metrics[j] = *m } output.ItemCollectionMetrics[table] = metrics } @@ -803,13 +815,13 @@ func decodeTransactWriteItemsOutput(ctx aws.Context, reader *cbor.Reader, input return output, nil } -func decodeTransactGetItemsOutput(ctx aws.Context, reader *cbor.Reader, input *dynamodb.TransactGetItemsInput, keySchemaCache *lru.Lru, attrListIdToNames *lru.Lru, output *dynamodb.TransactGetItemsOutput) (*dynamodb.TransactGetItemsOutput, error) { +func decodeTransactGetItemsOutput(ctx context.Context, reader *cbor.Reader, input *dynamodb.TransactGetItemsInput, keySchemaCache *lru.Lru, attrListIdToNames *lru.Lru, output *dynamodb.TransactGetItemsOutput) (*dynamodb.TransactGetItemsOutput, error) { length, err := reader.ReadArrayLength() if err != nil { return output, err } if length != 2 { - return output, awserr.New(request.ErrCodeSerialization, fmt.Sprintf("TransactGetResponse needs to have 2 elements, instead had: %d", length), nil) + return output, &smithy.SerializationError{Err: fmt.Errorf("TransactGetResponse needs to have 2 elements, instead had: %d", length)} } if output == nil { @@ -821,11 +833,11 @@ func decodeTransactGetItemsOutput(ctx aws.Context, reader *cbor.Reader, input *d return output, err } if numR != len(input.TransactItems) { - return output, awserr.New(request.ErrCodeSerialization, fmt.Sprintf("TransactGetResponse need to have the same number of Responses "+ - "as the length of TransactItems in the input: %d, instead had: %d", len(input.TransactItems), numR), nil) + return output, &smithy.SerializationError{Err: fmt.Errorf("TransactGetResponse need to have the same number of Responses "+ + "as the length of TransactItems in the input: %d, instead had: %d", len(input.TransactItems), numR)} } - responses := make([]*dynamodb.ItemResponse, numR) + responses := make([]types.ItemResponse, numR) for i := 0; i < numR; i++ { get := input.TransactItems[i].Get projectionOrdinals, err := buildProjectionOrdinals(get.ProjectionExpression, get.ExpressionAttributeNames) @@ -842,7 +854,7 @@ func decodeTransactGetItemsOutput(ctx aws.Context, reader *cbor.Reader, input *d item[k] = v } } - responses[i] = &dynamodb.ItemResponse{Item: item} + responses[i] = types.ItemResponse{Item: item} } output.Responses = responses @@ -851,18 +863,20 @@ func decodeTransactGetItemsOutput(ctx aws.Context, reader *cbor.Reader, input *d return output, err } if numCC > 0 { - output.ConsumedCapacity = make([]*dynamodb.ConsumedCapacity, numCC) + output.ConsumedCapacity = make([]types.ConsumedCapacity, numCC) for i := 0; i < numCC; i++ { - if output.ConsumedCapacity[i], err = decodeConsumedCapacityExtended(reader); err != nil { + capacity, err := decodeConsumedCapacityExtended(reader) + if err != nil { return output, err } + output.ConsumedCapacity[i] = *capacity } } return output, nil } -func decodeScanQueryItems(ctx aws.Context, reader *cbor.Reader, table string, keySchemaCache *lru.Lru, attrNamesListToId *lru.Lru, projectionOrdinals []documentPath) ([]map[string]*dynamodb.AttributeValue, error) { +func decodeScanQueryItems(ctx context.Context, reader *cbor.Reader, table string, keySchemaCache *lru.Lru, attrNamesListToId *lru.Lru, projectionOrdinals []documentPath) ([]map[string]types.AttributeValue, error) { consumed, err := consumeNil(reader) if err != nil { return nil, err @@ -871,7 +885,7 @@ func decodeScanQueryItems(ctx aws.Context, reader *cbor.Reader, table string, ke return nil, nil } - items := []map[string]*dynamodb.AttributeValue{} + items := []map[string]types.AttributeValue{} if len(projectionOrdinals) > 0 { err := consumeArray(reader, func(reader *cbor.Reader) error { i, err := decodeProjection(reader, projectionOrdinals) @@ -890,12 +904,12 @@ func decodeScanQueryItems(ctx aws.Context, reader *cbor.Reader, table string, ke return nil, err } err = consumeArray(reader, func(reader *cbor.Reader) error { - len, err := reader.ReadArrayLength() + length, err := reader.ReadArrayLength() if err != nil { return err } - if len != 2 { - return awserr.New(request.ErrCodeSerialization, fmt.Sprintf("expected array of size 2 containing key and value, got %d", len), nil) + if length != 2 { + return &smithy.SerializationError{Err: fmt.Errorf("expected array of size 2 containing key and value, got %d", length)} } key, err := decodeKey(reader, tableKeys) if err != nil { @@ -918,7 +932,7 @@ func decodeScanQueryItems(ctx aws.Context, reader *cbor.Reader, table string, ke return items, nil } -func decodeLastEvaluatedKey(ctx aws.Context, reader *cbor.Reader, table string, indexed bool, keySchemaCache *lru.Lru) (map[string]*dynamodb.AttributeValue, error) { +func decodeLastEvaluatedKey(ctx context.Context, reader *cbor.Reader, table string, indexed bool, keySchemaCache *lru.Lru) (map[string]types.AttributeValue, error) { if indexed { key, err := decodeCompoundKey(reader) if err != nil { @@ -1029,7 +1043,7 @@ func consumeBreak(reader *cbor.Reader) (bool, error) { return true, nil } -func decodeKey(reader *cbor.Reader, keys []dynamodb.AttributeDefinition) (map[string]*dynamodb.AttributeValue, error) { +func decodeKey(reader *cbor.Reader, keys []types.AttributeDefinition) (map[string]types.AttributeValue, error) { consumed, err := consumeNil(reader) if err != nil { return nil, err @@ -1044,7 +1058,7 @@ func decodeKey(reader *cbor.Reader, keys []dynamodb.AttributeDefinition) (map[st return k, nil } -func decodeCompoundKey(reader *cbor.Reader) (map[string]*dynamodb.AttributeValue, error) { +func decodeCompoundKey(reader *cbor.Reader) (map[string]types.AttributeValue, error) { consumed, err := consumeNil(reader) if err != nil { return nil, err @@ -1064,13 +1078,13 @@ func decodeCompoundKey(reader *cbor.Reader) (map[string]*dynamodb.AttributeValue return nil, err } if hdr != cbor.MapStream { - return nil, awserr.New(request.ErrCodeSerialization, "bad compound key", nil) + return nil, &smithy.SerializationError{Err: errors.New("bad compound key")} } _, err = r.ReadMapLength() if err != nil { return nil, err } - key := make(map[string]*dynamodb.AttributeValue, 4) + key := make(map[string]types.AttributeValue, 4) for { consumed, err := consumeBreak(r) if err != nil { @@ -1093,7 +1107,7 @@ func decodeCompoundKey(reader *cbor.Reader) (map[string]*dynamodb.AttributeValue return key, nil } -func decodeNonKeyAttributes(ctx aws.Context, reader *cbor.Reader, attrNamesListToId *lru.Lru, projectionOrdinals []documentPath) (map[string]*dynamodb.AttributeValue, error) { +func decodeNonKeyAttributes(ctx context.Context, reader *cbor.Reader, attrNamesListToId *lru.Lru, projectionOrdinals []documentPath) (map[string]types.AttributeValue, error) { hdr, err := reader.PeekHeader() if err != nil { return nil, err @@ -1120,15 +1134,15 @@ func decodeNonKeyAttributes(ctx aws.Context, reader *cbor.Reader, attrNamesListT case cbor.Map: return decodeProjection(reader, projectionOrdinals) } - return nil, awserr.New(request.ErrCodeSerialization, fmt.Sprintf("unexpected cbor type %v", hdr), nil) + return nil, &smithy.SerializationError{Err: fmt.Errorf("unexpected cbor type %v", hdr)} } -func decodeProjection(reader *cbor.Reader, projectionOrdinals []documentPath) (map[string]*dynamodb.AttributeValue, error) { +func decodeProjection(reader *cbor.Reader, projectionOrdinals []documentPath) (map[string]types.AttributeValue, error) { ib := &itemBuilder{} err := consumeMap(reader, func(ord int, r *cbor.Reader) error { if ord > len(projectionOrdinals) { - return awserr.New(request.ErrCodeSerialization, fmt.Sprintf("unexpected ordinal %v", ord), nil) + return &smithy.SerializationError{Err: fmt.Errorf("unexpected ordinal %v", ord)} } p := projectionOrdinals[ord] v, err := cbor.DecodeAttributeValue(r) @@ -1144,7 +1158,7 @@ func decodeProjection(reader *cbor.Reader, projectionOrdinals []documentPath) (m return ib.toItem(), nil } -func decodeAttributeProjection(ctx aws.Context, reader *cbor.Reader, attrListIdToNames *lru.Lru) (map[string]*dynamodb.AttributeValue, error) { +func decodeAttributeProjection(ctx context.Context, reader *cbor.Reader, attrListIdToNames *lru.Lru) (map[string]types.AttributeValue, error) { r, err := reader.BytesReader() if err != nil { return nil, err @@ -1161,12 +1175,12 @@ func decodeAttributeProjection(ctx aws.Context, reader *cbor.Reader, attrListIdT } ans, ok := attrNames.([]string) if !ok { - return nil, awserr.New(request.ErrCodeSerialization, "invalid type for attribute names list", nil) + return nil, &smithy.SerializationError{Err: errors.New("invalid type for attribute names list")} } - attrs := make(map[string]*dynamodb.AttributeValue) + attrs := make(map[string]types.AttributeValue) err = consumeMap(r, func(ord int, reader *cbor.Reader) error { if ord > len(ans) { - return awserr.New(request.ErrCodeSerialization, "invalid ordinal", nil) + return &smithy.SerializationError{Err: errors.New("invalid ordinal")} } av, err := cbor.DecodeAttributeValue(reader) if err != nil { @@ -1178,7 +1192,7 @@ func decodeAttributeProjection(ctx aws.Context, reader *cbor.Reader, attrListIdT return attrs, nil } -func decodeConsumedCapacity(reader *cbor.Reader) (*dynamodb.ConsumedCapacity, error) { +func decodeConsumedCapacity(reader *cbor.Reader) (*types.ConsumedCapacity, error) { consumed, err := consumeNil(reader) if err != nil { return nil, err @@ -1191,7 +1205,7 @@ func decodeConsumedCapacity(reader *cbor.Reader) (*dynamodb.ConsumedCapacity, er return nil, err } - cc := &dynamodb.ConsumedCapacity{} + cc := &types.ConsumedCapacity{} t, err := reader.ReadString() if err != nil { @@ -1214,7 +1228,7 @@ func decodeConsumedCapacity(reader *cbor.Reader) (*dynamodb.ConsumedCapacity, er if err != nil { return nil, err } - cc.Table = &dynamodb.Capacity{ + cc.Table = &types.Capacity{ CapacityUnits: aws.Float64(c), } } @@ -1231,7 +1245,7 @@ func decodeConsumedCapacity(reader *cbor.Reader) (*dynamodb.ConsumedCapacity, er return cc, nil } -func decodeConsumedCapacityExtended(reader *cbor.Reader) (*dynamodb.ConsumedCapacity, error) { +func decodeConsumedCapacityExtended(reader *cbor.Reader) (*types.ConsumedCapacity, error) { consumed, err := consumeNil(reader) if err != nil { return nil, err @@ -1240,7 +1254,7 @@ func decodeConsumedCapacityExtended(reader *cbor.Reader) (*dynamodb.ConsumedCapa return nil, nil } - cc := &dynamodb.ConsumedCapacity{} + cc := &types.ConsumedCapacity{} err = consumeMap(reader, func(key int, reader *cbor.Reader) error { switch key { case tableName: @@ -1248,45 +1262,45 @@ func decodeConsumedCapacityExtended(reader *cbor.Reader) (*dynamodb.ConsumedCapa if err != nil { return err } - cc.SetTableName(s) + cc.TableName = &s case capacityUnits: f, err := reader.ReadFloat64() if err != nil { return err } - cc.SetCapacityUnits(f) + cc.CapacityUnits = &f case readCapacityUnits: f, err := reader.ReadFloat64() if err != nil { return err } - cc.SetReadCapacityUnits(f) + cc.ReadCapacityUnits = &f case writeCapacityUnits: f, err := reader.ReadFloat64() if err != nil { return err } - cc.SetWriteCapacityUnits(f) + cc.WriteCapacityUnits = &f case table: c, err := decodeCapacity(reader) if err != nil { return err } - cc.SetTable(c) + cc.Table = c case globalSecondaryIndexes: c, err := decodeIndexConsumedCapacity(reader, true) if err != nil { return err } - cc.SetGlobalSecondaryIndexes(c) + cc.GlobalSecondaryIndexes = c case localSecondaryIndexes: c, err := decodeIndexConsumedCapacity(reader, true) if err != nil { return err } - cc.SetLocalSecondaryIndexes(c) + cc.LocalSecondaryIndexes = c default: - return awserr.New(request.ErrCodeSerialization, fmt.Sprintf("unknown response param key %d", key), nil) + return &smithy.SerializationError{Err: fmt.Errorf("unknown response param key %d", key)} } return nil }) @@ -1296,7 +1310,7 @@ func decodeConsumedCapacityExtended(reader *cbor.Reader) (*dynamodb.ConsumedCapa return cc, nil } -func decodeCapacity(reader *cbor.Reader) (*dynamodb.Capacity, error) { +func decodeCapacity(reader *cbor.Reader) (*types.Capacity, error) { consumed, err := consumeNil(reader) if err != nil { return nil, err @@ -1305,7 +1319,7 @@ func decodeCapacity(reader *cbor.Reader) (*dynamodb.Capacity, error) { return nil, nil } - c := &dynamodb.Capacity{} + c := &types.Capacity{} err = consumeMap(reader, func(key int, reader *cbor.Reader) error { switch key { case capacityUnits: @@ -1313,21 +1327,21 @@ func decodeCapacity(reader *cbor.Reader) (*dynamodb.Capacity, error) { if err != nil { return err } - c.SetCapacityUnits(f) + c.CapacityUnits = &f case readCapacityUnits: f, err := reader.ReadFloat64() if err != nil { return err } - c.SetReadCapacityUnits(f) + c.ReadCapacityUnits = &f case writeCapacityUnits: f, err := reader.ReadFloat64() if err != nil { return err } - c.SetWriteCapacityUnits(f) + c.WriteCapacityUnits = &f default: - return awserr.New(request.ErrCodeSerialization, fmt.Sprintf("unknown response param key %d", key), nil) + return &smithy.SerializationError{Err: fmt.Errorf("unknown response param key %d", key)} } return nil }) @@ -1337,7 +1351,7 @@ func decodeCapacity(reader *cbor.Reader) (*dynamodb.Capacity, error) { return c, nil } -func decodeIndexConsumedCapacity(reader *cbor.Reader, extended bool) (map[string]*dynamodb.Capacity, error) { +func decodeIndexConsumedCapacity(reader *cbor.Reader, extended bool) (map[string]types.Capacity, error) { consumed, err := consumeNil(reader) if err != nil { return nil, err @@ -1350,14 +1364,14 @@ func decodeIndexConsumedCapacity(reader *cbor.Reader, extended bool) (map[string if err != nil { return nil, err } - index := make(map[string]*dynamodb.Capacity, len) + index := make(map[string]types.Capacity, len) for len > 0 { len-- i, err := reader.ReadString() if err != nil { return nil, err } - var c *dynamodb.Capacity + var c *types.Capacity if extended { c, err = decodeCapacity(reader) if err != nil { @@ -1368,16 +1382,16 @@ func decodeIndexConsumedCapacity(reader *cbor.Reader, extended bool) (map[string if err != nil { return nil, err } - c = &dynamodb.Capacity{ + c = &types.Capacity{ CapacityUnits: aws.Float64(f), } } - index[i] = c + index[i] = *c } return index, nil } -func decodeItemCollectionMetrics(reader *cbor.Reader, partitionKey string) (*dynamodb.ItemCollectionMetrics, error) { +func decodeItemCollectionMetrics(reader *cbor.Reader, partitionKey string) (*types.ItemCollectionMetrics, error) { consumed, err := consumeNil(reader) if err != nil { return nil, err @@ -1403,23 +1417,23 @@ func decodeItemCollectionMetrics(reader *cbor.Reader, partitionKey string) (*dyn return nil, err } - icm := dynamodb.ItemCollectionMetrics{ - ItemCollectionKey: map[string]*dynamodb.AttributeValue{ + icm := types.ItemCollectionMetrics{ + ItemCollectionKey: map[string]types.AttributeValue{ partitionKey: av, }, - SizeEstimateRangeGB: []*float64{&l, &r}, + SizeEstimateRangeGB: []float64{l, r}, } return &icm, nil } -func getKeySchema(ctx aws.Context, keySchemaCache *lru.Lru, table string) ([]dynamodb.AttributeDefinition, error) { +func getKeySchema(ctx context.Context, keySchemaCache *lru.Lru, table string) ([]types.AttributeDefinition, error) { k, err := keySchemaCache.GetWithContext(ctx, table) if err != nil { return nil, err } - keys, ok := k.([]dynamodb.AttributeDefinition) + keys, ok := k.([]types.AttributeDefinition) if !ok { - return nil, awserr.New(request.ErrCodeSerialization, "invalid type for keyschema", nil) + return nil, &smithy.SerializationError{Err: errors.New("invalid type for keyschema")} } return keys, nil } diff --git a/dax/internal/client/sigv4.go b/dax/internal/client/sigv4.go index f526b8b..bd7c865 100644 --- a/dax/internal/client/sigv4.go +++ b/dax/internal/client/sigv4.go @@ -19,9 +19,10 @@ import ( "crypto/hmac" "crypto/sha256" "encoding/hex" - "github.com/aws/aws-sdk-go/aws/credentials" "strings" "time" + + "github.com/aws/aws-sdk-go-v2/aws" ) const ( @@ -42,11 +43,11 @@ const ( var signedHeaders = []string{headerHost, headerDate} var signedHeadersBytes = []byte(strings.Join(signedHeaders, ";")) -func generateSigV4(credentials credentials.Value, hostname, region, payload string) (string, string) { +func generateSigV4(credentials aws.Credentials, hostname, region, payload string) (string, string) { return generateSigV4WithTime(credentials, hostname, region, payload, time.Now().UTC()) } -func generateSigV4WithTime(credentials credentials.Value, hostname, region, payload string, time time.Time) (string, string) { +func generateSigV4WithTime(credentials aws.Credentials, hostname, region, payload string, time time.Time) (string, string) { headers := sigv4Headers(hostname, time, credentials.SessionToken) canonicalRequest := make([]byte, 0, 256) // 4 + 1 + 1 + 1 + 1 + (74+1+28+1) + 1 + 16 + 1 + 64 + 25% diff --git a/dax/internal/client/sigv4_test.go b/dax/internal/client/sigv4_test.go index cfe5b48..06c69f5 100644 --- a/dax/internal/client/sigv4_test.go +++ b/dax/internal/client/sigv4_test.go @@ -20,11 +20,11 @@ import ( "testing" "time" - "github.com/aws/aws-sdk-go/aws/credentials" + "github.com/aws/aws-sdk-go-v2/aws" ) func TestSigV4(t *testing.T) { - creds := credentials.Value{AccessKeyID: "ak", SecretAccessKey: "sk"} + creds := aws.Credentials{AccessKeyID: "ak", SecretAccessKey: "sk"} endpoint := "dynamodb.us-east-1.amazonaws.com" region := "us-east-1" payload := "payload" @@ -41,11 +41,10 @@ func TestSigV4(t *testing.T) { } // repeat with session token - creds = credentials.Value{ + creds = aws.Credentials{ AccessKeyID: "ak", SecretAccessKey: "sk", SessionToken: "st", - ProviderName: "", } actualStringToSign, actualSignature = generateSigV4WithTime(creds, endpoint, region, payload, time) if actualStringToSign != stringToSign { @@ -57,7 +56,7 @@ func TestSigV4(t *testing.T) { } func BenchmarkSigV4(b *testing.B) { - creds := credentials.Value{AccessKeyID: "ak", SecretAccessKey: "sk"} + creds := aws.Credentials{AccessKeyID: "ak", SecretAccessKey: "sk"} endpoint := "dynamodb.us-east-1.amazonaws.com" region := "us-east-1" payload := "payload" diff --git a/dax/internal/client/single.go b/dax/internal/client/single.go index 8ddeb26..99ecded 100644 --- a/dax/internal/client/single.go +++ b/dax/internal/client/single.go @@ -18,17 +18,15 @@ package client import ( "bytes" "context" - "fmt" + "errors" "time" "github.com/aws/aws-dax-go/dax/internal/cbor" "github.com/aws/aws-dax-go/dax/internal/lru" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/aws/client/metadata" - "github.com/aws/aws-sdk-go/aws/credentials" - "github.com/aws/aws-sdk-go/aws/request" - "github.com/aws/aws-sdk-go/service/dynamodb" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/dynamodb" + "github.com/aws/aws-sdk-go-v2/service/dynamodb/types" + "github.com/aws/smithy-go" ) const ( @@ -59,8 +57,6 @@ const ( OpScan = "Scan" ) -var clientInfo = metadata.ClientInfo{ServiceName: serviceName} - const ( keySchemaLruCacheSize = 100 attributeListLruCacheSize = 1000 @@ -68,22 +64,23 @@ const ( type SingleDaxClient struct { region string - credentials *credentials.Credentials + credentials aws.CredentialsProvider tubeAuthWindowSecs int64 executor *taskExecutor - handlers *request.Handlers pool *tubePool keySchema *lru.Lru attrNamesListToId *lru.Lru attrListIdToNames *lru.Lru } -func NewSingleClient(endpoint string, connConfigData connConfig, region string, credentials *credentials.Credentials) (*SingleDaxClient, error) { +var _ DaxAPI = (*SingleDaxClient)(nil) + +func NewSingleClient(endpoint string, connConfigData connConfig, region string, credentials aws.CredentialsProvider) (*SingleDaxClient, error) { return newSingleClientWithOptions(endpoint, connConfigData, region, credentials, -1, defaultDialer.DialContext) } -func newSingleClientWithOptions(endpoint string, connConfigData connConfig, region string, credentials *credentials.Credentials, maxPendingConnections int, dialContextFn dialContext) (*SingleDaxClient, error) { +func newSingleClientWithOptions(endpoint string, connConfigData connConfig, region string, credentials aws.CredentialsProvider, maxPendingConnections int, dialContextFn dialContext) (*SingleDaxClient, error) { po := defaultTubePoolOptions if maxPendingConnections > 0 { po.maxConcurrentConnAttempts = maxPendingConnections @@ -99,16 +96,12 @@ func newSingleClientWithOptions(endpoint string, connConfigData connConfig, regi executor: newExecutor(), } - client.handlers = client.buildHandlers() client.keySchema = &lru.Lru{ MaxEntries: keySchemaLruCacheSize, - LoadFunc: func(ctx aws.Context, key lru.Key) (interface{}, error) { + LoadFunc: func(ctx context.Context, key lru.Key) (interface{}, error) { table, ok := key.(string) if !ok { - return nil, awserr.New(request.ErrCodeSerialization, "unexpected type for table name", nil) - } - if ctx == nil { - ctx = aws.BackgroundContext() + return nil, &smithy.SerializationError{Err: errors.New("unexpected type for table name")} } return client.defineKeySchema(ctx, table) }, @@ -116,13 +109,10 @@ func newSingleClientWithOptions(endpoint string, connConfigData connConfig, regi client.attrNamesListToId = &lru.Lru{ MaxEntries: attributeListLruCacheSize, - LoadFunc: func(ctx aws.Context, key lru.Key) (interface{}, error) { + LoadFunc: func(ctx context.Context, key lru.Key) (interface{}, error) { attrNames, ok := key.([]string) if !ok { - return nil, awserr.New(request.ErrCodeSerialization, "unexpected type for attribute list", nil) - } - if ctx == nil { - ctx = aws.BackgroundContext() + return nil, &smithy.SerializationError{Err: errors.New("unexpected type for attribute list")} } return client.defineAttributeListId(ctx, attrNames) }, @@ -131,22 +121,19 @@ func newSingleClientWithOptions(endpoint string, connConfigData connConfig, regi w := cbor.NewWriter(&buf) defer w.Close() for _, v := range key.([]string) { - w.WriteString(v) + _ = w.WriteString(v) } - w.Flush() + _ = w.Flush() return string(buf.Bytes()) }, } client.attrListIdToNames = &lru.Lru{ MaxEntries: attributeListLruCacheSize, - LoadFunc: func(ctx aws.Context, key lru.Key) (interface{}, error) { + LoadFunc: func(ctx context.Context, key lru.Key) (interface{}, error) { id, ok := key.(int64) if !ok { - return nil, awserr.New(request.ErrCodeSerialization, "unexpected type for attribute list id", nil) - } - if ctx == nil { - ctx = aws.BackgroundContext() + return nil, &smithy.SerializationError{Err: errors.New("unexpected type for attribute list id")} } return client.defineAttributeList(ctx, id) }, @@ -163,24 +150,26 @@ func (client *SingleDaxClient) Close() error { return nil } -func (client *SingleDaxClient) startHealthChecks(cc *cluster, host hostPort) { +func (client *SingleDaxClient) startHealthChecks(ctx context.Context, cc *cluster, host hostPort) { cc.debugLog("Starting health checks for :: " + host.host) client.executor.start(cc.config.ClientHealthCheckInterval, func() error { - ctx, cfn := context.WithTimeout(aws.BackgroundContext(), 1*time.Second) + ctx, cfn := context.WithTimeout(ctx, 1*time.Second) defer cfn() var err error - _, err = client.endpoints(RequestOptions{MaxRetries: 3, Context: ctx}) + opts := RequestOptions{} + opts.RetryMaxAttempts = 3 + _, err = client.endpoints(ctx, opts) if err != nil { - cc.debugLog(fmt.Sprintf("Health checks failed with error " + err.Error() + " for host :: " + host.host)) - cc.onHealthCheckFailed(host) + cc.debugLog("Health checks failed with error " + err.Error() + " for host :: " + host.host) + cc.onHealthCheckFailed(ctx, host) } else { - cc.debugLog(fmt.Sprintf("Health checks succeeded for host:: " + host.host)) + cc.debugLog("Health checks succeeded for host:: " + host.host) } return nil }) } -func (client *SingleDaxClient) endpoints(opt RequestOptions) ([]serviceEndpoint, error) { +func (client *SingleDaxClient) endpoints(ctx context.Context, opt RequestOptions) ([]serviceEndpoint, error) { encoder := func(writer *cbor.Writer) error { return encodeEndpointsInput(writer) } @@ -190,13 +179,13 @@ func (client *SingleDaxClient) endpoints(opt RequestOptions) ([]serviceEndpoint, out, err = decodeEndpointsOutput(reader) return err } - if err = client.executeWithRetries(opEndpoints, opt, encoder, decoder); err != nil { - return nil, err + if err = client.executeWithRetries(ctx, opEndpoints, opt, encoder, decoder); err != nil { + return nil, operationError(opEndpoints, err) } return out, nil } -func (client *SingleDaxClient) defineAttributeListId(ctx aws.Context, attrNames []string) (int64, error) { +func (client *SingleDaxClient) defineAttributeListId(ctx context.Context, attrNames []string) (int64, error) { if len(attrNames) == 0 { return emptyAttributeListId, nil } @@ -209,14 +198,14 @@ func (client *SingleDaxClient) defineAttributeListId(ctx aws.Context, attrNames out, err = decodeDefineAttributeListIdOutput(reader) return err } - opt := RequestOptions{Context: ctx} - if err = client.executeWithRetries(opDefineAttributeListId, opt, encoder, decoder); err != nil { - return 0, err + opt := RequestOptions{} + if err = client.executeWithRetries(ctx, opDefineAttributeListId, opt, encoder, decoder); err != nil { + return 0, operationError(opDefineAttributeListId, err) } return out, nil } -func (client *SingleDaxClient) defineAttributeList(ctx aws.Context, id int64) ([]string, error) { +func (client *SingleDaxClient) defineAttributeList(ctx context.Context, id int64) ([]string, error) { if id == emptyAttributeListId { return []string{}, nil } @@ -229,164 +218,173 @@ func (client *SingleDaxClient) defineAttributeList(ctx aws.Context, id int64) ([ out, err = decodeDefineAttributeListOutput(reader) return err } - opt := RequestOptions{Context: ctx} - if err = client.executeWithRetries(opDefineAttributeList, opt, encoder, decoder); err != nil { - return nil, err + opt := RequestOptions{} + if err = client.executeWithRetries(ctx, opDefineAttributeList, opt, encoder, decoder); err != nil { + return nil, operationError(opDefineAttributeList, err) } return out, nil } -func (client *SingleDaxClient) defineKeySchema(ctx aws.Context, table string) ([]dynamodb.AttributeDefinition, error) { +func (client *SingleDaxClient) defineKeySchema(ctx context.Context, table string) ([]types.AttributeDefinition, error) { encoder := func(writer *cbor.Writer) error { return encodeDefineKeySchemaInput(table, writer) } - var out []dynamodb.AttributeDefinition + var out []types.AttributeDefinition var err error decoder := func(reader *cbor.Reader) error { out, err = decodeDefineKeySchemaOutput(reader) return err } - opt := RequestOptions{Context: ctx} - if err = client.executeWithRetries(opDefineKeySchema, opt, encoder, decoder); err != nil { - return nil, err + opt := RequestOptions{} + if err = client.executeWithRetries(ctx, opDefineKeySchema, opt, encoder, decoder); err != nil { + return nil, operationError(opDefineKeySchema, err) } return out, nil } -func (client *SingleDaxClient) PutItemWithOptions(input *dynamodb.PutItemInput, output *dynamodb.PutItemOutput, opt RequestOptions) (*dynamodb.PutItemOutput, error) { +func (client *SingleDaxClient) PutItemWithOptions(ctx context.Context, input *dynamodb.PutItemInput, opt RequestOptions) (*dynamodb.PutItemOutput, error) { encoder := func(writer *cbor.Writer) error { - return encodePutItemInput(opt.Context, input, client.keySchema, client.attrNamesListToId, writer) + return encodePutItemInput(ctx, input, client.keySchema, client.attrNamesListToId, writer) } - var err error + var output *dynamodb.PutItemOutput decoder := func(reader *cbor.Reader) error { - output, err = decodePutItemOutput(opt.Context, reader, input, client.keySchema, client.attrListIdToNames, output) + var err error + output, err = decodePutItemOutput(ctx, reader, input, client.keySchema, client.attrListIdToNames) return err } - if err = client.executeWithRetries(OpPutItem, opt, encoder, decoder); err != nil { - return output, err + if err := client.executeWithRetries(ctx, OpPutItem, opt, encoder, decoder); err != nil { + return output, operationError(OpPutItem, err) } return output, nil } -func (client *SingleDaxClient) DeleteItemWithOptions(input *dynamodb.DeleteItemInput, output *dynamodb.DeleteItemOutput, opt RequestOptions) (*dynamodb.DeleteItemOutput, error) { +func (client *SingleDaxClient) DeleteItemWithOptions(ctx context.Context, input *dynamodb.DeleteItemInput, opt RequestOptions) (*dynamodb.DeleteItemOutput, error) { encoder := func(writer *cbor.Writer) error { - return encodeDeleteItemInput(opt.Context, input, client.keySchema, writer) + return encodeDeleteItemInput(ctx, input, client.keySchema, writer) } - var err error + var output *dynamodb.DeleteItemOutput decoder := func(reader *cbor.Reader) error { - output, err = decodeDeleteItemOutput(opt.Context, reader, input, client.keySchema, client.attrListIdToNames, output) + var err error + output, err = decodeDeleteItemOutput(ctx, reader, input, client.keySchema, client.attrListIdToNames) return err } - if err = client.executeWithRetries(OpDeleteItem, opt, encoder, decoder); err != nil { - return output, err + if err := client.executeWithRetries(ctx, OpDeleteItem, opt, encoder, decoder); err != nil { + return output, operationError(OpDeleteItem, err) } return output, nil } -func (client *SingleDaxClient) UpdateItemWithOptions(input *dynamodb.UpdateItemInput, output *dynamodb.UpdateItemOutput, opt RequestOptions) (*dynamodb.UpdateItemOutput, error) { +func (client *SingleDaxClient) UpdateItemWithOptions(ctx context.Context, input *dynamodb.UpdateItemInput, opt RequestOptions) (*dynamodb.UpdateItemOutput, error) { encoder := func(writer *cbor.Writer) error { - return encodeUpdateItemInput(opt.Context, input, client.keySchema, writer) + return encodeUpdateItemInput(ctx, input, client.keySchema, writer) } - var err error + var output *dynamodb.UpdateItemOutput decoder := func(reader *cbor.Reader) error { - output, err = decodeUpdateItemOutput(opt.Context, reader, input, client.keySchema, client.attrListIdToNames, output) + var err error + output, err = decodeUpdateItemOutput(ctx, reader, input, client.keySchema, client.attrListIdToNames) return err } - if err = client.executeWithRetries(OpUpdateItem, opt, encoder, decoder); err != nil { - return output, err + if err := client.executeWithRetries(ctx, OpUpdateItem, opt, encoder, decoder); err != nil { + return output, operationError(OpUpdateItem, err) } return output, nil } -func (client *SingleDaxClient) GetItemWithOptions(input *dynamodb.GetItemInput, output *dynamodb.GetItemOutput, opt RequestOptions) (*dynamodb.GetItemOutput, error) { +func (client *SingleDaxClient) GetItemWithOptions(ctx context.Context, input *dynamodb.GetItemInput, opt RequestOptions) (*dynamodb.GetItemOutput, error) { encoder := func(writer *cbor.Writer) error { - return encodeGetItemInput(opt.Context, input, client.keySchema, writer) + return encodeGetItemInput(ctx, input, client.keySchema, writer) } - var err error + var output *dynamodb.GetItemOutput decoder := func(reader *cbor.Reader) error { - output, err = decodeGetItemOutput(opt.Context, reader, input, client.attrListIdToNames, output) + var err error + output, err = decodeGetItemOutput(ctx, reader, input, client.attrListIdToNames) return err } - if err = client.executeWithRetries(OpGetItem, opt, encoder, decoder); err != nil { - return output, err + if err := client.executeWithRetries(ctx, OpGetItem, opt, encoder, decoder); err != nil { + return output, operationError(OpGetItem, err) } return output, nil } -func (client *SingleDaxClient) ScanWithOptions(input *dynamodb.ScanInput, output *dynamodb.ScanOutput, opt RequestOptions) (*dynamodb.ScanOutput, error) { +func (client *SingleDaxClient) ScanWithOptions(ctx context.Context, input *dynamodb.ScanInput, opt RequestOptions) (*dynamodb.ScanOutput, error) { encoder := func(writer *cbor.Writer) error { - return encodeScanInput(opt.Context, input, client.keySchema, writer) + return encodeScanInput(ctx, input, client.keySchema, writer) } - var err error + var output *dynamodb.ScanOutput decoder := func(reader *cbor.Reader) error { - output, err = decodeScanOutput(opt.Context, reader, input, client.keySchema, client.attrListIdToNames, output) + var err error + output, err = decodeScanOutput(ctx, reader, input, client.keySchema, client.attrListIdToNames) return err } - if err = client.executeWithRetries(OpScan, opt, encoder, decoder); err != nil { - return output, err + if err := client.executeWithRetries(ctx, OpScan, opt, encoder, decoder); err != nil { + return output, operationError(OpScan, err) } return output, nil } -func (client *SingleDaxClient) QueryWithOptions(input *dynamodb.QueryInput, output *dynamodb.QueryOutput, opt RequestOptions) (*dynamodb.QueryOutput, error) { +func (client *SingleDaxClient) QueryWithOptions(ctx context.Context, input *dynamodb.QueryInput, opt RequestOptions) (*dynamodb.QueryOutput, error) { encoder := func(writer *cbor.Writer) error { - return encodeQueryInput(opt.Context, input, client.keySchema, writer) + return encodeQueryInput(ctx, input, client.keySchema, writer) } - var err error + var output *dynamodb.QueryOutput decoder := func(reader *cbor.Reader) error { - output, err = decodeQueryOutput(opt.Context, reader, input, client.keySchema, client.attrListIdToNames, output) + var err error + output, err = decodeQueryOutput(ctx, reader, input, client.keySchema, client.attrListIdToNames) return err } - if err = client.executeWithRetries(OpQuery, opt, encoder, decoder); err != nil { - return output, err + if err := client.executeWithRetries(ctx, OpQuery, opt, encoder, decoder); err != nil { + return output, operationError(OpQuery, err) } return output, nil } -func (client *SingleDaxClient) BatchWriteItemWithOptions(input *dynamodb.BatchWriteItemInput, output *dynamodb.BatchWriteItemOutput, opt RequestOptions) (*dynamodb.BatchWriteItemOutput, error) { +func (client *SingleDaxClient) BatchWriteItemWithOptions(ctx context.Context, input *dynamodb.BatchWriteItemInput, opt RequestOptions) (*dynamodb.BatchWriteItemOutput, error) { encoder := func(writer *cbor.Writer) error { - return encodeBatchWriteItemInput(opt.Context, input, client.keySchema, client.attrNamesListToId, writer) + return encodeBatchWriteItemInput(ctx, input, client.keySchema, client.attrNamesListToId, writer) } - var err error + var output *dynamodb.BatchWriteItemOutput decoder := func(reader *cbor.Reader) error { - output, err = decodeBatchWriteItemOutput(opt.Context, reader, client.keySchema, client.attrListIdToNames, output) + var err error + output, err = decodeBatchWriteItemOutput(ctx, reader, client.keySchema, client.attrListIdToNames, output) return err } - if err = client.executeWithRetries(OpBatchWriteItem, opt, encoder, decoder); err != nil { - return output, err + if err := client.executeWithRetries(ctx, OpBatchWriteItem, opt, encoder, decoder); err != nil { + return output, operationError(OpBatchWriteItem, err) } return output, nil } -func (client *SingleDaxClient) BatchGetItemWithOptions(input *dynamodb.BatchGetItemInput, output *dynamodb.BatchGetItemOutput, opt RequestOptions) (*dynamodb.BatchGetItemOutput, error) { +func (client *SingleDaxClient) BatchGetItemWithOptions(ctx context.Context, input *dynamodb.BatchGetItemInput, opt RequestOptions) (*dynamodb.BatchGetItemOutput, error) { encoder := func(writer *cbor.Writer) error { - return encodeBatchGetItemInput(opt.Context, input, client.keySchema, writer) + return encodeBatchGetItemInput(ctx, input, client.keySchema, writer) } - var err error + var output *dynamodb.BatchGetItemOutput decoder := func(reader *cbor.Reader) error { - output, err = decodeBatchGetItemOutput(opt.Context, reader, input, client.keySchema, client.attrListIdToNames, output) + var err error + output, err = decodeBatchGetItemOutput(ctx, reader, input, client.keySchema, client.attrListIdToNames, output) return err } - if err = client.executeWithRetries(OpBatchGetItem, opt, encoder, decoder); err != nil { - return output, err + if err := client.executeWithRetries(ctx, OpBatchGetItem, opt, encoder, decoder); err != nil { + return output, operationError(OpBatchGetItem, err) } return output, nil } -func (client *SingleDaxClient) TransactWriteItemsWithOptions(input *dynamodb.TransactWriteItemsInput, output *dynamodb.TransactWriteItemsOutput, opt RequestOptions) (*dynamodb.TransactWriteItemsOutput, error) { - extractedKeys := make([]map[string]*dynamodb.AttributeValue, len(input.TransactItems)) +func (client *SingleDaxClient) TransactWriteItemsWithOptions(ctx context.Context, input *dynamodb.TransactWriteItemsInput, opt RequestOptions) (*dynamodb.TransactWriteItemsOutput, error) { + extractedKeys := make([]map[string]types.AttributeValue, len(input.TransactItems)) encoder := func(writer *cbor.Writer) error { - return encodeTransactWriteItemsInput(opt.Context, input, client.keySchema, client.attrNamesListToId, writer, extractedKeys) + return encodeTransactWriteItemsInput(ctx, input, client.keySchema, client.attrNamesListToId, writer, extractedKeys) } - var err error + var output *dynamodb.TransactWriteItemsOutput decoder := func(reader *cbor.Reader) error { - output, err = decodeTransactWriteItemsOutput(opt.Context, reader, input, client.keySchema, client.attrListIdToNames, output) + var err error + output, err = decodeTransactWriteItemsOutput(ctx, reader, input, client.keySchema, client.attrListIdToNames, output) return err } - if err = client.executeWithRetries(OpBatchWriteItem, opt, encoder, decoder); err != nil { + if err := client.executeWithRetries(ctx, OpBatchWriteItem, opt, encoder, decoder); err != nil { if failure, ok := err.(*daxTransactionCanceledFailure); ok { - var cancellationReasons []*dynamodb.CancellationReason - if cancellationReasons, err = decodeTransactionCancellationReasons(opt.Context, failure, extractedKeys, client.attrListIdToNames); err != nil { + var cancellationReasons []types.CancellationReason + if cancellationReasons, err = decodeTransactionCancellationReasons(ctx, failure, extractedKeys, client.attrListIdToNames); err != nil { return output, err } failure.cancellationReasons = cancellationReasons @@ -397,20 +395,21 @@ func (client *SingleDaxClient) TransactWriteItemsWithOptions(input *dynamodb.Tra return output, nil } -func (client *SingleDaxClient) TransactGetItemsWithOptions(input *dynamodb.TransactGetItemsInput, output *dynamodb.TransactGetItemsOutput, opt RequestOptions) (*dynamodb.TransactGetItemsOutput, error) { - extractedKeys := make([]map[string]*dynamodb.AttributeValue, len(input.TransactItems)) +func (client *SingleDaxClient) TransactGetItemsWithOptions(ctx context.Context, input *dynamodb.TransactGetItemsInput, opt RequestOptions) (*dynamodb.TransactGetItemsOutput, error) { + extractedKeys := make([]map[string]types.AttributeValue, len(input.TransactItems)) encoder := func(writer *cbor.Writer) error { - return encodeTransactGetItemsInput(opt.Context, input, client.keySchema, writer, extractedKeys) + return encodeTransactGetItemsInput(ctx, input, client.keySchema, writer, extractedKeys) } - var err error + var output *dynamodb.TransactGetItemsOutput decoder := func(reader *cbor.Reader) error { - output, err = decodeTransactGetItemsOutput(opt.Context, reader, input, client.keySchema, client.attrListIdToNames, output) + var err error + output, err = decodeTransactGetItemsOutput(ctx, reader, input, client.keySchema, client.attrListIdToNames, output) return err } - if err = client.executeWithRetries(OpBatchWriteItem, opt, encoder, decoder); err != nil { + if err := client.executeWithRetries(ctx, OpBatchWriteItem, opt, encoder, decoder); err != nil { if failure, ok := err.(*daxTransactionCanceledFailure); ok { - var cancellationReasons []*dynamodb.CancellationReason - if cancellationReasons, err = decodeTransactionCancellationReasons(opt.Context, failure, extractedKeys, client.attrListIdToNames); err != nil { + var cancellationReasons []types.CancellationReason + if cancellationReasons, err = decodeTransactionCancellationReasons(ctx, failure, extractedKeys, client.attrListIdToNames); err != nil { return output, err } failure.cancellationReasons = cancellationReasons @@ -421,320 +420,45 @@ func (client *SingleDaxClient) TransactGetItemsWithOptions(input *dynamodb.Trans return output, nil } -func (client *SingleDaxClient) NewDaxRequest(op *request.Operation, input, output interface{}, opt RequestOptions) *request.Request { - req := request.New(aws.Config{}, clientInfo, *client.handlers, nil, op, input, output) - opt.applyTo(req) - return req -} - -func (client *SingleDaxClient) buildHandlers() *request.Handlers { - h := &request.Handlers{} - h.Build.PushFrontNamed(request.NamedHandler{Name: "dax.BuildHandler", Fn: client.build}) - h.Send.PushFrontNamed(request.NamedHandler{Name: "dax.SendHandler", Fn: client.send}) - return h -} - -func (client *SingleDaxClient) build(req *request.Request) { - var buf bytes.Buffer - w := cbor.NewWriter(&buf) - defer w.Close() - switch req.Operation.Name { - case OpGetItem: - input, ok := req.Params.(*dynamodb.GetItemInput) - if !ok { - req.Error = awserr.New(request.ErrCodeSerialization, "expected *GetItemInput", nil) - return - } - if err := encodeGetItemInput(req.Context(), input, client.keySchema, w); err != nil { - req.Error = translateError(err) - return - } - case OpScan: - input, ok := req.Params.(*dynamodb.ScanInput) - if !ok { - req.Error = awserr.New(request.ErrCodeSerialization, "expected *ScanInput", nil) - return - } - if err := encodeScanInput(req.Context(), input, client.keySchema, w); err != nil { - req.Error = translateError(err) - return - } - case OpQuery: - input, ok := req.Params.(*dynamodb.QueryInput) - if !ok { - req.Error = awserr.New(request.ErrCodeSerialization, "expected *QueryInput", nil) - return - } - if err := encodeQueryInput(req.Context(), input, client.keySchema, w); err != nil { - req.Error = translateError(err) - return - } - case OpBatchGetItem: - input, ok := req.Params.(*dynamodb.BatchGetItemInput) - if !ok { - req.Error = awserr.New(request.ErrCodeSerialization, "expected *BatchGetItemInput", nil) - return - } - if err := encodeBatchGetItemInput(req.Context(), input, client.keySchema, w); err != nil { - req.Error = translateError(err) - return - } - case OpPutItem: - input, ok := req.Params.(*dynamodb.PutItemInput) - if !ok { - req.Error = awserr.New(request.ErrCodeSerialization, "expected *PutItemInput", nil) - return - } - if err := encodePutItemInput(req.Context(), input, client.keySchema, client.attrNamesListToId, w); err != nil { - req.Error = translateError(err) - return - } - case OpDeleteItem: - input, ok := req.Params.(*dynamodb.DeleteItemInput) - if !ok { - req.Error = awserr.New(request.ErrCodeSerialization, "expected *DeleteItemInput", nil) - return - } - if err := encodeDeleteItemInput(req.Context(), input, client.keySchema, w); err != nil { - req.Error = translateError(err) - return - } - case OpUpdateItem: - input, ok := req.Params.(*dynamodb.UpdateItemInput) - if !ok { - req.Error = awserr.New(request.ErrCodeSerialization, "expected *UpdateItemInput", nil) - return - } - if err := encodeUpdateItemInput(req.Context(), input, client.keySchema, w); err != nil { - req.Error = translateError(err) - return - } - case OpBatchWriteItem: - input, ok := req.Params.(*dynamodb.BatchWriteItemInput) - if !ok { - req.Error = awserr.New(request.ErrCodeSerialization, "expected *BatchWriteItemInput", nil) - return - } - if err := encodeBatchWriteItemInput(req.Context(), input, client.keySchema, client.attrNamesListToId, w); err != nil { - req.Error = translateError(err) - return - } - case OpTransactGetItems: - input, ok := req.Params.(*dynamodb.TransactGetItemsInput) - if !ok { - req.Error = awserr.New(request.ErrCodeSerialization, "expected *TransactGetItemsInput", nil) - return - } - extractedKeys := make([]map[string]*dynamodb.AttributeValue, len(input.TransactItems)) - if err := encodeTransactGetItemsInput(req.Context(), input, client.keySchema, w, extractedKeys); err != nil { - req.Error = translateError(err) - return - } - case OpTransactWriteItems: - input, ok := req.Params.(*dynamodb.TransactWriteItemsInput) - if !ok { - req.Error = awserr.New(request.ErrCodeSerialization, "expected *TransactWriteItemsInput", nil) - return - } - extractedKeys := make([]map[string]*dynamodb.AttributeValue, len(input.TransactItems)) - if err := encodeTransactWriteItemsInput(req.Context(), input, client.keySchema, client.attrNamesListToId, w, extractedKeys); err != nil { - req.Error = translateError(err) - return - } - default: - req.Error = awserr.New(request.InvalidParameterErrCode, "unknown op "+req.Operation.Name, nil) - return - } - req.SetBufferBody(buf.Bytes()) -} - -func (client *SingleDaxClient) send(req *request.Request) { - opt := RequestOptions{} - if err := opt.mergeFromRequest(req, true); err != nil { - req.Error = err - return - } - switch req.Operation.Name { - case OpGetItem: - input, ok := req.Params.(*dynamodb.GetItemInput) - if !ok { - req.Error = awserr.New(request.ErrCodeSerialization, "expected *GetItemInput", nil) - return - } - output, ok := req.Data.(*dynamodb.GetItemOutput) - if !ok { - req.Error = awserr.New(request.ErrCodeSerialization, "expected *GetItemOutput", nil) - return - } - req.Data, req.Error = client.GetItemWithOptions(input, output, opt) - case OpScan: - input, ok := req.Params.(*dynamodb.ScanInput) - if !ok { - req.Error = awserr.New(request.ErrCodeSerialization, "expected *ScanInput", nil) - return - } - output, ok := req.Data.(*dynamodb.ScanOutput) - if !ok { - req.Error = awserr.New(request.ErrCodeSerialization, "expected *ScanOutput", nil) - return - } - req.Data, req.Error = client.ScanWithOptions(input, output, opt) - case OpQuery: - input, ok := req.Params.(*dynamodb.QueryInput) - if !ok { - req.Error = awserr.New(request.ErrCodeSerialization, "expected *QueryInput", nil) - return - } - output, ok := req.Data.(*dynamodb.QueryOutput) - if !ok { - req.Error = awserr.New(request.ErrCodeSerialization, "expected *QueryOutput", nil) - return - } - req.Data, req.Error = client.QueryWithOptions(input, output, opt) - case OpBatchGetItem: - input, ok := req.Params.(*dynamodb.BatchGetItemInput) - if !ok { - req.Error = awserr.New(request.ErrCodeSerialization, "expected *BatchGetItemInput", nil) - return - } - output, ok := req.Data.(*dynamodb.BatchGetItemOutput) - if !ok { - req.Error = awserr.New(request.ErrCodeSerialization, "expected *BatchGetItemOutput", nil) - return - } - req.Data, req.Error = client.BatchGetItemWithOptions(input, output, opt) - case OpPutItem: - input, ok := req.Params.(*dynamodb.PutItemInput) - if !ok { - req.Error = awserr.New(request.ErrCodeSerialization, "expected *PutItemInput", nil) - return - } - output, ok := req.Data.(*dynamodb.PutItemOutput) - if !ok { - req.Error = awserr.New(request.ErrCodeSerialization, "expected *PutItemOutput", nil) - return - } - req.Data, req.Error = client.PutItemWithOptions(input, output, opt) - case OpDeleteItem: - input, ok := req.Params.(*dynamodb.DeleteItemInput) - if !ok { - req.Error = awserr.New(request.ErrCodeSerialization, "expected *DeleteItemInput", nil) - return - } - output, ok := req.Data.(*dynamodb.DeleteItemOutput) - if !ok { - req.Error = awserr.New(request.ErrCodeSerialization, "expected *DeleteItemOutput", nil) - return - } - req.Data, req.Error = client.DeleteItemWithOptions(input, output, opt) - case OpUpdateItem: - input, ok := req.Params.(*dynamodb.UpdateItemInput) - if !ok { - req.Error = awserr.New(request.ErrCodeSerialization, "expected *UpdateItemInput", nil) - return - } - output, ok := req.Data.(*dynamodb.UpdateItemOutput) - if !ok { - req.Error = awserr.New(request.ErrCodeSerialization, "expected *UpdateItemOutput", nil) - return - } - req.Data, req.Error = client.UpdateItemWithOptions(input, output, opt) - case OpBatchWriteItem: - input, ok := req.Params.(*dynamodb.BatchWriteItemInput) - if !ok { - req.Error = awserr.New(request.ErrCodeSerialization, "expected *BatchWriteItemInput", nil) - return - } - output, ok := req.Data.(*dynamodb.BatchWriteItemOutput) - if !ok { - req.Error = awserr.New(request.ErrCodeSerialization, "expected *BatchWriteItemOutput", nil) - return - } - req.Data, req.Error = client.BatchWriteItemWithOptions(input, output, opt) - case OpTransactGetItems: - input, ok := req.Params.(*dynamodb.TransactGetItemsInput) - if !ok { - req.Error = awserr.New(request.ErrCodeSerialization, "expected *TransactGetItemsInput", nil) - return - } - output, ok := req.Data.(*dynamodb.TransactGetItemsOutput) - if !ok { - req.Error = awserr.New(request.ErrCodeSerialization, "expected *TransactGetItemsOutput", nil) - return - } - req.Data, req.Error = client.TransactGetItemsWithOptions(input, output, opt) - case OpTransactWriteItems: - input, ok := req.Params.(*dynamodb.TransactWriteItemsInput) - if !ok { - req.Error = awserr.New(request.ErrCodeSerialization, "expected *TransactWriteItemsInput", nil) - return - } - output, ok := req.Data.(*dynamodb.TransactWriteItemsOutput) - if !ok { - req.Error = awserr.New(request.ErrCodeSerialization, "expected *TransactWriteItemsOutput", nil) - return - } - req.Data, req.Error = client.TransactWriteItemsWithOptions(input, output, opt) - default: - req.Error = awserr.New(request.InvalidParameterErrCode, "unknown op "+req.Operation.Name, nil) - return - } -} - -func (client *SingleDaxClient) newContext(o RequestOptions) aws.Context { - if o.Context != nil { - return o.Context - } - return aws.BackgroundContext() -} - -func (client *SingleDaxClient) executeWithRetries(op string, o RequestOptions, encoder func(writer *cbor.Writer) error, decoder func(reader *cbor.Reader) error) error { - ctx := client.newContext(o) - - var sleepFun func() error - if o.RetryDelay > 0 { - retryDelay := o.RetryDelay - if o.SleepDelayFn == nil { - sleepFun = func() error { - return aws.SleepWithContext(ctx, retryDelay) - } - } else { - sleepFun = func() error { - o.SleepDelayFn(retryDelay) - return nil - } - } - } +func (client *SingleDaxClient) executeWithRetries(ctx context.Context, op string, o RequestOptions, encoder func(writer *cbor.Writer) error, decoder func(reader *cbor.Reader) error) error { var err error - attempts := o.MaxRetries + attempts := o.RetryMaxAttempts // Start from 0 to accommodate for the initial request for i := 0; i <= attempts; i++ { - if i > 0 && o.Logger != nil && o.LogLevel.Matches(aws.LogDebugWithRequestRetries) { - o.Logger.Log(fmt.Sprintf("DEBUG: Retrying Request %s/%s, attempt %d", service, op, i)) + if i > 0 && o.Logger != nil { + o.Logger.Logf(ClassificationDebug, "Retrying Request %s/%s, attempt %d", service, op, i) } - if err = client.executeWithContext(ctx, op, encoder, decoder, o); err == nil { + err = client.executeWithContext(ctx, op, encoder, decoder, o) + if err == nil { return nil - } else if ctx != nil && err == ctx.Err() { - return awserr.New(request.CanceledErrorCode, "request context canceled", err) + } + if errors.Is(err, context.Canceled) { + return &smithy.CanceledError{Err: err} } - if i != attempts && sleepFun != nil { - if err := sleepFun(); err != nil { - return awserr.New(request.CanceledErrorCode, "request context canceled", err) - } + if !isRetryable(o, i+1, err) { + return &smithy.OperationError{Err: err, ServiceID: service, OperationName: op} + } + + d, retryErr := o.Retryer.RetryDelay(i+1, err) + if retryErr != nil { + return &smithy.OperationError{Err: retryErr, ServiceID: service, OperationName: op} + } + if sleepErr := Sleep(ctx, op, d); sleepErr != nil { + return &smithy.OperationError{Err: sleepErr, ServiceID: service, OperationName: op} } - if o.Logger != nil && o.LogLevel.Matches(aws.LogDebugWithRequestRetries) { - o.Logger.Log(fmt.Sprintf("DEBUG: Error in executing %s%s : %s", service, op, err)) + if o.Logger != nil { + o.Logger.Logf(ClassificationDebug, "Error in executing %s%s : %s", service, op, err) } } // Return the last error occurred - return translateError(err) + return err } -func (client *SingleDaxClient) executeWithContext(ctx aws.Context, op string, encoder func(writer *cbor.Writer) error, decoder func(reader *cbor.Reader) error, opt RequestOptions) error { +func (client *SingleDaxClient) executeWithContext(ctx context.Context, op string, encoder func(writer *cbor.Writer) error, decoder func(reader *cbor.Reader) error, opt RequestOptions) error { t, err := client.pool.getWithContext(ctx, client.isHighPriority(op), opt) if err != nil { return err @@ -752,7 +476,7 @@ func (client *SingleDaxClient) executeWithContext(ctx aws.Context, op string, en return err } - if err = client.auth(t); err != nil { + if err = client.auth(ctx, t); err != nil { // Auth method writes in the tube and // it is not guaranteed that it will be drained completely on error client.pool.closeTube(t) @@ -823,9 +547,9 @@ func (client *SingleDaxClient) recycleTube(t tube, err error) { client.pool.closeTube(t) } } -func (client *SingleDaxClient) auth(t tube) error { +func (client *SingleDaxClient) auth(ctx context.Context, t tube) error { // TODO credentials.Get() cause a throughput drop of ~25 with 250 goroutines with DefaultCredentialChain (only instance profile credentials available) - creds, err := client.credentials.Get() + creds, err := client.credentials.Retrieve(ctx) if err != nil { return err } @@ -849,5 +573,5 @@ func (client *SingleDaxClient) reapIdleConnections() { } type HealthCheckDaxAPI interface { - startHealthChecks(cc *cluster, host hostPort) + startHealthChecks(ctx context.Context, cc *cluster, host hostPort) } diff --git a/dax/internal/client/single_test.go b/dax/internal/client/single_test.go index 4e7f9d2..af6955a 100644 --- a/dax/internal/client/single_test.go +++ b/dax/internal/client/single_test.go @@ -12,10 +12,7 @@ import ( "time" "github.com/aws/aws-dax-go/dax/internal/cbor" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/aws/credentials" - "github.com/aws/aws-sdk-go/aws/request" + "github.com/aws/smithy-go" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -56,7 +53,7 @@ func TestExecuteErrorHandling(t *testing.T) { &mockConn{rd: []byte{cbor.NegInt}}, func(writer *cbor.Writer) error { return nil }, nil, - awserr.New(request.ErrCodeSerialization, fmt.Sprintf("cbor: expected major type %d, got %d", cbor.Array, cbor.NegInt), nil), + &smithy.DeserializationError{Err: fmt.Errorf("cbor: expected major type %d, got %d", cbor.Array, cbor.NegInt)}, map[string]int{"Write": 2, "Read": 1, "SetDeadline": 1, "Close": 1}, }, { // decode error, discard tube @@ -83,7 +80,7 @@ func TestExecuteErrorHandling(t *testing.T) { } for i, c := range cases { - cli, err := newSingleClientWithOptions(":9121", unEncryptedConnConfig, "us-west-2", credentials.NewStaticCredentials("id", "secret", "tok"), 1, func(ctx context.Context, a, n string) (net.Conn, error) { + cli, err := newSingleClientWithOptions(":9121", unEncryptedConnConfig, "us-west-2", &testCredentialProvider{}, 1, func(ctx context.Context, a, n string) (net.Conn, error) { return c.conn, nil }) if err != nil { @@ -91,7 +88,7 @@ func TestExecuteErrorHandling(t *testing.T) { } cli.pool.closeTubeImmediately = true - err = cli.executeWithContext(aws.BackgroundContext(), OpGetItem, c.enc, c.dec, RequestOptions{}) + err = cli.executeWithContext(context.Background(), OpGetItem, c.enc, c.dec, RequestOptions{}) if !reflect.DeepEqual(c.ee, err) { t.Errorf("case[%d] expected error %v, got error %v", i, c.ee, err) } @@ -103,7 +100,7 @@ func TestExecuteErrorHandling(t *testing.T) { } func TestRetryPropogatesContextError(t *testing.T) { - client, clientErr := newSingleClientWithOptions(":9121", unEncryptedConnConfig, "us-west-2", credentials.NewStaticCredentials("id", "secret", "tok"), 1, func(ctx context.Context, a, n string) (net.Conn, error) { + client, clientErr := newSingleClientWithOptions(":9121", unEncryptedConnConfig, "us-west-2", &testCredentialProvider{}, 1, func(ctx context.Context, a, n string) (net.Conn, error) { return &mockConn{rd: []byte{cbor.Array + 0}}, nil }) defer client.Close() @@ -113,32 +110,31 @@ func TestRetryPropogatesContextError(t *testing.T) { client.pool.closeTubeImmediately = true - ctx, cancel := context.WithCancel(aws.BackgroundContext()) - requestOptions := RequestOptions{ - MaxRetries: 2, - Context: ctx, - } + ctx, cancel := context.WithCancel(context.Background()) + requestOptions := RequestOptions{} + requestOptions.RetryMaxAttempts = 2 writer := func(writer *cbor.Writer) error { return nil } reader := func(reader *cbor.Reader) error { return nil } // Cancel context to fail the execution + cancel() - err := client.executeWithRetries(OpGetItem, requestOptions, writer, reader) + err := client.executeWithRetries(ctx, OpGetItem, requestOptions, writer, reader) // Context related error should be returned - awsError, ok := err.(awserr.Error) + cancelErr, ok := err.(*smithy.CanceledError) if !ok { - t.Fatal("Error type is not awserr.Error") + t.Fatalf("Error type is not smithy.CanceledError, type is %T", err) } - if awsError.Code() != request.CanceledErrorCode || awsError.OrigErr() != context.Canceled { - t.Errorf("aws error doesn't match expected. %v", awsError) + if cancelErr.Err != context.Canceled { + t.Errorf("aws error doesn't match expected. %v", cancelErr) } } func TestRetryPropogatesOtherErrors(t *testing.T) { - client, clientErr := newSingleClientWithOptions(":9121", unEncryptedConnConfig, "us-west-2", credentials.NewStaticCredentials("id", "secret", "tok"), 1, func(ctx context.Context, a, n string) (net.Conn, error) { + client, clientErr := newSingleClientWithOptions(":9121", unEncryptedConnConfig, "us-west-2", &testCredentialProvider{}, 1, func(ctx context.Context, a, n string) (net.Conn, error) { return &mockConn{rd: []byte{cbor.Array + 0}}, nil }) defer client.Close() @@ -148,33 +144,32 @@ func TestRetryPropogatesOtherErrors(t *testing.T) { client.pool.closeTubeImmediately = true - requestOptions := RequestOptions{ - MaxRetries: 1, - } + requestOptions := RequestOptions{} + requestOptions.RetryMaxAttempts = 1 expectedError := errors.New("IO") writer := func(writer *cbor.Writer) error { return nil } reader := func(reader *cbor.Reader) error { return errors.New("IO") } - err := client.executeWithRetries(OpGetItem, requestOptions, writer, reader) + err := client.executeWithRetries(context.Background(), OpGetItem, requestOptions, writer, reader) // IO error should be returned - awsError, ok := err.(awserr.Error) + opeErr, ok := err.(*smithy.OperationError) if !ok { - t.Fatal("Error type is not awserr.Error") + t.Fatalf("Error type is not smithy.OperationError. type is %T", err) } - if awsError.OrigErr() == nil { + if opeErr.Err == nil { t.Fatal("Original error is empty") } - if awsError.Code() != "UnknownError" || awsError.OrigErr().Error() != expectedError.Error() { - t.Errorf("aws error doesn't match expected. %v", awsError) + if opeErr.Err.Error() != expectedError.Error() { + t.Errorf("error doesn't match expected. %v", opeErr) } } func TestRetryPropogatesOtherErrorsWithDelay(t *testing.T) { - client, clientErr := newSingleClientWithOptions(":9121", unEncryptedConnConfig, "us-west-2", credentials.NewStaticCredentials("id", "secret", "tok"), 1, func(ctx context.Context, a, n string) (net.Conn, error) { + client, clientErr := newSingleClientWithOptions(":9121", unEncryptedConnConfig, "us-west-2", &testCredentialProvider{}, 1, func(ctx context.Context, a, n string) (net.Conn, error) { return &mockConn{rd: []byte{cbor.Array + 0}}, nil }) defer client.Close() @@ -184,34 +179,32 @@ func TestRetryPropogatesOtherErrorsWithDelay(t *testing.T) { client.pool.closeTubeImmediately = true - requestOptions := RequestOptions{ - MaxRetries: 1, - RetryDelay: 1, - } + requestOptions := RequestOptions{} + requestOptions.RetryMaxAttempts = 1 expectedError := errors.New("IO") writer := func(writer *cbor.Writer) error { return nil } reader := func(reader *cbor.Reader) error { return expectedError } - err := client.executeWithRetries(OpGetItem, requestOptions, writer, reader) + err := client.executeWithRetries(context.Background(), OpGetItem, requestOptions, writer, reader) // IO error should be returned - awsError, ok := err.(awserr.Error) + opeErr, ok := err.(*smithy.OperationError) if !ok { - t.Fatal("Error type is not awserr.Error") + t.Fatalf("Error type is not smithy.OperationError. type is %T", err) } - if awsError.OrigErr() == nil { + if opeErr.Err == nil { t.Fatal("Original error is empty") } - if awsError.Code() != "UnknownError" || awsError.OrigErr().Error() != expectedError.Error() { - t.Errorf("aws error doesn't match expected. %v", awsError) + if opeErr.Err.Error() != expectedError.Error() { + t.Errorf("aws error doesn't match expected. %v", opeErr) } } func TestRetrySleepCycleCount(t *testing.T) { - client, clientErr := newSingleClientWithOptions(":9121", unEncryptedConnConfig, "us-west-2", credentials.NewStaticCredentials("id", "secret", "tok"), 1, func(ctx context.Context, a, n string) (net.Conn, error) { + client, clientErr := newSingleClientWithOptions(":9121", unEncryptedConnConfig, "us-west-2", &testCredentialProvider{}, 1, func(ctx context.Context, a, n string) (net.Conn, error) { return &mockConn{rd: []byte{cbor.Array + 0}}, nil }) defer client.Close() @@ -221,32 +214,29 @@ func TestRetrySleepCycleCount(t *testing.T) { client.pool.closeTubeImmediately = true - sleepCallCount := 0 - requestOptions := RequestOptions{ - MaxRetries: 0, - RetryDelay: 0, - SleepDelayFn: func(d time.Duration) { sleepCallCount++ }, - } + requestOptions := RequestOptions{} + tr := &testRetryer{} + requestOptions.Retryer = tr writer := func(writer *cbor.Writer) error { return nil } reader := func(reader *cbor.Reader) error { return errors.New("IO") } - client.executeWithRetries(OpGetItem, requestOptions, writer, reader) + client.executeWithRetries(context.Background(), OpGetItem, requestOptions, writer, reader) - if sleepCallCount != 0 { - t.Fatalf("Sleep was called %d times, but expected none", sleepCallCount) + if tr.CalledCount != 0 { + t.Fatalf("Sleep was called %d times, but expected none", tr.CalledCount) } - requestOptions.MaxRetries = 3 - requestOptions.RetryDelay = 1 - client.executeWithRetries(OpGetItem, requestOptions, writer, reader) + requestOptions.RetryMaxAttempts = 3 + tr.Attemps = requestOptions.RetryMaxAttempts + client.executeWithRetries(context.Background(), OpGetItem, requestOptions, writer, reader) - if sleepCallCount != requestOptions.MaxRetries { - t.Fatalf("Sleep was called %d times, but expected %d", sleepCallCount, requestOptions.MaxRetries) + if tr.CalledCount != requestOptions.RetryMaxAttempts { + t.Fatalf("Sleep was called %d times, but expected %d", tr.CalledCount, requestOptions.RetryMaxAttempts) } } func TestRetryLastError(t *testing.T) { - client, clientErr := newSingleClientWithOptions(":9121", unEncryptedConnConfig, "us-west-2", credentials.NewStaticCredentials("id", "secret", "tok"), 1, func(ctx context.Context, a, n string) (net.Conn, error) { + client, clientErr := newSingleClientWithOptions(":9121", unEncryptedConnConfig, "us-west-2", &testCredentialProvider{}, 1, func(ctx context.Context, a, n string) (net.Conn, error) { return &mockConn{rd: []byte{cbor.Array + 0}}, nil }) defer client.Close() @@ -257,11 +247,10 @@ func TestRetryLastError(t *testing.T) { client.pool.closeTubeImmediately = true var sleepCallCount uint - requestOptions := RequestOptions{ - MaxRetries: 2, - RetryDelay: 1, - SleepDelayFn: func(d time.Duration) { sleepCallCount++ }, - } + requestOptions := RequestOptions{} + requestOptions.RetryMaxAttempts = 2 + tr := &testRetryer{Attemps: requestOptions.RetryMaxAttempts} + requestOptions.Retryer = tr writer := func(writer *cbor.Writer) error { return nil } reader := func(reader *cbor.Reader) error { @@ -271,18 +260,18 @@ func TestRetryLastError(t *testing.T) { return errors.New("LastError") } } - err := client.executeWithRetries(OpGetItem, requestOptions, writer, reader) - awsError, ok := err.(awserr.Error) + err := client.executeWithRetries(context.Background(), OpGetItem, requestOptions, writer, reader) + opeErr, ok := err.(*smithy.OperationError) if !ok { - t.Fatal("Error type is not awserr.Error") + t.Fatalf("Error type is not smithy.OperationError. type is %T", err) } - if awsError.OrigErr() == nil { + if opeErr.Err == nil { t.Fatal("Original error is empty") } - if awsError.Code() != "UnknownError" || awsError.OrigErr().Error() != "LastError" { - t.Fatalf("aws error doesn't match expected. %v", awsError) + if opeErr.Err.Error() != "LastError" { + t.Fatalf("error doesn't match expected. %v", opeErr) } } @@ -291,7 +280,7 @@ func TestSingleClient_customDialer(t *testing.T) { var dialContextFn dialContext = func(ctx context.Context, address string, network string) (net.Conn, error) { return conn, nil } - client, err := newSingleClientWithOptions(":9121", unEncryptedConnConfig, "us-west-2", credentials.NewStaticCredentials("id", "secret", "tok"), 1, dialContextFn) + client, err := newSingleClientWithOptions(":9121", unEncryptedConnConfig, "us-west-2", &testCredentialProvider{}, 1, dialContextFn) require.NoError(t, err) defer client.Close() diff --git a/dax/internal/client/stub.go b/dax/internal/client/stub.go index b7a11d8..7dbcd85 100644 --- a/dax/internal/client/stub.go +++ b/dax/internal/client/stub.go @@ -6,9 +6,9 @@ is used to test pagination logic. package client import ( - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/request" - "github.com/aws/aws-sdk-go/service/dynamodb" + "context" + + "github.com/aws/aws-sdk-go-v2/service/dynamodb" ) type ClientStub struct { @@ -20,12 +20,15 @@ type ClientStub struct { scanResponses []*dynamodb.ScanOutput } -// Constructor +var _ DaxAPI = (*ClientStub)(nil) + +// NewClientStub creates ClientStub. func NewClientStub(batchGetItemResponses []*dynamodb.BatchGetItemOutput, queryResponses []*dynamodb.QueryOutput, scanResponses []*dynamodb.ScanOutput) *ClientStub { return &ClientStub{batchGetItemResponses: batchGetItemResponses, queryResponses: queryResponses, scanResponses: scanResponses} } // Stub methods + func (stub *ClientStub) GetBatchGetItemRequests() []*dynamodb.BatchGetItemInput { return stub.batchGetItemRequests } @@ -39,83 +42,53 @@ func (stub *ClientStub) GetScanRequests() []*dynamodb.ScanInput { } // DaxAPI methods -func (stub *ClientStub) PutItemWithOptions(input *dynamodb.PutItemInput, output *dynamodb.PutItemOutput, opt RequestOptions) (*dynamodb.PutItemOutput, error) { + +func (stub *ClientStub) PutItemWithOptions(_ context.Context, _ *dynamodb.PutItemInput, _ RequestOptions) (*dynamodb.PutItemOutput, error) { return nil, nil } -func (stub *ClientStub) DeleteItemWithOptions(input *dynamodb.DeleteItemInput, output *dynamodb.DeleteItemOutput, opt RequestOptions) (*dynamodb.DeleteItemOutput, error) { +func (stub *ClientStub) DeleteItemWithOptions(_ context.Context, _ *dynamodb.DeleteItemInput, _ RequestOptions) (*dynamodb.DeleteItemOutput, error) { return nil, nil } -func (stub *ClientStub) UpdateItemWithOptions(input *dynamodb.UpdateItemInput, output *dynamodb.UpdateItemOutput, opt RequestOptions) (*dynamodb.UpdateItemOutput, error) { +func (stub *ClientStub) UpdateItemWithOptions(_ context.Context, _ *dynamodb.UpdateItemInput, _ RequestOptions) (*dynamodb.UpdateItemOutput, error) { return nil, nil } -func (stub *ClientStub) GetItemWithOptions(input *dynamodb.GetItemInput, output *dynamodb.GetItemOutput, opt RequestOptions) (*dynamodb.GetItemOutput, error) { +func (stub *ClientStub) GetItemWithOptions(_ context.Context, _ *dynamodb.GetItemInput, _ RequestOptions) (*dynamodb.GetItemOutput, error) { return nil, nil } -func (stub *ClientStub) ScanWithOptions(input *dynamodb.ScanInput, output *dynamodb.ScanOutput, opt RequestOptions) (*dynamodb.ScanOutput, error) { - output, stub.scanResponses = stub.scanResponses[0], stub.scanResponses[1:] +func (stub *ClientStub) ScanWithOptions(_ context.Context, _ *dynamodb.ScanInput, _ RequestOptions) (*dynamodb.ScanOutput, error) { + output := stub.scanResponses[0] + stub.scanResponses = stub.scanResponses[1:] return output, nil } -func (stub *ClientStub) QueryWithOptions(input *dynamodb.QueryInput, output *dynamodb.QueryOutput, opt RequestOptions) (*dynamodb.QueryOutput, error) { - output, stub.queryResponses = stub.queryResponses[0], stub.queryResponses[1:] +func (stub *ClientStub) QueryWithOptions(_ context.Context, _ *dynamodb.QueryInput, _ RequestOptions) (*dynamodb.QueryOutput, error) { + output := stub.queryResponses[0] + stub.queryResponses = stub.queryResponses[1:] return output, nil } -func (stub *ClientStub) BatchWriteItemWithOptions(input *dynamodb.BatchWriteItemInput, output *dynamodb.BatchWriteItemOutput, opt RequestOptions) (*dynamodb.BatchWriteItemOutput, error) { +func (stub *ClientStub) BatchWriteItemWithOptions(_ context.Context, _ *dynamodb.BatchWriteItemInput, _ RequestOptions) (*dynamodb.BatchWriteItemOutput, error) { return nil, nil } -func (stub *ClientStub) BatchGetItemWithOptions(input *dynamodb.BatchGetItemInput, output *dynamodb.BatchGetItemOutput, opt RequestOptions) (*dynamodb.BatchGetItemOutput, error) { - output, stub.batchGetItemResponses = stub.batchGetItemResponses[0], stub.batchGetItemResponses[1:] +func (stub *ClientStub) BatchGetItemWithOptions(_ context.Context, _ *dynamodb.BatchGetItemInput, _ RequestOptions) (*dynamodb.BatchGetItemOutput, error) { + output := stub.batchGetItemResponses[0] + stub.batchGetItemResponses = stub.batchGetItemResponses[1:] return output, nil } -func (stub *ClientStub) TransactWriteItemsWithOptions(input *dynamodb.TransactWriteItemsInput, output *dynamodb.TransactWriteItemsOutput, opt RequestOptions) (*dynamodb.TransactWriteItemsOutput, error) { +func (stub *ClientStub) TransactWriteItemsWithOptions(_ context.Context, _ *dynamodb.TransactWriteItemsInput, _ RequestOptions) (*dynamodb.TransactWriteItemsOutput, error) { return nil, nil } -func (stub *ClientStub) TransactGetItemsWithOptions(input *dynamodb.TransactGetItemsInput, output *dynamodb.TransactGetItemsOutput, opt RequestOptions) (*dynamodb.TransactGetItemsOutput, error) { +func (stub *ClientStub) TransactGetItemsWithOptions(_ context.Context, _ *dynamodb.TransactGetItemsInput, _ RequestOptions) (*dynamodb.TransactGetItemsOutput, error) { return nil, nil } -func (stub *ClientStub) NewDaxRequest(op *request.Operation, input, output interface{}, opt RequestOptions) *request.Request { - h := request.Handlers{} - h.Build.PushFrontNamed(request.NamedHandler{Name: "dax.BuildHandler", Fn: stub.build}) - h.Send.PushFrontNamed(request.NamedHandler{Name: "dax.SendHandler", Fn: stub.send}) - - req := request.New(aws.Config{}, clientInfo, h, nil, op, input, output) - opt.applyTo(req) - return req -} - -func (stub *ClientStub) build(req *request.Request) { -} - -func (stub *ClientStub) send(req *request.Request) { - opt := RequestOptions{} - switch req.Operation.Name { - case OpBatchGetItem: - input, _ := req.Params.(*dynamodb.BatchGetItemInput) - stub.batchGetItemRequests = append(stub.batchGetItemRequests, input) - output, _ := req.Data.(*dynamodb.BatchGetItemOutput) - req.Data, req.Error = stub.BatchGetItemWithOptions(input, output, opt) - case OpQuery: - input, _ := req.Params.(*dynamodb.QueryInput) - stub.queryRequests = append(stub.queryRequests, input) - output, _ := req.Data.(*dynamodb.QueryOutput) - req.Data, req.Error = stub.QueryWithOptions(input, output, opt) - case OpScan: - input, _ := req.Params.(*dynamodb.ScanInput) - stub.scanRequests = append(stub.scanRequests, input) - output, _ := req.Data.(*dynamodb.ScanOutput) - req.Data, req.Error = stub.ScanWithOptions(input, output, opt) - } -} - -func (stub *ClientStub) endpoints(opt RequestOptions) ([]serviceEndpoint, error) { +func (stub *ClientStub) endpoints(_ context.Context, _ RequestOptions) ([]serviceEndpoint, error) { return nil, nil } diff --git a/dax/internal/client/tubepool.go b/dax/internal/client/tubepool.go index d0c0aee..70cbfa0 100644 --- a/dax/internal/client/tubepool.go +++ b/dax/internal/client/tubepool.go @@ -25,7 +25,6 @@ import ( "time" "github.com/aws/aws-dax-go/dax/internal/proxy" - "github.com/aws/aws-sdk-go/aws" ) const network = "tcp" @@ -348,8 +347,8 @@ func (p *tubePool) sessionBump() { // Logs debug logs if DEBUG logging is enabled. func (p *tubePool) logDebug(opt RequestOptions, logString string) { - if opt.Logger != nil && opt.LogLevel.AtLeast(aws.LogDebug) { - opt.Logger.Log(logString) + if opt.Logger != nil { + opt.Logger.Logf(ClassificationDebug, logString) } } diff --git a/dax/internal/lru/lru.go b/dax/internal/lru/lru.go index 727d828..3a475ad 100644 --- a/dax/internal/lru/lru.go +++ b/dax/internal/lru/lru.go @@ -16,7 +16,7 @@ package lru import ( - "github.com/aws/aws-sdk-go/aws" + "context" "sync" ) @@ -28,7 +28,7 @@ type Lru struct { // LoadFunc specifies the function that loads a value // for a specific key when not found in the cache. - LoadFunc func(ctx aws.Context, key Key) (interface{}, error) + LoadFunc func(ctx context.Context, key Key) (interface{}, error) loadGroup loadGroup // Optional KeyMarshaller. Caller should provide one when using @@ -62,7 +62,7 @@ func (c *Lru) lookup(key Key) (*entry, bool) { return v, ok } -func (c *Lru) GetWithContext(ctx aws.Context, okey Key) (interface{}, error) { +func (c *Lru) GetWithContext(ctx context.Context, okey Key) (interface{}, error) { ikey := okey if c.KeyMarshaller != nil { ikey = c.KeyMarshaller(okey) diff --git a/dax/internal/lru/lru_test.go b/dax/internal/lru/lru_test.go index b2e65da..8a3d758 100644 --- a/dax/internal/lru/lru_test.go +++ b/dax/internal/lru/lru_test.go @@ -18,7 +18,6 @@ package lru import ( "context" "fmt" - "github.com/aws/aws-sdk-go/aws" "reflect" "sync" "sync/atomic" @@ -28,7 +27,7 @@ import ( func TestLruGet(t *testing.T) { c := &Lru{ - LoadFunc: func(ctx aws.Context, key Key) (interface{}, error) { + LoadFunc: func(ctx context.Context, key Key) (interface{}, error) { return key, nil }, } @@ -47,7 +46,7 @@ func TestLruGet(t *testing.T) { func TestLruKeyMarshaller(t *testing.T) { loadCount := 0 c := &Lru{ - LoadFunc: func(ctx aws.Context, key Key) (interface{}, error) { + LoadFunc: func(ctx context.Context, key Key) (interface{}, error) { loadCount++ return key, nil }, @@ -71,7 +70,7 @@ func TestLruKeyMarshaller(t *testing.T) { func TestLruEvict(t *testing.T) { loads := 0 - loadFn := func(ctx aws.Context, key Key) (interface{}, error) { + loadFn := func(ctx context.Context, key Key) (interface{}, error) { loads++ return key, nil } @@ -121,7 +120,7 @@ func TestLruEvict(t *testing.T) { } func TestLruTimeout(t *testing.T) { - loadFn := func(ctx aws.Context, key Key) (interface{}, error) { + loadFn := func(ctx context.Context, key Key) (interface{}, error) { select { case <-ctx.Done(): return nil, ctx.Err() @@ -134,7 +133,7 @@ func TestLruTimeout(t *testing.T) { LoadFunc: loadFn, } - ctx, cfn := context.WithTimeout(aws.BackgroundContext(), 1*time.Millisecond) + ctx, cfn := context.WithTimeout(context.Background(), 1*time.Millisecond) defer cfn() key := "key1" v, err := c.GetWithContext(ctx, key) @@ -149,7 +148,7 @@ func TestLruTimeout(t *testing.T) { func TestLruConcurrentLoad(t *testing.T) { var loads int32 loadTime := 10 * time.Millisecond - loadFn := func(ctx aws.Context, key Key) (interface{}, error) { + loadFn := func(ctx context.Context, key Key) (interface{}, error) { <-time.After(loadTime) atomic.AddInt32(&loads, 1) return key, nil @@ -195,7 +194,7 @@ func TestLruConcurrentLoad(t *testing.T) { func TestLruSingleLoader(t *testing.T) { valueCh := make(chan interface{}) - loadFn := func(ctx aws.Context, key Key) (interface{}, error) { + loadFn := func(ctx context.Context, key Key) (interface{}, error) { return <-valueCh, nil } @@ -252,7 +251,7 @@ func TestLoadGroup(t *testing.T) { func BenchmarkLruGet(b *testing.B) { c := &Lru{ - LoadFunc: func(ctx aws.Context, key Key) (interface{}, error) { + LoadFunc: func(ctx context.Context, key Key) (interface{}, error) { return key, nil }, } diff --git a/dax/internal/parser/expression.go b/dax/internal/parser/expression.go index f09ff07..0b02772 100644 --- a/dax/internal/parser/expression.go +++ b/dax/internal/parser/expression.go @@ -25,9 +25,7 @@ import ( "github.com/antlr/antlr4/runtime/Go/antlr" "github.com/aws/aws-dax-go/dax/internal/cbor" "github.com/aws/aws-dax-go/dax/internal/parser/generated" - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/aws/request" - "github.com/aws/aws-sdk-go/service/dynamodb" + "github.com/aws/aws-sdk-go-v2/service/dynamodb/types" ) const ( @@ -43,12 +41,12 @@ type ExpressionEncoder struct { // input expressions map[int]string - substitutes map[string]*string - variables map[string]*dynamodb.AttributeValue + substitutes map[string]string + variables map[string]types.AttributeValue // output encoded map[int][]byte - variableValues []dynamodb.AttributeValue + variableValues []types.AttributeValue // book keeping stack []sexpr @@ -64,7 +62,7 @@ type ExpressionEncoder struct { buf *bytes.Buffer } -func NewExpressionEncoder(expr map[int]string, subs map[string]*string, vars map[string]*dynamodb.AttributeValue) *ExpressionEncoder { +func NewExpressionEncoder(expr map[int]string, subs map[string]string, vars map[string]types.AttributeValue) *ExpressionEncoder { var b bytes.Buffer us := make(stringSet, len(subs)) us.addKeysStrVal(subs) @@ -77,7 +75,7 @@ func NewExpressionEncoder(expr map[int]string, subs map[string]*string, vars map encoded: make(map[int][]byte), variableIdByName: make(map[string]int), - variableValues: make([]dynamodb.AttributeValue, 0, len(vars)), + variableValues: make([]types.AttributeValue, 0, len(vars)), unusedSubstitutes: us, unusedVariables: uv, @@ -123,7 +121,7 @@ func (e *ExpressionEncoder) reset(typ int) { e.exprType = typ e.nestingLevel = 0 e.variableIdByName = make(map[string]int) - e.variableValues = make([]dynamodb.AttributeValue, 0, len(e.variables)) + e.variableValues = make([]types.AttributeValue, 0, len(e.variables)) e.err = nil } @@ -179,7 +177,7 @@ func (e *ExpressionEncoder) fullExpr(typ int, expr []byte) ([]byte, error) { if typ != ProjectionExpr { e.cborWriter.WriteArrayHeader(len(e.variableValues)) for _, v := range e.variableValues { - if err := cbor.EncodeAttributeValue(&v, e.cborWriter); err != nil { + if err := cbor.EncodeAttributeValue(v, e.cborWriter); err != nil { return nil, err } } @@ -200,7 +198,7 @@ func (e *ExpressionEncoder) ExitId(ctx *generated.IdContext) { return } e.unusedSubstitutes.remove(id) - e.push(e.encodeDocumentPathElement(*s)) + e.push(e.encodeDocumentPathElement(s)) } else { e.push(e.encodeDocumentPathElement(id)) } @@ -550,7 +548,7 @@ func (e *ExpressionEncoder) encodeVariable(l string) sexpr { if !ok { id = len(e.variableValues) e.variableIdByName[n] = id - e.variableValues = append(e.variableValues, *v) + e.variableValues = append(e.variableValues, v) } return e.encodeFunction(opVariable, []sexpr{e.encodeId(id)}) } @@ -611,8 +609,8 @@ func (e *ExpressionEncoder) pop() sexpr { return v } -func newInvalidParameterError(msg string) awserr.Error { - return awserr.New(request.InvalidParameterErrCode, msg, nil) +func newInvalidParameterError(msg string) error { + return fmt.Errorf("invalid parameter: %s", msg) } type sexpr struct { @@ -622,13 +620,13 @@ type sexpr struct { type stringSet map[string]struct{} -func (s stringSet) addKeysStrVal(m map[string]*string) { +func (s stringSet) addKeysStrVal(m map[string]string) { for k, _ := range m { s[k] = struct{}{} } } -func (s stringSet) addKeysAttrVal(m map[string]*dynamodb.AttributeValue) { +func (s stringSet) addKeysAttrVal(m map[string]types.AttributeValue) { for k, _ := range m { s[k] = struct{}{} } diff --git a/dax/internal/parser/expression_test.go b/dax/internal/parser/expression_test.go index 7b88c4c..4fa8dd7 100644 --- a/dax/internal/parser/expression_test.go +++ b/dax/internal/parser/expression_test.go @@ -23,16 +23,15 @@ import ( "strings" "testing" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/dynamodb" + "github.com/aws/aws-sdk-go-v2/service/dynamodb/types" ) func TestExpressionEncoder(t *testing.T) { cases := []struct { typ int in string - subs map[string]*string - vars map[string]*dynamodb.AttributeValue + subs map[string]string + vars map[string]types.AttributeValue out []byte }{ { @@ -58,7 +57,7 @@ func TestExpressionEncoder(t *testing.T) { { typ: ProjectionExpr, in: "a1,a3.#s1", - subs: map[string]*string{"#s1": aws.String("k2")}, + subs: map[string]string{"#s1": "k2"}, out: fromHex("0x82018282126261318312626133626B32"), }, { @@ -69,24 +68,24 @@ func TestExpressionEncoder(t *testing.T) { { typ: FilterExpr, in: "a1 <> :v1", - vars: map[string]*dynamodb.AttributeValue{":v1": &dynamodb.AttributeValue{N: aws.String("5")}}, + vars: map[string]types.AttributeValue{":v1": &types.AttributeValueMemberN{Value: "5"}}, out: fromHex("0x8301830182126261318211008105"), }, { typ: FilterExpr, in: "a1 < :v1 and a2 >= :v2", - vars: map[string]*dynamodb.AttributeValue{ - ":v1": &dynamodb.AttributeValue{N: aws.String("5")}, - ":v2": &dynamodb.AttributeValue{N: aws.String("10")}, + vars: map[string]types.AttributeValue{ + ":v1": &types.AttributeValueMemberN{Value: "5"}, + ":v2": &types.AttributeValueMemberN{Value: "10"}, }, out: fromHex("0x83018306830282126261318211008303821262613282110182050A"), }, { typ: FilterExpr, in: "a1 > :v1 or a2 <= :v2", - vars: map[string]*dynamodb.AttributeValue{ - ":v1": &dynamodb.AttributeValue{N: aws.String("5")}, - ":v2": &dynamodb.AttributeValue{N: aws.String("10")}, + vars: map[string]types.AttributeValue{ + ":v1": &types.AttributeValueMemberN{Value: "5"}, + ":v2": &types.AttributeValueMemberN{Value: "10"}, }, out: fromHex("0x83018307830482126261318211008305821262613282110182050A"), }, @@ -103,9 +102,9 @@ func TestExpressionEncoder(t *testing.T) { { typ: FilterExpr, in: "a between :v1 and :v2", - vars: map[string]*dynamodb.AttributeValue{ - ":v1": &dynamodb.AttributeValue{N: aws.String("5")}, - ":v2": &dynamodb.AttributeValue{N: aws.String("10")}, + vars: map[string]types.AttributeValue{ + ":v1": &types.AttributeValueMemberN{Value: "5"}, + ":v2": &types.AttributeValueMemberN{Value: "10"}, }, out: fromHex("0x830184098212616182110082110182050A"), }, @@ -117,7 +116,7 @@ func TestExpressionEncoder(t *testing.T) { { typ: ConditionExpr, in: "attribute_not_exists(#a.k1)", - subs: map[string]*string{"#a": aws.String("a1")}, + subs: map[string]string{"#a": "a1"}, out: fromHex("0x8301820C8312626131626B3180"), }, { @@ -133,7 +132,7 @@ func TestExpressionEncoder(t *testing.T) { { typ: ConditionExpr, in: "CONTAINS(a, :v)", - vars: map[string]*dynamodb.AttributeValue{":v": &dynamodb.AttributeValue{N: aws.String("5")}}, + vars: map[string]types.AttributeValue{":v": &types.AttributeValueMemberN{Value: "5"}}, out: fromHex("0x8301830F821261618211008105"), }, { @@ -144,34 +143,34 @@ func TestExpressionEncoder(t *testing.T) { { typ: UpdateExpr, in: "SET #pr.#5star[1] = :r5, #pr.#3star = :r3", - subs: map[string]*string{ - "#pr": aws.String("a1"), - "#5star": aws.String("k5"), - "#3star": aws.String("k3"), + subs: map[string]string{ + "#pr": "a1", + "#5star": "k5", + "#3star": "k3", }, - vars: map[string]*dynamodb.AttributeValue{ - ":r3": &dynamodb.AttributeValue{N: aws.String("3")}, - ":r5": &dynamodb.AttributeValue{N: aws.String("5")}, + vars: map[string]types.AttributeValue{ + ":r3": &types.AttributeValueMemberN{Value: "3"}, + ":r5": &types.AttributeValueMemberN{Value: "5"}, }, out: fromHex("0x83018283138412626131626B35D90CFC0182110083138312626131626B33821101820503"), }, { typ: UpdateExpr, in: "SET Price = Price - :p", - vars: map[string]*dynamodb.AttributeValue{":p": &dynamodb.AttributeValue{N: aws.String("5")}}, + vars: map[string]types.AttributeValue{":p": &types.AttributeValueMemberN{Value: "5"}}, out: fromHex("0x8301818313821265507269636583181A82126550726963658211008105"), }, { typ: UpdateExpr, in: "SET #ri = list_append(#ri, :vals)", - subs: map[string]*string{"#ri": aws.String("RelatedItems")}, - vars: map[string]*dynamodb.AttributeValue{":vals": &dynamodb.AttributeValue{N: aws.String("5")}}, + subs: map[string]string{"#ri": "RelatedItems"}, + vars: map[string]types.AttributeValue{":vals": &types.AttributeValueMemberN{Value: "5"}}, out: fromHex("0x830181831382126C52656C617465644974656D7383181882126C52656C617465644974656D738211008105"), }, { typ: UpdateExpr, in: "SET Price = if_not_exists(Price, :p)", - vars: map[string]*dynamodb.AttributeValue{":p": &dynamodb.AttributeValue{N: aws.String("10")}}, + vars: map[string]types.AttributeValue{":p": &types.AttributeValueMemberN{Value: "10"}}, out: fromHex("0x8301818313821265507269636583178212655072696365821100810A"), }, { @@ -182,19 +181,19 @@ func TestExpressionEncoder(t *testing.T) { { typ: UpdateExpr, in: "ADD QuantityOnHand :q", - vars: map[string]*dynamodb.AttributeValue{":q": &dynamodb.AttributeValue{N: aws.String("5")}}, + vars: map[string]types.AttributeValue{":q": &types.AttributeValueMemberN{Value: "5"}}, out: fromHex("0x830181831482126E5175616E746974794F6E48616E648211008105"), }, { typ: UpdateExpr, in: "DELETE Color :p", - vars: map[string]*dynamodb.AttributeValue{":p": &dynamodb.AttributeValue{N: aws.String("5")}}, + vars: map[string]types.AttributeValue{":p": &types.AttributeValueMemberN{Value: "5"}}, out: fromHex("0x8301818315821265436F6C6F728211008105"), }, { typ: UpdateExpr, in: "DELETE Color :p, Color_2 :p", - vars: map[string]*dynamodb.AttributeValue{":p": &dynamodb.AttributeValue{N: aws.String("5")}}, + vars: map[string]types.AttributeValue{":p": &types.AttributeValueMemberN{Value: "5"}}, out: fromHex("0x8301828315821265436F6C6F728211008315821267436F6C6F725F328211008105"), }, } @@ -225,8 +224,8 @@ func TestExpressionEncoderErrors(t *testing.T) { cases := []struct { typ int in string - subs map[string]*string - vars map[string]*dynamodb.AttributeValue + subs map[string]string + vars map[string]types.AttributeValue err error }{ { @@ -237,7 +236,7 @@ func TestExpressionEncoderErrors(t *testing.T) { { typ: ProjectionExpr, in: "a", - subs: map[string]*string{"#b": aws.String("c")}, + subs: map[string]string{"#b": "c"}, err: newInvalidParameterError("Value provided in ExpressionAttributeNames unused in expressions: keys: {#b}"), }, { @@ -253,9 +252,9 @@ func TestExpressionEncoderErrors(t *testing.T) { { typ: ConditionExpr, in: "a < :v", - vars: map[string]*dynamodb.AttributeValue{ - ":v": &dynamodb.AttributeValue{N: aws.String("10")}, - ":z": &dynamodb.AttributeValue{N: aws.String("5")}, + vars: map[string]types.AttributeValue{ + ":v": &types.AttributeValueMemberN{Value: "10"}, + ":z": &types.AttributeValueMemberN{Value: "5"}, }, err: newInvalidParameterError("Value provided in ExpressionAttributeValues unused in expressions: keys: {:z}"), }, @@ -335,9 +334,9 @@ func BenchmarkFilter(b *testing.B) { expr := map[int]string{ KeyConditionExpr: "pk = :v1 and hk < :v2", } - vars := map[string]*dynamodb.AttributeValue{ - ":v1": &dynamodb.AttributeValue{S: aws.String("pkval")}, - ":v2": &dynamodb.AttributeValue{N: aws.String("5")}, + vars := map[string]types.AttributeValue{ + ":v1": &types.AttributeValueMemberS{Value: "pkval"}, + ":v2": &types.AttributeValueMemberN{Value: "5"}, } expected := []byte{131, 1, 131, 6, 131, 0, 130, 18, 98, 112, 107, 130, 17, 0, 131, 2, 130, 18, 98, 104, 107, 130, 17, 1, 130, 101, 112, 107, 118, 97, 108, 5} diff --git a/dax/pagination_test.go b/dax/pagination_test.go index b584ef4..be54572 100644 --- a/dax/pagination_test.go +++ b/dax/pagination_test.go @@ -1,318 +1,315 @@ package dax import ( - "reflect" - "testing" - "github.com/aws/aws-dax-go/dax/internal/client" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/dynamodb" ) func NewWithInternalClient(c client.DaxAPI) *Dax { return &Dax{client: c, config: DefaultConfig()} } -func TestPaginationBatchGetItemPage(t *testing.T) { - pages, numPages, gotToEnd := map[string][]map[string]*dynamodb.AttributeValue{}, 0, false - - resps := []*dynamodb.BatchGetItemOutput{ - { - Responses: map[string][]map[string]*dynamodb.AttributeValue{ - "tablename": { - { - "key": {S: aws.String("key1")}, - "attr": {S: aws.String("attr1")}, - }, - { - "key": {S: aws.String("key2")}, - "attr": {S: aws.String("attr2")}, - }, - }, - }, - UnprocessedKeys: map[string]*dynamodb.KeysAndAttributes{ - "tablename": { - Keys: []map[string]*dynamodb.AttributeValue{ - {"key": {S: aws.String("key3")}}, - {"key": {S: aws.String("key4")}}, - {"key": {S: aws.String("key5")}}, - }, - }, - }, - }, - { - Responses: map[string][]map[string]*dynamodb.AttributeValue{ - "tablename": { - { - "key": {S: aws.String("key3")}, - "attr": {S: aws.String("attr3")}, - }, - { - "key": {S: aws.String("key4")}, - "attr": {S: aws.String("attr4")}, - }, - }, - }, - UnprocessedKeys: map[string]*dynamodb.KeysAndAttributes{ - "tablename": { - Keys: []map[string]*dynamodb.AttributeValue{ - {"key": {S: aws.String("key5")}}, - }, - }, - }, - }, - { - Responses: map[string][]map[string]*dynamodb.AttributeValue{ - "tablename": { - { - "key": {S: aws.String("key5")}, - "attr": {S: aws.String("attr5")}, - }, - }, - }, - }, - } - - stub := client.NewClientStub(resps, nil, nil) - db := NewWithInternalClient(stub) - params := &dynamodb.BatchGetItemInput{ - RequestItems: map[string]*dynamodb.KeysAndAttributes{ - "tablename": { - Keys: []map[string]*dynamodb.AttributeValue{ - {"key": {S: aws.String("key1")}}, - {"key": {S: aws.String("key2")}}, - {"key": {S: aws.String("key3")}}, - {"key": {S: aws.String("key4")}}, - {"key": {S: aws.String("key5")}}, - }, - }, - }, - } - err := db.BatchGetItemPages(params, func(p *dynamodb.BatchGetItemOutput, last bool) bool { - numPages++ - for k, v := range p.Responses { - pages[k] = append(pages[k], v...) - } - if last { - if gotToEnd { - t.Errorf("last=true happened twice") - } - gotToEnd = true - } - return true - }) - - // There was no error - if err != nil { - t.Errorf("expect nil, %v", err) - } - - // The items were all returned - if e, a := - map[string][]map[string]*dynamodb.AttributeValue{ - "tablename": { - {"key": {S: aws.String("key1")}, "attr": {S: aws.String("attr1")}}, - {"key": {S: aws.String("key2")}, "attr": {S: aws.String("attr2")}}, - {"key": {S: aws.String("key3")}, "attr": {S: aws.String("attr3")}}, - {"key": {S: aws.String("key4")}, "attr": {S: aws.String("attr4")}}, - {"key": {S: aws.String("key5")}, "attr": {S: aws.String("attr5")}}, - }}, pages; !reflect.DeepEqual(e, a) { - t.Errorf("expect %v, got %v", e, a) - } - - // The results were returned in the expected number of pages - if e, a := 3, numPages; e != a { - t.Errorf("expect %v, got %v", e, a) - } - - // The last page was signaled - if !gotToEnd { - t.Errorf("expect true") - } - - // Each request had the correct number of keys - for i, e := range []int{5, 3, 1} { - a := len(stub.GetBatchGetItemRequests()[i].RequestItems["tablename"].Keys) - if e != a { - t.Errorf("expect %v, got %v at index %d", e, a, i) - } - } - - // The last request had the correct key - if e, a := "key5", *stub.GetBatchGetItemRequests()[2].RequestItems["tablename"].Keys[0]["key"].S; e != a { - t.Errorf("expect %v, got %v", e, a) - } -} - -func TestPaginationQueryPage(t *testing.T) { - pages, numPages, gotToEnd := []map[string]*dynamodb.AttributeValue{}, 0, false - - resps := []*dynamodb.QueryOutput{ - { - LastEvaluatedKey: map[string]*dynamodb.AttributeValue{"key": {S: aws.String("key1")}}, - Count: aws.Int64(1), - Items: []map[string]*dynamodb.AttributeValue{ - { - "key": {S: aws.String("key1")}, - }, - }, - }, - { - LastEvaluatedKey: map[string]*dynamodb.AttributeValue{"key": {S: aws.String("key2")}}, - Count: aws.Int64(1), - Items: []map[string]*dynamodb.AttributeValue{ - { - "key": {S: aws.String("key2")}, - }, - }, - }, - { - LastEvaluatedKey: map[string]*dynamodb.AttributeValue{}, - Count: aws.Int64(1), - Items: []map[string]*dynamodb.AttributeValue{ - { - "key": {S: aws.String("key3")}, - }, - }, - }, - } - - stub := client.NewClientStub(nil, resps, nil) - db := NewWithInternalClient(stub) - params := &dynamodb.QueryInput{ - Limit: aws.Int64(1), - TableName: aws.String("tablename"), - } - err := db.QueryPages(params, func(p *dynamodb.QueryOutput, last bool) bool { - numPages++ - pages = append(pages, p.Items...) - if last { - if gotToEnd { - t.Errorf("last=true happened twice") - } - gotToEnd = true - } - return true - }) - - // There was no error - if err != nil { - t.Errorf("expect nil, %v", err) - } - - // The correct items were returned - if e, a := - []map[string]*dynamodb.AttributeValue{ - {"key": {S: aws.String("key1")}}, - {"key": {S: aws.String("key2")}}, - {"key": {S: aws.String("key3")}}, - }, pages; !reflect.DeepEqual(e, a) { - t.Errorf("expect %v, got %v", e, a) - } - - // Items were returned in the correct number of pages - if e, a := 3, numPages; e != a { - t.Errorf("expect %v, got %v", e, a) - } - - // The last page was signaled - if !gotToEnd { - t.Errorf("expect true") - } - - // Each request had the correct start key - if a := stub.GetQueryRequests()[0].ExclusiveStartKey; a != nil { - t.Errorf("expect nil, %v", a) - } - for i, e := range []string{"key1", "key2"} { - if a := *stub.GetQueryRequests()[i+1].ExclusiveStartKey["key"].S; e != a { - t.Errorf("expect %s, got %s at index %d", e, a, i+1) - } - } -} - -func TestPaginationScanPage(t *testing.T) { - pages, numPages, gotToEnd := []map[string]*dynamodb.AttributeValue{}, 0, false - - resps := []*dynamodb.ScanOutput{ - { - LastEvaluatedKey: map[string]*dynamodb.AttributeValue{"key": {S: aws.String("key1")}}, - Count: aws.Int64(1), - Items: []map[string]*dynamodb.AttributeValue{ - { - "key": {S: aws.String("key1")}, - }, - }, - }, - { - LastEvaluatedKey: map[string]*dynamodb.AttributeValue{"key": {S: aws.String("key2")}}, - Count: aws.Int64(1), - Items: []map[string]*dynamodb.AttributeValue{ - { - "key": {S: aws.String("key2")}, - }, - }, - }, - { - LastEvaluatedKey: map[string]*dynamodb.AttributeValue{}, - Count: aws.Int64(1), - Items: []map[string]*dynamodb.AttributeValue{ - { - "key": {S: aws.String("key3")}, - }, - }, - }, - } - - stub := client.NewClientStub(nil, nil, resps) - db := NewWithInternalClient(stub) - params := &dynamodb.ScanInput{ - Limit: aws.Int64(1), - TableName: aws.String("tablename"), - } - err := db.ScanPages(params, func(p *dynamodb.ScanOutput, last bool) bool { - numPages++ - pages = append(pages, p.Items...) - if last { - if gotToEnd { - t.Errorf("last=true happened twice") - } - gotToEnd = true - } - return true - }) - - // There was no error - if err != nil { - t.Errorf("expect nil, %v", err) - } - - // The correct items were returned - if e, a := - []map[string]*dynamodb.AttributeValue{ - {"key": {S: aws.String("key1")}}, - {"key": {S: aws.String("key2")}}, - {"key": {S: aws.String("key3")}}, - }, pages; !reflect.DeepEqual(e, a) { - t.Errorf("expect %v, got %v", e, a) - } - - // Items were returned in the correct number of pages - if e, a := 3, numPages; e != a { - t.Errorf("expect %v, got %v", e, a) - } - - // Last page was signaled - if !gotToEnd { - t.Errorf("expect true") - } - // Each request had the correct start key - if a := stub.GetScanRequests()[0].ExclusiveStartKey; a != nil { - t.Errorf("expect nil, %v", a) - } - for i, e := range []string{"key1", "key2"} { - if a := *stub.GetScanRequests()[i+1].ExclusiveStartKey["key"].S; e != a { - t.Errorf("expect %s, got %s at index %d", e, a, i+1) - } - } -} +//func TestPaginationBatchGetItemPage(t *testing.T) { +// pages, numPages, gotToEnd := map[string][]map[string]types.AttributeValue{}, 0, false +// +// resps := []*dynamodb.BatchGetItemOutput{ +// { +// Responses: map[string][]map[string]types.AttributeValue{ +// "tablename": { +// { +// "key": &types.AttributeValueMemberS{Value: "key1"}, +// "attr": &types.AttributeValueMemberS{Value: "attr1"}, +// }, +// { +// "key": &types.AttributeValueMemberS{Value: "key2"}, +// "attr": &types.AttributeValueMemberS{Value: "attr2"}, +// }, +// }, +// }, +// UnprocessedKeys: map[string]types.KeysAndAttributes{ +// "tablename": { +// Keys: []map[string]types.AttributeValue{ +// {"key": &types.AttributeValueMemberS{Value: "key3"}}, +// {"key": &types.AttributeValueMemberS{Value: "key4"}}, +// {"key": &types.AttributeValueMemberS{Value: "key5"}}, +// }, +// }, +// }, +// }, +// { +// Responses: map[string][]map[string]types.AttributeValue{ +// "tablename": { +// { +// "key": &types.AttributeValueMemberS{Value: "key3"}, +// "attr": &types.AttributeValueMemberS{Value: "attr3"}, +// }, +// { +// "key": &types.AttributeValueMemberS{Value: "key4"}, +// "attr": &types.AttributeValueMemberS{Value: "attr4"}, +// }, +// }, +// }, +// UnprocessedKeys: map[string]types.KeysAndAttributes{ +// "tablename": { +// Keys: []map[string]types.AttributeValue{ +// {"key": &types.AttributeValueMemberS{Value: "key5"}}, +// }, +// }, +// }, +// }, +// { +// Responses: map[string][]map[string]types.AttributeValue{ +// "tablename": { +// { +// "key": &types.AttributeValueMemberS{Value: "key5"}, +// "attr": &types.AttributeValueMemberS{Value: "attr5"}, +// }, +// }, +// }, +// }, +// } +// +// stub := client.NewClientStub(resps, nil, nil) +// db := NewWithInternalClient(stub) +// params := &dynamodb.BatchGetItemInput{ +// RequestItems: map[string]types.KeysAndAttributes{ +// "tablename": { +// Keys: []map[string]types.AttributeValue{ +// {"key": &types.AttributeValueMemberS{Value: "key1"}}, +// {"key": &types.AttributeValueMemberS{Value: "key2"}}, +// {"key": &types.AttributeValueMemberS{Value: "key3"}}, +// {"key": &types.AttributeValueMemberS{Value: "key4"}}, +// {"key": &types.AttributeValueMemberS{Value: "key5"}}, +// }, +// }, +// }, +// } +// err := db.BatchGetItemPages(params, func(p *dynamodb.BatchGetItemOutput, last bool) bool { +// numPages++ +// for k, v := range p.Responses { +// pages[k] = append(pages[k], v...) +// } +// if last { +// if gotToEnd { +// t.Errorf("last=true happened twice") +// } +// gotToEnd = true +// } +// return true +// }) +// +// // There was no error +// if err != nil { +// t.Errorf("expect nil, %v", err) +// } +// +// // The items were all returned +// if e, a := +// map[string][]map[string]types.AttributeValue{ +// "tablename": { +// {"key": &types.AttributeValueMemberS{Value: "key1"}, "attr": &types.AttributeValueMemberS{Value: "attr1"}}, +// {"key": &types.AttributeValueMemberS{Value: "key2"}, "attr": &types.AttributeValueMemberS{Value: "attr2"}}, +// {"key": &types.AttributeValueMemberS{Value: "key3"}, "attr": &types.AttributeValueMemberS{Value: "attr3"}}, +// {"key": &types.AttributeValueMemberS{Value: "key4"}, "attr": &types.AttributeValueMemberS{Value: "attr4"}}, +// {"key": &types.AttributeValueMemberS{Value: "key5"}, "attr": &types.AttributeValueMemberS{Value: "attr5"}}, +// }}, pages; !reflect.DeepEqual(e, a) { +// t.Errorf("expect %v, got %v", e, a) +// } +// +// // The results were returned in the expected number of pages +// if e, a := 3, numPages; e != a { +// t.Errorf("expect %v, got %v", e, a) +// } +// +// // The last page was signaled +// if !gotToEnd { +// t.Errorf("expect true") +// } +// +// // Each request had the correct number of keys +// for i, e := range []int{5, 3, 1} { +// a := len(stub.GetBatchGetItemRequests()[i].RequestItems["tablename"].Keys) +// if e != a { +// t.Errorf("expect %v, got %v at index %d", e, a, i) +// } +// } +// +// // The last request had the correct key +// if e, a := "key5", stub.GetBatchGetItemRequests()[2].RequestItems["tablename"].Keys[0]["key"].(*types.AttributeValueMemberS).Value; e != a { +// t.Errorf("expect %v, got %v", e, a) +// } +//} +// +//func TestPaginationQueryPage(t *testing.T) { +// var pages []map[string]types.AttributeValue +// numPages, gotToEnd := 0, false +// +// resps := []*dynamodb.QueryOutput{ +// { +// LastEvaluatedKey: map[string]types.AttributeValue{"key": &types.AttributeValueMemberS{Value: ("key1")}}, +// Count: 1, +// Items: []map[string]types.AttributeValue{ +// { +// "key": &types.AttributeValueMemberS{Value: "key1"}, +// }, +// }, +// }, +// { +// LastEvaluatedKey: map[string]types.AttributeValue{"key": &types.AttributeValueMemberS{Value: "key2"}}, +// Count: 1, +// Items: []map[string]types.AttributeValue{ +// { +// "key": &types.AttributeValueMemberS{Value: "key2"}, +// }, +// }, +// }, +// { +// LastEvaluatedKey: map[string]types.AttributeValue{}, +// Count: 1, +// Items: []map[string]types.AttributeValue{ +// { +// "key": &types.AttributeValueMemberS{Value: "key3"}, +// }, +// }, +// }, +// } +// +// stub := client.NewClientStub(nil, resps, nil) +// db := NewWithInternalClient(stub) +// params := &dynamodb.QueryInput{ +// Limit: aws.Int32(1), +// TableName: aws.String("tablename"), +// } +// err := db.QueryPages(params, func(p *dynamodb.QueryOutput, last bool) bool { +// numPages++ +// pages = append(pages, p.Items...) +// if last { +// if gotToEnd { +// t.Errorf("last=true happened twice") +// } +// gotToEnd = true +// } +// return true +// }) +// +// // There was no error +// if err != nil { +// t.Errorf("expect nil, %v", err) +// } +// +// // The correct items were returned +// if e, a := +// []map[string]types.AttributeValue{ +// {"key": &types.AttributeValueMemberS{Value: "key1"}}, +// {"key": &types.AttributeValueMemberS{Value: "key2"}}, +// {"key": &types.AttributeValueMemberS{Value: "key3"}}, +// }, pages; !reflect.DeepEqual(e, a) { +// t.Errorf("expect %v, got %v", e, a) +// } +// +// // Items were returned in the correct number of pages +// if e, a := 3, numPages; e != a { +// t.Errorf("expect %v, got %v", e, a) +// } +// +// // The last page was signaled +// if !gotToEnd { +// t.Errorf("expect true") +// } +// +// // Each request had the correct start key +// if a := stub.GetQueryRequests()[0].ExclusiveStartKey; a != nil { +// t.Errorf("expect nil, %v", a) +// } +// for i, e := range []string{"key1", "key2"} { +// if a := stub.GetQueryRequests()[i+1].ExclusiveStartKey["key"].(*types.AttributeValueMemberS).Value; e != a { +// t.Errorf("expect %s, got %s at index %d", e, a, i+1) +// } +// } +//} +// +//func TestPaginationScanPage(t *testing.T) { +// var pages []map[string]types.AttributeValue +// numPages, gotToEnd := 0, false +// +// resps := []*dynamodb.ScanOutput{ +// { +// LastEvaluatedKey: map[string]types.AttributeValue{"key": &types.AttributeValueMemberS{Value: "key1"}}, +// Count: 1, +// Items: []map[string]types.AttributeValue{ +// { +// "key": &types.AttributeValueMemberS{Value: "key1"}, +// }, +// }, +// }, +// { +// LastEvaluatedKey: map[string]types.AttributeValue{"key": &types.AttributeValueMemberS{Value: "key2"}}, +// Count: 1, +// Items: []map[string]types.AttributeValue{ +// { +// "key": &types.AttributeValueMemberS{Value: "key2"}, +// }, +// }, +// }, +// { +// LastEvaluatedKey: map[string]types.AttributeValue{}, +// Count: 1, +// Items: []map[string]types.AttributeValue{ +// { +// "key": &types.AttributeValueMemberS{Value: "key3"}, +// }, +// }, +// }, +// } +// +// stub := client.NewClientStub(nil, nil, resps) +// db := NewWithInternalClient(stub) +// params := &dynamodb.ScanInput{ +// Limit: aws.Int32(1), +// TableName: aws.String("tablename"), +// } +// err := db.ScanPages(params, func(p *dynamodb.ScanOutput, last bool) bool { +// numPages++ +// pages = append(pages, p.Items...) +// if last { +// if gotToEnd { +// t.Errorf("last=true happened twice") +// } +// gotToEnd = true +// } +// return true +// }) +// +// // There was no error +// if err != nil { +// t.Errorf("expect nil, %v", err) +// } +// +// // The correct items were returned +// if e, a := +// []map[string]types.AttributeValue{ +// {"key": &types.AttributeValueMemberS{Value: "key1"}}, +// {"key": &types.AttributeValueMemberS{Value: "key2"}}, +// {"key": &types.AttributeValueMemberS{Value: "key3"}}, +// }, pages; !reflect.DeepEqual(e, a) { +// t.Errorf("expect %v, got %v", e, a) +// } +// +// // Items were returned in the correct number of pages +// if e, a := 3, numPages; e != a { +// t.Errorf("expect %v, got %v", e, a) +// } +// +// // Last page was signaled +// if !gotToEnd { +// t.Errorf("expect true") +// } +// // Each request had the correct start key +// if a := stub.GetScanRequests()[0].ExclusiveStartKey; a != nil { +// t.Errorf("expect nil, %v", a) +// } +// for i, e := range []string{"key1", "key2"} { +// if a := stub.GetScanRequests()[i+1].ExclusiveStartKey["key"].(*types.AttributeValueMemberS).Value; e != a { +// t.Errorf("expect %s, got %s at index %d", e, a, i+1) +// } +// } +//} diff --git a/dax/service.go b/dax/service.go index 1b165a7..694bc94 100644 --- a/dax/service.go +++ b/dax/service.go @@ -18,18 +18,15 @@ package dax import ( "context" "crypto/tls" - "errors" - "fmt" "net" "net/url" - "time" "github.com/aws/aws-dax-go/dax/internal/client" "github.com/aws/aws-dax-go/dax/internal/proxy" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/client/metadata" - "github.com/aws/aws-sdk-go/aws/request" - "github.com/aws/aws-sdk-go/aws/session" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" + "github.com/aws/aws-sdk-go-v2/service/dynamodb" + "github.com/aws/smithy-go/logging" ) // Dax makes requests to the Amazon DAX API, which conforms to the DynamoDB API. @@ -40,18 +37,18 @@ type Dax struct { config Config } +var _ DynamoDBAPI = (*Dax)(nil) + const ServiceName = "dax" type Config struct { client.Config // Default request options - RequestTimeout time.Duration - WriteRetries int - ReadRetries int + WriteRetries int + ReadRetries int - LogLevel aws.LogLevelType - Logger aws.Logger + Logger logging.Logger } // DefaultConfig returns the default DAX configuration. @@ -60,33 +57,27 @@ type Config struct { // to start up a DAX client. func DefaultConfig() Config { return Config{ - Config: client.DefaultConfig(), - RequestTimeout: 1 * time.Minute, - WriteRetries: 2, - ReadRetries: 2, - LogLevel: aws.LogOff, - Logger: aws.NewDefaultLogger(), + Config: client.DefaultConfig(), + WriteRetries: 2, + ReadRetries: 2, + Logger: &logging.Nop{}, } } -// NewWithSession creates a new instance of the DAX config with a session. -// -// Only configurations relevent to DAX will be used, others will be ignored. -func NewConfigWithSession(session session.Session) Config { +// NewConfigWithSDKConfig creates a new instance of the DAX config with an aws.Config. +func NewConfigWithSDKConfig(config aws.Config) Config { dc := DefaultConfig() - if session.Config != nil { - dc.mergeFrom(*session.Config) - } + dc.mergeFrom(config) return dc } // New creates a new instance of the DAX client with a DAX configuration. -func New(cfg Config) (*Dax, error) { - cfg.Config.SetLogger(cfg.Logger, cfg.LogLevel) - c, err := client.New(cfg.Config) +func New(ctx context.Context, cfg Config) (*Dax, error) { + cfg.Config.SetLogger(cfg.Logger) + c, err := client.New(ctx, cfg.Config) if err != nil { if cfg.Logger != nil { - cfg.Logger.Log(fmt.Sprintf("ERROR: Exception in initialisation of DAX Client : %s", err)) + cfg.Logger.Logf(client.ClassificationError, "Exception in initialisation of DAX Client : %s", err) } return nil, err } @@ -110,89 +101,69 @@ func SecureDialContext(endpoint string, skipHostnameVerification bool) (func(ctx return dialer.DialContext, nil } -// NewWithSession creates a new instance of the DAX client with a session. -// -// Only configurations relevent to DAX will be used, others will be ignored. +// NewWithSDKConfig creates a new instance of the DAX client with an aws.Config. // // Example: -// mySession := session.Must(session.NewSession( -// &aws.Config{ -// Region: aws.String("us-east-1"), -// Endpoint: aws.String("dax://mycluster.frfx8h.clustercfg.dax.usw2.amazonaws.com:8111"), -// })) +// config := aws.Config{ +// Region: "us-east-1", +// EndpointResolverWithOptions: aws.EndpointResolverWithOptionsFunc(func(service, region string, options ...any) (aws.Endpoint, error) { +// return aws.Endpoint{ +// URL: "dax://mycluster.frfx8h.clustercfg.dax.usw2.amazonaws.com:8111", +// }, nil +// }), +// } // // // Create a DAX client from just a session. -// svc := dax.NewWithSession(mySession) -func NewWithSession(session session.Session) (*Dax, error) { +// svc := dax.NewWithSDKConfig(ctx, config) +func NewWithSDKConfig(ctx context.Context, config aws.Config) (*Dax, error) { dc := DefaultConfig() - if session.Config != nil { - dc.mergeFrom(*session.Config) - } - return New(dc) + dc.mergeFrom(config) + return New(ctx, dc) } func (c *Config) mergeFrom(ac aws.Config) { - if r := ac.MaxRetries; r != nil && *r != aws.UseServiceDefaultRetries { - c.WriteRetries = *r - c.ReadRetries = *r + if r := ac.RetryMaxAttempts; r > 0 { + c.WriteRetries = r + c.ReadRetries = r } + if ac.Logger != nil { c.Logger = ac.Logger } - if ac.LogLevel != nil { - c.LogLevel = *ac.LogLevel - } if ac.Credentials != nil { c.Credentials = ac.Credentials } - if ac.Endpoint != nil { - c.HostPorts = []string{*ac.Endpoint} + if ac.EndpointResolverWithOptions != nil { + c.EndpointResolver = ac.EndpointResolverWithOptions } - if ac.Region != nil { - c.Region = *ac.Region + if ac.Region != "" { + c.Region = ac.Region } } -func (c *Config) requestOptions(read bool, ctx context.Context, opts ...request.Option) (client.RequestOptions, context.CancelFunc, error) { +func (c *Config) requestOptions(read bool, opts ...func(*dynamodb.Options)) client.RequestOptions { r := c.WriteRetries if read { r = c.ReadRetries } - var cfn context.CancelFunc - if ctx == nil && c.RequestTimeout > 0 { - ctx, cfn = context.WithTimeout(aws.BackgroundContext(), c.RequestTimeout) - } - opt := client.RequestOptions{ - LogLevel: c.LogLevel, - Logger: c.Logger, - MaxRetries: r, - } - if err := opt.MergeFromRequestOptions(ctx, opts...); err != nil { - if c.Logger != nil && c.LogLevel.AtLeast(aws.LogDebug) { - c.Logger.Log(fmt.Sprintf("DEBUG: Error in merging from Request Options : %s", err)) - } - return client.RequestOptions{}, nil, err - } - return opt, cfn, nil -} -func buildHandlersForUnimplementedOperations() *request.Handlers { - h := &request.Handlers{} - h.Build.PushFrontNamed(request.NamedHandler{ - Name: "dax.BuildHandler", - Fn: func(r *request.Request) { - r.Error = errors.New(client.ErrCodeNotImplemented) - return - }}) - return h -} + opt := client.RequestOptions{} + opt.Logger = c.Logger + opt.RetryMaxAttempts = r -var handlersForUnimplementedOperations = buildHandlersForUnimplementedOperations() + // merge from request options + for _, o := range opts { + o(&opt.Options) + } -func newRequestForUnimplementedOperation() *request.Request { - op := &request.Operation{Name: "Unimplemented"} - clientInfo := metadata.ClientInfo{ServiceName: "dax"} - req := request.New(aws.Config{}, clientInfo, *handlersForUnimplementedOperations, nil, op, nil, nil) - return req + if opt.Retryer != nil { + opt.Retryer = retry.NewStandard( + func(options *retry.StandardOptions) { + options.MaxAttempts = r + options.Retryables = append(options.Retryables, retry.IsErrorRetryableFunc(client.IsErrorRetryable)) + }, + ) + } + return opt } diff --git a/dax/service_test.go b/dax/service_test.go index 3f4132f..ed0b528 100644 --- a/dax/service_test.go +++ b/dax/service_test.go @@ -3,7 +3,7 @@ package dax import ( "testing" - "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go-v2/aws" ) func TestConfigMergeFrom(t *testing.T) { @@ -24,22 +24,20 @@ func TestConfigMergeFrom(t *testing.T) { { testName: "DefaultConfig merging with an aws config that specifies aws.UseServiceDefaultRetries should result in using default retries", daxConfig: DefaultConfig(), - awsConfig: aws.Config{MaxRetries: aws.Int(aws.UseServiceDefaultRetries)}, + awsConfig: aws.Config{RetryMaxAttempts: -1}, expectedWriteRetries: 2, expectedReadRetries: 2, }, { testName: "DefaultConfig merging with an aws config that specifies a non-negative MaxRetry should result in using that value as both WriteRetries and ReadRetries", daxConfig: DefaultConfig(), - awsConfig: aws.Config{MaxRetries: aws.Int(123)}, + awsConfig: aws.Config{RetryMaxAttempts: 123}, expectedWriteRetries: 123, expectedReadRetries: 123, }, } for _, testCase := range testCases { - testCase := testCase - t.Run(testCase.testName, func(t *testing.T) { testCase.daxConfig.mergeFrom(testCase.awsConfig) if testCase.daxConfig.WriteRetries != testCase.expectedWriteRetries { diff --git a/go.mod b/go.mod index b3d040d..7d41b1e 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,10 @@ go 1.11 require ( github.com/antlr/antlr4 v0.0.0-20181218183524-be58ebffde8e - github.com/aws/aws-sdk-go v1.44.171 + github.com/aws/aws-sdk-go-v2 v1.18.0 + github.com/aws/aws-sdk-go-v2/config v1.18.25 + github.com/aws/aws-sdk-go-v2/service/dynamodb v1.19.5 + github.com/aws/smithy-go v1.13.5 github.com/gofrs/uuid v3.3.0+incompatible github.com/stretchr/testify v1.5.1 ) diff --git a/go.sum b/go.sum index 2267024..83f4411 100644 --- a/go.sum +++ b/go.sum @@ -1,75 +1,56 @@ github.com/antlr/antlr4 v0.0.0-20181218183524-be58ebffde8e h1:yxMh4HIdsSh2EqxUESWvzszYMNzOugRyYCeohfwNULM= github.com/antlr/antlr4 v0.0.0-20181218183524-be58ebffde8e/go.mod h1:T7PbCXFs94rrTttyxjbyT5+/1V8T2TYDejxUfHJjw1Y= -github.com/aws/aws-sdk-go v1.36.22 h1:kkQdiotYI9RlGoAoMPbQyHKsl9oyT+vz/w2cN6EUZKs= -github.com/aws/aws-sdk-go v1.36.22/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= -github.com/aws/aws-sdk-go v1.44.171 h1:maREiPAmibvuONMOEZIkCH2OTosLRnDelceTtH3SYfo= -github.com/aws/aws-sdk-go v1.44.171/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= +github.com/aws/aws-sdk-go-v2 v1.17.8/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw= +github.com/aws/aws-sdk-go-v2 v1.18.0 h1:882kkTpSFhdgYRKVZ/VCgf7sd0ru57p2JCxz4/oN5RY= +github.com/aws/aws-sdk-go-v2 v1.18.0/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw= +github.com/aws/aws-sdk-go-v2/config v1.18.25 h1:JuYyZcnMPBiFqn87L2cRppo+rNwgah6YwD3VuyvaW6Q= +github.com/aws/aws-sdk-go-v2/config v1.18.25/go.mod h1:dZnYpD5wTW/dQF0rRNLVypB396zWCcPiBIvdvSWHEg4= +github.com/aws/aws-sdk-go-v2/credentials v1.13.24 h1:PjiYyls3QdCrzqUN35jMWtUK1vqVZ+zLfdOa/UPFDp0= +github.com/aws/aws-sdk-go-v2/credentials v1.13.24/go.mod h1:jYPYi99wUOPIFi0rhiOvXeSEReVOzBqFNOX5bXYoG2o= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.3 h1:jJPgroehGvjrde3XufFIJUZVK5A2L9a3KwSFgKy9n8w= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.3/go.mod h1:4Q0UFP0YJf0NrsEuEYHpM9fTSEVnD16Z3uyEF7J9JGM= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.32/go.mod h1:RudqOgadTWdcS3t/erPQo24pcVEoYyqj/kKW5Vya21I= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.33 h1:kG5eQilShqmJbv11XL1VpyDbaEJzWxd4zRiCG30GSn4= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.33/go.mod h1:7i0PF1ME/2eUPFcjkVIwq+DOygHEoK92t5cDqNgYbIw= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.26/go.mod h1:vq86l7956VgFr0/FWQ2BWnK07QC3WYsepKzy33qqY5U= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.27 h1:vFQlirhuM8lLlpI7imKOMsjdQLuN9CPi+k44F/OFVsk= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.27/go.mod h1:UrHnn3QV/d0pBZ6QBAEQcqFLf8FAzLmoUfPVIueOvoM= +github.com/aws/aws-sdk-go-v2/internal/ini v1.3.34 h1:gGLG7yKaXG02/jBlg210R7VgQIotiQntNhsCFejawx8= +github.com/aws/aws-sdk-go-v2/internal/ini v1.3.34/go.mod h1:Etz2dj6UHYuw+Xw830KfzCfWGMzqvUTCjUj5b76GVDc= +github.com/aws/aws-sdk-go-v2/service/dynamodb v1.19.5 h1:22zOCZ3Xf5qL0bH/Bc/jSH6P6SRTDPQEj2yxk+8wIXA= +github.com/aws/aws-sdk-go-v2/service/dynamodb v1.19.5/go.mod h1:2XzQIYZ2VeZzxUnFIe0EpYIdkol6eEgs3vSAFjTLw4Q= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.11 h1:y2+VQzC6Zh2ojtV2LoC0MNwHWc6qXv/j2vrQtlftkdA= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.11/go.mod h1:iV4q2hsqtNECrfmlXyord9u4zyuFEJX9eLgLpSPzWA8= +github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.7.26 h1:XsLNgECTon/ughUzILFbbeC953tTbXnJv4GQPUHm80A= +github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.7.26/go.mod h1:zSW1SZ9ZQQZlRfqur2sI2Mn/ptcDLi6mtlPaXIIw0IE= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.27 h1:0iKliEXAcCa2qVtRs7Ot5hItA2MsufrphbRFlz1Owxo= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.27/go.mod h1:EOwBD4J4S5qYszS5/3DpkejfuK+Z5/1uzICfPaZLtqw= +github.com/aws/aws-sdk-go-v2/service/sso v1.12.10 h1:UBQjaMTCKwyUYwiVnUt6toEJwGXsLBI6al083tpjJzY= +github.com/aws/aws-sdk-go-v2/service/sso v1.12.10/go.mod h1:ouy2P4z6sJN70fR3ka3wD3Ro3KezSxU6eKGQI2+2fjI= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.10 h1:PkHIIJs8qvq0e5QybnZoG1K/9QTrLr9OsqCIo59jOBA= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.10/go.mod h1:AFvkxc8xfBe8XA+5St5XIHHrQQtkxqrRincx4hmMHOk= +github.com/aws/aws-sdk-go-v2/service/sts v1.19.0 h1:2DQLAKDteoEDI8zpCzqBMaZlJuoE9iTYD0gFmXVax9E= +github.com/aws/aws-sdk-go-v2/service/sts v1.19.0/go.mod h1:BgQOMsg8av8jset59jelyPW7NoZcZXLVpDsXunGDrk8= +github.com/aws/smithy-go v1.13.5 h1:hgz0X/DX0dGqTYpGALqXJoRKRj5oQ7150i5FdTePzO8= +github.com/aws/smithy-go v1.13.5/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/gofrs/uuid v3.3.0+incompatible h1:8K4tyRfvU1CYPgJsveYFQMhpFd/wXNM7iK6rR7UHz84= github.com/gofrs/uuid v3.3.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= -github.com/gofrs/uuid v4.3.1+incompatible h1:0/KbAdpx3UXAx1kEOWHJeOkpbgRFGHVgv+CFIY7dBJI= -github.com/gofrs/uuid v4.3.1+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= +github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= -github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= -github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= -github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.1.0 h1:hZ/3BUoy5aId7sCpA/Tc5lt8DkFgdVS2onTpJsZ/fl0= -golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg= -golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=