Metadata-Version: 2.1
Name: firestore-pydantic-odm
Version: 0.2.2
Summary: Asynchronous Pydantic ODM for Google Cloud Firestore
Home-page: https://github.com/santosdevco/firestore-pydantic-odm
Author: Santos Dev Co
Author-email: projects@santosdevco.com
License: MIT
Project-URL: Documentation, https://github.com/santosdevco/firestore-pydantic-odm#readme
Project-URL: Changelog, https://github.com/santosdevco/firestore-pydantic-odm/releases
Project-URL: Issue Tracker, https://github.com/santosdevco/firestore-pydantic-odm/issues
Project-URL: Source Code, https://github.com/santosdevco/firestore-pydantic-odm
Keywords: firestore,pydantic,odm,asyncio,google cloud
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Framework :: AsyncIO
Classifier: Topic :: Database :: Front-Ends
Classifier: Typing :: Typed
Requires-Python: >=3.8
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: pydantic>=1.10
Requires-Dist: google-cloud-firestore>=2.0.0
Provides-Extra: dev
Requires-Dist: black; extra == "dev"
Requires-Dist: ruff; extra == "dev"
Requires-Dist: pytest; extra == "dev"
Requires-Dist: pytest-asyncio; extra == "dev"
Provides-Extra: emulator
Requires-Dist: google-cloud-firestore-emulator; extra == "emulator"


[![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/santosdevco/firestore-pydantic-odm/publish.yml)](https://github.com/santosdevco/firestore-pydantic-odm/actions/workflows/publish.yml)
[![PyPI](https://img.shields.io/pypi/v/firestore-pydantic-odm)](https://pypi.org/project/firestore-pydantic-odm/)
[![PyPI - Python Version](https://img.shields.io/pypi/pyversions/firestore-pydantic-odm)](https://pypi.org/project/firestore-pydantic-odm/)
[![License: BSD 3-Clause](https://img.shields.io/badge/License-BSD%203--Clause-blue.svg)](https://opensource.org/licenses/BSD-3-Clause)

# Firestore Pydantic ODM

**Firestore Pydantic ODM** is a lightweight, fully-typed Object-Document Mapper for **Google Cloud Firestore**.  
It combines [Pydantic]’s data-validation super-powers with Firestore’s scalable NoSQL store, offering async CRUD, batch writes, transactions, and **projections that request only the fields you need**—making queries faster and cheaper.

---

## Features

* **Asynchronous CRUD:** Full support for creating, reading, updating, and deleting Firestore documents using `async/await`.
* **Validation with Pydantic:** Define your data models with automatic validation, ensuring data integrity before it reaches the database.
* **Advanced Queries:** Perform searches with filters, projections (selecting only specific fields), and ordering.
* **Batch Operations and Transactions:** Group multiple write operations and execute transactions atomically for greater efficiency and consistency.
* **Emulator and Testing Support:** Easily switch to the Firestore emulator or plug in mocks for unit testing.
* **Seamless Integration:** Fits smoothly into any Python project with minimal setup.

---

## Installation

```bash
pip install firestore-pydantic-odm
```

---

## Quick Start

### 1 · Define a model

```python
from firestore_pydantic_odm import BaseFirestoreModel

class User(BaseFirestoreModel):
    class Settings:
        name = "users"      # Firestore collection name

    name: str
    email: str
```

### 2 · Initialise Firestore

```python
from firestore_pydantic_odm import FirestoreDB, BaseFirestoreModel

db = FirestoreDB(project_id="my-project", emulator_host="localhost:8080")  # optional emulator
BaseFirestoreModel.initialize_db(db)
```

### 3 · Async CRUD

```python
user = User(name="Alice", email="alice@example.com")
await user.save()               # CREATE

user.email = "alice@new.com"
await user.update()             # UPDATE

await user.delete()             # DELETE
```

### 4 · Querying & Projections

```python
# Simple filter
async for u in User.find(filters=[User.name == "Alice"]):
    print(u)

# Single document
u = await User.find_one(filters=[User.email == "alice@new.com"])
```

#### Projections — selecting only the fields you need

```python
from pydantic import BaseModel

class UserProjection(BaseModel):
    name: str            # only grab the `name` field

async for u in User.find(
        filters=[User.age >= 18],
        projection=UserProjection):
    print(u.name)        # `u` is an instance of UserProjection

# Fetch a single document with a projection
u = await User.find_one(
        filters=[User.id == "abc123"],
        projection=UserProjection)
```

> **How it works:** the ODM converts `UserProjection` into a Firestore **field mask**, so the RPC fetches *only* the columns defined in that class.
> Each item yielded by `find()` (or returned by `find_one()`) is therefore of type **`UserProjection`**, giving you a clean `List[UserProjection]` with exactly the data requested.

### 5 · Batch writes

```python
from firestore_pydantic_odm import BatchOperation

ops = [
    (BatchOperation.CREATE, User(name="Bob", email="bob@example.com")),
    (BatchOperation.UPDATE, user),            # previously fetched instance
    (BatchOperation.DELETE, another_user)     # instance with `id` set
]
await User.batch_write(ops)
```

---

## Testing

The project ships with `pytest` and `pytest-asyncio` fixtures. To run the suite:

```bash
pytest
```

Set `FIRESTORE_EMULATOR_HOST=localhost:8080` to run tests against the local emulator instead of production Firestore.

---

## Contributing

1. Fork the repository
2. `git checkout -b feature/awesome`
3. Write code & tests; ensure **all tests pass**
4. Open a Pull Request describing your improvements

---

## License

Distributed under the **BSD 3-Clause License**.
See the [`LICENSE`](LICENSE) file for full text.



