Files
cmautobuy/client/src/settings_repository.py
T

126 lines
4.3 KiB
Python

"""非敏感应用设置的 SQLite Repository。"""
import json
from datetime import datetime, timezone
from pathlib import Path
from typing import Any, Mapping, Optional, Union
from .db import initialize_database, open_database
from .task_models import AppSettingRecord
PathValue = Union[str, Path]
def _utc_now_iso() -> str:
return datetime.now(timezone.utc).isoformat(timespec="seconds").replace(
"+00:00", "Z"
)
class SettingsRepository:
"""用 JSON 保存非敏感设置;凭据不得传入本类。"""
def __init__(self, db_path: Optional[PathValue] = None):
self._db_path = initialize_database(db_path)
def get(self, setting_key: str, default: Any = None) -> Any:
"""读取设置值;键不存在时返回 default。"""
record = self.get_record(setting_key)
return default if record is None else record.value
def get_record(self, setting_key: str) -> Optional[AppSettingRecord]:
"""读取包含更新时间的完整设置记录。"""
key = self._validate_key(setting_key)
connection = open_database(self._db_path)
try:
row = connection.execute(
"SELECT setting_key, value_json, updated_at"
" FROM app_settings WHERE setting_key = ?",
(key,),
).fetchone()
finally:
connection.close()
if row is None:
return None
return AppSettingRecord(
setting_key=row["setting_key"],
value=json.loads(row["value_json"]),
updated_at=row["updated_at"],
)
def set(
self, setting_key: str, value: Any, updated_at: Optional[str] = None
) -> AppSettingRecord:
"""新增或更新一个非敏感设置并返回保存后的记录。"""
key = self._validate_key(setting_key)
now = updated_at or _utc_now_iso()
value_json = json.dumps(value, ensure_ascii=False)
connection = open_database(self._db_path)
try:
with connection:
connection.execute(
"INSERT INTO app_settings (setting_key, value_json, updated_at)"
" VALUES (?, ?, ?)"
" ON CONFLICT(setting_key) DO UPDATE SET"
" value_json = excluded.value_json,"
" updated_at = excluded.updated_at",
(key, value_json, now),
)
finally:
connection.close()
return AppSettingRecord(key, value, now)
def set_many(
self, values: Mapping[str, Any], updated_at: Optional[str] = None
) -> list[AppSettingRecord]:
"""在同一事务中保存多个非敏感设置。"""
if not values:
return []
normalized = [
(self._validate_key(key), value) for key, value in values.items()
]
now = updated_at or _utc_now_iso()
connection = open_database(self._db_path)
try:
with connection:
for key, value in normalized:
connection.execute(
"INSERT INTO app_settings"
" (setting_key, value_json, updated_at)"
" VALUES (?, ?, ?)"
" ON CONFLICT(setting_key) DO UPDATE SET"
" value_json = excluded.value_json,"
" updated_at = excluded.updated_at",
(key, json.dumps(value, ensure_ascii=False), now),
)
finally:
connection.close()
return [AppSettingRecord(key, value, now) for key, value in normalized]
def delete(self, setting_key: str) -> bool:
"""删除设置;确实删除了一条记录时返回 True。"""
key = self._validate_key(setting_key)
connection = open_database(self._db_path)
try:
with connection:
cursor = connection.execute(
"DELETE FROM app_settings WHERE setting_key = ?", (key,)
)
return cursor.rowcount > 0
finally:
connection.close()
@staticmethod
def _validate_key(setting_key: str) -> str:
key = setting_key.strip()
if not key:
raise ValueError("setting_key 不能为空")
return key