from __future__ import annotations import json import sqlite3 from pathlib import Path from typing import Any DEFAULT_MAX_STEPS = 20 class DeviceConfigStore: def __init__( self, db_path: str | Path = "tasks/device_config.sqlite3", *, default_max_steps: int = DEFAULT_MAX_STEPS, ) -> None: self.db_path = Path(db_path) self.default_max_steps = default_max_steps self.db_path.parent.mkdir(parents=True, exist_ok=True) self._ensure_schema() def add( self, *, device_id: str, name: str | None = None, driver_type: str, connection_info: dict[str, Any], ) -> None: with self._connect() as connection: connection.execute( """ insert or replace into device_configs ( device_id, name, driver_type, connection_info ) values (?, ?, ?, ?) """, ( device_id, name, driver_type, json.dumps(connection_info, ensure_ascii=False), ), ) def remove(self, device_id: str) -> None: with self._connect() as connection: connection.execute( "delete from device_configs where device_id = ?", (device_id,), ) def get(self, device_id: str) -> dict[str, Any] | None: with self._connect() as connection: row = connection.execute( "select * from device_configs where device_id = ?", (device_id,), ).fetchone() return self._row_to_config(row) if row else None def list(self) -> list[dict[str, Any]]: with self._connect() as connection: rows = connection.execute( "select * from device_configs order by device_id" ).fetchall() return [self._row_to_config(row) for row in rows] def get_setting(self, key: str) -> str | None: with self._connect() as connection: row = connection.execute( "select value from settings where key = ?", (key,), ).fetchone() return str(row["value"]) if row else None def set_setting(self, key: str, value: object) -> None: with self._connect() as connection: connection.execute( """ insert into settings (key, value) values (?, ?) on conflict(key) do update set value = excluded.value """, (key, str(value)), ) def _ensure_schema(self) -> None: with self._connect() as connection: connection.execute( """ create table if not exists device_configs ( device_id text primary key, name text, driver_type text not null, connection_info text not null ) """ ) connection.execute( """ create table if not exists settings ( key text primary key, value text not null ) """ ) connection.execute( "insert or ignore into settings (key, value) values (?, ?)", ("max_steps", str(self.default_max_steps)), ) def _connect(self) -> sqlite3.Connection: connection = sqlite3.connect(self.db_path) connection.row_factory = sqlite3.Row return connection def _row_to_config(self, row: sqlite3.Row) -> dict[str, Any]: return { "device_id": row["device_id"], "name": row["name"], "driver_type": row["driver_type"], "connection_info": json.loads(row["connection_info"]), }