refactor: complete runtime configuration migration

This commit is contained in:
jxxghp
2026-08-22 19:07:07 +08:00
parent d131f8d571
commit 1bb6e36e8c
80 changed files with 1432 additions and 581 deletions
+9 -9
View File
@@ -115,7 +115,7 @@ class AgentChatOper(DbOper):
}
payload = {key: value for key, value in payload.items() if value is not None}
if chat:
chat.update(self._db, payload)
self._stage_update(chat, payload)
return self.get(session_id=session_id, user_id=user_id) or self.get(session_id=session_id)
chat = AgentChat(
@@ -134,7 +134,7 @@ class AgentChatOper(DbOper):
created_at=now,
updated_at=now,
)
chat.create(self._db)
self._stage_create(chat)
return self.get(session_id=session_id, user_id=user_id) or self.get(session_id=session_id)
def save_agent_messages(
@@ -153,8 +153,8 @@ class AgentChatOper(DbOper):
chat = self.ensure_session(session_id=session_id, user_id=user_id)
if not chat:
return
chat.update(
self._db,
self._stage_update(
chat,
{
"agent_messages": messages or [],
"updated_at": self._now(),
@@ -192,8 +192,8 @@ class AgentChatOper(DbOper):
return
if self.has_custom_title(chat.title):
return
chat.update(
self._db,
self._stage_update(
chat,
{
"title": normalized_title,
"updated_at": self._now(),
@@ -232,8 +232,8 @@ class AgentChatOper(DbOper):
if self.has_custom_title(chat.title)
else self._normalize_title(title, normalized_messages)
)
chat.update(
self._db,
self._stage_update(
chat,
{
"title": normalized_title,
"preview": self._normalize_preview(normalized_messages),
@@ -311,7 +311,7 @@ class AgentChatOper(DbOper):
chat = await self.async_get(session_id=session_id, user_id=user_id)
if not chat:
return False
await AgentChat.async_delete(self._db, chat.id)
await self._stage_async_delete(AgentChat, chat.id)
return True
async def async_stage_delete(
+7 -7
View File
@@ -59,7 +59,7 @@ class DownloadHistoryOper(DbOper):
"""
新增下载历史
"""
DownloadHistory(**kwargs).create(self._db)
self._stage_create(DownloadHistory(**kwargs))
def stage_add(self, payload: dict) -> DownloadHistory:
"""在调用方同步 Session 中暂存下载历史并返回已分配 ID 的记录。"""
@@ -76,7 +76,7 @@ class DownloadHistoryOper(DbOper):
"""
for file_item in file_items:
downloadfile = DownloadFiles(**file_item)
downloadfile.create(self._db)
self._stage_create(downloadfile)
def stage_add_files(self, file_items: List[dict]) -> None:
"""在调用方事务内批量暂存下载文件,不逐条提交。"""
@@ -89,7 +89,7 @@ class DownloadHistoryOper(DbOper):
"""
清空下载历史文件记录
"""
DownloadFiles.truncate(self._db)
self._stage_truncate(DownloadFiles)
def get_files_by_hash(self, download_hash: str, state: Optional[int] = None) -> List[DownloadFiles]:
"""
@@ -171,13 +171,13 @@ class DownloadHistoryOper(DbOper):
"""
异步删除下载记录。
"""
await DownloadHistory.async_delete(self._db, historyid)
await self._stage_async_delete(DownloadHistory, historyid)
def truncate(self):
"""
清空下载记录
"""
DownloadHistory.truncate(self._db)
self._stage_truncate(DownloadHistory)
def get_last_by(self, mtype=None, title: Optional[str] = None, year: Optional[str] = None,
season: Optional[str] = None, episode: Optional[str] = None,
@@ -230,7 +230,7 @@ class DownloadHistoryOper(DbOper):
"""
删除下载记录
"""
DownloadHistory.delete(self._db, historyid)
self._stage_delete(DownloadHistory, historyid)
def stage_delete_history(self, historyid: int) -> None:
"""暂存下载记录删除,不由模型装饰器提交事务。"""
@@ -244,4 +244,4 @@ class DownloadHistoryOper(DbOper):
"""
删除下载文件记录
"""
DownloadFiles.delete(self._db, downloadfileid)
self._stage_delete(DownloadFiles, downloadfileid)
+3 -3
View File
@@ -35,7 +35,7 @@ class MediaServerOper(DbOper):
return False
item = MediaServerItem(**kwargs)
if not item.get_by_server_itemid(self._db, server, item_id):
item.create(self._db)
self._stage_create(item)
return True
return False
@@ -51,10 +51,10 @@ class MediaServerOper(DbOper):
item = MediaServerItem.get_by_server_itemid(self._db, server, item_id)
if item:
item.update(self._db, kwargs)
self._stage_update(item, kwargs)
return False
MediaServerItem(**kwargs).create(self._db)
self._stage_create(MediaServerItem(**kwargs))
return True
def empty(self, server: Optional[str] = None):
+1 -1
View File
@@ -99,7 +99,7 @@ class MessageOper(DbOper):
if k not in Message.__table__.columns.keys(): # noqa
kwargs.pop(k)
return await Message(**kwargs).async_create(self._db)
return await self._stage_async_create(Message(**kwargs))
def list_by_page(self, page: int = 1, count: int = 30) -> list[Message]:
"""
+7 -7
View File
@@ -21,11 +21,11 @@ class PluginDataOper(DbOper):
"""
plugin = PluginData.get_plugin_data_by_key(self._db, plugin_id, key)
if plugin:
plugin.update(self._db, {
self._stage_update(plugin, {
"value": value
})
else:
PluginData(plugin_id=plugin_id, key=key, value=value).create(self._db)
self._stage_create(PluginData(plugin_id=plugin_id, key=key, value=value))
async def async_save(self, plugin_id: str, key: str, value: Any) -> None:
"""
@@ -39,11 +39,11 @@ class PluginDataOper(DbOper):
self._db, plugin_id, key
)
if plugin:
await plugin.async_update(self._db, {"value": value})
await self._stage_async_update(plugin, {"value": value})
else:
await PluginData(
plugin_id=plugin_id, key=key, value=value
).async_create(self._db)
await self._stage_async_create(
PluginData(plugin_id=plugin_id, key=key, value=value)
)
def get_data(self, plugin_id: str, key: Optional[str] = None) -> Any:
"""
@@ -102,7 +102,7 @@ class PluginDataOper(DbOper):
"""
清空插件数据
"""
PluginData.truncate(self._db)
self._stage_truncate(PluginData)
def get_data_all(self, plugin_id: str) -> Any:
"""
+24 -22
View File
@@ -21,7 +21,7 @@ class SiteOper(DbOper):
"""
site = Site(**kwargs)
if not site.get_by_domain(self._db, kwargs.get("domain")):
site.create(self._db)
self._stage_create(site)
return True, "新增站点成功"
return False, "站点已存在"
@@ -113,7 +113,7 @@ class SiteOper(DbOper):
"""
删除站点
"""
Site.delete(self._db, sid)
self._stage_delete(Site, sid)
def reset(self) -> None:
"""清空站点表;兼容入口的事务由组合根统一持有。"""
@@ -130,7 +130,7 @@ class SiteOper(DbOper):
site = Site.get(self._db, sid)
if not site:
return None
site.update(self._db, payload)
self._stage_update(site, payload)
return site
async def async_update(self, sid: int, payload: dict) -> Optional[Site]:
@@ -139,7 +139,7 @@ class SiteOper(DbOper):
"""
site = await self.async_get(sid)
if site:
await site.async_update(self._db, payload)
await self._stage_async_update(site, payload)
return site
def get_by_domain(self, domain: str) -> Optional[Site]:
@@ -179,7 +179,7 @@ class SiteOper(DbOper):
site = Site.get_by_domain(self._db, domain)
if not site:
return False, "站点不存在"
site.update(self._db, {
self._stage_update(site, {
"cookie": cookies
})
return True, "更新站点Cookie成功"
@@ -191,7 +191,7 @@ class SiteOper(DbOper):
site = Site.get_by_domain(self._db, domain)
if not site:
return False, "站点不存在"
site.update(self._db, {
self._stage_update(site, {
"rss": rss
})
return True, "更新站点RSS地址成功"
@@ -215,10 +215,10 @@ class SiteOper(DbOper):
if siteuserdatas:
# 存在则更新
if not payload.get("err_msg"):
siteuserdatas[0].update(self._db, payload)
self._stage_update(siteuserdatas[0], payload)
else:
# 不存在则插入
SiteUserData(**payload).create(self._db)
self._stage_create(SiteUserData(**payload))
return True, "更新站点用户数据成功"
def get_userdata(self) -> List[SiteUserData]:
@@ -287,9 +287,11 @@ class SiteOper(DbOper):
icon_base64 = f"data:image/ico;base64,{icon_base64}" if icon_base64 else ""
siteicon = self.get_icon_by_domain(domain)
if not siteicon:
SiteIcon(name=name, domain=domain, url=icon_url, base64=icon_base64).create(self._db)
self._stage_create(
SiteIcon(name=name, domain=domain, url=icon_url, base64=icon_base64)
)
elif icon_base64:
siteicon.update(self._db, {
self._stage_update(siteicon, {
"url": icon_url,
"base64": icon_base64
})
@@ -313,7 +315,7 @@ class SiteOper(DbOper):
note = dict(sorted(note.items(), key=lambda x: x[0], reverse=True)[:10])
avg_seconds = sum([v for v in note.values()]) // avg_times
sta.update(self._db, {
self._stage_update(sta, {
"success": sta.success + 1,
"seconds": avg_seconds or sta.seconds,
"lst_state": 0,
@@ -326,7 +328,7 @@ class SiteOper(DbOper):
note = {
lst_date: seconds or 1
}
SiteStatistic(
self._stage_create(SiteStatistic(
domain=domain,
success=1,
fail=0,
@@ -334,7 +336,7 @@ class SiteOper(DbOper):
lst_state=0,
lst_mod_date=lst_date,
note=note
).create(self._db)
))
def fail(self, domain: str):
"""
@@ -343,19 +345,19 @@ class SiteOper(DbOper):
lst_date = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
sta = SiteStatistic.get_by_domain(self._db, domain)
if sta:
sta.update(self._db, {
self._stage_update(sta, {
"fail": sta.fail + 1,
"lst_state": 1,
"lst_mod_date": lst_date
})
else:
SiteStatistic(
self._stage_create(SiteStatistic(
domain=domain,
success=0,
fail=1,
lst_state=1,
lst_mod_date=lst_date
).create(self._db)
))
async def async_success(self, domain: str, seconds: Optional[int] = None):
"""
@@ -375,7 +377,7 @@ class SiteOper(DbOper):
note = dict(sorted(note.items(), key=lambda x: x[0], reverse=True)[:10])
avg_seconds = sum([v for v in note.values()]) // avg_times
await sta.async_update(self._db, {
await self._stage_async_update(sta, {
"success": sta.success + 1,
"seconds": avg_seconds or sta.seconds,
"lst_state": 0,
@@ -388,7 +390,7 @@ class SiteOper(DbOper):
note = {
lst_date: seconds or 1
}
await SiteStatistic(
await self._stage_async_create(SiteStatistic(
domain=domain,
success=1,
fail=0,
@@ -396,7 +398,7 @@ class SiteOper(DbOper):
lst_state=0,
lst_mod_date=lst_date,
note=note
).async_create(self._db)
))
async def async_fail(self, domain: str):
"""
@@ -405,16 +407,16 @@ class SiteOper(DbOper):
lst_date = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
sta = await SiteStatistic.async_get_by_domain(self._db, domain)
if sta:
await sta.async_update(self._db, {
await self._stage_async_update(sta, {
"fail": sta.fail + 1,
"lst_state": 1,
"lst_mod_date": lst_date
})
else:
await SiteStatistic(
await self._stage_async_create(SiteStatistic(
domain=domain,
success=0,
fail=1,
lst_state=1,
lst_mod_date=lst_date
).async_create(self._db)
))
+7 -7
View File
@@ -227,7 +227,7 @@ class SubscribeOper(DbOper):
if after_commit:
after_commit(subscribe.id)
return subscribe.id, "订阅已存在"
Subscribe(**_persistable(payload)).create(self._db)
self._stage_create(Subscribe(**_persistable(payload)))
subscribe = self._exists(identity, username)
if not subscribe:
return 0, "新增订阅失败"
@@ -251,7 +251,7 @@ class SubscribeOper(DbOper):
if after_commit:
await after_commit(subscribe.id)
return subscribe.id, "订阅已存在"
await Subscribe(**_persistable(payload)).async_create(self._db)
await self._stage_async_create(Subscribe(**_persistable(payload)))
subscribe = await self._async_exists(identity, username)
if not subscribe:
return 0, "新增订阅失败"
@@ -472,13 +472,13 @@ class SubscribeOper(DbOper):
"""
删除订阅
"""
Subscribe.delete(self._db, rid=sid)
self._stage_delete(Subscribe, sid)
async def async_delete(self, sid: int):
"""
异步删除订阅。
"""
await Subscribe.async_delete(self._db, rid=sid)
await self._stage_async_delete(Subscribe, sid)
async def stage_delete(self, sid: int) -> None:
"""登记订阅删除但不提交,由 Application UnitOfWork 控制事务边界。"""
@@ -493,7 +493,7 @@ class SubscribeOper(DbOper):
subscribe = await self.async_get(sid)
if subscribe:
payload = _normalize_integer_flags(payload)
await subscribe.async_update(self._db, payload)
await self._stage_async_update(subscribe, payload)
return subscribe
async def async_stage_update(
@@ -527,7 +527,7 @@ class SubscribeOper(DbOper):
subscribe = self.get(sid)
if subscribe:
payload = _normalize_integer_flags(payload)
subscribe.update(self._db, payload)
self._stage_update(subscribe, payload)
return subscribe
def list_by_username(self, username: str, state: Optional[str] = None,
@@ -556,7 +556,7 @@ class SubscribeOper(DbOper):
if "id" in kwargs:
kwargs.pop("id")
subscribe = SubscribeHistory(**kwargs)
subscribe.create(self._db)
self._stage_create(subscribe)
def exist_history(
self, media_source: MediaSource, media_id: str,
+1 -1
View File
@@ -47,4 +47,4 @@ class SubscribeHistoryOper(DbOper):
async def async_delete(self, history_id: int) -> None:
"""异步删除订阅历史。"""
await SubscribeHistory.async_delete(self._db, history_id)
await self._stage_async_delete(SubscribeHistory, history_id)
+5 -5
View File
@@ -43,12 +43,12 @@ class SystemConfigOper(DbOper, metaclass=Singleton):
if old_value != value:
# 假值(False/0/None/空容器)同样落库而不是删除记录:
# 读取端以「无记录」表示未配置并回落默认值,删除会使布尔开关的关闭态无法持久化
conf.update(self._db, {"value": value})
self._stage_update(conf, {"value": value})
return True
return None
else:
conf = SystemConfig(key=key, value=value)
conf.create(self._db)
self._stage_create(conf)
return True
async def async_set(self, key: Union[str, SystemConfigKey], value: Any) -> Optional[bool]:
@@ -78,10 +78,10 @@ class SystemConfigOper(DbOper, metaclass=Singleton):
if conf:
# 假值(False/0/None/空容器)同样落库而不是删除记录:
# 读取端以「无记录」表示未配置并回落默认值,删除会使布尔开关的关闭态无法持久化
await conf.async_update(self._db, {"value": value})
await self._stage_async_update(conf, {"value": value})
else:
conf = SystemConfig(key=key, value=value)
await conf.async_create(self._db)
await self._stage_async_create(conf)
# 数据库更新成功后,再更新缓存
with self._rlock:
self.__SYSTEMCONF[key] = copy.deepcopy(value)
@@ -132,5 +132,5 @@ class SystemConfigOper(DbOper, metaclass=Singleton):
# 写入数据库
conf = SystemConfig.get_by_key(self._db, key)
if conf:
conf.delete(self._db, conf.id)
self._stage_delete(SystemConfig, conf.id)
return True
+4 -4
View File
@@ -177,7 +177,7 @@ class TransferHistoryOper(DbOper):
kwargs.update({
"date": time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
})
TransferHistory(**kwargs).create(self._db)
self._stage_create(TransferHistory(**kwargs))
def statistic(self, days: int = 7) -> List[Any]:
"""
@@ -226,7 +226,7 @@ class TransferHistoryOper(DbOper):
"""
删除转移记录
"""
TransferHistory.delete(self._db, historyid)
self._stage_delete(TransferHistory, historyid)
def stage_delete(self, historyid: int) -> None:
"""暂存整理记录删除,不由模型装饰器提交事务。"""
@@ -244,13 +244,13 @@ class TransferHistoryOper(DbOper):
"""
异步删除转移记录。
"""
await TransferHistory.async_delete(self._db, historyid)
await self._stage_async_delete(TransferHistory, historyid)
def truncate(self):
"""
清空转移记录
"""
TransferHistory.truncate(self._db)
self._stage_truncate(TransferHistory)
def add_force(self, **kwargs) -> Optional[TransferHistory]:
"""
+1 -1
View File
@@ -33,7 +33,7 @@ class UserOper(DbOper):
新增用户
"""
user = User(**kwargs)
user.create(self._db)
self._stage_create(user)
def get_by_name(self, name: str) -> Optional[User]:
"""
+3 -3
View File
@@ -31,12 +31,12 @@ class UserConfigOper(DbOper, metaclass=Singleton):
conf = UserConfig.get_by_key(db=self._db, username=username, key=key)
if conf:
if value:
conf.update(self._db, {"value": value})
self._stage_update(conf, {"value": value})
else:
conf.delete(self._db, conf.id)
self._stage_delete(UserConfig, conf.id)
else:
conf = UserConfig(username=username, key=key, value=value)
conf.create(self._db)
self._stage_create(conf)
def get(self, username: str, key: Optional[Union[str, UserConfigKey]] = None) -> Any:
"""
+1 -1
View File
@@ -67,7 +67,7 @@ class WorkflowOper(DbOper):
"""
wf = Workflow(**kwargs)
if not wf.get_by_name(self._db, kwargs.get("name")):
wf.create(self._db)
self._stage_create(wf)
return True, "新增工作流成功"
return False, "工作流已存在"