85 lines
2.5 KiB
Python
85 lines
2.5 KiB
Python
from __future__ import annotations
|
|
|
|
import sqlite3
|
|
from dataclasses import dataclass
|
|
from datetime import datetime
|
|
from pathlib import Path
|
|
|
|
SCHEMA = """
|
|
CREATE TABLE IF NOT EXISTS alerts (
|
|
key TEXT PRIMARY KEY,
|
|
source TEXT NOT NULL,
|
|
title TEXT NOT NULL,
|
|
first_seen TEXT NOT NULL,
|
|
last_alerted TEXT NOT NULL,
|
|
reminded INTEGER NOT NULL DEFAULT 0,
|
|
open INTEGER NOT NULL DEFAULT 1
|
|
)
|
|
"""
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class AlertRecord:
|
|
key: str
|
|
source: str
|
|
title: str
|
|
first_seen: datetime
|
|
last_alerted: datetime
|
|
reminded: bool
|
|
open: bool
|
|
|
|
|
|
class StateStore:
|
|
def __init__(self, path: Path) -> None:
|
|
path.parent.mkdir(parents=True, exist_ok=True)
|
|
self._conn = sqlite3.connect(path)
|
|
self._conn.row_factory = sqlite3.Row
|
|
self._conn.execute(SCHEMA)
|
|
|
|
def close(self) -> None:
|
|
self._conn.close()
|
|
|
|
def load(self) -> dict[str, AlertRecord]:
|
|
rows = self._conn.execute("SELECT * FROM alerts").fetchall()
|
|
return {
|
|
row["key"]: AlertRecord(
|
|
key=row["key"],
|
|
source=row["source"],
|
|
title=row["title"],
|
|
first_seen=datetime.fromisoformat(row["first_seen"]),
|
|
last_alerted=datetime.fromisoformat(row["last_alerted"]),
|
|
reminded=bool(row["reminded"]),
|
|
open=bool(row["open"]),
|
|
)
|
|
for row in rows
|
|
}
|
|
|
|
def save(self, records: list[AlertRecord]) -> None:
|
|
if not records:
|
|
return
|
|
with self._conn:
|
|
self._conn.executemany(
|
|
"""
|
|
INSERT INTO alerts (key, source, title, first_seen, last_alerted, reminded, open)
|
|
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
ON CONFLICT(key) DO UPDATE SET
|
|
source = excluded.source,
|
|
title = excluded.title,
|
|
first_seen = excluded.first_seen,
|
|
last_alerted = excluded.last_alerted,
|
|
reminded = excluded.reminded,
|
|
open = excluded.open
|
|
""",
|
|
[
|
|
(
|
|
r.key,
|
|
r.source,
|
|
r.title,
|
|
r.first_seen.isoformat(),
|
|
r.last_alerted.isoformat(),
|
|
int(r.reminded),
|
|
int(r.open),
|
|
)
|
|
for r in records
|
|
],
|
|
)
|