Skip to content

Commit 4f46bb7

Browse files
committed
refactor: use <observation class>:<observed_property> in observed property
1 parent 0df0815 commit 4f46bb7

6 files changed

Lines changed: 69 additions & 57 deletions

File tree

api/observation.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -177,12 +177,11 @@ def get_observations(
177177
sql = sql.where(Observation.observation_datetime <= end_time)
178178

179179
if observation_class == "groundwater level":
180-
sql = sql.where(Observation.observed_property == "groundwater level")
180+
sql = sql.where(Observation.observed_property.like("groundwater level:%"))
181181
elif observation_class == "water chemistry":
182-
sql = sql.where(Observation.observed_property != "groundwater level")
183-
sql = sql.where(Observation.observed_property != "temperature")
182+
sql = sql.where(Observation.observed_property.like("water chemistry:%"))
184183
elif observation_class == "geothermal":
185-
sql = sql.where(Observation.observed_property == "temperature")
184+
sql = sql.where(Observation.observed_property.like("geothermal:%"))
186185

187186
sql = order_sort_filter(sql, Observation, sort, order, filter_)
188187

core/lexicon.json

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,12 @@
1313
{"category": "unit", "term": "m²/s", "definition": "square meters per second"},
1414
{"category": "unit", "term": "deg C", "definition": "degree Celsius"},
1515

16-
{"category": "observed_property", "term": "groundwater level", "definition": "groundwater level measurement" },
16+
{"category": "observed_property", "term": "groundwater level:groundwater level", "definition": "groundwater level measurement" },
1717

18-
{"category": "observed_property", "term": "temperature", "definition": "Temperature measurement"},
19-
20-
{"category": "observed_property", "term": "pH", "definition": "pH"},
21-
{"category": "observed_property", "term": "Alkalinity as CaCO3", "definition": "Alkalinity as CaCO3"},
18+
{"category": "observed_property", "term": "geothermal:temperature", "definition": "Temperature measurement"},
19+
20+
{"category": "observed_property", "term": "water chemistry:pH", "definition": "pH"},
21+
{"category": "observed_property", "term": "water chemistry:Alkalinity as CaCO3", "definition": "Alkalinity as CaCO3"},
2222

2323

2424

schemas/observation.py

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@
3636

3737

3838
class ValidateObservation(BaseModel):
39-
39+
_observation_class: str
40+
observed_property: str
4041
observation_datetime: AwareDatetime
4142

4243
@field_validator("observation_datetime", check_fields=False)
@@ -54,6 +55,16 @@ def convert_observation_datetime_to_utc(
5455
return observation_datetime.astimezone(timezone.utc)
5556
return observation_datetime
5657

58+
@model_validator(mode="after")
59+
def prepend_observed_property(self: Self) -> Self:
60+
observed_property = self.observed_property
61+
observation_class = self._observation_class
62+
if observed_property is not None:
63+
observation_class = self._observation_class
64+
if not observed_property.startswith(f"{observation_class}:"):
65+
self.observed_property = f"{observation_class}:{observed_property}"
66+
return self
67+
5768

5869
# -------- CREATE ----------
5970
class CreateBaseObservation(ValidateObservation):
@@ -67,15 +78,17 @@ class CreateBaseObservation(ValidateObservation):
6778

6879

6980
class CreateGroundwaterLevelObservation(CreateBaseObservation):
81+
_observation_class: str = "groundwater level"
7082
measuring_point_height: float
7183
level_status: str
7284

7385

7486
class CreateWaterChemistryObservation(CreateBaseObservation):
75-
pass
87+
_observation_class: str = "water chemistry"
7688

7789

7890
class CreateGeothermalObservation(CreateBaseObservation):
91+
_observation_class: str = "geothermal"
7992
observation_depth: float
8093

8194

@@ -93,15 +106,17 @@ class UpdateBaseObservation(ValidateObservation):
93106

94107

95108
class UpdateGroundwaterLevelObservation(UpdateBaseObservation):
109+
_observation_class: str = "groundwater level"
96110
measuring_point_height: float | None = None
97111
level_status: str | None = None
98112

99113

100114
class UpdateWaterChemistryObservation(UpdateBaseObservation):
101-
pass
115+
_observation_class: str = "water chemistry"
102116

103117

104118
class UpdateGeothermalObservation(UpdateBaseObservation):
119+
_observation_class: str = "geothermal"
105120
observation_depth: float | None = None
106121

107122

@@ -115,6 +130,11 @@ class BaseObservationResponse(ORMBaseModel):
115130
value: float | None
116131
unit: str
117132

133+
@field_validator("observed_property")
134+
def remove_observed_property_prefix(cls, v: str) -> str:
135+
colon_index = v.find(":")
136+
return v[colon_index + 1 :]
137+
118138

119139
class GroundwaterLevelObservationResponse(BaseObservationResponse):
120140
depth_to_water_bgs: float | None

services/observation_helper.py

Lines changed: 4 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -6,35 +6,15 @@
66
from services.exceptions_helper import PydanticStyleException
77
from services.query_helper import simple_get_by_id
88

9-
observation_class_to_observed_properties = {
10-
"groundwater level": ["groundwater level"],
11-
"geothermal": ["temperature"],
12-
"water chemistry": ["pH", "Alkalinity as CaCO3"],
13-
}
14-
15-
observation_property_to_class = {}
16-
for key, value in observation_class_to_observed_properties.items():
17-
for prop in value:
18-
observation_property_to_class[prop] = key
19-
209

2110
def verify_observed_property_corresponds_with_observation_class(
2211
observation: Observation, observation_class: str
23-
) -> None:
24-
"""
25-
Verify that the observed property of the retrieved Observation corresponds
26-
with the observation class as defined by the path
27-
(e.g. /observation/water-chemistry). Raise an error if they do not
28-
correspond.
29-
"""
12+
):
3013
observed_property = observation.observed_property
14+
colon_index = observed_property.find(":")
15+
actual_observation_class = observed_property[:colon_index]
3116

32-
if (
33-
observed_property
34-
not in observation_class_to_observed_properties[observation_class]
35-
):
36-
actual_observation_class = observation_property_to_class[observed_property]
37-
17+
if actual_observation_class != observation_class:
3818
raise PydanticStyleException(
3919
status_code=HTTP_404_NOT_FOUND,
4020
detail=[

tests/conftest.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ def groundwater_level_observation(sensor, sample):
175175
observation_datetime="2025-01-01T00:04:00Z",
176176
sample_id=sample.id,
177177
sensor_id=sensor.id,
178-
observed_property="groundwater level",
178+
observed_property="groundwater level:groundwater level",
179179
release_status="draft",
180180
value=10.0,
181181
unit="ft",
@@ -196,7 +196,7 @@ def water_chemistry_observation(sensor, sample):
196196
observation_datetime="2025-01-01T00:03:00Z",
197197
sample_id=sample.id,
198198
sensor_id=sensor.id,
199-
observed_property="pH",
199+
observed_property="water chemistry:pH",
200200
release_status="draft",
201201
value=4.0,
202202
unit="dimensionless",
@@ -215,7 +215,7 @@ def geothermal_observation(sensor, sample):
215215
observation_datetime="2025-01-01T00:02:00Z",
216216
sample_id=sample.id,
217217
sensor_id=sensor.id,
218-
observed_property="temperature",
218+
observed_property="geothermal:temperature",
219219
release_status="draft",
220220
value=20.0,
221221
unit="deg C",

tests/test_observation.py

Lines changed: 31 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ def observation_to_delete(sample, sensor):
4949
observation_datetime="2019-01-01T00:03:00Z",
5050
sample_id=sample.id,
5151
sensor_id=sensor.id,
52-
observed_property="pH",
52+
observed_property="water chemistry:pH",
5353
release_status="draft",
5454
value=4.0,
5555
unit="dimensionless",
@@ -182,7 +182,7 @@ def test_patch_groundwater_level_observation_404_wrong_observation_class(
182182
assert response.status_code == 404
183183
data = response.json()
184184

185-
if obs.observed_property == "temperature":
185+
if obs.observed_property == "geothermal:temperature":
186186
observation_class = "geothermal"
187187
else:
188188
observation_class = "water chemistry"
@@ -225,7 +225,7 @@ def test_patch_water_chemistry_observation_404_wrong_observation_class(
225225
assert response.status_code == 404
226226
data = response.json()
227227

228-
if obs.observed_property == "temperature":
228+
if obs.observed_property == "geothermal:temperature":
229229
observation_class = "geothermal"
230230
else:
231231
observation_class = "groundwater level"
@@ -266,7 +266,7 @@ def test_patch_geothermal_observation_404_wrong_observation_class(
266266
assert response.status_code == 404
267267
data = response.json()
268268

269-
if obs.observed_property == "groundwater level":
269+
if obs.observed_property == "groundwater level:groundwater level":
270270
observation_class = "groundwater level"
271271
else:
272272
observation_class = "water chemistry"
@@ -305,10 +305,10 @@ def test_get_observation_by_id(
305305
data = response.json()
306306

307307
assert data["id"] == obs.id
308-
if obs.observed_property == "groundwater level":
308+
if obs.observed_property == "groundwater level:groundwater level":
309309
assert data["depth_to_water_bgs"] == obs.value - obs.measuring_point_height
310310
assert data["observation_depth"] is None
311-
elif obs.observed_property == "temperature":
311+
elif obs.observed_property == "geothermal:temperature":
312312
assert data["depth_to_water_bgs"] is None
313313
assert data["observation_depth"] == obs.observation_depth
314314
else:
@@ -340,9 +340,10 @@ def test_get_groundwater_level_observations(
340340
data["items"][0]["observation_datetime"]
341341
== groundwater_level_observation.observation_datetime
342342
)
343+
colon_index = groundwater_level_observation.observed_property.find(":")
343344
assert (
344345
data["items"][0]["observed_property"]
345-
== groundwater_level_observation.observed_property
346+
== groundwater_level_observation.observed_property[colon_index + 1 :]
346347
)
347348
assert (
348349
data["items"][0]["release_status"]
@@ -380,7 +381,11 @@ def test_get_groundwater_level_observation_by_id(groundwater_level_observation):
380381
data["observation_datetime"]
381382
== groundwater_level_observation.observation_datetime
382383
)
383-
assert data["observed_property"] == groundwater_level_observation.observed_property
384+
colon_index = groundwater_level_observation.observed_property.find(":")
385+
assert (
386+
data["observed_property"]
387+
== groundwater_level_observation.observed_property[colon_index + 1 :]
388+
)
384389
assert data["release_status"] == groundwater_level_observation.release_status
385390
assert data["level_status"] == groundwater_level_observation.level_status
386391
assert data["value"] == groundwater_level_observation.value
@@ -416,7 +421,7 @@ def test_get_groundwater_level_observation_by_id_404_wrong_observation_class(
416421
assert response.status_code == 404
417422
data = response.json()
418423

419-
if obs.observed_property == "temperature":
424+
if obs.observed_property == "geothermal:temperature":
420425
actual_observation_class = "geothermal"
421426
else:
422427
actual_observation_class = "water chemistry"
@@ -512,9 +517,10 @@ def test_get_water_chemistry_observations(water_chemistry_observation):
512517
data["items"][0]["observation_datetime"]
513518
== water_chemistry_observation.observation_datetime
514519
)
520+
colon_index = water_chemistry_observation.observed_property.find(":")
515521
assert (
516522
data["items"][0]["observed_property"]
517-
== water_chemistry_observation.observed_property
523+
== water_chemistry_observation.observed_property[colon_index + 1 :]
518524
)
519525
assert data["items"][0]["value"] == water_chemistry_observation.value
520526
assert data["items"][0]["unit"] == water_chemistry_observation.unit
@@ -535,7 +541,11 @@ def test_get_water_chemistry_observation_by_id(water_chemistry_observation):
535541
assert (
536542
data["observation_datetime"] == water_chemistry_observation.observation_datetime
537543
)
538-
assert data["observed_property"] == water_chemistry_observation.observed_property
544+
colon_index = water_chemistry_observation.observed_property.find(":")
545+
assert (
546+
data["observed_property"]
547+
== water_chemistry_observation.observed_property[colon_index + 1 :]
548+
)
539549
assert data["value"] == water_chemistry_observation.value
540550
assert data["unit"] == water_chemistry_observation.unit
541551

@@ -558,12 +568,10 @@ def test_get_water_chemistry_observation_by_id_404_wrong_observation_class(
558568
assert response.status_code == 404
559569
data = response.json()
560570

561-
if obs.observed_property == "groundwater level":
571+
if obs.observed_property == "groundwater level:groundwater level":
562572
actual_observation_class = "groundwater level"
563-
elif obs.observed_property == "temperature":
564-
actual_observation_class = "geothermal"
565573
else:
566-
url = f"/observation/water-chemistry/{obs.id}"
574+
actual_observation_class = "geothermal"
567575

568576
assert (
569577
data["detail"][0]["msg"]
@@ -586,9 +594,10 @@ def test_get_geothermal_observations(geothermal_observation):
586594
data["items"][0]["observation_datetime"]
587595
== geothermal_observation.observation_datetime
588596
)
597+
colon_index = geothermal_observation.observed_property.find(":")
589598
assert (
590599
data["items"][0]["observed_property"]
591-
== geothermal_observation.observed_property
600+
== geothermal_observation.observed_property[colon_index + 1 :]
592601
)
593602
assert data["items"][0]["value"] == geothermal_observation.value
594603
assert data["items"][0]["unit"] == geothermal_observation.unit
@@ -609,7 +618,11 @@ def test_get_geothermal_observation_by_id(geothermal_observation):
609618
assert data["sample_id"] == geothermal_observation.sample_id
610619
assert data["sensor_id"] == geothermal_observation.sensor_id
611620
assert data["observation_datetime"] == geothermal_observation.observation_datetime
612-
assert data["observed_property"] == geothermal_observation.observed_property
621+
colon_index = geothermal_observation.observed_property.find(":")
622+
assert (
623+
data["observed_property"]
624+
== geothermal_observation.observed_property[colon_index + 1 :]
625+
)
613626
assert data["value"] == geothermal_observation.value
614627
assert data["unit"] == geothermal_observation.unit
615628
assert data["observation_depth"] == geothermal_observation.observation_depth
@@ -631,7 +644,7 @@ def test_get_geothermal_observation_by_id_404_wrong_observation_class(
631644
assert response.status_code == 404
632645
data = response.json()
633646

634-
if obs.observed_property == "groundwater level":
647+
if obs.observed_property == "groundwater level:groundwater level":
635648
actual_observation_class = "groundwater level"
636649
else:
637650
actual_observation_class = "water chemistry"

0 commit comments

Comments
 (0)