Better DDB expressions support1: TokenizationDDB

Currently the mock for DynamoDB has adhoc code to implement
its updateExpression functionality.  This series will
transform the logic such that Update Expressions are processed
as follows:
 1) Expression gets parsed into a tokenlist (tokenized) -> This commit
 2) Tokenlist get transformed to expression tree (AST)
 3) The AST gets validated (full semantic correctness)
 4) AST gets processed to perform the update

This alows for a more realistic mocking. It will throw exceptions much
more aggressively avoiding situations where a test passes against the
mock but fails with an exception when running against AWS.

Introduction of step 3 also allows to have the update expression as an
atomic unit of work. So updates at the start of the expression cannot
be performed if there is an error further down the expression.

This specific commit will tokenize expressions but the tokenlist is not
yet used. It is purely to keep clear boundaries.  It does do a minor
refactoring of the exceptions to allow more re-use and to ease testing.

This series of changes is to aid providing a long-term solution for
https://github.com/spulec/moto/issues/2806.
This commit is contained in:
pvbouwel 2020-04-11 11:07:22 +01:00
commit 7ea419dd54
5 changed files with 527 additions and 14 deletions

View file

@ -9,7 +9,7 @@ import six
from moto.core.responses import BaseResponse
from moto.core.utils import camelcase_to_underscores, amzn_request_id
from .exceptions import InvalidIndexNameError, InvalidUpdateExpression, ItemSizeTooLarge
from .exceptions import InvalidIndexNameError, InvalidUpdateExpression, ItemSizeTooLarge, MockValidationException
from moto.dynamodb2.models import dynamodb_backends, dynamo_json_dump
@ -298,7 +298,7 @@ class DynamoHandler(BaseResponse):
)
except ItemSizeTooLarge:
er = "com.amazonaws.dynamodb.v20111205#ValidationException"
return self.error(er, ItemSizeTooLarge.message)
return self.error(er, ItemSizeTooLarge.item_size_too_large_msg)
except KeyError as ke:
er = "com.amazonaws.dynamodb.v20111205#ValidationException"
return self.error(er, ke.args[0])
@ -764,15 +764,9 @@ class DynamoHandler(BaseResponse):
expected,
condition_expression,
)
except InvalidUpdateExpression:
except MockValidationException as mve:
er = "com.amazonaws.dynamodb.v20111205#ValidationException"
return self.error(
er,
"The document path provided in the update expression is invalid for update",
)
except ItemSizeTooLarge:
er = "com.amazonaws.dynamodb.v20111205#ValidationException"
return self.error(er, ItemSizeTooLarge.message)
return self.error(er, mve.exception_msg)
except ValueError:
er = "com.amazonaws.dynamodb.v20111205#ConditionalCheckFailedException"
return self.error(