-
Notifications
You must be signed in to change notification settings - Fork 4
feat: fix water elevation units to feet in materialized view and update related tests #590
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,122 @@ | ||
| """fix water elevation units to feet | ||
|
|
||
| Revision ID: n7a8b9c0d1e2 | ||
| Revises: m6f7a8b9c0d1 | ||
| Create Date: 2026-03-10 11:10:00.000000 | ||
| """ | ||
|
|
||
| from typing import Sequence, Union | ||
|
|
||
| from alembic import op | ||
| from sqlalchemy import inspect, text | ||
|
|
||
| # revision identifiers, used by Alembic. | ||
| revision: str = "n7a8b9c0d1e2" | ||
| down_revision: Union[str, Sequence[str], None] = "m6f7a8b9c0d1" | ||
| branch_labels: Union[str, Sequence[str], None] = None | ||
| depends_on: Union[str, Sequence[str], None] = None | ||
|
|
||
| METERS_TO_FEET = 3.28084 | ||
|
|
||
| LATEST_LOCATION_CTE = """ | ||
| SELECT DISTINCT ON (lta.thing_id) | ||
| lta.thing_id, | ||
| lta.location_id, | ||
| lta.effective_start | ||
| FROM location_thing_association AS lta | ||
| WHERE lta.effective_end IS NULL | ||
| ORDER BY lta.thing_id, lta.effective_start DESC | ||
| """.strip() | ||
|
|
||
|
|
||
| def _create_water_elevation_view() -> str: | ||
| return f""" | ||
| CREATE MATERIALIZED VIEW ogc_water_elevation_wells AS | ||
| WITH latest_location AS ( | ||
| {LATEST_LOCATION_CTE} | ||
| ), | ||
| ranked_obs AS ( | ||
| SELECT | ||
| fe.thing_id, | ||
| o.id AS observation_id, | ||
| o.observation_datetime, | ||
| (o.value - COALESCE(o.measuring_point_height, 0)) | ||
| AS depth_to_water_below_ground_surface | ||
| FROM observation AS o | ||
| JOIN sample AS s ON s.id = o.sample_id | ||
| JOIN field_activity AS fa ON fa.id = s.field_activity_id | ||
| JOIN field_event AS fe ON fe.id = fa.field_event_id | ||
| JOIN thing AS t ON t.id = fe.thing_id | ||
| WHERE | ||
| t.thing_type = 'water well' | ||
| AND fa.activity_type = 'groundwater level' | ||
| AND o.value IS NOT NULL | ||
| AND o.observation_datetime IS NOT NULL | ||
| ), | ||
| latest_obs AS ( | ||
| SELECT | ||
| ro.*, | ||
| ROW_NUMBER() OVER ( | ||
| PARTITION BY ro.thing_id | ||
| ORDER BY ro.observation_datetime DESC, ro.observation_id DESC | ||
| ) AS rn | ||
| FROM ranked_obs AS ro | ||
| ) | ||
| SELECT | ||
| t.id AS id, | ||
| t.name, | ||
| t.thing_type, | ||
| lo.observation_id, | ||
| lo.observation_datetime, | ||
| l.elevation, | ||
| lo.depth_to_water_below_ground_surface, | ||
| ((l.elevation * {METERS_TO_FEET}) - lo.depth_to_water_below_ground_surface) | ||
| AS water_elevation, | ||
jirhiker marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| l.point | ||
| FROM latest_obs AS lo | ||
| JOIN thing AS t ON t.id = lo.thing_id | ||
| JOIN latest_location AS ll ON ll.thing_id = t.id | ||
| JOIN location AS l ON l.id = ll.location_id | ||
| WHERE lo.rn = 1 | ||
| """ | ||
|
|
||
|
|
||
| def upgrade() -> None: | ||
| bind = op.get_bind() | ||
| inspector = inspect(bind) | ||
| existing_tables = set(inspector.get_table_names(schema="public")) | ||
| required_tables = { | ||
| "thing", | ||
| "location", | ||
| "location_thing_association", | ||
| "observation", | ||
| "sample", | ||
| "field_activity", | ||
| "field_event", | ||
| } | ||
|
|
||
| if not required_tables.issubset(existing_tables): | ||
| missing = sorted(t for t in required_tables if t not in existing_tables) | ||
| raise RuntimeError( | ||
| "Cannot create ogc_water_elevation_wells. Missing required tables: " | ||
| + ", ".join(missing) | ||
| ) | ||
|
|
||
| op.execute(text("DROP MATERIALIZED VIEW IF EXISTS ogc_water_elevation_wells")) | ||
| op.execute(text(_create_water_elevation_view())) | ||
| op.execute( | ||
| text( | ||
| "COMMENT ON MATERIALIZED VIEW ogc_water_elevation_wells IS " | ||
| "'Latest water elevation per well in feet; computed as (elevation_m * 3.28084) - depth_to_water_below_ground_surface_ft.'" | ||
| ) | ||
| ) | ||
| op.execute( | ||
| text( | ||
| "CREATE UNIQUE INDEX ux_ogc_water_elevation_wells_id " | ||
| "ON ogc_water_elevation_wells (id)" | ||
| ) | ||
| ) | ||
|
|
||
|
|
||
| def downgrade() -> None: | ||
| op.execute(text("DROP MATERIALIZED VIEW IF EXISTS ogc_water_elevation_wells")) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The migration's Useful? React with 👍 / 👎.
Comment on lines
+121
to
+122
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In
_create_water_elevation_view,water_elevationnow convertsl.elevationto feet but subtractsdepth_to_water_below_ground_surfacewithout unit normalization, so any groundwater observation stored in meters (o.unit = 'm') will produce a mixed-unit result (feet minus meters) and an incorrect elevation. This regression is user-impacting wherever groundwater-level records are not already in feet, so the expression should convert depth based ono.unit(or explicitly constrain to feet-only data).Useful? React with 👍 / 👎.