from __future__ import annotations import json import sqlite3 from datetime import datetime from typing import Any class HeavenRepositoryMixin: def list_sector_phase_overrides(self) -> dict[str, str]: with self.connect() as connection: rows = connection.execute( "SELECT name, element FROM sector_phase_overrides ORDER BY updated_at DESC, name" ).fetchall() return {row["name"]: row["element"] for row in rows} def save_sector_phase_override(self, name: str, element: str) -> None: now = datetime.now().astimezone().isoformat(timespec="seconds") with self.connect() as connection: connection.execute( """ INSERT INTO sector_phase_overrides (name, element, updated_at) VALUES (?, ?, ?) ON CONFLICT(name) DO UPDATE SET element = excluded.element, updated_at = excluded.updated_at """, (name, element, now), ) def delete_sector_phase_override(self, name: str) -> bool: with self.connect() as connection: cursor = connection.execute( "DELETE FROM sector_phase_overrides WHERE name = ?", (name,), ) return cursor.rowcount > 0 @staticmethod def _heaven_reading_dict(row: sqlite3.Row | None) -> dict[str, Any] | None: if not row: return None return { "id": int(row["id"]), "mode": str(row["mode"]), "context_date": str(row["context_date"]), "subject": str(row["subject"]), "subject_detail": str(row["subject_detail"]), "answer": str(row["answer"]), "created_at": str(row["created_at"]), } def save_heaven_reading( self, user_id: int, mode: str, context_date: str, subject: str, subject_detail: str, answer: str, context_snapshot: dict[str, Any], dedupe_key: str, ) -> dict[str, Any]: now = datetime.now().astimezone().isoformat(timespec="seconds") snapshot_json = json.dumps( context_snapshot, ensure_ascii=False, separators=(",", ":") ) with self.connect() as connection: connection.execute( """ INSERT INTO heaven_readings (user_id, mode, context_date, subject, subject_detail, answer, context_snapshot, dedupe_key, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) ON CONFLICT(user_id, dedupe_key) DO NOTHING """, ( int(user_id), mode, context_date, subject, subject_detail, answer, snapshot_json, dedupe_key, now, ), ) row = connection.execute( """ SELECT id, mode, context_date, subject, subject_detail, answer, created_at FROM heaven_readings WHERE user_id = ? AND dedupe_key = ? """, (int(user_id), dedupe_key), ).fetchone() connection.execute( """ DELETE FROM heaven_readings WHERE user_id = ? AND mode = ? AND id NOT IN ( SELECT id FROM heaven_readings WHERE user_id = ? AND mode = ? ORDER BY id DESC LIMIT 100 ) """, (int(user_id), mode, int(user_id), mode), ) result = self._heaven_reading_dict(row) if not result: raise ValueError("解读记录保存失败。") return result def list_heaven_readings( self, user_id: int, mode: str, context_date: str = "", limit: int = 100, ) -> list[dict[str, Any]]: clauses = ["user_id = ?", "mode = ?"] parameters: list[Any] = [int(user_id), mode] if context_date: clauses.append("context_date = ?") parameters.append(context_date) parameters.append(max(1, min(100, int(limit)))) with self.connect() as connection: rows = connection.execute( f""" SELECT id, mode, context_date, subject, subject_detail, answer, created_at FROM heaven_readings WHERE {' AND '.join(clauses)} ORDER BY context_date DESC, id DESC LIMIT ? """, parameters, ).fetchall() return [self._heaven_reading_dict(row) for row in rows if row] def latest_heaven_reading( self, user_id: int, mode: str, context_date: str = "" ) -> dict[str, Any] | None: items = self.list_heaven_readings(user_id, mode, context_date, 1) return items[0] if items else None def delete_heaven_reading(self, user_id: int, reading_id: int) -> bool: with self.connect() as connection: cursor = connection.execute( "DELETE FROM heaven_readings WHERE id = ? AND user_id = ?", (int(reading_id), int(user_id)), ) return cursor.rowcount > 0