From 5783e6d4a13a4a5f6e4ee27f5209b74ed944727c Mon Sep 17 00:00:00 2001 From: Kelsey Smuczynski Date: Fri, 6 Feb 2026 11:30:02 -0700 Subject: [PATCH 1/6] fix(test): update tests to stop using `thing_id` and to validate the real FK/relationship on `chemistry_sample_info_id` --- tests/test_radionuclides_legacy.py | 26 +++++++------------------- 1 file changed, 7 insertions(+), 19 deletions(-) diff --git a/tests/test_radionuclides_legacy.py b/tests/test_radionuclides_legacy.py index 68fd1d193..b1e88c64b 100644 --- a/tests/test_radionuclides_legacy.py +++ b/tests/test_radionuclides_legacy.py @@ -54,7 +54,6 @@ def test_create_radionuclides_all_fields(water_well_thing): record = NMA_Radionuclides( nma_global_id=uuid4(), - thing_id=water_well_thing.id, chemistry_sample_info_id=sample_info.id, nma_sample_pt_id=sample_info.nma_sample_pt_id, nma_sample_point_id=sample_info.nma_sample_point_id, @@ -103,7 +102,6 @@ def test_create_radionuclides_minimal(water_well_thing): record = NMA_Radionuclides( nma_global_id=uuid4(), - thing_id=water_well_thing.id, chemistry_sample_info_id=sample_info.id, ) session.add(record) @@ -136,7 +134,6 @@ def test_read_radionuclides_by_id(water_well_thing): record = NMA_Radionuclides( nma_global_id=uuid4(), - thing_id=water_well_thing.id, chemistry_sample_info_id=sample_info.id, ) session.add(record) @@ -166,13 +163,11 @@ def test_query_radionuclides_by_nma_sample_point_id(water_well_thing): record1 = NMA_Radionuclides( nma_global_id=uuid4(), - thing_id=water_well_thing.id, chemistry_sample_info_id=sample_info.id, nma_sample_point_id=sample_info.nma_sample_point_id, ) record2 = NMA_Radionuclides( nma_global_id=uuid4(), - thing_id=water_well_thing.id, chemistry_sample_info_id=sample_info.id, nma_sample_point_id="OTHER-PT", ) @@ -212,7 +207,6 @@ def test_update_radionuclides(water_well_thing): record = NMA_Radionuclides( nma_global_id=uuid4(), - thing_id=water_well_thing.id, chemistry_sample_info_id=sample_info.id, ) session.add(record) @@ -246,7 +240,6 @@ def test_delete_radionuclides(water_well_thing): record = NMA_Radionuclides( nma_global_id=uuid4(), - thing_id=water_well_thing.id, chemistry_sample_info_id=sample_info.id, ) session.add(record) @@ -269,7 +262,6 @@ def test_radionuclides_has_all_migrated_columns(): expected_columns = [ "id", "nma_global_id", - "thing_id", "chemistry_sample_info_id", "nma_sample_pt_id", "nma_sample_point_id", @@ -303,22 +295,19 @@ def test_radionuclides_table_name(): def test_radionuclides_fk_has_cascade(): - """NMA_Radionuclides.thing_id FK has ondelete=CASCADE.""" - col = NMA_Radionuclides.__table__.c.thing_id + """NMA_Radionuclides.chemistry_sample_info_id FK has ondelete=CASCADE.""" + col = NMA_Radionuclides.__table__.c.chemistry_sample_info_id fk = list(col.foreign_keys)[0] assert fk.ondelete == "CASCADE" -def test_radionuclides_back_populates_thing(water_well_thing): - """NMA_Radionuclides.thing navigates back to Thing.""" +def test_radionuclides_back_populates_sample_info(water_well_thing): + """NMA_Radionuclides.chemistry_sample_info navigates back to sample info.""" with session_ctx() as session: - well = session.merge(water_well_thing) - - # Radionuclides requires a chemistry_sample_info (which FKs to Thing) sample_info = NMA_Chemistry_SampleInfo( nma_sample_pt_id=uuid4(), nma_sample_point_id=_next_sample_point_id(), - thing_id=well.id, + thing_id=water_well_thing.id, ) session.add(sample_info) session.commit() @@ -327,14 +316,13 @@ def test_radionuclides_back_populates_thing(water_well_thing): record = NMA_Radionuclides( nma_global_id=uuid4(), chemistry_sample_info_id=sample_info.id, - thing_id=well.id, ) session.add(record) session.commit() session.refresh(record) - assert record.thing is not None - assert record.thing.id == well.id + assert record.chemistry_sample_info is not None + assert record.chemistry_sample_info.id == sample_info.id session.delete(record) session.delete(sample_info) From 775b94910e5cef94a56f17eb6f3ad61a9a67d49d Mon Sep 17 00:00:00 2001 From: Kelsey Smuczynski Date: Fri, 6 Feb 2026 11:42:27 -0700 Subject: [PATCH 2/6] fix(test): assert radionuclides back-populates on sample info - verify sample_info.radionuclides includes the new record - keep FK/relationship tests aligned to chemistry_sample_info_id --- tests/test_radionuclides_legacy.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/test_radionuclides_legacy.py b/tests/test_radionuclides_legacy.py index b1e88c64b..46c13f0a4 100644 --- a/tests/test_radionuclides_legacy.py +++ b/tests/test_radionuclides_legacy.py @@ -302,7 +302,7 @@ def test_radionuclides_fk_has_cascade(): def test_radionuclides_back_populates_sample_info(water_well_thing): - """NMA_Radionuclides.chemistry_sample_info navigates back to sample info.""" + """NMA_Radionuclides <-> NMA_Chemistry_SampleInfo back_populates works.""" with session_ctx() as session: sample_info = NMA_Chemistry_SampleInfo( nma_sample_pt_id=uuid4(), @@ -323,6 +323,7 @@ def test_radionuclides_back_populates_sample_info(water_well_thing): assert record.chemistry_sample_info is not None assert record.chemistry_sample_info.id == sample_info.id + assert record in sample_info.radionuclides session.delete(record) session.delete(sample_info) From f8876395befd14d14e1fc69975a4752465fffdef Mon Sep 17 00:00:00 2001 From: Kelsey Smuczynski Date: Fri, 6 Feb 2026 13:14:40 -0700 Subject: [PATCH 3/6] fix(test): update radionuclide tests to require chemistry sample info --- .../test_nma_legacy_relationships.py | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/tests/integration/test_nma_legacy_relationships.py b/tests/integration/test_nma_legacy_relationships.py index c34867c49..4210c767c 100644 --- a/tests/integration/test_nma_legacy_relationships.py +++ b/tests/integration/test_nma_legacy_relationships.py @@ -251,16 +251,16 @@ def test_stratigraphy_requires_well(self): session.add(record) session.flush() - def test_radionuclides_requires_well(self): + def test_radionuclides_requires_sample_info(self): """ @radionuclides - Scenario: Radionuclide results require a well + Scenario: Radionuclide results require chemistry sample info """ with session_ctx() as session: - with pytest.raises(ValueError, match="requires a parent Thing"): + with pytest.raises(ValueError, match="requires a chemistry_sample_info_id"): record = NMA_Radionuclides( nma_sample_pt_id=uuid.uuid4(), - thing_id=None, # This should raise ValueError + chemistry_sample_info_id=None, # This should raise ValueError ) session.add(record) session.flush() @@ -375,8 +375,8 @@ def test_well_navigates_to_stratigraphy_logs(self, well_for_relationships): assert len(well.stratigraphy_logs) >= 1 assert any(s.nma_point_id == "NAVSTRAT1" for s in well.stratigraphy_logs) - def test_well_navigates_to_radionuclides(self, well_for_relationships): - """Well can navigate to its radionuclide results.""" + def test_sample_info_navigates_to_radionuclides(self, well_for_relationships): + """Chemistry sample info can navigate to its radionuclide results.""" with session_ctx() as session: well = session.merge(well_for_relationships) @@ -395,15 +395,14 @@ def test_well_navigates_to_radionuclides(self, well_for_relationships): nma_global_id=uuid.uuid4(), chemistry_sample_info_id=chem_sample.id, nma_sample_pt_id=chem_sample.nma_sample_pt_id, - thing_id=well.id, ) session.add(radio) session.commit() - session.refresh(well) + session.refresh(chem_sample) # Navigate through relationship - assert hasattr(well, "radionuclides") - assert len(well.radionuclides) >= 1 + assert hasattr(chem_sample, "radionuclides") + assert len(chem_sample.radionuclides) >= 1 def test_well_navigates_to_associated_data(self, well_for_relationships): """Well can navigate to its associated data.""" @@ -597,7 +596,6 @@ def test_deleting_well_cascades_to_radionuclides(self): nma_global_id=uuid.uuid4(), chemistry_sample_info_id=chem_sample.id, nma_sample_pt_id=chem_sample.nma_sample_pt_id, - thing_id=well.id, ) session.add(radio) session.commit() From 4dfa22ff037de120d5e919a28ba34c793d93a715 Mon Sep 17 00:00:00 2001 From: Kelsey Smuczynski Date: Fri, 6 Feb 2026 13:14:47 -0700 Subject: [PATCH 4/6] fix(test): remove redundant radionuclides relationship tests from Thing model --- tests/test_thing.py | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/tests/test_thing.py b/tests/test_thing.py index 343f24dbf..713b7444b 100644 --- a/tests/test_thing.py +++ b/tests/test_thing.py @@ -1166,10 +1166,6 @@ def test_thing_has_hydraulics_data_relationship(self): """Thing model has hydraulics_data relationship collection.""" assert hasattr(Thing, "hydraulics_data") - def test_thing_has_radionuclides_relationship(self): - """Thing model has radionuclides relationship collection.""" - assert hasattr(Thing, "radionuclides") - def test_thing_has_associated_data_relationship(self): """Thing model has associated_data relationship collection.""" assert hasattr(Thing, "associated_data") @@ -1188,12 +1184,6 @@ def test_hydraulics_data_has_cascade_delete(self): assert rel is not None, "hydraulics_data relationship should exist" assert "delete" in rel.cascade or "all" in rel.cascade - def test_radionuclides_has_cascade_delete(self): - """radionuclides relationship has cascade delete configured.""" - rel = Thing.__mapper__.relationships.get("radionuclides") - assert rel is not None, "radionuclides relationship should exist" - assert "delete" in rel.cascade or "all" in rel.cascade - def test_associated_data_has_cascade_delete(self): """associated_data relationship has cascade delete configured.""" rel = Thing.__mapper__.relationships.get("associated_data") From aac5ef006439305c2d2a2e7cf2881f740963e21a Mon Sep 17 00:00:00 2001 From: Kelsey Smuczynski Date: Fri, 6 Feb 2026 14:06:59 -0700 Subject: [PATCH 5/6] fix(test): update chemistry sample relationships to reference Thing instead of Location --- .../steps/nma-legacy-relationships.py | 118 +++++------------- 1 file changed, 28 insertions(+), 90 deletions(-) diff --git a/tests/features/steps/nma-legacy-relationships.py b/tests/features/steps/nma-legacy-relationships.py index 849e60f39..6aaa090e3 100644 --- a/tests/features/steps/nma-legacy-relationships.py +++ b/tests/features/steps/nma-legacy-relationships.py @@ -22,7 +22,7 @@ - All models use `id` (Integer, autoincrement) as PK - Legacy UUID columns renamed with `nma_` prefix (e.g., `nma_global_id`) - Legacy string columns renamed with `nma_` prefix (e.g., `nma_point_id`) -- Chemistry samples FK to Location (not Thing) +- Chemistry samples FK to Thing - Other NMA models (hydraulics, stratigraphy, etc.) FK to Thing - Chemistry children use `chemistry_sample_info_id` (Integer FK) """ @@ -34,7 +34,7 @@ from behave.runner import Context from sqlalchemy.exc import IntegrityError, StatementError -from db import Location, Thing +from db import Thing from db.engine import session_ctx from db.nma_legacy import ( NMA_Chemistry_SampleInfo, @@ -130,7 +130,7 @@ def step_then_find_by_locationid(context: Context): @when("I try to save chemistry sample information") def step_when_save_chemistry(context: Context): - """Attempt to save chemistry sample info without a location.""" + """Attempt to save chemistry sample info without a well.""" context.orphan_error = None context.record_saved = False @@ -139,7 +139,7 @@ def step_when_save_chemistry(context: Context): chemistry = NMA_Chemistry_SampleInfo( nma_sample_pt_id=uuid.uuid4(), nma_sample_point_id="TEST001", - location_id=None, # No parent location + thing_id=None, # No parent well collection_date=datetime.now(), ) session.add(chemistry) @@ -159,11 +159,11 @@ def step_then_well_required(context: Context): @then("orphaned chemistry records are not allowed") def step_then_no_orphan_chemistry(context: Context): - """Verify no orphan chemistry records exist (FK to Location).""" + """Verify no orphan chemistry records exist (FK to Thing).""" with session_ctx() as session: orphan_count = ( session.query(NMA_Chemistry_SampleInfo) - .filter(NMA_Chemistry_SampleInfo.location_id.is_(None)) + .filter(NMA_Chemistry_SampleInfo.thing_id.is_(None)) .count() ) assert orphan_count == 0, f"Found {orphan_count} orphan chemistry records" @@ -256,38 +256,16 @@ def step_then_no_orphan_lithology(context: Context): @when("I try to save radionuclide results") def step_when_save_radionuclides(context: Context): - """Attempt to save radionuclide results without a well.""" + """Attempt to save radionuclide results without chemistry sample info.""" context.orphan_error = None context.record_saved = False try: with session_ctx() as session: - # First create a Location for the chemistry sample (chemistry FKs to Location) - location = Location( - point="POINT(-107.949533 33.809665)", - elevation=2464.9, - release_status="draft", - ) - session.add(location) - session.commit() - session.refresh(location) - - # Create chemistry sample info for the radionuclide - chemistry_sample = NMA_Chemistry_SampleInfo( - nma_sample_pt_id=uuid.uuid4(), - nma_sample_point_id="TEST001", - location_id=location.id, - collection_date=datetime.now(), - ) - session.add(chemistry_sample) - session.commit() - session.refresh(chemistry_sample) - radionuclide = NMA_Radionuclides( nma_global_id=uuid.uuid4(), - thing_id=None, # No parent well - this should fail - chemistry_sample_info_id=chemistry_sample.id, - nma_sample_pt_id=chemistry_sample.nma_sample_pt_id, + chemistry_sample_info_id=None, # No parent sample info - should fail + nma_sample_pt_id=uuid.uuid4(), analyte="U-238", ) session.add(radionuclide) @@ -304,7 +282,7 @@ def step_then_no_orphan_radionuclides(context: Context): with session_ctx() as session: orphan_count = ( session.query(NMA_Radionuclides) - .filter(NMA_Radionuclides.thing_id.is_(None)) + .filter(NMA_Radionuclides.chemistry_sample_info_id.is_(None)) .count() ) assert orphan_count == 0, f"Found {orphan_count} orphan radionuclide records" @@ -397,26 +375,21 @@ def step_then_no_orphan_soil_rock(context: Context): def step_when_access_relationships(context: Context): """Access the well's relationships. - Note: Chemistry samples now FK to Location, not Thing. - Chemistry samples are accessed via Location.chemistry_sample_infos. + Note: Chemistry samples FK to Thing. + Chemistry samples are accessed via Thing.chemistry_sample_infos. """ with session_ctx() as session: well = session.query(Thing).filter(Thing.id == context.test_well_id).first() - # Chemistry samples are now on Location, not Thing - # Access via the test location created in step_given_well_has_chemistry - location = None - if hasattr(context, "test_location_id"): - location = ( - session.query(Location) - .filter(Location.id == context.test_location_id) - .first() - ) + chemistry_samples = well.chemistry_sample_infos if well else [] + radionuclides = [ + radio for sample in chemistry_samples for radio in sample.radionuclides + ] context.well_relationships = { - "chemistry_samples": location.chemistry_sample_infos if location else [], + "chemistry_samples": chemistry_samples, "hydraulics_data": well.hydraulics_data, "lithology_logs": well.stratigraphy_logs, - "radionuclides": well.radionuclides, + "radionuclides": radionuclides, "associated_data": well.associated_data, "soil_rock_results": well.soil_rock_results, } @@ -451,36 +424,21 @@ def step_then_relationships_correct(context: Context): @given("a well has chemistry sample records") def step_given_well_has_chemistry(context: Context): - """Create chemistry samples for a location associated with a well. - - Note: Chemistry samples now FK to Location (not Thing). - This step creates a Location and associates chemistry samples with it. - """ + """Create chemistry samples for a well.""" if not hasattr(context, "test_well"): step_given_well_exists(context) with session_ctx() as session: - # Create a Location for chemistry samples - location = Location( - point="POINT(-107.949533 33.809665)", - elevation=2464.9, - release_status="draft", - ) - session.add(location) - session.commit() - session.refresh(location) - context.test_location_id = location.id - chemistry1 = NMA_Chemistry_SampleInfo( nma_sample_pt_id=uuid.uuid4(), nma_sample_point_id="TEST001", - location_id=context.test_location_id, + thing_id=context.test_well_id, collection_date=datetime.now(), ) chemistry2 = NMA_Chemistry_SampleInfo( nma_sample_pt_id=uuid.uuid4(), nma_sample_point_id="TEST002", - location_id=context.test_location_id, + thing_id=context.test_well_id, collection_date=datetime.now(), ) session.add_all([chemistry1, chemistry2]) @@ -537,26 +495,16 @@ def step_given_well_has_lithology(context: Context): def step_given_well_has_radionuclides(context: Context): """Create radionuclide results for a well. - Note: Chemistry samples FK to Location, Radionuclides FK to both Thing and ChemistrySampleInfo. + Note: Chemistry samples FK to Thing, Radionuclides FK to ChemistrySampleInfo. """ if not hasattr(context, "test_well"): step_given_well_exists(context) with session_ctx() as session: - # Create a Location for the chemistry sample (chemistry FKs to Location) - location = Location( - point="POINT(-107.949533 33.809665)", - elevation=2464.9, - release_status="draft", - ) - session.add(location) - session.commit() - session.refresh(location) - chemistry_sample = NMA_Chemistry_SampleInfo( nma_sample_pt_id=uuid.uuid4(), nma_sample_point_id="TEST001", - location_id=location.id, + thing_id=context.test_well_id, collection_date=datetime.now(), ) session.add(chemistry_sample) @@ -565,7 +513,6 @@ def step_given_well_has_radionuclides(context: Context): radionuclide = NMA_Radionuclides( nma_global_id=uuid.uuid4(), - thing_id=context.test_well_id, chemistry_sample_info_id=chemistry_sample.id, nma_sample_pt_id=chemistry_sample.nma_sample_pt_id, analyte="U-238", @@ -573,6 +520,7 @@ def step_given_well_has_radionuclides(context: Context): session.add(radionuclide) session.commit() context.radionuclide_results = radionuclide + context.radionuclide_results_id = radionuclide.id @given("a well has associated data") @@ -624,17 +572,11 @@ def step_when_well_deleted(context: Context): @then("its chemistry samples are also deleted") def step_then_chemistry_deleted(context: Context): - """Verify chemistry samples are cascade deleted when Location is deleted. - - Note: Chemistry samples now FK to Location (not Thing), so this step - verifies no chemistry samples exist for the test location. - """ + """Verify chemistry samples are cascade deleted when Thing is deleted.""" with session_ctx() as session: - # Chemistry samples FK to Location, not Thing - # When a Location is deleted, its chemistry samples cascade delete remaining = ( session.query(NMA_Chemistry_SampleInfo) - .filter(NMA_Chemistry_SampleInfo.location_id == context.test_location_id) + .filter(NMA_Chemistry_SampleInfo.thing_id == context.test_well_id) .count() ) assert remaining == 0, f"Expected 0 chemistry samples, found {remaining}" @@ -668,12 +610,8 @@ def step_then_lithology_deleted(context: Context): def step_then_radionuclides_deleted(context: Context): """Verify radionuclide results are cascade deleted.""" with session_ctx() as session: - remaining = ( - session.query(NMA_Radionuclides) - .filter(NMA_Radionuclides.thing_id == context.test_well_id) - .count() - ) - assert remaining == 0, f"Expected 0 radionuclide records, found {remaining}" + orphan = session.get(NMA_Radionuclides, context.radionuclide_results_id) + assert orphan is None, "Radionuclide record should be deleted with well" @then("its associated data is also deleted") From 98984136d4019ac7ff9092cdd18c3f70e444d6eb Mon Sep 17 00:00:00 2001 From: Kelsey Smuczynski Date: Fri, 6 Feb 2026 14:57:21 -0700 Subject: [PATCH 6/6] fix(test): reorganize nma legacy relationship tests - Moved radionuclide sample-info requirement into its own class - Moved sample-info navigation test under a new navigation section --- .../test_nma_legacy_relationships.py | 105 +++++++++++------- 1 file changed, 62 insertions(+), 43 deletions(-) diff --git a/tests/integration/test_nma_legacy_relationships.py b/tests/integration/test_nma_legacy_relationships.py index 4210c767c..c613f13cd 100644 --- a/tests/integration/test_nma_legacy_relationships.py +++ b/tests/integration/test_nma_legacy_relationships.py @@ -251,20 +251,6 @@ def test_stratigraphy_requires_well(self): session.add(record) session.flush() - def test_radionuclides_requires_sample_info(self): - """ - @radionuclides - Scenario: Radionuclide results require chemistry sample info - """ - with session_ctx() as session: - with pytest.raises(ValueError, match="requires a chemistry_sample_info_id"): - record = NMA_Radionuclides( - nma_sample_pt_id=uuid.uuid4(), - chemistry_sample_info_id=None, # This should raise ValueError - ) - session.add(record) - session.flush() - def test_associated_data_requires_well(self): """ @associated-data @@ -375,35 +361,6 @@ def test_well_navigates_to_stratigraphy_logs(self, well_for_relationships): assert len(well.stratigraphy_logs) >= 1 assert any(s.nma_point_id == "NAVSTRAT1" for s in well.stratigraphy_logs) - def test_sample_info_navigates_to_radionuclides(self, well_for_relationships): - """Chemistry sample info can navigate to its radionuclide results.""" - with session_ctx() as session: - well = session.merge(well_for_relationships) - - # Create a chemistry sample for the thing (chemistry FKs to Thing) - chem_sample = NMA_Chemistry_SampleInfo( - nma_sample_pt_id=uuid.uuid4(), - nma_sample_point_id="NAVRAD01", # Required, max 10 chars - thing_id=well.id, - ) - session.add(chem_sample) - session.commit() - session.refresh(chem_sample) - - # Create radionuclide record for this well using the chemistry_sample_info_id - radio = NMA_Radionuclides( - nma_global_id=uuid.uuid4(), - chemistry_sample_info_id=chem_sample.id, - nma_sample_pt_id=chem_sample.nma_sample_pt_id, - ) - session.add(radio) - session.commit() - session.refresh(chem_sample) - - # Navigate through relationship - assert hasattr(chem_sample, "radionuclides") - assert len(chem_sample.radionuclides) >= 1 - def test_well_navigates_to_associated_data(self, well_for_relationships): """Well can navigate to its associated data.""" with session_ctx() as session: @@ -444,6 +401,42 @@ def test_well_navigates_to_soil_rock_results(self, well_for_relationships): assert any(s.nma_point_id == "NAV-SOIL-01" for s in well.soil_rock_results) +class TestChemistrySampleInfoNavigation: + """ + @relationships + Scenario: Chemistry sample info can access its related records + """ + + def test_sample_info_navigates_to_radionuclides(self, well_for_relationships): + """Chemistry sample info can navigate to its radionuclide results.""" + with session_ctx() as session: + well = session.merge(well_for_relationships) + + # Create a chemistry sample for the thing (chemistry FKs to Thing) + chem_sample = NMA_Chemistry_SampleInfo( + nma_sample_pt_id=uuid.uuid4(), + nma_sample_point_id="NAVRAD01", # Required, max 10 chars + thing_id=well.id, + ) + session.add(chem_sample) + session.commit() + session.refresh(chem_sample) + + # Create radionuclide record using the chemistry_sample_info_id + radio = NMA_Radionuclides( + nma_global_id=uuid.uuid4(), + chemistry_sample_info_id=chem_sample.id, + nma_sample_pt_id=chem_sample.nma_sample_pt_id, + ) + session.add(radio) + session.commit() + session.refresh(chem_sample) + + # Navigate through relationship + assert hasattr(chem_sample, "radionuclides") + assert len(chem_sample.radionuclides) >= 1 + + # ============================================================================= # Deleting a Well Removes Related Records (Cascade Delete) # ============================================================================= @@ -680,3 +673,29 @@ def test_deleting_well_cascades_to_soil_rock_results(self): # Verify soil/rock results were also deleted orphan = session.get(NMA_Soil_Rock_Results, soil_id) assert orphan is None, "Soil/rock results should be deleted with well" + + +# ============================================================================= +# Chemistry Children Require Sample Info +# ============================================================================= + + +class TestChemistryChildrenRequireSampleInfo: + """ + @radionuclides + Scenario: Chemistry children require a parent sample info + """ + + def test_radionuclides_requires_sample_info(self): + """ + @radionuclides + Scenario: Radionuclide results require chemistry sample info + """ + with session_ctx() as session: + with pytest.raises(ValueError, match="requires a chemistry_sample_info_id"): + record = NMA_Radionuclides( + nma_sample_pt_id=uuid.uuid4(), + chemistry_sample_info_id=None, # This should raise ValueError + ) + session.add(record) + session.flush()