Repository: atviriduomenys/spinta

Issue:
XSD -> DSA: post_process_refs
When building a model tree, the top level `element` and `complexType` nodes are being turned into models, but the references on properties on other models are not being created. this is being done to avoid too much logic happening at once. 

Because of this, we need to revisit each property and create those links as needed. If property has a link to a model, which hasn't been properly processed yet, it will have `xsd_ref_to` if it is connected through `ref` and `xsd_type_to` if it's connected through `type`. Models that have to be checked, have `is_root_model` set to True and they have `source`. 


To search models quicker, models that can be referenced, will be added to `XSDReader`     `top_level_element_models` or  `top_level_complex_type_models` dictionaries depending on if it's created from `element` or from `complexType`. 


- [ ] tests
- [ ] documentation
- [ ] entry in CHANGES.rst

Discussion:

Patch:
diff --git a/spinta/manifests/xsd2/helpers.py b/spinta/manifests/xsd2/helpers.py
index e3ebea7e..ca2b7d5b 100644
--- a/spinta/manifests/xsd2/helpers.py
+++ b/spinta/manifests/xsd2/helpers.py
@@ -338,7 +338,25 @@ class XSDReader:
             self.models.append(self.resource_model)
 
     def _post_process_refs(self):
-        pass
+        """
+        Links properties in all models to their target models based on xsd_ref_to and xsd_type_to.
+        """
+        for model in self.models:
+            for prop in model.properties.values():
+                
+                if prop.xsd_ref_to:
+                    try:
+                        target_model: XSDModel = self.top_level_element_models[prop.xsd_ref_to]
+                    except KeyError:
+                        raise KeyError("Reference to a non-existing model")
+                    
+                elif prop.xsd_type_to:
+                    try:
+                        target_model: XSDModel = self.top_level_complex_type_models[prop.xsd_type_to]
+                    except KeyError:
+                        raise KeyError("Reference to a non-existing model")
+
+                prop.ref_model = target_model
 
     def _add_expand_to_top_level_models(self):
         pass


Test patch:
diff --git a/tests/manifests/xsd2/test_helpers.py b/tests/manifests/xsd2/test_helpers.py
index 528a79db..dab00c5c 100644
--- a/tests/manifests/xsd2/test_helpers.py
+++ b/tests/manifests/xsd2/test_helpers.py
@@ -1,6 +1,9 @@
+from pyexpat import model
+from typing import Callable
 import pytest
 
-from spinta.manifests.xsd2.helpers import XSDReader, State, XSDProperty, XSDType, XSDModel, XSDDatasetResource, _is_array
+from spinta.cli import data
+from spinta.manifests.xsd2.helpers import XSDReader, State, XSDProperty, XSDType, XSDModel, XSDDatasetResource
 from unittest.mock import MagicMock, patch
 from lxml import etree
 
@@ -719,3 +722,78 @@ def test_process_sequence_only_choices(setup_instance):
     for group, expected in zip(property_groups, expected_groups):
         property_names = [prop.xsd_name for prop in group]
         assert property_names == expected, "Property group does not match any expected group."
+
+@pytest.fixture
+def xsd_reader():
+    return XSDReader("test", "test")
+
+@pytest.fixture
+def create_xsd_model() -> Callable[..., XSDModel]:
+    def _create(name: str) -> XSDModel:
+        dataset_resource = XSDDatasetResource(dataset_name="test")
+        model = XSDModel(dataset_resource=dataset_resource)
+        model.xsd_name = name
+        return model
+    return _create
+
+@pytest.fixture
+def create_ref_xsd_property() -> Callable[..., XSDProperty]:
+    def _create(name: str, type: str, ref_model: str) -> XSDProperty:
+        prop = XSDProperty(
+            xsd_name=name,
+            property_type=XSDType(name=type),
+            required=True,
+        )
+        if type == "ref":
+            prop.xsd_ref_to = ref_model
+        elif type == "type":
+            prop.xsd_type_to = ref_model
+        return prop
+    return _create
+
+@pytest.fixture
+def setup_models(xsd_reader, create_xsd_model, create_ref_xsd_property):
+    model_a = create_xsd_model("ModelA")
+    model_b = create_xsd_model("ModelB")
+
+    prop1 = create_ref_xsd_property("prop1", "ref", model_b.xsd_name)
+    prop2 = create_ref_xsd_property("prop2", "type", model_a.xsd_name)
+
+    model_a.properties["prop1"] = prop1
+    model_b.properties["prop2"] = prop2
+
+    xsd_reader.models.extend([model_a, model_b])
+
+    xsd_reader.top_level_element_models[model_b.xsd_name] = model_b
+    xsd_reader.top_level_complex_type_models[model_a.xsd_name] = model_a
+    
+    return {
+        "xsd_reader": xsd_reader,
+        "models": {
+            "ModelA": model_a,
+            "ModelB": model_b,
+        },
+        "properties": {
+            "prop1": prop1,
+            "prop2": prop2,
+        }
+    }
+
+
+def test_post_process_refs_links_existing_references(setup_models):
+    """
+    Test that _post_process_refs correctly links properties to existing models.
+    """
+    xsd_reader, models, properties = setup_models["xsd_reader"], setup_models["models"], setup_models["properties"]
+    model_a, model_b = models["ModelA"], models["ModelB"]
+    prop1, prop2 = properties["prop1"], properties["prop2"]
+    
+    xsd_reader._post_process_refs()
+        
+    # Property1 in ModelA should link to ModelB via ref_model
+    assert prop1.ref_model is not None
+    assert prop1.ref_model == model_b
+    
+    # Property2 in ModelB should link to ModelA via ref_model
+    assert prop2.ref_model is not None
+    assert prop2.ref_model == model_a
\ No newline at end of file