Sorting¶
Therismos provides a sorting system for modeling sort criteria as object structures, similar to how expressions model filters.
Quick Start¶
from therismos.sorting import SortSpec, SortCriterion, SortOrder
spec = SortSpec([
SortCriterion("age", SortOrder.DESCENDING),
SortCriterion("name", SortOrder.ASCENDING),
])
from therismos.sorting.visitors import StringVisitor
print(spec.accept(StringVisitor()))
# "age DESC, name ASC"
Sort Orders¶
| Value | Meaning |
|---|---|
SortOrder.ASCENDING (1) |
Sort in ascending order |
SortOrder.DESCENDING (-1) |
Sort in descending order |
SortOrder.NONE (0) |
No sorting — filtered out during optimization |
Creating Sort Specifications¶
spec = SortSpec([
SortCriterion("created_at", SortOrder.DESCENDING),
SortCriterion("priority", SortOrder.ASCENDING),
SortCriterion("name", SortOrder.ASCENDING),
])
spec.append(SortCriterion("id", SortOrder.ASCENDING))
print(len(spec)) # 4
Optimization¶
Removes NONE criteria and keeps only the last occurrence of each field:
from therismos.sorting.optimizer import optimize
spec = SortSpec([
SortCriterion("age", SortOrder.ASCENDING),
SortCriterion("name", SortOrder.NONE), # removed
SortCriterion("age", SortOrder.DESCENDING), # overrides first "age"
])
optimized, records = optimize(spec)
# SortSpec([SortCriterion("age", SortOrder.DESCENDING)])
for record in records:
print(record.reason)
Optimization rules:
- Remove NONE orders: Criteria with
SortOrder.NONEare removed - Remove redundant criteria: When a field appears multiple times, only the last occurrence is kept
Built-in Visitors¶
from therismos.sorting.visitors import StringVisitor, DictVisitor, FieldGathererVisitor
spec = SortSpec([
SortCriterion("age", SortOrder.DESCENDING),
SortCriterion("name", SortOrder.ASCENDING),
])
print(spec.accept(StringVisitor()))
# "age DESC, name ASC"
result = spec.accept(DictVisitor())
# [{"field": "age", "order": "DESC"}, {"field": "name", "order": "ASC"}]
field_visitor = FieldGathererVisitor()
spec.accept(field_visitor)
print(field_visitor.field_names)
# {"age", "name"}
Custom Visitors¶
from therismos.sorting import SortCriterion, SortSpec
class SQLVisitor:
def visit_sort_criterion(self, criterion: SortCriterion) -> str:
order_str = "ASC" if criterion.order == SortOrder.ASCENDING else "DESC"
return f"{criterion.field} {order_str}"
def visit_sort_spec(self, spec: SortSpec) -> str:
if not spec:
return ""
parts = [criterion.accept(self) for criterion in spec]
return "ORDER BY " + ", ".join(parts)
result = spec.accept(SQLVisitor())
# "ORDER BY created_at DESC, name ASC"