feat: migrate storage from JSON files to SQLite
Lint & Test / test (push) Failing after 28s

Replace 22 individual JSON store files with a single SQLite database
(data/ledgrab.db). All entity stores now use BaseSqliteStore backed by
SQLite with WAL mode, write-through caching, and thread-safe access.

- Add Database class with SQLite backup/restore API
- Add BaseSqliteStore as drop-in replacement for BaseJsonStore
- Convert all 16 entity stores to SQLite
- Move global settings (MQTT, external URL, auto-backup) to SQLite
  settings table
- Replace JSON backup/restore with SQLite snapshot backups (.db files)
- Remove partial export/import feature (backend + frontend)
- Update demo seed to write directly to SQLite
- Add "Backup Now" button to settings UI
- Remove StorageConfig file path fields (single database_file remains)
This commit is contained in:
2026-03-25 00:03:19 +03:00
parent 29fb944494
commit 9dfd2365f4
38 changed files with 941 additions and 880 deletions
@@ -1,27 +1,28 @@
"""Automation storage using JSON files."""
"""Automation storage using SQLite."""
import uuid
from datetime import datetime, timezone
from typing import List, Optional
from wled_controller.storage.automation import Automation, Condition
from wled_controller.storage.base_store import BaseJsonStore
from wled_controller.storage.base_sqlite_store import BaseSqliteStore
from wled_controller.storage.database import Database
from wled_controller.utils import get_logger
logger = get_logger(__name__)
class AutomationStore(BaseJsonStore[Automation]):
_json_key = "automations"
class AutomationStore(BaseSqliteStore[Automation]):
_table_name = "automations"
_entity_name = "Automation"
def __init__(self, file_path: str):
super().__init__(file_path, Automation.from_dict)
def __init__(self, db: Database):
super().__init__(db, Automation.from_dict)
# Backward-compatible aliases
get_all_automations = BaseJsonStore.get_all
get_automation = BaseJsonStore.get
delete_automation = BaseJsonStore.delete
get_all_automations = BaseSqliteStore.get_all
get_automation = BaseSqliteStore.get
delete_automation = BaseSqliteStore.delete
def create_automation(
self,
@@ -56,7 +57,7 @@ class AutomationStore(BaseJsonStore[Automation]):
)
self._items[automation_id] = automation
self._save()
self._save_item(automation_id, automation)
logger.info(f"Created automation: {name} ({automation_id})")
return automation
@@ -93,6 +94,6 @@ class AutomationStore(BaseJsonStore[Automation]):
automation.tags = tags
automation.updated_at = datetime.now(timezone.utc)
self._save()
self._save_item(automation_id, automation)
logger.info(f"Updated automation: {automation_id}")
return automation