import z from "zod/v4"; import { OrderByState } from "../../../interfaces/orderBy"; import { UiColumnMappings } from "../../../tableDefinitions"; import { logger } from "../../logger"; type OrderByStateNotNull = Exclude; export function orderByToClickhouseSql( orderBy: OrderByState | OrderByState[] = [], tableColumns: UiColumnMappings, usedInAggregation = false, ): string { if ( !orderBy || (Array.isArray(orderBy) && orderBy.filter(Boolean).length === 0) ) { return ""; } if (!Array.isArray(orderBy)) { orderBy = [orderBy]; } // Initialize an array to hold order by clauses const orderByClauses: string[] = []; // Loop through each orderBy entry for (const ob of orderBy.filter((o): o is OrderByStateNotNull => Boolean(o), )) { // Get column definition to map column to internal name, e.g. "t.id" const col = tableColumns.find( (c) => c.uiTableName === ob.column || c.uiTableId === ob.column, ); if (!col) { logger.warn("Invalid order by column", ob.column); throw new Error("Invalid order by column: " + ob.column); } // Assert that ob.order is either "asc" or "desc" const orderByOrder = z.enum(["ASC", "DESC"]); const order = orderByOrder.safeParse(ob.order); if (!order.success) { logger.warn("Invalid order", ob.order); throw new Error("Invalid order: " + ob.order); } const column = `${col.queryPrefix ? col.queryPrefix + "." : ""}${col.clickhouseSelect}`; // Append the order by clause to the array orderByClauses.push( `${usedInAggregation ? `anyLast(${column})` : column} ${order.data}`, ); } // Join all order by clauses with a comma and return return `ORDER BY ${orderByClauses.join(", ")}`; }