Merge pull request #1364 from terrycain/bug_1358

Adds if_not_exists function to DynamoDB Update Expression
This commit is contained in:
Steve Pulec 2018-03-06 22:46:11 -05:00 committed by GitHub
commit 1a299ffbfc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 86 additions and 2 deletions

View File

@ -135,7 +135,9 @@ class Item(BaseModel):
assert len(parts) % 2 == 0, "Mismatched operators and values in update expression: '{}'".format(update_expression)
for action, valstr in zip(parts[:-1:2], parts[1::2]):
action = action.upper()
values = valstr.split(',')
# "Should" retain arguments in side (...)
values = re.split(r',(?![^(]*\))', valstr)
for value in values:
# A Real value
value = value.lstrip(":").rstrip(",").strip()
@ -145,9 +147,23 @@ class Item(BaseModel):
if action == "REMOVE":
self.attrs.pop(value, None)
elif action == 'SET':
key, value = value.split("=")
key, value = value.split("=", 1)
key = key.strip()
value = value.strip()
# If not exists, changes value to a default if needed, else its the same as it was
if value.startswith('if_not_exists'):
# Function signature
match = re.match(r'.*if_not_exists\((?P<path>.+),\s*(?P<default>.+)\).*', value)
if not match:
raise TypeError
path, value = match.groups()
# If it already exists, get its value so we dont overwrite it
if path in self.attrs:
value = self.attrs[path].cast_value
if value in expression_attribute_values:
value = DynamoType(expression_attribute_values[value])
else:

View File

@ -1067,3 +1067,71 @@ def test_update_item_on_map():
resp = table.scan()
resp['Items'][0]['body'].should.equal({'nested': {'data': 'new_value'}})
# https://github.com/spulec/moto/issues/1358
@mock_dynamodb2
def test_update_if_not_exists():
dynamodb = boto3.resource('dynamodb', region_name='us-east-1')
# Create the DynamoDB table.
dynamodb.create_table(
TableName='users',
KeySchema=[
{
'AttributeName': 'forum_name',
'KeyType': 'HASH'
},
{
'AttributeName': 'subject',
'KeyType': 'RANGE'
},
],
AttributeDefinitions=[
{
'AttributeName': 'forum_name',
'AttributeType': 'S'
},
{
'AttributeName': 'subject',
'AttributeType': 'S'
},
],
ProvisionedThroughput={
'ReadCapacityUnits': 5,
'WriteCapacityUnits': 5
}
)
table = dynamodb.Table('users')
table.put_item(Item={
'forum_name': 'the-key',
'subject': '123'
})
table.update_item(Key={
'forum_name': 'the-key',
'subject': '123'
},
UpdateExpression='SET created_at = if_not_exists(created_at, :created_at)',
ExpressionAttributeValues={
':created_at': 123
}
)
resp = table.scan()
assert resp['Items'][0]['created_at'] == 123
table.update_item(Key={
'forum_name': 'the-key',
'subject': '123'
},
UpdateExpression='SET created_at = if_not_exists(created_at, :created_at)',
ExpressionAttributeValues={
':created_at': 456
}
)
resp = table.scan()
# Still the original value
assert resp['Items'][0]['created_at'] == 123