refactor: make model sessions explicit

This commit is contained in:
jxxghp
2026-08-23 23:33:07 +08:00
parent 820582ab12
commit 6e69258e3c
65 changed files with 1299 additions and 2010 deletions
-5
View File
@@ -5,7 +5,6 @@ from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.orm import Mapped, Session, mapped_column
from app.db.base import Base, get_id_column
from app.db.decorators import legacy_async_db_query, legacy_db_query
class AgentChat(Base):
@@ -50,7 +49,6 @@ class AgentChat(Base):
)
@classmethod
@legacy_db_query
def get_by_session(
cls, db: Session, session_id: str, user_id: Optional[str] = None
) -> Optional["AgentChat"]:
@@ -63,7 +61,6 @@ class AgentChat(Base):
return db.execute(statement.order_by(cls.id.desc())).scalars().first()
@classmethod
@legacy_async_db_query
async def async_get_by_session(
cls, db: AsyncSession, session_id: str, user_id: Optional[str] = None
) -> Optional["AgentChat"]:
@@ -77,7 +74,6 @@ class AgentChat(Base):
return result.scalars().first()
@classmethod
@legacy_db_query
def list_by_page(
cls,
db: Session,
@@ -103,7 +99,6 @@ class AgentChat(Base):
).scalars().all())
@classmethod
@legacy_async_db_query
async def async_list_by_page(
cls,
db: AsyncSession,
+11 -31
View File
@@ -4,7 +4,6 @@ from sqlalchemy import Boolean, Index, Integer, String, Text, select, update
from sqlalchemy.orm import Mapped, Session, mapped_column
from app.db.base import Base, execute_dml, get_id_column
from app.db.decorators import legacy_db_query
def _get_for_user_statement(
@@ -85,47 +84,28 @@ class AgentTask(Base):
return task.id
@classmethod
@legacy_db_query
def get_for_user(
cls,
db: Session | int | None = None,
task_id: int | None = None,
db: Session,
task_id: int,
user_id: Optional[str] = None,
) -> Optional["AgentTask"]:
"""
按任务 ID 和可选用户 ID 查询,并保留无 Session 的旧插件调用方式。
"""
if task_id is None and isinstance(db, int):
task_id, db = db, None
if task_id is None:
raise TypeError("task_id is required")
def query(session: Session) -> Optional["AgentTask"]:
"""在给定会话中读取单个 Agent 任务。"""
return session.execute(
_get_for_user_statement(cls, task_id=task_id, user_id=user_id)
).scalars().first()
return query(db)
"""在调用方会话中按任务 ID 和可选用户 ID 查询。"""
return db.execute(
_get_for_user_statement(cls, task_id=task_id, user_id=user_id)
).scalars().first()
@classmethod
@legacy_db_query
def list_for_user(
cls,
db: Session | None = None,
db: Session,
user_id: Optional[str] = None,
enabled: Optional[bool] = None,
) -> list["AgentTask"]:
"""
按用户和启用状态查询,并保留无 Session 的旧插件调用方式。
"""
def query(session: Session) -> list["AgentTask"]:
"""在给定会话中读取 Agent 任务列表。"""
return list(session.execute(
_list_for_user_statement(cls, user_id=user_id, enabled=enabled)
).scalars().all())
return query(db)
"""在调用方会话中按用户和启用状态查询。"""
return list(db.execute(
_list_for_user_statement(cls, user_id=user_id, enabled=enabled)
).scalars().all())
@classmethod
def update_task(
-3
View File
@@ -4,7 +4,6 @@ from sqlalchemy import Index, Integer, String, Text, delete, select, update
from sqlalchemy.orm import Mapped, Session, mapped_column
from app.db.base import Base, execute_dml, get_id_column
from app.db.decorators import legacy_db_query
from app.db.models.agenttask import AgentTask
@@ -249,7 +248,6 @@ class AgentTaskRun(Base):
return True
@classmethod
@legacy_db_query
def get_by_run_id(
cls,
db: Session,
@@ -261,7 +259,6 @@ class AgentTaskRun(Base):
).scalars().first()
@classmethod
@legacy_db_query
def list_for_task(
cls,
db: Session,
-17
View File
@@ -6,7 +6,6 @@ from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.orm import Mapped, Session, mapped_column
from app.db.base import Base, execute_dml, get_id_column
from app.db.decorators import legacy_async_db_query, legacy_db_query
from app.db.models._constraints import media_identity_constraint
from app.schemas.types import MediaSource
@@ -77,7 +76,6 @@ class DownloadHistory(Base):
)
@classmethod
@legacy_db_query
def get_by_hash(cls, db: Session, download_hash: str):
return db.execute(
select(DownloadHistory)
@@ -86,7 +84,6 @@ class DownloadHistory(Base):
).scalars().first()
@classmethod
@legacy_db_query
def get_by_hashes(cls, db: Session, download_hashes: List[str]):
"""
批量查询多个下载任务的最新历史记录,避免在上层形成 N+1 查询。
@@ -119,7 +116,6 @@ class DownloadHistory(Base):
]
@classmethod
@legacy_db_query
def get_by_media_identity(
cls, db: Session, media_source: MediaSource, media_id: str,
music_type: Optional[str] = None,
@@ -136,7 +132,6 @@ class DownloadHistory(Base):
return list(db.execute(statement).scalars().all())
@classmethod
@legacy_db_query
def list_by_page(
cls, db: Session, page: int = 1, count: int = 30
):
@@ -148,7 +143,6 @@ class DownloadHistory(Base):
).scalars().all())
@classmethod
@legacy_async_db_query
async def async_list_by_page(
cls, db: AsyncSession, page: int = 1, count: int = 30
):
@@ -161,7 +155,6 @@ class DownloadHistory(Base):
return list(result.scalars().all())
@classmethod
@legacy_async_db_query
async def async_list_by_title(
cls,
db: AsyncSession,
@@ -177,13 +170,11 @@ class DownloadHistory(Base):
return list(result.scalars().all())
@classmethod
@legacy_async_db_query
async def async_count(cls, db: AsyncSession):
result = await db.execute(select(func.count(cls.id)))
return result.scalar()
@classmethod
@legacy_async_db_query
async def async_count_by_title(cls, db: AsyncSession, title: str):
result = await db.execute(
select(func.count(cls.id)).filter(_title_like(cls.title, title))
@@ -191,14 +182,12 @@ class DownloadHistory(Base):
return result.scalar()
@classmethod
@legacy_db_query
def get_by_path(cls, db: Session, path: str):
return db.execute(
select(DownloadHistory).where(DownloadHistory.path == path)
).scalars().first()
@classmethod
@legacy_db_query
def get_last_by(
cls,
db: Session,
@@ -237,7 +226,6 @@ class DownloadHistory(Base):
@classmethod
@legacy_db_query
def list_by_user_date(cls, db: Session, date: str, username: Optional[str] = None):
"""
查询某用户某时间之前的下载历史。
@@ -256,7 +244,6 @@ class DownloadHistory(Base):
).scalars().all())
@classmethod
@legacy_db_query
def list_by_date(
cls,
db: Session,
@@ -282,7 +269,6 @@ class DownloadHistory(Base):
).scalars().all())
@classmethod
@legacy_db_query
def list_by_type(cls, db: Session, mtype: str, days: int):
return list(db.execute(
select(DownloadHistory).where(
@@ -345,7 +331,6 @@ class DownloadFiles(Base):
)
@classmethod
@legacy_db_query
def get_by_hash(cls, db: Session, download_hash: str, state: Optional[int] = None):
statement = select(cls).where(cls.download_hash == download_hash)
if state is not None:
@@ -353,7 +338,6 @@ class DownloadFiles(Base):
return list(db.execute(statement).scalars().all())
@classmethod
@legacy_db_query
def get_by_fullpath(cls, db: Session, fullpath: str, all_files: bool = False):
result = db.execute(
select(cls).where(cls.fullpath == fullpath).order_by(cls.id.desc())
@@ -361,7 +345,6 @@ class DownloadFiles(Base):
return list(result.all()) if all_files else result.first()
@classmethod
@legacy_db_query
def get_by_savepath(cls, db: Session, savepath: str):
return list(db.execute(select(cls).where(cls.savepath == savepath)).scalars().all())
-8
View File
@@ -7,7 +7,6 @@ from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.orm import Mapped, Session, mapped_column
from app.db.base import Base, execute_dml, get_id_column
from app.db.decorators import legacy_async_db_query, legacy_db_query
from app.db.models._constraints import media_identity_constraint
from app.schemas.types import MediaSource
@@ -53,12 +52,10 @@ class MediaServerItem(Base):
)
@classmethod
@legacy_db_query
def get_by_itemid(cls, db: Session, item_id: str):
return db.execute(select(cls).where(cls.item_id == item_id)).scalars().first()
@classmethod
@legacy_db_query
def get_by_server_itemid(cls, db: Session, server: str, item_id: str):
return db.execute(
select(cls).where(cls.server == server, cls.item_id == item_id)
@@ -97,7 +94,6 @@ class MediaServerItem(Base):
)
@classmethod
@legacy_db_query
def exist_by_media_identity(
cls, db: Session, media_source: MediaSource, media_id: str, mtype: str,
):
@@ -109,7 +105,6 @@ class MediaServerItem(Base):
)).scalars().first()
@classmethod
@legacy_db_query
def exists_by_title(cls, db: Session, title: str, mtype: str, year: str):
statement = select(cls).where(cls.title == title)
if mtype:
@@ -119,13 +114,11 @@ class MediaServerItem(Base):
return db.execute(statement).scalars().first()
@classmethod
@legacy_async_db_query
async def async_get_by_itemid(cls, db: AsyncSession, item_id: str):
result = await db.execute(select(cls).filter(cls.item_id == item_id))
return result.scalars().first()
@classmethod
@legacy_async_db_query
async def async_exist_by_media_identity(
cls, db: AsyncSession, media_source: MediaSource, media_id: str, mtype: str,
):
@@ -138,7 +131,6 @@ class MediaServerItem(Base):
return result.scalars().first()
@classmethod
@legacy_async_db_query
async def async_exists_by_title(cls, db: AsyncSession, title: str, mtype: str, year: str):
if not mtype and not year:
result = await db.execute(select(cls).filter(cls.title == title))
+45 -73
View File
@@ -5,7 +5,6 @@ from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.orm import Mapped, Session, mapped_column
from app.db.base import Base, execute_dml, get_id_column
from app.db.decorators import legacy_async_db_query, legacy_db_query
class Message(Base):
@@ -49,33 +48,25 @@ class Message(Base):
return self.to_dict()
@classmethod
@legacy_db_query
def list_by_page(
cls,
db: Session | None = None,
db: Session,
page: int = 1,
count: int = 30,
) -> List["Message"]:
"""
分页获取消息记录,兼容显式会话和旧插件无会话调用。
"""
def query(session: Session) -> List["Message"]:
"""在给定同步会话中执行消息分页查询。"""
return list(session.execute(
select(cls)
.order_by(cls.reg_time.desc(), cls.id.desc())
.offset((page - 1) * count)
.limit(count)
).scalars().all())
return query(db)
"""在调用方同步会话中分页获取消息记录。"""
return list(db.execute(
select(cls)
.order_by(cls.reg_time.desc(), cls.id.desc())
.offset((page - 1) * count)
.limit(count)
).scalars().all())
@classmethod
@legacy_db_query
def exists_by_source(
cls,
db: Session | str | None = None,
source: str | None = None,
db: Session,
source: str,
) -> bool:
"""
判断指定来源标识的消息记录是否存在。
@@ -84,44 +75,29 @@ class Message(Base):
:param source: 消息来源唯一标识
:return: 是否存在匹配记录
"""
if source is None and isinstance(db, str):
source, db = db, None
if source is None:
raise TypeError("source is required")
def query(session: Session) -> bool:
"""在给定同步会话中执行来源存在性查询。"""
return session.execute(
select(cls.id).where(cls.source == source).limit(1)
).scalars().first() is not None
return query(db)
return db.execute(
select(cls.id).where(cls.source == source).limit(1)
).scalars().first() is not None
@classmethod
@legacy_async_db_query
async def async_list_by_page(
cls, db: AsyncSession | None = None, page: int = 1, count: int = 30
cls, db: AsyncSession, page: int = 1, count: int = 30
) -> List["Message"]:
"""
异步分页获取消息记录。
"""
async def query(session: AsyncSession) -> List["Message"]:
"""在给定异步会话中执行消息分页查询。"""
result = await session.execute(
select(cls)
.order_by(cls.reg_time.desc(), cls.id.desc())
.offset((page - 1) * count)
.limit(count)
)
return list(result.scalars().all())
return await query(db)
result = await db.execute(
select(cls)
.order_by(cls.reg_time.desc(), cls.id.desc())
.offset((page - 1) * count)
.limit(count)
)
return list(result.scalars().all())
@classmethod
@legacy_async_db_query
async def async_list_sent_by_page(
cls,
db: AsyncSession | None = None,
db: AsyncSession,
page: int = 1,
count: int = 30,
all_clear_before: Optional[str] = None,
@@ -131,35 +107,31 @@ class Message(Base):
"""
分页获取系统发送的通知消息。
"""
async def query(session: AsyncSession) -> List["Message"]:
"""在给定异步会话中执行通知消息分页查询。"""
statement = select(cls).where(cls.action == 1)
if all_clear_before:
statement = statement.where(cls.reg_time > all_clear_before)
if system_clear_before:
statement = statement.where(
or_(
and_(cls.image.isnot(None), cls.image != ""),
cls.reg_time > system_clear_before,
)
statement = select(cls).where(cls.action == 1)
if all_clear_before:
statement = statement.where(cls.reg_time > all_clear_before)
if system_clear_before:
statement = statement.where(
or_(
and_(cls.image.isnot(None), cls.image != ""),
cls.reg_time > system_clear_before,
)
if media_clear_before:
statement = statement.where(
or_(
cls.image.is_(None),
cls.image == "",
cls.reg_time > media_clear_before,
)
)
result = await session.execute(
statement
.order_by(cls.reg_time.desc(), cls.id.desc())
.offset((page - 1) * count)
.limit(count)
)
return list(result.scalars().all())
return await query(db)
if media_clear_before:
statement = statement.where(
or_(
cls.image.is_(None),
cls.image == "",
cls.reg_time > media_clear_before,
)
)
result = await db.execute(
statement
.order_by(cls.reg_time.desc(), cls.id.desc())
.offset((page - 1) * count)
.limit(count)
)
return list(result.scalars().all())
@classmethod
def delete_before(
+16 -44
View File
@@ -5,10 +5,6 @@ from sqlalchemy.orm import Mapped, Session, mapped_column
from datetime import datetime
from app.db.base import Base, get_id_column
from app.db.decorators import (
legacy_async_db_query,
legacy_db_query,
)
def _get_by_user_id_statement(model: type["PassKey"], user_id: int):
@@ -54,75 +50,51 @@ class PassKey(Base):
transports: Mapped[Optional[str]] = mapped_column(String, nullable=True)
@classmethod
@legacy_db_query
def get_by_user_id(
cls,
db: Session | int | None = None,
user_id: int | None = None,
db: Session,
user_id: int,
):
"""获取用户的所有 PassKey,并保留无 Session 的旧插件调用方式"""
if user_id is None and isinstance(db, int):
user_id, db = db, None
if user_id is None:
raise TypeError("user_id is required")
def query(session: Session):
"""在给定会话中执行启用凭证查询。"""
return list(session.execute(
_get_by_user_id_statement(cls, user_id)
).scalars().all())
return query(db)
"""在调用方 Session 中获取用户的所有启用 PassKey。"""
return list(db.execute(
_get_by_user_id_statement(cls, user_id)
).scalars().all())
@classmethod
@legacy_async_db_query
async def async_get_by_user_id(cls, db: AsyncSession, user_id: int):
"""异步获取用户的所有 PassKey,并保留旧插件无 Session 调用"""
"""在调用方 AsyncSession 中获取用户的所有启用 PassKey。"""
result = await db.execute(
_get_by_user_id_statement(cls, user_id)
)
return list(result.scalars().all())
@classmethod
@legacy_db_query
def get_by_credential_id(
cls,
db: Session | str | None = None,
credential_id: str | None = None,
db: Session,
credential_id: str,
):
"""按凭证 ID 获取 PassKey,并保留无 Session 的旧插件调用方式"""
if credential_id is None and isinstance(db, str):
credential_id, db = db, None
if credential_id is None:
raise TypeError("credential_id is required")
def query(session: Session):
"""在给定会话中执行启用凭证查询。"""
return session.execute(
_get_by_credential_id_statement(cls, credential_id)
).scalars().first()
return query(db)
"""在调用方 Session 中按凭证 ID 获取启用 PassKey。"""
return db.execute(
_get_by_credential_id_statement(cls, credential_id)
).scalars().first()
@classmethod
@legacy_async_db_query
async def async_get_by_credential_id(cls, db: AsyncSession, credential_id: str):
"""异步根据凭证 ID 获取 PassKey,并保留旧插件无 Session 调用"""
"""在调用方 AsyncSession 中根据凭证 ID 获取启用 PassKey。"""
result = await db.execute(
_get_by_credential_id_statement(cls, credential_id)
)
return result.scalars().first()
@classmethod
@legacy_db_query
def get_by_id(cls, db: Session, passkey_id: int):
"""根据 ID 获取 PassKey,并保留旧插件无 Session 调用"""
"""在调用方 Session 中根据 ID 获取 PassKey。"""
return db.execute(select(cls).where(cls.id == passkey_id)).scalars().first()
@classmethod
@legacy_async_db_query
async def async_get_by_id(cls, db: AsyncSession, passkey_id: int):
"""异步根据 ID 获取 PassKey,并保留旧插件无 Session 调用"""
"""在调用方 AsyncSession 中根据 ID 获取 PassKey"""
result = await db.execute(
select(cls).filter(cls.id == passkey_id)
)
+12 -31
View File
@@ -4,7 +4,6 @@ from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.orm import Mapped, Session, mapped_column
from app.db.base import get_id_column, Base
from app.db.decorators import legacy_async_db_query, legacy_db_query
class PluginData(Base):
@@ -21,44 +20,32 @@ class PluginData(Base):
)
@classmethod
@legacy_db_query
def get_plugin_data(cls, db: Session | None = None, plugin_id: str | None = None):
"""在调用方 Session 中读取插件全部数据,并兼容旧无会话入口。"""
if plugin_id is None:
raise TypeError("plugin_id is required")
def get_plugin_data(cls, db: Session, plugin_id: str):
"""在调用方 Session 中读取插件全部数据。"""
return list(db.execute(select(cls).where(cls.plugin_id == plugin_id)).scalars().all())
@classmethod
@legacy_async_db_query
async def async_get_plugin_data(
cls, db: AsyncSession | None = None, plugin_id: str | None = None
cls, db: AsyncSession, plugin_id: str
):
"""在调用方 AsyncSession 中读取插件全部数据,并兼容旧无会话入口"""
if plugin_id is None:
raise TypeError("plugin_id is required")
"""在调用方 AsyncSession 中读取插件全部数据。"""
result = await db.execute(select(cls).where(cls.plugin_id == plugin_id))
return list(result.scalars().all())
@classmethod
@legacy_db_query
def get_plugin_data_by_key(
cls, db: Session | None = None, plugin_id: str | None = None, key: str | None = None
cls, db: Session, plugin_id: str, key: str
):
"""在调用方 Session 中按键读取插件数据,并兼容旧无会话入口"""
if plugin_id is None or key is None:
raise TypeError("plugin_id and key are required")
"""在调用方 Session 中按键读取插件数据。"""
return db.execute(
select(cls).where(cls.plugin_id == plugin_id, cls.key == key)
).scalars().first()
@classmethod
@legacy_async_db_query
async def async_get_plugin_data_by_key(
cls, db: AsyncSession | None = None, plugin_id: str | None = None, key: str | None = None
cls, db: AsyncSession, plugin_id: str, key: str
):
"""在调用方 AsyncSession 中按键读取插件数据,并兼容旧无会话入口"""
if plugin_id is None or key is None:
raise TypeError("plugin_id and key are required")
"""在调用方 AsyncSession 中按键读取插件数据。"""
result = await db.execute(
select(cls).where(cls.plugin_id == plugin_id, cls.key == key)
)
@@ -75,22 +62,16 @@ class PluginData(Base):
db.execute(delete(cls).where(cls.plugin_id == plugin_id))
@classmethod
@legacy_db_query
def get_plugin_data_by_plugin_id(
cls, db: Session | None = None, plugin_id: str | None = None
cls, db: Session, plugin_id: str
):
"""在调用方 Session 中按插件 ID 读取数据,并兼容旧无会话入口"""
if plugin_id is None:
raise TypeError("plugin_id is required")
"""在调用方 Session 中按插件 ID 读取数据。"""
return list(db.execute(select(cls).where(cls.plugin_id == plugin_id)).scalars().all())
@classmethod
@legacy_async_db_query
async def async_get_plugin_data_by_plugin_id(
cls, db: AsyncSession | None = None, plugin_id: str | None = None
cls, db: AsyncSession, plugin_id: str
):
"""在调用方 AsyncSession 中按插件 ID 读取数据,并兼容旧无会话入口"""
if plugin_id is None:
raise TypeError("plugin_id is required")
"""在调用方 AsyncSession 中按插件 ID 读取数据。"""
result = await db.execute(select(cls).where(cls.plugin_id == plugin_id))
return list(result.scalars().all())
+35 -92
View File
@@ -6,7 +6,6 @@ from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.orm import Mapped, Session, mapped_column
from app.db.base import Base, get_id_column
from app.db.decorators import legacy_async_db_query, legacy_db_query
class Site(Base):
@@ -58,122 +57,66 @@ class Site(Base):
downloader: Mapped[Optional[str]] = mapped_column(String)
@classmethod
@legacy_db_query
def get_by_domain(cls, db: Session | str | None = None, domain: str | None = None):
"""按域名查询站点,兼容显式会话和旧插件无会话调用。"""
if domain is None and isinstance(db, str):
domain, db = db, None
if domain is None:
raise TypeError("domain is required")
def query(session: Session):
"""在给定同步会话中执行域名查询。"""
return session.execute(select(cls).where(cls.domain == domain)).scalars().first()
return query(db)
def get_by_domain(cls, db: Session, domain: str):
"""在调用方 Session 中按域名查询站点。"""
return db.execute(select(cls).where(cls.domain == domain)).scalars().first()
@classmethod
@legacy_async_db_query
async def async_get_by_domain(
cls,
db: AsyncSession | str | None = None,
domain: str | None = None,
db: AsyncSession,
domain: str,
):
"""异步按域名查询站点,兼容显式会话和旧插件无会话调用"""
if domain is None and isinstance(db, str):
domain, db = db, None
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 await query(db)
"""在调用方 AsyncSession 中按域名查询站点"""
result = await db.execute(select(cls).where(cls.domain == domain))
return result.scalar_one_or_none()
@classmethod
@legacy_async_db_query
async def async_get_by_name(
cls,
db: AsyncSession | str | None = None,
name: str | None = None,
db: AsyncSession,
name: str,
):
"""异步按站点名称查询,兼容显式会话和旧插件无会话调用"""
if name is None and isinstance(db, str):
name, db = db, None
if name is None:
raise TypeError("name is required")
async def query(session: AsyncSession):
"""在给定异步会话中执行名称查询。"""
result = await session.execute(select(cls).where(cls.name == name))
return result.scalar_one_or_none()
return await query(db)
"""在调用方 AsyncSession 中按站点名称查询"""
result = await db.execute(select(cls).where(cls.name == name))
return result.scalar_one_or_none()
@classmethod
@legacy_db_query
def get_actives(cls, db: Session | None = None):
"""查询启用站点,兼容显式会话和旧插件无会话调用。"""
def query(session: Session):
"""在给定同步会话中执行启用站点查询。"""
return list(session.execute(select(cls).where(cls.is_active.is_(True))).scalars().all())
return query(db)
def get_actives(cls, db: Session):
"""在调用方 Session 中查询启用站点。"""
return list(db.execute(
select(cls).where(cls.is_active.is_(True))
).scalars().all())
@classmethod
@legacy_async_db_query
async def async_get_actives(cls, db: AsyncSession | None = None):
"""异步查询启用站点,兼容显式会话和旧插件无会话调用。"""
async def query(session: AsyncSession):
"""在给定异步会话中执行启用站点查询。"""
result = await session.execute(select(cls).where(cls.is_active.is_(True)))
return list(result.scalars().all())
return await query(db)
async def async_get_actives(cls, db: AsyncSession):
"""在调用方 AsyncSession 中查询启用站点。"""
result = await db.execute(select(cls).where(cls.is_active.is_(True)))
return list(result.scalars().all())
@classmethod
@legacy_db_query
def list_order_by_pri(cls, db: Session | None = None):
"""按优先级升序查询站点,兼容显式会话和旧插件无会话调用。"""
def query(session: Session):
"""在给定同步会话中执行优先级查询。"""
return list(session.execute(select(cls).order_by(cls.pri)).scalars().all())
return query(db)
def list_order_by_pri(cls, db: Session):
"""在调用方 Session 中按优先级升序查询站点。"""
return list(db.execute(select(cls).order_by(cls.pri)).scalars().all())
@classmethod
@legacy_async_db_query
async def async_list_order_by_pri(cls, db: AsyncSession | None = None):
"""异步按优先级升序查询站点,兼容显式会话和旧插件无会话调用。"""
async def query(session: AsyncSession):
"""在给定异步会话中执行优先级查询。"""
result = await session.execute(select(cls).order_by(cls.pri))
return list(result.scalars().all())
return await query(db)
async def async_list_order_by_pri(cls, db: AsyncSession):
"""在调用方 AsyncSession 中按优先级升序查询站点。"""
result = await db.execute(select(cls).order_by(cls.pri))
return list(result.scalars().all())
@classmethod
@legacy_db_query
def get_domains_by_ids(
cls,
db: Session | list[int] | None = None,
ids: list[int] | None = None,
db: Session,
ids: list[int],
):
"""按 ID 查询域名,兼容显式会话和旧插件无会话调用"""
if ids is None and isinstance(db, list):
ids, db = db, None
if ids is None:
raise TypeError("ids is required")
"""在调用方 Session 中按 ID 查询域名。"""
if not ids:
return []
def query(session: Session):
"""在给定同步会话中执行域名投影查询。"""
return list(session.execute(select(cls.domain).where(cls.id.in_(ids))).scalars().all())
return query(db)
return list(db.execute(
select(cls.domain).where(cls.id.in_(ids))
).scalars().all())
@classmethod
def reset(cls, db: Session):
+4 -13
View File
@@ -4,7 +4,6 @@ from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.orm import Mapped, Session, mapped_column
from app.db.base import Base, get_id_column
from app.db.decorators import legacy_async_db_query
class SiteIcon(Base):
@@ -27,19 +26,11 @@ class SiteIcon(Base):
return db.execute(select(cls).where(cls.domain == domain)).scalars().first()
@classmethod
@legacy_async_db_query
async def async_get_by_domain(
cls,
db: AsyncSession | None = None,
domain: str | None = None,
db: AsyncSession,
domain: str,
):
"""在调用方 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 await query(db)
result = await db.execute(select(cls).where(cls.domain == domain))
return result.scalar_one_or_none()
+5 -14
View File
@@ -6,7 +6,6 @@ from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.orm import Mapped, Session, mapped_column
from app.db.base import get_id_column, Base
from app.db.decorators import legacy_async_db_query
class SiteStatistic(Base):
@@ -35,22 +34,14 @@ class SiteStatistic(Base):
return db.execute(select(cls).where(cls.domain == domain)).scalars().first()
@classmethod
@legacy_async_db_query
async def async_get_by_domain(
cls,
db: AsyncSession | None = None,
domain: str | None = None,
db: AsyncSession,
domain: str,
):
"""在调用方 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 await query(db)
"""在调用方 AsyncSession 中查询站点统计。"""
result = await db.execute(select(cls).where(cls.domain == domain))
return result.scalar_one_or_none()
@classmethod
def reset(cls, db: Session):
-6
View File
@@ -6,7 +6,6 @@ from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.orm import Mapped, Session, mapped_column
from app.db.base import Base, execute_dml, get_id_column
from app.db.decorators import legacy_async_db_query, legacy_db_query
class SiteUserData(Base):
@@ -61,7 +60,6 @@ class SiteUserData(Base):
)
@classmethod
@legacy_db_query
def get_by_domain(cls, db: Session, domain: str, workdate: Optional[str] = None, worktime: Optional[str] = None):
statement = select(cls).where(cls.domain == domain)
if workdate and worktime:
@@ -72,7 +70,6 @@ class SiteUserData(Base):
return list(db.execute(statement).scalars().all())
@classmethod
@legacy_async_db_query
async def async_get_by_domain(cls, db: AsyncSession, domain: str, workdate: Optional[str] = None, worktime: Optional[str] = None):
query = select(cls).filter(cls.domain == domain)
if workdate and worktime:
@@ -83,12 +80,10 @@ class SiteUserData(Base):
return list(result.scalars().all())
@classmethod
@legacy_db_query
def get_by_date(cls, db: Session, date: str):
return list(db.execute(select(cls).where(cls.updated_day == date)).scalars().all())
@classmethod
@legacy_db_query
def get_latest(cls, db: Session):
"""
获取各站点最新一天的数据
@@ -113,7 +108,6 @@ class SiteUserData(Base):
).scalars().all())
@classmethod
@legacy_async_db_query
async def async_get_latest(cls, db: AsyncSession):
"""
异步获取各站点最新一天的数据
+107 -210
View File
@@ -6,7 +6,6 @@ from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.orm import Mapped, Session, mapped_column
from app.db.base import get_id_column, Base
from app.db.decorators import legacy_async_db_query, legacy_db_query
from app.db.models._constraints import media_identity_constraint
from app.schemas.types import MUSIC_ENTITY_RECORDING, MediaSource
@@ -140,9 +139,8 @@ class Subscribe(Base):
return condition
@classmethod
@legacy_db_query
def exists(
cls, db: Session | MediaSource | None = None,
cls, db: Session,
media_source: MediaSource | str | None = None,
media_id: str | None = None,
season: Optional[int] = None,
@@ -150,27 +148,21 @@ class Subscribe(Base):
music_type: Optional[str] = None,
):
"""按媒体身份、季号与剧集组查询已有订阅。"""
if db is not None and not isinstance(db, Session):
media_source, media_id, db = db, media_source, None
condition = cls._identity_condition(
media_source, media_id, music_type
)
if condition is None:
return None
def query(session: Session):
"""在给定会话中执行订阅身份查询。"""
statement = select(cls).where(condition)
if season is not None:
statement = statement.where(cls.season == season)
return session.execute(
statement.where(cls.episode_group == episode_group)
).scalars().first()
return query(db)
statement = select(cls).where(condition)
if season is not None:
statement = statement.where(cls.season == season)
return db.execute(
statement.where(cls.episode_group == episode_group)
).scalars().first()
@classmethod
@legacy_async_db_query
async def async_exists(
cls, db: AsyncSession | MediaSource | None = None,
cls, db: AsyncSession,
media_source: MediaSource | str | None = None,
media_id: str | None = None,
season: Optional[int] = None,
@@ -178,28 +170,22 @@ class Subscribe(Base):
music_type: Optional[str] = None,
):
"""异步按媒体身份、季号与剧集组查询已有订阅。"""
if db is not None and not isinstance(db, AsyncSession):
media_source, media_id, db = db, media_source, None
condition = cls._identity_condition(
media_source, media_id, music_type
)
if condition is None:
return None
async def query(session: AsyncSession):
"""在给定异步会话中执行订阅身份查询。"""
statement = select(cls).where(condition)
if season is not None:
statement = statement.where(cls.season == season)
result = await session.execute(
statement.where(cls.episode_group == episode_group)
)
return result.scalars().first()
return await query(db)
statement = select(cls).where(condition)
if season is not None:
statement = statement.where(cls.season == season)
result = await db.execute(
statement.where(cls.episode_group == episode_group)
)
return result.scalars().first()
@classmethod
@legacy_db_query
def exists_by_username(
cls, db: Session | str | None = None,
cls, db: Session,
username: str | MediaSource | None = None,
media_source: MediaSource | str | None = None,
media_id: str | None = None,
@@ -210,8 +196,6 @@ class Subscribe(Base):
"""
按订阅 owner、媒体身份、季号与剧集组查询订阅行。
"""
if db is not None and not isinstance(db, Session):
username, media_source, media_id, db = db, username, media_source, None
if not username:
return None
condition = cls._identity_condition(
@@ -219,20 +203,16 @@ class Subscribe(Base):
)
if condition is None:
return None
def query(session: Session):
"""在给定会话中执行订阅 owner 查询。"""
statement = select(cls).where(cls.username == username, condition)
if season is not None:
statement = statement.where(cls.season == season)
return session.execute(
statement.where(cls.episode_group == episode_group)
).scalars().first()
return query(db)
statement = select(cls).where(cls.username == username, condition)
if season is not None:
statement = statement.where(cls.season == season)
return db.execute(
statement.where(cls.episode_group == episode_group)
).scalars().first()
@classmethod
@legacy_async_db_query
async def async_exists_by_username(
cls, db: AsyncSession | str | None = None,
cls, db: AsyncSession,
username: str | MediaSource | None = None,
media_source: MediaSource | str | None = None,
media_id: str | None = None, season: Optional[int] = None,
@@ -242,8 +222,6 @@ class Subscribe(Base):
"""
异步按订阅 owner、媒体身份、季号与剧集组查询订阅行。
"""
if db is not None and not isinstance(db, AsyncSession):
username, media_source, media_id, db = db, username, media_source, None
if not username:
return None
condition = cls._identity_condition(
@@ -251,112 +229,76 @@ class Subscribe(Base):
)
if condition is None:
return None
async def query(session: AsyncSession):
"""在给定异步会话中执行订阅 owner 查询。"""
statement = select(cls).where(cls.username == username, condition)
if season is not None:
statement = statement.where(cls.season == season)
result = await session.execute(
statement.where(cls.episode_group == episode_group)
)
return result.scalars().first()
return await query(db)
statement = select(cls).where(cls.username == username, condition)
if season is not None:
statement = statement.where(cls.season == season)
result = await db.execute(
statement.where(cls.episode_group == episode_group)
)
return result.scalars().first()
@classmethod
@legacy_db_query
def get_by_state(cls, db: Session | str | None = None, state: str | None = None):
"""按状态列表查询订阅,兼容显式会话和旧插件无会话调用。"""
if not isinstance(db, Session):
state, db = db if state is None else state, None
def query(session: Session):
"""在给定会话中执行状态查询。"""
statement = select(cls)
if state:
statement = statement.where(cls.state.in_(state.split(',')))
return list(session.execute(statement).scalars().all())
return query(db)
def get_by_state(cls, db: Session, state: str | None = None):
"""在调用方 Session 中按状态列表查询订阅。"""
statement = select(cls)
if state:
statement = statement.where(cls.state.in_(state.split(',')))
return list(db.execute(statement).scalars().all())
@classmethod
@legacy_async_db_query
async def async_get_by_state(
cls, db: AsyncSession | str | None = None, state: str | None = None
cls, db: AsyncSession, state: str | None = None
):
"""异步按状态列表查询订阅,兼容显式会话和旧插件无会话调用"""
if not isinstance(db, AsyncSession):
state, db = db if state is None else state, None
async def query(session: AsyncSession):
"""在给定异步会话中执行状态查询。"""
statement = select(cls)
if state:
statement = statement.where(cls.state.in_(state.split(',')))
result = await session.execute(statement)
return list(result.scalars().all())
return await query(db)
"""在调用方 AsyncSession 中按状态列表查询订阅"""
statement = select(cls)
if state:
statement = statement.where(cls.state.in_(state.split(',')))
result = await db.execute(statement)
return list(result.scalars().all())
@classmethod
@legacy_db_query
def get_by_title(
cls, db: Session | str | None = None, title: str | None = None,
cls, db: Session, title: str,
season: Optional[int] = None,
):
"""按标题查询订阅,兼容显式会话和旧插件无会话调用"""
if not isinstance(db, Session):
title, db = db if title is None else title, None
def query(session: Session):
"""在给定会话中执行标题查询。"""
statement = select(cls).where(cls.name == title)
if season is not None:
statement = statement.where(cls.season == season)
return session.execute(statement).scalars().first()
return query(db)
"""在调用方 Session 中按标题查询订阅。"""
statement = select(cls).where(cls.name == title)
if season is not None:
statement = statement.where(cls.season == season)
return db.execute(statement).scalars().first()
@classmethod
@legacy_async_db_query
async def async_get_by_title(
cls, db: AsyncSession | str | None = None, title: str | None = None,
cls, db: AsyncSession, title: str,
season: Optional[int] = None,
):
"""异步按标题查询订阅,兼容显式会话和旧插件无会话调用"""
if not isinstance(db, AsyncSession):
title, db = db if title is None else title, None
async def query(session: AsyncSession):
"""在给定异步会话中执行标题查询。"""
statement = select(cls).where(cls.name == title)
if season is not None:
statement = statement.where(cls.season == season)
result = await session.execute(statement)
return result.scalars().first()
return await query(db)
"""在调用方 AsyncSession 中按标题查询订阅"""
statement = select(cls).where(cls.name == title)
if season is not None:
statement = statement.where(cls.season == season)
result = await db.execute(statement)
return result.scalars().first()
@classmethod
@legacy_async_db_query
async def async_list_by_title(
cls, db: AsyncSession | str | None = None, title: str | None = None,
cls, db: AsyncSession, title: str,
season: Optional[int] = None,
):
"""异步按标题查询候选订阅列表,兼容显式会话和旧插件无会话调用"""
if not isinstance(db, AsyncSession):
title, db = db if title is None else title, None
async def query(session: AsyncSession):
"""在给定异步会话中执行标题列表查询。"""
statement = select(cls).where(cls.name == title)
if season is not None:
statement = statement.where(cls.season == season)
result = await session.execute(statement)
return list(result.scalars().all())
return await query(db)
"""在调用方 AsyncSession 中按标题查询候选订阅列表"""
statement = select(cls).where(cls.name == title)
if season is not None:
statement = statement.where(cls.season == season)
result = await db.execute(statement)
return list(result.scalars().all())
@classmethod
@legacy_db_query
def list_by_media_identity(
cls, db: Session | MediaSource | None = None,
cls, db: Session,
media_source: MediaSource | str | None = None,
media_id: str | None = None,
music_type: Optional[str] = None,
):
"""同步按统一媒体身份查询候选订阅列表。"""
if db is not None and not isinstance(db, Session):
media_source, media_id, db = db, media_source, None
condition = cls._identity_condition(
media_source=media_source,
media_id=media_id,
@@ -364,22 +306,16 @@ class Subscribe(Base):
)
if condition is None:
return []
def query(session: Session):
"""在给定会话中执行媒体身份列表查询。"""
return list(session.execute(select(cls).where(condition)).scalars().all())
return query(db)
return list(db.execute(select(cls).where(condition)).scalars().all())
@classmethod
@legacy_async_db_query
async def async_list_by_media_identity(
cls, db: AsyncSession | MediaSource | None = None,
cls, db: AsyncSession,
media_source: MediaSource | str | None = None,
media_id: str | None = None,
music_type: Optional[str] = None,
):
"""异步按统一媒体身份查询候选订阅列表。"""
if db is not None and not isinstance(db, AsyncSession):
media_source, media_id, db = db, media_source, None
condition = cls._identity_condition(
media_source=media_source,
media_id=media_id,
@@ -387,16 +323,12 @@ class Subscribe(Base):
)
if condition is None:
return []
async def query(session: AsyncSession):
"""在给定异步会话中执行媒体身份列表查询。"""
result = await session.execute(select(cls).where(condition))
return list(result.scalars().all())
return await query(db)
result = await db.execute(select(cls).where(condition))
return list(result.scalars().all())
@classmethod
@legacy_db_query
def get_by(
cls, db: Session | str | None = None,
cls, db: Session,
type: str | MediaSource | None = None,
media_source: MediaSource | str | None = None,
media_id: str | None = None,
@@ -406,8 +338,6 @@ class Subscribe(Base):
"""
根据条件查询订阅
"""
if db is not None and not isinstance(db, Session):
type, media_source, media_id, db = db, type, media_source, None
condition = cls._identity_condition(
media_source, media_id, music_type
)
@@ -416,15 +346,11 @@ class Subscribe(Base):
statement = select(cls).where(condition, cls.type == type)
if season is not None:
statement = statement.where(cls.season == season)
def query(session: Session):
"""在给定会话中执行类型媒体查询。"""
return session.execute(statement).scalars().first()
return query(db)
return db.execute(statement).scalars().first()
@classmethod
@legacy_async_db_query
async def async_get_by(
cls, db: AsyncSession | str | None = None,
cls, db: AsyncSession,
type: str | MediaSource | None = None,
media_source: MediaSource | str | None = None,
media_id: str | None = None,
@@ -434,8 +360,6 @@ class Subscribe(Base):
"""
根据条件查询订阅
"""
if db is not None and not isinstance(db, AsyncSession):
type, media_source, media_id, db = db, type, media_source, None
condition = cls._identity_condition(
media_source, media_id, music_type
)
@@ -444,76 +368,49 @@ class Subscribe(Base):
query = select(cls).filter(condition, cls.type == type)
if season is not None:
query = query.filter(cls.season == season)
async def execute_query(session: AsyncSession):
"""在给定异步会话中执行类型媒体查询。"""
result = await session.execute(query)
return result.scalars().first()
return await execute_query(db)
result = await db.execute(query)
return result.scalars().first()
@classmethod
@legacy_db_query
def list_by_username(cls, db: Session | str | None = None, username: str | None = None,
def list_by_username(cls, db: Session, username: str,
state: Optional[str] = None, mtype: Optional[str] = None):
"""按用户筛选订阅,兼容显式会话和旧插件无会话调用"""
if not isinstance(db, Session):
username, db = db if username is None else username, None
def query(session: Session):
"""在给定会话中执行用户筛选查询。"""
statement = select(cls).where(cls.username == username)
if state:
statement = statement.where(cls.state == state)
if mtype:
statement = statement.where(cls.type == mtype)
return list(session.execute(statement).scalars().all())
return query(db)
"""在调用方 Session 中按用户筛选订阅。"""
statement = select(cls).where(cls.username == username)
if state:
statement = statement.where(cls.state == state)
if mtype:
statement = statement.where(cls.type == mtype)
return list(db.execute(statement).scalars().all())
@classmethod
@legacy_async_db_query
async def async_list_by_username(cls, db: AsyncSession | str | None = None,
username: str | None = None, state: Optional[str] = None,
async def async_list_by_username(cls, db: AsyncSession,
username: str, state: Optional[str] = None,
mtype: Optional[str] = None):
"""异步按用户筛选订阅,兼容显式会话和旧插件无会话调用"""
if not isinstance(db, AsyncSession):
username, db = db if username is None else username, None
async def query(session: AsyncSession):
"""在给定异步会话中执行用户筛选查询。"""
statement = select(cls).where(cls.username == username)
if state:
statement = statement.where(cls.state == state)
if mtype:
statement = statement.where(cls.type == mtype)
result = await session.execute(statement)
return list(result.scalars().all())
return await query(db)
"""在调用方 AsyncSession 中按用户筛选订阅"""
statement = select(cls).where(cls.username == username)
if state:
statement = statement.where(cls.state == state)
if mtype:
statement = statement.where(cls.type == mtype)
result = await db.execute(statement)
return list(result.scalars().all())
@classmethod
@legacy_db_query
def list_by_type(cls, db: Session | str | None = None, mtype: str | None = None, days: int = 7):
"""按类型查询最近时间窗内的订阅,兼容显式会话和旧插件无会话调用。"""
if not isinstance(db, Session):
mtype, db = db if mtype is None else mtype, None
def query(session: Session):
"""在给定会话中执行时间窗订阅查询。"""
return list(session.execute(select(cls).where(
cls.type == mtype,
cls.date >= time.strftime("%Y-%m-%d %H:%M:%S",
time.localtime(time.time() - 86400 * int(days)))
)).scalars().all())
return query(db)
def list_by_type(cls, db: Session, mtype: str, days: int = 7):
"""在调用方 Session 中按类型查询最近时间窗内的订阅。"""
return list(db.execute(select(cls).where(
cls.type == mtype,
cls.date >= time.strftime("%Y-%m-%d %H:%M:%S",
time.localtime(time.time() - 86400 * int(days)))
)).scalars().all())
@classmethod
@legacy_async_db_query
async def async_list_by_type(cls, db: AsyncSession | str | None = None,
mtype: str | None = None, days: int = 7):
"""异步按类型查询最近时间窗内的订阅,兼容显式会话和旧插件无会话调用。"""
if not isinstance(db, AsyncSession):
mtype, db = db if mtype is None else mtype, None
async def query(session: AsyncSession):
"""在给定异步会话中执行时间窗订阅查询。"""
result = await session.execute(select(cls).where(
cls.type == mtype,
cls.date >= time.strftime("%Y-%m-%d %H:%M:%S",
time.localtime(time.time() - 86400 * int(days)))
))
return list(result.scalars().all())
return await query(db)
async def async_list_by_type(cls, db: AsyncSession,
mtype: str, days: int = 7):
"""在调用方 AsyncSession 中按类型查询最近时间窗内的订阅。"""
result = await db.execute(select(cls).where(
cls.type == mtype,
cls.date >= time.strftime("%Y-%m-%d %H:%M:%S",
time.localtime(time.time() - 86400 * int(days)))
))
return list(result.scalars().all())
+2 -8
View File
@@ -5,7 +5,6 @@ from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.orm import Mapped, Session, mapped_column
from app.db.base import Base, get_id_column
from app.db.decorators import legacy_async_db_query, legacy_db_query
from app.db.models._constraints import media_identity_constraint
from app.schemas.types import MUSIC_ENTITY_RECORDING, MediaSource
@@ -107,9 +106,8 @@ class SubscribeHistory(Base):
)
@classmethod
@legacy_db_query
def list_by_type(cls, db: Session, mtype: str, page: int = 1, count: int = 30):
"""按媒体类型分页查询订阅历史,并保留旧插件无 Session 调用"""
"""在调用方 Session 中按媒体类型分页查询订阅历史。"""
return list(db.execute(
select(cls).where(
cls.type == mtype
@@ -119,9 +117,8 @@ class SubscribeHistory(Base):
).scalars().all())
@classmethod
@legacy_async_db_query
async def async_list_by_type(cls, db: AsyncSession, mtype: str, page: int = 1, count: int = 30):
"""异步按媒体类型分页查询订阅历史,并保留旧插件无 Session 调用"""
"""在调用方 AsyncSession 中按媒体类型分页查询订阅历史"""
result = await db.execute(
select(cls).filter(
cls.type == mtype
@@ -132,7 +129,6 @@ class SubscribeHistory(Base):
return list(result.scalars().all())
@classmethod
@legacy_async_db_query
async def async_list_by_type_and_username(
cls,
db: AsyncSession,
@@ -177,7 +173,6 @@ class SubscribeHistory(Base):
return condition
@classmethod
@legacy_db_query
def exists(
cls, db: Session, media_source: MediaSource, media_id: str,
season: Optional[int] = None,
@@ -197,7 +192,6 @@ class SubscribeHistory(Base):
return db.execute(statement).scalars().first()
@classmethod
@legacy_async_db_query
async def async_exists(
cls, db: AsyncSession, media_source: MediaSource, media_id: str,
season: Optional[int] = None,
+2 -5
View File
@@ -4,7 +4,6 @@ from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.orm import Mapped, Session, mapped_column
from app.db.base import Base, get_id_column
from app.db.decorators import legacy_async_db_query, legacy_db_query
class SystemConfig(Base):
@@ -18,15 +17,13 @@ class SystemConfig(Base):
value: Mapped[Optional[Any]] = mapped_column(JSON)
@classmethod
@legacy_db_query
def get_by_key(cls, db: Session, key: str):
"""按配置键查询系统配置,并保留旧插件无 Session 调用"""
"""在调用方 Session 中按配置键查询系统配置。"""
return db.execute(select(cls).where(cls.key == key)).scalars().first()
@classmethod
@legacy_async_db_query
async def async_get_by_key(cls, db: AsyncSession, key: str):
"""异步按配置键查询系统配置,并保留旧插件无 Session 调用"""
"""在调用方 AsyncSession 中按配置键查询系统配置"""
result = await db.execute(select(cls).where(cls.key == key))
return result.scalar_one_or_none()
+21 -88
View File
@@ -8,10 +8,6 @@ from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.orm import Mapped, Session, mapped_column
from app.db.base import Base, execute_dml, get_id_column
from app.db.decorators import (
legacy_async_db_query,
legacy_db_query,
)
from app.db.models._constraints import media_identity_constraint
from app.schemas.types import MUSIC_ENTITY_ALBUM, MUSIC_ENTITY_RECORDING, MediaSource, MediaType
@@ -97,7 +93,6 @@ class TransferHistory(Base):
)
@classmethod
@legacy_db_query
def list_by_title(cls, db: Session, title: str, page: int = 1, count: int = 30,
status: Optional[bool] = None, wildcard: bool = False):
if wildcard:
@@ -124,7 +119,6 @@ class TransferHistory(Base):
return list(db.execute(statement).scalars().all())
@classmethod
@legacy_async_db_query
async def async_list_by_title(cls, db: AsyncSession, title: str, page: int = 1, count: int = 30,
status: Optional[bool] = None, wildcard: bool = False):
if wildcard:
@@ -152,7 +146,6 @@ class TransferHistory(Base):
return list(result.scalars().all())
@classmethod
@legacy_db_query
def list_by_page(cls, db: Session, page: int = 1, count: int = 30, status: Optional[bool] = None):
statement = select(cls)
if status is not None:
@@ -166,7 +159,6 @@ class TransferHistory(Base):
return list(db.execute(statement).scalars().all())
@classmethod
@legacy_async_db_query
async def async_list_by_page(cls, db: AsyncSession, page: int = 1, count: int = 30,
status: Optional[bool] = None):
if status is not None:
@@ -188,30 +180,19 @@ class TransferHistory(Base):
return list(result.scalars().all())
@classmethod
@legacy_db_query
def get_by_hash(
cls,
db: Session | str | None = None,
download_hash: str | None = None,
db: Session,
download_hash: str,
):
"""按下载哈希查询最新记录,兼容旧插件无会话调用"""
if download_hash is None and isinstance(db, str):
download_hash, db = db, None
if download_hash is None:
raise TypeError("download_hash is required")
def query(session: Session):
"""在调用方提供的同步会话中执行哈希查询。"""
return session.execute(
select(cls).where(cls.download_hash == download_hash)
).scalars().first()
return query(db)
"""在调用方 Session 中按下载哈希查询最新记录。"""
return db.execute(
select(cls).where(cls.download_hash == download_hash)
).scalars().first()
@classmethod
@legacy_db_query
def get_by_src(
cls, db: Session | str | None = None, src: str | None = None,
cls, db: Session, src: str,
storage: Optional[str] = None
) -> Optional["TransferHistory"]:
"""
@@ -222,26 +203,14 @@ class TransferHistory(Base):
:param storage: 源存储类型
:return: 命中的整理记录,未命中时返回 None
"""
if src is None and isinstance(db, str):
src, db = db, None
if src is None:
raise TypeError("src is required")
def query(session: Session):
"""在调用方提供的同步会话中执行源路径查询。"""
statement = select(cls).where(cls.src == src)
if storage:
statement = statement.where(cls.src_storage == storage)
return session.execute(
statement.order_by(cls.id.desc())
).scalars().first()
return query(db)
statement = select(cls).where(cls.src == src)
if storage:
statement = statement.where(cls.src_storage == storage)
return db.execute(statement.order_by(cls.id.desc())).scalars().first()
@classmethod
@legacy_db_query
def get_success_by_src(
cls, db: Session | str | None = None, src: str | None = None,
cls, db: Session, src: str,
storage: Optional[str] = None
) -> Optional["TransferHistory"]:
"""
@@ -254,26 +223,14 @@ class TransferHistory(Base):
:param storage: 源存储类型
:return: 命中的成功整理记录,未命中时返回 None
"""
if src is None and isinstance(db, str):
src, db = db, None
if src is None:
raise TypeError("src is required")
def query(session: Session):
"""在调用方提供的同步会话中执行成功源路径查询。"""
statement = select(cls).where(cls.src == src, cls.status.is_(True))
if storage:
statement = statement.where(cls.src_storage == storage)
return session.execute(
statement.order_by(cls.id.desc())
).scalars().first()
return query(db)
statement = select(cls).where(cls.src == src, cls.status.is_(True))
if storage:
statement = statement.where(cls.src_storage == storage)
return db.execute(statement.order_by(cls.id.desc())).scalars().first()
@classmethod
@legacy_db_query
def get_by_dest(
cls, db: Session | str | None = None, dest: str | None = None,
cls, db: Session, dest: str,
storage: Optional[str] = None
) -> Optional["TransferHistory"]:
"""
@@ -284,24 +241,12 @@ class TransferHistory(Base):
:param storage: 目标存储类型
:return: 命中的整理记录,未命中时返回 None
"""
if dest is None and isinstance(db, str):
dest, db = db, None
if dest is None:
raise TypeError("dest is required")
def query(session: Session):
"""在调用方提供的同步会话中执行目标路径查询。"""
statement = select(cls).where(cls.dest == dest)
if storage:
statement = statement.where(cls.dest_storage == storage)
return session.execute(
statement.order_by(cls.id.desc())
).scalars().first()
return query(db)
statement = select(cls).where(cls.dest == dest)
if storage:
statement = statement.where(cls.dest_storage == storage)
return db.execute(statement.order_by(cls.id.desc())).scalars().first()
@classmethod
@legacy_db_query
def list_success_by_src(
cls,
db: Session,
@@ -341,7 +286,6 @@ class TransferHistory(Base):
return list(db.execute(statement).scalars().all())
@classmethod
@legacy_db_query
def list_success_move_by_dest(
cls,
db: Session,
@@ -384,14 +328,12 @@ class TransferHistory(Base):
return list(db.execute(statement).scalars().all())
@classmethod
@legacy_db_query
def list_by_hash(cls, db: Session, download_hash: str):
return list(db.execute(
select(cls).where(cls.download_hash == download_hash)
).scalars().all())
@classmethod
@legacy_db_query
def statistic(cls, db: Session, days: int = 7):
"""
统计最近days天的下载历史数量,按日期分组返回每日数量
@@ -408,7 +350,6 @@ class TransferHistory(Base):
).all())
@classmethod
@legacy_db_query
def monthly_media_statistics(cls, db: Session):
"""
统计当月成功整理的电影、电视剧、剧集和音乐数量。
@@ -474,7 +415,6 @@ class TransferHistory(Base):
return 1
@classmethod
@legacy_async_db_query
async def async_statistic(cls, db: AsyncSession, days: int = 7):
"""
统计最近days天的下载历史数量,按日期分组返回每日数量
@@ -489,7 +429,6 @@ class TransferHistory(Base):
return result.all()
@classmethod
@legacy_db_query
def count(cls, db: Session, status: Optional[bool] = None):
statement = select(func.count(cls.id))
if status is not None:
@@ -497,7 +436,6 @@ class TransferHistory(Base):
return db.execute(statement).scalar()
@classmethod
@legacy_async_db_query
async def async_count(cls, db: AsyncSession, status: Optional[bool] = None):
if status is not None:
result = await db.execute(
@@ -510,7 +448,6 @@ class TransferHistory(Base):
return result.scalar()
@classmethod
@legacy_db_query
def count_by_title(cls, db: Session, title: str, status: Optional[bool] = None, wildcard: bool = False):
if wildcard:
text_filter = or_(
@@ -530,7 +467,6 @@ class TransferHistory(Base):
return db.execute(statement).scalar()
@classmethod
@legacy_async_db_query
async def async_count_by_title(cls, db: AsyncSession, title: str, status: Optional[bool] = None, wildcard: bool = False):
if wildcard:
text_filter = or_(
@@ -551,7 +487,6 @@ class TransferHistory(Base):
return result.scalar()
@classmethod
@legacy_db_query
def list_by(cls, db: Session, mtype: Optional[str] = None, title: Optional[str] = None, year: Optional[str] = None,
season: Optional[str] = None,
episode: Optional[str] = None,
@@ -589,7 +524,6 @@ class TransferHistory(Base):
return list(db.execute(statement).scalars().all())
@classmethod
@legacy_db_query
def get_by_media_identity(
cls, db: Session, media_source: MediaSource, media_id: str,
mtype: Optional[str] = None,
@@ -636,7 +570,6 @@ class TransferHistory(Base):
return history
@classmethod
@legacy_db_query
def list_by_date(cls, db: Session, date: str):
"""
查询某时间之后的转移历史
-2
View File
@@ -4,7 +4,6 @@ from sqlalchemy import Index, String, delete, select
from sqlalchemy.orm import Mapped, Session, mapped_column
from app.db.base import Base, execute_dml, get_id_column
from app.db.decorators import legacy_db_query
class TransferPending(Base):
@@ -73,7 +72,6 @@ class TransferPending(Base):
)
@classmethod
@legacy_db_query
def list_all(cls, db: Session, limit: Optional[int] = 5000) -> List["TransferPending"]:
"""
列出全部待整理登记,供启动回放使用。
+17 -58
View File
@@ -4,7 +4,6 @@ from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.orm import Mapped, Session, mapped_column
from app.db.base import Base, get_id_column
from app.db.decorators import legacy_async_db_query, legacy_db_query
class User(Base):
@@ -35,78 +34,38 @@ class User(Base):
settings: Mapped[Optional[Any]] = mapped_column(JSON, default=dict)
@classmethod
@legacy_db_query
def get_by_name(
cls,
db: Session | str | None = None,
name: str | None = None,
db: Session,
name: str,
):
"""按用户名查询用户,兼容显式会话和旧插件无会话调用"""
if name is None and isinstance(db, str):
name, db = db, None
if name is None:
raise TypeError("name is required")
def query(session: Session):
"""在给定会话中执行用户名查询。"""
return session.execute(select(cls).where(cls.name == name)).scalars().first()
return query(db)
"""在调用方同步会话中按用户名查询用户。"""
return db.execute(select(cls).where(cls.name == name)).scalars().first()
@classmethod
@legacy_async_db_query
async def async_get_by_name(
cls,
db: AsyncSession | str | None = None,
name: str | None = None,
db: AsyncSession,
name: str,
):
"""异步按用户名查询,兼容显式会话和旧插件无会话调用"""
if name is None and isinstance(db, str):
name, db = db, None
if name is None:
raise TypeError("name is required")
async def query(session: AsyncSession):
"""在给定异步会话中执行用户名查询。"""
result = await session.execute(select(cls).filter(cls.name == name))
return result.scalars().first()
return await query(db)
"""在调用方异步会话中按用户名查询用户"""
result = await db.execute(select(cls).filter(cls.name == name))
return result.scalars().first()
@classmethod
@legacy_db_query
def get_by_id(cls, db: Session | int | None = None, user_id: int | None = None):
"""按用户 ID 查询用户,兼容显式会话和旧插件无会话调用。"""
if user_id is None and isinstance(db, int):
user_id, db = db, None
if user_id is None:
raise TypeError("user_id is required")
def query(session: Session):
"""在给定会话中执行用户 ID 查询。"""
return session.execute(select(cls).where(cls.id == user_id)).scalars().first()
return query(db)
def get_by_id(cls, db: Session, user_id: int):
"""在调用方同步会话中按用户 ID 查询用户。"""
return db.execute(select(cls).where(cls.id == user_id)).scalars().first()
@classmethod
@legacy_async_db_query
async def async_get_by_id(
cls,
db: AsyncSession | int | None = None,
user_id: int | None = None,
db: AsyncSession,
user_id: int,
):
"""异步按用户 ID 查询,兼容显式会话和旧插件无会话调用"""
if user_id is None and isinstance(db, int):
user_id, db = db, None
if user_id is None:
raise TypeError("user_id is required")
async def query(session: AsyncSession):
"""在给定异步会话中执行用户 ID 查询。"""
result = await session.execute(select(cls).filter(cls.id == user_id))
return result.scalars().first()
return await query(db)
"""在调用方异步会话中按用户 ID 查询用户"""
result = await db.execute(select(cls).filter(cls.id == user_id))
return result.scalars().first()
def delete_by_name(self, db: Session, name: str):
user = self.get_by_name(db, name)
-9
View File
@@ -7,7 +7,6 @@ from sqlalchemy.orm import Mapped, mapped_column
from sqlalchemy.ext.asyncio import AsyncSession
from app.db.base import Base, get_id_column
from app.db.decorators import legacy_async_db_query, legacy_db_query
class Workflow(Base):
@@ -56,18 +55,15 @@ class Workflow(Base):
)
@classmethod
@legacy_db_query
def get_enabled_workflows(cls, db):
return list(db.execute(select(cls).where(cls.state != 'P')).scalars().all())
@classmethod
@legacy_async_db_query
async def async_get_enabled_workflows(cls, db: AsyncSession):
result = await db.execute(select(cls).where(cls.state != 'P'))
return list(result.scalars().all())
@classmethod
@legacy_db_query
def get_timer_triggered_workflows(cls, db):
"""获取定时触发的工作流"""
return list(db.execute(select(cls).where(
@@ -81,7 +77,6 @@ class Workflow(Base):
)).scalars().all())
@classmethod
@legacy_async_db_query
async def async_get_timer_triggered_workflows(cls, db: AsyncSession):
"""异步获取定时触发的工作流"""
result = await db.execute(select(cls).where(
@@ -96,7 +91,6 @@ class Workflow(Base):
return list(result.scalars().all())
@classmethod
@legacy_db_query
def get_event_triggered_workflows(cls, db):
"""获取事件触发的工作流"""
return list(db.execute(select(cls).where(
@@ -107,7 +101,6 @@ class Workflow(Base):
)).scalars().all())
@classmethod
@legacy_async_db_query
async def async_get_event_triggered_workflows(cls, db: AsyncSession):
"""异步获取事件触发的工作流"""
result = await db.execute(select(cls).where(
@@ -119,12 +112,10 @@ class Workflow(Base):
return list(result.scalars().all())
@classmethod
@legacy_db_query
def get_by_name(cls, db, name: str):
return db.execute(select(cls).where(cls.name == name)).scalars().first()
@classmethod
@legacy_async_db_query
async def async_get_by_name(cls, db: AsyncSession, name: str):
result = await db.execute(select(cls).where(cls.name == name))
return result.scalars().first()