Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Merge branch 'dynamodb-update-item' of https://github.com/milancermak…

…/boto into milancermak-dynamodb-update-item
  • Loading branch information...
commit 4e460715fafc1654e5915016c850449761098d79 2 parents 6e47ee6 + 654eca7
@garnaat garnaat authored
View
70 boto/dynamodb/item.py
@@ -44,6 +44,7 @@ def __init__(self, table, hash_key=None, range_key=None, attrs=None):
if attrs:
self.update(attrs)
self.consumed_units = 0
+ self._updates = {}
@property
def hash_key(self):
@@ -60,7 +61,21 @@ def hash_key_name(self):
@property
def range_key_name(self):
return self._range_key_name
-
+
+ def add_attribute(self, attr_name, attr_value):
+ """
+ Add an attribute to an item in DynamoDB. Consult AWS Documentation
+ for semantics of ADD. The update action is not executed until you call
+ save().
+
+ :type attr_name: str
+ :param attr_name: Name of the attribute you want to alter.
+
+ :type attr_value: int|long|float|set
+ :param attr_value: Value which is to be added to the attribute.
+ """
+ self._updates[attr_name] = ("ADD", attr_value)
+
def delete(self, expected_value=None, return_values=None):
"""
Delete the item from DynamoDB.
@@ -81,6 +96,22 @@ def delete(self, expected_value=None, return_values=None):
"""
self.table.layer2.delete_item(self, expected_value, return_values)
+ def delete_attribute(self, attr_name, attr_value=None):
+ """
+ Delete an attribute from an item in DynamoDB. Consult AWS Documentation
+ for semantics of DELETE. The update action is not executed until you call
+ save().
+
+ :type attr_name: str
+ :param attr_name: Name of the attribute you want to alter.
+
+ :type attr_value: set
+ :param attr_value: A set of values to be removed from the attribute.
+ This parameter is optional. If None, the whole attribute is
+ removed from the item.
+ """
+ self._updates[attr_name] = ("DELETE", attr_value)
+
def put(self, expected_value=None, return_values=None):
"""
Store a new item or completely replace an existing item
@@ -101,3 +132,40 @@ def put(self, expected_value=None, return_values=None):
of the old item is returned.
"""
self.table.layer2.put_item(self, expected_value, return_values)
+
+ def put_attribute(self, attr_name, attr_value):
+ """
+ Put an attribute to an item in DynamoDB. Consult AWS Documentation
+ for semantics of PUT. The update action is not executed until you call
+ save().
+
+ :type attr_name: str
+ :param attr_name: Name of the attribute you want to alter.
+
+ :type attr_value: int|long|float|str|set
+ :param attr_value: New value of the attribute.
+ """
+ self._updates[attr_name] = ("PUT", attr_value)
+
+ def save(self, expected_values=None, return_values=None):
+ """
+ Commits pending updates to Amazon DynamoDB.
+
+ :type expected_values: dict
+ :param expected_values: A dictionary of name/value pairs that you expect.
+ This dictionary should have name/value pairs where the name
+ is the name of the attribute and the value is either the value
+ you are expecting or False if you expect the attribute not to
+ exist.
+
+ :type return_values: str
+ :param return_values: Controls the return of attribute name/value pairs
+ before they were updated. Possible values are: None, 'ALL_OLD',
+ 'UPDATED_OLD', 'ALL_NEW' or 'UPDATED_NEW'. If 'ALL_OLD' is
+ specified and the item is overwritten, the content of the old item
+ is returned. If 'ALL_NEW' is specified, then all the attributes of
+ the new version of the item are returned. If 'UPDATED_NEW' is
+ specified, the new versions of only the updated attributes are
+ returned.
+ """
+ self.table.layer2.save_item(self, expected_values, return_values)
View
53 boto/dynamodb/layer2.py
@@ -70,6 +70,22 @@ def __init__(self, aws_access_key_id=None, aws_secret_access_key=None,
is_secure, port, proxy, proxy_port,
host, debug, session_token)
+ def dynamize_attribute_updates(self, pending_updates):
+ """
+ Convert a set of pending item updates into the structure
+ required by Layer1.
+ """
+ d = {}
+ for attr_name in pending_updates:
+ action, value = pending_updates[attr_name]
+ if value is None:
+ # DELETE without an attribute value
+ d[attr_name] = {"Action": action}
+ else:
+ d[attr_name] = {"Action": action,
+ "Value": self.dynamize_value(value)}
+ return d
+
def dynamize_item(self, item):
d = {}
for attr_name in item:
@@ -607,3 +623,40 @@ def scan(self, table, scan_filter=None,
if response:
for item in response['Items']:
yield item_class(table, attrs=item)
+
+ def save_item(self, item, expected_value=None, return_values=None):
+ """
+ Commit pending item updates to Amazon DynamoDB.
+
+ :type item: :class:`boto.dynamodb.item.Item`
+ :param item: The Item to update in Amazon DynamoDB.
+
+ :type expected_values: dict
+ :param expected_values: A dictionary of name/value pairs that you expect.
+ This dictionary should have name/value pairs where the name
+ is the name of the attribute and the value is either the value
+ you are expecting or False if you expect the attribute not to
+ exist.
+
+ :type return_values: str
+ :param return_values: Controls the return of attribute name/value pairs
+ before they were updated. Possible values are: None, 'ALL_OLD',
+ 'UPDATED_OLD', 'ALL_NEW' or 'UPDATED_NEW'. If 'ALL_OLD' is
+ specified and the item is overwritten, the content of the old item
+ is returned. If 'ALL_NEW' is specified, then all the attributes of
+ the new version of the item are returned. If 'UPDATED_NEW' is
+ specified, the new versions of only the updated attributes are
+ returned.
+
+ """
+ expected_value = self.dynamize_expected_value(expected_value)
+ key = self.build_key_from_values(item.table.schema,
+ item.hash_key, item.range_key)
+ attr_updates = self.dynamize_attribute_updates(item._updates)
+
+ response = self.layer1.update_item(item.table.name, key,
+ attr_updates,
+ expected_value, return_values)
+ item._updates.clear()
+ if 'ConsumedCapacityUnits' in response:
+ item.consumed_units = response['ConsumedCapacityUnits']
View
28 tests/dynamodb/test_layer2.py
@@ -150,13 +150,27 @@ def test_layer2_basic(self):
pass
- # # Now update the existing object
- # attribute_updates = {'Views': {'Value': {'N': '5'},
- # 'Action': 'PUT'},
- # 'Tags': {'Value': {'SS': ['foobar']},
- # 'Action': 'ADD'}}
- # result = c.update_item(table_name, key=key1,
- # attribute_updates=attribute_updates)
+ # Now update the existing object
+ item1.add_attribute('Replies', 2)
+
+ removed_attr = 'Public'
+ item1.delete_attribute(removed_attr)
+
+ removed_tag = item1_attrs['Tags'].copy().pop()
+ item1.delete_attribute('Tags', set([removed_tag]))
+
+ replies_by_set = set(['Adam', 'Arnie'])
+ item1.put_attribute('RepliesBy', replies_by_set)
+ item1.save()
+
+ # Check for correct updates
+ item1_updated = table.get_item(item1_key, item1_range,
+ consistent_read=True)
+ assert item1_updated['Replies'] == item1_attrs['Replies'] + 2
+ self.assertFalse(item1_updated.has_key(removed_attr))
+ self.assertTrue(removed_tag not in item1_updated['Tags'])
+ self.assertTrue(item1_updated.has_key('RepliesBy'))
+ self.assertTrue(item1_updated['RepliesBy'] == replies_by_set)
# Put a few more items into the table
item2_key = 'Amazon DynamoDB'
Please sign in to comment.
Something went wrong with that request. Please try again.