From f6b8ea54ffba1136c774253ac9452ab1ef2a8ac5 Mon Sep 17 00:00:00 2001 From: Kimball Bighorse Date: Wed, 14 Jan 2026 11:19:31 -0800 Subject: [PATCH] fix: change NMAMinorTraceChemistry volume from Float to Integer Update volume field type to match source database schema (NM_Aquifer_Dev_DB). Changes: - Update model type in db/nma_legacy.py - Add _safe_int() helper in transfer script - Update tests to use integer values - Add Alembic migration to alter column type Closes #379 Co-Authored-By: Claude Opus 4.5 --- ...c7d8e9_change_minor_trace_volume_to_int.py | 43 +++++++++++++++++++ db/nma_legacy.py | 2 +- tests/test_nma_chemistry_lineage.py | 4 +- transfers/minor_trace_chemistry_transfer.py | 9 +++- 4 files changed, 54 insertions(+), 4 deletions(-) create mode 100644 alembic/versions/g4a5b6c7d8e9_change_minor_trace_volume_to_int.py diff --git a/alembic/versions/g4a5b6c7d8e9_change_minor_trace_volume_to_int.py b/alembic/versions/g4a5b6c7d8e9_change_minor_trace_volume_to_int.py new file mode 100644 index 00000000..037f562b --- /dev/null +++ b/alembic/versions/g4a5b6c7d8e9_change_minor_trace_volume_to_int.py @@ -0,0 +1,43 @@ +"""change NMA_MinorTraceChemistry volume from Float to Integer + +Revision ID: g4a5b6c7d8e9 +Revises: f3b4c5d6e7f8 +Create Date: 2026-01-14 12:00:00.000000 + +This migration changes the volume column in NMA_MinorTraceChemistry from Float to Integer +to match the source database schema (NM_Aquifer_Dev_DB). +""" + +from typing import Sequence, Union + +from alembic import op +import sqlalchemy as sa + + +revision: str = "g4a5b6c7d8e9" +down_revision: Union[str, Sequence[str], None] = "f3b4c5d6e7f8" +branch_labels: Union[str, Sequence[str], None] = None +depends_on: Union[str, Sequence[str], None] = None + + +def upgrade() -> None: + """Change volume column from Float to Integer.""" + op.alter_column( + "NMA_MinorTraceChemistry", + "volume", + existing_type=sa.Float(), + type_=sa.Integer(), + existing_nullable=True, + postgresql_using="volume::integer", + ) + + +def downgrade() -> None: + """Revert volume column from Integer back to Float.""" + op.alter_column( + "NMA_MinorTraceChemistry", + "volume", + existing_type=sa.Integer(), + type_=sa.Float(), + existing_nullable=True, + ) diff --git a/db/nma_legacy.py b/db/nma_legacy.py index 07ca6efa..45ebbf5f 100644 --- a/db/nma_legacy.py +++ b/db/nma_legacy.py @@ -375,7 +375,7 @@ class NMAMinorTraceChemistry(Base): notes: Mapped[Optional[str]] = mapped_column(Text) analyses_agency: Mapped[Optional[str]] = mapped_column(String(100)) uncertainty: Mapped[Optional[float]] = mapped_column(Float) - volume: Mapped[Optional[float]] = mapped_column(Float) + volume: Mapped[Optional[int]] = mapped_column(Integer) volume_unit: Mapped[Optional[str]] = mapped_column(String(20)) # --- Relationships --- diff --git a/tests/test_nma_chemistry_lineage.py b/tests/test_nma_chemistry_lineage.py index b58edb91..b1e712b6 100644 --- a/tests/test_nma_chemistry_lineage.py +++ b/tests/test_nma_chemistry_lineage.py @@ -155,7 +155,7 @@ def test_nma_minor_trace_chemistry_save_all_columns(shared_well): notes="Test measurement", analyses_agency="NMBGMR", uncertainty=0.002, - volume=500.0, + volume=500, volume_unit="mL", ) session.add(mtc) @@ -174,7 +174,7 @@ def test_nma_minor_trace_chemistry_save_all_columns(shared_well): assert mtc.notes == "Test measurement" assert mtc.analyses_agency == "NMBGMR" assert mtc.uncertainty == 0.002 - assert mtc.volume == 500.0 + assert mtc.volume == 500 assert mtc.volume_unit == "mL" session.delete(sample_info) diff --git a/transfers/minor_trace_chemistry_transfer.py b/transfers/minor_trace_chemistry_transfer.py index d89a20c9..b23d3bf5 100644 --- a/transfers/minor_trace_chemistry_transfer.py +++ b/transfers/minor_trace_chemistry_transfer.py @@ -185,7 +185,7 @@ def _row_to_dict(self, row) -> Optional[dict[str, Any]]: "notes": self._safe_str(row, "Notes"), "analyses_agency": self._safe_str(row, "AnalysesAgency"), "uncertainty": self._safe_float(row, "Uncertainty"), - "volume": self._safe_float(row, "Volume"), + "volume": self._safe_int(row, "Volume"), "volume_unit": self._safe_str(row, "VolumeUnit"), } @@ -225,6 +225,13 @@ def _safe_float(self, row, attr: str) -> Optional[float]: return None return float(val) + def _safe_int(self, row, attr: str) -> Optional[int]: + """Safely get an int value, returning None for NaN.""" + val = getattr(row, attr, None) + if val is None or pd.isna(val): + return None + return int(val) + def _parse_date(self, row, attr: str) -> Optional[date]: """Parse a date value from the row.""" val = getattr(row, attr, None)