Tweak comparison to treat NULL/NOT_NULL correctly. (#1709)
The AWS documentation says that a ComparisonOperator of NULL means the attribute should not exist, whereas NOT_NULL means that the attribute should exist. It explicitly says that an attribute with a value of NULL is considered to exist, which contradicts our previous implementation. This affects both put_item and get_item in dynamodb2. https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_Condition.html
This commit is contained in:
parent
7d201c48b5
commit
802402bdba
4 changed files with 107 additions and 12 deletions
|
|
@ -29,8 +29,10 @@ COMPARISON_FUNCS = {
|
|||
'GT': GT_FUNCTION,
|
||||
'>': GT_FUNCTION,
|
||||
|
||||
'NULL': lambda item_value: item_value is None,
|
||||
'NOT_NULL': lambda item_value: item_value is not None,
|
||||
# NULL means the value should not exist at all
|
||||
'NULL': lambda item_value: False,
|
||||
# NOT_NULL means the value merely has to exist, and values of None are valid
|
||||
'NOT_NULL': lambda item_value: True,
|
||||
'CONTAINS': lambda item_value, test_value: test_value in item_value,
|
||||
'NOT_CONTAINS': lambda item_value, test_value: test_value not in item_value,
|
||||
'BEGINS_WITH': lambda item_value, test_value: item_value.startswith(test_value),
|
||||
|
|
|
|||
|
|
@ -409,7 +409,8 @@ class Table(BaseModel):
|
|||
current_attr = current
|
||||
|
||||
for key, val in expected.items():
|
||||
if 'Exists' in val and val['Exists'] is False:
|
||||
if 'Exists' in val and val['Exists'] is False \
|
||||
or 'ComparisonOperator' in val and val['ComparisonOperator'] == 'NULL':
|
||||
if key in current_attr:
|
||||
raise ValueError("The conditional request failed")
|
||||
elif key not in current_attr:
|
||||
|
|
@ -419,8 +420,10 @@ class Table(BaseModel):
|
|||
elif 'ComparisonOperator' in val:
|
||||
comparison_func = get_comparison_func(
|
||||
val['ComparisonOperator'])
|
||||
dynamo_types = [DynamoType(ele) for ele in val[
|
||||
"AttributeValueList"]]
|
||||
dynamo_types = [
|
||||
DynamoType(ele) for ele in
|
||||
val.get("AttributeValueList", [])
|
||||
]
|
||||
for t in dynamo_types:
|
||||
if not comparison_func(current_attr[key].value, t.value):
|
||||
raise ValueError('The conditional request failed')
|
||||
|
|
@ -827,7 +830,8 @@ class DynamoDBBackend(BaseBackend):
|
|||
expected = {}
|
||||
|
||||
for key, val in expected.items():
|
||||
if 'Exists' in val and val['Exists'] is False:
|
||||
if 'Exists' in val and val['Exists'] is False \
|
||||
or 'ComparisonOperator' in val and val['ComparisonOperator'] == 'NULL':
|
||||
if key in item_attr:
|
||||
raise ValueError("The conditional request failed")
|
||||
elif key not in item_attr:
|
||||
|
|
@ -837,8 +841,10 @@ class DynamoDBBackend(BaseBackend):
|
|||
elif 'ComparisonOperator' in val:
|
||||
comparison_func = get_comparison_func(
|
||||
val['ComparisonOperator'])
|
||||
dynamo_types = [DynamoType(ele) for ele in val[
|
||||
"AttributeValueList"]]
|
||||
dynamo_types = [
|
||||
DynamoType(ele) for ele in
|
||||
val.get("AttributeValueList", [])
|
||||
]
|
||||
for t in dynamo_types:
|
||||
if not comparison_func(item_attr[key].value, t.value):
|
||||
raise ValueError('The conditional request failed')
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue