Adding pervasive column sorting

This commit is contained in:
Ian Roddis committed 2026-07-31 09:52:09 -03:00
1 parent 34679d53e8
commit 2fb662080b
27 files changed
+614 -111

No files matched your search

+43 -6
View File
@@ -4,9 +4,47 @@ from sqlalchemy.ext.asyncio import AsyncSession
from app.models.associations import augmented_part_imported_parts
from app.models.augmented_part import AugmentedPart
from app.models.imported_part import ImportedPart
from app.models.manufacturer import Manufacturer
from app.models.part_colour import PartColour
from app.models.part_type import PartType
from app.models.scope_model import ScopeModel
from app.models.sub_part_type import SubPartType
_RELATIONSHIPS = ["colour", "manufacturer", "scope_model", "part_type", "sub_part_type"]
# Sortable columns for the admin list, keyed by the query-string "sort" value.
# Columns backed by a related table's name require an outer join (the FK may be
# nullable, e.g. scope_model_id) so unrelated rows still appear, ordered last.
SORT_COLUMNS = {
"id": (AugmentedPart.id, None),
"sku": (AugmentedPart.sku, None),
"description": (AugmentedPart.description, None),
"colour": (PartColour.name, (PartColour, AugmentedPart.colour_id == PartColour.id)),
"manufacturer": (
Manufacturer.name,
(Manufacturer, AugmentedPart.manufacturer_id == Manufacturer.id),
),
"scope_model": (
ScopeModel.name,
(ScopeModel, AugmentedPart.scope_model_id == ScopeModel.id),
),
"part_type": (PartType.name, (PartType, AugmentedPart.part_type_id == PartType.id)),
"sub_part_type": (
SubPartType.name,
(SubPartType, AugmentedPart.sub_part_type_id == SubPartType.id),
),
}
def _apply_sort(q, sort: str, direction: str):
column, join = SORT_COLUMNS.get(sort, SORT_COLUMNS["description"])
if join is not None:
table, cond = join
q = q.outerjoin(table, cond)
order = column.desc() if direction == "desc" else column.asc()
# AugmentedPart.id as a tiebreaker keeps paginated ordering stable.
return q.order_by(order, AugmentedPart.id)
async def get(db: AsyncSession, augmented_part_id: int) -> AugmentedPart | None:
return await db.get(AugmentedPart, augmented_part_id)
@@ -35,9 +73,7 @@ async def get_many(db: AsyncSession, ids: list[int]) -> list[AugmentedPart]:
"""Fetch augmented parts by id in one query (selectin relationships loaded)."""
if not ids:
return []
result = await db.execute(
select(AugmentedPart).where(AugmentedPart.id.in_(ids))
)
result = await db.execute(select(AugmentedPart).where(AugmentedPart.id.in_(ids)))
return list(result.scalars().all())
@@ -49,6 +85,8 @@ async def list_filtered(
scope_model_id: int | None = None,
part_type_id: int | None = None,
sub_part_type_id: int | None = None,
sort: str = "description",
direction: str = "asc",
skip: int = 0,
limit: int = 100,
) -> list[AugmentedPart]:
@@ -65,9 +103,8 @@ async def list_filtered(
q = q.where(AugmentedPart.part_type_id == part_type_id)
if sub_part_type_id is not None:
q = q.where(AugmentedPart.sub_part_type_id == sub_part_type_id)
result = await db.execute(
q.order_by(AugmentedPart.description).offset(skip).limit(limit)
)
q = _apply_sort(q, sort, direction)
result = await db.execute(q.offset(skip).limit(limit))
return list(result.scalars().all())