1from moto.dynamodb2.limits import HASH_KEY_MAX_LENGTH, RANGE_KEY_MAX_LENGTH
2
3
4class InvalidIndexNameError(ValueError):
5    pass
6
7
8class MockValidationException(ValueError):
9    def __init__(self, message):
10        self.exception_msg = message
11
12
13class InvalidUpdateExpressionInvalidDocumentPath(MockValidationException):
14    invalid_update_expression_msg = (
15        "The document path provided in the update expression is invalid for update"
16    )
17
18    def __init__(self):
19        super(InvalidUpdateExpressionInvalidDocumentPath, self).__init__(
20            self.invalid_update_expression_msg
21        )
22
23
24class InvalidUpdateExpression(MockValidationException):
25    invalid_update_expr_msg = "Invalid UpdateExpression: {update_expression_error}"
26
27    def __init__(self, update_expression_error):
28        self.update_expression_error = update_expression_error
29        super(InvalidUpdateExpression, self).__init__(
30            self.invalid_update_expr_msg.format(
31                update_expression_error=update_expression_error
32            )
33        )
34
35
36class AttributeDoesNotExist(MockValidationException):
37    attr_does_not_exist_msg = (
38        "The provided expression refers to an attribute that does not exist in the item"
39    )
40
41    def __init__(self):
42        super(AttributeDoesNotExist, self).__init__(self.attr_does_not_exist_msg)
43
44
45class ProvidedKeyDoesNotExist(MockValidationException):
46    provided_key_does_not_exist_msg = (
47        "The provided key element does not match the schema"
48    )
49
50    def __init__(self):
51        super(ProvidedKeyDoesNotExist, self).__init__(
52            self.provided_key_does_not_exist_msg
53        )
54
55
56class ExpressionAttributeNameNotDefined(InvalidUpdateExpression):
57    name_not_defined_msg = "An expression attribute name used in the document path is not defined; attribute name: {n}"
58
59    def __init__(self, attribute_name):
60        self.not_defined_attribute_name = attribute_name
61        super(ExpressionAttributeNameNotDefined, self).__init__(
62            self.name_not_defined_msg.format(n=attribute_name)
63        )
64
65
66class AttributeIsReservedKeyword(InvalidUpdateExpression):
67    attribute_is_keyword_msg = (
68        "Attribute name is a reserved keyword; reserved keyword: {keyword}"
69    )
70
71    def __init__(self, keyword):
72        self.keyword = keyword
73        super(AttributeIsReservedKeyword, self).__init__(
74            self.attribute_is_keyword_msg.format(keyword=keyword)
75        )
76
77
78class ExpressionAttributeValueNotDefined(InvalidUpdateExpression):
79    attr_value_not_defined_msg = "An expression attribute value used in expression is not defined; attribute value: {attribute_value}"
80
81    def __init__(self, attribute_value):
82        self.attribute_value = attribute_value
83        super(ExpressionAttributeValueNotDefined, self).__init__(
84            self.attr_value_not_defined_msg.format(attribute_value=attribute_value)
85        )
86
87
88class UpdateExprSyntaxError(InvalidUpdateExpression):
89    update_expr_syntax_error_msg = "Syntax error; {error_detail}"
90
91    def __init__(self, error_detail):
92        self.error_detail = error_detail
93        super(UpdateExprSyntaxError, self).__init__(
94            self.update_expr_syntax_error_msg.format(error_detail=error_detail)
95        )
96
97
98class InvalidTokenException(UpdateExprSyntaxError):
99    token_detail_msg = 'token: "{token}", near: "{near}"'
100
101    def __init__(self, token, near):
102        self.token = token
103        self.near = near
104        super(InvalidTokenException, self).__init__(
105            self.token_detail_msg.format(token=token, near=near)
106        )
107
108
109class InvalidExpressionAttributeNameKey(MockValidationException):
110    invalid_expr_attr_name_msg = (
111        'ExpressionAttributeNames contains invalid key: Syntax error; key: "{key}"'
112    )
113
114    def __init__(self, key):
115        self.key = key
116        super(InvalidExpressionAttributeNameKey, self).__init__(
117            self.invalid_expr_attr_name_msg.format(key=key)
118        )
119
120
121class ItemSizeTooLarge(MockValidationException):
122    item_size_too_large_msg = "Item size has exceeded the maximum allowed size"
123
124    def __init__(self):
125        super(ItemSizeTooLarge, self).__init__(self.item_size_too_large_msg)
126
127
128class ItemSizeToUpdateTooLarge(MockValidationException):
129    item_size_to_update_too_large_msg = (
130        "Item size to update has exceeded the maximum allowed size"
131    )
132
133    def __init__(self):
134        super(ItemSizeToUpdateTooLarge, self).__init__(
135            self.item_size_to_update_too_large_msg
136        )
137
138
139class HashKeyTooLong(MockValidationException):
140    # deliberately no space between of and {lim}
141    key_too_large_msg = "One or more parameter values were invalid: Size of hashkey has exceeded the maximum size limit of{lim} bytes".format(
142        lim=HASH_KEY_MAX_LENGTH
143    )
144
145    def __init__(self):
146        super(HashKeyTooLong, self).__init__(self.key_too_large_msg)
147
148
149class RangeKeyTooLong(MockValidationException):
150    key_too_large_msg = "One or more parameter values were invalid: Aggregated size of all range keys has exceeded the size limit of {lim} bytes".format(
151        lim=RANGE_KEY_MAX_LENGTH
152    )
153
154    def __init__(self):
155        super(RangeKeyTooLong, self).__init__(self.key_too_large_msg)
156
157
158class IncorrectOperandType(InvalidUpdateExpression):
159    inv_operand_msg = "Incorrect operand type for operator or function; operator or function: {f}, operand type: {t}"
160
161    def __init__(self, operator_or_function, operand_type):
162        self.operator_or_function = operator_or_function
163        self.operand_type = operand_type
164        super(IncorrectOperandType, self).__init__(
165            self.inv_operand_msg.format(f=operator_or_function, t=operand_type)
166        )
167
168
169class IncorrectDataType(MockValidationException):
170    inc_data_type_msg = "An operand in the update expression has an incorrect data type"
171
172    def __init__(self):
173        super(IncorrectDataType, self).__init__(self.inc_data_type_msg)
174
175
176class ConditionalCheckFailed(ValueError):
177    msg = "The conditional request failed"
178
179    def __init__(self):
180        super(ConditionalCheckFailed, self).__init__(self.msg)
181
182
183class TransactionCanceledException(ValueError):
184    cancel_reason_msg = "Transaction cancelled, please refer cancellation reasons for specific reasons [{}]"
185
186    def __init__(self, errors):
187        msg = self.cancel_reason_msg.format(", ".join([str(err) for err in errors]))
188        super(TransactionCanceledException, self).__init__(msg)
189
190
191class EmptyKeyAttributeException(MockValidationException):
192    empty_str_msg = "One or more parameter values were invalid: An AttributeValue may not contain an empty string"
193    # AWS has a different message for empty index keys
194    empty_index_msg = "One or more parameter values are not valid. The update expression attempted to update a secondary index key to a value that is not supported. The AttributeValue for a key attribute cannot contain an empty string value."
195
196    def __init__(self, key_in_index=False):
197        super(EmptyKeyAttributeException, self).__init__(
198            self.empty_index_msg if key_in_index else self.empty_str_msg
199        )
200
201
202class UpdateHashRangeKeyException(MockValidationException):
203    msg = "One or more parameter values were invalid: Cannot update attribute {}. This attribute is part of the key"
204
205    def __init__(self, key_name):
206        super(UpdateHashRangeKeyException, self).__init__(self.msg.format(key_name))
207
208
209class InvalidAttributeTypeError(MockValidationException):
210    msg = "One or more parameter values were invalid: Type mismatch for key {} expected: {} actual: {}"
211
212    def __init__(self, name, expected_type, actual_type):
213        super().__init__(self.msg.format(name, expected_type, actual_type))
214
215
216class TooManyAddClauses(InvalidUpdateExpression):
217    msg = 'The "ADD" section can only be used once in an update expression;'
218
219    def __init__(self):
220        super(TooManyAddClauses, self).__init__(self.msg)
221