mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-11 05:42:19 +00:00
Every sync marked all of an account's analytics cells stale, so the slice re-read the pre-fold remainder (every reading older than five years, folded per source and day, the slice's largest statement on a long history) and the day view re-read its past history blocks, although a sync of today's readings cannot change either. A cache key can now name the instant its value's readings end before (closedBlockKeyPart). invalidateUserMeasurements takes touchedFrom, the earliest measuredAt a write created, changed or removed, and leaves such blocks in place when it is not earlier; without it every block goes as before. The batch route passes it from the identities it wrote. The pre-fold remainder moves into its own module and is cached as a closed block; the day view's past history blocks carry their end, with a day of margin for a night across midnight. The batch route's two up-front reads move into batch-stored-rows.ts with the once-per-batch key rule they share.
50 lines
1.7 KiB
TypeScript
50 lines
1.7 KiB
TypeScript
import { beforeEach, describe, expect, it } from "vitest";
|
|
|
|
import {
|
|
closedBlockKeyPart,
|
|
closedBlockUntouched,
|
|
invalidateUserMeasurements,
|
|
} from "../invalidate";
|
|
import { caches, type ServerCache } from "../server-cache";
|
|
|
|
const analytics = caches.analytics as ServerCache<{ v: number }>;
|
|
|
|
const USER = "u-closed";
|
|
const SPLIT = Date.UTC(2021, 9, 22);
|
|
const closedKey = `${USER}|pre-fold-remainder|${closedBlockKeyPart(SPLIT)}|x`;
|
|
const openKey = `${USER}|dashboard-snapshot|en`;
|
|
|
|
describe("closed analytics blocks", () => {
|
|
beforeEach(() => {
|
|
analytics.deleteByPrefix(`${USER}|`);
|
|
analytics.set(closedKey, { v: 1 });
|
|
analytics.set(openKey, { v: 2 });
|
|
});
|
|
|
|
it("reads the instant a closed block ends before", () => {
|
|
expect(closedBlockUntouched(closedKey, new Date(SPLIT))).toBe(true);
|
|
expect(closedBlockUntouched(closedKey, new Date(SPLIT - 1))).toBe(false);
|
|
expect(closedBlockUntouched(openKey, new Date(SPLIT))).toBe(false);
|
|
});
|
|
|
|
it("survives a write of newer readings, evicting or marking stale", () => {
|
|
for (const evict of [false, true]) {
|
|
invalidateUserMeasurements(USER, {
|
|
evict,
|
|
touchedFrom: new Date(SPLIT + 86_400_000),
|
|
});
|
|
expect(analytics.get(closedKey)).toEqual({ v: 1 });
|
|
expect(analytics.get(openKey)).toBeNull();
|
|
analytics.set(openKey, { v: 2 });
|
|
}
|
|
});
|
|
|
|
it("goes with a write that reaches before it, or does not say", () => {
|
|
invalidateUserMeasurements(USER, { touchedFrom: new Date(SPLIT - 1) });
|
|
expect(analytics.get(closedKey)).toBeNull();
|
|
analytics.set(closedKey, { v: 1 });
|
|
invalidateUserMeasurements(USER);
|
|
expect(analytics.get(closedKey)).toBeNull();
|
|
});
|
|
});
|