Merge pull request #2986 from bblommers/dynamodb_transact_errors
#2985 - DynamoDB - TransactWriteItems - Fix error-type returned
This commit is contained in:
commit
9712acc75f
4 changed files with 90 additions and 41 deletions
|
|
@ -149,3 +149,18 @@ class IncorrectDataType(MockValidationException):
|
|||
|
||||
def __init__(self):
|
||||
super(IncorrectDataType, self).__init__(self.inc_data_type_msg)
|
||||
|
||||
|
||||
class ConditionalCheckFailed(ValueError):
|
||||
msg = "The conditional request failed"
|
||||
|
||||
def __init__(self):
|
||||
super(ConditionalCheckFailed, self).__init__(self.msg)
|
||||
|
||||
|
||||
class TransactionCanceledException(ValueError):
|
||||
cancel_reason_msg = "Transaction cancelled, please refer cancellation reasons for specific reasons [{}]"
|
||||
|
||||
def __init__(self, errors):
|
||||
msg = self.cancel_reason_msg.format(", ".join([str(err) for err in errors]))
|
||||
super(TransactionCanceledException, self).__init__(msg)
|
||||
|
|
|
|||
|
|
@ -18,6 +18,8 @@ from moto.dynamodb2.exceptions import (
|
|||
InvalidIndexNameError,
|
||||
ItemSizeTooLarge,
|
||||
ItemSizeToUpdateTooLarge,
|
||||
ConditionalCheckFailed,
|
||||
TransactionCanceledException,
|
||||
)
|
||||
from moto.dynamodb2.models.utilities import bytesize
|
||||
from moto.dynamodb2.models.dynamo_type import DynamoType
|
||||
|
|
@ -459,14 +461,14 @@ class Table(BaseModel):
|
|||
|
||||
if not overwrite:
|
||||
if not get_expected(expected).expr(current):
|
||||
raise ValueError("The conditional request failed")
|
||||
raise ConditionalCheckFailed
|
||||
condition_op = get_filter_expression(
|
||||
condition_expression,
|
||||
expression_attribute_names,
|
||||
expression_attribute_values,
|
||||
)
|
||||
if not condition_op.expr(current):
|
||||
raise ValueError("The conditional request failed")
|
||||
raise ConditionalCheckFailed
|
||||
|
||||
if range_value:
|
||||
self.items[hash_value][range_value] = item
|
||||
|
|
@ -1076,14 +1078,14 @@ class DynamoDBBackend(BaseBackend):
|
|||
expected = {}
|
||||
|
||||
if not get_expected(expected).expr(item):
|
||||
raise ValueError("The conditional request failed")
|
||||
raise ConditionalCheckFailed
|
||||
condition_op = get_filter_expression(
|
||||
condition_expression,
|
||||
expression_attribute_names,
|
||||
expression_attribute_values,
|
||||
)
|
||||
if not condition_op.expr(item):
|
||||
raise ValueError("The conditional request failed")
|
||||
raise ConditionalCheckFailed
|
||||
|
||||
# Update does not fail on new items, so create one
|
||||
if item is None:
|
||||
|
|
@ -1136,7 +1138,7 @@ class DynamoDBBackend(BaseBackend):
|
|||
expression_attribute_values,
|
||||
)
|
||||
if not condition_op.expr(item):
|
||||
raise ValueError("The conditional request failed")
|
||||
raise ConditionalCheckFailed
|
||||
|
||||
return table.delete_item(hash_value, range_value)
|
||||
|
||||
|
|
@ -1167,8 +1169,9 @@ class DynamoDBBackend(BaseBackend):
|
|||
def transact_write_items(self, transact_items):
|
||||
# Create a backup in case any of the transactions fail
|
||||
original_table_state = copy.deepcopy(self.tables)
|
||||
try:
|
||||
for item in transact_items:
|
||||
errors = []
|
||||
for item in transact_items:
|
||||
try:
|
||||
if "ConditionCheck" in item:
|
||||
item = item["ConditionCheck"]
|
||||
key = item["Key"]
|
||||
|
|
@ -1188,7 +1191,7 @@ class DynamoDBBackend(BaseBackend):
|
|||
expression_attribute_values,
|
||||
)
|
||||
if not condition_op.expr(current):
|
||||
raise ValueError("The conditional request failed")
|
||||
raise ConditionalCheckFailed()
|
||||
elif "Put" in item:
|
||||
item = item["Put"]
|
||||
attrs = item["Item"]
|
||||
|
|
@ -1247,10 +1250,13 @@ class DynamoDBBackend(BaseBackend):
|
|||
)
|
||||
else:
|
||||
raise ValueError
|
||||
except: # noqa: E722 Do not use bare except
|
||||
# Rollback to the original state, and reraise the error
|
||||
errors.append(None)
|
||||
except Exception as e: # noqa: E722 Do not use bare except
|
||||
errors.append(type(e).__name__)
|
||||
if any(errors):
|
||||
# Rollback to the original state, and reraise the errors
|
||||
self.tables = original_table_state
|
||||
raise
|
||||
raise TransactionCanceledException(errors)
|
||||
|
||||
def describe_continuous_backups(self, table_name):
|
||||
table = self.get_table(table_name)
|
||||
|
|
|
|||
|
|
@ -9,7 +9,12 @@ import six
|
|||
|
||||
from moto.core.responses import BaseResponse
|
||||
from moto.core.utils import camelcase_to_underscores, amzn_request_id
|
||||
from .exceptions import InvalidIndexNameError, ItemSizeTooLarge, MockValidationException
|
||||
from .exceptions import (
|
||||
InvalidIndexNameError,
|
||||
ItemSizeTooLarge,
|
||||
MockValidationException,
|
||||
TransactionCanceledException,
|
||||
)
|
||||
from moto.dynamodb2.models import dynamodb_backends, dynamo_json_dump
|
||||
|
||||
|
||||
|
|
@ -929,11 +934,9 @@ class DynamoHandler(BaseResponse):
|
|||
transact_items = self.body["TransactItems"]
|
||||
try:
|
||||
self.dynamodb_backend.transact_write_items(transact_items)
|
||||
except ValueError:
|
||||
er = "com.amazonaws.dynamodb.v20111205#ConditionalCheckFailedException"
|
||||
return self.error(
|
||||
er, "A condition specified in the operation could not be evaluated."
|
||||
)
|
||||
except TransactionCanceledException as e:
|
||||
er = "com.amazonaws.dynamodb.v20111205#TransactionCanceledException"
|
||||
return self.error(er, str(e))
|
||||
response = {"ConsumedCapacity": [], "ItemCollectionMetrics": {}}
|
||||
return dynamo_json_dump(response)
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue