Repository with mixins, templates, and utilities for work with SQLAlchemy
Project description
Alchemist CeRBeR library
This repository layer implements a flexible, reusable, and type-safe ORM interaction system using SQLAlchemy, Python type hints*, and mixin-based composition. It supports both synchronous and asynchronous operations and provides a clean abstraction over database queries.
📦 Key Features
- Mixin-based architecture for reusable logic
- Synchronous and asynchronous implementations
- Type-safe ORM interactions using Pydantic and SQLAlchemy ORM
- Sorting, filtering, and joining capabilities
- Error handling with custom exceptions
- Unit of Work pattern for transaction management
- Support for filters using dynamic operators (
eq,lt,in,between, etc.)
📚 Usage Example
1. Define ORM Models
import uuid
from datetime import UTC, datetime
from sqlalchemy import DateTime, ForeignKey
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship
class Base(DeclarativeBase):
pass
class User(Base):
__tablename__ = "users"
id: Mapped[str] = mapped_column(primary_key=True, default=lambda: str(uuid.uuid4()))
name: Mapped[str] = mapped_column(nullable=False)
age: Mapped[int] = mapped_column(nullable=True)
email: Mapped[str] = mapped_column(nullable=False, unique=True)
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=datetime.now(UTC), nullable=False)
posts: Mapped[list["Post"]] = relationship(back_populates="author", cascade="all, delete-orphan")
class Post(Base):
__tablename__ = "posts"
id: Mapped[str] = mapped_column(primary_key=True, default=lambda: str(uuid.uuid4()))
title: Mapped[str] = mapped_column(nullable=False)
content: Mapped[str] = mapped_column(nullable=False)
author_id: Mapped[str] = mapped_column(ForeignKey("users.id"), nullable=False)
author: Mapped["User"] = relationship(back_populates="posts")
2. Build a Repository
from alchemist_cerber.mixins.readable import AsyncRepositoryGetMultiMixin, AsyncRepositoryGetOneMixin
from alchemist_cerber.utils.base import OrmModelT
from sqlalchemy.ext.asyncio import AsyncSession
class UserRepository(
AsyncRepositoryGetMultiMixin[User],
AsyncRepositoryGetOneMixin[User],
):
_orm_model = User
def __init__(self, session: AsyncSession):
super().__init__(session)
3. Use the Repository
from alchemist_cerber.schemas import ColumnFilter, SortingItem
from alchemist_cerber.constants import AlchemyOperator
filters = [
ColumnFilter(column=User.age, value=18, operator=AlchemyOperator.GT),
ColumnFilter(column=User.name, value="Alice", operator=AlchemyOperator.EQ),
]
sorting = [SortingItem(field_name="age", is_asc=False)]
users = await user_repo.get_multi(
limit=10,
offset=0,
orm_filters=tuple(filters),
sort_params=tuple(sorting),
)
4. Configure Join Related Models
Override _use_join() in your repository to eager-load related data:
from sqlalchemy.orm import joinedload
from sqlalchemy import Select
class PostRepository(AsyncRepositoryGetMultiMixin[Post]):
_orm_model = Post
@staticmethod
def _use_join(current_statement: Select[tuple[Post]]) -> Select[tuple[Post]]:
return current_statement.options(joinedload(Post.author))
5. Use Unit of Work for Transactions
from repository.units_of_work import AsyncUnitOfWorkManager
async with AsyncUnitOfWorkManager(session_factory) as uow:
user_repo = UserRepository(uow.session)
post_repo = PostRepository(uow.session)
user = await user_repo.get_one_unique(...)
await post_repo.save(...)
await uow.commit()
🛠️ Development Setup
This project uses Poetry for dependency management, Ruff for linting and formatting, mypy for type checking, and pytest for testing.
1. Install Dependencies
To install all required dependencies and set up the environment:
make init
This will:
- Install all dependencies via
poetry install - Copy
.env.exampleto.env
2. Formatting Code
To format and sort imports:
make format
This will:
- Sort
pyproject.tomlkeys - Fix import order with
ruff - Auto-format code using
ruff format
3. Linting & Type Checking
To lint and type-check the code:
make lint
This will:
- Run
rufffor linting (flake8-compatible, fast) - Run
mypyfor static type checking
4. Running Tests
To run tests:
make test
This will:
- Run all tests using
pytest
🧰 Tools Used
| Tool | Purpose |
|---|---|
| Poetry | Dependency management |
| Ruff | Linting & formatting |
| mypy | Static type checking |
| pytest | Testing framework |
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file alchemist_cerber-0.1.1.tar.gz.
File metadata
- Download URL: alchemist_cerber-0.1.1.tar.gz
- Upload date:
- Size: 8.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/2.3.2 CPython/3.12.12 Linux/6.11.0-1018-azure
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2212f66eb46c2e512e5875c1267bbe90d89f9e019e0406b8634c28b2fcf8fc50
|
|
| MD5 |
532a5138cd1bd210d95d9dc086e23e57
|
|
| BLAKE2b-256 |
0ddf20b3b7c5e83241dcf04782185ae27ee767e1983e4b1b2df348aabb4bc326
|
File details
Details for the file alchemist_cerber-0.1.1-py3-none-any.whl.
File metadata
- Download URL: alchemist_cerber-0.1.1-py3-none-any.whl
- Upload date:
- Size: 10.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/2.3.2 CPython/3.12.12 Linux/6.11.0-1018-azure
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
84fca195579557aa0f1af8ebe57c2cd097bd365e1170ad2554c17422a859fb51
|
|
| MD5 |
6b0fd7aa5d502eb7a685c78b0c6d082a
|
|
| BLAKE2b-256 |
88d34f735268ff5fd51dde83ba2505e457295d0bac3aef7f34f056dcc14bd689
|