95 lines
3.1 KiB
Python
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()
|