Add cached image quickstart #336

Open
didericis-codex wants to merge 9 commits from issue-330-cached-images into main
2 changed files with 40 additions and 33 deletions
Showing only changes of commit 114126e162 - Show all commits
+23 -31
View File
@@ -14,66 +14,58 @@ except ImportError:
from supervise_types import host_db_path # type: ignore[import-not-found] # pylint: disable=import-error,no-name-in-module from supervise_types import host_db_path # type: ignore[import-not-found] # pylint: disable=import-error,no-name-in-module
CACHED_IMAGE_STALE_WARNING_DAYS = "cached_image_stale_warning_days"
DEFAULT_CACHED_IMAGE_STALE_WARNING_DAYS = 1 DEFAULT_CACHED_IMAGE_STALE_WARNING_DAYS = 1
class ConfigStore(DbStore): class ConfigStore(DbStore):
"""SQLite key/value configuration for host-side bot-bottle settings.""" """SQLite configuration for host-side bot-bottle settings."""
def __init__(self, db_path: Path | None = None) -> None: def __init__(self, db_path: Path | None = None) -> None:
migrations = TableMigrations("config_store", [ migrations = TableMigrations("config_store", [
# v1 — generic string key/value settings # v1 — host-side bot-bottle settings
""" """
CREATE TABLE IF NOT EXISTS bot_bottle_config ( CREATE TABLE IF NOT EXISTS bot_bottle_config (
key TEXT PRIMARY KEY, id INTEGER PRIMARY KEY CHECK (id = 1),
value TEXT NOT NULL cached_image_stale_warning_days INTEGER NOT NULL DEFAULT 1
) )
""", """,
didericis-codex marked this conversation as resolved Outdated
Outdated
Review

Will be easier to surface migration issues or problems with config changes if we make the specific config keys explicit. Think we should just put them in the schema here rather than having a generic key.

Will be easier to surface migration issues or problems with config changes if we make the specific config keys explicit. Think we should just put them in the schema here rather than having a generic `key`.
Outdated
Review

Done in 0c70de0e07. The config store schema now uses explicit settings columns with cached_image_stale_warning_days directly on the table, and the generic key/value accessors are gone. I also added a schema assertion test so this stays explicit.

Done in 0c70de0e07efdd7dca22bf85860c6b2d00198b52. The config store schema now uses explicit settings columns with `cached_image_stale_warning_days` directly on the table, and the generic key/value accessors are gone. I also added a schema assertion test so this stays explicit.
]) ])
super().__init__(db_path or host_db_path(), migrations) super().__init__(db_path or host_db_path(), migrations)
def get(self, key: str) -> str | None: def cached_image_stale_warning_days(self) -> int:
if not self.db_path.is_file(): if not self.db_path.is_file():
return None return DEFAULT_CACHED_IMAGE_STALE_WARNING_DAYS
with self._connect() as conn: with self._connect() as conn:
row = conn.execute( row = conn.execute(
"SELECT value FROM bot_bottle_config WHERE key = ?", """
(key,), SELECT cached_image_stale_warning_days
FROM bot_bottle_config
WHERE id = 1
""",
).fetchone() ).fetchone()
return str(row["value"]) if row is not None else None if row is None:
return DEFAULT_CACHED_IMAGE_STALE_WARNING_DAYS
try:
return int(row["cached_image_stale_warning_days"])
except (TypeError, ValueError):
return DEFAULT_CACHED_IMAGE_STALE_WARNING_DAYS
def set(self, key: str, value: str) -> Path: def set_cached_image_stale_warning_days(self, days: int) -> Path:
with self._connect() as conn: with self._connect() as conn:
conn.execute( conn.execute(
""" """
INSERT INTO bot_bottle_config (key, value) INSERT INTO bot_bottle_config (id, cached_image_stale_warning_days)
VALUES (?, ?) VALUES (1, ?)
ON CONFLICT(key) DO UPDATE SET value = excluded.value ON CONFLICT(id) DO UPDATE SET
cached_image_stale_warning_days = excluded.cached_image_stale_warning_days
""", """,
(key, value), (days,),
) )
self._chmod() self._chmod()
return self.db_path return self.db_path
def get_int(self, key: str, default: int) -> int:
raw = self.get(key)
if raw is None:
return default
try:
return int(raw)
except ValueError:
return default
def cached_image_stale_warning_days(self) -> int:
return self.get_int(
CACHED_IMAGE_STALE_WARNING_DAYS,
DEFAULT_CACHED_IMAGE_STALE_WARNING_DAYS,
)
__all__ = [ __all__ = [
"CACHED_IMAGE_STALE_WARNING_DAYS",
"DEFAULT_CACHED_IMAGE_STALE_WARNING_DAYS", "DEFAULT_CACHED_IMAGE_STALE_WARNING_DAYS",
"ConfigStore", "ConfigStore",
] ]
+17 -2
View File
@@ -2,12 +2,12 @@
from __future__ import annotations from __future__ import annotations
import sqlite3
import tempfile import tempfile
import unittest import unittest
from pathlib import Path from pathlib import Path
from bot_bottle.config_store import ( from bot_bottle.config_store import (
CACHED_IMAGE_STALE_WARNING_DAYS,
DEFAULT_CACHED_IMAGE_STALE_WARNING_DAYS, DEFAULT_CACHED_IMAGE_STALE_WARNING_DAYS,
ConfigStore, ConfigStore,
) )
@@ -28,9 +28,24 @@ class TestConfigStore(unittest.TestCase):
with tempfile.TemporaryDirectory(prefix="config-store.") as tmp: with tempfile.TemporaryDirectory(prefix="config-store.") as tmp:
store = ConfigStore(Path(tmp) / "bot-bottle.db") store = ConfigStore(Path(tmp) / "bot-bottle.db")
store.migrate() store.migrate()
store.set(CACHED_IMAGE_STALE_WARNING_DAYS, "7") store.set_cached_image_stale_warning_days(7)
self.assertEqual(7, store.cached_image_stale_warning_days()) self.assertEqual(7, store.cached_image_stale_warning_days())
def test_config_schema_uses_explicit_settings_columns(self) -> None:
with tempfile.TemporaryDirectory(prefix="config-store.") as tmp:
store = ConfigStore(Path(tmp) / "bot-bottle.db")
store.migrate()
with sqlite3.connect(store.db_path) as conn:
conn.row_factory = sqlite3.Row
columns = [
row["name"]
for row in conn.execute("PRAGMA table_info(bot_bottle_config)")
]
self.assertEqual([
"id",
"cached_image_stale_warning_days",
], columns)
def test_store_manager_includes_config_store(self) -> None: def test_store_manager_includes_config_store(self) -> None:
with tempfile.TemporaryDirectory(prefix="config-store.") as tmp: with tempfile.TemporaryDirectory(prefix="config-store.") as tmp:
db = Path(tmp) / "bot-bottle.db" db = Path(tmp) / "bot-bottle.db"