fix(labs): store the catalog slug as a marker's analyte key

The matcher stored the registry entry's key, so LDL and HDL markers were
recorded as total-cholesterol. The key now names what the marker is (the
catalog slug, or a registry-only key for an analyte with no seed), and the
registry resolves ldl and hdl to the cholesterol entry for the conversion as
before. A key already written in the old form is rewritten by the same fill
step that brings a stale key in line with its name, the first time a reading
needs it. The OpenAPI descriptions say what the key is and that it follows
the marker's name and unit.
This commit is contained in:
Marc-André Bombeck committed 2026-10-14 19:18:49 +02:00
1 parent cd1449e63e
commit 07f09e1b61
11 files changed
+91 -33

No files matched your search

@@ -88,6 +88,33 @@ describe("POST /api/biomarkers", () => {
expect(data.analyteKey).toBe("total-cholesterol");
});
it("stores the catalog slug for LDL and HDL, and converts them as cholesterol", async () => {
for (const [name, key] of [
["LDL cholesterol", "ldl"],
["HDL-Cholesterin", "hdl"],
]) {
const res = await post({ name, unit: "mg/dL" });
const { data } = (await res.json()) as { data: { analyteKey: string } };
expect(data.analyteKey, name).toBe(key);
}
const ldl = await prisma.biomarker.findFirstOrThrow({
where: { userId: USER, name: "LDL cholesterol" },
});
const reading = await postReading({
biomarkerId: ldl.id,
value: 3,
unit: "mmol/L",
takenAt: "2026-05-04T08:00:00.000Z",
});
expect(reading.status).toBe(201);
const { data: dto } = (await reading.json()) as {
data: { value: number; converted: boolean };
};
expect(dto.converted).toBe(true);
// 3 mmol/L x 38.6664 (C27H46O, 386.664 g/mol).
expect(dto.value.toFixed(2)).toBe("116.00");
});
it("leaves a free name, and a known name in an unreachable unit, unlinked", async () => {
for (const [name, unit] of [
["My own marker", "mg/dL"],
@@ -277,6 +304,24 @@ describe("ensureAnalyteKey", () => {
).toBe("urea");
});
it("corrects a key stored as the registry entry rather than the catalog slug", async () => {
// Before the slug was stored, an LDL marker got the cholesterol entry's
// key. Same conversion, wrong identity; the fill step rewrites it once.
const marker = await prisma.biomarker.create({
data: {
userId: USER,
name: "LDL-Cholesterin",
unit: "mg/dL",
analyteKey: "total-cholesterol",
},
});
expect(await ensureAnalyteKey(prisma, marker)).toBe("ldl");
const row = await prisma.biomarker.findUnique({ where: { id: marker.id } });
expect(row?.analyteKey).toBe("ldl");
// And a second run changes nothing.
expect(await ensureAnalyteKey(prisma, row!)).toBe("ldl");
});
it("converges when two callers fill the same marker", async () => {
const marker = await prisma.biomarker.create({
data: { userId: USER, name: "Kreatinin", unit: "mg/dL" },