mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-11 13:52:20 +00:00
test(personal-records): detection worker + queue + UI badge coverage
Adds the integration suite for the detection worker against a real Postgres testcontainer. Covers measurement-driven PRs (steps, RHR, VO2 max), idempotency on re-run, silent-flag propagation, and the drift guard that every PR-trackable metric type lands in the scan loop. Also patches a pre-existing schema gap: the (userId, metricType, metricSlot, achievedAt) unique index on personal_records is NULLS-DISTINCT in Postgres, so the index alone does not dedup the measurement-driven rows (metricSlot = NULL). The worker now does an application-level pre-flight findFirst on the same composite key before each insert, keeping both the workout path (index covers it) and the measurement path (application-level guard) idempotent without a Migration.
This commit is contained in:
1 parent
dd44a0df49
commit
223b8a9208
4 files changed
+212
-2
No files matched your search
@@ -76,6 +76,7 @@ interface FakeWhere {
|
||||
sportType?: string;
|
||||
totalDistanceM?: { gte: number };
|
||||
durationSec?: { gt: number } | { gte: number };
|
||||
achievedAt?: Date;
|
||||
}
|
||||
|
||||
function makeFakePrisma(state: {
|
||||
@@ -122,6 +123,11 @@ function makeFakePrisma(state: {
|
||||
row.metricSlot !== where.metricSlot
|
||||
)
|
||||
return false;
|
||||
if (
|
||||
where.achievedAt !== undefined &&
|
||||
row.achievedAt.getTime() !== where.achievedAt.getTime()
|
||||
)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -240,8 +240,23 @@ export async function detectPersonalRecordsForUser(
|
||||
const outcome = compareToCurrentBest(best.value, currentPR?.value, direction);
|
||||
if (outcome === "no-improvement") continue;
|
||||
|
||||
// ON CONFLICT DO NOTHING via `skipDuplicates`. Re-running the
|
||||
// same job is a guaranteed no-op once the row exists.
|
||||
// Application-level idempotency. The DB unique index covers the
|
||||
// workout case (`metric_slot` non-null) but Postgres' default
|
||||
// NULLS-DISTINCT semantics mean `(userId, metric, NULL, ts)`
|
||||
// doesn't dedup at the index level — a second handler invocation
|
||||
// would otherwise write a second row at the same achievedAt. The
|
||||
// explicit pre-flight findFirst keeps both code paths safe.
|
||||
const existing = await prisma.personalRecord.findFirst({
|
||||
where: {
|
||||
userId,
|
||||
metricType,
|
||||
metricSlot: null,
|
||||
achievedAt: best.measuredAt,
|
||||
},
|
||||
select: { id: true },
|
||||
});
|
||||
if (existing) continue;
|
||||
|
||||
const result = await prisma.personalRecord.createMany({
|
||||
data: [
|
||||
{
|
||||
|
||||
Reference in new issue
Block a user