Files
MoviePilot/app/db/oper/pluginidentity.py
T

82 lines
2.7 KiB
Python

"""插件来源身份的数据访问原语。"""
from collections.abc import Sequence
from typing import cast
from sqlalchemy import select, update
from sqlalchemy.orm import Session
from app.db.base import DbOper, execute_dml
from app.db.models.pluginidentity import PluginIdentity
class PluginIdentityOper(DbOper):
"""在调用方 Session 中查询并条件暂存插件来源身份。"""
def get_by_plugin_id(self, plugin_id: str) -> PluginIdentity | None:
"""按规范化物理插件 ID 查询唯一身份。"""
return self._execute_sync_query(
lambda session: cast(
PluginIdentity | None,
session.execute(
select(PluginIdentity).where(
PluginIdentity.normalized_plugin_id == plugin_id
)
).scalar_one_or_none(),
)
)
def list_by_plugin_ids(
self,
plugin_ids: Sequence[str],
) -> list[PluginIdentity]:
"""批量读取规范化物理插件 ID 对应的身份。"""
if not plugin_ids:
return []
return list(
self._execute_sync_query(
lambda session: session.execute(
select(PluginIdentity).where(
PluginIdentity.normalized_plugin_id.in_(plugin_ids)
)
).scalars()
)
)
def stage_create(self, identity: PluginIdentity) -> None:
"""暂存首次身份并立即暴露数据库唯一键竞争。"""
def stage(session: Session) -> None:
"""加入并 flush 当前调用方事务。"""
session.add(identity)
session.flush()
self._execute_sync_write(stage)
def stage_replace(
self,
identity: PluginIdentity,
*,
expected_revision: int,
) -> bool:
"""仅在当前 revision 匹配时替换整份审计事实。"""
values = {
column.name: getattr(identity, column.name)
for column in PluginIdentity.__table__.columns
if column.name != "id"
}
return bool(
self._execute_sync_write(
lambda session: execute_dml(
session,
update(PluginIdentity)
.where(
PluginIdentity.normalized_plugin_id
== identity.normalized_plugin_id,
PluginIdentity.revision == expected_revision,
)
.values(**values),
execution_options={"synchronize_session": False},
)
)
)