You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@couchdb.apache.org by Paul Davis <pa...@gmail.com> on 2016/08/09 17:57:56 UTC

Curious API corner case when re-creating deleted documents

Hey all,

We had a customer get tripped up on a fairly obscure part of the API
today and I thought I'd ask the community if we shouldn't tweak things
lightly.

The basic setup was that a user accidentally deleted a doc and then
went through the steps to recreate it. It all worked fine except the
actual recreation threw an conflict error even though the user
specified the "correct" revision of the deleted doc (ie, the revision
that marked it as deleted rather than the revision of the body they
used to restore).

The issue here was that when we last changed revision tree merging in
couch_db_updater we expressly tightened a check when recreating
deleted documents to require that it have a _rev value at the root of
the tree. (ie, no revision specified and had one auto-generated by
couch). The reason for this was that there were cases when people
specified internal revisions (ie, non leaf revisions) which CouchDB
happily accepted and extended which created branches where there
weren't any previously.

I asked Robert Newson his thoughts and he leaned toward the current
behavior being correct where I'm thinking that we should allow the
extension. Given the disagreement I figured the mailing list would be
the best place to ask what others though would be best given that its
all a bit subtle.

For the record, Bob's point was that by requiring the rev be absent
when creating (or re-creating) a doc directly delineates
(re-)?creation from update. I on the other hand know that even though
no revision is specified it will still create a revision based on the
deleted revision so the response you get back might look surprising
when it doesn't start with "1-" which clearly indicates is using old
history when re-creating the doc.

Here's a link to a gist that shows the corner case towards the bottom.
I'll also paste it below for future people that live in a sad
post-gist world.

https://gist.github.com/davisp/8484f2a8187dd214cae0fcde4d0c2440

Paul

N.B. acurl is basically just an alias to "curl -u davisp"

$ acurl 'https://davisp.cloudant.com/test-db/_all_docs?keys=["foo"]' |
python -m json.tool
{
    "rows": [
        {
            "id": "foo",
            "key": "foo",
            "value": {
                "deleted": true,
                "rev": "2-eec205a9d413992850a6e32678485900"
            }
        }
    ],
    "total_rows": 7
}
$ acurl 'https://davisp.cloudant.com/test-db/foo?rev=2-eec205a9d413992850a6e32678485900&revs=true'
| python -m json.tool
{
    "_deleted": true,
    "_id": "foo",
    "_rev": "2-eec205a9d413992850a6e32678485900",
    "_revisions": {
        "ids": [
            "eec205a9d413992850a6e32678485900",
            "967a00dff5e02add41819138abb3284d"
        ],
        "start": 2
    }
}
$ acurl https://davisp.cloudant.com/test-db/foo?rev=1-967a00dff5e02add41819138abb3284d
| python -m json.tool
{
    "error": "not_found",
    "reason": "missing"
}
$ # A curious corner case
$ cat foo.json
{
    "_id": "foo",
    "_rev": "2-eec205a9d413992850a6e32678485900",
    "stuff": "bar"
}
$ acurl -X PUT https://davisp.cloudant.com/test-db/foo -d @foo.json |
python -m json.tool
{
    "error": "conflict",
    "reason": "Document update conflict."
}