Skip to content

Commit

Permalink
Prevent overlapping expr name prefixes from corrupting projection expr
Browse files Browse the repository at this point in the history
h/t @beheh. This patch handles the case when ProjectionExpression looks
like "#1, ..., #10" - the previous code used `replace`, which would make
the resulting projection into "foo, ..., foo0".
  • Loading branch information
joolean committed Sep 9, 2019
1 parent 3a5d857 commit f4df7a4
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 1 deletion.
11 changes: 10 additions & 1 deletion moto/dynamodb2/responses.py
Original file line number Diff line number Diff line change
Expand Up @@ -356,9 +356,18 @@ def query(self):

if projection_expression and expression_attribute_names:
expressions = [x.strip() for x in projection_expression.split(',')]
projection_expression = None
for expression in expressions:
if projection_expression is not None:
projection_expression = projection_expression + ", "
else:
projection_expression = ""

if expression in expression_attribute_names:
projection_expression = projection_expression.replace(expression, expression_attribute_names[expression])
projection_expression = projection_expression + \
expression_attribute_names[expression]
else:
projection_expression = projection_expression + expression

filter_kwargs = {}

Expand Down
47 changes: 47 additions & 0 deletions tests/test_dynamodb2/test_dynamodb.py
Original file line number Diff line number Diff line change
Expand Up @@ -973,6 +973,53 @@ def test_query_filter():
assert response['Count'] == 2


@mock_dynamodb2
def test_query_filter_overlapping_expression_prefixes():
client = boto3.client('dynamodb', region_name='us-east-1')
dynamodb = boto3.resource('dynamodb', region_name='us-east-1')

# Create the DynamoDB table.
client.create_table(
TableName='test1',
AttributeDefinitions=[{'AttributeName': 'client', 'AttributeType': 'S'}, {'AttributeName': 'app', 'AttributeType': 'S'}],
KeySchema=[{'AttributeName': 'client', 'KeyType': 'HASH'}, {'AttributeName': 'app', 'KeyType': 'RANGE'}],
ProvisionedThroughput={'ReadCapacityUnits': 123, 'WriteCapacityUnits': 123}
)

client.put_item(
TableName='test1',
Item={
'client': {'S': 'client1'},
'app': {'S': 'app1'},
'nested': {'M': {
'version': {'S': 'version1'},
'contents': {'L': [
{'S': 'value1'}, {'S': 'value2'},
]},
}},
})

table = dynamodb.Table('test1')
response = table.query(
KeyConditionExpression=Key('client').eq('client1') & Key('app').eq('app1'),
ProjectionExpression='#1, #10, nested',
ExpressionAttributeNames={
'#1': 'client',
'#10': 'app',
}
)

assert response['Count'] == 1
assert response['Items'][0] == {
'client': 'client1',
'app': 'app1',
'nested': {
'version': 'version1',
'contents': ['value1', 'value2']
}
}


@mock_dynamodb2
def test_scan_filter():
client = boto3.client('dynamodb', region_name='us-east-1')
Expand Down

0 comments on commit f4df7a4

Please sign in to comment.