11"""The loader for the first JSON-based dataset configuration."""
22
33import json
4- from typing import Any , Optional , Union
4+ from typing import Any , Optional , Type , Union
55
66from pydantic import BaseModel , Field , PrivateAttr , validate_call
77from typing_extensions import Literal
88
99from dve .core_engine .backends .base .reference_data import ReferenceConfig , ReferenceConfigUnion
10- from dve .core_engine .backends .metadata .contract import DataContractMetadata , ReaderConfig
10+ from dve .core_engine .backends .metadata .contract import ChildHierarchyNode , DataContractMetadata , HierarchyNode , ReaderConfig
1111from dve .core_engine .backends .metadata .rules import AbstractStep , Rule , RuleMetadata
1212from dve .core_engine .configuration .base import BaseEngineConfig
1313from dve .core_engine .configuration .v1 .filters import (
2424from dve .core_engine .message import DataContractErrorDetail
2525from dve .core_engine .type_hints import EntityName , ErrorCategory , ErrorType , TemplateVariables
2626from dve .core_engine .validation import RowValidator
27+ from dve .metadata_parser .exc import EntityNotFoundError
2728from dve .parser .file_handling import joinuri , open_stream , resolve_location
2829from dve .parser .type_hints import URI , Extension
2930
3839
3940FieldName = str
4041"""The name of a field within a model/schema."""
42+ JoinFields = Optional [list [str ]]
43+ """The fields required to join a child entity back to the parent"""
4144TypeOrDef = Union [ # pylint: disable=C0103
4245 TypeName , "_CallableTypeDefinition" , "_ModelTypeDefinition" , "_TypeAliasDefinition"
4346]
@@ -81,6 +84,14 @@ class _TypeAliasDefinition(_BaseTypeDefintion):
8184 """The name of the Python type."""
8285
8386
87+ class _LinkageConfig (BaseModel ):
88+ """Specify how to link entities back to parents if required"""
89+ parent_entity : EntityName
90+ """The name of the parent entity"""
91+ join_fields : JoinFields
92+ """The fields that can be used to link back to the parent entity"""
93+
94+
8495class _SchemaConfig (BaseModel ):
8596 """Configuration for a component schema within a dataset."""
8697
@@ -112,6 +123,7 @@ class _ModelConfig(_SchemaConfig):
112123 """Reader configuration options for the model."""
113124 aliases : dict [FieldName , FieldName ] = Field (default_factory = dict )
114125 """An alias field name mapping."""
126+ linkage_details : Optional [_LinkageConfig ] = None
115127
116128
117129class _RuleStoreConfig (BaseModel ):
@@ -330,6 +342,7 @@ def get_contract_metadata(self) -> DataContractMetadata:
330342 validators = validators ,
331343 reporting_fields = reporting_fields ,
332344 cache_originals = self .contract .cache_originals ,
345+ linkage_hierarchy = self .determine_entity_hierarchy ()
333346 )
334347
335348 def load_error_message_info (self , uri ):
@@ -351,3 +364,22 @@ def get_rule_metadata(self) -> RuleMetadata:
351364 global_variables = self .transformations .parameters , # pylint: disable=E1101
352365 reference_data_config = self .get_reference_data_config (),
353366 )
367+
368+ def determine_entity_hierarchy (self ) -> list [HierarchyNode ]:
369+ """Determine the linkage hierarchy using contact config"""
370+ linkage_hierarchy = {name : model_conf .linkage_details for name , model_conf in self .contract .datasets .items ()}
371+ top_level_parents = {}
372+ for name , linkage_detail in linkage_hierarchy .items ():
373+ if not linkage_detail :
374+ top_level_parents [name ] = HierarchyNode (entity_name = name )
375+ continue
376+ for main_entity , details in top_level_parents .items ():
377+ if (linkage_detail .parent_entity == main_entity
378+ or linkage_detail .parent_entity in details .get_descendents ()):
379+ top_level_parents [main_entity ].add_child_node (linkage_detail .parent_entity ,
380+ ChildHierarchyNode (entity_name = name ,
381+ join_fields = linkage_detail .join_fields ))
382+ break
383+ else :
384+ raise EntityNotFoundError (f"Can't find parent entity { linkage_detail .parent_entity } defined to establish hierarchy for { name } - please ensure it is defined above any child entities in the dischema." )
385+ return top_level_parents
0 commit comments