From 312400759f68fc3fbb6b902a8e07f49ebdae4474 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 15 Jul 2026 15:53:10 +0200 Subject: [PATCH] fix: normalize official agricultural crop groups --- CHANGELOG.md | 2 ++ .../app/services/vector_feature_service.py | 22 ++++++++++++++++++- ...t_sprint205_agricultural_parcel_history.py | 14 ++++++++++++ .../provision_agricultural_parcel_history.py | 2 ++ 4 files changed, 39 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e71a9979..61078d85 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,8 @@ - Added a scope-specific 18-edition temporal series while explicitly disabling parcel-level lineage and excluding the provisional current campaign. - Added focused source, clipping, metric, pagination, packaging and UI tests. +- Added compatibility for the official comma-separated grain and horticulture + group labels after live source validation exposed their exact wording. ## Sprint 204 Governed BWK and Natura 2000 for Mol (2026-07-15) diff --git a/backend/app/services/vector_feature_service.py b/backend/app/services/vector_feature_service.py index e50f3b12..81340537 100644 --- a/backend/app/services/vector_feature_service.py +++ b/backend/app/services/vector_feature_service.py @@ -101,8 +101,25 @@ SEMANTIC_COUNT_LABELS = { "agriculture": "Landbouwgebruikspercelen", } +# Sprint 205 initially normalized two official comma-separated ALZ group labels +# mechanically. Keep those persisted values queryable while new artifacts use +# the explicit controlled keys. +SELECTION_FILTER_VALUE_ALIASES: dict[tuple[str, str], tuple[str, ...]] = { + ("main_crop_group_key", "grains_seeds_legumes"): ("granen,_zaden_en_peulvruchten",), + ("main_crop_group_key", "horticulture"): ("groenten,_kruiden_en_sierplanten",), +} + class VectorFeatureService: + @staticmethod + def _expanded_selection_filter_values(filter_property: str, filter_values: list[Any]) -> list[str]: + expanded: list[str] = [] + for value in filter_values: + normalized = str(value) + expanded.append(normalized) + expanded.extend(SELECTION_FILTER_VALUE_ALIASES.get((filter_property, normalized), ())) + return list(dict.fromkeys(expanded)) + @staticmethod def _dataset_theme(dataset: Dataset) -> str | None: source_metadata = dataset.source_metadata if isinstance(dataset.source_metadata, dict) else {} @@ -453,7 +470,10 @@ class VectorFeatureService: details={"dataset_id": str(dataset.id), "filter_property": filter_property}, status_code=500, ) - normalized_filter_values = [str(value) for value in filter_values] + normalized_filter_values = VectorFeatureService._expanded_selection_filter_values( + filter_property, + filter_values, + ) metric_filter += ( VectorFeature.properties_json.op("->>")(filter_property).in_(normalized_filter_values), ) diff --git a/backend/tests/test_sprint205_agricultural_parcel_history.py b/backend/tests/test_sprint205_agricultural_parcel_history.py index 94485fd7..3523058c 100644 --- a/backend/tests/test_sprint205_agricultural_parcel_history.py +++ b/backend/tests/test_sprint205_agricultural_parcel_history.py @@ -150,6 +150,20 @@ def test_crop_code_list_preserves_year_specific_titles_and_reports_conflicts() - assert result["code_title_conflicts"] == {"201": ["Korrelmais", "Mais"]} assert "maincropgroup_title" in result["historical_comparison_rule"] assert module.normalized_group_title("Maïs") == "maize" + assert module.normalized_group_title("Granen, zaden en peulvruchten") == "grains_seeds_legumes" + assert module.normalized_group_title("Groenten, kruiden en sierplanten") == "horticulture" + + +def test_persisted_first_import_group_keys_remain_query_compatible() -> None: + assert VectorFeatureService._expanded_selection_filter_values( + "main_crop_group_key", + ["grains_seeds_legumes", "horticulture"], + ) == [ + "grains_seeds_legumes", + "granen,_zaden_en_peulvruchten", + "horticulture", + "groenten,_kruiden_en_sierplanten", + ] def test_features_are_exactly_clipped_in_lambert72_and_keep_source_fields() -> None: diff --git a/scripts/provision_agricultural_parcel_history.py b/scripts/provision_agricultural_parcel_history.py index e922d5dd..04548e64 100644 --- a/scripts/provision_agricultural_parcel_history.py +++ b/scripts/provision_agricultural_parcel_history.py @@ -94,8 +94,10 @@ GROUP_ALIASES = { "grasland": "grassland", "mais": "maize", "granen/zaden/peulvruchten": "grains_seeds_legumes", + "granen, zaden en peulvruchten": "grains_seeds_legumes", "aardappelen": "potatoes", "groenten/kruiden/sierplanten": "horticulture", + "groenten, kruiden en sierplanten": "horticulture", "suikerbieten": "sugar_beets", "voedergewassen": "fodder_crops", "fruit en noten": "fruit_nuts",