From 9930bef8aafb09e13e94921c4ee784e5b3c87a94 Mon Sep 17 00:00:00 2001 From: Nathnael Date: Thu, 13 Aug 2026 07:54:44 +0000 Subject: [PATCH] fix(freight-api): quote fallback sort aliases Sorting by a column with no explicit sortExpr fell back to the bare select alias unquoted. Postgres folds unquoted identifiers to lowercase, so any camelCase alias (utilizationPct, bookedTons) 42703'd. Quote the fallback to match the case TypeORM's addSelect actually emitted. --- .../src/modules/reports/report-runner.service.ts | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/apps/edr-freight-api/src/modules/reports/report-runner.service.ts b/apps/edr-freight-api/src/modules/reports/report-runner.service.ts index 5df9ba2e1..09933de42 100644 --- a/apps/edr-freight-api/src/modules/reports/report-runner.service.ts +++ b/apps/edr-freight-api/src/modules/reports/report-runner.service.ts @@ -48,6 +48,15 @@ function coerceParams( return params; } +/** + * Sort expression for a column with no explicit `sortExpr`: the SELECT alias + * TypeORM emitted for it, quoted. TypeORM always double-quotes `addSelect` + * aliases in the generated SQL (preserving case) — ordering by the bare, + * unquoted key instead lets Postgres fold it to lowercase and 42703 on any + * camelCase alias (e.g. "utilizationPct" -> unquoted "utilizationpct"). + */ +const aliasSortExpr = (key: string): string => `"${key.replace(/"/g, '""')}"`; + /** Resolve a client-requested sort column against the report's own whitelist. */ function resolveSort( def: ReportDefinition, @@ -57,14 +66,14 @@ function resolveSort( const dir = sortOrder?.toUpperCase() === 'DESC' ? 'DESC' : 'ASC'; const requested = sortBy && def.columns.find((c) => c.key === sortBy && c.sortable); if (requested) { - return { key: requested.key, expr: requested.sortExpr ?? requested.key, dir }; + return { key: requested.key, expr: requested.sortExpr ?? aliasSortExpr(requested.key), dir }; } if (!def.defaultSort) return null; const fallback = def.columns.find((c) => c.key === def.defaultSort!.key); if (!fallback) return null; return { key: fallback.key, - expr: fallback.sortExpr ?? fallback.key, + expr: fallback.sortExpr ?? aliasSortExpr(fallback.key), dir: def.defaultSort.dir, }; }