Skip to content

Commit 04d3171

Browse files
committed
Handle operation for patch separately
Patch remove operation is now able to remove element from list and dict, Added more test on new changes committer: Ralf Schlatterbeck <[email protected]>
1 parent 6a9aac6 commit 04d3171

File tree

2 files changed

+84
-25
lines changed

2 files changed

+84
-25
lines changed

roundup/rest.py

Lines changed: 60 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import sys
1313
import time
1414
import traceback
15+
import xml
1516
from roundup import hyperdb
1617
from roundup.exceptions import *
1718

@@ -223,6 +224,59 @@ def error_obj(self, status, msg, source=None):
223224

224225
return result
225226

227+
def patch_data(self, op, old_val, new_val):
228+
"""Perform patch operation based on old_val and new_val
229+
230+
Args:
231+
op (string): PATCH operation: add, replace, remove
232+
old_val: old value of the property
233+
new_val: new value of the property
234+
235+
Returns:
236+
result (string): value after performed the operation
237+
"""
238+
# add operation: If neither of the value is None, use the other one
239+
# Otherwise, concat those 2 value
240+
if op == 'add':
241+
if old_val is None:
242+
result = new_val
243+
elif new_val is None:
244+
result = old_val
245+
else:
246+
result = old_val + new_val
247+
# Replace operation: new value is returned
248+
elif op == 'replace':
249+
result = new_val
250+
# Remove operation:
251+
# if old_val is not a list/dict, change it to None
252+
# if old_val is a list/dict, but the parameter is empty,
253+
# change it to none
254+
# if old_val is a list/dict, and parameter is not empty
255+
# proceed to remove the values from parameter from the list/dict
256+
elif op == 'remove':
257+
if isinstance(old_val, list):
258+
if new_val is None:
259+
result = []
260+
elif isinstance(new_val, list):
261+
result = [x for x in old_val if x not in new_val]
262+
else:
263+
if new_val in old_val:
264+
old_val.remove(new_val)
265+
elif isinstance(old_val, dict):
266+
if new_val is None:
267+
result = {}
268+
elif isinstance(new_val, dict):
269+
for x in new_val:
270+
old_val.pop(x, None)
271+
else:
272+
old_val.pop(new_val, None)
273+
else:
274+
result = None
275+
else:
276+
raise UsageError('PATCH Operation %s is not allowed' % op)
277+
278+
return result
279+
226280
@_data_decorator
227281
def get_collection(self, class_name, input):
228282
"""GET resource from class URI.
@@ -704,18 +758,9 @@ def patch_element(self, class_name, item_id, input):
704758
(prop, class_name, item_id)
705759
)
706760

707-
if op == 'add':
708-
props[prop] = class_obj.get(item_id, prop) + props[prop]
709-
elif op == 'replace':
710-
pass
711-
elif op == 'remove':
712-
current_prop = class_obj.get(item_id, prop)
713-
if isinstance(current_prop, list):
714-
props[prop] = []
715-
else:
716-
props[prop] = None
717-
else:
718-
raise UsageError('PATCH Operation %s is not allowed' % op)
761+
props[prop] = self.patch_data(
762+
op, class_obj.get(item_id, prop), props[prop]
763+
)
719764

720765
try:
721766
result = class_obj.set(item_id, **props)
@@ -776,18 +821,9 @@ def patch_attribute(self, class_name, item_id, attr_name, input):
776821
)
777822
}
778823

779-
if op == 'add':
780-
props[prop] = class_obj.get(item_id, prop) + props[prop]
781-
elif op == 'replace':
782-
pass
783-
elif op == 'remove':
784-
current_prop = class_obj.get(item_id, prop)
785-
if isinstance(current_prop, list):
786-
props[prop] = []
787-
else:
788-
props[prop] = None
789-
else:
790-
raise UsageError('PATCH Operation %s is not allowed' % op)
824+
props[prop] = self.patch_data(
825+
op, class_obj.get(item_id, prop), props[prop]
826+
)
791827

792828
try:
793829
result = class_obj.set(item_id, **props)

test/test_rest.py

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -440,7 +440,7 @@ def testPatchRemoveAll(self):
440440
"""
441441
Test Patch Action 'Remove'
442442
"""
443-
# create a new issue with userid 1 in the nosy list
443+
# create a new issue with userid 1 and 2 in the nosy list
444444
issue_id = self.db.issue.create(title='foo', nosy=['1', '2'])
445445

446446
# remove the nosy list and the title
@@ -461,6 +461,29 @@ def testPatchRemoveAll(self):
461461
self.assertEqual(len(results['attributes']['nosy']), 0)
462462
self.assertEqual(results['attributes']['nosy'], [])
463463

464+
def testPatchRemove(self):
465+
"""
466+
Test Patch Action 'Remove' only some element from a list
467+
"""
468+
# create a new issue with userid 1, 2, 3 in the nosy list
469+
issue_id = self.db.issue.create(title='foo', nosy=['1', '2', '3'])
470+
471+
# remove the nosy list and the title
472+
form = cgi.FieldStorage()
473+
form.list = [
474+
cgi.MiniFieldStorage('op', 'remove'),
475+
cgi.MiniFieldStorage('nosy', '1, 2'),
476+
]
477+
results = self.server.patch_element('issue', issue_id, form)
478+
self.assertEqual(self.dummy_client.response_code, 200)
479+
480+
# verify the result
481+
results = self.server.get_element('issue', issue_id, self.empty_form)
482+
results = results['data']
483+
self.assertEqual(self.dummy_client.response_code, 200)
484+
self.assertEqual(len(results['attributes']['nosy']), 1)
485+
self.assertEqual(results['attributes']['nosy'], ['3'])
486+
464487

465488
def get_obj(path, id):
466489
return {

0 commit comments

Comments
 (0)