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
3 changes: 2 additions & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,8 @@ raise states the problem and then the move that fixes it, in that order.
(`skip_geometry` -> `skipGeometry`, `filter_lang` -> `filter-lang`); tests
assert exact URLs and query params.
- Multi-value OGC params are comma-joined GETs, except `monitoring-locations`
which POSTs CQL2 JSON. The OGC edge WAF caps total request bytes (URL + body)
and `combined-metadata`, which POST CQL2 JSON because comma-joined values
return no rows. The OGC edge WAF caps total request bytes (URL + body)
at ~8200, so `dataretrieval/ogc/chunking.py` auto-splits oversized queries
across chunks (both GET and POST paths); preserve this when adding new
list-shaped kwargs.
Expand Down
7 changes: 4 additions & 3 deletions dataretrieval/waterdata/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,13 +73,14 @@
- {"monitoring_location_id", "time_series_id"}
)

# The Water Data API dialect: ``monitoring-locations`` doesn't accept
# comma-separated multi-value GET params (so it must POST CQL2 JSON),
# The Water Data API dialect: ``monitoring-locations`` and
# ``combined-metadata`` don't interpret comma-separated GET params as multiple
# values (they return empty results, so multi-value filters must POST CQL2 JSON),
# ``daily`` renders its time arguments date-only (``YYYY-MM-DD``), and the
# ``time_cols``/``numerical_cols``/``sort_cols`` are the Water-Data column
# vocabulary used to coerce datetime/numeric columns and to sort results.
WATERDATA_DIALECT = OgcDialect(
cql2_services=frozenset({"monitoring-locations"}),
cql2_services=frozenset({"combined-metadata", "monitoring-locations"}),
date_only_services=frozenset({"daily"}),
time_cols=frozenset(
{
Expand Down
47 changes: 33 additions & 14 deletions tests/waterdata_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -1077,26 +1077,45 @@ def test_get_combined_metadata(httpx_mock):
assert hasattr(md, "url") and hasattr(md, "query_time")


def test_get_combined_metadata_multi_site(httpx_mock):
"""Multiple sites are comma-joined into one GET.

Only ``monitoring-locations`` is a CQL2/POST collection in the Water Data
dialect; ``combined-metadata`` is not, so this stays a query param.
"""
sites = ["USGS-07069000", "USGS-07064000", "USGS-07068000"]
@pytest.mark.parametrize(
("kwargs", "property_name", "values"),
[
(
{"monitoring_location_id": ["USGS-07069000", "USGS-07064000"]},
"monitoring_location_id",
["USGS-07069000", "USGS-07064000"],
),
({"site_type_code": ["ST", "ST-TS"]}, "site_type_code", ["ST", "ST-TS"]),
({"agency_code": ["USGS", "USBR"]}, "agency_code", ["USGS", "USBR"]),
(
{"state": ["New York", "New Jersey"]},
"state_name",
["New York", "New Jersey"],
),
],
)
def test_get_combined_metadata_iterables_use_post_cql(
httpx_mock, kwargs, property_name, values
):
"""Iterable filters use CQL2 because comma-joined GET values match no rows."""
_mock_items(httpx_mock, "combined-metadata")

get_combined_metadata(
monitoring_location_id=sites, parameter_code="00060", skip_geometry=True
)
get_combined_metadata(parameter_code="00060", skip_geometry=True, **kwargs)

req = next(
r for r in httpx_mock.get_requests() if "combined-metadata/items" in str(r.url)
)
assert req.method == "GET"
qs = _sent(httpx_mock, "combined-metadata")[0]
assert qs["monitoring_location_id"] == [",".join(sites)]
assert qs["parameter_code"] == ["00060"]
assert req.method == "POST"
assert parse_qs(urlsplit(str(req.url)).query)["parameter_code"] == ["00060"]
assert json.loads(req.content) == {
"op": "and",
"args": [
{
"op": "in",
"args": [{"property": property_name}, values],
}
],
}


# --- peaks -------------------------------------------------------------------
Expand Down