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:
parent
4cef58cd98
commit
3578dc2f32
10 changed files with 3331 additions and 9 deletions
|
|
@ -13,6 +13,7 @@ from dataclasses import dataclass
|
|||
from fastapi import HTTPException
|
||||
from sqlalchemy import func, or_, select
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from sqlalchemy.orm import noload
|
||||
|
||||
from api.models.fabric_graph import FabricGraphEdge, FabricGraphImport, FabricGraphNode
|
||||
from api.models.managed_repo import ManagedRepo
|
||||
|
|
@ -95,6 +96,79 @@ async def resolve_repository_slug(
|
|||
)
|
||||
|
||||
|
||||
async def repository_resolutions_for_repositories(
|
||||
session: AsyncSession,
|
||||
repositories: list[ManagedRepo],
|
||||
) -> dict[uuid.UUID, RepositorySlugResolution]:
|
||||
"""Resolve a repository collection with one slug-registry query.
|
||||
|
||||
Collection callers already hold canonical ``ManagedRepo`` rows. Resolving
|
||||
every row through :func:`resolve_repository_slug` would issue two identity
|
||||
queries per repository. Load the complete alias sets once instead while
|
||||
retaining the pre-registry compatibility behavior.
|
||||
"""
|
||||
|
||||
if not repositories:
|
||||
return {}
|
||||
|
||||
repository_ids = [repository.id for repository in repositories]
|
||||
records = list(
|
||||
(
|
||||
await session.execute(
|
||||
select(RepositorySlug)
|
||||
.options(
|
||||
noload(RepositorySlug.repo),
|
||||
noload(RepositorySlug.source_operation),
|
||||
)
|
||||
.where(RepositorySlug.repo_id.in_(repository_ids))
|
||||
.order_by(RepositorySlug.repo_id, RepositorySlug.kind.desc(), RepositorySlug.slug)
|
||||
)
|
||||
).scalars()
|
||||
)
|
||||
records_by_repository: dict[uuid.UUID, list[RepositorySlug]] = {
|
||||
repository_id: [] for repository_id in repository_ids
|
||||
}
|
||||
for record in records:
|
||||
records_by_repository[record.repo_id].append(record)
|
||||
|
||||
resolutions: dict[uuid.UUID, RepositorySlugResolution] = {}
|
||||
for repository in repositories:
|
||||
repository_records = records_by_repository[repository.id]
|
||||
requested_record = next(
|
||||
(record for record in repository_records if record.slug == repository.slug),
|
||||
None,
|
||||
)
|
||||
if requested_record is None:
|
||||
# Compatibility for databases upgraded before the identity backfill.
|
||||
resolutions[repository.id] = RepositorySlugResolution(
|
||||
repo=repository,
|
||||
requested_slug=repository.slug,
|
||||
canonical_slug=repository.slug,
|
||||
slug_status="canonical",
|
||||
aliases=(),
|
||||
)
|
||||
continue
|
||||
|
||||
canonicals = [record for record in repository_records if record.kind == "canonical"]
|
||||
if len(canonicals) != 1 or canonicals[0].slug != repository.slug:
|
||||
raise HTTPException(
|
||||
status_code=409,
|
||||
detail=f"Repository '{repository.id}' has inconsistent canonical slug state",
|
||||
)
|
||||
resolutions[repository.id] = RepositorySlugResolution(
|
||||
repo=repository,
|
||||
requested_slug=repository.slug,
|
||||
canonical_slug=repository.slug,
|
||||
slug_status=requested_record.kind,
|
||||
aliases=tuple(
|
||||
record.slug for record in repository_records if record.kind == "alias"
|
||||
),
|
||||
source_operation_id=requested_record.source_operation_id,
|
||||
)
|
||||
|
||||
return resolutions
|
||||
|
||||
|
||||
async def canonicalize_repository_slug(session: AsyncSession, value: str) -> str:
|
||||
"""Canonicalize a value only when it is a registered repository identity."""
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue