fix(mapping): preserve excluded_attributes on update, backfill relationship source/target class - #152
Conversation
…onship source/target class When updating an existing entity or relationship mapping, if the incoming payload omits excluded_attributes but the previous mapping had one, that list is now carried forward — previously only the general excluded flag was preserved, not the concrete list, so re-saving a mapping that had excluded attributes could silently re-include them. When resolving source_class/target_class for a relationship's consistency checks, if those fields are empty — as they always are for relationships saved via Manual Mapping, which never sends them — they're now backfilled from the corresponding ontology property's rdfs:domain/rdfs:range instead of being left empty. This is the backend counterpart to the companion Manual Mapping PR, which stops the gap from being created going forward; this fix handles mappings that already have it. Verified this applies cleanly on top of develop's schema-drift feature added to this file since 0.7.1 — the two are unrelated and don't overlap.
|
|
benoitcayladbx
left a comment
There was a problem hiding this comment.
Relevant as the backend counterpart to #150. On current develop, add_or_update_*_mapping still only preserves the excluded flag, not excluded_attributes, and _diagnose_relationship still reads empty source_class/target_class as-is. Please keep the PR; it needs a tighter contract + tests.
Must fix
-
Omit vs empty list (correctness).
build_entity_mapping/build_relationship_mappingonly copyexcluded_attributeswhendata.get("excluded_attributes")is truthy, so an explicit[](user cleared all exclusions) never lands onnew_mapping. Your new branch then treats that as “key absent” and restores the previous list.Use key presence, not truthiness:
if "excluded_attributes" in data: new_mapping["excluded_attributes"] = list(data.get("excluded_attributes") or []) elif m.get("excluded_attributes"): new_mapping["excluded_attributes"] = list(m["excluded_attributes"])
Mirror the same
"excluded_attributes" in datacheck inside the builders, or preserve only inadd_or_update_*and always stamp the list fromdatawhen the key is present. -
Tests (
.cursor/08,src/.coding_rules.md§10). This is domain behaviour — it must have unit tests. Extendtests/units/mapping/test_mapping_service.py(TestAddOrUpdateEntity.test_update_existing) andtests/units/mapping/test_attribute_exclusion.py:- update omitting the key keeps the previous
excluded_attributes; - update sending
[]clears them; _diagnose_relationshipwith emptysource_class/target_classfills from property domain/range (and stays empty when the property is unknown).
- update omitting the key keeps the previous
-
Changelog —
changelogs/v0.8.0/<github-user>_YYYY-MM-DD.log(English). -
CLA still pending.
Guidance / nits
- Diagnostic backfill vs persist. Falling back in
_diagnose_relationshipunblocks the consistency UI, but the mapping JSON on disk stays empty until something writessource_class. Prefer filling at save time (build_relationship_mappingor Manual Mapping #150) so later consumers (R2RML, agents) see the same data. Diagnosis can keep the fallback for legacy rows. - The comment citing
EstudioPais -> Paisis fine as an illustration, but a generic “Designer header already shows domain → range” is enough (.cursor/05— comments explain why, not a tenant-specific example). - Reusing
ont_propinstead of looking it up twice is good.
Please rebase on latest develop (schema-drift in this file has moved on; your hunks still look isolated, which is good) and add the tests above.
What
Companion backend fix to #150 (the Manual Mapping save-state PR), in
src/back/objects/mapping/Mapping.py:excluded_attributesbut the previous mapping had one, that list is now carried forward. Previously only the generalexcludedflag was preserved this way, not the concreteexcluded_attributeslist — so re-saving a mapping that had excluded attributes could silently re-include them.source_class/target_classfor consistency checks, if those fields are empty — as they always are for relationships saved via Manual Mapping, which never sends them — they're now backfilled from the corresponding ontology property'srdfs:domain/rdfs:rangeinstead of being left empty.Why
#150 stops new Manual Mapping saves from losing
source_class/target_class/excluded_attributesgoing forward. This PR is the counterpart for mappings that already exist without them (created before #150, or from any other code path that doesn't send those fields) — the consistency check now recovers what it needs from the ontology itself rather than reporting incomplete data for an otherwise-correctly-configured relationship.A note on how this PR came together
This is a delayed follow-up to #146–#150: when we first put those together,
Mapping.pyhad since grown a substantial schema-drift feature ondevelopthat we hadn't checked our change against, so we held it back. We've now verified this patch applies cleanly on top of that feature with no overlap at all — the drift-detection code and this fix touch entirely different methods — so there was nothing to reconcile, just due diligence to do first.How to test
excluded_attributes(e.g. via a code path that omits it) — the attribute should stay excluded instead of reappearing.source_class/target_class), then run the mapping consistency check —source_class/target_classshould resolve from the property's domain/range instead of showing empty.