mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-13 14:32:03 +00:00
fix(medications): report the dose-history window doses were read over
The dose-history response reported the slot window: `from` clamped to the medication's creation, `to` the request's end. Recorded doses are now read from the requested start and, for a dose recorded ahead of its slot, up to that slot, so the response reported a narrower window than the rows it carried. `from` and `to` now report the window recorded doses were read over. Both fields keep their shape; the OpenAPI descriptions say what they mean. Refs #1028
This commit is contained in:
1 parent
c41df33dd3
commit
3170a622d1
4 files changed
+37
-12
No files matched your search
+11
-6
@@ -5961,21 +5961,23 @@ paths:
|
||||
- in: query
|
||||
name: from
|
||||
schema:
|
||||
description: Window start (inclusive). Defaults to 90 days before `to`; clamped to the medication's `createdAt` and a
|
||||
366-day span floor.
|
||||
description: Window start (inclusive). Defaults to 90 days before `to`; clamped to a 366-day span floor. Recorded doses
|
||||
are returned from this instant; expected slots are not minted before the medication's `createdAt`.
|
||||
type: string
|
||||
format: date-time
|
||||
pattern: ^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d(?:\.\d+)?)?(?:Z|([+-](?:[01]\d|2[0-3]):[0-5]\d)))$
|
||||
description: Window start (inclusive). Defaults to 90 days before `to`; clamped to the medication's `createdAt` and a
|
||||
366-day span floor.
|
||||
description: Window start (inclusive). Defaults to 90 days before `to`; clamped to a 366-day span floor. Recorded doses
|
||||
are returned from this instant; expected slots are not minted before the medication's `createdAt`.
|
||||
- in: query
|
||||
name: to
|
||||
schema:
|
||||
description: Window end (inclusive). Defaults to now. Must be ≥ `from`.
|
||||
description: Window end (inclusive). Defaults to now. Must be ≥ `from`. A dose recorded ahead of its slot (the slot's
|
||||
time within a day after `to`) is still returned.
|
||||
type: string
|
||||
format: date-time
|
||||
pattern: ^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d(?:\.\d+)?)?(?:Z|([+-](?:[01]\d|2[0-3]):[0-5]\d)))$
|
||||
description: Window end (inclusive). Defaults to now. Must be ≥ `from`.
|
||||
description: Window end (inclusive). Defaults to now. Must be ≥ `from`. A dose recorded ahead of its slot (the slot's
|
||||
time within a day after `to`) is still returned.
|
||||
responses:
|
||||
"200":
|
||||
description: Dose-history ledger.
|
||||
@@ -43671,10 +43673,13 @@ components:
|
||||
type: string
|
||||
format: date-time
|
||||
pattern: ^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d(?:\.\d+)?)?(?:Z|([+-](?:[01]\d|2[0-3]):[0-5]\d)))$
|
||||
description: "Start of the window recorded doses were read over: the requested `from` after the span clamp."
|
||||
to:
|
||||
type: string
|
||||
format: date-time
|
||||
pattern: ^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d(?:\.\d+)?)?(?:Z|([+-](?:[01]\d|2[0-3]):[0-5]\d)))$
|
||||
description: "End of the window recorded doses were read over: the requested `to`, or the slot time of a dose recorded
|
||||
ahead of its slot when that lies later (at most one day after `to`)."
|
||||
family:
|
||||
type: string
|
||||
enum:
|
||||
|
||||
@@ -344,6 +344,9 @@ describe("GET /api/medications/[id]/dose-history — intakes recorded before cre
|
||||
json.data.rows as Array<{ intake: { id: string | null } | null }>
|
||||
).map((r) => r.intake?.id);
|
||||
expect(ids).toContain("evt-earlier-today");
|
||||
// The response reports the window the recorded doses were read
|
||||
// over: the requested start, not the medication's creation.
|
||||
expect(json.data.from).toBe(from);
|
||||
} finally {
|
||||
vi.useRealTimers();
|
||||
}
|
||||
@@ -410,6 +413,9 @@ describe("GET /api/medications/[id]/dose-history — early take (#1028 class)",
|
||||
status: string;
|
||||
intake: { id: string | null } | null;
|
||||
}>;
|
||||
// `to` reports how far recorded doses were read: up to the early
|
||||
// dose's slot, past the request's own now.
|
||||
expect(json.data.to).toBe(slot.toISOString());
|
||||
const early = rows.find((r) => r.intake?.id === "evt-early");
|
||||
expect(early?.status).toBe("taken_on_time");
|
||||
// The read horizon stretches only to the recorded anchor: no later
|
||||
|
||||
@@ -313,9 +313,13 @@ export const GET = apiHandler(
|
||||
meta: { row_count: serialized.length, family },
|
||||
});
|
||||
|
||||
// The window the recorded doses were read over (#1028): from the
|
||||
// requested start (slots additionally start at the medication's
|
||||
// creation) to the read horizon, which reaches past `to` only for a dose
|
||||
// recorded ahead of its slot.
|
||||
return apiSuccess({
|
||||
from: from.toISOString(),
|
||||
to: to.toISOString(),
|
||||
from: intakeFrom.toISOString(),
|
||||
to: horizon.toISOString(),
|
||||
family,
|
||||
hasExpectedSlots: bands.length > 0,
|
||||
rows: serialized,
|
||||
|
||||
@@ -911,12 +911,14 @@ export const doseHistoryQuery = z.object({
|
||||
.datetime({ offset: true })
|
||||
.optional()
|
||||
.describe(
|
||||
"Window start (inclusive). Defaults to 90 days before `to`; clamped to the medication's `createdAt` and a 366-day span floor.",
|
||||
"Window start (inclusive). Defaults to 90 days before `to`; clamped to a 366-day span floor. Recorded doses are returned from this instant; expected slots are not minted before the medication's `createdAt`.",
|
||||
),
|
||||
to: z.iso
|
||||
.datetime({ offset: true })
|
||||
.optional()
|
||||
.describe("Window end (inclusive). Defaults to now. Must be ≥ `from`."),
|
||||
.describe(
|
||||
"Window end (inclusive). Defaults to now. Must be ≥ `from`. A dose recorded ahead of its slot (the slot's time within a day after `to`) is still returned.",
|
||||
),
|
||||
});
|
||||
|
||||
const doseHistoryRow = z
|
||||
@@ -982,8 +984,16 @@ const doseHistoryRow = z
|
||||
|
||||
export const doseHistoryResponse = z
|
||||
.object({
|
||||
from: z.iso.datetime({ offset: true }),
|
||||
to: z.iso.datetime({ offset: true }),
|
||||
from: z.iso
|
||||
.datetime({ offset: true })
|
||||
.describe(
|
||||
"Start of the window recorded doses were read over: the requested `from` after the span clamp.",
|
||||
),
|
||||
to: z.iso
|
||||
.datetime({ offset: true })
|
||||
.describe(
|
||||
"End of the window recorded doses were read over: the requested `to`, or the slot time of a dose recorded ahead of its slot when that lies later (at most one day after `to`).",
|
||||
),
|
||||
family: z
|
||||
.enum(["daily", "weekly", "one_shot", "none"])
|
||||
.describe("Cadence family the window's slots were minted under."),
|
||||
|
||||
Reference in new issue
Block a user