refactor: 推进后端分层架构治理

This commit is contained in:
jxxghp
2026-08-18 00:29:14 +08:00
parent 5d0bacabd5
commit 5128ae9e1e
363 changed files with 34179 additions and 6019 deletions
+59 -27
View File
@@ -1,28 +1,60 @@
"""
ORM 模型。
"""ORM 模型的惰性兼容导出与显式注册入口。"""
_identity 必须在此处导入:它在 import 期把媒体身份归一挂到 mapper 事件上,是六张带
身份列的表的写入不变量。导入任一模型都会先初始化本包,因此这一行让强制点无处可绕。
"""
from . import _identity # noqa: F401 仅为注册 mapper 事件,不导出符号
from .agentchat import AgentChat
from .agenttask import AgentTask
from .agenttaskrun import AgentTaskRun
from .downloadfailure import DownloadFailure
from .downloadhistory import DownloadHistory, DownloadFiles
from .mediaserver import MediaServerItem
from .message import Message
from .passkey import PassKey
from .plugindata import PluginData
from .site import Site
from .siteicon import SiteIcon
from .sitestatistic import SiteStatistic
from .siteuserdata import SiteUserData
from .subscribe import Subscribe
from .subscribehistory import SubscribeHistory
from .systemconfig import SystemConfig
from .transferhistory import TransferHistory
from .transferpending import TransferPending
from .user import User
from .userconfig import UserConfig
from .workflow import Workflow
from importlib import import_module
from typing import Any
from . import _identity # noqa: F401 注册全局媒体身份写入不变量
_MODEL_EXPORTS = {
"AgentChat": ("app.db.models.agentchat", "AgentChat"),
"AgentTask": ("app.db.models.agenttask", "AgentTask"),
"AgentTaskRun": ("app.db.models.agenttaskrun", "AgentTaskRun"),
"DownloadFailure": ("app.db.models.downloadfailure", "DownloadFailure"),
"DownloadFiles": ("app.db.models.downloadhistory", "DownloadFiles"),
"DownloadHistory": ("app.db.models.downloadhistory", "DownloadHistory"),
"MediaServerItem": ("app.db.models.mediaserver", "MediaServerItem"),
"Message": ("app.db.models.message", "Message"),
"PassKey": ("app.db.models.passkey", "PassKey"),
"PluginData": ("app.db.models.plugindata", "PluginData"),
"Site": ("app.db.models.site", "Site"),
"SiteIcon": ("app.db.models.siteicon", "SiteIcon"),
"SiteStatistic": ("app.db.models.sitestatistic", "SiteStatistic"),
"SiteUserData": ("app.db.models.siteuserdata", "SiteUserData"),
"Subscribe": ("app.db.models.subscribe", "Subscribe"),
"SubscribeHistory": (
"app.db.models.subscribehistory",
"SubscribeHistory",
),
"SystemConfig": ("app.db.models.systemconfig", "SystemConfig"),
"TransferHistory": ("app.db.models.transferhistory", "TransferHistory"),
"TransferPending": ("app.db.models.transferpending", "TransferPending"),
"User": ("app.db.models.user", "User"),
"UserConfig": ("app.db.models.userconfig", "UserConfig"),
"Workflow": ("app.db.models.workflow", "Workflow"),
}
def load_all_models() -> None:
"""显式导入全部 ORM 模型,供建表和 Alembic 元数据收集使用。"""
for module_name, _ in dict.fromkeys(_MODEL_EXPORTS.values()):
import_module(module_name)
def __getattr__(name: str) -> Any:
"""按需解析旧模型包级导出,并缓存模型类。"""
contract = _MODEL_EXPORTS.get(name)
if contract is None:
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
module_name, symbol_name = contract
value = getattr(import_module(module_name), symbol_name)
globals()[name] = value
return value
def __dir__() -> list[str]:
"""返回模型包的兼容公开面。"""
return sorted({*globals(), *_MODEL_EXPORTS, "load_all_models"})
__all__ = [*_MODEL_EXPORTS, "load_all_models"]
+2 -1
View File
@@ -4,7 +4,8 @@ from sqlalchemy import Integer, String, JSON, Index, select
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.orm import Mapped, Session, mapped_column
from app.db import Base, async_db_query, db_query, get_id_column
from app.db.base import Base, get_id_column
from app.db.decorators import async_db_query, db_query
class AgentChat(Base):
+2 -1
View File
@@ -3,7 +3,8 @@ from typing import Optional
from sqlalchemy import Boolean, Index, Integer, String, Text, select, update
from sqlalchemy.orm import Mapped, Session, mapped_column
from app.db import Base, db_query, db_update, execute_dml, get_id_column
from app.db.base import Base, execute_dml, get_id_column
from app.db.decorators import db_query, db_update
class AgentTask(Base):
+2 -1
View File
@@ -3,7 +3,8 @@ from typing import Any, Dict, List, Optional
from sqlalchemy import Index, Integer, String, Text, delete, select, update
from sqlalchemy.orm import Mapped, Session, mapped_column
from app.db import Base, db_query, db_update, execute_dml, get_id_column
from app.db.base import Base, execute_dml, get_id_column
from app.db.decorators import db_query, db_update
from app.db.models.agenttask import AgentTask
+2 -1
View File
@@ -3,7 +3,8 @@ from typing import List, Optional
from sqlalchemy import Float, Index, Integer, String, delete, select
from sqlalchemy.orm import Mapped, Session, mapped_column
from app.db import Base, db_query, db_update, execute_dml, get_id_column
from app.db.base import Base, execute_dml, get_id_column
from app.db.decorators import db_query, db_update
from app.db.models._constraints import media_identity_constraint
+2 -1
View File
@@ -5,7 +5,8 @@ from sqlalchemy import Integer, String, JSON, Index, delete, select, func, updat
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.orm import Mapped, Session, mapped_column
from app.db import Base, async_db_query, db_query, db_update, execute_dml, get_id_column
from app.db.base import Base, execute_dml, get_id_column
from app.db.decorators import async_db_query, db_query, db_update
from app.db.models._constraints import media_identity_constraint
from app.schemas.types import MediaSource
+3 -2
View File
@@ -1,12 +1,13 @@
from datetime import datetime
from typing import Any, List, Optional
from sqlalchemy import Integer, String, JSON, Index, delete, or_
from sqlalchemy import String, JSON, Index, delete, or_
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.orm import Mapped, Session, mapped_column
from app.db import Base, async_db_query, db_query, db_update, execute_dml, get_id_column
from app.db.base import Base, execute_dml, get_id_column
from app.db.decorators import async_db_query, db_query, db_update
from app.db.models._constraints import media_identity_constraint
from app.schemas.types import MediaSource
+2 -1
View File
@@ -4,7 +4,8 @@ from sqlalchemy import Integer, String, JSON, Index, and_, delete, or_, select
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.orm import Mapped, Session, mapped_column
from app.db import Base, async_db_query, db_query, db_update, execute_dml, get_id_column
from app.db.base import Base, execute_dml, get_id_column
from app.db.decorators import async_db_query, db_query, db_update
class Message(Base):
+2 -1
View File
@@ -4,7 +4,8 @@ from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.orm import Mapped, Session, mapped_column
from datetime import datetime
from app.db import Base, db_query, db_update, async_db_query, async_db_update, get_id_column
from app.db.base import Base, get_id_column
from app.db.decorators import db_query, db_update, async_db_query, async_db_update
class PassKey(Base):
+2 -7
View File
@@ -3,13 +3,8 @@ from sqlalchemy import String, JSON, Index, delete, select
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.orm import Mapped, Session, mapped_column
from app.db import (
db_query,
db_update,
async_db_query,
get_id_column,
Base,
)
from app.db.base import get_id_column, Base
from app.db.decorators import db_query, db_update, async_db_query
class PluginData(Base):
+2 -1
View File
@@ -5,7 +5,8 @@ from sqlalchemy import Boolean, Integer, String, JSON, select, delete
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.orm import Mapped, Session, mapped_column
from app.db import db_query, db_update, Base, async_db_query, async_db_update, get_id_column
from app.db.base import Base, get_id_column
from app.db.decorators import db_query, db_update, async_db_query, async_db_update
class Site(Base):
+2 -1
View File
@@ -3,7 +3,8 @@ from sqlalchemy import String, select
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.orm import Mapped, Session, mapped_column
from app.db import db_query, Base, get_id_column, async_db_query
from app.db.base import Base, get_id_column
from app.db.decorators import db_query, async_db_query
class SiteIcon(Base):
+2 -1
View File
@@ -5,7 +5,8 @@ from sqlalchemy import Integer, String, JSON, delete, select
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.orm import Mapped, Session, mapped_column
from app.db import db_query, db_update, get_id_column, Base, async_db_query
from app.db.base import get_id_column, Base
from app.db.decorators import db_query, db_update, async_db_query
class SiteStatistic(Base):
+2 -1
View File
@@ -5,7 +5,8 @@ from sqlalchemy import Integer, String, Float, JSON, Index, delete, func, or_, s
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.orm import Mapped, Session, mapped_column
from app.db import Base, async_db_query, db_query, db_update, execute_dml, get_id_column
from app.db.base import Base, execute_dml, get_id_column
from app.db.decorators import async_db_query, db_query, db_update
class SiteUserData(Base):
+2 -1
View File
@@ -5,7 +5,8 @@ from sqlalchemy import Integer, String, Float, JSON, Index, delete, or_, select
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.orm import Mapped, Session, mapped_column
from app.db import db_query, db_update, get_id_column, Base, async_db_query, async_db_update
from app.db.base import get_id_column, Base
from app.db.decorators import db_query, db_update, async_db_query, async_db_update
from app.db.models._constraints import media_identity_constraint
from app.schemas.types import MUSIC_ENTITY_RECORDING, MediaSource
+2 -1
View File
@@ -4,7 +4,8 @@ from sqlalchemy import Integer, String, Float, JSON, Index, or_, select
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.orm import Mapped, Session, mapped_column
from app.db import db_query, Base, get_id_column, async_db_query
from app.db.base import Base, get_id_column
from app.db.decorators import db_query, async_db_query
from app.db.models._constraints import media_identity_constraint
from app.schemas.types import MUSIC_ENTITY_RECORDING, MediaSource
+2 -1
View File
@@ -3,7 +3,8 @@ from sqlalchemy import String, JSON, select
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.orm import Mapped, Session, mapped_column
from app.db import db_query, db_update, Base, async_db_query, get_id_column
from app.db.base import Base, get_id_column
from app.db.decorators import db_query, db_update, async_db_query
class SystemConfig(Base):
+2 -1
View File
@@ -7,7 +7,8 @@ from sqlalchemy import Boolean, Index, Integer, JSON, String, delete, func, or_,
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.orm import Mapped, Session, mapped_column
from app.db import Base, async_db_query, db_query, db_update, execute_dml, get_id_column
from app.db.base import Base, execute_dml, get_id_column
from app.db.decorators import async_db_query, db_query, db_update
from app.db.models._constraints import media_identity_constraint
from app.schemas.types import MUSIC_ENTITY_ALBUM, MUSIC_ENTITY_RECORDING, MediaSource, MediaType
+2 -1
View File
@@ -3,7 +3,8 @@ from typing import List, Optional
from sqlalchemy import Index, String, delete, select
from sqlalchemy.orm import Mapped, Session, mapped_column
from app.db import Base, db_query, db_update, execute_dml, get_id_column
from app.db.base import Base, execute_dml, get_id_column
from app.db.decorators import db_query, db_update
class TransferPending(Base):
+2 -1
View File
@@ -3,7 +3,8 @@ from sqlalchemy import Boolean, JSON, String, select
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.orm import Mapped, Session, mapped_column
from app.db import Base, db_query, db_update, async_db_query, async_db_update, get_id_column
from app.db.base import Base, get_id_column
from app.db.decorators import db_query, db_update, async_db_query, async_db_update
class User(Base):
+2 -1
View File
@@ -2,7 +2,8 @@ from typing import Any, Optional
from sqlalchemy import String, UniqueConstraint, JSON, select
from sqlalchemy.orm import Mapped, Session, mapped_column
from app.db import db_query, db_update, get_id_column, Base
from app.db.base import get_id_column, Base
from app.db.decorators import db_query, db_update
class UserConfig(Base):
+2 -1
View File
@@ -6,7 +6,8 @@ from sqlalchemy import Integer, JSON, String, Index, and_, or_, select, update
from sqlalchemy.orm import Mapped, mapped_column
from sqlalchemy.ext.asyncio import AsyncSession
from app.db import Base, db_query, get_id_column, db_update, async_db_query, async_db_update
from app.db.base import Base, get_id_column
from app.db.decorators import db_query, db_update, async_db_query, async_db_update
class Workflow(Base):