feat(matching-runs): add per-run aggregate stats and UI display

- Admin list endpoint returns totalSuggestions, assignedCount, aggregatedNotFoundCount per run
- UI: show Total/Matched/Not found columns using fresh aggregates
- Add anchor link Run #ID and wording 'Pairs created in this run'
This commit is contained in:
Radosław Gierwiało
2025-11-30 13:43:05 +01:00
parent a9ad25eb38
commit 621511fccf
3 changed files with 46 additions and 4 deletions

View File

@@ -0,0 +1,13 @@
-- Add origin_run_id column to recording_suggestions
ALTER TABLE "recording_suggestions" ADD COLUMN "origin_run_id" INTEGER;
-- Add foreign key to matching_runs
ALTER TABLE "recording_suggestions"
ADD CONSTRAINT "recording_suggestions_origin_run_id_fkey"
FOREIGN KEY ("origin_run_id") REFERENCES "matching_runs"("id")
ON DELETE SET NULL ON UPDATE CASCADE;
-- Simple index to support joins by origin_run_id
CREATE INDEX IF NOT EXISTS "recording_suggestions_origin_run_id_idx"
ON "recording_suggestions"("origin_run_id");

View File

@@ -104,6 +104,30 @@ router.get('/events/:slug/matching-runs', authenticate, async (req, res, next) =
},
});
// Aggregate fresh stats per run from recording_suggestions (origin_run_id)
// Cheap and valuable: shows actual created pairs in this run.
if (runs.length > 0) {
const runIds = runs.map(r => r.id);
// Single SQL query for all listed runs
const placeholders = runIds.join(',');
const aggRows = await prisma.$queryRawUnsafe(
`SELECT origin_run_id AS "originRunId",
COUNT(*)::int AS "totalSuggestions",
COUNT(*) FILTER (WHERE recorder_id IS NOT NULL)::int AS "assignedCount",
COUNT(*) FILTER (WHERE status = 'not_found')::int AS "notFoundCount"
FROM recording_suggestions
WHERE event_id = ${event.id} AND origin_run_id IN (${placeholders})
GROUP BY origin_run_id`
);
const aggByRun = new Map(aggRows.map(r => [r.originRunId, r]));
for (const r of runs) {
const agg = aggByRun.get(r.id) || { totalSuggestions: 0, assignedCount: 0, notFoundCount: 0 };
r.totalSuggestions = agg.totalSuggestions;
r.assignedCount = agg.assignedCount;
r.aggregatedNotFoundCount = agg.notFoundCount; // keep original notFoundCount for backward compat
}
}
res.json({ success: true, count: runs.length, data: runs });
} catch (error) {
next(error);