from __future__ import annotations from functools import lru_cache from typing import NamedTuple, Any, Dict, Tuple from sqlalchemy import inspect from sqlalchemy.orm import Mapper class RelInfo(NamedTuple): key: str uselist: bool target_cls: type | None @lru_cache(maxsize=512) def mapper_info(model: type) -> Dict[str, Any]: m: Mapper = inspect(model) cols = tuple(prop.key for prop in m.column_attrs) rels = { r.key: RelInfo(r.key, bool(r.uselist), getattr(r.mapper, "class_", None)) for r in m.relationships } pks = tuple(c.key for c in m.primary_key) table = getattr(model, "__table__", None) return {"cols": cols, "rels": rels, "pks": pks, "table": table} def rel_map(model: type) -> Dict[str, RelInfo]: return mapper_info(model)["rels"] def column_names_for_model(model: type) -> Tuple[str, ...]: return mapper_info(model)["col"]