Sorting
Define portable sort options and use them across client, server, and table flows.
Sorting definitions map public sort keys to portable sort fields.
Define Sorting
import {
createSortingParser,
defineSorting,
resolveSortingSchema,
sortOption,
} from "@tulip-systems/query";
export const projectSorting = defineSorting({
title: sortOption((direction) => ({ field: "title", direction })),
customerName: sortOption((direction) => ({ field: "customerName", direction })),
createdAt: sortOption((direction) => ({ field: "createdAt", direction })),
});
export const projectSortsSchema = resolveSortingSchema(projectSorting);
export const projectSortingParser = createSortingParser(projectSorting, {
fallback: [{ key: "createdAt", direction: "desc" }],
});The URL/API input shape is an ordered array:
type SortInput = {
key: string;
direction: "asc" | "desc";
};The parsed output uses logical backend fields:
type ParsedSort = {
field: string;
direction: "asc" | "desc";
};Client Hook
Use useSorting(...) anywhere a client component owns sorting state.
import { useSorting } from "@tulip-systems/query/client";
const sorting = useSorting(projectSorting, {
defaults: [{ key: "createdAt", direction: "desc" }],
});The hook returns:
{
input;
query;
setQuery;
defaults;
constraints;
}Use sorting.input in query input. It includes defaults and constraints and is the shape expected by schemas from resolveSortingSchema(...).
Server Compilation
Compile parsed sorts at the backend boundary.
import { createDatabaseSortingCompiler } from "@tulip-systems/query/drizzle";
const parsedSorts = projectSortingParser.parse(input.sorts);
const orderBy = createDatabaseSortingCompiler(projectSorting)({
title: projects.title,
customerName: customers.name,
createdAt: projects.createdAt,
}).parse(parsedSorts);Like filters, sort fields are logical compiler keys. Provider-specific compilers can map them to an external API format instead of SQL.
Table Integration
Pass the sorting controller into table config. The table layer bridges TanStack sorting events back into sorting.setQuery(...).
const sorting = useSorting(projectSorting);
const config = createTableConfig({
queryData: data,
columns,
strategy,
sorting,
});Avoid keeping a separate table-owned sorting query state. Dataset sorting is the source of truth.