From 96c2506fd416db910002178cdcad00e113ef2d93 Mon Sep 17 00:00:00 2001 From: Ber Zoidberg Date: Tue, 11 Jun 2019 22:38:15 -0700 Subject: [PATCH] Fix DynamoDB UpdateExpression support for REMOVE on nested maps --- moto/dynamodb2/models.py | 23 +++++++++++++++ .../test_dynamodb_table_without_range_key.py | 29 +++++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/moto/dynamodb2/models.py b/moto/dynamodb2/models.py index 6bcde41b2..2f6575354 100644 --- a/moto/dynamodb2/models.py +++ b/moto/dynamodb2/models.py @@ -149,6 +149,29 @@ class Item(BaseModel): value = re.sub(r'{0}\b'.format(k), v, value) if action == "REMOVE": + key = value + if '.' not in key: + self.attrs.pop(value, None) + else: + # Handle nested dict updates + key_parts = key.split('.') + attr = key_parts.pop(0) + if attr not in self.attrs: + raise ValueError + + last_val = self.attrs[attr].value + for key_part in key_parts[:-1]: + # Hack but it'll do, traverses into a dict + last_val_type = list(last_val.keys()) + if last_val_type and last_val_type[0] == 'M': + last_val = last_val['M'] + + if key_part not in last_val: + last_val[key_part] = {'M': {}} + + last_val = last_val[key_part] + + last_val.pop(key_parts[-1], None) self.attrs.pop(value, None) elif action == 'SET': key, value = value.split("=", 1) diff --git a/tests/test_dynamodb2/test_dynamodb_table_without_range_key.py b/tests/test_dynamodb2/test_dynamodb_table_without_range_key.py index 1880c7cab..d882b14a6 100644 --- a/tests/test_dynamodb2/test_dynamodb_table_without_range_key.py +++ b/tests/test_dynamodb2/test_dynamodb_table_without_range_key.py @@ -450,6 +450,35 @@ def test_update_item_remove(): }) +@mock_dynamodb2_deprecated +def test_update_item_nested_remove(): + conn = boto.dynamodb2.connect_to_region("us-east-1") + table = Table.create('messages', schema=[ + HashKey('username') + ]) + + data = { + 'username': "steve", + 'Meta': { + 'FullName': 'Steve Urkel' + } + } + table.put_item(data=data) + key_map = { + 'username': {"S": "steve"} + } + + # Then remove the SentBy field + conn.update_item("messages", key_map, + update_expression="REMOVE Meta.FullName") + + returned_item = table.get_item(username="steve") + dict(returned_item).should.equal({ + 'username': "steve", + 'Meta': {} + }) + + @mock_dynamodb2_deprecated def test_update_item_set(): conn = boto.dynamodb2.connect_to_region("us-east-1")