Correct behavior of ReturnValues parameter to put_item and update_item
This commit is contained in:
		
							parent
							
								
									90a62b5640
								
							
						
					
					
						commit
						770ad1db56
					
				| @ -183,6 +183,7 @@ class DynamoHandler(BaseResponse): | |||||||
|     def put_item(self): |     def put_item(self): | ||||||
|         name = self.body['TableName'] |         name = self.body['TableName'] | ||||||
|         item = self.body['Item'] |         item = self.body['Item'] | ||||||
|  |         return_values = self.body.get('ReturnValues', 'NONE') | ||||||
| 
 | 
 | ||||||
|         if has_empty_keys_or_values(item): |         if has_empty_keys_or_values(item): | ||||||
|             return get_empty_str_error() |             return get_empty_str_error() | ||||||
| @ -193,6 +194,13 @@ class DynamoHandler(BaseResponse): | |||||||
|         else: |         else: | ||||||
|             expected = None |             expected = None | ||||||
| 
 | 
 | ||||||
|  |         if return_values == 'ALL_OLD': | ||||||
|  |             existing_item = self.dynamodb_backend.get_item(name, item) | ||||||
|  |             if existing_item: | ||||||
|  |                 existing_attributes = existing_item.to_json()['Attributes'] | ||||||
|  |             else: | ||||||
|  |                 existing_attributes = {} | ||||||
|  | 
 | ||||||
|         # Attempt to parse simple ConditionExpressions into an Expected |         # Attempt to parse simple ConditionExpressions into an Expected | ||||||
|         # expression |         # expression | ||||||
|         if not expected: |         if not expected: | ||||||
| @ -228,6 +236,10 @@ class DynamoHandler(BaseResponse): | |||||||
|                 'TableName': name, |                 'TableName': name, | ||||||
|                 'CapacityUnits': 1 |                 'CapacityUnits': 1 | ||||||
|             } |             } | ||||||
|  |             if return_values == 'ALL_OLD': | ||||||
|  |                 item_dict['Attributes'] = existing_attributes | ||||||
|  |             else: | ||||||
|  |                 item_dict.pop('Attributes', None) | ||||||
|             return dynamo_json_dump(item_dict) |             return dynamo_json_dump(item_dict) | ||||||
|         else: |         else: | ||||||
|             er = 'com.amazonaws.dynamodb.v20111205#ResourceNotFoundException' |             er = 'com.amazonaws.dynamodb.v20111205#ResourceNotFoundException' | ||||||
| @ -527,9 +539,9 @@ class DynamoHandler(BaseResponse): | |||||||
|         return dynamo_json_dump(item_dict) |         return dynamo_json_dump(item_dict) | ||||||
| 
 | 
 | ||||||
|     def update_item(self): |     def update_item(self): | ||||||
| 
 |  | ||||||
|         name = self.body['TableName'] |         name = self.body['TableName'] | ||||||
|         key = self.body['Key'] |         key = self.body['Key'] | ||||||
|  |         return_values = self.body.get('ReturnValues', 'NONE') | ||||||
|         update_expression = self.body.get('UpdateExpression') |         update_expression = self.body.get('UpdateExpression') | ||||||
|         attribute_updates = self.body.get('AttributeUpdates') |         attribute_updates = self.body.get('AttributeUpdates') | ||||||
|         expression_attribute_names = self.body.get( |         expression_attribute_names = self.body.get( | ||||||
| @ -537,6 +549,10 @@ class DynamoHandler(BaseResponse): | |||||||
|         expression_attribute_values = self.body.get( |         expression_attribute_values = self.body.get( | ||||||
|             'ExpressionAttributeValues', {}) |             'ExpressionAttributeValues', {}) | ||||||
|         existing_item = self.dynamodb_backend.get_item(name, key) |         existing_item = self.dynamodb_backend.get_item(name, key) | ||||||
|  |         if existing_item: | ||||||
|  |             existing_attributes = existing_item.to_json()['Attributes'] | ||||||
|  |         else: | ||||||
|  |             existing_attributes = {} | ||||||
| 
 | 
 | ||||||
|         if has_empty_keys_or_values(expression_attribute_values): |         if has_empty_keys_or_values(expression_attribute_values): | ||||||
|             return get_empty_str_error() |             return get_empty_str_error() | ||||||
| @ -591,8 +607,26 @@ class DynamoHandler(BaseResponse): | |||||||
|             'TableName': name, |             'TableName': name, | ||||||
|             'CapacityUnits': 0.5 |             'CapacityUnits': 0.5 | ||||||
|         } |         } | ||||||
|         if not existing_item: |         unchanged_attributes = { | ||||||
|  |             k for k in existing_attributes.keys() | ||||||
|  |             if existing_attributes[k] == item_dict['Attributes'].get(k) | ||||||
|  |         } | ||||||
|  |         changed_attributes = set(existing_attributes.keys()).union(item_dict['Attributes'].keys()).difference(unchanged_attributes) | ||||||
|  | 
 | ||||||
