dynamodb: fix deleting last set element (w/attr name) (#3708)
* dynamodb: deleting last set element * add user-facing test
This commit is contained in:
parent
e61d794cbc
commit
0912abe5f6
@ -165,8 +165,18 @@ class DeleteExecutor(NodeExecutor):
|
||||
# the last item in the set, we have to remove the attribute.
|
||||
if not string_set_list:
|
||||
element = self.get_element_to_action()
|
||||
if isinstance(element, ExpressionAttributeName):
|
||||
attribute_name = self.expression_attribute_names[
|
||||
element.get_attribute_name_placeholder()
|
||||
]
|
||||
elif isinstance(element, ExpressionAttribute):
|
||||
attribute_name = element.get_attribute_name()
|
||||
else:
|
||||
raise NotImplementedError(
|
||||
"Moto does not support deleting {t} yet".format(t=type(element))
|
||||
)
|
||||
container = self.get_item_before_end_of_path(item)
|
||||
container.pop(element.get_attribute_name())
|
||||
del container[attribute_name]
|
||||
|
||||
|
||||
class RemoveExecutor(NodeExecutor):
|
||||
|
@ -5598,8 +5598,14 @@ def test_lsi_projection_type_keys_only():
|
||||
|
||||
|
||||
@mock_dynamodb2
|
||||
def test_set_attribute_is_dropped_if_empty_after_update_expression():
|
||||
@pytest.mark.parametrize(
|
||||
"attr_name",
|
||||
["orders", "#placeholder"],
|
||||
ids=["use attribute name", "use expression attribute name"],
|
||||
)
|
||||
def test_set_attribute_is_dropped_if_empty_after_update_expression(attr_name):
|
||||
table_name, item_key, set_item = "test-table", "test-id", "test-data"
|
||||
expression_attribute_names = {"#placeholder": "orders"}
|
||||
client = boto3.client("dynamodb", region_name="us-east-1")
|
||||
client.create_table(
|
||||
TableName=table_name,
|
||||
@ -5611,7 +5617,8 @@ def test_set_attribute_is_dropped_if_empty_after_update_expression():
|
||||
client.update_item(
|
||||
TableName=table_name,
|
||||
Key={"customer": {"S": item_key}},
|
||||
UpdateExpression="ADD orders :order",
|
||||
UpdateExpression="ADD {} :order".format(attr_name),
|
||||
ExpressionAttributeNames=expression_attribute_names,
|
||||
ExpressionAttributeValues={":order": {"SS": [set_item]}},
|
||||
)
|
||||
resp = client.scan(TableName=table_name, ProjectionExpression="customer, orders")
|
||||
@ -5622,7 +5629,8 @@ def test_set_attribute_is_dropped_if_empty_after_update_expression():
|
||||
client.update_item(
|
||||
TableName=table_name,
|
||||
Key={"customer": {"S": item_key}},
|
||||
UpdateExpression="DELETE orders :order",
|
||||
UpdateExpression="DELETE {} :order".format(attr_name),
|
||||
ExpressionAttributeNames=expression_attribute_names,
|
||||
ExpressionAttributeValues={":order": {"SS": [set_item]}},
|
||||
)
|
||||
resp = client.scan(TableName=table_name, ProjectionExpression="customer, orders")
|
||||
|
@ -282,24 +282,26 @@ def test_execution_of_remove_in_list(table):
|
||||
assert expected_item == item
|
||||
|
||||
|
||||
def test_execution_of_delete_element_from_set(table):
|
||||
update_expression = "delete s :value"
|
||||
@pytest.mark.parametrize("attr_name", ["s", "#placeholder"])
|
||||
def test_execution_of_delete_element_from_set(table, attr_name):
|
||||
expression_attribute_names = {"#placeholder": "s"}
|
||||
update_expression = "delete {} :value".format(attr_name)
|
||||
update_expression_ast = UpdateExpressionParser.make(update_expression)
|
||||
item = Item(
|
||||
hash_key=DynamoType({"S": "id"}),
|
||||
hash_key_type="TYPE",
|
||||
range_key=None,
|
||||
range_key_type=None,
|
||||
attrs={"id": {"S": "foo2"}, "s": {"SS": ["value1", "value2", "value3"]},},
|
||||
attrs={"id": {"S": "foo2"}, "s": {"SS": ["value1", "value2", "value3"]}},
|
||||
)
|
||||
validated_ast = UpdateExpressionValidator(
|
||||
update_expression_ast,
|
||||
expression_attribute_names=None,
|
||||
expression_attribute_names=expression_attribute_names,
|
||||
expression_attribute_values={":value": {"SS": ["value2", "value5"]}},
|
||||
item=item,
|
||||
table=table,
|
||||
).validate()
|
||||
UpdateExpressionExecutor(validated_ast, item, None).execute()
|
||||
UpdateExpressionExecutor(validated_ast, item, expression_attribute_names).execute()
|
||||
expected_item = Item(
|
||||
hash_key=DynamoType({"S": "id"}),
|
||||
hash_key_type="TYPE",
|
||||
@ -309,6 +311,26 @@ def test_execution_of_delete_element_from_set(table):
|
||||
)
|
||||
assert expected_item == item
|
||||
|
||||
# delete last elements
|
||||
update_expression = "delete {} :value".format(attr_name)
|
||||
update_expression_ast = UpdateExpressionParser.make(update_expression)
|
||||
validated_ast = UpdateExpressionValidator(
|
||||
update_expression_ast,
|
||||
expression_attribute_names=expression_attribute_names,
|
||||
expression_attribute_values={":value": {"SS": ["value1", "value3"]}},
|
||||
item=item,
|
||||
table=table,
|
||||
).validate()
|
||||
UpdateExpressionExecutor(validated_ast, item, expression_attribute_names).execute()
|
||||
expected_item = Item(
|
||||
hash_key=DynamoType({"S": "id"}),
|
||||
hash_key_type="TYPE",
|
||||
range_key=None,
|
||||
range_key_type=None,
|
||||
attrs={"id": {"S": "foo2"}},
|
||||
)
|
||||
assert expected_item == item
|
||||
|
||||
|
||||
def test_execution_of_add_number(table):
|
||||
update_expression = "add s :value"
|
||||
|
Loading…
Reference in New Issue
Block a user