Merge pull request #1627 from MauPalantir/support-nested

Support assignment of nested attributes if only the topmost value exists
This commit is contained in:
Steve Pulec 2018-05-29 22:28:27 -04:00 committed by GitHub
commit e1c445ad3c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 33 additions and 7 deletions

View File

@ -176,16 +176,17 @@ class Item(BaseModel):
key_parts = key.split('.') key_parts = key.split('.')
attr = key_parts.pop(0) attr = key_parts.pop(0)
if attr not in self.attrs: if attr not in self.attrs:
raise ValueError() raise ValueError
last_val = self.attrs[attr].value last_val = self.attrs[attr].value
for key_part in key_parts: for key_part in key_parts:
# Hack but it'll do, traverses into a dict # Hack but it'll do, traverses into a dict
if list(last_val.keys())[0] == 'M': last_val_type = list(last_val.keys())
last_val = last_val['M'] if last_val_type and last_val_type[0] == 'M':
last_val = last_val['M']
if key_part not in last_val: if key_part not in last_val:
raise ValueError() last_val[key_part] = {'M': {}}
last_val = last_val[key_part] last_val = last_val[key_part]

View File

@ -6,6 +6,7 @@ import boto3
from boto3.dynamodb.conditions import Attr from boto3.dynamodb.conditions import Attr
import sure # noqa import sure # noqa
import requests import requests
from pytest import raises
from moto import mock_dynamodb2, mock_dynamodb2_deprecated from moto import mock_dynamodb2, mock_dynamodb2_deprecated
from moto.dynamodb2 import dynamodb_backend2 from moto.dynamodb2 import dynamodb_backend2
from boto.exception import JSONResponseError from boto.exception import JSONResponseError
@ -1052,6 +1053,7 @@ def test_query_missing_expr_names():
@mock_dynamodb2 @mock_dynamodb2
def test_update_item_on_map(): def test_update_item_on_map():
dynamodb = boto3.resource('dynamodb', region_name='us-east-1') dynamodb = boto3.resource('dynamodb', region_name='us-east-1')
client = boto3.client('dynamodb', region_name='us-east-1')
# Create the DynamoDB table. # Create the DynamoDB table.
dynamodb.create_table( dynamodb.create_table(
@ -1092,21 +1094,44 @@ def test_update_item_on_map():
resp = table.scan() resp = table.scan()
resp['Items'][0]['body'].should.equal({'nested': {'data': 'test'}}) resp['Items'][0]['body'].should.equal({'nested': {'data': 'test'}})
# Nonexistent nested attributes are supported for existing top-level attributes.
table.update_item(Key={ table.update_item(Key={
'forum_name': 'the-key', 'forum_name': 'the-key',
'subject': '123' 'subject': '123'
}, },
UpdateExpression='SET body.#nested.#data = :tb', UpdateExpression='SET body.#nested.#data = :tb, body.nested.#nonexistentnested.#data = :tb2',
ExpressionAttributeNames={ ExpressionAttributeNames={
'#nested': 'nested', '#nested': 'nested',
'#nonexistentnested': 'nonexistentnested',
'#data': 'data' '#data': 'data'
}, },
ExpressionAttributeValues={ ExpressionAttributeValues={
':tb': 'new_value' ':tb': 'new_value',
':tb2': 'other_value'
}) })
resp = table.scan() resp = table.scan()
resp['Items'][0]['body'].should.equal({'nested': {'data': 'new_value'}}) resp['Items'][0]['body'].should.equal({
'nested': {
'data': 'new_value',
'nonexistentnested': {'data': 'other_value'}
}
})
# Test nested value for a nonexistent attribute.
with raises(client.exceptions.ConditionalCheckFailedException):
table.update_item(Key={
'forum_name': 'the-key',
'subject': '123'
},
UpdateExpression='SET nonexistent.#nested = :tb',
ExpressionAttributeNames={
'#nested': 'nested'
},
ExpressionAttributeValues={
':tb': 'new_value'
})
# https://github.com/spulec/moto/issues/1358 # https://github.com/spulec/moto/issues/1358