from __future__ import annotations import sqlite3 from pathlib import Path from typing import Any from core.models import Task, TaskStatus, utc_now class TaskMetadataStore: def __init__(self, db_path: str | Path = "tasks/tasks.sqlite3") -> None: self.db_path = Path(db_path) self.db_path.parent.mkdir(parents=True, exist_ok=True) self._ensure_schema() def create_task(self, task: Task) -> None: with self._connect() as connection: connection.execute( """ insert into tasks ( id, goal, device_id, status, created_at, updated_at, completed_at, failure_reason ) values (?, ?, ?, ?, ?, ?, ?, ?) """, ( task.id, task.goal, task.device_id, task.status, task.created_at.isoformat(), task.updated_at.isoformat(), task.completed_at.isoformat() if task.completed_at else None, task.failure_reason, ), ) def update_task( self, task_id: str, *, status: TaskStatus | None = None, failure_reason: str | None = None, completed: bool = False, ) -> None: updates: dict[str, Any] = {"updated_at": utc_now().isoformat()} if status: updates["status"] = status if failure_reason is not None: updates["failure_reason"] = failure_reason if completed: updates["completed_at"] = utc_now().isoformat() assignments = ", ".join(f"{key} = ?" for key in updates) values = [*updates.values(), task_id] with self._connect() as connection: connection.execute( f"update tasks set {assignments} where id = ?", values, ) def get_task(self, task_id: str) -> dict[str, Any] | None: with self._connect() as connection: row = connection.execute( "select * from tasks where id = ?", (task_id,), ).fetchone() return dict(row) if row else None def list_tasks(self) -> list[dict[str, Any]]: with self._connect() as connection: rows = connection.execute( "select * from tasks order by created_at desc" ).fetchall() return [dict(row) for row in rows] def list_task_ids(self) -> list[str]: with self._connect() as connection: rows = connection.execute( "select id from tasks order by created_at desc" ).fetchall() return [row["id"] for row in rows] def delete_task(self, task_id: str) -> None: """Delete a task row. No-op if the task does not exist.""" with self._connect() as connection: connection.execute( "delete from tasks where id = ?", (task_id,), ) def _ensure_schema(self) -> None: with self._connect() as connection: connection.execute( """ create table if not exists tasks ( id text primary key, goal text not null, device_id text not null, status text not null, created_at text not null, updated_at text not null, completed_at text, failure_reason text ) """ ) def _connect(self) -> sqlite3.Connection: connection = sqlite3.connect(self.db_path) connection.row_factory = sqlite3.Row return connection