Source code for httk.store.backend.postgresql.engine

"""PostgreSQL database construction for :class:`~httk.store.backend.sql.engine.Backend`."""

import importlib
from typing import TYPE_CHECKING

import sqlalchemy

if TYPE_CHECKING:
    from httk.store.backend.sql.engine import Backend


[docs] def database( cls: "type[Backend]", url: str | sqlalchemy.URL, *, database: str | None = None, ) -> "Backend": """Build a PostgreSQL-backed backend from a ``postgresql://`` URL. PostgreSQL is fully transactional and rides the existing ``"transactional"`` write profile with no special-casing. Only the psycopg 3 driver is supported: a bare ``postgresql://`` URL is normalized to ``postgresql+psycopg://`` (SQLAlchemy 2.0 would otherwise select psycopg2), and any other explicit driver is rejected. :param cls: The backend class to instantiate. :param url: PostgreSQL SQLAlchemy URL or URL string. :param database: The database name overriding the URL path, if supplied. :return: The configured PostgreSQL backend wrapper. :raises ImportError: If ``psycopg`` (psycopg 3) is not installed; install the ``httk-store[postgresql]`` extra to use ``Backend.postgresql()``. :raises ValueError: If the URL names a driver other than ``postgresql+psycopg`` (psycopg 3). """ try: importlib.import_module("psycopg") except ImportError as error: raise ImportError( "the PostgreSQL backend needs psycopg (psycopg 3); install the 'httk-store[postgresql]' extra " "to use Backend.postgresql()" ) from error from sqlalchemy.engine import make_url postgres_url = make_url(url) if isinstance(url, str) else url if postgres_url.drivername == "postgresql": postgres_url = postgres_url.set(drivername="postgresql+psycopg") elif postgres_url.drivername != "postgresql+psycopg": raise ValueError( f"Backend.postgresql() supports only the 'postgresql+psycopg' driver (psycopg 3), " f"not {postgres_url.drivername!r}" ) if database is not None: postgres_url = postgres_url.set(database=database) engine = sqlalchemy.create_engine(postgres_url) return cls(engine)