fix(api): KB 架構審查修復 I3-I5
- I3: Service 層加 IKnowledgeRepository Protocol 型別標注 - I4: search 方法加入 tags JSONB 搜尋 (cast→String→ilike) - I5: get_categories 獨立方法,不再繞道 list_entries(limit=0) 首席架構師審查 87/100 → 全部 Important issues 已修復 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -71,8 +71,8 @@ async def search_entries(
|
||||
async def get_categories() -> list[dict]:
|
||||
"""取得分類樹 (含各類數量)"""
|
||||
service = get_knowledge_service()
|
||||
result = await service.list_entries(limit=0)
|
||||
return [cat.model_dump() for cat in result.categories]
|
||||
cats = await service.get_categories()
|
||||
return [cat.model_dump() for cat in cats]
|
||||
|
||||
|
||||
@router.get("/{entry_id}", response_model=KnowledgeEntry)
|
||||
|
||||
@@ -12,7 +12,7 @@ Knowledge Base Phase 1: CRUD + 搜尋
|
||||
"""
|
||||
|
||||
import structlog
|
||||
from sqlalchemy import func, or_, select, update
|
||||
from sqlalchemy import String, func, or_, select, update
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from src.db.models import KnowledgeEntryRecord
|
||||
@@ -154,7 +154,7 @@ class KnowledgeDBRepository:
|
||||
return [(row.category, row.cnt) for row in result.all()]
|
||||
|
||||
async def search(self, query: str, limit: int = 20) -> list[KnowledgeEntry]:
|
||||
"""關鍵字搜尋 (title + content)"""
|
||||
"""關鍵字搜尋 (title + content + tags)"""
|
||||
like_q = f"%{query}%"
|
||||
result = await self.db.execute(
|
||||
select(KnowledgeEntryRecord)
|
||||
@@ -163,6 +163,7 @@ class KnowledgeDBRepository:
|
||||
or_(
|
||||
KnowledgeEntryRecord.title.ilike(like_q),
|
||||
KnowledgeEntryRecord.content.ilike(like_q),
|
||||
KnowledgeEntryRecord.tags.cast(String).ilike(like_q),
|
||||
),
|
||||
)
|
||||
.order_by(KnowledgeEntryRecord.view_count.desc())
|
||||
|
||||
@@ -24,6 +24,7 @@ from src.models.knowledge import (
|
||||
KnowledgeEntryUpdate,
|
||||
KnowledgeListResponse,
|
||||
)
|
||||
from src.repositories.interfaces import IKnowledgeRepository
|
||||
from src.repositories.knowledge_repository import KnowledgeDBRepository
|
||||
|
||||
logger = structlog.get_logger(__name__)
|
||||
@@ -49,7 +50,7 @@ class KnowledgeService:
|
||||
async def create_entry(self, data: KnowledgeEntryCreate) -> KnowledgeEntry:
|
||||
"""建立知識條目"""
|
||||
async with get_db_context() as db:
|
||||
repo = KnowledgeDBRepository(db)
|
||||
repo: IKnowledgeRepository = KnowledgeDBRepository(db)
|
||||
entry = await repo.create(data)
|
||||
logger.info(
|
||||
"knowledge_entry_created",
|
||||
@@ -62,7 +63,7 @@ class KnowledgeService:
|
||||
async def get_entry(self, entry_id: str) -> KnowledgeEntry | None:
|
||||
"""取得知識條目 (view_count +1)"""
|
||||
async with get_db_context() as db:
|
||||
repo = KnowledgeDBRepository(db)
|
||||
repo: IKnowledgeRepository = KnowledgeDBRepository(db)
|
||||
entry = await repo.get_by_id(entry_id)
|
||||
if entry:
|
||||
await repo.increment_view_count(entry_id)
|
||||
@@ -75,7 +76,7 @@ class KnowledgeService:
|
||||
"""更新知識條目"""
|
||||
update_data = data.model_dump(exclude_none=True)
|
||||
async with get_db_context() as db:
|
||||
repo = KnowledgeDBRepository(db)
|
||||
repo: IKnowledgeRepository = KnowledgeDBRepository(db)
|
||||
if not update_data:
|
||||
return await repo.get_by_id(entry_id)
|
||||
return await repo.update(entry_id, update_data)
|
||||
@@ -83,7 +84,7 @@ class KnowledgeService:
|
||||
async def approve_entry(self, entry_id: str) -> KnowledgeEntry | None:
|
||||
"""審核通過 (draft/review → approved)"""
|
||||
async with get_db_context() as db:
|
||||
repo = KnowledgeDBRepository(db)
|
||||
repo: IKnowledgeRepository = KnowledgeDBRepository(db)
|
||||
entry = await repo.get_by_id(entry_id)
|
||||
if not entry:
|
||||
return None
|
||||
@@ -94,7 +95,7 @@ class KnowledgeService:
|
||||
async def archive_entry(self, entry_id: str) -> bool:
|
||||
"""封存 (軟刪除)"""
|
||||
async with get_db_context() as db:
|
||||
repo = KnowledgeDBRepository(db)
|
||||
repo: IKnowledgeRepository = KnowledgeDBRepository(db)
|
||||
return await repo.delete(entry_id)
|
||||
|
||||
async def list_entries(
|
||||
@@ -109,7 +110,7 @@ class KnowledgeService:
|
||||
) -> KnowledgeListResponse:
|
||||
"""列出知識條目 + 分類統計"""
|
||||
async with get_db_context() as db:
|
||||
repo = KnowledgeDBRepository(db)
|
||||
repo: IKnowledgeRepository = KnowledgeDBRepository(db)
|
||||
items, total = await repo.list_entries(
|
||||
category=category,
|
||||
entry_type=entry_type,
|
||||
@@ -127,8 +128,15 @@ class KnowledgeService:
|
||||
items=items, total=total, categories=categories
|
||||
)
|
||||
|
||||
async def get_categories(self) -> list[CategoryCount]:
|
||||
"""取得分類統計(直接呼叫 repo,不走 list_entries)"""
|
||||
async with get_db_context() as db:
|
||||
repo: IKnowledgeRepository = KnowledgeDBRepository(db)
|
||||
categories_raw = await repo.get_categories()
|
||||
return [CategoryCount(category=cat, count=cnt) for cat, cnt in categories_raw]
|
||||
|
||||
async def search(self, query: str, limit: int = 20) -> list[KnowledgeEntry]:
|
||||
"""關鍵字搜尋"""
|
||||
async with get_db_context() as db:
|
||||
repo = KnowledgeDBRepository(db)
|
||||
repo: IKnowledgeRepository = KnowledgeDBRepository(db)
|
||||
return await repo.search(query, limit)
|
||||
|
||||
Reference in New Issue
Block a user