From ad6f390b5768012fa65007d32c8bb2d421349cb8 Mon Sep 17 00:00:00 2001 From: axisrow Date: Fri, 10 Jul 2026 12:07:09 +0800 Subject: [PATCH] refactor(db): drop six verified-dead repository/bundle methods (vulture, #1136) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Removes six methods flagged by vulture and verified dead across all five surfaces (FastAPI/Web/CLI/agent/TUI). For each, repo-wide grep (src/ tests/ scripts/ docs/ conftest.py) returned exactly 1 hit — the definition — with no string references. Dynamic repo access in the codebase targets other specific names (clear_dialogs, get_recent_for_channels, get_channels, …); the dispatcher's dynamic dispatch is f"_handle_{command}"-shaped and unrelated. Repository methods (underlying repo layer stays — these are unused readers): 1. ChannelsRepository.get_channels_by_tag — born in #271 (tags feature) with no caller (git grep at 2af529ea: definition only). The tag feature uses list_all_tags/create_tag/delete_tag/set_channel_tags/get_channel_tags (see src/cli/commands/channel.py); this reverse reader was never wired to any surface. 2. DialogCacheRepository.has_dialogs — born in bc2bddde with no caller. All live dialog_cache methods (enumerated from call sites): clear_all_dialogs, clear_dialogs, count_dialogs, get_all_phones, get_cached_at, get_dialog, list_dialogs, replace_dialogs — has_dialogs absent. 3. GenerationRunsRepository.list_by_status — definition-only at every commit that touched it (#292, #555, #780); moderation/runs surfaces use list_pending_moderation / list_runs instead. Bundle wrappers (unused thin wrappers over LIVE repo methods that stay): 4. AccountBundle.list_live_usable_accounts — AccountsRepository. get_live_usable_accounts stays (17 live refs). 5. AccountBundle.update_premium — AccountsRepository.update_account_premium stays (24 live refs). 6. MessageBundle.get_message_stats — MessagesRepository.get_stats stays (used via Database.get_stats -> dashboard route). No public-API/parity impact: none of the six is reachable from any of the five surfaces. Part of #1136 / #1130. Co-Authored-By: Claude --- src/database/bundles.py | 12 +----------- src/database/repositories/channels.py | 12 ------------ src/database/repositories/dialog_cache.py | 8 -------- src/database/repositories/generation_runs.py | 12 ------------ 4 files changed, 1 insertion(+), 43 deletions(-) diff --git a/src/database/bundles.py b/src/database/bundles.py index 5562f6f7..b0d11541 100644 --- a/src/database/bundles.py +++ b/src/database/bundles.py @@ -112,10 +112,6 @@ async def list_accounts(self, active_only: bool = False) -> list[Account]: """Список аккаунтов (с секретом сессии); `active_only` — только активные.""" return await self.accounts.get_accounts(active_only) - async def list_live_usable_accounts(self, active_only: bool = False) -> list[Account]: - """Аккаунты, пригодные для живого подключения (валидная читаемая сессия).""" - return await self.accounts.get_live_usable_accounts(active_only) - async def list_account_summaries(self, active_only: bool = False) -> list[AccountSummary]: """Безопасные для UI сводки аккаунтов (`AccountSummary`, без `session_string`).""" return await self.accounts.get_account_summaries(active_only) @@ -136,9 +132,7 @@ async def update_flood(self, phone: str, until) -> None: """Записать `flood_wait_until` для аккаунта (момент окончания FLOOD_WAIT).""" await self.accounts.update_account_flood(phone, until) - async def update_premium(self, phone: str, is_premium: bool) -> None: - """Обновить флаг Premium-статуса аккаунта.""" - await self.accounts.update_account_premium(phone, is_premium) + @dataclass(frozen=True) @@ -544,10 +538,6 @@ async def delete_messages_for_channel(self, channel_id: int) -> int: """Удалить все сообщения канала; вернуть число удалённых строк.""" return await self.messages.delete_messages_for_channel(channel_id) - async def get_message_stats(self) -> dict: - """Сводная статистика по таблице сообщений (счётчики и т.п.).""" - return await self.messages.get_stats() - async def count_matching_prefixes_in_other_channels( self, channel_id: int, diff --git a/src/database/repositories/channels.py b/src/database/repositories/channels.py index a9ad1666..a1236364 100644 --- a/src/database/repositories/channels.py +++ b/src/database/repositories/channels.py @@ -619,15 +619,3 @@ async def set_channel_tags(self, channel_pk: int, tag_names: list[str]) -> None: SELECT ?, id FROM tags WHERE name = ?""", (channel_pk, name), ) - - async def get_channels_by_tag(self, tag: str) -> list[Channel]: - """Каналы, помеченные данным тегом, по возрастанию pk.""" - cur = await self._db.execute( - """SELECT c.* FROM channels c - JOIN channel_tags ct ON ct.channel_pk = c.id - JOIN tags t ON t.id = ct.tag_id - WHERE t.name = ? - ORDER BY c.id""", - (tag,), - ) - return [self._map_channel(r) for r in await cur.fetchall()] diff --git a/src/database/repositories/dialog_cache.py b/src/database/repositories/dialog_cache.py index b3057211..551bb9a0 100644 --- a/src/database/repositories/dialog_cache.py +++ b/src/database/repositories/dialog_cache.py @@ -120,14 +120,6 @@ async def clear_dialogs(self, phone: str) -> None: ) await self._database.execute_write("DELETE FROM dialog_cache WHERE phone = ?", (phone,)) - async def has_dialogs(self, phone: str) -> bool: - """True, если для аккаунта есть хотя бы один кэшированный диалог.""" - cur = await self._db.execute( - "SELECT 1 FROM dialog_cache WHERE phone = ? LIMIT 1", - (phone,), - ) - return bool(await cur.fetchone()) - async def get_cached_at(self, phone: str) -> datetime | None: """Время самого свежего кэшированного диалога аккаунта (для оценки устаревания).""" cur = await self._db.execute( diff --git a/src/database/repositories/generation_runs.py b/src/database/repositories/generation_runs.py index bcfdfbff..b52c0956 100644 --- a/src/database/repositories/generation_runs.py +++ b/src/database/repositories/generation_runs.py @@ -392,18 +392,6 @@ async def list_by_pipeline( rows = await cur.fetchall() return [self._to_generation_run(row) for row in rows] - async def list_by_status(self, statuses: list[str], limit: int = 20) -> list[GenerationRun]: - """List runs filtered by execution status (pending/running/completed/failed).""" - if not statuses: - return [] - placeholders = ",".join("?" * len(statuses)) - cur = await self._db.execute( - f"SELECT * FROM generation_runs WHERE status IN ({placeholders}) ORDER BY id DESC LIMIT ?", - (*statuses, limit), - ) - rows = await cur.fetchall() - return [self._to_generation_run(row) for row in rows] - async def get_calendar_stats(self) -> dict: """Return counts grouped by moderation_status, plus published count.""" cur = await self._db.execute(