from collections.abc import Iterator from contextlib import contextmanager from sqlalchemy.engine import Engine from sqlmodel import Session, create_engine from infrastructure.postgres.config import PostgresConfig def make_engine(config: PostgresConfig) -> Engine: return create_engine( config.url(), pool_size=config.pool_size, max_overflow=config.max_overflow, pool_pre_ping=config.pool_pre_ping, pool_recycle=config.pool_recycle, ) def make_session(engine: Engine) -> Session: return Session(engine) @contextmanager # pyright: ignore[reportDeprecated] def transactional_session(engine: Engine) -> Iterator[Session]: """Yield a session whose lifecycle owns the transaction. On clean exit the session commits; on any exception it rolls back and re-raises. Either way the session is closed. Callers in the application layer can do their work inside the ``with`` block without ever invoking ``.commit()`` / ``.rollback()`` themselves -- transaction semantics stay in the infrastructure layer. """ session = Session(engine) try: yield session session.commit() except Exception: session.rollback() raise finally: session.close()