| """AnalysisDataSourceStore — read per-analysis data-source bindings (#10). | |
| The dedorch `data_sources` table records which catalog sources an analysis is scoped | |
| to (`reference_id` = the catalog source id). It's written at `/analysis/create`; this | |
| store is the read seam for the two consumers — `structured_flow` catalog scoping and | |
| the report's data-source appendix. | |
| Fail-open by convention at the call sites: an empty binding (legacy room, or the FE | |
| not yet sending ids) means "no restriction" — fall back to the whole catalog. Mirrors | |
| `AnalysisStateStore`: each call opens its own `AsyncSession`. | |
| """ | |
| from __future__ import annotations | |
| from sqlalchemy import select | |
| from src.db.postgres.connection import AsyncSessionLocal | |
| from src.db.postgres.models import AnalysisDataSourceRow | |
| from src.middlewares.logging import get_logger | |
| logger = get_logger("binding_store") | |
| class AnalysisDataSourceStore: | |
| """Read the bound catalog `source_id`s for an analysis.""" | |
| async def get(self, analysis_id: str) -> list[str]: | |
| async with AsyncSessionLocal() as session: | |
| result = await session.execute( | |
| select(AnalysisDataSourceRow.reference_id).where( | |
| AnalysisDataSourceRow.analysis_id == analysis_id | |
| ) | |
| ) | |
| return list(result.scalars().all()) | |