import json from datetime import datetime from typing import Any import pymysql class MySQLRepository: def __init__(self, config: dict[str, Any]) -> None: self.config = config self._ensure_schema() def _connect(self): return pymysql.connect( host=self.config["mysql_host"], port=int(self.config.get("mysql_port", 3306)), user=self.config["mysql_username"], password=self.config["mysql_password"], database=self.config["mysql_database"], charset=self.config.get("mysql_charset", "utf8mb4"), autocommit=True, cursorclass=pymysql.cursors.DictCursor, ) def _ensure_schema(self) -> None: statements = [ """ CREATE TABLE IF NOT EXISTS app_documents ( id BIGINT AUTO_INCREMENT PRIMARY KEY, category VARCHAR(64) NOT NULL, doc_key VARCHAR(128) NOT NULL, sort_value VARCHAR(64) DEFAULT NULL, payload LONGTEXT NOT NULL, created_at DATETIME NOT NULL, updated_at DATETIME NOT NULL, UNIQUE KEY uniq_category_key (category, doc_key), KEY idx_category_sort (category, sort_value) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 """ ] with self._connect() as connection: with connection.cursor() as cursor: for statement in statements: cursor.execute(statement) def read_document(self, category: str, doc_key: str, default: dict[str, Any] | None = None) -> dict[str, Any]: sql = "SELECT payload FROM app_documents WHERE category=%s AND doc_key=%s LIMIT 1" with self._connect() as connection: with connection.cursor() as cursor: cursor.execute(sql, (category, doc_key)) row = cursor.fetchone() if not row: return default or {} return json.loads(row["payload"]) def write_document( self, category: str, doc_key: str, payload: dict[str, Any], *, sort_value: str | None = None, ) -> None: now = datetime.now().strftime("%Y-%m-%d %H:%M:%S") sql = """ INSERT INTO app_documents (category, doc_key, sort_value, payload, created_at, updated_at) VALUES (%s, %s, %s, %s, %s, %s) ON DUPLICATE KEY UPDATE sort_value=VALUES(sort_value), payload=VALUES(payload), updated_at=VALUES(updated_at) """ serialized = json.dumps(payload, ensure_ascii=False) with self._connect() as connection: with connection.cursor() as cursor: cursor.execute(sql, (category, doc_key, sort_value, serialized, now, now)) def list_documents( self, category: str, *, limit: int | None = None, descending: bool = True, ) -> list[dict[str, Any]]: direction = "DESC" if descending else "ASC" sql = f"SELECT payload FROM app_documents WHERE category=%s ORDER BY sort_value {direction}, updated_at {direction}" params: list[Any] = [category] if limit is not None: sql += " LIMIT %s" params.append(limit) with self._connect() as connection: with connection.cursor() as cursor: cursor.execute(sql, params) rows = cursor.fetchall() return [json.loads(row["payload"]) for row in rows]