"""Repository for the `runs` table.""" from __future__ import annotations import json from typing import Any from db.connection import get_db class RunsRepository: async def insert( self, scenario: str, identifier: str, success: bool, failure_reason: str | None, steps: list[dict[str, Any]], total_ms: int, ) -> int: async with get_db() as db: cur = await db.execute( """INSERT INTO runs (scenario, identifier, success, failure_reason, steps_json, total_ms) VALUES (?, ?, ?, ?, ?, ?)""", (scenario, identifier, int(success), failure_reason, json.dumps(steps), total_ms), ) await db.commit() return int(cur.lastrowid or 0) async def stats(self) -> dict[str, Any]: async with get_db() as db: total = (await (await db.execute("SELECT COUNT(*) FROM runs")).fetchone())[0] unique_ids = (await (await db.execute("SELECT COUNT(DISTINCT identifier) FROM runs")).fetchone())[0] successes = (await (await db.execute("SELECT COUNT(*) FROM runs WHERE success=1")).fetchone())[0] failures = (await (await db.execute("SELECT COUNT(*) FROM runs WHERE success=0")).fetchone())[0] failure_reasons = [ {"reason": r["failure_reason"], "count": r["cnt"]} for r in await (await db.execute( """SELECT failure_reason, COUNT(*) as cnt FROM runs WHERE success=0 AND failure_reason IS NOT NULL GROUP BY failure_reason ORDER BY cnt DESC LIMIT 10""" )).fetchall() ] scenario_breakdown = [ { "scenario": r["scenario"], "total": r["total"], "success": r["ok"], "failure": r["fail"], } for r in await (await db.execute( """SELECT scenario, COUNT(*) as total, SUM(success) as ok, COUNT(*) - SUM(success) as fail FROM runs GROUP BY scenario""" )).fetchall() ] recent = [ dict(r) for r in await (await db.execute( """SELECT id, created_at, scenario, identifier, success, failure_reason, total_ms FROM runs ORDER BY id DESC LIMIT 50""" )).fetchall() ] return { "total_runs": total, "unique_identifiers": unique_ids, "successes": successes, "failures": failures, "success_rate": round(successes / total * 100, 1) if total else 0.0, "failure_reasons": failure_reasons, "scenario_breakdown": scenario_breakdown, "recent_runs": recent, } runs_repo = RunsRepository()