83 lines
3.0 KiB
Python
83 lines
3.0 KiB
Python
"""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()
|