metricq / aiocouch

🛋 An asynchronous client library for CouchDB 2.x and 3.x
https://aiocouch.readthedocs.io/en/latest/
BSD 3-Clause "New" or "Revised" License
29 stars 10 forks source link

Implement Database.save(doc) #10

Closed adrienverge closed 4 years ago

adrienverge commented 4 years ago

There are cases when it's not handy to use the Document class. An example is when we don't know whether the document exists or not, whether Document.create() or Document.fetch() should be called.

I propose to implement Database.save(doc), similarly to what couchdb-python proposes [1]:

try:
    doc = await db["counter"]
except NotFoundError:
    doc = {"_id": "counter", "value": 1}

doc["value"] += 1
await db.save(doc)

[1]: https://couchdb-python.readthedocs.io/en/latest/client.html#couchdb.client.Database.save


Note: I also started implementing a wrapper like this:

async def __setitem__(self, id, doc):
    if "_id" not in doc:
        doc["_id"] = id
    elif doc["_id"] != id:
        raise ValueError(f"ID '{id}' does not match ID in document")

    return await self.save(doc)

but this doesn't work, because we can't await db["test"] = doc.

bmario commented 4 years ago

I'm sorry, documentation hasn't been the highest priority 😞

If I understand you correctly, your problem can already be solved with this:

doc = await db.create("counter", exists_ok=True)
doc.setdefault("value", 1)
doc["value"] += 1
await doc.save()

Or in case of many documents with update_docs().

I'm seeing the need to create a Document object as a good thing, so I'm hesitant to merge a way to circumvent that without a good use case. What I totally agree is that a method get(id, create=False) with the create parameter similar to update_docs would be a nice addition. Unfortunately, you can't pack that into __getitem__.

adrienverge commented 4 years ago

Thanks, I hadn't even looked into db.create() because of the name, but using it + if not doc.exists: doc.update({"value": 1}) does the job.

I agree that there should only be one good way of using the lib, and this way should use the handy Document class.

I'll close this and follow discussion in https://github.com/metricq/aiocouch/pull/11#issuecomment-601870243 and https://github.com/metricq/aiocouch/pull/12.