AI-News/backend/app/db/repositories/home_featured.py

83 lines
2.8 KiB
Python
Raw Normal View History

2025-12-04 10:04:21 +08:00
# app/db/repositories/home_featured.py
from typing import List, Sequence
from asyncpg import Connection
from app.db.repositories.base import BaseRepository
class HomeFeaturedRepository(BaseRepository):
"""
维护首页推送文章的排序列表最多 10
仅存 slug + sort_order真正返回文章数据时再通过 ArticlesRepository 拉取
"""
def __init__(self, conn: Connection) -> None:
super().__init__(conn)
async def _ensure_table(self) -> None:
await self.connection.execute(
"""
CREATE TABLE IF NOT EXISTS home_featured_articles (
slug TEXT PRIMARY KEY,
sort_order INT NOT NULL DEFAULT 0,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
""",
)
async def list_slugs(self, *, limit: int = 10) -> List[str]:
await self._ensure_table()
rows = await self.connection.fetch(
"""
SELECT slug
FROM home_featured_articles
ORDER BY sort_order ASC, updated_at DESC, created_at DESC
LIMIT $1;
""",
limit,
)
return [row["slug"] for row in rows]
async def save_slugs(self, *, slugs: Sequence[str], limit: int = 10) -> List[str]:
"""
保存首页推送顺序自动去重并截断到 limit
返回最终生效的 slug 顺序
"""
await self._ensure_table()
clean_slugs: List[str] = []
for slug in slugs:
normalized = str(slug).strip()
if not normalized:
continue
if normalized not in clean_slugs:
clean_slugs.append(normalized)
clean_slugs = clean_slugs[:limit]
async with self.connection.transaction():
if clean_slugs:
await self.connection.execute(
"""
DELETE FROM home_featured_articles
WHERE slug <> ALL($1::text[]);
""",
clean_slugs,
)
for idx, slug in enumerate(clean_slugs):
await self.connection.execute(
"""
INSERT INTO home_featured_articles (slug, sort_order)
VALUES ($1, $2)
ON CONFLICT (slug) DO UPDATE
SET sort_order = EXCLUDED.sort_order,
updated_at = NOW();
""",
slug,
idx,
)
else:
await self.connection.execute("DELETE FROM home_featured_articles;")
return clean_slugs