|  |         if return_values == 'NONE': | ||||||
|             item_dict['Attributes'] = {} |             item_dict['Attributes'] = {} | ||||||
|  |         elif return_values == 'ALL_OLD': | ||||||
|  |             item_dict['Attributes'] = existing_attributes | ||||||
|  |         elif return_values == 'UPDATED_OLD': | ||||||
|  |             item_dict['Attributes'] = { | ||||||
|  |                 k: v for k, v in existing_attributes.items() | ||||||
|  |                 if k in changed_attributes | ||||||
|  |             } | ||||||
|  |         elif return_values == 'UPDATED_NEW': | ||||||
|  |             item_dict['Attributes'] = { | ||||||
|  |                 k: v for k, v in item_dict['Attributes'].items() | ||||||
|  |                 if k in changed_attributes | ||||||
|  |             } | ||||||
| 
 | 
 | ||||||
|         return dynamo_json_dump(item_dict) |         return dynamo_json_dump(item_dict) | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1246,6 +1246,69 @@ def test_update_if_not_exists(): | |||||||
|     assert resp['Items'][0]['created_at'] == 123 |     assert resp['Items'][0]['created_at'] == 123 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | # https://github.com/spulec/moto/issues/1937 | ||||||
|  | @mock_dynamodb2 | ||||||
|  | def test_update_return_attributes(): | ||||||
|  |     dynamodb = boto3.client('dynamodb', region_name='us-east-1') | ||||||
|  | 
 | ||||||
|  |     dynamodb.create_table( | ||||||
|  |         TableName='moto-test', | ||||||
|  |         KeySchema=[{'AttributeName': 'id', 'KeyType': 'HASH'}], | ||||||
|  |         AttributeDefinitions=[{'AttributeName': 'id', 'AttributeType': 'S'}], | ||||||
|  |         ProvisionedThroughput={'ReadCapacityUnits': 1, 'WriteCapacityUnits': 1} | ||||||
|  |     ) | ||||||
|  | 
 | ||||||
|  |     def update(col, to, rv): | ||||||
|  |         return dynamodb.update_item( | ||||||
|  |             TableName='moto-test', | ||||||
|  |             Key={'id': {'S': 'foo'}}, | ||||||
|  |             AttributeUpdates={col: {'Value': {'S': to}, 'Action': 'PUT'}}, | ||||||
|  |             ReturnValues=rv | ||||||
|  |         ) | ||||||
|  | 
 | ||||||
|  |     r = update('col1', 'val1', 'ALL_NEW') | ||||||
|  |     assert r['Attributes'] == {'id': {'S': 'foo'}, 'col1': {'S': 'val1'}} | ||||||
|  | 
 | ||||||
|  |     r = update('col1', 'val2', 'ALL_OLD') | ||||||
|  |     assert r['Attributes'] == {'id': {'S': 'foo'}, 'col1': {'S': 'val1'}} | ||||||
|  | 
 | ||||||
|  |     r = update('col2', 'val3', 'UPDATED_NEW') | ||||||
|  |     assert r['Attributes'] == {'col2': {'S': 'val3'}} | ||||||
|  | 
 | ||||||
|  |     r = update('col2', 'val4', 'UPDATED_OLD') | ||||||
|  |     assert r['Attributes'] == {'col2': {'S': 'val3'}} | ||||||
|  | 
 | ||||||
|  |     r = update('col1', 'val5', 'NONE') | ||||||
|  |     assert r['Attributes'] == {} | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | @mock_dynamodb2 | ||||||
|  | def test_put_return_attributes(): | ||||||
|  |     dynamodb = boto3.client('dynamodb', region_name='us-east-1') | ||||||
|  | 
 | ||||||
|  |     dynamodb.create_table( | ||||||
|  |         TableName='moto-test', | ||||||
|  |         KeySchema=[{'AttributeName': 'id', 'KeyType': 'HASH'}], | ||||||
|  |         AttributeDefinitions=[{'AttributeName': 'id', 'AttributeType': 'S'}], | ||||||
|  |         ProvisionedThroughput={'ReadCapacityUnits': 1, 'WriteCapacityUnits': 1} | ||||||
|  |     ) | ||||||
|  | 
 | ||||||
|  |     r = dynamodb.put_item( | ||||||
|  |         TableName='moto-test', | ||||||
|  |         Item={'id': {'S': 'foo'}, 'col1': {'S': 'val1'}}, | ||||||
|  |         ReturnValues='NONE' | ||||||
|  |     ) | ||||||
|  |     assert 'Attributes' not in r | ||||||
|  |      | ||||||
|  |     r = dynamodb.put_item( | ||||||
|  |         TableName='moto-test', | ||||||
|  |         Item={'id': {'S': 'foo'}, 'col1': {'S': 'val2'}}, | ||||||
|  |         ReturnValues='ALL_OLD' | ||||||
|  |     ) | ||||||
|  |     assert r['Attributes'] == {'id': {'S': 'foo'}, 'col1': {'S': 'val1'}} | ||||||
|  |      | ||||||
|  |      | ||||||
|  | 
 | ||||||
| @mock_dynamodb2 | @mock_dynamodb2 | ||||||
| def test_query_global_secondary_index_when_created_via_update_table_resource(): | def test_query_global_secondary_index_when_created_via_update_table_resource(): | ||||||
|     dynamodb = boto3.resource('dynamodb', region_name='us-east-1') |     dynamodb = boto3.resource('dynamodb', region_name='us-east-1') | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user