mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-10 05:12:14 +00:00
fix(sleep): one day total for every sleep reader, and the latest night is a night
A day's sleep is the main night plus its naps (daySleepMinutes). The series, the sleep score and the composition already read it that way; the sleep list, the CSV export and the correlation sleep channel read the main night alone, so a day of naps listed as 0 h and an average over the list counted it as a night without sleep. The list now carries the day total in value and the main night alone in the new mainAsleepMinutes field; the nap caption reads as included. GET /api/sleep/night without a date answered the latest day holding any sleep, so a nap after the last night left the hypnogram with no night to draw. It now walks back to the latest night with a main sleep; nap days stay reachable by date. The SQL night page bounded a night by its asleep sessions only, so an in-bed-only session of the same night fell outside a chunked read that the one-night read counted. The span now covers every session of the night.
This commit is contained in:
1 parent
3004f55875
commit
63bbf0931c
20 files changed
+339
-94
No files matched your search
@@ -328,6 +328,27 @@ export const measurementResource = z
|
||||
// Synthesised-row extras — present only on the collapsed day-sum mode.
|
||||
dayKey: z.string().optional(),
|
||||
sampleCount: z.number().int().optional(),
|
||||
// Per-night extras — present only on `type=SLEEP_DURATION` list rows.
|
||||
mainAsleepMinutes: z
|
||||
.number()
|
||||
.int()
|
||||
.nonnegative()
|
||||
.nullable()
|
||||
.optional()
|
||||
.describe(
|
||||
"The main night's own time asleep in minutes; null on a day of naps alone. On a sleep row `value` is the day's total, the main night plus its naps.",
|
||||
),
|
||||
napCount: z
|
||||
.number()
|
||||
.int()
|
||||
.nonnegative()
|
||||
.optional()
|
||||
.describe("Naps on the same wake day."),
|
||||
napAsleepMinutes: z
|
||||
.number()
|
||||
.nonnegative()
|
||||
.optional()
|
||||
.describe("Time asleep across those naps, in minutes."),
|
||||
})
|
||||
.meta({
|
||||
id: "MeasurementResource",
|
||||
@@ -804,7 +825,7 @@ export const measurementPaths: NonNullable<ZodOpenApiObject["paths"]> = {
|
||||
summary: "List measurements",
|
||||
description:
|
||||
"Filter by type + date range. Response is paged via offset/limit; default limit 100.\n\n" +
|
||||
"With `groupBy=day` on a cumulative type the rows are one sum per local day, and `limit` / `offset` page over those days; every returned day is complete, which is why `valueMin` / `valueMax` (a filter on single readings) are refused with 422 beside `groupBy=day`. `type=SLEEP_DURATION` returns one row per night, paged the same way over nights; every night of the page has a row, and a day whose only sleep is daytime naps carries `value` 0 with its naps in `napCount` / `napAsleepMinutes`. Its `dayKey` is the same day `/api/sleep/night?date=` answers for. On both, `meta.total` counts the days or nights in the filtered window. A day-sum page takes `limit` as asked (up to the list's 5000); a sleep page holds at most 1000 nights, and `meta.limit` echoes the value applied.",
|
||||
"With `groupBy=day` on a cumulative type the rows are one sum per local day, and `limit` / `offset` page over those days; every returned day is complete, which is why `valueMin` / `valueMax` (a filter on single readings) are refused with 422 beside `groupBy=day`. `type=SLEEP_DURATION` returns one row per night, paged the same way over nights; every night of the page has a row, and `value` is the day's time asleep, the main night plus its naps (the same total `/api/measurements/series?kind=sleep` and the sleep score read), with the main night alone in `mainAsleepMinutes` and the naps in `napCount` / `napAsleepMinutes`; a day whose only sleep is daytime naps carries the naps' minutes and `mainAsleepMinutes: null`. Its `dayKey` is the same day `/api/sleep/night?date=` answers for. On both, `meta.total` counts the days or nights in the filtered window. A day-sum page takes `limit` as asked (up to the list's 5000); a sleep page holds at most 1000 nights, and `meta.limit` echoes the value applied.",
|
||||
requestParams: {
|
||||
query: listMeasurementsSchema,
|
||||
},
|
||||
@@ -1118,7 +1139,7 @@ export const measurementPaths: NonNullable<ZodOpenApiObject["paths"]> = {
|
||||
tags: ["Measurements"],
|
||||
summary: "Reconstructed sleep night (hypnogram source, v1.11.5)",
|
||||
description:
|
||||
"Returns one night's reconstructed sleep session for the phase-progression (hypnogram) view: the canonical source's stage segments (each with an absolute start/end), the per-stage breakdown, asleep/in-bed/awake totals, the mid-sleep awakenings count, and same-wake-day naps surfaced separately. Session-clustered, keyed by the local wake day, collapsed to one source via the sleep priority ladder so two sources never overlay. `date` omitted returns the most recent night holding sleep, however old. Any past date is answered, with no window cut. A read-only view over existing per-stage SLEEP_DURATION rows — no schema, no new measurement type.",
|
||||
"Returns one night's reconstructed sleep session for the phase-progression (hypnogram) view: the canonical source's stage segments (each with an absolute start/end), the per-stage breakdown, asleep/in-bed/awake totals, the mid-sleep awakenings count, and same-wake-day naps surfaced separately. Session-clustered, keyed by the local wake day, collapsed to one source via the sleep priority ladder so two sources never overlay. `date` omitted returns the most recent night with a main sleep, however old; later days of naps alone are stepped over and stay reachable by `date`. An account that has only ever napped gets its latest day of naps. Any past date is answered, with no window cut. A read-only view over existing per-stage SLEEP_DURATION rows — no schema, no new measurement type.",
|
||||
requestParams: {
|
||||
query: z.object({
|
||||
date: z
|
||||
@@ -1126,7 +1147,7 @@ export const measurementPaths: NonNullable<ZodOpenApiObject["paths"]> = {
|
||||
.regex(/^\d{4}-\d{2}-\d{2}$/)
|
||||
.optional()
|
||||
.describe(
|
||||
"Wake-day key (YYYY-MM-DD). Omit for the most recent night.",
|
||||
"Wake-day key (YYYY-MM-DD). Omit for the most recent night with a main sleep.",
|
||||
),
|
||||
}),
|
||||
},
|
||||
|
||||
Reference in new issue
Block a user