From 6b3880bb3d5503dab4075c117b72524909e06ce1 Mon Sep 17 00:00:00 2001 From: Miles Crabill Date: Thu, 27 Oct 2022 10:17:27 -0700 Subject: [PATCH 1/6] `dynamodb_table_item` `create`: use `ConditionExpression` - per [AWS' documentation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/LegacyConditionalParameters.Expected.html) `Expected` is a legacy parameter and should no longer be used - should fix https://github.com/hashicorp/terraform-provider-aws/issues/26080, or at least be more predictable, while maintaining the same behavior for tables without composite keys. It seems like `Expected` is only checking that the hash key does not exist whereas this `ConditionExpression` will check whether an item with the same hash key _and_ range key does not exist - [this blog post](https://www.alexdebrie.com/posts/dynamodb-condition-expressions/) explains how this `ConditionExpression` works, essentially the condition will always be compared against a single item and so it is sufficient to just check for the existence of the hash key --- internal/service/dynamodb/table_item.go | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/internal/service/dynamodb/table_item.go b/internal/service/dynamodb/table_item.go index ac98fd9a55b9..3737052cac53 100644 --- a/internal/service/dynamodb/table_item.go +++ b/internal/service/dynamodb/table_item.go @@ -73,11 +73,7 @@ func resourceTableItemCreate(d *schema.ResourceData, meta interface{}) error { _, err = conn.PutItem(&dynamodb.PutItemInput{ Item: attributes, // Explode if item exists. We didn't create it. - Expected: map[string]*dynamodb.ExpectedAttributeValue{ - hashKey: { - Exists: aws.Bool(false), - }, - }, + ConditionExpression: aws.String(fmt.Sprintf("attribute_not_exists(%s)", hashKey)), TableName: aws.String(tableName), }) if err != nil { From e6dcc6087edf34be2e0ddb835fa39d6d3495f174 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 27 Oct 2022 14:23:00 -0400 Subject: [PATCH 2/6] Run 'make fmt'. --- internal/service/dynamodb/table_item.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/service/dynamodb/table_item.go b/internal/service/dynamodb/table_item.go index 3737052cac53..005bee79aa9b 100644 --- a/internal/service/dynamodb/table_item.go +++ b/internal/service/dynamodb/table_item.go @@ -74,7 +74,7 @@ func resourceTableItemCreate(d *schema.ResourceData, meta interface{}) error { Item: attributes, // Explode if item exists. We didn't create it. ConditionExpression: aws.String(fmt.Sprintf("attribute_not_exists(%s)", hashKey)), - TableName: aws.String(tableName), + TableName: aws.String(tableName), }) if err != nil { return err From 47c9709b0cb6133e031f32e8f8780ddaf4d14d29 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 27 Oct 2022 15:03:32 -0400 Subject: [PATCH 3/6] r/aws_dynamodb_table_item: Allow reserved words in ConditionExpression. --- internal/service/dynamodb/table_item.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/internal/service/dynamodb/table_item.go b/internal/service/dynamodb/table_item.go index 005bee79aa9b..f4e050b2a54a 100644 --- a/internal/service/dynamodb/table_item.go +++ b/internal/service/dynamodb/table_item.go @@ -73,8 +73,9 @@ func resourceTableItemCreate(d *schema.ResourceData, meta interface{}) error { _, err = conn.PutItem(&dynamodb.PutItemInput{ Item: attributes, // Explode if item exists. We didn't create it. - ConditionExpression: aws.String(fmt.Sprintf("attribute_not_exists(%s)", hashKey)), - TableName: aws.String(tableName), + ConditionExpression: aws.String("attribute_not_exists(#hk)"), + ExpressionAttributeNames: aws.StringMap(map[string]string{"#hk": hashKey}), + TableName: aws.String(tableName), }) if err != nil { return err From 84ec27c86ece23c0dede977af368e53af3c86e32 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 27 Oct 2022 15:22:17 -0400 Subject: [PATCH 4/6] Add 'TestAccDynamoDBTableItem_withDuplicateItemsSameRangeKey' and 'TestAccDynamoDBTableItem_withDuplicateItemsDifferentRangeKey'. --- internal/service/dynamodb/table_item_test.go | 77 ++++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/internal/service/dynamodb/table_item_test.go b/internal/service/dynamodb/table_item_test.go index 836595a94360..aeb946c7d44b 100644 --- a/internal/service/dynamodb/table_item_test.go +++ b/internal/service/dynamodb/table_item_test.go @@ -2,6 +2,7 @@ package dynamodb_test import ( "fmt" + "regexp" "testing" "github.com/aws/aws-sdk-go/aws" @@ -135,6 +136,82 @@ func TestAccDynamoDBTableItem_withMultipleItems(t *testing.T) { }) } +func TestAccDynamoDBTableItem_withDuplicateItemsSameRangeKey(t *testing.T) { + tableName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + hashKey := "hashKey" + rangeKey := "rangeKey" + firstItem := `{ + "hashKey": {"S": "something"}, + "rangeKey": {"S": "first"}, + "one": {"N": "11111"}, + "two": {"N": "22222"}, + "three": {"N": "33333"} +}` + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, dynamodb.EndpointsID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckTableItemDestroy, + Steps: []resource.TestStep{ + { + Config: testAccTableItemConfig_multiple(tableName, hashKey, rangeKey, firstItem, firstItem), + ExpectError: regexp.MustCompile(`ConditionalCheckFailedException: The conditional request failed`), + }, + }, + }) +} + +func TestAccDynamoDBTableItem_withDuplicateItemsDifferentRangeKey(t *testing.T) { + var conf1 dynamodb.GetItemOutput + var conf2 dynamodb.GetItemOutput + + tableName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + hashKey := "hashKey" + rangeKey := "rangeKey" + firstItem := `{ + "hashKey": {"S": "something"}, + "rangeKey": {"S": "first"}, + "one": {"N": "11111"}, + "two": {"N": "22222"}, + "three": {"N": "33333"} +}` + secondItem := `{ + "hashKey": {"S": "something"}, + "rangeKey": {"S": "second"}, + "one": {"N": "11111"}, + "two": {"N": "22222"}, + "three": {"N": "33333"} +}` + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, dynamodb.EndpointsID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckTableItemDestroy, + Steps: []resource.TestStep{ + { + Config: testAccTableItemConfig_multiple(tableName, hashKey, rangeKey, firstItem, secondItem), + Check: resource.ComposeTestCheckFunc( + testAccCheckTableItemExists("aws_dynamodb_table_item.test1", &conf1), + testAccCheckTableItemExists("aws_dynamodb_table_item.test2", &conf2), + testAccCheckTableItemCount(tableName, 2), + + resource.TestCheckResourceAttr("aws_dynamodb_table_item.test1", "hash_key", hashKey), + resource.TestCheckResourceAttr("aws_dynamodb_table_item.test1", "range_key", rangeKey), + resource.TestCheckResourceAttr("aws_dynamodb_table_item.test1", "table_name", tableName), + resource.TestCheckResourceAttr("aws_dynamodb_table_item.test1", "item", firstItem+"\n"), + + resource.TestCheckResourceAttr("aws_dynamodb_table_item.test2", "hash_key", hashKey), + resource.TestCheckResourceAttr("aws_dynamodb_table_item.test2", "range_key", rangeKey), + resource.TestCheckResourceAttr("aws_dynamodb_table_item.test2", "table_name", tableName), + resource.TestCheckResourceAttr("aws_dynamodb_table_item.test2", "item", secondItem+"\n"), + ), + }, + }, + }) +} + func TestAccDynamoDBTableItem_wonkyItems(t *testing.T) { var conf1 dynamodb.GetItemOutput From 68fafb9d37f72c9b257deeccd8900a7134be8430 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 27 Oct 2022 15:25:05 -0400 Subject: [PATCH 5/6] Add CHANGELOG entry. --- .changelog/27517.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/27517.txt diff --git a/.changelog/27517.txt b/.changelog/27517.txt new file mode 100644 index 000000000000..05a22ae67246 --- /dev/null +++ b/.changelog/27517.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +resource/aws_dynamodb_table_item: Allow the creation of items with the same hash key but different rage keys +``` \ No newline at end of file From 26b21883f17f555bf41365da060c14921b21cbc6 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 27 Oct 2022 15:53:10 -0400 Subject: [PATCH 6/6] Update 27517.txt --- .changelog/27517.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.changelog/27517.txt b/.changelog/27517.txt index 05a22ae67246..690a3701ec5c 100644 --- a/.changelog/27517.txt +++ b/.changelog/27517.txt @@ -1,3 +1,3 @@ ```release-note:enhancement -resource/aws_dynamodb_table_item: Allow the creation of items with the same hash key but different rage keys -``` \ No newline at end of file +resource/aws_dynamodb_table_item: Allow the creation of items with the same hash key but different range keys +```