test(measurements): group the hourly-mean fake once instead of per day

The in-memory day-aggregate fake re-filtered every row for every day,
converting each timestamp to the profile timezone again, so a 1000-day
series took about five seconds and the graded pulse-status test hit its
timeout. It now groups by day and segment in one pass (4.8 s to 85 ms).
This commit is contained in:
Marc-André Bombeck committed 2026-10-04 16:14:10 +02:00
1 parent 57c7cf8be9
commit 28046f05f7
1 file changed
+24 -15
@@ -81,22 +81,31 @@ export async function fakeReadDayAggregates(
// Mirror the SQL's hourly-mean day: the mean of the (day, segment)'s local
// hours' means.
const starts = opts.segmentStarts ?? [];
// Group once by (day, segment) with the fold's own filters, so a long
// series stays linear instead of re-filtering every row per day.
const membersByKey = new Map<
string,
Array<{ measuredAt: Date; value: number }>
>();
for (const r of rows) {
const t = r.measuredAt.getTime();
if (t < opts.since.getTime()) continue;
if (opts.until && t > opts.until.getTime()) continue;
if (
opts.valueRange &&
(r.value < opts.valueRange.min || r.value > opts.valueRange.max)
) {
continue;
}
const key = `${userDayKey(r.measuredAt, opts.timeZone)}|${
starts.filter((st) => t < st.getTime()).length
}`;
const list = membersByKey.get(key);
if (list) list.push(r);
else membersByKey.set(key, [r]);
}
return days.map((d) => {
const members = rows.filter((r) => {
const t = r.measuredAt.getTime();
if (t < opts.since.getTime()) return false;
if (opts.until && t > opts.until.getTime()) return false;
if (
opts.valueRange &&
(r.value < opts.valueRange.min || r.value > opts.valueRange.max)
) {
return false;
}
return (
userDayKey(r.measuredAt, opts.timeZone) === d.day &&
starts.filter((s) => t < s.getTime()).length === d.segment
);
});
const members = membersByKey.get(`${d.day}|${d.segment}`) ?? [];
const dayMean = dayValue(opts.type, members, opts.timeZone);
return dayMean === null ? d : { ...d, dayMean };
});