Source code for ingot.ordering

"""ORDER BY application from typed Pydantic sort clauses."""

from __future__ import annotations

from typing import TYPE_CHECKING, Any, Literal

if TYPE_CHECKING:
    from collections.abc import Sequence

    from pydantic import BaseModel
    from sqlalchemy import Select


SortDirection = Literal["asc", "desc"]
"""Direction keys accepted by a sort clause's ``dir`` field.

Callers' Pydantic sort-clause models should declare ``dir`` as
a ``Literal`` over this set (or use this alias directly).
"""


[docs] def apply_ordering( stmt: Select, sort_clauses: Sequence[BaseModel] | None, model: type, default_field: str, default_dir: SortDirection = "asc", ) -> Select: """Apply one or more sort clauses to a SELECT statement. Each clause is a Pydantic model with ``field`` (an enum whose ``.value`` is the column name) and ``dir`` (:data:`SortDirection`). When *sort_clauses* is ``None`` or empty, the default field and direction are used. Args: stmt: The SQLAlchemy SELECT statement to sort. sort_clauses: List of sort clause models, or ``None``. model: The SQLAlchemy model class providing columns. default_field: Column name to sort by when no clauses are provided. default_dir: Direction for the default sort. Returns: The statement with ORDER BY applied. """ if not sort_clauses: default_col = getattr(model, default_field) return stmt.order_by(_sort_expr(default_col, default_dir)) for clause in sort_clauses: field_enum = getattr(clause, "field", None) if field_enum is None: continue direction: SortDirection = getattr(clause, "dir", "asc") col = getattr(model, field_enum.value) stmt = stmt.order_by(_sort_expr(col, direction)) return stmt
def _sort_expr(col: Any, direction: SortDirection) -> Any: """Wrap *col* in the given sort direction. Args: col: A SQLAlchemy column. direction: ``"asc"`` or ``"desc"``. Returns: ``col.asc()`` or ``col.desc()``. """ return col.desc() if direction == "desc" else col.asc()