cloudant / python-cloudant

A Python library for Cloudant and CouchDB
Apache License 2.0
163 stars 55 forks source link

document.save() does not return response data indicating new _rev #395

Closed andy-maier closed 6 years ago

andy-maier commented 6 years ago

Bug Description

1. Steps to reproduce and the simplest code sample possible to demonstrate the issue

This is a request for an extension (backwards compatible).

The document.save() method performs a PUT operation on the document. According to the Cloudant API reference for Documents, the response to the PUT operation contains data like in the following example:

{
    "ok":true,
    "id":"apple",
    "rev":"2-9176459034"
}

The important piece of information in that response is the new revision of the updated document.

Having the new revision at hand significantly simplifies the algorithm to resolve server-side conflicts: The returned new revision can easily be checked against the conflict revisions returned when specifying query parameter conflicts=true, to find out whether a successful update lost or won a server-side conflict.

However, the response data is not returned in the current implementation of the Document.save() method:

    def save(self):
        """
        . . .
        """
        headers = {}
        headers.setdefault('Content-Type', 'application/json')
        if not self.exists():
            self.create()
            return
        put_resp = self.r_session.put(
            self.document_url,
            data=self.json(),
            headers=headers
        )
        put_resp.raise_for_status()
        data = put_resp.json()
        super(Document, self).__setitem__('_rev', data['rev'])
        return   # <-- No response data returned, currently

This could easily and backwards compatibly be added by returning the response data as a json object (= dict):

    def save(self):
        . . .
        data = put_resp.json()
        super(Document, self).__setitem__('_rev', data['rev'])
        return data    # <-- Response data returned

2. What you expected to happen

Make the new revision that is already returned in the HTTP response of a document update available to the callers of the Document.save() method.

Update the docstring of the method, accordingly.

3. What actually happened

Document.save() returns None, and the returned new revision is not surfaced to the caller.

Environment details

rajinib commented 6 years ago

Hi @andy-maier, when you call Document.save() it will update the _rev field of your existing Document object and you'll be able to access the new revision with doc.get('_rev').
For example:

    doc = Document(db, 'doc-id')
    doc['new'] = 'value'
    assert doc.exists() is False
    assert doc.get('_rev') is None
    doc.create() #create the doc
    assert doc.exists() is True
    assert doc.get('_rev').startswith('1-')
    doc['new'] = 'newer value'
    doc.save() #update the 'new' field
    assert doc.get('_rev').startswith('2-')
rajinib commented 6 years ago

Closing as stale, please reopen if you require further assistance.