Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
53b486c
chore(deps): build against climate-ref 0.20.0
lewisjared Oct 24, 2026
c9c1b35
refactor: use select_latest_executions from climate-ref
lewisjared Oct 21, 2026
09623d9
refactor: read resource summaries from ResourcesReader
lewisjared Oct 21, 2026
5c299e9
refactor: build era and source filters on InputDatasetFilter
lewisjared Oct 21, 2026
c72b0e1
refactor: filter the executions list in ExecutionGroupFilter
lewisjared Oct 21, 2026
3887e75
refactor: count groups per era with ExecutionsReader.statistics
lewisjared Oct 21, 2026
85ab7b3
refactor: count diagnostic groups with DiagnosticsReader.stats
lewisjared Oct 21, 2026
f6bc7c9
refactor: read value flags from DiagnosticsReader.with_values
lewisjared Oct 21, 2026
3996ffb
refactor: list datasets with DatasetsReader.list
lewisjared Oct 21, 2026
67d9227
chore: use Session.get for execution outputs
lewisjared Oct 21, 2026
3cfe64f
refactor: resolve the mip_era query value in one place
lewisjared Oct 21, 2026
0e554fa
test: pin how mixed-era and obs-only executions are scoped
lewisjared Oct 21, 2026
0a8cbc3
refactor: scope values by era with or_no_model_input
lewisjared Oct 22, 2026
33145ec
refactor: read catalog resource usage from ResourcesReader.summaries
lewisjared Oct 22, 2026
029ee43
fix: treat a blank isolate_ids or exclude_ids as no filter
lewisjared Oct 22, 2026
79323cd
fix: return an empty model for an unknown mip_era
lewisjared Oct 22, 2026
4efb05c
test: stop pytest collecting the test config helpers as tests
lewisjared Oct 22, 2026
b2b0861
refactor: build the last era filters from cmip_input_filter
lewisjared Oct 22, 2026
e1c2ae7
refactor(api)!: drop the per-attempt execution counts from diagnostics
lewisjared Oct 22, 2026
a83b615
refactor(api)!: remove the /diagnostics/facets endpoint
lewisjared Oct 22, 2026
2878e52
refactor(api)!: build on climate-ref's query package with explicit fi…
lewisjared Oct 24, 2026
4014eaa
perf: count diagnostic groups without counting their executions
lewisjared Oct 23, 2026
44ad2f7
perf: fetch metric value facets apart from the values
lewisjared Oct 23, 2026
8ba17c5
docs: add changelog for #147
lewisjared Oct 23, 2026
b0c3177
docs: drop 'all' from the execution values value_type
lewisjared Oct 24, 2026
0f393c2
fix: keep obs-only groups in every era-scoped count
lewisjared Oct 24, 2026
00be0e1
fix: enable an execution's value tabs from its own values
lewisjared Oct 24, 2026
1755cb2
fix: leave groups with a retracted latest execution out of the model …
lewisjared Oct 24, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion backend/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ dependencies = [
"psycopg[binary]<4.0.0,>=3.1.13",
"pydantic-settings<3.0.0,>=2.13.1",
"sentry-sdk[fastapi]>=2.0.0",
"climate-ref[aft-providers,postgres]>=0.19.0,<0.20",
"climate-ref[aft-providers,postgres]>=0.20.0,<0.21",
"loguru",
"pyyaml>=6.0",
"fastapi-sqlalchemy-monitor>=1.1.3",
Expand Down
59 changes: 24 additions & 35 deletions backend/src/ref_backend/api/routes/datasets.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,17 @@
from typing import Any

from fastapi import APIRouter, HTTPException, Query
from sqlalchemy import func, select

from climate_ref import models
from climate_ref.datasets import get_dataset_adapter
from climate_ref.results import DatasetFilter
from climate_ref.results.datasets import DatasetView, select_datasets
from climate_ref.results import DatasetFilter, ExecutionGroupFilter, InputDatasetFilter
from climate_ref.results.datasets import DatasetView
from climate_ref_core.datasets import SourceDatasetType
from ref_backend.api.deps import AppContextDep, ReaderDep, SessionDep
from ref_backend.api.deps import AppContextDep, ReaderDep
from ref_backend.core.execution_groups import load_execution_groups
from ref_backend.models import (
Collection,
Dataset,
ExecutionGroup,
)
from ref_backend.models.executions import EXECUTION_GROUP_LOAD_OPTIONS

router = APIRouter(prefix="/datasets", tags=["datasets"])

Expand All @@ -39,7 +36,7 @@ def _parse_source_type(dataset_type: str) -> SourceDatasetType:

@router.get("/", name="list")
async def _list( # noqa: PLR0913, PLR0917
session: SessionDep,
reader: ReaderDep,
offset: int = Query(0, ge=0),
limit: int = Query(10, ge=1, le=100),
name_contains: str = Query(None, description="Filter datasets by name"),
Expand All @@ -61,27 +58,21 @@ async def _list( # noqa: PLR0913, PLR0917
)
dataset_type = SourceDatasetType.CMIP6.value

source_type = _parse_source_type(dataset_type)
adapter = get_dataset_adapter(source_type.value)

dataset_filter = DatasetFilter(
source_type=source_type,
source_type=_parse_source_type(dataset_type),
facets=_parse_facets(facets) if facets else None,
slug_contains=name_contains or None,
# Retracted datasets stay visible: this is an inspection view, not a solve-time query.
include_retracted=True,
)
try:
statement = select_datasets(dataset_filter, latest_group_by=adapter.dataset_id_metadata)
datasets = reader.datasets.list(dataset_filter, offset=offset, limit=limit)
except ValueError as exc:
raise HTTPException(status_code=400, detail=str(exc)) from None

if name_contains:
statement = statement.where(models.Dataset.slug.ilike(f"%{name_contains}%"))

total_count = session.execute(select(func.count()).select_from(statement.subquery())).scalar_one()
datasets = session.execute(statement.offset(offset).limit(limit)).scalars().unique().all()

return Collection(data=[Dataset.build(ds) for ds in datasets], total_count=total_count)
return Collection(
data=[Dataset.build_from_view(ds) for ds in datasets.items], total_count=datasets.total_count
)


@router.get("/{slug}", name="get")
Expand All @@ -108,20 +99,18 @@ async def executions(
limit: int = Query(10, ge=1, le=100),
) -> Collection[ExecutionGroup]:
"""
List the currently registered diagnostics
"""
execution_groups_query = (
app_context.session.query(models.ExecutionGroup)
.options(*EXECUTION_GROUP_LOAD_OPTIONS)
.join(models.ExecutionGroup.executions)
.join(models.Execution.datasets)
.filter(models.Dataset.id == dataset_id)
.distinct()
)
total_count = execution_groups_query.count()
_execution_groups = execution_groups_query.offset(offset).limit(limit).all()
List the execution groups whose latest execution used this dataset

return Collection(
data=[ExecutionGroup.build(eg, app_context) for eg in _execution_groups],
total_count=total_count,
Groups from every diagnostic version are returned, retracted ones included.
"""
groups, total_count = load_execution_groups(
app_context.session,
ExecutionGroupFilter(
input_datasets=InputDatasetFilter(dataset_ids=dataset_id),
include_superseded=True,
include_retracted=True,
),
offset=offset,
limit=limit,
)
return Collection(data=[ExecutionGroup.build(g, app_context) for g in groups], total_count=total_count)
Loading
Loading