Skip to content

Commit 1828bda

Browse files
authored
Nicer update syntax for adding and removing subsets. Fixes pynamodb#389 (pynamodb#408)
1 parent 14e2507 commit 1828bda

File tree

4 files changed

+43
-12
lines changed

4 files changed

+43
-12
lines changed

pynamodb/attributes.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -163,11 +163,11 @@ def set(self, value):
163163
def remove(self):
164164
return Path(self).remove()
165165

166-
def add(self, value):
167-
return Path(self).add(value)
166+
def add(self, *values):
167+
return Path(self).add(*values)
168168

169-
def delete(self, value):
170-
return Path(self).delete(value)
169+
def delete(self, *values):
170+
return Path(self).delete(*values)
171171

172172

173173
class AttributeContainerMeta(type):

pynamodb/expressions/operand.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -275,12 +275,14 @@ def remove(self):
275275
# Returns an update action that removes this attribute from the item
276276
return RemoveAction(self)
277277

278-
def add(self, value):
279-
# Returns an update action that appends the given value to a set or mathematically adds it to a number
278+
def add(self, *values):
279+
# Returns an update action that appends the given values to a set or mathematically adds a value to a number
280+
value = values[0] if len(values) == 1 else values
280281
return AddAction(self, self._to_operand(value))
281282

282-
def delete(self, value):
283-
# Returns an update action that removes the given value from a set attribute
283+
def delete(self, *values):
284+
# Returns an update action that removes the given values from a set attribute
285+
value = values[0] if len(values) == 1 else values
284286
return DeleteAction(self, self._to_operand(value))
285287

286288
def exists(self):

pynamodb/tests/test_expressions.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -475,6 +475,14 @@ def test_add_action(self):
475475
assert expression_attribute_values == {':0': {'N': '0'}}
476476

477477
def test_add_action_set(self):
478+
action = NumberSetAttribute(attr_name='foo').add(0, 1)
479+
placeholder_names, expression_attribute_values = {}, {}
480+
expression = action.serialize(placeholder_names, expression_attribute_values)
481+
assert expression == "#0 :0"
482+
assert placeholder_names == {'foo': '#0'}
483+
assert expression_attribute_values == {':0': {'NS': ['0', '1']}}
484+
485+
def test_add_action_serialized(self):
478486
action = NumberSetAttribute(attr_name='foo').add({'NS': ['0']})
479487
placeholder_names, expression_attribute_values = {}, {}
480488
expression = action.serialize(placeholder_names, expression_attribute_values)
@@ -487,6 +495,22 @@ def test_add_action_list(self):
487495
Path('foo').add({'L': [{'N': '0'}]})
488496

489497
def test_delete_action(self):
498+
action = NumberSetAttribute(attr_name='foo').delete(0, 1)
499+
placeholder_names, expression_attribute_values = {}, {}
500+
expression = action.serialize(placeholder_names, expression_attribute_values)
501+
assert expression == "#0 :0"
502+
assert placeholder_names == {'foo': '#0'}
503+
assert expression_attribute_values == {':0': {'NS': ['0', '1']}}
504+
505+
def test_delete_action_set(self):
506+
action = NumberSetAttribute(attr_name='foo').delete(set([0, 1]))
507+
placeholder_names, expression_attribute_values = {}, {}
508+
expression = action.serialize(placeholder_names, expression_attribute_values)
509+
assert expression == "#0 :0"
510+
assert placeholder_names == {'foo': '#0'}
511+
assert expression_attribute_values == {':0': {'NS': ['0', '1']}}
512+
513+
def test_delete_action_serialized(self):
490514
action = NumberSetAttribute(attr_name='foo').delete({'NS': ['0']})
491515
placeholder_names, expression_attribute_values = {}, {}
492516
expression = action.serialize(placeholder_names, expression_attribute_values)

pynamodb/tests/test_model.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -966,7 +966,8 @@ def test_update(self):
966966
SimpleUserModel.views.remove(),
967967
SimpleUserModel.is_active.set(None),
968968
SimpleUserModel.signature.set(None),
969-
SimpleUserModel.custom_aliases.set(['bob'])
969+
SimpleUserModel.custom_aliases.set(['bob']),
970+
SimpleUserModel.numbers.delete(0, 1)
970971
])
971972

972973
args = req.call_args[0][1]
@@ -978,13 +979,14 @@ def test_update(self):
978979
'S': 'foo'
979980
}
980981
},
981-
'UpdateExpression': 'SET #0 = :0, #1 = :1, #2 = :2, #3 = :3 REMOVE #4',
982+
'UpdateExpression': 'SET #0 = :0, #1 = :1, #2 = :2, #3 = :3 REMOVE #4 DELETE #5 :4',
982983
'ExpressionAttributeNames': {
983984
'#0': 'email',
984985
'#1': 'is_active',
985986
'#2': 'signature',
986987
'#3': 'aliases',
987-
'#4': 'views'
988+
'#4': 'views',
989+
'#5': 'numbers'
988990
},
989991
'ExpressionAttributeValues': {
990992
':0': {
@@ -997,7 +999,10 @@ def test_update(self):
997999
'NULL': True
9981000
},
9991001
':3': {
1000-
'SS': set(['bob'])
1002+
'SS': ['bob']
1003+
},
1004+
':4': {
1005+
'NS': ['0', '1']
10011006
}
10021007
},
10031008
'ReturnConsumedCapacity': 'TOTAL'

0 commit comments

Comments
 (0)