diff --git a/src/vtlengine/Operators/Join.py b/src/vtlengine/Operators/Join.py index 043121ac1..fc67df5fc 100644 --- a/src/vtlengine/Operators/Join.py +++ b/src/vtlengine/Operators/Join.py @@ -406,7 +406,20 @@ def execute(cls, dataset: Dataset, op: Any, left: str, right: str) -> Dataset: return op.evaluate(left_dataset, right_dataset) @classmethod - def validate(cls, dataset: Dataset, child: Any, op_map: Dict[str, Any]) -> None: + def validate(cls, dataset: Dataset, child: Any, op_map: Dict[str, Any]) -> Dataset: + if isinstance(child, list): + for c in child: + dataset = cls.validate(dataset, c, op_map) + else: + cls._check_bin_expr(dataset, child, op_map) + left_dataset = cls.create_dataset("left", child.left.value, dataset) + right_dataset = cls.create_dataset("right", child.right.value, dataset) + dataset, _ = cls.get_common_components(left_dataset, right_dataset) + + return dataset + + @classmethod + def _check_bin_expr(cls, dataset: Dataset, child: Any, op_map: Dict[str, Any]) -> None: if not isinstance(child, BinOp): raise Exception( f"Invalid expression {child} on apply operator. Only BinOp are accepted" @@ -438,7 +451,12 @@ def create_dataset(cls, name: str, prefix: str, dataset: Dataset) -> Dataset: for component in dataset.components.values() if component.name.startswith(prefix) or component.role is Role.IDENTIFIER } - data = dataset.data[list(components.keys())] if dataset.data is not None else pd.DataFrame() + comp_names = list(components.keys()) + data = ( + dataset.data[comp_names] + if dataset.data is not None + else pd.DataFrame(columns=comp_names) + ) for component in components.values(): component.name = ( diff --git a/tests/Semantic/data/DataStructure/input/GH_609-1.json b/tests/Semantic/data/DataStructure/input/GH_609-1.json new file mode 100644 index 000000000..55773c574 --- /dev/null +++ b/tests/Semantic/data/DataStructure/input/GH_609-1.json @@ -0,0 +1,21 @@ +{ + "datasets": [ + { + "name": "DS_1", + "DataStructure": [ + { + "name": "Id_1", + "type": "Integer", + "role": "Identifier", + "nullable": false + }, + { + "name": "Me_1", + "type": "Number", + "role": "Measure", + "nullable": true + } + ] + } + ] +} \ No newline at end of file diff --git a/tests/Semantic/data/DataStructure/output/GH_609-1.json b/tests/Semantic/data/DataStructure/output/GH_609-1.json new file mode 100644 index 000000000..9143772a7 --- /dev/null +++ b/tests/Semantic/data/DataStructure/output/GH_609-1.json @@ -0,0 +1,21 @@ +{ + "datasets": [ + { + "name": "DS_r", + "DataStructure": [ + { + "name": "Id_1", + "type": "Integer", + "role": "Identifier", + "nullable": false + }, + { + "name": "Me_1", + "type": "Number", + "role": "Measure", + "nullable": true + } + ] + } + ] +} \ No newline at end of file diff --git a/tests/Semantic/data/vtl/GH_609.vtl b/tests/Semantic/data/vtl/GH_609.vtl new file mode 100644 index 000000000..3ccc2352f --- /dev/null +++ b/tests/Semantic/data/vtl/GH_609.vtl @@ -0,0 +1 @@ +DS_r := inner_join (DS_1 as d1, DS_1 as d2 apply d1 + d2); \ No newline at end of file diff --git a/tests/Semantic/test_semantic.py b/tests/Semantic/test_semantic.py index dac46892f..95e038414 100644 --- a/tests/Semantic/test_semantic.py +++ b/tests/Semantic/test_semantic.py @@ -1854,6 +1854,19 @@ def test_20(self): self.BaseTest(code=code, number_inputs=number_inputs, references_names=references_names) + def test_GH_609(self): + """ + Dataset --> Dataset + Status: + Expression: DS_r := inner_join (DS_1 as d1, DS_1 as d2 apply d1 + d2); + Description: Apply operation fails on semantic run + """ + code = "GH_609" + number_inputs = 1 + references_names = ["1"] + + self.BaseTest(code=code, number_inputs=number_inputs, references_names=references_names) + class AggregateTests(SemanticHelper): """ """