interactive-chat / engine /repositories /play_session.py
Junhoee's picture
Upload 98 files
f646e0b verified
Raw
History Blame Contribute Delete
2.7 kB
"""ν”Œλ ˆμ΄ μ„Έμ…˜ μ˜μ†ν™” β€” SQLite (κ³„νš: docs/plans/persistence.md).
- κΆŒμœ„: CLAUDE.md "ν˜„μž¬ μœ μ €μ˜ μ„œμ‚¬ μœ„μΉ˜ κΆŒμœ„: DB play_session.current_state_id"의 MVP κ΅¬ν˜„.
payload(JSON)에 StoryEngine.snapshot() 전체λ₯Ό λ‹΄λŠ”λ‹€ (story μœ„μΉ˜ + μˆ¨μ€ μƒνƒœ)
- μ½˜ν…μΈ  버전 뢈일치 μ„Έμ…˜μ€ loadμ—μ„œ None (λ¬΄νš¨ν™” β€” μƒˆ μ„Έμ…˜ μ‹œμž‘ μœ λ„)
- 포켓(μ±„νŒ…) 쀑간 μƒνƒœλŠ” μ €μž₯ν•˜μ§€ μ•ŠλŠ”λ‹€ (μœ μ € κ²°μ • β€” 볡원 μ‹œ 포켓 폐기)
"""
from __future__ import annotations
import json
import sqlite3
from contextlib import closing
from datetime import datetime, timedelta, timezone
from pathlib import Path
_SCHEMA = """
CREATE TABLE IF NOT EXISTS play_session (
sid TEXT PRIMARY KEY,
payload TEXT NOT NULL,
content_version TEXT NOT NULL,
updated_at TEXT NOT NULL
)
"""
class PlaySessionRepository:
def __init__(self, db_path: str | Path):
self.db_path = Path(db_path)
self.db_path.parent.mkdir(parents=True, exist_ok=True)
with closing(self._conn()) as conn, conn:
conn.execute(_SCHEMA)
def _conn(self) -> sqlite3.Connection:
conn = sqlite3.connect(self.db_path)
conn.execute("PRAGMA journal_mode=WAL")
return conn
def save(self, sid: str, payload: dict, content_version: str) -> None:
with closing(self._conn()) as conn, conn:
conn.execute(
"INSERT INTO play_session (sid, payload, content_version, updated_at) "
"VALUES (?, ?, ?, ?) "
"ON CONFLICT(sid) DO UPDATE SET payload=excluded.payload, "
"content_version=excluded.content_version, updated_at=excluded.updated_at",
(sid, json.dumps(payload, ensure_ascii=False), content_version,
datetime.now(timezone.utc).isoformat()))
def load(self, sid: str, content_version: str) -> dict | None:
"""μŠ€λƒ…μƒ· λ‘œλ“œ. 미쑴재 λ˜λŠ” μ½˜ν…μΈ  버전 뢈일치면 None."""
with closing(self._conn()) as conn:
row = conn.execute(
"SELECT payload, content_version FROM play_session WHERE sid=?",
(sid,)).fetchone()
if row is None or row[1] != content_version:
return None
return json.loads(row[0])
def purge(self, days: int = 30) -> int:
"""N일 λ―Έκ°±μ‹  μ„Έμ…˜ μ‚­μ œ. μ‚­μ œ 건수 λ°˜ν™˜."""
cutoff = (datetime.now(timezone.utc) - timedelta(days=days)).isoformat()
with closing(self._conn()) as conn, conn:
cur = conn.execute(
"DELETE FROM play_session WHERE updated_at < ?", (cutoff,))
return cur.rowcount