Skip to content

Commit

Permalink
PB-1169: Remove forecast filter from GET search
Browse files Browse the repository at this point in the history
Decided to remove the forecast filtering options from the GET /search request
due to colons in the parameter names.
Also fixed the POST request body to actually use the parameters that contain a
colon.
  • Loading branch information
benschs committed Jan 23, 2025
1 parent 9915e3b commit 3e0d8fc
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 106 deletions.
14 changes: 14 additions & 0 deletions app/stac_api/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,20 @@ def harmonize_post_get_for_search(request):
query_param['ids'] = query_param['ids'].split(',') # to array
if 'collections' in query_param:
query_param['collections'] = query_param['collections'].split(',') # to array

# Forecast properties can only be filtered with method POST.
# Decision was made as `:` need to be url encoded and (at least for now) we do not need to
# support forecast filtering in the GET request.
if 'forecast:reference_datetime' in query_param:
del query_param['forecast:reference_datetime']
if 'forecast:horizon' in query_param:
del query_param['forecast:horizon']
if 'forecast:duration' in query_param:
del query_param['forecast:duration']
if 'forecast:variable' in query_param:
del query_param['forecast:variable']
if 'forecast:perturbed' in query_param:
del query_param['forecast:perturbed']
return query_param


Expand Down
10 changes: 5 additions & 5 deletions app/stac_api/validators_serializer.py
Original file line number Diff line number Diff line change
Expand Up @@ -359,11 +359,11 @@ def validate_query_parameters_post_search(self, query_param):
"limit",
"cursor",
"query",
"forecast_reference_datetime",
"forecast_horizon",
"forecast_duration",
"forecast_variable",
"forecast_perturbed"
"forecast:reference_datetime",
"forecast:horizon",
"forecast:duration",
"forecast:variable",
"forecast:perturbed"
]
wrong_query_parameters = set(query_param.keys()).difference(set(accepted_query_parameters))
if wrong_query_parameters:
Expand Down
20 changes: 10 additions & 10 deletions app/stac_api/views/general.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,18 +93,18 @@ def get_queryset(self):
queryset = queryset.filter_by_query(dict_query)
if 'intersects' in query_param:
queryset = queryset.filter_by_intersects(json.dumps(query_param['intersects']))
if 'forecast_reference_datetime' in query_param:
if 'forecast:reference_datetime' in query_param:
queryset = queryset.filter_by_forecast_reference_datetime(
query_param['forecast_reference_datetime']
query_param['forecast:reference_datetime']
)
if 'forecast_horizon' in query_param:
queryset = queryset.filter_by_forecast_horizon(query_param['forecast_horizon'])
if 'forecast_duration' in query_param:
queryset = queryset.filter_by_forecast_duration(query_param['forecast_duration'])
if 'forecast_variable' in query_param:
queryset = queryset.filter_by_forecast_variable(query_param['forecast_variable'])
if 'forecast_perturbed' in query_param:
queryset = queryset.filter_by_forecast_perturbed(query_param['forecast_perturbed'])
if 'forecast:horizon' in query_param:
queryset = queryset.filter_by_forecast_horizon(query_param['forecast:horizon'])
if 'forecast:duration' in query_param:
queryset = queryset.filter_by_forecast_duration(query_param['forecast:duration'])
if 'forecast:variable' in query_param:
queryset = queryset.filter_by_forecast_variable(query_param['forecast:variable'])
if 'forecast:perturbed' in query_param:
queryset = queryset.filter_by_forecast_perturbed(query_param['forecast:perturbed'])

