additive only — every existing name preserved, swallow contract unchanged. brings mongo in line with the redis/psql/mysql datastore trio's naming/lifecycle. bump v0.1.3 -> v0.1.4 Signed-off-by: disqualifier <dev@disqualifier.me>
100 lines
3.6 KiB
Markdown
100 lines
3.6 KiB
Markdown
# mongo
|
|
|
|
Async MongoDB wrapper over [motor](https://motor.readthedocs.io/). Thin, opinionated
|
|
helpers for the common paths, with a raw escape hatch for everything else.
|
|
|
|
## Install
|
|
|
|
`requirements.txt`:
|
|
|
|
```
|
|
mongo @ git+ssh://git@git.rethinkstudios.io/rethink-public/mongo.git@v0.1.4
|
|
```
|
|
|
|
Direct:
|
|
|
|
```bash
|
|
pip install "mongo @ git+ssh://git@git.rethinkstudios.io/rethink-public/mongo.git@v0.1.4"
|
|
```
|
|
|
|
Requires `motor` and `pymongo` (pulled transitively).
|
|
|
|
Drop the `@v0.1.4` suffix from the line above to install the latest unpinned.
|
|
|
|
## Usage
|
|
|
|
**Object (preferred)** — one client per process:
|
|
|
|
```python
|
|
from mongo import MongoDB
|
|
|
|
db = MongoDB(conn_string, database) # attach as bot.db / app.db
|
|
await db.connect() # optional: ping to fail-early on a bad URI
|
|
users = await db.get_documents("users", {"active": True})
|
|
db.close() # on shutdown (sync)
|
|
|
|
# or with guaranteed cleanup:
|
|
async with MongoDB(conn_string, database) as db:
|
|
await db.get_documents("users", {"active": True})
|
|
```
|
|
|
|
The class is `MongoDB`; **`Mongo` remains a back-compat alias** (`Mongo = MongoDB`), so
|
|
existing `Mongo(...)` call sites keep working unchanged.
|
|
|
|
**Module proxy (back-compat)** — arm once, then call bare:
|
|
|
|
```python
|
|
import mongo # NOT `from mongo import ...`
|
|
mongo.init(conn_string, database)
|
|
users = await mongo.get_documents("users", {"active": True})
|
|
```
|
|
|
|
Both styles share one client. The proxy exists so legacy call sites keep working
|
|
after a one-line `init()`; new code should use the object.
|
|
|
|
## Naming consistency with the datastore trio
|
|
|
|
mongo predates the `redis`/`psql`/`mysql` trio; this version makes it surface-consistent
|
|
**without breaking anything** (all additive, every old name preserved):
|
|
|
|
- class is **`MongoDB`** (with `Mongo` kept as an alias)
|
|
- **`connect()`** + **`async with`** like the trio (motor connects lazily, so `connect()`
|
|
just pings to validate early)
|
|
- **`exists()`** aliases `check_document_exists()`; **`delete()`** aliases
|
|
`delete_document()` — old names still work, the trio-consistent names are now available
|
|
|
|
The one deliberate difference that remains: **mongo swallows** (see below) where the trio
|
|
is **fail-loud**. That's intentional — flipping it would break existing consumers' branch-
|
|
on-result control flow.
|
|
|
|
## Error contract
|
|
|
|
- **Wrapped methods** log-and-swallow exceptions and return a safe default
|
|
(`False` / `[]` / `{}` / `0` / `None`). Branch on the result. (`connect()` is the
|
|
exception — it raises on a bad connection so you can fail-early.)
|
|
- **`db.collection(name)`** (or `db[name]`) returns the raw motor collection:
|
|
full driver surface, no swallowing, **raises**. Use it for anything not wrapped
|
|
(`find_one_and_*` beyond what's exposed, change streams, complex bulk ops).
|
|
|
|
## API
|
|
|
|
See the module docstring and method docstrings in `mongo.py` — that's the source
|
|
of truth. Grouped as: collection/index management, create, read, update, delete,
|
|
bulk, checks. Atomic ops (`find_one_and_update/replace/delete`) and `bulk_write`
|
|
are included.
|
|
|
|
## Gotchas
|
|
|
|
- `from mongo import func` won't see the proxy (resolved at import, before `init`).
|
|
Use `import mongo` then `mongo.func(...)`.
|
|
- `find_one_and_update` returns the **after** image by default (`return_after=True`).
|
|
- `bulk_write` takes pymongo ops the caller builds:
|
|
```python
|
|
from pymongo import UpdateOne
|
|
ops = [UpdateOne({"_id": i}, {"$set": {...}}, upsert=True) for i in ids]
|
|
await db.bulk_write("col", ops)
|
|
```
|
|
|
|
## Versioning
|
|
|
|
Releases are tagged `vX.Y.Z`. The install line above pins a release; drop the `@vX.Y.Z` suffix to install the latest unpinned. Pin deliberately for reproducible installs. |