mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-10 21:32:18 +00:00
perf(charts): wire aggregate=daily for windows beyond a week
The chart fetcher always pulled raw rows from `/api/measurements` — up to ~5 000 pulse samples per range-tab change on a continuous- monitoring account. The server's `aggregate=daily` SQL path lands in v1.4.29 C2; this commit teaches `<HealthChart>` to ask for it on every window over 7 days. Short windows (7-day overview) keep raw fetching so hour-by-hour detail stays visible. Effect on a 30-day pulse view: payload drops from up to ~5 000 rows to one row per day. The client-side `dailyAggregates` Map becomes a no-op on already-bucketed rows. Range test gains two assertions: the default 30-day window asks for `aggregate=daily`; the `windowOverride="last7days"` mini-chart omits the parameter.
This commit is contained in:
1 parent
642e78a6f7
commit
cdc9c5f27f
2 files changed
+39
No files matched your search
@@ -84,6 +84,36 @@ describe("<HealthChart> — bounded range fetch", () => {
|
||||
expect(measurementsUrl!).toMatch(/type=PULSE/);
|
||||
// Guard against the legacy unbounded paginator returning.
|
||||
expect(measurementsUrl!).not.toMatch(/offset=/);
|
||||
// v1.4.29 C3 — the default 30-day window must request server-
|
||||
// side daily aggregation so the client doesn't pay for ~5000
|
||||
// raw pulse rows on every range-tab change.
|
||||
expect(measurementsUrl!).toMatch(/aggregate=daily/);
|
||||
});
|
||||
|
||||
it("omits aggregate=daily on windows of 7 days or fewer", async () => {
|
||||
// v1.4.29 C3 — short windows keep raw fetching so the user can
|
||||
// see hour-by-hour detail on the 7-day view.
|
||||
const { I18nProvider } = await import("@/lib/i18n/context");
|
||||
const { HealthChart } = await import("../health-chart");
|
||||
|
||||
renderToStaticMarkup(
|
||||
<I18nProvider initialLocale="en">
|
||||
<HealthChart
|
||||
types={["PULSE"]}
|
||||
title="Pulse"
|
||||
unit="bpm"
|
||||
windowOverride="last7days"
|
||||
/>
|
||||
</I18nProvider>,
|
||||
);
|
||||
|
||||
await new Promise((resolve) => setTimeout(resolve, 0));
|
||||
|
||||
const measurementsUrl = fetchCalls.find((u) =>
|
||||
u.includes("/api/measurements"),
|
||||
);
|
||||
expect(measurementsUrl).toBeDefined();
|
||||
expect(measurementsUrl!).not.toMatch(/aggregate=daily/);
|
||||
});
|
||||
|
||||
it("re-keys the query when the range window changes", async () => {
|
||||
|
||||
@@ -577,6 +577,15 @@ export function HealthChart({
|
||||
typeParams.set("from", fetchWindow.from);
|
||||
typeParams.set("to", fetchWindow.to);
|
||||
typeParams.set("limit", "5000");
|
||||
// v1.4.29 C3 — windows over 7 days ask the server to bucket
|
||||
// daily. Caps the chart's per-type payload at ~365 rows
|
||||
// instead of ~5 000 for high-density types (pulse), and drops
|
||||
// Recharts paint cost ~50× on continuous-monitoring accounts.
|
||||
// Short windows keep raw fetching so hour-by-hour detail
|
||||
// stays visible.
|
||||
if (fetchWindow.windowDays > 7) {
|
||||
typeParams.set("aggregate", "daily");
|
||||
}
|
||||
|
||||
const res = await fetch(`/api/measurements?${typeParams}`);
|
||||
if (!res.ok) return;
|
||||
|
||||
Reference in new issue
Block a user