Skip to content

Commit 5a99609

Browse files
committed
fix(admin): return day column as text in getCampaignProgression
`postgres.js` returns PG `date` as a string, not a `Date`, which broke the tRPC serializer (`value.toISOString is not a function`). Use `to_char(submitted_at, 'YYYY-MM-DD')` to force a text column and drop the now-unused `toIsoDay` helper.
1 parent c6cda4f commit 5a99609

2 files changed

Lines changed: 13 additions & 18 deletions

File tree

packages/app/src/server/api/routers/__tests__/adminStats.test.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@ type SelectChain = {
1616
orderBy: ReturnType<typeof vi.fn>;
1717
};
1818

19-
function buildDb(rows: Array<{ day: Date; year: number; count: number }> = []) {
19+
function buildDb(
20+
rows: Array<{ day: string; year: number; count: number }> = [],
21+
) {
2022
const orderBy = vi.fn().mockResolvedValue(rows);
2123
const chain: SelectChain = {
2224
from: vi.fn().mockReturnThis(),
@@ -74,10 +76,10 @@ describe("adminStatsRouter.getCampaignProgression", () => {
7476

7577
it("groups points by year and computes a running cumulative total", async () => {
7678
const db = buildDb([
77-
{ day: new Date("2025-01-05T00:00:00Z"), year: 2025, count: 10 },
78-
{ day: new Date("2025-01-06T00:00:00Z"), year: 2025, count: 5 },
79-
{ day: new Date("2026-01-05T00:00:00Z"), year: 2026, count: 20 },
80-
{ day: new Date("2026-01-08T00:00:00Z"), year: 2026, count: 3 },
79+
{ day: "2025-01-05", year: 2025, count: 10 },
80+
{ day: "2025-01-06", year: 2025, count: 5 },
81+
{ day: "2026-01-05", year: 2026, count: 20 },
82+
{ day: "2026-01-08", year: 2026, count: 3 },
8183
]);
8284
const { adminStatsRouter } = await import("../adminStats");
8385
const caller = adminStatsRouter.createCaller({

packages/app/src/server/api/routers/adminStats.ts

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -18,17 +18,7 @@ import { COMPANY_SIZE_RANGES } from "~/modules/domain";
1818
import { adminProcedure, createTRPCRouter } from "~/server/api/trpc";
1919
import { companies, declarations } from "~/server/db/schema";
2020

21-
type AggregatedRow = { day: Date; year: number; count: number };
22-
23-
/**
24-
* Convert a PG `date` cast (returned as `Date` in UTC midnight) to an ISO
25-
* YYYY-MM-DD string suitable for a cross-year chart axis.
26-
*/
27-
function toIsoDay(value: Date): string {
28-
const iso = value.toISOString();
29-
// `2026-02-15T00:00:00.000Z` → `2026-02-15`
30-
return iso.slice(0, 10);
31-
}
21+
type AggregatedRow = { day: string; year: number; count: number };
3222

3323
/**
3424
* Walk the per-day rows (already ordered by (year, day) ASC) and produce one
@@ -44,7 +34,7 @@ function buildSeries(rows: AggregatedRow[]): CampaignProgressionSeries[] {
4434
const list = byYear.get(year) ?? [];
4535
const previous = list[list.length - 1]?.cumulative ?? 0;
4636
list.push({
47-
day: toIsoDay(row.day),
37+
day: row.day,
4838
cumulative: previous + row.count,
4939
});
5040
byYear.set(year, list);
@@ -84,7 +74,10 @@ export const adminStatsRouter = createTRPCRouter({
8474
);
8575
}
8676

87-
const dayExpr = sql<Date>`date_trunc('day', ${declarations.submittedAt})::date`;
77+
// `to_char` forces a text return so the postgres.js driver hands back
78+
// a plain ISO string (YYYY-MM-DD) rather than a `Date` that would then
79+
// need timezone-safe formatting.
80+
const dayExpr = sql<string>`to_char(${declarations.submittedAt}, 'YYYY-MM-DD')`;
8881

8982
const query = ctx.db
9083
.select({

0 commit comments

Comments
 (0)