mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-14 22:50:51 +00:00
fix(measurements): keep a folded hour out of a blood-pressure reading
The reading delete found the cuff's pulse by owner, source and identical instant. The dense fold anchors an hour of heart rate at the local HH:30 under the samples' source, so a reading taken at half past took that hour with it. Aggregate (stats:) rows are never part of a reading now, for the delete and for the restore.
This commit is contained in:
1 parent
ad5d154561
commit
17d9c15dbc
2 files changed
+83
-1
No files matched your search
@@ -14,6 +14,14 @@
|
||||
* Deleting a systolic or a diastolic takes the whole reading with it.
|
||||
* Deleting a pulse takes only the pulse: a pulse is also a value of its own,
|
||||
* and removing one is no reason to remove a blood pressure.
|
||||
*
|
||||
* An aggregate row is never part of a reading. The dense fold stores an
|
||||
* hour of heart rate as one `stats:` row at the local HH:30 of that hour
|
||||
* (`canonicalHourlyTimestamp`), under the same source as the samples it
|
||||
* folded, and the client's hourly heart-rate bucket is a `stats:` row as
|
||||
* well. A cuff reading taken at half past, from the same source, shares its
|
||||
* instant with that row; it is still an hour of somebody's heart rate, not
|
||||
* the cuff's pulse, and a delete must not take it.
|
||||
*/
|
||||
import type { MeasurementType, Prisma } from "@/generated/prisma/client";
|
||||
|
||||
@@ -30,6 +38,9 @@ const BP_READING_TYPES: MeasurementType[] = [
|
||||
"PULSE",
|
||||
];
|
||||
|
||||
/** The externalId prefix every aggregate (folded or bucketed) row carries. */
|
||||
const AGGREGATE_EXTERNAL_ID_PREFIX = "stats:";
|
||||
|
||||
export interface ReadingAnchor {
|
||||
id: string;
|
||||
type: MeasurementType | string;
|
||||
@@ -70,6 +81,20 @@ export async function bloodPressureSiblings(
|
||||
userId,
|
||||
id: { notIn: rows.map((r) => r.id) },
|
||||
type: { in: BP_READING_TYPES },
|
||||
// Spelled with the NULL arm: a bare `NOT startsWith` is NULL, not
|
||||
// true, for the NULL externalId of a manual row and would drop it.
|
||||
AND: [
|
||||
{
|
||||
OR: [
|
||||
{ externalId: null },
|
||||
{
|
||||
NOT: {
|
||||
externalId: { startsWith: AGGREGATE_EXTERNAL_ID_PREFIX },
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
OR: anchors.map((a) => ({
|
||||
source: a.source as Prisma.MeasurementWhereInput["source"],
|
||||
measuredAt: a.measuredAt,
|
||||
|
||||
Reference in new issue
Block a user