Skip to content

Commit d2eb5b1

Browse files
committed
Add copy() method to client.Database (issue 74).
--HG-- extra : convert_revision : svn%3A7a298fb0-333a-0410-83e7-658617cd9cf3/trunk%40155
1 parent 12b329c commit d2eb5b1

File tree

3 files changed

+62
-0
lines changed

3 files changed

+62
-0
lines changed

ChangeLog.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ http://couchdb-python.googlecode.com/svn/tags/0.6.0
1818
* Removed the `eager` option on the `query()` and `view()` methods of
1919
`schema.Document`. Use the `include_docs` option instead, which doesn't
2020
require an additional request per document.
21+
* Added a `copy()` method to the `client.Database` class, which translates to
22+
a HTTP COPY request (issue 74).
2123

2224

2325
Version 0.5

couchdb/client.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,43 @@ def compact(self):
346346
resp, data = self.resource.post('_compact')
347347
return data['ok']
348348

349+
def copy(self, src, dest):
350+
"""Copy the given document to create a new document.
351+
352+
:param src: the ID of the document to copy, or a dictionary or
353+
`Document` object representing the source document.
354+
:param dest: either the destination document ID as string, or a
355+
dictionary or `Document` instance of the document that
356+
should be overwritten.
357+
:return: the new revision of the destination document
358+
:rtype: `str`
359+
"""
360+
if not isinstance(src, basestring):
361+
if not isinstance(src, dict):
362+
if hasattr(src, 'items'):
363+
src = src.items()
364+
else:
365+
raise TypeError('expected dict or string, got %s' %
366+
type(src))
367+
src = src['_id']
368+
369+
if not isinstance(dest, basestring):
370+
if not isinstance(dest, dict):
371+
if hasattr(dest, 'items'):
372+
dest = src.items()
373+
else:
374+
raise TypeError('expected dict or string, got %s' %
375+
type(dest))
376+
if '_rev' in dest:
377+
dest = '%s?rev=%s' % (dest['_id'], dest['_rev'])
378+
else:
379+
dest = dest['_id']
380+
381+
resp, data = self.resource._request('COPY', src,
382+
headers={'Destination': dest})
383+
return data['rev']
384+
385+
349386
def delete(self, doc):
350387
"""Delete the given document from the database.
351388

couchdb/tests/client.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,29 @@ def test_bulk_update_all_or_nothing(self):
223223
doc = self.db.get(doc['_id'], conflicts=True)
224224
assert '_conflicts' in doc
225225

226+
def test_copy_doc(self):
227+
self.db['foo'] = {'status': 'testing'}
228+
result = self.db.copy('foo', 'bar')
229+
self.assertEqual(result, self.db['bar'].rev)
230+
231+
def test_copy_doc_conflict(self):
232+
self.db['bar'] = {'status': 'idle'}
233+
self.db['foo'] = {'status': 'testing'}
234+
self.assertRaises(client.ResourceConflict, self.db.copy, 'foo', 'bar')
235+
236+
def test_copy_doc_overwrite(self):
237+
self.db['bar'] = {'status': 'idle'}
238+
self.db['foo'] = {'status': 'testing'}
239+
result = self.db.copy('foo', self.db['bar'])
240+
doc = self.db['bar']
241+
self.assertEqual(result, doc.rev)
242+
self.assertEqual('testing', doc['status'])
243+
244+
def test_copy_doc_srcobj(self):
245+
self.db['foo'] = {'status': 'testing'}
246+
self.db.copy(self.db['foo'], 'bar')
247+
self.assertEqual('testing', self.db['bar']['status'])
248+
226249

227250
def suite():
228251
suite = unittest.TestSuite()

0 commit comments

Comments
 (0)