Skip to content

Commit

Permalink
Document: Copy documents using HTTP COPY provided by CouchDB
Browse files Browse the repository at this point in the history
While at it, rename copy_doc as copy.
  • Loading branch information
Jyrki Pulliainen committed Aug 24, 2010
1 parent 5ce26d0 commit 54fca8b
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 30 deletions.
40 changes: 33 additions & 7 deletions test/test_client.py
Expand Up @@ -1014,7 +1014,7 @@ def create_db_callback(db):
)

def create_doc_callback(doc):
doc.copy_doc('newname', copy_done)
doc.copy('newname', copy_done)

def copy_done(doc):
eq(doc.id, 'newname')
Expand All @@ -1026,6 +1026,31 @@ def copy_done(doc):
ioloop.start()


@with_ioloop
@with_couchdb
def test_copy_document_exists(baseurl, ioloop):
def do_test(db):
def create_doc(doc):
db.set(
{'testvalue': 'something'},
copy_doc,
)

def copy_doc(doc):
doc.copy('newname', copy_done)

def copy_done(result):
eq(result.error, True)
eq(result.errno, trombi.errors.CONFLICT)
eq(result.msg, 'Document update conflict.')
ioloop.stop()

db.set('newname', {'something': 'else'}, create_doc)

s = trombi.Server(baseurl, io_loop=ioloop)
s.create('testdb', callback=do_test)
ioloop.start()

@with_ioloop
@with_couchdb
def test_copy_document_with_attachments(baseurl, ioloop):
Expand All @@ -1037,7 +1062,7 @@ def create_db_callback(db):
)

def create_doc_callback(doc):
doc.copy_doc('newname', copy_done)
doc.copy('newname', copy_done)

def copy_done(doc):
eq(doc.id, 'newname')
Expand Down Expand Up @@ -1065,14 +1090,15 @@ def create_doc_callback(doc):
doc.db.get(doc.id, got_doc)

def got_doc(doc):
doc.copy_doc('newname', copy_done)
doc.copy('newname', copy_done)

def copy_done(doc):
eq(doc.id, 'newname')
eq(dict(doc), {'testvalue': 'something'})
eq(doc.attachments.keys(), ['foo'])
eq(doc.attachments['foo']['content_type'], 'text/plain')
eq(doc.attachments['foo']['data'], 'YmFy')
doc.load_attachment('foo', loaded_attachment)

def loaded_attachment(attach):
eq(attach, 'bar')
ioloop.stop()

s = trombi.Server(baseurl, io_loop=ioloop)
Expand All @@ -1094,7 +1120,7 @@ def create_doc_callback(doc):
doc.db.get(doc.id, got_doc, attachments=True)

def got_doc(doc):
doc.copy_doc('newname', copy_done)
doc.copy('newname', copy_done)

def copy_done(doc):
eq(doc.id, 'newname')
Expand Down
41 changes: 18 additions & 23 deletions trombi/client.py
Expand Up @@ -376,33 +376,28 @@ def _as_dict(self):
result.update(self.data)
return result

def copy_doc(self, new_id, callback):
# WARNING: Due to the lack of support of custom, non-standard
# HTTP methods in tornado's AsyncHTTPClient, this operation is
# not atomic in any way, just a convenience wrapper.
#
# Also, this hogs memory as hell if there's a load of
# attachments. Please do know what you're doing if you use
# this function :p
def copy(self, new_id, callback):
assert self.rev and self.id

def get_done(doc):
assert doc.id is not None

attachments = getattr(doc, 'attachments', None)
if attachments:
attachments = dict(
(key, (val['content_type'], b64decode(val['data']))) for
key, val in attachments.items())
def _copy_done(response):
if response.code != 201:
callback(_error_response(response))
return

self.db.set(
doc.copy(),
doc_id=new_id,
callback=callback,
attachments=attachments
)
content = json.loads(response.body)
doc = Document(self.db, self.data)
doc.attachments = self.attachments.copy()
doc.id = content['id']
doc.rev = content['rev']
callback(doc)

self.db.get(self.id, callback=get_done, attachments=True)
self.db._fetch(
'%s' % urllib.quote(self.id, safe=''),
_copy_done,
allow_nonstandard_methods=True,
method='COPY',
headers={'Destination': urllib.quote(new_id, safe='')}
)

def attach(self, name, data, callback, type='text/plain'):
def _really_callback(response):
Expand Down

0 comments on commit 54fca8b

Please sign in to comment.