Skip to main content

Minimal, explicit Repository & Unit-of-Work layer over SQLAlchemy 2.x

This project has been archived.

The maintainers of this project have marked this project as archived. No new releases are expected.

Project description

SARepo

Minimal, explicit Repository + Unit of Work layer on top of SQLAlchemy 2.x (sync & async).
No magic method names — just clean typed APIs, composable specs, pagination, and optional soft-delete.


🚀 Quick Start (Sync)

from sqlalchemy import create_engine, String
from sqlalchemy.orm import sessionmaker, DeclarativeBase, Mapped, mapped_column

from SARepo.sa_repo import SARepository
from SARepo.base import PageRequest
from SARepo.specs import and_specs, ilike


class Base(DeclarativeBase):
    pass


class Request(Base):
    __tablename__ = "requests"

    id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
    title: Mapped[str] = mapped_column(String(255))
    status: Mapped[str] = mapped_column(String(50))


# Setup database
engine = create_engine("sqlite+pysqlite:///:memory:", echo=False)
Base.metadata.create_all(engine)
SessionLocal = sessionmaker(bind=engine, expire_on_commit=False)

# Usage
with SessionLocal() as session:
    repo = SARepository(Request, session)

    # Create
    r = repo.add(Request(title="Hello", status="NEW"))
    session.commit()

    # Query + Paginate
    page = repo.page(PageRequest(0, 10), spec=ilike(Request.title, "%He%"))
    print(page.total, [i.title for i in page.items])

⚙️ Async Quick Start

import asyncio
from sqlalchemy.ext.asyncio import create_async_engine, async_sessionmaker

from SARepo.sa_repo import SAAsyncRepository
from SARepo.base import PageRequest


async def main():
    engine = create_async_engine("sqlite+aiosqlite:///:memory:", echo=False)
    async with engine.begin() as conn:
        await conn.run_sync(Base.metadata.create_all)

    SessionLocal = async_sessionmaker(bind=engine, expire_on_commit=False)

    async with SessionLocal() as session:
        repo = SAAsyncRepository(Request, session)

        await repo.add(Request(title="Hello", status="NEW"))
        await session.commit()

        page = await repo.page(PageRequest(0, 10))
        print(page.total)


asyncio.run(main())

🧠 Features

SARepository / SAAsyncRepository

  • Clean CRUD operations (get, add, update, remove, etc.)
  • page() method with total count

Composable Specs

  • Combine filters easily (eq, ilike, and_specs, not_deleted)

Soft Delete

  • Automatically filters out rows with is_deleted=True if the model has this column

Typed Protocol Interface

  • CrudRepository protocol for structural typing & IDE autocompletion

Unit of Work

  • Minimal sync & async helpers for transactional operations

🧩 Example: Spec Composition

from SARepo.specs import eq, ilike, and_specs

spec = and_specs(
    eq(Request.status, "NEW"),
    ilike(Request.title, "%Hello%")
)

page = repo.page(PageRequest(0, 10), spec=spec)

📜 License

MIT License
Copyright (c) 2025


🧭 Project Structure (Example)

SARepo/
│
├── sa_repo.py         # Core Repository classes (sync & async)
├── base.py            # Pagination, PageRequest, DTO helpers
├── specs.py           # Composable query specs
├── uow.py             # Optional Unit of Work layer
├── __init__.py

✅ Philosophy

  • No ORM “magic” — only explicit SQLAlchemy 2.0 APIs
  • One repository → one model
  • Predictable transaction scope
  • Works with Pydantic DTOs or dataclasses
  • 100 % type-safe

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

sarepo-0.1.8.tar.gz (11.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

sarepo-0.1.8-py3-none-any.whl (10.0 kB view details)

Uploaded Python 3

File details

Details for the file sarepo-0.1.8.tar.gz.

File metadata

  • Download URL: sarepo-0.1.8.tar.gz
  • Upload date:
  • Size: 11.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.7

File hashes

Hashes for sarepo-0.1.8.tar.gz
Algorithm Hash digest
SHA256 954c3e41babb54ee3f2e389dc81c4fea1a219e3b5f5141e91e0bf81e4490f74f
MD5 fb91fd7246a93d4cb4b0795f7b63893c
BLAKE2b-256 2b1866d2437fbcbc460e668d5add8e0c66528f5d1788fd0163a380b40fd678e5

See more details on using hashes here.

File details

Details for the file sarepo-0.1.8-py3-none-any.whl.

File metadata

  • Download URL: sarepo-0.1.8-py3-none-any.whl
  • Upload date:
  • Size: 10.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.7

File hashes

Hashes for sarepo-0.1.8-py3-none-any.whl
Algorithm Hash digest
SHA256 ff4492e894e1477ba192b6a216d2e27b90557e60acc48c5f188d59a2a29a170e
MD5 92afa9e037c6128f5421426099a5f2c4
BLAKE2b-256 1f9b88b1802b1b7edd63bb08f0168b4b415420b100b5658d3e0bdfe496704a35

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page