Skip to main content

Pydantic-typed repository pattern over Supabase (and other backends via the DatabaseManager ABC).

Project description

db_handler

A small, opinionated Python package that wraps Supabase with a Pydantic-typed repository pattern. It consolidates the implementations that previously lived copy-pasted inside several projects (Cyclone, JDBOT, OpinionBlogger, TexasLawBrandEngine — see code_base/ for the originals).

Three pieces:

  • DatabaseManager — abstract base class describing the CRUD surface.
  • SupabaseManager — concrete DatabaseManager backed by Supabase / PostgREST, with retries, JSON-safe payload coercion, duplicate-key handling via KeyError, and a NOT_NULL sentinel.
  • BaseRepository[T] — generic per-table repo bound to a Pydantic model.

Install

This package is not on PyPI. Install directly from GitHub:

pip install "git+https://github.com/tjdaley/db_handler.git"

Pin a tag or commit for reproducibility:

pip install "git+https://github.com/tjdaley/db_handler.git@v0.1.0"

In requirements.txt:

db_handler @ git+https://github.com/tjdaley/db_handler.git@v0.1.0

In pyproject.toml (PEP 508):

dependencies = [
    "db_handler @ git+https://github.com/tjdaley/db_handler.git@v0.1.0",
]

Configuration

SupabaseManager reads credentials from constructor arguments first, then falls back to environment variables:

Setting Constructor arg Env var
Project URL url SUPABASE_URL
Service / anon key key SUPABASE_SERVICE_ROLE_KEY (then SUPABASE_KEY)
from db_handler import SupabaseManager

# from env vars
db = SupabaseManager()

# explicit
db = SupabaseManager(url="https://xxx.supabase.co", key="ey...")

# offline tests — skip the connection probe
db = SupabaseManager(url="...", key="...", verify_connection=False)

Usage

from pydantic import BaseModel
from db_handler import BaseRepository, SupabaseManager, NOT_NULL


class Attorney(BaseModel):
    id: int
    firm_id: int
    name: str
    bar_number: str | None = None


class AttorneyRepo(BaseRepository[Attorney]):
    def __init__(self, manager):
        super().__init__(manager, "attorneys", Attorney)

    # Table-specific helpers go here
    def by_firm_id(self, firm_id: int) -> list[Attorney]:
        rows, _ = self.select_many({"firm_id": firm_id})
        return rows

    def with_bar_number(self) -> list[Attorney]:
        rows, _ = self.select_many({"bar_number": NOT_NULL})
        return rows


db = SupabaseManager()
attorneys = AttorneyRepo(db)

attorney = attorneys.insert({"firm_id": 17, "name": "Atticus Finch"})
fetched = attorneys.select_one({"id": attorney.id})
attorneys.update(attorney.id, {"bar_number": "TX-123456"})
attorneys.delete(attorney.id)

Filtering

select_one / select_many accept a condition dict. Values map as follows:

Value Translates to
scalar (int, str, ...) field = value
None field IS NULL
NOT_NULL field IS NOT NULL
list / tuple / set field IN (...)

Upsert

attorneys.upsert(
    {"firm_id": 17, "name": "Atticus Finch", "bar_number": "TX-123456"},
    on_conflict="bar_number",
)

Duplicate keys

insert raises KeyError on a unique-constraint violation, with the offending column and value parsed from the PostgREST error detail.

JSON-safe payloads

insert / upsert / update automatically coerce datetime, date, Enum, UUID, and Decimal values (recursively, including inside nested dicts/lists) so that PostgREST can serialize them.

Logging

The library uses logging.getLogger("db_handler.*") and does not mutate log levels of httpx or postgrest. Configure those in your application:

import logging
logging.getLogger("db_handler").setLevel(logging.INFO)
logging.getLogger("httpx").setLevel(logging.WARNING)
logging.getLogger("postgrest").setLevel(logging.WARNING)

Adding a new backend

Implement DatabaseManager for any backend; repositories don't care:

from db_handler import DatabaseManager, BaseRepository

class SqliteManager(DatabaseManager):
    ...

repo = BaseRepository(SqliteManager(...), "attorneys", Attorney)

Repo layout

db_handler/
├── pyproject.toml
├── README.md
├── LICENSE
├── src/
│   └── db_handler/
│       ├── __init__.py
│       ├── manager.py            # DatabaseManager + NOT_NULL
│       ├── supabase_manager.py   # SupabaseManager
│       ├── repository.py         # BaseRepository
│       ├── _json.py              # json_safe coercion
│       └── py.typed

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

tjd_db_handler-0.1.2.tar.gz (9.9 kB view details)

Uploaded Source

Built Distribution

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

tjd_db_handler-0.1.2-py3-none-any.whl (10.0 kB view details)

Uploaded Python 3

File details

Details for the file tjd_db_handler-0.1.2.tar.gz.

File metadata

  • Download URL: tjd_db_handler-0.1.2.tar.gz
  • Upload date:
  • Size: 9.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for tjd_db_handler-0.1.2.tar.gz
Algorithm Hash digest
SHA256 128c03aa8d66e13266474e7f2d0387344a963c1937dfa3e54eaff6aba0b0a7c3
MD5 debb406907fd5ed3f228349aa2fe769b
BLAKE2b-256 125c7eef8a3e22173674d32fa9340a1d7fe5eddbf00ecd4fd7d2f8ee9336d074

See more details on using hashes here.

Provenance

The following attestation bundles were made for tjd_db_handler-0.1.2.tar.gz:

Publisher: publish.yaml on tjdaley/db_handler

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file tjd_db_handler-0.1.2-py3-none-any.whl.

File metadata

  • Download URL: tjd_db_handler-0.1.2-py3-none-any.whl
  • Upload date:
  • Size: 10.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for tjd_db_handler-0.1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 85f101c73bd2c026fdd5465002757823c94243bdfc681df94f516b08394171b6
MD5 98595e3ce6e808147e342c7b165aee55
BLAKE2b-256 ff33fbdd9ef1f53b7ff7e3957f76d8ba3d7d7540a5688c5b26e4bfa7deb54ba5

See more details on using hashes here.

Provenance

The following attestation bundles were made for tjd_db_handler-0.1.2-py3-none-any.whl:

Publisher: publish.yaml on tjdaley/db_handler

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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