Source code for fsh_lib.ordering

from dataclasses import dataclass
from typing import TYPE_CHECKING, Any, cast

from fsh_lib._relationships import resolve_sort_target, sort_expr

if TYPE_CHECKING:
    from collections.abc import Sequence

    from pydantic import BaseModel
    from sqlalchemy import Select
    from sqlalchemy.orm import RelationshipProperty

    from fsh_lib._relationships import SortDirection

__all__ = ["OrderKey", "apply_ordering"]


[docs] @dataclass(frozen=True) class OrderKey: field: str direction: SortDirection expr: Any
def apply_ordering( stmt: Select, sort_clauses: Sequence[BaseModel] | None, model: type, default_field: str, default_dir: SortDirection = "asc", ) -> tuple[Select, set[RelationshipProperty], list[OrderKey]]: joined: set[RelationshipProperty] = set() keys: list[OrderKey] = [] def order_by_field( stmt: Select, field: str, direction: SortDirection, ) -> Select: col, join_attr = resolve_sort_target(model, field) if join_attr is not None: rel = cast("RelationshipProperty", join_attr.property) if rel not in joined: joined.add(rel) stmt = stmt.join(join_attr, isouter=True) keys.append(OrderKey(field=field, direction=direction, expr=col)) return stmt.order_by(sort_expr(col, direction)) if not sort_clauses: return ( order_by_field(stmt, default_field, default_dir), joined, keys, ) for clause in sort_clauses: field_enum = getattr(clause, "field", None) if field_enum is None: continue direction: SortDirection = getattr(clause, "direction", "asc") stmt = order_by_field(stmt, field_enum.value, direction) return stmt, joined, keys