Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ from that cache, so the database is only ever hit once per refresh.
| `GET /stats` | Total collections, events, hazard items, impact items, response items |
| `GET /stats/sources` | Per-source item counts and date ranges, aggregated across collections |
| `GET /stats/events/by-hazard-type` | Event counts grouped by hazard code |
| `GET /stats/events/by-country` | Event counts grouped by country code |
| `GET /stats/items/by-year` | Item counts by year, broken down by type |

## Configuration
Expand Down
5 changes: 5 additions & 0 deletions app/cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ class Snapshot:
total_response_items: int
sources: list[dict]
events_by_hazard_type: list[dict]
events_by_country: list[dict]
items_by_year: list[dict]
generated_at: datetime

Expand Down Expand Up @@ -128,6 +129,9 @@ def refresh(self) -> None:
cur.execute(queries.EVENTS_BY_HAZARD_TYPE)
events_by_hazard_type = cur.fetchall()

cur.execute(queries.EVENTS_BY_COUNTRY)
events_by_country = cur.fetchall()

cur.execute(queries.ITEMS_BY_YEAR)
items_by_year = cur.fetchall()

Expand All @@ -145,6 +149,7 @@ def refresh(self) -> None:
total_response_items=totals["response"],
sources=_with_iso_dates(sources),
events_by_hazard_type=events_by_hazard_type,
events_by_country=events_by_country,
items_by_year=_aggregate_items_by_year(items_by_year),
generated_at=datetime.now(UTC),
)
Expand Down
5 changes: 5 additions & 0 deletions app/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,11 @@ def events_by_hazard_type(snapshot: CachedSnapshot):
return snapshot.events_by_hazard_type


@app.get("/stats/events/by-country")
def events_by_country(snapshot: CachedSnapshot):
return snapshot.events_by_country


@app.get("/stats/items/by-year")
def items_by_year(snapshot: CachedSnapshot):
return snapshot.items_by_year
9 changes: 9 additions & 0 deletions app/queries.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,15 @@
ORDER BY 2 DESC
"""

EVENTS_BY_COUNTRY = """
SELECT country_code, count(*) AS event_count
FROM pgstac.items,
jsonb_array_elements_text(content->'properties'->'monty:country_codes') AS country_code
WHERE collection LIKE '%-events'
GROUP BY 1
ORDER BY 2 DESC
"""

ITEMS_BY_YEAR = """
SELECT collection, extract(year FROM datetime)::int AS year, count(*) AS item_count
FROM pgstac.items
Expand Down
3 changes: 3 additions & 0 deletions tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ def make_snapshot() -> Snapshot:
}
],
events_by_hazard_type=[{"hazard_code": "EQ", "event_count": 4051947}],
events_by_country=[{"country_code": "USA", "event_count": 72578}],
items_by_year=[{"year": 2026, "events": 372935, "hazards": 0, "impacts": 0, "response": 0}],
generated_at=datetime.now(UTC),
)
Expand All @@ -43,6 +44,7 @@ def test_stats_not_ready_before_first_refresh():
"/stats",
"/stats/sources",
"/stats/events/by-hazard-type",
"/stats/events/by-country",
"/stats/items/by-year",
):
assert client.get(path).status_code == 503
Expand All @@ -68,6 +70,7 @@ def test_stats_served_from_cache_once_ready():
assert sources[0]["earliest"] == "1990-01-01T00:22:33.990000+00:00"

assert client.get("/stats/events/by-hazard-type").json() == [{"hazard_code": "EQ", "event_count": 4051947}]
assert client.get("/stats/events/by-country").json() == [{"country_code": "USA", "event_count": 72578}]
assert client.get("/stats/items/by-year").json() == [
{"year": 2026, "events": 372935, "hazards": 0, "impacts": 0, "response": 0}
]
Expand Down
Loading