if settings.DEBUG_ENABLE_DB_EXPLAIN_ANALYZE:
logger.debug(
Expand Down
114 changes: 23 additions & 91 deletions app/tests/tests_10/test_search_endpoint.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import logging
from datetime import datetime
from datetime import timedelta
from urllib.parse import quote_plus

from django.test import Client
from django.test import override_settings
Expand Down Expand Up @@ -609,31 +610,15 @@ def setUp(self): # pylint: disable=invalid-name
self.maxDiff = None # pylint: disable=invalid-name

def test_reference_datetime_exact(self):
val = '2025-01-01T13:05:10Z'
response = self.client.get(f"{self.path}?forecast_reference_datetime={val}")
self.assertStatusCode(200, response)
json_data = response.json()
self.assertEqual(len(json_data['features']), 1)
for feature in json_data['features']:
self.assertIn(feature['id'], ['item-1'])

payload = {"forecast_reference_datetime": f"{val}"}
payload = {"forecast:reference_datetime": "2025-01-01T13:05:10Z"}
response = self.client.post(self.path, data=payload, content_type="application/json")
self.assertStatusCode(200, response)
json_data = response.json()
self.assertEqual(len(json_data['features']), 1)
for feature in json_data['features']:
self.assertIn(feature['id'], ['item-1'])

val = '2025-02-01T13:05:10Z'
response = self.client.get(f"{self.path}?forecast_reference_datetime={val}")
self.assertStatusCode(200, response)
json_data = response.json()
self.assertEqual(len(json_data['features']), 3)
for feature in json_data['features']:
self.assertIn(feature['id'], ['item-2', 'item-3', 'item-4'])

payload = {"forecast_reference_datetime": f"{val}"}
payload = {"forecast:reference_datetime": "2025-02-01T13:05:10Z"}
response = self.client.post(self.path, data=payload, content_type="application/json")
self.assertStatusCode(200, response)
json_data = response.json()
Expand All @@ -642,15 +627,7 @@ def test_reference_datetime_exact(self):
self.assertIn(feature['id'], ['item-2', 'item-3', 'item-4'])

def test_reference_datetime_range(self):
val = '2025-02-01T00:00:00Z/2025-02-28T00:00:00Z'
response = self.client.get(f"{self.path}?forecast_reference_datetime={val}")
self.assertStatusCode(200, response)
json_data = response.json()
self.assertEqual(len(json_data['features']), 3)
for feature in json_data['features']:
self.assertIn(feature['id'], ['item-2', 'item-3', 'item-4'])

payload = {"forecast_reference_datetime": f"{val}"}
payload = {"forecast:reference_datetime": "2025-02-01T00:00:00Z/2025-02-28T00:00:00Z"}
response = self.client.post(self.path, data=payload, content_type="application/json")
self.assertStatusCode(200, response)
json_data = response.json()
Expand All @@ -659,15 +636,7 @@ def test_reference_datetime_range(self):
self.assertIn(feature['id'], ['item-2', 'item-3', 'item-4'])

def test_reference_datetime_open_end(self):
val = '2025-02-01T13:05:10Z/..'
response = self.client.get(f"{self.path}?forecast_reference_datetime={val}")
self.assertStatusCode(200, response)
json_data = response.json()
self.assertEqual(len(json_data['features']), 4)
for feature in json_data['features']:
self.assertIn(feature['id'], ['item-2', 'item-3', 'item-4', 'item-5'])

payload = {"forecast_reference_datetime": f"{val}"}
payload = {"forecast:reference_datetime": "2025-02-01T13:05:10Z/.."}
response = self.client.post(self.path, data=payload, content_type="application/json")
self.assertStatusCode(200, response)
json_data = response.json()
Expand All @@ -676,15 +645,7 @@ def test_reference_datetime_open_end(self):
self.assertIn(feature['id'], ['item-2', 'item-3', 'item-4', 'item-5'])

def test_reference_datetime_open_start(self):
val = '../2025-02-01T13:05:10Z'
response = self.client.get(f"{self.path}?forecast_reference_datetime={val}")
self.assertStatusCode(200, response)
json_data = response.json()
self.assertEqual(len(json_data['features']), 4)
for feature in json_data['features']:
self.assertIn(feature['id'], ['item-1', 'item-2', 'item-3', 'item-4'])

payload = {"forecast_reference_datetime": f"{val}"}
payload = {"forecast:reference_datetime": "../2025-02-01T13:05:10Z"}
response = self.client.post(self.path, data=payload, content_type="application/json")
self.assertStatusCode(200, response)
json_data = response.json()
Expand All @@ -693,15 +654,7 @@ def test_reference_datetime_open_start(self):
self.assertIn(feature['id'], ['item-1', 'item-2', 'item-3', 'item-4'])

def test_horizon(self):
val = 'PT3H'
response = self.client.get(f"{self.path}?forecast_horizon={val}")
self.assertStatusCode(200, response)
json_data = response.json()
self.assertEqual(len(json_data['features']), 1)
for feature in json_data['features']:
self.assertIn(feature['id'], ['item-3'])

payload = {"forecast_horizon": f"{val}"}
payload = {"forecast:horizon": "PT3H"}
response = self.client.post(self.path, data=payload, content_type="application/json")
self.assertStatusCode(200, response)
json_data = response.json()
Expand All @@ -710,15 +663,7 @@ def test_horizon(self):
self.assertIn(feature['id'], ['item-3'])

def test_duration(self):
val = 'PT12H'
response = self.client.get(f"{self.path}?forecast_duration={val}")
self.assertStatusCode(200, response)
json_data = response.json()
self.assertEqual(len(json_data['features']), 4)
for feature in json_data['features']:
self.assertIn(feature['id'], ['item-1', 'item-2', 'item-4', 'item-5'])

payload = {"forecast_duration": f"{val}"}
payload = {"forecast:duration": "PT12H"}
response = self.client.post(self.path, data=payload, content_type="application/json")
self.assertStatusCode(200, response)
json_data = response.json()
Expand All @@ -727,15 +672,7 @@ def test_duration(self):
self.assertIn(feature['id'], ['item-1', 'item-2', 'item-4', 'item-5'])

def test_variable(self):
val = 'air_temperature'
response = self.client.get(f"{self.path}?forecast_variable={val}")
self.assertStatusCode(200, response)
json_data = response.json()
self.assertEqual(len(json_data['features']), 2)
for feature in json_data['features']:
self.assertIn(feature['id'], ['item-4', 'item-5'])

payload = {"forecast_variable": f"{val}"}
payload = {"forecast:variable": "air_temperature"}
response = self.client.post(self.path, data=payload, content_type="application/json")
self.assertStatusCode(200, response)
json_data = response.json()
Expand All @@ -744,15 +681,7 @@ def test_variable(self):
self.assertIn(feature['id'], ['item-4', 'item-5'])

def test_perturbed(self):
val = 'True'
response = self.client.get(f"{self.path}?forecast_perturbed={val}")
self.assertStatusCode(200, response)
json_data = response.json()
self.assertEqual(len(json_data['features']), 1)
for feature in json_data['features']:
self.assertIn(feature['id'], ['item-4'])

payload = {"forecast_perturbed": f"{val}"}
payload = {"forecast:perturbed": "True"}
response = self.client.post(self.path, data=payload, content_type="application/json")
self.assertStatusCode(200, response)
json_data = response.json()
Expand All @@ -761,21 +690,24 @@ def test_perturbed(self):
self.assertIn(feature['id'], ['item-4'])

def test_multiple(self):
response = self.client.get(
f"{self.path}?forecast_perturbed=False&forecast_horizon=PT6H&forecast_variable=T"
)
self.assertStatusCode(200, response)
json_data = response.json()
self.assertEqual(len(json_data['features']), 2)
for feature in json_data['features']:
self.assertIn(feature['id'], ['item-1', 'item-2'])

payload = {
"forecast_perturbed": "False", "forecast_horizon": "PT6H", "forecast_variable": "T"
"forecast:perturbed": "False", "forecast:horizon": "PT6H", "forecast:variable": "T"
}
response = self.client.post(self.path, data=payload, content_type="application/json")
self.assertStatusCode(200, response)
json_data = response.json()
self.assertEqual(len(json_data['features']), 2)
for feature in json_data['features']:
self.assertIn(feature['id'], ['item-1', 'item-2'])

def test_get_request_does_not_filter_forecast(self):
response = self.client.get(
f"{self.path}?" + quote_plus(
"forecast:reference_datetime=2025-01-01T13:05:10Z&" + "forecast:duration=PT12H&" +
"forecast:perturbed=False&" + "forecast:horizon=PT6H&" + "forecast:variable=T"
)
)
self.assertStatusCode(200, response)
json_data = response.json()
# As GET request should not filter for forecast expect all 5 features to be returned.
self.assertEqual(len(json_data['features']), 5)

0 comments on commit 3e0d8fc

Please sign in to comment.