diff --git a/moto/dynamodb2/responses.py b/moto/dynamodb2/responses.py index 91d2f45ee..f48519681 100644 --- a/moto/dynamodb2/responses.py +++ b/moto/dynamodb2/responses.py @@ -1,6 +1,7 @@ from __future__ import unicode_literals import json import six +import re from moto.core.responses import BaseResponse from moto.core.utils import camelcase_to_underscores @@ -150,6 +151,26 @@ class DynamoHandler(BaseResponse): else: expected = None + # Attempt to parse simple ConditionExpressions into an Expected expression + if not expected: + condition_expression = self.body.get('ConditionExpression') + if condition_expression and 'OR' not in condition_expression: + cond_items = [c.strip() for c in condition_expression.split('AND')] + + if cond_items: + expected = {} + overwrite = False + exists_re = re.compile('^attribute_exists\((.*)\)$') + not_exists_re = re.compile('^attribute_not_exists\((.*)\)$') + + for cond in cond_items: + exists_m = exists_re.match(cond) + not_exists_m = not_exists_re.match(cond) + if exists_m: + expected[exists_m.group(1)] = {'Exists': True} + elif not_exists_m: + expected[not_exists_m.group(1)] = {'Exists': False} + try: result = dynamodb_backend2.put_item(name, item, expected, overwrite) except Exception: diff --git a/tests/test_dynamodb2/test_dynamodb_table_with_range_key.py b/tests/test_dynamodb2/test_dynamodb_table_with_range_key.py index 53295646a..476ae14f4 100644 --- a/tests/test_dynamodb2/test_dynamodb_table_with_range_key.py +++ b/tests/test_dynamodb2/test_dynamodb_table_with_range_key.py @@ -1016,6 +1016,72 @@ def test_boto3_conditions(): results['Count'].should.equal(1) +@mock_dynamodb2 +def test_boto3_put_item_with_conditions(): + import botocore + dynamodb = boto3.resource('dynamodb', region_name='us-east-1') + + # Create the DynamoDB table. + 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.put_item( + Item={ + 'forum_name': 'the-key-2', + 'subject': '1234', + }, + ConditionExpression='attribute_not_exists(forum_name) AND attribute_not_exists(subject)' + ) + + table.put_item.when.called_with( + Item={ + 'forum_name': 'the-key', + 'subject': '123' + }, + ConditionExpression='attribute_not_exists(forum_name) AND attribute_not_exists(subject)' + ).should.throw(botocore.exceptions.ClientError) + + table.put_item.when.called_with( + Item={ + 'forum_name': 'bogus-key', + 'subject': 'bogus', + 'test': '123' + }, + ConditionExpression='attribute_exists(forum_name) AND attribute_exists(subject)' + ).should.throw(botocore.exceptions.ClientError) + + def _create_table_with_range_key(): dynamodb = boto3.resource('dynamodb', region_name='us-east-1')