mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-09-08 17:08:35 +08:00
refactor: migrate site read queries to explicit sessions
This commit is contained in:
@@ -43,6 +43,14 @@ def run_legacy_sync_query(operation: Callable[[Session], _R]) -> _R:
|
|||||||
except Exception as close_err: # noqa: BLE001 兼容查询释放失败不改变返回语义
|
except Exception as close_err: # noqa: BLE001 兼容查询释放失败不改变返回语义
|
||||||
logger.error(f"释放数据库会话失败:{close_err}")
|
logger.error(f"释放数据库会话失败:{close_err}")
|
||||||
|
|
||||||
|
|
||||||
|
async def run_legacy_async_query(
|
||||||
|
operation: Callable[[AsyncSession], Awaitable[_R]],
|
||||||
|
) -> _R:
|
||||||
|
"""为移除异步查询装饰器的旧 Model ABI 提供一次性异步会话。"""
|
||||||
|
async with async_session_scope() as db:
|
||||||
|
return await operation(db)
|
||||||
|
|
||||||
def _get_args_db(
|
def _get_args_db(
|
||||||
args: tuple[Any, ...],
|
args: tuple[Any, ...],
|
||||||
kwargs: dict[str, Any],
|
kwargs: dict[str, Any],
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ from sqlalchemy.ext.asyncio import AsyncSession
|
|||||||
from sqlalchemy.orm import Mapped, Session, mapped_column
|
from sqlalchemy.orm import Mapped, Session, mapped_column
|
||||||
|
|
||||||
from app.db.base import Base, get_id_column
|
from app.db.base import Base, get_id_column
|
||||||
from app.db.decorators import db_query, async_db_query
|
from app.db.decorators import run_legacy_async_query
|
||||||
|
|
||||||
|
|
||||||
class SiteIcon(Base):
|
class SiteIcon(Base):
|
||||||
@@ -22,12 +22,25 @@ class SiteIcon(Base):
|
|||||||
base64: Mapped[Optional[str]] = mapped_column(String)
|
base64: Mapped[Optional[str]] = mapped_column(String)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@db_query
|
|
||||||
def get_by_domain(cls, db: Session, domain: str):
|
def get_by_domain(cls, db: Session, domain: str):
|
||||||
|
"""在调用方 Session 中查询站点图标。"""
|
||||||
return db.execute(select(cls).where(cls.domain == domain)).scalars().first()
|
return db.execute(select(cls).where(cls.domain == domain)).scalars().first()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@async_db_query
|
async def async_get_by_domain(
|
||||||
async def async_get_by_domain(cls, db: AsyncSession, domain: str):
|
cls,
|
||||||
result = await db.execute(select(cls).where(cls.domain == domain))
|
db: AsyncSession | None = None,
|
||||||
|
domain: str | None = None,
|
||||||
|
):
|
||||||
|
"""在调用方 AsyncSession 中查询站点图标。"""
|
||||||
|
if domain is None:
|
||||||
|
raise TypeError("domain is required")
|
||||||
|
|
||||||
|
async def query(session: AsyncSession):
|
||||||
|
"""在给定异步会话中执行站点图标查询。"""
|
||||||
|
result = await session.execute(select(cls).where(cls.domain == domain))
|
||||||
return result.scalar_one_or_none()
|
return result.scalar_one_or_none()
|
||||||
|
|
||||||
|
if isinstance(db, AsyncSession):
|
||||||
|
return await query(db)
|
||||||
|
return await run_legacy_async_query(query)
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ from sqlalchemy.ext.asyncio import AsyncSession
|
|||||||
from sqlalchemy.orm import Mapped, Session, mapped_column
|
from sqlalchemy.orm import Mapped, Session, mapped_column
|
||||||
|
|
||||||
from app.db.base import get_id_column, Base
|
from app.db.base import get_id_column, Base
|
||||||
from app.db.decorators import db_query, async_db_query
|
from app.db.decorators import run_legacy_async_query
|
||||||
|
|
||||||
|
|
||||||
class SiteStatistic(Base):
|
class SiteStatistic(Base):
|
||||||
@@ -30,16 +30,29 @@ class SiteStatistic(Base):
|
|||||||
note: Mapped[Optional[Any]] = mapped_column(JSON)
|
note: Mapped[Optional[Any]] = mapped_column(JSON)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@db_query
|
|
||||||
def get_by_domain(cls, db: Session, domain: str):
|
def get_by_domain(cls, db: Session, domain: str):
|
||||||
|
"""在调用方 Session 中查询站点统计。"""
|
||||||
return db.execute(select(cls).where(cls.domain == domain)).scalars().first()
|
return db.execute(select(cls).where(cls.domain == domain)).scalars().first()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@async_db_query
|
async def async_get_by_domain(
|
||||||
async def async_get_by_domain(cls, db: AsyncSession, domain: str):
|
cls,
|
||||||
result = await db.execute(select(cls).where(cls.domain == domain))
|
db: AsyncSession | None = None,
|
||||||
|
domain: str | None = None,
|
||||||
|
):
|
||||||
|
"""在调用方 AsyncSession 中查询站点统计,并兼容旧无会话调用。"""
|
||||||
|
if domain is None:
|
||||||
|
raise TypeError("domain is required")
|
||||||
|
|
||||||
|
async def query(session: AsyncSession):
|
||||||
|
"""在给定异步会话中执行站点统计查询。"""
|
||||||
|
result = await session.execute(select(cls).where(cls.domain == domain))
|
||||||
return result.scalar_one_or_none()
|
return result.scalar_one_or_none()
|
||||||
|
|
||||||
|
if isinstance(db, AsyncSession):
|
||||||
|
return await query(db)
|
||||||
|
return await run_legacy_async_query(query)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def reset(cls, db: Session):
|
def reset(cls, db: Session):
|
||||||
"""在调用方持有的事务中暂存统计表清空操作。"""
|
"""在调用方持有的事务中暂存统计表清空操作。"""
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ from sqlalchemy import String, UniqueConstraint, JSON, select
|
|||||||
from sqlalchemy.orm import Mapped, Session, mapped_column
|
from sqlalchemy.orm import Mapped, Session, mapped_column
|
||||||
|
|
||||||
from app.db.base import get_id_column, Base
|
from app.db.base import get_id_column, Base
|
||||||
from app.db.decorators import db_query
|
|
||||||
|
|
||||||
|
|
||||||
class UserConfig(Base):
|
class UserConfig(Base):
|
||||||
@@ -24,8 +23,8 @@ class UserConfig(Base):
|
|||||||
)
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@db_query
|
|
||||||
def get_by_key(cls, db: Session, username: str, key: str):
|
def get_by_key(cls, db: Session, username: str, key: str):
|
||||||
|
"""在调用方 Session 中查询用户配置。"""
|
||||||
return db.execute(
|
return db.execute(
|
||||||
select(cls).where(cls.username == username, cls.key == key)
|
select(cls).where(cls.username == username, cls.key == key)
|
||||||
).scalars().first()
|
).scalars().first()
|
||||||
|
|||||||
@@ -1042,6 +1042,8 @@ runtime provider,旧插件或测试替换模块级 `settings` 时仍保持原
|
|||||||
无 Session ABI;用户查询与兼容专项 75 项测试、Pylint 及架构基线通过,查询装饰器由 119 个降至 117 个。
|
无 Session ABI;用户查询与兼容专项 75 项测试、Pylint 及架构基线通过,查询装饰器由 119 个降至 117 个。
|
||||||
随后将 Agent 系统设置查询/更新工具切换到已装配的 `RuntimeSettingsService` 窄端口,保留工具构造和
|
随后将 Agent 系统设置查询/更新工具切换到已装配的 `RuntimeSettingsService` 窄端口,保留工具构造和
|
||||||
设置更新返回 ABI;配置债务由 103 个文件降至 101 个文件,系统设置工具专项测试与架构基线通过。
|
设置更新返回 ABI;配置债务由 103 个文件降至 101 个文件,系统设置工具专项测试与架构基线通过。
|
||||||
|
站点图标、站点统计和用户配置的只读 Model 方法随后改为显式 Session 执行,异步无 Session 旧 ABI 由
|
||||||
|
一次性兼容查询会话承接;查询装饰器由 117 个降至 112 个,站点查询专项测试与架构基线通过。
|
||||||
|
|
||||||
同日修正适配器配置下沉边界:OCR、CookieCloud、DoH、Rust 和资源签名等低层实现不再直接依赖
|
同日修正适配器配置下沉边界:OCR、CookieCloud、DoH、Rust 和资源签名等低层实现不再直接依赖
|
||||||
`app.application`,由 `app.runtime.settings` 端口承接组合根注入;未启动装配时仍回退旧 Settings ABI,
|
`app.application`,由 `app.runtime.settings` 端口承接组合根注入;未启动装配时仍回退旧 Settings ABI,
|
||||||
|
|||||||
+2
-3
@@ -13,8 +13,8 @@
|
|||||||
"runtime_to_db": [],
|
"runtime_to_db": [],
|
||||||
"workflow_to_db": []
|
"workflow_to_db": []
|
||||||
},
|
},
|
||||||
"edge_count": 6420,
|
"edge_count": 6419,
|
||||||
"edge_sha256": "7c586d713c6014eb485763f8b7704d9421d95ba7d145910a33163dcb36882914",
|
"edge_sha256": "bc2f57394915b9f90921a91cc4630a4426975ee765ece75a1aa0640080e41b4f",
|
||||||
"edges": [
|
"edges": [
|
||||||
"app -> app.runtime",
|
"app -> app.runtime",
|
||||||
"app -> app.runtime.compat",
|
"app -> app.runtime.compat",
|
||||||
@@ -3557,7 +3557,6 @@
|
|||||||
"app.db.models.user -> app.db.decorators",
|
"app.db.models.user -> app.db.decorators",
|
||||||
"app.db.models.userconfig -> app.db",
|
"app.db.models.userconfig -> app.db",
|
||||||
"app.db.models.userconfig -> app.db.base",
|
"app.db.models.userconfig -> app.db.base",
|
||||||
"app.db.models.userconfig -> app.db.decorators",
|
|
||||||
"app.db.models.workflow -> app.db",
|
"app.db.models.workflow -> app.db",
|
||||||
"app.db.models.workflow -> app.db.base",
|
"app.db.models.workflow -> app.db.base",
|
||||||
"app.db.models.workflow -> app.db.decorators",
|
"app.db.models.workflow -> app.db.decorators",
|
||||||
|
|||||||
+3
-28
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"model_decorators": {
|
"model_decorators": {
|
||||||
"by_kind": {
|
"by_kind": {
|
||||||
"async_db_query": 49,
|
"async_db_query": 47,
|
||||||
"async_db_update": 0,
|
"async_db_update": 0,
|
||||||
"db_query": 68,
|
"db_query": 65,
|
||||||
"db_update": 0
|
"db_update": 0
|
||||||
},
|
},
|
||||||
"count": 117,
|
"count": 112,
|
||||||
"methods": [
|
"methods": [
|
||||||
{
|
{
|
||||||
"decorator": "async_db_query",
|
"decorator": "async_db_query",
|
||||||
@@ -263,26 +263,6 @@
|
|||||||
"file": "app/db/models/site.py",
|
"file": "app/db/models/site.py",
|
||||||
"method": "Site.list_order_by_pri"
|
"method": "Site.list_order_by_pri"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"decorator": "async_db_query",
|
|
||||||
"file": "app/db/models/siteicon.py",
|
|
||||||
"method": "SiteIcon.async_get_by_domain"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"decorator": "db_query",
|
|
||||||
"file": "app/db/models/siteicon.py",
|
|
||||||
"method": "SiteIcon.get_by_domain"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"decorator": "async_db_query",
|
|
||||||
"file": "app/db/models/sitestatistic.py",
|
|
||||||
"method": "SiteStatistic.async_get_by_domain"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"decorator": "db_query",
|
|
||||||
"file": "app/db/models/sitestatistic.py",
|
|
||||||
"method": "SiteStatistic.get_by_domain"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"decorator": "async_db_query",
|
"decorator": "async_db_query",
|
||||||
"file": "app/db/models/siteuserdata.py",
|
"file": "app/db/models/siteuserdata.py",
|
||||||
@@ -548,11 +528,6 @@
|
|||||||
"file": "app/db/models/user.py",
|
"file": "app/db/models/user.py",
|
||||||
"method": "User.async_get_by_name"
|
"method": "User.async_get_by_name"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"decorator": "db_query",
|
|
||||||
"file": "app/db/models/userconfig.py",
|
|
||||||
"method": "UserConfig.get_by_key"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"decorator": "async_db_query",
|
"decorator": "async_db_query",
|
||||||
"file": "app/db/models/workflow.py",
|
"file": "app/db/models/workflow.py",
|
||||||
|
|||||||
Reference in New Issue
Block a user