mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-09 21:10:59 +00:00
Refuse a first course beside a medication taken continuously
A medication with no course rows and no window is running since its creation; a course added beside it projected the medication into ending, which stopped its reminders and dropped its history from compliance. The create now refuses that (medications.course.currentOpen; End course writes the first course). A window the rows never recorded is materialised as the first course before the new one is checked.
This commit is contained in:
1 parent
1494409209
commit
16c16000e7
2 files changed
+67
-1
No files matched your search
@@ -178,8 +178,41 @@ export async function createCourse(
|
||||
args.userId,
|
||||
args.medicationId,
|
||||
);
|
||||
// A medication without course rows is not empty history. With no window
|
||||
// at all it has been taken continuously since creation and is running
|
||||
// now, so a course cannot be added beside it (it ends its course first,
|
||||
// "End course" writes one). With a window the rows never recorded (a
|
||||
// file restored past the backfill), that window is its first course and
|
||||
// is materialised before the new one is checked against it. Either way
|
||||
// nothing the person already recorded can be cut off by the projection.
|
||||
let existing: { startsOn: Date; endsOn: Date | null }[] = courses;
|
||||
if (courses.length === 0) {
|
||||
if (medication.startsOn === null && medication.endsOn === null) {
|
||||
throw new CourseWriteError("currentOpen");
|
||||
}
|
||||
const implicit = windowAsCourse(
|
||||
medication.startsOn,
|
||||
medication.endsOn,
|
||||
undefined,
|
||||
medication.createdAt,
|
||||
args.timeZone,
|
||||
);
|
||||
refuseIfInvalid(
|
||||
[implicit, { startsOn: args.startsOn, endsOn: args.endsOn }],
|
||||
todayKey,
|
||||
medication.oneShot,
|
||||
);
|
||||
await tx.medicationCourse.create({
|
||||
data: {
|
||||
medicationId: args.medicationId,
|
||||
userId: args.userId,
|
||||
...implicit,
|
||||
},
|
||||
});
|
||||
existing = [implicit];
|
||||
}
|
||||
refuseIfInvalid(
|
||||
[...courses, { startsOn: args.startsOn, endsOn: args.endsOn }],
|
||||
[...existing, { startsOn: args.startsOn, endsOn: args.endsOn }],
|
||||
todayKey,
|
||||
medication.oneShot,
|
||||
);
|
||||
|
||||
@@ -275,6 +275,39 @@ describe("course writes keep the projection", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("never lets a first course cut off a chronic medication's history", async () => {
|
||||
// Taken continuously since creation: no window, no course row. A course
|
||||
// added beside it would project the medication into ending.
|
||||
const chronic = await makeMedication({});
|
||||
const refused = await postCourse(chronic.id, {
|
||||
startsOn: "2026-03-01",
|
||||
endsOn: "2026-03-31",
|
||||
});
|
||||
expect(refused.status).toBe(422);
|
||||
expect((await refused.json()).meta.errorCode).toBe(
|
||||
"medications.course.currentOpen",
|
||||
);
|
||||
expect(await courses(chronic.id)).toEqual([]);
|
||||
expect(await window(chronic.id)).toEqual({ startsOn: null, endsOn: null });
|
||||
|
||||
// A window the rows never recorded (written past the course writer, as
|
||||
// an older restore could) becomes the first course before the new one.
|
||||
const legacy = await makeMedication({});
|
||||
await getPrismaClient().medication.update({
|
||||
where: { id: legacy.id },
|
||||
data: { startsOn: D("2026-01-10"), endsOn: D("2026-01-20") },
|
||||
});
|
||||
const added = await postCourse(legacy.id, {
|
||||
startsOn: "2026-03-01",
|
||||
endsOn: "2026-03-05",
|
||||
});
|
||||
expect(added.status).toBe(201);
|
||||
expect(await courses(legacy.id)).toEqual([
|
||||
["2026-01-10", "2026-01-20"],
|
||||
["2026-03-01", "2026-03-05"],
|
||||
]);
|
||||
});
|
||||
|
||||
it("lets the medication's own PUT edit the latest course", async () => {
|
||||
const med = await makeMedication({
|
||||
startsOn: "2026-03-01",
|
||||
|
||||
Reference in new issue
Block a user