mirror of
https://github.com/RichieCahill/dotfiles.git
synced 2026-04-17 04:58:19 -04:00
60 lines
1.7 KiB
Python
60 lines
1.7 KiB
Python
"""database."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import logging
|
|
from typing import TYPE_CHECKING
|
|
|
|
from sqlalchemy import inspect
|
|
from sqlalchemy.exc import NoInspectionAvailable
|
|
|
|
if TYPE_CHECKING:
|
|
from collections.abc import Sequence
|
|
|
|
from sqlalchemy.orm import Session
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
def safe_insert(orm_objects: Sequence[object], session: Session) -> list[tuple[Exception, object]]:
|
|
"""Safer insert at allows for partial rollbacks.
|
|
|
|
Args:
|
|
orm_objects (Sequence[object]): Tables to insert.
|
|
session (Session): Database session.
|
|
"""
|
|
if unmapped := [orm_object for orm_object in orm_objects if not _is_mapped_instance(orm_object)]:
|
|
error = f"binary_search_insert expects ORM-mapped instances {unmapped}"
|
|
raise TypeError(error)
|
|
return _safe_insert(orm_objects, session)
|
|
|
|
|
|
def _safe_insert(objects: Sequence[object], session: Session) -> list[tuple[Exception, object]]:
|
|
exceptions: list[tuple[Exception, object]] = []
|
|
try:
|
|
session.add_all(objects)
|
|
session.commit()
|
|
|
|
except Exception as error:
|
|
session.rollback()
|
|
|
|
objects_len = len(objects)
|
|
if objects_len == 1:
|
|
logger.exception(objects)
|
|
return [(error, objects[0])]
|
|
|
|
middle = objects_len // 2
|
|
exceptions.extend(_safe_insert(objects=objects[:middle], session=session))
|
|
exceptions.extend(_safe_insert(objects=objects[middle:], session=session))
|
|
return exceptions
|
|
|
|
|
|
def _is_mapped_instance(obj: object) -> bool:
|
|
"""Return True if `obj` is a SQLAlchemy ORM-mapped instance."""
|
|
try:
|
|
inspect(obj) # raises NoInspectionAvailable if not mapped
|
|
except NoInspectionAvailable:
|
|
return False
|
|
else:
|
|
return True
|