mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-12 14:16:12 +00:00
ensureDbCompatibility ran ALTER TABLE / CREATE TABLE IF NOT EXISTS on the login, register, token and session paths, mirroring columns every migration under prisma/migrations already creates. The entrypoint applies those migrations before the server listens and stops the boot when one fails, so the mirror never had work to do, and DDL on a request path needs the table's owner: a connection that may only read and write rows fails every login on it. Drop the module, its call sites and the mocks that stubbed it out.
101 lines
3.0 KiB
TypeScript
101 lines
3.0 KiB
TypeScript
/**
|
|
* v1.42 — the timeline's long windows read the rolled-up months from the
|
|
* month the rollup fold boundary falls in, whatever the account's zone.
|
|
* Against Postgres.
|
|
*
|
|
* The rollup tier keys its months by the UTC calendar. West of UTC the local
|
|
* midnight of the boundary month comes hours after that month's UTC start, so
|
|
* a read from the local midnight left the month out: a gap in a month series,
|
|
* and a quarter averaged over two of its three months.
|
|
*/
|
|
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
|
|
import { getPrismaClient, truncateAllTables } from "./setup";
|
|
|
|
/**
|
|
* Five years before this the fold boundary falls on 2021-10-10, so the first
|
|
* rolled-up month is November 2021 and the first rolled-up quarter Q1 2022.
|
|
*/
|
|
const NOW = new Date("2026-10-09T12:00:00.000Z");
|
|
const TZ = "America/New_York";
|
|
const USER = "timeline-west";
|
|
|
|
beforeEach(async () => {
|
|
await truncateAllTables(getPrismaClient());
|
|
vi.useFakeTimers({ toFake: ["Date"] });
|
|
vi.setSystemTime(NOW);
|
|
await getPrismaClient().user.create({
|
|
data: {
|
|
id: USER,
|
|
username: USER,
|
|
email: `${USER}@example.test`,
|
|
timezone: TZ,
|
|
},
|
|
});
|
|
});
|
|
|
|
afterEach(() => {
|
|
vi.useRealTimers();
|
|
});
|
|
|
|
/** One DAY rollup row of resting heart rate per `[UTC date, mean, count]`. */
|
|
async function seedDays(days: Array<[string, number, number]>) {
|
|
await getPrismaClient().measurementRollup.createMany({
|
|
data: days.map(([date, mean, count]) => ({
|
|
userId: USER,
|
|
type: "RESTING_HEART_RATE" as const,
|
|
granularity: "DAY" as const,
|
|
bucketStart: new Date(`${date}T00:00:00.000Z`),
|
|
source: "APPLE_HEALTH" as const,
|
|
count,
|
|
mean,
|
|
minValue: mean,
|
|
maxValue: mean,
|
|
sumValue: mean * count,
|
|
})),
|
|
});
|
|
}
|
|
|
|
async function series(bucket: "month" | "quarter") {
|
|
const { loadTimelineSeries } = await import("@/lib/timeline/series");
|
|
const [out] = await loadTimelineSeries({
|
|
userId: USER,
|
|
keys: ["RESTING_HEART_RATE"],
|
|
from: "2016-10-09",
|
|
to: "2026-10-09",
|
|
tz: TZ,
|
|
bucket,
|
|
priorityJson: null,
|
|
now: NOW,
|
|
});
|
|
return out?.points ?? [];
|
|
}
|
|
|
|
describe("timeline rollup months west of UTC", () => {
|
|
it("keeps the first rolled-up month after the fold boundary", async () => {
|
|
await seedDays([
|
|
["2021-11-05", 60, 2],
|
|
["2021-12-05", 62, 2],
|
|
["2022-01-05", 64, 2],
|
|
]);
|
|
const points = await series("month");
|
|
expect(points).toEqual([
|
|
{ t: "2021-11-01", mean: 60, count: 2 },
|
|
{ t: "2021-12-01", mean: 62, count: 2 },
|
|
{ t: "2022-01-01", mean: 64, count: 2 },
|
|
]);
|
|
});
|
|
|
|
it("averages the first rolled-up quarter over all three of its months", async () => {
|
|
await seedDays([
|
|
["2022-01-05", 60, 1],
|
|
["2022-02-05", 63, 1],
|
|
["2022-02-06", 63, 1],
|
|
["2022-03-05", 66, 1],
|
|
]);
|
|
const points = await series("quarter");
|
|
// Each month weighs its days: (60 + 63 + 63 + 66) / 4.
|
|
expect(points).toEqual([{ t: "2022-01-01", mean: 63, count: 4 }]);
|
|
});
|
|
});
|