From 06492026c349ccfc5c1ab84dc00b6b1a31a9f68d Mon Sep 17 00:00:00 2001 From: Eric Reinecke Date: Fri, 10 Nov 2017 21:35:01 -0800 Subject: [PATCH 1/2] dynamodb2 items are copied when using ProjectionExpression to avoid mutating originals --- moto/dynamodb2/models.py | 3 ++- tests/test_dynamodb2/test_dynamodb.py | 9 +++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/moto/dynamodb2/models.py b/moto/dynamodb2/models.py index e5bce2f6..2b686b11 100644 --- a/moto/dynamodb2/models.py +++ b/moto/dynamodb2/models.py @@ -1,5 +1,6 @@ from __future__ import unicode_literals from collections import defaultdict +import copy import datetime import decimal import json @@ -492,7 +493,7 @@ class Table(BaseModel): if projection_expression: expressions = [x.strip() for x in projection_expression.split(',')] - for result in possible_results: + for result in copy.deepcopy(possible_results): for attr in list(result.attrs): if attr not in expressions: result.attrs.pop(attr) diff --git a/tests/test_dynamodb2/test_dynamodb.py b/tests/test_dynamodb2/test_dynamodb.py index a0bfc983..08547089 100644 --- a/tests/test_dynamodb2/test_dynamodb.py +++ b/tests/test_dynamodb2/test_dynamodb.py @@ -371,6 +371,15 @@ def test_basic_projection_expressions(): assert 'body' in results['Items'][1] assert results['Items'][1]['body'] == 'yet another test message' + # The projection expression should not remove data from storage + results = table.query( + KeyConditionExpression=Key('forum_name').eq( + 'the-key'), + ) + assert 'subject' in results['Items'][0] + assert 'body' in results['Items'][1] + assert 'forum_name' in results['Items'][1] + @mock_dynamodb2 def test_basic_projection_expressions_with_attr_expression_names(): From 64fb0207e29a81c35768e08f337fc595a1e086d3 Mon Sep 17 00:00:00 2001 From: Eric Reinecke Date: Fri, 10 Nov 2017 21:57:16 -0800 Subject: [PATCH 2/2] dynamodb2 was evaluating ProjectionExpression on the wrong local result set --- moto/dynamodb2/models.py | 3 ++- tests/test_dynamodb2/test_dynamodb.py | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/moto/dynamodb2/models.py b/moto/dynamodb2/models.py index 2b686b11..a4d8feb3 100644 --- a/moto/dynamodb2/models.py +++ b/moto/dynamodb2/models.py @@ -493,7 +493,8 @@ class Table(BaseModel): if projection_expression: expressions = [x.strip() for x in projection_expression.split(',')] - for result in copy.deepcopy(possible_results): + results = copy.deepcopy(results) + for result in results: for attr in list(result.attrs): if attr not in expressions: result.attrs.pop(attr) diff --git a/tests/test_dynamodb2/test_dynamodb.py b/tests/test_dynamodb2/test_dynamodb.py index 08547089..87175cfe 100644 --- a/tests/test_dynamodb2/test_dynamodb.py +++ b/tests/test_dynamodb2/test_dynamodb.py @@ -367,8 +367,10 @@ def test_basic_projection_expressions(): ) assert 'body' in results['Items'][0] + assert 'subject' not in results['Items'][0] assert results['Items'][0]['body'] == 'some test message' assert 'body' in results['Items'][1] + assert 'subject' not in results['Items'][1] assert results['Items'][1]['body'] == 'yet another test message' # The projection expression should not remove data from storage