fix: bound repository collection identity projection

Assistant: codex
Assistant-Model: gpt-6-astra
Assistant-Session: 01a06ed7-828d-7ca0-a8d4-0c3e5a0c4102
This commit is contained in:
tegwick 2026-09-05 02:03:52 +02:00
parent 4cef58cd98
commit 3578dc2f32
10 changed files with 3331 additions and 9 deletions

View file

@ -13,7 +13,7 @@ from fastapi import APIRouter, Depends, HTTPException, Response, status
from sqlalchemy import case, func, or_, select
from sqlalchemy.exc import IntegrityError
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.orm import noload
from sqlalchemy.orm import joinedload, noload
from api.config import settings
from api.database import get_session
@ -57,6 +57,7 @@ from api.services.repository_identity import stage_initial_repository_identity
from api.services.repository_aliases import (
RepositorySlugResolution,
affected_slug_predicate,
repository_resolutions_for_repositories,
repository_resolution_for_id,
resolve_repository_slug,
stale_external_references,
@ -126,17 +127,20 @@ async def list_repos(
response.headers["Cache-Control"] = "max-age=60, stale-while-revalidate=30"
q = (
select(ManagedRepo)
.options(noload(ManagedRepo.goals))
.options(
noload("*"),
joinedload(ManagedRepo.domain).noload("*"),
)
.order_by(ManagedRepo.name)
)
if domain:
domain_result = await session.execute(select(Domain).where(Domain.slug == domain))
domain_obj = domain_result.scalar_one_or_none()
if domain_obj is None:
domain_result = await session.execute(select(Domain.id).where(Domain.slug == domain))
domain_id = domain_result.scalar_one_or_none()
if domain_id is None:
raise HTTPException(status_code=404, detail=f"Domain '{domain}' not found")
q = q.where(
or_(
ManagedRepo.domain_id == domain_obj.id,
ManagedRepo.domain_id == domain_id,
ManagedRepo.secondary_domains.contains([domain]),
)
)
@ -147,7 +151,9 @@ async def list_repos(
if business_stake:
q = q.where(ManagedRepo.business_stake.contains([business_stake]))
result = await session.execute(q)
return await _project_repo_reads(session, list(result.scalars().all()))
repositories = list(result.scalars().all())
resolutions = await repository_resolutions_for_repositories(session, repositories)
return await _project_repo_reads(session, repositories, resolutions=resolutions)
@router.post("/", response_model=RepoRead, status_code=status.HTTP_201_CREATED)
@ -944,6 +950,7 @@ async def _project_repo_reads(
repositories: list[ManagedRepo],
*,
requested: RepositorySlugResolution | None = None,
resolutions: dict[uuid.UUID, RepositorySlugResolution] | None = None,
include_stale_external: bool = False,
) -> list[RepoRead]:
projections = await _sbom_projection_map()
@ -952,7 +959,11 @@ async def _project_repo_reads(
resolution = (
requested
if requested is not None and requested.repo.id == repository.id
else await repository_resolution_for_id(session, repository)
else (
resolutions[repository.id]
if resolutions is not None
else await repository_resolution_for_id(session, repository)
)
)
read = RepoRead.model_validate(repository)
read = read.model_copy(