From 0f1e40db95ddcd6af9e6bb1ca3b37bc4a524df6c Mon Sep 17 00:00:00 2001 From: Jacob Brown Date: Wed, 24 Sep 2025 10:26:21 -0600 Subject: [PATCH 1/3] WIP: first draft of thing_id query parameter for /sensor --- api/sensor.py | 9 +++++++-- tests/test_sensor.py | 27 +++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/api/sensor.py b/api/sensor.py index 33dbe5c97..8a2569915 100644 --- a/api/sensor.py +++ b/api/sensor.py @@ -26,7 +26,7 @@ editor_dependency, viewer_dependency, ) -from db import Observation, Sample, Sensor +from db import Observation, Sample, Sensor, FieldActivity, FieldEvent, Thing from schemas.sensor import SensorResponse, CreateSensor, UpdateSensor from services.crud_helper import model_patcher, model_deleter, model_adder from services.exceptions_helper import PydanticStyleException @@ -145,9 +145,14 @@ async def get_sensors( if observed_property is not None: conditions.append(Observation.observed_property == observed_property) + # TODO: update after Deployment table is implemented if thing_id is not None: + # Observation is joined for all filters joins.append(Sample) - conditions.append(Sample.thing_id == thing_id) + joins.append(FieldActivity) + joins.append(FieldEvent) + joins.append(Thing) + conditions.append(Thing.id == thing_id) if conditions: sql = sql.join(Observation) diff --git a/tests/test_sensor.py b/tests/test_sensor.py index 0c9e5aab9..bf724693b 100644 --- a/tests/test_sensor.py +++ b/tests/test_sensor.py @@ -161,6 +161,33 @@ def test_get_sensors(sensor): assert data["items"][0]["notes"] == sensor.notes +# TODO: update after Deployment table is implemented +def test_get_sensors_by_thing_id( + sensor, + water_chemistry_observation, + water_chemistry_sample, + water_chemistry_field_activity, + field_event, + water_well_thing, +): + response = client.get(f"/sensor?thing_id={water_well_thing.id}") + assert response.status_code == 200 + data = response.json() + assert data["total"] == 1 + assert data["items"][0]["id"] == sensor.id + assert data["items"][0]["created_at"] == sensor.created_at.isoformat().replace( + "+00:00", "Z" + ) + assert data["items"][0]["release_status"] == sensor.release_status + assert data["items"][0]["name"] == sensor.name + assert data["items"][0]["model"] == sensor.model + assert data["items"][0]["serial_no"] == sensor.serial_no + assert data["items"][0]["datetime_installed"] == sensor.datetime_installed + assert data["items"][0]["datetime_removed"] == sensor.datetime_removed + assert data["items"][0]["recording_interval"] == sensor.recording_interval + assert data["items"][0]["notes"] == sensor.notes + + def test_get_sensor_by_id(sensor): response = client.get(f"/sensor/{sensor.id}") assert response.status_code == 200 From 1e85d3c37dccfcf39286e859f7189c171a1cd524 Mon Sep 17 00:00:00 2001 From: Jacob Brown Date: Wed, 24 Sep 2025 14:01:18 -0600 Subject: [PATCH 2/3] fix: fix thing_id query parameter for /sensor --- api/sensor.py | 15 ++++++--------- core/lexicon.json | 3 +++ tests/conftest.py | 20 ++++++++++++++++++++ tests/test_sensor.py | 6 +----- 4 files changed, 30 insertions(+), 14 deletions(-) diff --git a/api/sensor.py b/api/sensor.py index 8a2569915..39dc12662 100644 --- a/api/sensor.py +++ b/api/sensor.py @@ -26,7 +26,7 @@ editor_dependency, viewer_dependency, ) -from db import Observation, Sample, Sensor, FieldActivity, FieldEvent, Thing +from db import Observation, Sensor, Deployment, Thing from schemas.sensor import SensorResponse, CreateSensor, UpdateSensor from services.crud_helper import model_patcher, model_deleter, model_adder from services.exceptions_helper import PydanticStyleException @@ -138,28 +138,25 @@ async def get_sensors( This endpoint is a placeholder and should be implemented with actual logic. """ sql = select(Sensor) - # TODO: a sensor is not yet related to observation, so this won't work at the moment if thing_id is not None or observed_property is not None: conditions = [] joins = [] if observed_property is not None: + joins.append(Observation) conditions.append(Observation.observed_property == observed_property) - # TODO: update after Deployment table is implemented if thing_id is not None: - # Observation is joined for all filters - joins.append(Sample) - joins.append(FieldActivity) - joins.append(FieldEvent) + joins.append(Deployment) joins.append(Thing) conditions.append(Thing.id == thing_id) - if conditions: - sql = sql.join(Observation) + if joins: for j in joins: sql = sql.join(j) + if conditions: sql = sql.where(and_(*conditions)) + print(sql) sql = order_sort_filter(sql, Sensor, sort=sort, order=order, filter_=filter_) return paginate(conn=session, query=sql) diff --git a/core/lexicon.json b/core/lexicon.json index 41826dcb4..14d2a1828 100644 --- a/core/lexicon.json +++ b/core/lexicon.json @@ -114,6 +114,9 @@ {"categories": [{"name": "unit", "description": null}], "term": "deg C", "definition": "degree Celsius"}, {"categories": [{"name": "unit", "description": null}], "term": "deg second", "definition": "degree second"}, {"categories": [{"name": "unit", "description": null}], "term": "deg minute", "definition": "degree minute"}, + {"categories": [{"name": "unit", "description": null}], "term": "second", "definition": "second"}, + {"categories": [{"name": "unit", "description": null}], "term": "minute", "definition": "minute"}, + {"categories": [{"name": "unit", "description": null}], "term": "hour", "definition": "hour"}, {"categories": [{"name": "observed_property", "description": null}], "term": "groundwater level", "definition": "groundwater level measurement" }, {"categories": [{"name": "observed_property", "description": null}], "term": "temperature", "definition": "Temperature measurement"}, diff --git a/tests/conftest.py b/tests/conftest.py index 250754c0a..fe0fe8f87 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -219,6 +219,26 @@ def second_sensor(): session.commit() +@pytest.fixture(scope="session") +def sensor_to_water_well_thing_deployment(sensor, water_well_thing): + with session_ctx() as session: + deployment = Deployment( + sensor_id=sensor.id, + thing_id=water_well_thing.id, + installation_date="2023-01-01", + removal_date=None, + recording_interval=24, + recording_interval_units="hour", + hanging_cable_length=10, + hanging_point_height=0, + hanging_point_description="hang 10", + notes="deployment fixture", + ) + session.add(deployment) + session.commit() + yield deployment + + @pytest.fixture(scope="session") def contact(water_well_thing): with session_ctx() as session: diff --git a/tests/test_sensor.py b/tests/test_sensor.py index bf724693b..4ff87c80f 100644 --- a/tests/test_sensor.py +++ b/tests/test_sensor.py @@ -161,13 +161,9 @@ def test_get_sensors(sensor): assert data["items"][0]["notes"] == sensor.notes -# TODO: update after Deployment table is implemented def test_get_sensors_by_thing_id( sensor, - water_chemistry_observation, - water_chemistry_sample, - water_chemistry_field_activity, - field_event, + sensor_to_water_well_thing_deployment, water_well_thing, ): response = client.get(f"/sensor?thing_id={water_well_thing.id}") From ecf29692852ccb24e6411b7bd3ccb437608d619a Mon Sep 17 00:00:00 2001 From: Jacob Brown Date: Wed, 24 Sep 2025 14:07:53 -0600 Subject: [PATCH 3/3] refactor: remove print debugging statement --- api/sensor.py | 1 - 1 file changed, 1 deletion(-) diff --git a/api/sensor.py b/api/sensor.py index 39dc12662..92360a4d1 100644 --- a/api/sensor.py +++ b/api/sensor.py @@ -156,7 +156,6 @@ async def get_sensors( if conditions: sql = sql.where(and_(*conditions)) - print(sql) sql = order_sort_filter(sql, Sensor, sort=sort, order=order, filter_=filter_) return paginate(conn=session, query=sql)