""" CRUD for løp (races) og stasjoner (stations). """ import uuid from typing import Optional import aiosqlite async def init_race_tables(db: aiosqlite.Connection) -> None: await db.executescript(""" CREATE TABLE IF NOT EXISTS races ( race_id TEXT PRIMARY KEY, name TEXT NOT NULL, date TEXT, description TEXT, is_active INTEGER NOT NULL DEFAULT 0, created_at TEXT NOT NULL DEFAULT (datetime('now')) ); CREATE TABLE IF NOT EXISTS stations ( station_id TEXT PRIMARY KEY, race_id TEXT NOT NULL REFERENCES races(race_id) ON DELETE CASCADE, name TEXT NOT NULL, display_name TEXT NOT NULL, station_order INTEGER NOT NULL DEFAULT 0, gps_lat REAL, gps_lon REAL, gps_alt REAL, created_at TEXT NOT NULL DEFAULT (datetime('now')), UNIQUE(race_id, name) ); CREATE INDEX IF NOT EXISTS idx_stations_race ON stations(race_id, station_order); """) await db.commit() # ── Løp ────────────────────────────────────────────────────────────────────── async def create_race( db: aiosqlite.Connection, name: str, date: Optional[str] = None, description: Optional[str] = None, ) -> dict: race_id = str(uuid.uuid4()) await db.execute( "INSERT INTO races (race_id, name, date, description) VALUES (?, ?, ?, ?)", (race_id, name, date, description), ) # Sett som aktivt hvis det er første løpet async with db.execute("SELECT COUNT(*) FROM races") as cur: count = (await cur.fetchone())[0] if count == 1: await db.execute("UPDATE races SET is_active = 1 WHERE race_id = ?", (race_id,)) # Opprett standard start- og målstasjon for order, (sname, display) in enumerate([("start", "Start"), ("finish", "Mål")]): await db.execute( """INSERT INTO stations (station_id, race_id, name, display_name, station_order) VALUES (?, ?, ?, ?, ?)""", (str(uuid.uuid4()), race_id, sname, display, order * 1000), ) await db.commit() return await get_race(db, race_id) async def get_race(db: aiosqlite.Connection, race_id: str) -> Optional[dict]: async with db.execute("SELECT * FROM races WHERE race_id = ?", (race_id,)) as cur: row = await cur.fetchone() return dict(row) if row else None async def list_races(db: aiosqlite.Connection) -> list[dict]: async with db.execute("SELECT * FROM races ORDER BY date DESC, created_at DESC") as cur: rows = await cur.fetchall() return [dict(r) for r in rows] async def update_race( db: aiosqlite.Connection, race_id: str, name: str, date: Optional[str], description: Optional[str], ) -> bool: cur = await db.execute( "UPDATE races SET name = ?, date = ?, description = ? WHERE race_id = ?", (name, date, description, race_id), ) await db.commit() return cur.rowcount > 0 async def delete_race(db: aiosqlite.Connection, race_id: str) -> bool: cur = await db.execute("DELETE FROM races WHERE race_id = ?", (race_id,)) await db.commit() return cur.rowcount > 0 async def set_active_race(db: aiosqlite.Connection, race_id: str) -> bool: await db.execute("UPDATE races SET is_active = 0") cur = await db.execute( "UPDATE races SET is_active = 1 WHERE race_id = ?", (race_id,) ) await db.commit() return cur.rowcount > 0 async def get_active_race(db: aiosqlite.Connection) -> Optional[dict]: async with db.execute("SELECT * FROM races WHERE is_active = 1 LIMIT 1") as cur: row = await cur.fetchone() return dict(row) if row else None # ── Stasjoner ───────────────────────────────────────────────────────────────── async def list_stations(db: aiosqlite.Connection, race_id: str) -> list[dict]: async with db.execute( "SELECT * FROM stations WHERE race_id = ? ORDER BY station_order", (race_id,), ) as cur: rows = await cur.fetchall() return [dict(r) for r in rows] async def get_station(db: aiosqlite.Connection, station_id: str) -> Optional[dict]: async with db.execute( "SELECT * FROM stations WHERE station_id = ?", (station_id,) ) as cur: row = await cur.fetchone() return dict(row) if row else None async def create_station( db: aiosqlite.Connection, race_id: str, name: str, display_name: str, station_order: int, gps_lat: Optional[float] = None, gps_lon: Optional[float] = None, gps_alt: Optional[float] = None, ) -> dict: station_id = str(uuid.uuid4()) await db.execute( """INSERT INTO stations (station_id, race_id, name, display_name, station_order, gps_lat, gps_lon, gps_alt) VALUES (?, ?, ?, ?, ?, ?, ?, ?)""", (station_id, race_id, name, display_name, station_order, gps_lat, gps_lon, gps_alt), ) await db.commit() return dict((await db.execute( "SELECT * FROM stations WHERE station_id = ?", (station_id,) )).get_cursor() or {}) async def upsert_station( db: aiosqlite.Connection, race_id: str, name: str, display_name: str, station_order: int, gps_lat: Optional[float] = None, gps_lon: Optional[float] = None, gps_alt: Optional[float] = None, station_id: Optional[str] = None, ) -> dict: if station_id: await db.execute( """UPDATE stations SET name=?, display_name=?, station_order=?, gps_lat=?, gps_lon=?, gps_alt=? WHERE station_id=?""", (name, display_name, station_order, gps_lat, gps_lon, gps_alt, station_id), ) else: station_id = str(uuid.uuid4()) await db.execute( """INSERT INTO stations (station_id, race_id, name, display_name, station_order, gps_lat, gps_lon, gps_alt) VALUES (?, ?, ?, ?, ?, ?, ?, ?)""", (station_id, race_id, name, display_name, station_order, gps_lat, gps_lon, gps_alt), ) await db.commit() async with db.execute("SELECT * FROM stations WHERE station_id = ?", (station_id,)) as cur: row = await cur.fetchone() return dict(row) async def delete_station(db: aiosqlite.Connection, station_id: str) -> bool: # Ikke tillat sletting av start/finish async with db.execute( "SELECT name FROM stations WHERE station_id = ?", (station_id,) ) as cur: row = await cur.fetchone() if row and row["name"] in ("start", "finish"): return False cur = await db.execute("DELETE FROM stations WHERE station_id = ?", (station_id,)) await db.commit() return cur.rowcount > 0