from fastapi import HTTPException from sqlalchemy import func, select from sqlalchemy.ext.asyncio import AsyncSession from api.database import get_session from api.models.domain import Domain from api.models.extension_point import ExtensionPoint from api.models.managed_repo import ManagedRepo from api.models.technical_debt import TechnicalDebt from api.models.topic import Topic from api.models.workstream import Workstream from api.schemas.domain import ( DomainCreate, DomainDetail, DomainRead, DomainRename, DomainUpdate, RepoStub, ) from hub_core.routers.domains import create_domains_router async def _build_domain_detail(domain: Domain, session: AsyncSession) -> DomainDetail: topic_count_row = await session.execute( select(func.count()).select_from(Topic).where(Topic.domain_id == domain.id) ) topic_count = topic_count_row.scalar_one() topic_ids_row = await session.execute(select(Topic.id).where(Topic.domain_id == domain.id)) topic_ids = [row[0] for row in topic_ids_row.all()] workstream_count = 0 if topic_ids: workstream_count_row = await session.execute( select(func.count()).select_from(Workstream) .where(Workstream.topic_id.in_(topic_ids)) .where(Workstream.status == "active") ) workstream_count = workstream_count_row.scalar_one() ep_count_row = await session.execute( select(func.count()).select_from(ExtensionPoint) .where(ExtensionPoint.domain_id == domain.id) ) td_count_row = await session.execute( select(func.count()).select_from(TechnicalDebt) .where(TechnicalDebt.domain_id == domain.id) ) repos_row = await session.execute( select(ManagedRepo) .where(ManagedRepo.domain_id == domain.id) .where(ManagedRepo.status == "active") .order_by(ManagedRepo.name) ) repos = list(repos_row.scalars().all()) return DomainDetail( id=domain.id, slug=domain.slug, name=domain.name, description=domain.description, status=domain.status, created_at=domain.created_at, updated_at=domain.updated_at, topic_count=topic_count, workstream_count=workstream_count, ep_count=ep_count_row.scalar_one(), td_count=td_count_row.scalar_one(), repos=[RepoStub.model_validate(repo) for repo in repos], ) async def _reject_archive_with_active_topics(domain: Domain, session: AsyncSession) -> None: active_topics = await session.execute( select(func.count()).select_from(Topic) .where(Topic.domain_id == domain.id) .where(Topic.status == "active") ) if active_topics.scalar_one() > 0: raise HTTPException( status_code=409, detail="Cannot archive domain with active topics. Archive or reassign topics first.", ) router = create_domains_router( get_session, domain_model=Domain, repo_model=ManagedRepo, domain_create_schema=DomainCreate, domain_detail_schema=DomainDetail, domain_read_schema=DomainRead, domain_rename_schema=DomainRename, domain_update_schema=DomainUpdate, repo_stub_schema=RepoStub, detail_builder=_build_domain_detail, before_archive=_reject_archive_with_active_topics, list_noload_fields=("topics", "repos", "goals"), include_update_route=False, ) __all__ = ["router"]