From 310ef4885a00b6df245445e6e0547d75941a6e44 Mon Sep 17 00:00:00 2001 From: jake-sigtech <81232270+jake-sigtech@users.noreply.github.com> Date: Fri, 18 Nov 2022 21:51:51 +0000 Subject: [PATCH] DynamoDB: fix: Add support for `ReturnValuesOnConditionCheckFailure=ALL_OLD` (#5676) --- moto/dynamodb/models/__init__.py | 11 ++++++ tests/test_dynamodb/test_dynamodb.py | 54 ++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+) diff --git a/moto/dynamodb/models/__init__.py b/moto/dynamodb/models/__init__.py index 7081dc2b6..90573a0fb 100644 --- a/moto/dynamodb/models/__init__.py +++ b/moto/dynamodb/models/__init__.py @@ -1701,6 +1701,17 @@ class DynamoDBBackend(BaseBackend): expression_attribute_values = item.get( "ExpressionAttributeValues", None ) + + return_values_on_condition_check_failure = item.get( + "ReturnValuesOnConditionCheckFailure", None + ) + current = self.get_item(table_name, attrs) + if ( + return_values_on_condition_check_failure == "ALL_OLD" + and current + ): + item["Item"] = current.to_json()["Attributes"] + self.put_item( table_name, attrs, diff --git a/tests/test_dynamodb/test_dynamodb.py b/tests/test_dynamodb/test_dynamodb.py index f25bba2b9..ce2229572 100644 --- a/tests/test_dynamodb/test_dynamodb.py +++ b/tests/test_dynamodb/test_dynamodb.py @@ -3896,6 +3896,60 @@ def test_transact_write_items_put_conditional_expressions(): items[0].should.equal({"id": {"S": "foo2"}}) +@mock_dynamodb +def test_transact_write_items_put_conditional_expressions_return_values_on_condition_check_failure_all_old(): + table_schema = { + "KeySchema": [{"AttributeName": "id", "KeyType": "HASH"}], + "AttributeDefinitions": [{"AttributeName": "id", "AttributeType": "S"}], + } + dynamodb = boto3.client("dynamodb", region_name="us-east-1") + dynamodb.create_table( + TableName="test-table", BillingMode="PAY_PER_REQUEST", **table_schema + ) + dynamodb.put_item(TableName="test-table", Item={"id": {"S": "foo2"}}) + # Put multiple items + with pytest.raises(ClientError) as ex: + dynamodb.transact_write_items( + TransactItems=[ + { + "Put": { + "Item": { + "id": {"S": "foo{}".format(str(i))}, + "foo": {"S": "bar"}, + }, + "TableName": "test-table", + "ConditionExpression": "#i <> :i", + "ExpressionAttributeNames": {"#i": "id"}, + "ReturnValuesOnConditionCheckFailure": "ALL_OLD", + "ExpressionAttributeValues": { + ":i": { + "S": "foo2" + } # This item already exist, so the ConditionExpression should fail + }, + } + } + for i in range(0, 5) + ] + ) + # Assert the exception is correct + ex.value.response["Error"]["Code"].should.equal("TransactionCanceledException") + reasons = ex.value.response["CancellationReasons"] + reasons.should.have.length_of(5) + reasons.should.contain( + { + "Code": "ConditionalCheckFailed", + "Message": "The conditional request failed", + "Item": {"id": {"S": "foo2"}}, + } + ) + reasons.should.contain({"Code": "None"}) + ex.value.response["ResponseMetadata"]["HTTPStatusCode"].should.equal(400) + # Assert all are present + items = dynamodb.scan(TableName="test-table")["Items"] + items.should.have.length_of(1) + items[0].should.equal({"id": {"S": "foo2"}}) + + @mock_dynamodb def test_transact_write_items_conditioncheck_passes(): table_schema = {