Metadata-Version: 2.4
Name: vellum-odm
Version: 0.1.0
Summary: The Precision ODM for Asynchronous MongoDB & Pydantic.
Project-URL: Homepage, https://github.com/wailbentafat/vellum
Project-URL: Repository, https://github.com/wailbentafat/vellum
Project-URL: Documentation, https://github.com/wailbentafat/vellum
Author-email: bentafat wail <150479778+wailbentafat@users.noreply.github.com>
License-File: LICENSE
Keywords: async,database,mongodb,motor,odm,pydantic
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Database
Classifier: Topic :: Database :: Front-Ends
Classifier: Typing :: Typed
Requires-Python: >=3.12
Requires-Dist: cryptography>=44.0
Requires-Dist: motor<4.0,>=3.2
Requires-Dist: pydantic>=2.0
Requires-Dist: pymongo<5.0,>=4.0
Description-Content-Type: text/markdown

# Vellum

**The Precision ODM for Asynchronous MongoDB & Pydantic.**

Vellum is a type-safe, async Python ODM for MongoDB built on Pydantic v2 and Motor. It provides a clean repository pattern, fluent aggregation builder, lifecycle hooks, optimistic concurrency, soft deletes, and transactions — all with full type hints.

## Installation

```bash
pip install vellum-odm
```

## Quick Start

```python
from motor.motor_asyncio import AsyncIOMotorClient
from vellum import VellumBaseModel, VellumRepository, AggregationPipeline

# 1. Define a model
class User(VellumBaseModel):
    name: str
    email: str

    class Settings:
        collection_name = "users"
        indexes = [{"key": [("email", 1)], "unique": True}]

# 2. Connect and create a repository
client = AsyncIOMotorClient("mongodb://localhost:27017")
db = client["myapp"]
repo = VellumRepository(User, db)

# 3. CRUD
user = await repo.create(User(name="Alice", email="alice@example.com"))
fetched = await repo.get(user.id)
user.name = "Bob"
await repo.update(user.id, user)
await repo.delete(user.id)

# 4. Query
users = await repo.find({"name": "Alice"})
count = await repo.count({"name": "Alice"})

# 5. Aggregation
results = await (
    AggregationPipeline(repo.collection)
    .match({"status": "active"})
    .group("$department", total={"$sum": 1})
    .sort([("total", -1)])
    .execute()
)
```

## Features

| Feature | Description |
|---|---|
| **Type-safe queries** | Expression classes for all MongoDB operators (`Eq`, `Gt`, `In`, `Regex`, `ElemMatch`, ...) |
| **Fluent aggregation** | `AggregationPipeline` with `match`, `group`, `project`, `sort`, `unwind`, `lookup`, etc. |
| **Lifecycle hooks** | `before_insert`, `after_insert`, `before_update`, ... on your model |
| **OCC** | `OptimisticConcurrencyMixin` — automatic version-based conflict detection |
| **Soft delete** | `SoftDeleteMixin` — automatic filtering, `soft_delete()` / `restore()` |
| **Transactions** | `async with repo.transaction() as session:` |
| **FastAPI integration** | `repository_factory` for `Depends` injection |
| **Aggregation output models** | Pass a Pydantic model to `project()` / `group()` for validated results |

## Documentation

- [Learning Guide](docs/learning.md) — explains bugs found and concepts introduced
- [Roadmap](docs/roadmap.md) — planned features and improvements

## Requirements

- Python >= 3.12
- MongoDB >= 4.0 (transactions require a replica set)

## License

MIT
