Source code for scgo.database.transactions

"""Simple transaction helpers for SCGO databases."""

from __future__ import annotations

import sqlite3
from collections.abc import Generator
from contextlib import contextmanager

from ase_ga.data import DataConnection

from scgo.exceptions import (
    SCGOValidationError,
)
from scgo.utils.logging import get_logger

logger = get_logger(__name__)


_VALID_ISOLATION_LEVELS = frozenset({"DEFERRED", "IMMEDIATE", "EXCLUSIVE"})


[docs] @contextmanager def database_transaction( db: DataConnection, isolation_level: str = "DEFERRED", ) -> Generator[sqlite3.Connection, None, None]: """Context manager for a transaction. Yields: sqlite3.Connection: Raw connection. Commits on success; rolls back on error. """ if not hasattr(db, "c") or db.c is None: raise SCGOValidationError("Invalid database connection") if isolation_level.upper() not in _VALID_ISOLATION_LEVELS: raise SCGOValidationError( f"Invalid isolation level: {isolation_level!r}. " f"Must be one of {sorted(_VALID_ISOLATION_LEVELS)}" ) # Use managed_connection() to get actual SQLite connection with db.c.managed_connection() as conn: try: conn.execute(f"BEGIN {isolation_level.upper()}") logger.debug(f"Started {isolation_level} transaction") yield conn # Yield connection instead of db conn.commit() logger.debug("Transaction committed") except Exception: conn.rollback() logger.debug("Transaction rolled back") raise