ducklm/app/events/event_store.py

95 lines
3.1 KiB
Python

from __future__ import annotations
import json
import sqlite3
from pathlib import Path
from app.core.contracts import RuntimeEvent
class SQLiteEventStore:
"""Append-only event store with per-task ordered history."""
def __init__(self, db_path: str | Path) -> None:
self._db_path = Path(db_path)
self._db_path.parent.mkdir(parents=True, exist_ok=True)
self._initialize()
def append(self, event: RuntimeEvent) -> None:
with sqlite3.connect(self._db_path) as conn:
conn.execute(
"""
INSERT INTO events (
event_id, task_id, session_id, sequence, type, timestamp,
payload_json, causation_id, correlation_id
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
""",
(
event.event_id,
event.task_id,
event.session_id,
event.sequence,
event.type,
event.timestamp.isoformat(),
json.dumps(event.payload),
event.causation_id,
event.correlation_id,
),
)
conn.commit()
def list_for_task(self, task_id: str) -> list[RuntimeEvent]:
with sqlite3.connect(self._db_path) as conn:
rows = conn.execute(
"""
SELECT event_id, task_id, session_id, sequence, type, timestamp,
payload_json, causation_id, correlation_id
FROM events
WHERE task_id = ?
ORDER BY sequence ASC
""",
(task_id,),
).fetchall()
return [
RuntimeEvent(
event_id=row[0],
task_id=row[1],
session_id=row[2],
sequence=row[3],
type=row[4],
timestamp=row[5],
payload=json.loads(row[6]),
causation_id=row[7],
correlation_id=row[8],
)
for row in rows
]
def get_latest_sequence(self, task_id: str) -> int:
with sqlite3.connect(self._db_path) as conn:
row = conn.execute(
"SELECT COALESCE(MAX(sequence), 0) FROM events WHERE task_id = ?",
(task_id,),
).fetchone()
return int(row[0]) if row else 0
def _initialize(self) -> None:
with sqlite3.connect(self._db_path) as conn:
conn.execute(
"""
CREATE TABLE IF NOT EXISTS events (
event_id TEXT PRIMARY KEY,
task_id TEXT NOT NULL,
session_id TEXT NOT NULL,
sequence INTEGER NOT NULL,
type TEXT NOT NULL,
timestamp TEXT NOT NULL,
payload_json TEXT NOT NULL,
causation_id TEXT,
correlation_id TEXT NOT NULL,
UNIQUE(task_id, sequence)
)
"""
)
conn.commit()