diff --git a/backend/src/module/database/bangumi.py b/backend/src/module/database/bangumi.py index d3f48f73..75499cf6 100644 --- a/backend/src/module/database/bangumi.py +++ b/backend/src/module/database/bangumi.py @@ -5,7 +5,7 @@ from typing import TYPE_CHECKING, Optional from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.sql import func -from sqlmodel import and_, delete, false, or_, select +from sqlmodel import and_, delete, false, or_, select, update from module.models import Bangumi, BangumiUpdate @@ -559,8 +559,22 @@ class BangumiDatabase: logger.debug("Delete bangumi id: %s.", _id) async def delete_all(self): - statement = delete(Bangumi) - await self.session.execute(statement) + # torrent / aria2_gid 行经外键引用 bangumi.id(PRAGMA foreign_keys=ON), + # 必须先清理引用,否则整表重置在约束上直接回滚。种子记录随规则一起删 + # (与 delete_rule 语义一致,重新添加后能重新下载);aria2 映射行保留 + # 但解除关联。 + from module.models.aria2 import Aria2Gid + from module.models.torrent import Torrent + + await self.session.execute( + delete(Torrent).where(Torrent.bangumi_id.is_not(None)) # type: ignore[attr-defined] + ) + await self.session.execute( + update(Aria2Gid) + .where(Aria2Gid.bangumi_id.is_not(None)) # type: ignore[attr-defined] + .values(bangumi_id=None) + ) + await self.session.execute(delete(Bangumi)) await self.session.commit() async def search_all(self) -> list[Bangumi]: diff --git a/backend/src/test/test_database.py b/backend/src/test/test_database.py index d60039d3..ae0b683d 100644 --- a/backend/src/test/test_database.py +++ b/backend/src/test/test_database.py @@ -126,6 +126,30 @@ async def test_rss_add_reenables_disabled_duplicate(db_session): assert item.enabled is True +async def test_bangumi_delete_all_with_fk_references_succeeds(db_session): + """reset/all 全表重置:torrent/aria2_gid 行经外键引用 bangumi 时, + 必须先清理引用,否则 PRAGMA foreign_keys=ON 下整个删除直接回滚。""" + from sqlalchemy import text + from sqlmodel import select as sql_select + + from module.models.aria2 import Aria2Gid + + await db_session.execute(text("PRAGMA foreign_keys=ON")) + await _ensure_bangumi(db_session, 1) + db_session.add(Torrent(name="ep01", url="https://example.com/1", bangumi_id=1)) + db_session.add(Aria2Gid(gid="gid-1", bangumi_id=1)) + await db_session.commit() + + db = BangumiDatabase(db_session) + await db.delete_all() + + assert await db.search_all() == [] + torrents = (await db_session.execute(sql_select(Torrent))).scalars().all() + assert torrents == [] + gid_row = (await db_session.execute(sql_select(Aria2Gid))).scalars().one() + assert gid_row.bangumi_id is None + + # --------------------------------------------------------------------------- # TorrentDatabase qb_hash methods # ---------------------------------------------------------------------------