126 lines
4.3 KiB
Python
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
|