83 lines
2.8 KiB
Python
83 lines
2.8 KiB
Python
|
|
# 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
|