diff --git a/tests/fixtures/timeseries/timeseries.json b/tests/fixtures/timeseries/timeseries.json index 47e89337793c5427ee7e9d1ae27003434910d324..a255e293f7db763ee82390b5974b9726b47be84b 100644 --- a/tests/fixtures/timeseries/timeseries.json +++ b/tests/fixtures/timeseries/timeseries.json @@ -35,5 +35,20 @@ "Station code": "XXX", "Station name": "Secret" } }, "programme_id": 0 + }, + { + "station_id": 3, + "variable_id": 7, + "label": "CMA", + "order": 3, + "sampling_frequency": 0, + "aggregation": 0, + "data_start_date": "2023-09-07 15:30:00+00:00", + "data_end_date": "2024-12-31 14:30:00+00:00", + "data_origin": 0, + "data_origin_type": 0, + "sampling_height": 7, + "additional_metadata": {}, + "programme_id": 0 } ] diff --git a/tests/fixtures/timeseries/timeseries_timeseries_roles.json b/tests/fixtures/timeseries/timeseries_timeseries_roles.json index 562603fe5fb62c67bb83b5eb893678a7c93b430c..cbe47c2d2b619d344d9fdc1dda6b35c665828d7c 100644 --- a/tests/fixtures/timeseries/timeseries_timeseries_roles.json +++ b/tests/fixtures/timeseries/timeseries_timeseries_roles.json @@ -13,5 +13,10 @@ "_comment": "Every time series needs at least one role (time series without roles are not allowed!)", "timeseries_id": 2, "role_id": 1 + }, + { + "_comment": "Every time series needs at least one role (time series without roles are not allowed!)", + "timeseries_id": 3, + "role_id": 2 } ] diff --git a/tests/test_search.py b/tests/test_search.py index 34061821483cdea4dffaeddc96222c719e5ee02d..5ccf147c08b0da377c39396ef51fc5960bd6daa0 100644 --- a/tests/test_search.py +++ b/tests/test_search.py @@ -368,7 +368,119 @@ class TestApps: 'street_address': 'Wilhelm-Johnen-Straße', 'country': 'Germany', 'homepage': 'https://www.fz-juelich.de', - 'contact_url': 'mailto:toar-data@fz-juelich.de'}}}]}] + 'contact_url': 'mailto:toar-data@fz-juelich.de'}}}]}, + {'id': 3, + 'additional_metadata': {}, + 'aggregation': 'mean', + 'coverage': -1.0, + 'data_end_date': '2024-12-31T14:30:00+00:00', + 'data_origin': 'instrument', + 'data_origin_type': 'measurement', + 'data_start_date': '2023-09-07T15:30:00+00:00', + 'doi': '', + 'label': 'CMA', + 'order': 3, + 'programme': { + 'description': '', + 'homepage': '', + 'id': 0, + 'longname': '', + 'name': '', + }, + 'provider_version': 'N/A', + 'roles': [ + { + 'contact': { + 'id': 4, + 'organisation': { + 'city': 'Dessau-Roßlau', + 'contact_url': 'mailto:immission@uba.de', + 'country': 'Germany', + 'homepage': 'https://www.umweltbundesamt.de', + 'id': 1, + 'kind': 'government', + 'longname': 'Umweltbundesamt', + 'name': 'UBA', + 'postcode': '06844', + 'street_address': 'Wörlitzer Platz 1', + }, + }, + 'id': 2, + 'role': 'resource provider', + 'status': 'active', + }, + ], + 'sampling_frequency': 'hourly', + 'sampling_height': 7.0, + 'station': { + 'additional_metadata': {}, + 'aux_docs': [], + 'aux_images': [], + 'aux_urls': [], + 'changelog': [ + { + 'author_id': 1, + 'datetime': '2023-08-15T21:16:20.596545+00:00', + 'description': 'station created', + 'new_value': '', + 'old_value': '', + 'station_id': 3, + 'type_of_change': 'created', + }, + ], + 'codes': [ + 'China_test8', + ], + 'coordinate_validation_status': 'not checked', + 'coordinates': { + 'alt': 1534.0, + 'lat': 36.256, + 'lng': 117.106, + }, + 'country': 'China', + 'globalmeta': { + 'climatic_zone_year2016': '6 (warm temperate dry)', + 'distance_to_major_road_year2020': -999.0, + 'dominant_ecoregion_year2017': '-1 (undefined)', + 'dominant_landcover_year2012': '10 (Cropland, rainfed)', + 'ecoregion_description_25km_year2017': '', + 'htap_region_tier1_year2010': '10 (SAF Sub Saharan/sub Sahel Africa)', + 'landcover_description_25km_year2012': '', + 'max_population_density_25km_year1990': -1.0, + 'max_population_density_25km_year2015': -1.0, + 'max_stable_nightlights_25km_year1992': -999.0, + 'max_stable_nightlights_25km_year2013': -999.0, + 'max_topography_srtm_relative_alt_5km_year1994': -999.0, + 'mean_nox_emissions_10km_year2000': -999.0, + 'mean_nox_emissions_10km_year2015': -999.0, + 'mean_population_density_250m_year1990': -1.0, + 'mean_population_density_250m_year2015': -1.0, + 'mean_population_density_5km_year1990': -1.0, + 'mean_population_density_5km_year2015': -1.0, + 'mean_stable_nightlights_1km_year2013': -999.0, + 'mean_stable_nightlights_5km_year2013': -999.0, + 'mean_topography_srtm_alt_1km_year1994': -999.0, + 'mean_topography_srtm_alt_90m_year1994': -999.0, + 'min_topography_srtm_relative_alt_5km_year1994': -999.0, + 'stddev_topography_srtm_relative_alt_5km_year1994': -999.0, + 'toar1_category': 'unclassified', + 'toar2_category': 'suburban', + }, + 'id': 3, + 'name': 'Test_China', + 'state': 'Shandong Sheng', + 'timezone': 'Asia/Shanghai', + 'type': 'unknown', + 'type_of_area': 'unknown', + }, + 'variable': { + 'cf_standardname': 'mole_fraction_of_toluene_in_air', + 'chemical_formula': 'C7H8', + 'displayname': 'Toluene', + 'id': 7, + 'longname': 'toluene', + 'name': 'toluene', + 'units': 'nmol mol-1' }}] assert response.json() == expected_resp @@ -517,6 +629,63 @@ class TestApps: 'author_id': 1, 'type_of_change': 'created' }]}, + 'programme': {'id': 0, 'name': '', 'longname': '', 'homepage': '', 'description': ''}}, + {'id': 3, 'label': 'CMA', 'order': 3, + 'sampling_frequency': 'hourly', 'aggregation': 'mean', 'data_origin_type': 'measurement', + 'data_start_date': '2023-09-07T15:30:00+00:00', 'data_end_date': '2024-12-31T14:30:00+00:00', 'coverage': -1.0, + 'data_origin': 'instrument', 'sampling_height': 7.0, + 'provider_version': 'N/A', + 'doi': '', + 'additional_metadata': {}, + 'roles': [{'id': 2, 'role': 'resource provider', 'status': 'active', + 'contact': {'id': 4, 'organisation': {'id': 1, 'name': 'UBA', 'longname': 'Umweltbundesamt', + 'kind': 'government', 'city': 'Dessau-Roßlau', 'postcode': '06844', 'street_address': 'Wörlitzer Platz 1', + 'country': 'Germany', 'homepage': 'https://www.umweltbundesamt.de', 'contact_url': 'mailto:immission@uba.de'}}}], + 'variable': {'name': 'toluene', 'longname': 'toluene', 'displayname': 'Toluene', + 'cf_standardname': 'mole_fraction_of_toluene_in_air', 'units': 'nmol mol-1', + 'chemical_formula': 'C7H8', 'id': 7}, + 'station': {'id': 3, 'codes': [ 'China_test8' ], 'name': 'Test_China', + 'coordinates': { 'alt': 1534.0, 'lat': 36.256, 'lng': 117.106 }, + 'coordinate_validation_status': 'not checked', + 'country': 'China', 'state': 'Shandong Sheng', + 'type': 'unknown', 'type_of_area': 'unknown', + 'timezone': 'Asia/Shanghai', 'additional_metadata': {}, + 'aux_images': [], 'aux_docs': [], 'aux_urls': [], + 'globalmeta': { + 'climatic_zone_year2016': '6 (warm temperate dry)', + 'distance_to_major_road_year2020': -999.0, + 'dominant_ecoregion_year2017': '-1 (undefined)', + 'dominant_landcover_year2012': '10 (Cropland, rainfed)', + 'ecoregion_description_25km_year2017': '', + 'htap_region_tier1_year2010': '10 (SAF Sub Saharan/sub Sahel Africa)', + 'landcover_description_25km_year2012': '', + 'max_population_density_25km_year1990': -1.0, + 'max_population_density_25km_year2015': -1.0, + 'max_stable_nightlights_25km_year1992': -999.0, + 'max_stable_nightlights_25km_year2013': -999.0, + 'max_topography_srtm_relative_alt_5km_year1994': -999.0, + 'mean_nox_emissions_10km_year2000': -999.0, + 'mean_nox_emissions_10km_year2015': -999.0, + 'mean_population_density_250m_year1990': -1.0, + 'mean_population_density_250m_year2015': -1.0, + 'mean_population_density_5km_year1990': -1.0, + 'mean_population_density_5km_year2015': -1.0, + 'mean_stable_nightlights_1km_year2013': -999.0, + 'mean_stable_nightlights_5km_year2013': -999.0, + 'mean_topography_srtm_alt_1km_year1994': -999.0, + 'mean_topography_srtm_alt_90m_year1994': -999.0, + 'min_topography_srtm_relative_alt_5km_year1994': -999.0, + 'stddev_topography_srtm_relative_alt_5km_year1994': -999.0, + 'toar1_category': 'unclassified', + 'toar2_category': 'suburban'}, + 'changelog': [{'datetime': '2023-08-15T21:16:20.596545+00:00', + 'description': 'station created', + 'old_value': '', + 'new_value': '', + 'station_id': 3, + 'author_id': 1, + 'type_of_change': 'created' + }]}, 'programme': {'id': 0, 'name': '', 'longname': '', 'homepage': '', 'description': ''}}] assert response.json() == expected_resp @@ -537,6 +706,14 @@ class TestApps: assert response.json() == expected_resp + def test_search_empty_bounding_box_and_fields(self, client, db): + response = client.get("/search/?bounding_box=117,36,118,37&fields=station_id") + expected_status_code = 200 + assert response.status_code == expected_status_code + expected_resp = [] + assert response.json() == expected_resp + + def test_search_with_bounding_box(self, client, db): response = client.get("/search/?bounding_box=36,117,37,118") expected_status_code = 200 @@ -603,7 +780,119 @@ class TestApps: 'author_id': 1, 'type_of_change': 'created' }]}, - 'programme': {'id': 0, 'name': '', 'longname': '', 'homepage': '', 'description': ''}}] + 'programme': {'id': 0, 'name': '', 'longname': '', 'homepage': '', 'description': ''}}, + {'id': 3, + 'additional_metadata': {}, + 'aggregation': 'mean', + 'coverage': -1.0, + 'data_end_date': '2024-12-31T14:30:00+00:00', + 'data_origin': 'instrument', + 'data_origin_type': 'measurement', + 'data_start_date': '2023-09-07T15:30:00+00:00', + 'doi': '', + 'label': 'CMA', + 'order': 3, + 'programme': { + 'description': '', + 'homepage': '', + 'id': 0, + 'longname': '', + 'name': '', + }, + 'provider_version': 'N/A', + 'roles': [ + { + 'contact': { + 'id': 4, + 'organisation': { + 'city': 'Dessau-Roßlau', + 'contact_url': 'mailto:immission@uba.de', + 'country': 'Germany', + 'homepage': 'https://www.umweltbundesamt.de', + 'id': 1, + 'kind': 'government', + 'longname': 'Umweltbundesamt', + 'name': 'UBA', + 'postcode': '06844', + 'street_address': 'Wörlitzer Platz 1', + }, + }, + 'id': 2, + 'role': 'resource provider', + 'status': 'active', + }, + ], + 'sampling_frequency': 'hourly', + 'sampling_height': 7.0, + 'station': { + 'additional_metadata': {}, + 'aux_docs': [], + 'aux_images': [], + 'aux_urls': [], + 'changelog': [ + { + 'author_id': 1, + 'datetime': '2023-08-15T21:16:20.596545+00:00', + 'description': 'station created', + 'new_value': '', + 'old_value': '', + 'station_id': 3, + 'type_of_change': 'created', + }, + ], + 'codes': [ + 'China_test8', + ], + 'coordinate_validation_status': 'not checked', + 'coordinates': { + 'alt': 1534.0, + 'lat': 36.256, + 'lng': 117.106, + }, + 'country': 'China', + 'globalmeta': { + 'climatic_zone_year2016': '6 (warm temperate dry)', + 'distance_to_major_road_year2020': -999.0, + 'dominant_ecoregion_year2017': '-1 (undefined)', + 'dominant_landcover_year2012': '10 (Cropland, rainfed)', + 'ecoregion_description_25km_year2017': '', + 'htap_region_tier1_year2010': '10 (SAF Sub Saharan/sub Sahel Africa)', + 'landcover_description_25km_year2012': '', + 'max_population_density_25km_year1990': -1.0, + 'max_population_density_25km_year2015': -1.0, + 'max_stable_nightlights_25km_year1992': -999.0, + 'max_stable_nightlights_25km_year2013': -999.0, + 'max_topography_srtm_relative_alt_5km_year1994': -999.0, + 'mean_nox_emissions_10km_year2000': -999.0, + 'mean_nox_emissions_10km_year2015': -999.0, + 'mean_population_density_250m_year1990': -1.0, + 'mean_population_density_250m_year2015': -1.0, + 'mean_population_density_5km_year1990': -1.0, + 'mean_population_density_5km_year2015': -1.0, + 'mean_stable_nightlights_1km_year2013': -999.0, + 'mean_stable_nightlights_5km_year2013': -999.0, + 'mean_topography_srtm_alt_1km_year1994': -999.0, + 'mean_topography_srtm_alt_90m_year1994': -999.0, + 'min_topography_srtm_relative_alt_5km_year1994': -999.0, + 'stddev_topography_srtm_relative_alt_5km_year1994': -999.0, + 'toar1_category': 'unclassified', + 'toar2_category': 'suburban', + }, + 'id': 3, + 'name': 'Test_China', + 'state': 'Shandong Sheng', + 'timezone': 'Asia/Shanghai', + 'type': 'unknown', + 'type_of_area': 'unknown', + }, + 'variable': { + 'cf_standardname': 'mole_fraction_of_toluene_in_air', + 'chemical_formula': 'C7H8', + 'displayname': 'Toluene', + 'id': 7, + 'longname': 'toluene', + 'name': 'toluene', + 'units': 'nmol mol-1' }}] assert response.json() == expected_resp @@ -711,8 +1000,21 @@ class TestApps: 'Station name': 'Secret'} }, 'roles': {'role': 'resource provider', 'status': 'active', 'contact_id': 5} - } - ] + }, + {'id': 3, + 'order': 3, + 'additional_metadata': {}, + 'roles': {'role': 'resource provider', 'status': 'active', 'contact_id': 4} + }] + assert response.json() == expected_resp + + + def test_search_with_fields_unique_station_id(self, client, db): + response = client.get("/search/?fields=station_id") + expected_status_code = 200 + assert response.status_code == expected_status_code + expected_resp = [{"station": {"id": 2}}, + {"station": {"id": 3}}] assert response.json() == expected_resp @@ -799,6 +1101,63 @@ class TestApps: 'author_id': 1, 'type_of_change': 'created' }]}, + 'programme': {'id': 0, 'name': '', 'longname': '', 'homepage': '', 'description': ''}}, + {'id': 3, 'label': 'CMA', 'order': 3, + 'sampling_frequency': 'hourly', 'aggregation': 'mean', 'data_origin_type': 'measurement', + 'data_start_date': '2023-09-07T15:30:00+00:00', 'data_end_date': '2024-12-31T14:30:00+00:00', 'coverage': -1.0, + 'data_origin': 'instrument', 'sampling_height': 7.0, + 'provider_version': 'N/A', + 'doi': '', + 'additional_metadata': {}, + 'roles': [{'id': 2, 'role': 'resource provider', 'status': 'active', + 'contact': {'id': 4, 'organisation': {'id': 1, 'name': 'UBA', 'longname': 'Umweltbundesamt', + 'kind': 'government', 'city': 'Dessau-Roßlau', 'postcode': '06844', 'street_address': 'Wörlitzer Platz 1', + 'country': 'Germany', 'homepage': 'https://www.umweltbundesamt.de', 'contact_url': 'mailto:immission@uba.de'}}}], + 'variable': {'name': 'toluene', 'longname': 'toluene', 'displayname': 'Toluene', + 'cf_standardname': 'mole_fraction_of_toluene_in_air', 'units': 'nmol mol-1', + 'chemical_formula': 'C7H8', 'id': 7}, + 'station': {'id': 3, 'codes': [ 'China_test8' ], 'name': 'Test_China', + 'coordinates': { 'alt': 1534.0, 'lat': 36.256, 'lng': 117.106 }, + 'coordinate_validation_status': 'not checked', + 'country': 'China', 'state': 'Shandong Sheng', + 'type': 'unknown', 'type_of_area': 'unknown', + 'timezone': 'Asia/Shanghai', 'additional_metadata': {}, + 'aux_images': [], 'aux_docs': [], 'aux_urls': [], + 'globalmeta': { + 'climatic_zone_year2016': '6 (warm temperate dry)', + 'distance_to_major_road_year2020': -999.0, + 'dominant_ecoregion_year2017': '-1 (undefined)', + 'dominant_landcover_year2012': '10 (Cropland, rainfed)', + 'ecoregion_description_25km_year2017': '', + 'htap_region_tier1_year2010': '10 (SAF Sub Saharan/sub Sahel Africa)', + 'landcover_description_25km_year2012': '', + 'max_population_density_25km_year1990': -1.0, + 'max_population_density_25km_year2015': -1.0, + 'max_stable_nightlights_25km_year1992': -999.0, + 'max_stable_nightlights_25km_year2013': -999.0, + 'max_topography_srtm_relative_alt_5km_year1994': -999.0, + 'mean_nox_emissions_10km_year2000': -999.0, + 'mean_nox_emissions_10km_year2015': -999.0, + 'mean_population_density_250m_year1990': -1.0, + 'mean_population_density_250m_year2015': -1.0, + 'mean_population_density_5km_year1990': -1.0, + 'mean_population_density_5km_year2015': -1.0, + 'mean_stable_nightlights_1km_year2013': -999.0, + 'mean_stable_nightlights_5km_year2013': -999.0, + 'mean_topography_srtm_alt_1km_year1994': -999.0, + 'mean_topography_srtm_alt_90m_year1994': -999.0, + 'min_topography_srtm_relative_alt_5km_year1994': -999.0, + 'stddev_topography_srtm_relative_alt_5km_year1994': -999.0, + 'toar1_category': 'unclassified', + 'toar2_category': 'suburban'}, + 'changelog': [{'datetime': '2023-08-15T21:16:20.596545+00:00', + 'description': 'station created', + 'old_value': '', + 'new_value': '', + 'station_id': 3, + 'author_id': 1, + 'type_of_change': 'created' + }]}, 'programme': {'id': 0, 'name': '', 'longname': '', 'homepage': '', 'description': ''}}] assert response.json() == expected_resp @@ -869,6 +1228,63 @@ class TestApps: 'author_id': 1, 'type_of_change': 'created' }]}, + 'programme': {'id': 0, 'name': '', 'longname': '', 'homepage': '', 'description': ''}}, + {'id': 3, 'label': 'CMA', 'order': 3, + 'sampling_frequency': 'hourly', 'aggregation': 'mean', 'data_origin_type': 'measurement', + 'data_start_date': '2023-09-07T15:30:00+00:00', 'data_end_date': '2024-12-31T14:30:00+00:00', 'coverage': -1.0, + 'data_origin': 'instrument', 'sampling_height': 7.0, + 'provider_version': 'N/A', + 'doi': '', + 'additional_metadata': {}, + 'roles': [{'id': 2, 'role': 'resource provider', 'status': 'active', + 'contact': {'id': 4, 'organisation': {'id': 1, 'name': 'UBA', 'longname': 'Umweltbundesamt', + 'kind': 'government', 'city': 'Dessau-Roßlau', 'postcode': '06844', 'street_address': 'Wörlitzer Platz 1', + 'country': 'Germany', 'homepage': 'https://www.umweltbundesamt.de', 'contact_url': 'mailto:immission@uba.de'}}}], + 'variable': {'name': 'toluene', 'longname': 'toluene', 'displayname': 'Toluene', + 'cf_standardname': 'mole_fraction_of_toluene_in_air', 'units': 'nmol mol-1', + 'chemical_formula': 'C7H8', 'id': 7}, + 'station': {'id': 3, 'codes': [ 'China_test8' ], 'name': 'Test_China', + 'coordinates': { 'alt': 1534.0, 'lat': 36.256, 'lng': 117.106 }, + 'coordinate_validation_status': 'not checked', + 'country': 'China', 'state': 'Shandong Sheng', + 'type': 'unknown', 'type_of_area': 'unknown', + 'timezone': 'Asia/Shanghai', 'additional_metadata': {}, + 'aux_images': [], 'aux_docs': [], 'aux_urls': [], + 'globalmeta': { + 'climatic_zone_year2016': '6 (warm temperate dry)', + 'distance_to_major_road_year2020': -999.0, + 'dominant_ecoregion_year2017': '-1 (undefined)', + 'dominant_landcover_year2012': '10 (Cropland, rainfed)', + 'ecoregion_description_25km_year2017': '', + 'htap_region_tier1_year2010': '10 (SAF Sub Saharan/sub Sahel Africa)', + 'landcover_description_25km_year2012': '', + 'max_population_density_25km_year1990': -1.0, + 'max_population_density_25km_year2015': -1.0, + 'max_stable_nightlights_25km_year1992': -999.0, + 'max_stable_nightlights_25km_year2013': -999.0, + 'max_topography_srtm_relative_alt_5km_year1994': -999.0, + 'mean_nox_emissions_10km_year2000': -999.0, + 'mean_nox_emissions_10km_year2015': -999.0, + 'mean_population_density_250m_year1990': -1.0, + 'mean_population_density_250m_year2015': -1.0, + 'mean_population_density_5km_year1990': -1.0, + 'mean_population_density_5km_year2015': -1.0, + 'mean_stable_nightlights_1km_year2013': -999.0, + 'mean_stable_nightlights_5km_year2013': -999.0, + 'mean_topography_srtm_alt_1km_year1994': -999.0, + 'mean_topography_srtm_alt_90m_year1994': -999.0, + 'min_topography_srtm_relative_alt_5km_year1994': -999.0, + 'stddev_topography_srtm_relative_alt_5km_year1994': -999.0, + 'toar1_category': 'unclassified', + 'toar2_category': 'suburban'}, + 'changelog': [{'datetime': '2023-08-15T21:16:20.596545+00:00', + 'description': 'station created', + 'old_value': '', + 'new_value': '', + 'station_id': 3, + 'author_id': 1, + 'type_of_change': 'created' + }]}, 'programme': {'id': 0, 'name': '', 'longname': '', 'homepage': '', 'description': ''}}] assert response.json() == expected_resp @@ -939,6 +1355,63 @@ class TestApps: 'author_id': 1, 'type_of_change': 'created' }]}, + 'programme': {'id': 0, 'name': '', 'longname': '', 'homepage': '', 'description': ''}}, + {'id': 3, 'label': 'CMA', 'order': 3, + 'sampling_frequency': 'hourly', 'aggregation': 'mean', 'data_origin_type': 'measurement', + 'data_start_date': '2023-09-07T15:30:00+00:00', 'data_end_date': '2024-12-31T14:30:00+00:00', 'coverage': -1.0, + 'data_origin': 'instrument', 'sampling_height': 7.0, + 'provider_version': 'N/A', + 'doi': '', + 'additional_metadata': {}, + 'roles': [{'id': 2, 'role': 'resource provider', 'status': 'active', + 'contact': {'id': 4, 'organisation': {'id': 1, 'name': 'UBA', 'longname': 'Umweltbundesamt', + 'kind': 'government', 'city': 'Dessau-Roßlau', 'postcode': '06844', 'street_address': 'Wörlitzer Platz 1', + 'country': 'Germany', 'homepage': 'https://www.umweltbundesamt.de', 'contact_url': 'mailto:immission@uba.de'}}}], + 'variable': {'name': 'toluene', 'longname': 'toluene', 'displayname': 'Toluene', + 'cf_standardname': 'mole_fraction_of_toluene_in_air', 'units': 'nmol mol-1', + 'chemical_formula': 'C7H8', 'id': 7}, + 'station': {'id': 3, 'codes': [ 'China_test8' ], 'name': 'Test_China', + 'coordinates': { 'alt': 1534.0, 'lat': 36.256, 'lng': 117.106 }, + 'coordinate_validation_status': 'not checked', + 'country': 'China', 'state': 'Shandong Sheng', + 'type': 'unknown', 'type_of_area': 'unknown', + 'timezone': 'Asia/Shanghai', 'additional_metadata': {}, + 'aux_images': [], 'aux_docs': [], 'aux_urls': [], + 'globalmeta': { + 'climatic_zone_year2016': '6 (warm temperate dry)', + 'distance_to_major_road_year2020': -999.0, + 'dominant_ecoregion_year2017': '-1 (undefined)', + 'dominant_landcover_year2012': '10 (Cropland, rainfed)', + 'ecoregion_description_25km_year2017': '', + 'htap_region_tier1_year2010': '10 (SAF Sub Saharan/sub Sahel Africa)', + 'landcover_description_25km_year2012': '', + 'max_population_density_25km_year1990': -1.0, + 'max_population_density_25km_year2015': -1.0, + 'max_stable_nightlights_25km_year1992': -999.0, + 'max_stable_nightlights_25km_year2013': -999.0, + 'max_topography_srtm_relative_alt_5km_year1994': -999.0, + 'mean_nox_emissions_10km_year2000': -999.0, + 'mean_nox_emissions_10km_year2015': -999.0, + 'mean_population_density_250m_year1990': -1.0, + 'mean_population_density_250m_year2015': -1.0, + 'mean_population_density_5km_year1990': -1.0, + 'mean_population_density_5km_year2015': -1.0, + 'mean_stable_nightlights_1km_year2013': -999.0, + 'mean_stable_nightlights_5km_year2013': -999.0, + 'mean_topography_srtm_alt_1km_year1994': -999.0, + 'mean_topography_srtm_alt_90m_year1994': -999.0, + 'min_topography_srtm_relative_alt_5km_year1994': -999.0, + 'stddev_topography_srtm_relative_alt_5km_year1994': -999.0, + 'toar1_category': 'unclassified', + 'toar2_category': 'suburban'}, + 'changelog': [{'datetime': '2023-08-15T21:16:20.596545+00:00', + 'description': 'station created', + 'old_value': '', + 'new_value': '', + 'station_id': 3, + 'author_id': 1, + 'type_of_change': 'created' + }]}, 'programme': {'id': 0, 'name': '', 'longname': '', 'homepage': '', 'description': ''}}] assert response.json() == expected_resp diff --git a/tests/test_search_aggregations.py b/tests/test_search_aggregations.py index 7e2d7cea0d43336ceb7a9a3228b4bbe5cc05df86..c2fa4304b8413195fb25b9e3ada324a26fc6ffd6 100644 --- a/tests/test_search_aggregations.py +++ b/tests/test_search_aggregations.py @@ -372,9 +372,122 @@ class TestApps: 'street_address': 'Wilhelm-Johnen-Straße', 'country': 'Germany', 'homepage': 'https://www.fz-juelich.de', - 'contact_url': 'mailto:toar-data@fz-juelich.de'}}}]}] + 'contact_url': 'mailto:toar-data@fz-juelich.de'}}}]}, + {'id': 3, + 'additional_metadata': {}, + 'aggregation': 'mean', + 'coverage': -1.0, + 'data_end_date': '2024-12-31T14:30:00+00:00', + 'data_origin': 'instrument', + 'data_origin_type': 'measurement', + 'data_start_date': '2023-09-07T15:30:00+00:00', + 'doi': '', + 'label': 'CMA', + 'order': 3, + 'programme': { + 'description': '', + 'homepage': '', + 'id': 0, + 'longname': '', + 'name': '', + }, + 'provider_version': 'N/A', + 'roles': [ + { + 'contact': { + 'id': 4, + 'organisation': { + 'city': 'Dessau-Roßlau', + 'contact_url': 'mailto:immission@uba.de', + 'country': 'Germany', + 'homepage': 'https://www.umweltbundesamt.de', + 'id': 1, + 'kind': 'government', + 'longname': 'Umweltbundesamt', + 'name': 'UBA', + 'postcode': '06844', + 'street_address': 'Wörlitzer Platz 1', + }, + }, + 'id': 2, + 'role': 'resource provider', + 'status': 'active', + }, + ], + 'sampling_frequency': 'hourly', + 'sampling_height': 7.0, + 'station': { + 'additional_metadata': {}, + 'aux_docs': [], + 'aux_images': [], + 'aux_urls': [], + 'changelog': [ + { + 'author_id': 1, + 'datetime': '2023-08-15T21:16:20.596545+00:00', + 'description': 'station created', + 'new_value': '', + 'old_value': '', + 'station_id': 3, + 'type_of_change': 'created', + }, + ], + 'codes': [ + 'China_test8', + ], + 'coordinate_validation_status': 'not checked', + 'coordinates': { + 'alt': 1534.0, + 'lat': 36.256, + 'lng': 117.106, + }, + 'country': 'China', + 'globalmeta': { + 'climatic_zone_year2016': '6 (warm temperate dry)', + 'distance_to_major_road_year2020': -999.0, + 'dominant_ecoregion_year2017': '-1 (undefined)', + 'dominant_landcover_year2012': '10 (Cropland, rainfed)', + 'ecoregion_description_25km_year2017': '', + 'htap_region_tier1_year2010': '10 (SAF Sub Saharan/sub Sahel Africa)', + 'landcover_description_25km_year2012': '', + 'max_population_density_25km_year1990': -1.0, + 'max_population_density_25km_year2015': -1.0, + 'max_stable_nightlights_25km_year1992': -999.0, + 'max_stable_nightlights_25km_year2013': -999.0, + 'max_topography_srtm_relative_alt_5km_year1994': -999.0, + 'mean_nox_emissions_10km_year2000': -999.0, + 'mean_nox_emissions_10km_year2015': -999.0, + 'mean_population_density_250m_year1990': -1.0, + 'mean_population_density_250m_year2015': -1.0, + 'mean_population_density_5km_year1990': -1.0, + 'mean_population_density_5km_year2015': -1.0, + 'mean_stable_nightlights_1km_year2013': -999.0, + 'mean_stable_nightlights_5km_year2013': -999.0, + 'mean_topography_srtm_alt_1km_year1994': -999.0, + 'mean_topography_srtm_alt_90m_year1994': -999.0, + 'min_topography_srtm_relative_alt_5km_year1994': -999.0, + 'stddev_topography_srtm_relative_alt_5km_year1994': -999.0, + 'toar1_category': 'unclassified', + 'toar2_category': 'suburban', + }, + 'id': 3, + 'name': 'Test_China', + 'state': 'Shandong Sheng', + 'timezone': 'Asia/Shanghai', + 'type': 'unknown', + 'type_of_area': 'unknown', + }, + 'variable': { + 'cf_standardname': 'mole_fraction_of_toluene_in_air', + 'chemical_formula': 'C7H8', + 'displayname': 'Toluene', + 'id': 7, + 'longname': 'toluene', + 'name': 'toluene', + 'units': 'nmol mol-1' }}] assert response.json() == expected_resp + def test_search_single(self, client, db): response = client.get("/search/a?id=2") expected_status_code = 200 @@ -989,5 +1102,5 @@ class TestApps: response = client.get("/search/a?fields=id+fields=id") expected_status_code = 200 assert response.status_code == expected_status_code - expected_resp = [{"id": 1,}, {"id": 2}] + expected_resp = [{"id": 1,}, {"id": 2}, {"id": 3}] assert response.json() == expected_resp diff --git a/toardb/timeseries/crud.py b/toardb/timeseries/crud.py index cc5a0af3330e4b3eef0a2cc34c1f744093c8de60..e4476246236fc58d862f6bbd6e36d0bdcb732c2d 100644 --- a/toardb/timeseries/crud.py +++ b/toardb/timeseries/crud.py @@ -294,22 +294,38 @@ def search_all(db, path_params, query_params, lts=False): endpoint = "timeseries" if lts else "search" try: - return TimeseriesQuery.from_query_params(query_params, db, endpoint).adapt_objects(db) - + ts_list = TimeseriesQuery.from_query_params(query_params, db, endpoint).adapt_objects(db) + # remove duplicates + if ts_list and isinstance(ts_list[0], dict): + try: + ts_set = set(json.dumps(ts, sort_keys=True) for ts in ts_list) + return [json.loads(ts) for ts in ts_set] + except: # not correct, because duplicates are NOT removed!!! + return ts_list + else: + return ts_list except (KeyError, ValueError) as e: status_code = 400 return JSONResponse(status_code=status_code, content=str(e)) -def search_all_aggreagtion(db, path_params, signs, query_params_list, lts=False): +def search_all_aggregation(db, path_params, signs, query_params_list, lts=False): endpoint = "timeseries" if lts else "search" try: - return TimeseriesQuery.aggregate( + ts_list = TimeseriesQuery.aggregate( TimeseriesQuery.from_query_params(query_params, db, endpoint, sign) for sign, query_params in zip(signs, query_params_list) ).adapt_objects(db) - + # remove duplicates + if ts_list and isinstance(ts_list[0], dict): + try: + ts_set = set(json.dumps(ts, sort_keys=True) for ts in ts_list) + return [json.loads(ts) for ts in ts_set] + except: # not correct, because duplicates are NOT removed!!! + return ts_list + else: + return ts_list except (KeyError, ValueError) as e: status_code = 400 return JSONResponse(status_code=status_code, content=str(e)) diff --git a/toardb/timeseries/timeseries.py b/toardb/timeseries/timeseries.py index 84630ee4079b426283f1585131489f2b9ff4b442..7cc27d2d49666bee10157fa624894901ea8f0c9e 100644 --- a/toardb/timeseries/timeseries.py +++ b/toardb/timeseries/timeseries.py @@ -46,15 +46,16 @@ def search_all_timeseries(request: Request, db: Session = Depends(get_db)): updated_query_params = get_query_params(request.url.query) return crud.search_all(db, path_params=request.path_params, query_params=updated_query_params) -# Does not make sense when only certain fields are selected in diffrent requests needs diffrent syntax -# order of concatinated statmens is also unclear + +# Does not make sense when only certain fields are selected in different requests needs different syntax +# order of concatenated statements is also unclear @router.get('/search/a', response_model=List[schemas.Timeseries] | List[schemas.TimeseriesFields], response_model_exclude_none=True, response_model_exclude_unset=True) def search_all_timeseries_aggregations(request: Request, db: Session = Depends(get_db)): urls = re.split(r"(?=[+-]\D)", "+" + request.url.query)[1:] if urls: signs = [url.startswith("+") for url in urls] query_params = [get_query_params(url[1:]) for url in urls] - return crud.search_all_aggreagtion( + return crud.search_all_aggregation( db, path_params=request.path_params, signs=signs, query_params_list=query_params ) else: