diff --git a/README.md b/README.md index 580fae6..fb044de 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/app/cache.py b/app/cache.py index e2e98b5..14cd446 100644 --- a/app/cache.py +++ b/app/cache.py @@ -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 @@ -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() @@ -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), ) diff --git a/app/main.py b/app/main.py index dd30e1f..f35f5a1 100644 --- a/app/main.py +++ b/app/main.py @@ -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 diff --git a/app/queries.py b/app/queries.py index 721a894..9cba26e 100644 --- a/app/queries.py +++ b/app/queries.py @@ -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 diff --git a/tests/test_api.py b/tests/test_api.py index 0ca9847..8fdc999 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -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), ) @@ -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 @@ -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} ]