vtlengine 1.0.1__tar.gz → 1.0.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of vtlengine might be problematic. Click here for more details.

Files changed (59) hide show
  1. {vtlengine-1.0.1 → vtlengine-1.0.2}/PKG-INFO +14 -5
  2. {vtlengine-1.0.1 → vtlengine-1.0.2}/README.md +8 -1
  3. {vtlengine-1.0.1 → vtlengine-1.0.2}/pyproject.toml +22 -12
  4. {vtlengine-1.0.1 → vtlengine-1.0.2}/src/vtlengine/API/_InternalApi.py +9 -5
  5. {vtlengine-1.0.1 → vtlengine-1.0.2}/src/vtlengine/API/__init__.py +1 -1
  6. {vtlengine-1.0.1 → vtlengine-1.0.2}/src/vtlengine/AST/ASTConstructorModules/Expr.py +96 -5
  7. {vtlengine-1.0.1 → vtlengine-1.0.2}/src/vtlengine/AST/ASTConstructorModules/ExprComponents.py +76 -2
  8. {vtlengine-1.0.1 → vtlengine-1.0.2}/src/vtlengine/AST/ASTTemplate.py +16 -0
  9. {vtlengine-1.0.1 → vtlengine-1.0.2}/src/vtlengine/AST/Grammar/Vtl.g4 +49 -20
  10. {vtlengine-1.0.1 → vtlengine-1.0.2}/src/vtlengine/AST/Grammar/VtlTokens.g4 +13 -1
  11. vtlengine-1.0.2/src/vtlengine/AST/Grammar/lexer.py +2139 -0
  12. {vtlengine-1.0.1 → vtlengine-1.0.2}/src/vtlengine/AST/Grammar/parser.py +5758 -3939
  13. {vtlengine-1.0.1 → vtlengine-1.0.2}/src/vtlengine/AST/Grammar/tokens.py +12 -0
  14. {vtlengine-1.0.1 → vtlengine-1.0.2}/src/vtlengine/AST/VtlVisitor.py +9 -1
  15. {vtlengine-1.0.1 → vtlengine-1.0.2}/src/vtlengine/AST/__init__.py +19 -0
  16. {vtlengine-1.0.1 → vtlengine-1.0.2}/src/vtlengine/DataTypes/TimeHandling.py +2 -0
  17. {vtlengine-1.0.1 → vtlengine-1.0.2}/src/vtlengine/Exceptions/__init__.py +44 -0
  18. {vtlengine-1.0.1 → vtlengine-1.0.2}/src/vtlengine/Exceptions/messages.py +16 -8
  19. {vtlengine-1.0.1 → vtlengine-1.0.2}/src/vtlengine/Interpreter/__init__.py +52 -26
  20. {vtlengine-1.0.1 → vtlengine-1.0.2}/src/vtlengine/Model/__init__.py +7 -0
  21. {vtlengine-1.0.1 → vtlengine-1.0.2}/src/vtlengine/Operators/Analytic.py +53 -21
  22. {vtlengine-1.0.1 → vtlengine-1.0.2}/src/vtlengine/Operators/Boolean.py +1 -1
  23. {vtlengine-1.0.1 → vtlengine-1.0.2}/src/vtlengine/Operators/Conditional.py +143 -2
  24. {vtlengine-1.0.1 → vtlengine-1.0.2}/src/vtlengine/Operators/Numeric.py +40 -2
  25. {vtlengine-1.0.1 → vtlengine-1.0.2}/src/vtlengine/Operators/Time.py +134 -0
  26. {vtlengine-1.0.1 → vtlengine-1.0.2}/src/vtlengine/Utils/__init__.py +37 -1
  27. {vtlengine-1.0.1 → vtlengine-1.0.2}/src/vtlengine/files/parser/__init__.py +2 -0
  28. {vtlengine-1.0.1 → vtlengine-1.0.2}/src/vtlengine/files/parser/_time_checking.py +2 -0
  29. vtlengine-1.0.1/src/vtlengine/AST/Grammar/lexer.py +0 -2029
  30. {vtlengine-1.0.1 → vtlengine-1.0.2}/LICENSE.md +0 -0
  31. {vtlengine-1.0.1 → vtlengine-1.0.2}/src/vtlengine/AST/ASTConstructor.py +0 -0
  32. {vtlengine-1.0.1 → vtlengine-1.0.2}/src/vtlengine/AST/ASTConstructorModules/Terminals.py +0 -0
  33. {vtlengine-1.0.1 → vtlengine-1.0.2}/src/vtlengine/AST/ASTConstructorModules/__init__.py +0 -0
  34. {vtlengine-1.0.1 → vtlengine-1.0.2}/src/vtlengine/AST/ASTDataExchange.py +0 -0
  35. {vtlengine-1.0.1 → vtlengine-1.0.2}/src/vtlengine/AST/ASTEncoders.py +0 -0
  36. {vtlengine-1.0.1 → vtlengine-1.0.2}/src/vtlengine/AST/ASTVisitor.py +0 -0
  37. {vtlengine-1.0.1 → vtlengine-1.0.2}/src/vtlengine/AST/DAG/__init__.py +0 -0
  38. {vtlengine-1.0.1 → vtlengine-1.0.2}/src/vtlengine/AST/DAG/_words.py +0 -0
  39. {vtlengine-1.0.1 → vtlengine-1.0.2}/src/vtlengine/AST/Grammar/__init__.py +0 -0
  40. {vtlengine-1.0.1 → vtlengine-1.0.2}/src/vtlengine/DataTypes/NumericTypesHandling.py +0 -0
  41. {vtlengine-1.0.1 → vtlengine-1.0.2}/src/vtlengine/DataTypes/__init__.py +0 -0
  42. {vtlengine-1.0.1 → vtlengine-1.0.2}/src/vtlengine/Operators/Aggregation.py +0 -0
  43. {vtlengine-1.0.1 → vtlengine-1.0.2}/src/vtlengine/Operators/Assignment.py +0 -0
  44. {vtlengine-1.0.1 → vtlengine-1.0.2}/src/vtlengine/Operators/CastOperator.py +0 -0
  45. {vtlengine-1.0.1 → vtlengine-1.0.2}/src/vtlengine/Operators/Clause.py +0 -0
  46. {vtlengine-1.0.1 → vtlengine-1.0.2}/src/vtlengine/Operators/Comparison.py +0 -0
  47. {vtlengine-1.0.1 → vtlengine-1.0.2}/src/vtlengine/Operators/General.py +0 -0
  48. {vtlengine-1.0.1 → vtlengine-1.0.2}/src/vtlengine/Operators/HROperators.py +0 -0
  49. {vtlengine-1.0.1 → vtlengine-1.0.2}/src/vtlengine/Operators/Join.py +0 -0
  50. {vtlengine-1.0.1 → vtlengine-1.0.2}/src/vtlengine/Operators/RoleSetter.py +0 -0
  51. {vtlengine-1.0.1 → vtlengine-1.0.2}/src/vtlengine/Operators/Set.py +0 -0
  52. {vtlengine-1.0.1 → vtlengine-1.0.2}/src/vtlengine/Operators/String.py +0 -0
  53. {vtlengine-1.0.1 → vtlengine-1.0.2}/src/vtlengine/Operators/Validation.py +0 -0
  54. {vtlengine-1.0.1 → vtlengine-1.0.2}/src/vtlengine/Operators/__init__.py +0 -0
  55. {vtlengine-1.0.1 → vtlengine-1.0.2}/src/vtlengine/__init__.py +0 -0
  56. {vtlengine-1.0.1 → vtlengine-1.0.2}/src/vtlengine/files/__init__.py +0 -0
  57. {vtlengine-1.0.1 → vtlengine-1.0.2}/src/vtlengine/files/output/__init__.py +0 -0
  58. {vtlengine-1.0.1 → vtlengine-1.0.2}/src/vtlengine/files/output/_time_period_representation.py +0 -0
  59. {vtlengine-1.0.1 → vtlengine-1.0.2}/src/vtlengine/files/parser/_rfc_dialect.py +0 -0
@@ -1,12 +1,14 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: vtlengine
3
- Version: 1.0.1
3
+ Version: 1.0.2
4
4
  Summary: Run and Validate VTL Scripts
5
+ Home-page: https://github.com/Meaningful-Data/vtlengine
5
6
  License: AGPL-3.0
7
+ Keywords: vtl,sdmx,vtlengine,Validation and Transformation Language
6
8
  Author: MeaningfulData
7
9
  Author-email: info@meaningfuldata.eu
8
10
  Requires-Python: >=3.10,<4.0
9
- Classifier: Development Status :: 4 - Beta
11
+ Classifier: Development Status :: 5 - Production/Stable
10
12
  Classifier: Intended Audience :: Developers
11
13
  Classifier: Intended Audience :: Information Technology
12
14
  Classifier: Intended Audience :: Science/Research
@@ -16,20 +18,26 @@ Classifier: Programming Language :: Python :: 3.10
16
18
  Classifier: Programming Language :: Python :: 3.11
17
19
  Classifier: Programming Language :: Python :: 3.12
18
20
  Classifier: Programming Language :: Python :: 3.13
21
+ Classifier: Typing :: Typed
19
22
  Requires-Dist: antlr4-python3-runtime (==4.9.2)
20
23
  Requires-Dist: bottleneck (>=1.3.4,<2.0.0)
21
24
  Requires-Dist: duckdb (>=1.1.1,<2.0.0)
22
25
  Requires-Dist: networkx (>=2.8.8,<3.0.0)
23
- Requires-Dist: numba (>=0.60.0,<0.61.0)
24
26
  Requires-Dist: numexpr (>=2.9.0,<3.0.0)
25
27
  Requires-Dist: pandas (>=2.1.4,<3.0.0)
26
- Requires-Dist: pyarrow (>=17.0.0,<18.0.0)
27
28
  Requires-Dist: s3fs (>=2024.9.0,<2025.0.0)
28
29
  Requires-Dist: sqlglot (>=22.2.0,<23.0.0)
30
+ Project-URL: Repository, https://github.com/Meaningful-Data/vtlengine
29
31
  Description-Content-Type: text/markdown
30
32
 
31
33
  # VTL Engine
32
34
 
35
+ | | |
36
+ |---------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
37
+ | Testing | [![Testing](https://github.com/Meaningful-Data/vtlengine/actions/workflows/testing.yml/badge.svg)](https://github.com/Meaningful-Data/vtlengine/actions/workflows/testing.yml) |
38
+ | Package | [![PyPI Latest Release](https://img.shields.io/pypi/v/vtlengine.svg)](https://pypi.org/project/vtlengine/) |
39
+ | License | [![License - AGPL 3.0](https://img.shields.io/pypi/l/vtlengine.svg)](https://github.com/Meaningful-Data/vtlengine/blob/main/LICENSE.md) |
40
+
33
41
  ## Introduction
34
42
 
35
43
  The VTL Engine is a Python library for validating and running VTL scripts.
@@ -67,7 +75,8 @@ Any action with VTL requires the following elements as input:
67
75
  * **VTL Script**: Is the VTL to be executed, which includes the transformation scheme, as well as de
68
76
  User Defined Operators, Hierarchical Rulesets and Datapoint Rulesets. It is provided as a string
69
77
  or as a Path object to a vtl file.
70
- * **Data structures** : Provides the structure of the input artifacts of the VTL script, according to
78
+ * **Data structures** : Provides the structure of the input artifacts of the VTL script, according
79
+ to
71
80
  the VTL Information model. Given that the current version doesn't prescribe a standard format for
72
81
  providing the information, the VTL Engine is implementing a JSON format that can be found here.
73
82
  Data Structures can be provided as Dictionaries or as Paths to JSON files. It is possible to have
@@ -1,5 +1,11 @@
1
1
  # VTL Engine
2
2
 
3
+ | | |
4
+ |---------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
5
+ | Testing | [![Testing](https://github.com/Meaningful-Data/vtlengine/actions/workflows/testing.yml/badge.svg)](https://github.com/Meaningful-Data/vtlengine/actions/workflows/testing.yml) |
6
+ | Package | [![PyPI Latest Release](https://img.shields.io/pypi/v/vtlengine.svg)](https://pypi.org/project/vtlengine/) |
7
+ | License | [![License - AGPL 3.0](https://img.shields.io/pypi/l/vtlengine.svg)](https://github.com/Meaningful-Data/vtlengine/blob/main/LICENSE.md) |
8
+
3
9
  ## Introduction
4
10
 
5
11
  The VTL Engine is a Python library for validating and running VTL scripts.
@@ -37,7 +43,8 @@ Any action with VTL requires the following elements as input:
37
43
  * **VTL Script**: Is the VTL to be executed, which includes the transformation scheme, as well as de
38
44
  User Defined Operators, Hierarchical Rulesets and Datapoint Rulesets. It is provided as a string
39
45
  or as a Path object to a vtl file.
40
- * **Data structures** : Provides the structure of the input artifacts of the VTL script, according to
46
+ * **Data structures** : Provides the structure of the input artifacts of the VTL script, according
47
+ to
41
48
  the VTL Information model. Given that the current version doesn't prescribe a standard format for
42
49
  providing the information, the VTL Engine is implementing a JSON format that can be found here.
43
50
  Data Structures can be provided as Dictionaries or as Paths to JSON files. It is possible to have
@@ -1,32 +1,41 @@
1
1
  [tool.poetry]
2
2
  name = "vtlengine"
3
- version = "1.0.1"
3
+ version = "1.0.2"
4
4
  description = "Run and Validate VTL Scripts"
5
5
  authors = ["MeaningfulData <info@meaningfuldata.eu>"]
6
6
  license = "AGPL-3.0"
7
7
  readme = "README.md"
8
+
8
9
  classifiers = [
9
- "Development Status :: 4 - Beta",
10
+ "Development Status :: 5 - Production/Stable",
10
11
  "Intended Audience :: Developers",
11
12
  "Intended Audience :: Information Technology",
12
13
  "Intended Audience :: Science/Research",
14
+ "Typing :: Typed"
13
15
  ]
14
16
 
17
+ keywords = ['vtl', 'sdmx', 'vtlengine', 'Validation and Transformation Language']
18
+ repository = 'https://github.com/Meaningful-Data/vtlengine'
19
+
20
+ [project.urls]
21
+ BugTracker = 'https://github.com/Meaningful-Data/vtlengine/issues'
22
+ Documentation = 'https://docs.vtlengine.meaningfuldata.eu'
23
+ SourceCode = 'https://github.com/Meaningful-Data/vtlengine'
24
+
15
25
  [tool.poetry.dependencies]
16
26
  python = "^3.10"
17
27
  # PyPi dependencies
18
- duckdb="^1.1.1"
19
- numba="^0.60.0"
20
- s3fs="^2024.9.0"
21
- pyarrow = "^17.0.0"
28
+ duckdb = "^1.1.1"
29
+ #numba = "^0.60.0"
30
+ s3fs = "^2024.9.0"
22
31
 
23
32
  # APT dependencies
24
- antlr4-python3-runtime="4.9.2"
25
- networkx="^2.8.8"
26
- numexpr="^2.9.0"
27
- pandas="^2.1.4"
28
- bottleneck="^1.3.4"
29
- sqlglot="^22.2.0"
33
+ antlr4-python3-runtime = "4.9.2"
34
+ networkx = "^2.8.8"
35
+ numexpr = "^2.9.0"
36
+ pandas = "^2.1.4"
37
+ bottleneck = "^1.3.4"
38
+ sqlglot = "^22.2.0"
30
39
 
31
40
  [tool.poetry.dev-dependencies]
32
41
  pytest = "^7.3"
@@ -39,6 +48,7 @@ black = "^24.8.0"
39
48
  mypy = "^1.11.2"
40
49
  pandas-stubs = "^2.2.3.241009"
41
50
  stubs = "^1.0.0"
51
+ toml = "^0.10.2"
42
52
 
43
53
  [tool.black]
44
54
  line_length = 100
@@ -8,7 +8,9 @@ from s3fs import S3FileSystem # type: ignore[import-untyped]
8
8
 
9
9
  from vtlengine.AST import PersistentAssignment, Start
10
10
  from vtlengine.DataTypes import SCALAR_TYPES
11
- from vtlengine.Model import ValueDomain, Dataset, Scalar, Component, Role, ExternalRoutine
11
+ from vtlengine.Exceptions import check_key
12
+ from vtlengine.Model import (ValueDomain, Dataset, Scalar, Component, Role,
13
+ ExternalRoutine, Role_keys)
12
14
  from vtlengine.files.parser import _validate_pandas, _fill_dataset_empty_data
13
15
 
14
16
  base_path = Path(__file__).parent
@@ -30,15 +32,17 @@ def _load_dataset_from_structure(structures: Dict[str, Any]) -> Dict[str, Any]:
30
32
  if "datasets" in structures:
31
33
  for dataset_json in structures["datasets"]:
32
34
  dataset_name = dataset_json["name"]
33
- components = {
34
- component["name"]: Component(
35
+ components = {}
36
+
37
+ for component in dataset_json["DataStructure"]:
38
+ check_key("data_type", SCALAR_TYPES.keys(), component["type"])
39
+ check_key("role", Role_keys, component["role"])
40
+ components[component["name"]] = Component(
35
41
  name=component["name"],
36
42
  data_type=SCALAR_TYPES[component["type"]],
37
43
  role=Role(component["role"]),
38
44
  nullable=component["nullable"],
39
45
  )
40
- for component in dataset_json["DataStructure"]
41
- }
42
46
 
43
47
  datasets[dataset_name] = Dataset(name=dataset_name, components=components, data=None)
44
48
  if "scalars" in structures:
@@ -78,7 +78,7 @@ def create_ast(text: str) -> Start:
78
78
  stream = _lexer(text)
79
79
  cst = _parser(stream)
80
80
  visitor = ASTVisitor()
81
- ast = visitor.visit(cst)
81
+ ast = visitor.visitStart(cst)
82
82
  DAGAnalyzer.createDAG(ast)
83
83
  return ast
84
84
 
@@ -1,5 +1,6 @@
1
1
  import re
2
2
  from copy import copy
3
+ from typing import Any
3
4
 
4
5
  from antlr4.tree.Tree import TerminalNodeImpl
5
6
 
@@ -25,6 +26,8 @@ from vtlengine.AST import (
25
26
  Analytic,
26
27
  Windowing,
27
28
  VarID,
29
+ Case,
30
+ CaseObj,
28
31
  )
29
32
  from vtlengine.AST.ASTConstructorModules.ExprComponents import ExprComp
30
33
  from vtlengine.AST.ASTConstructorModules.Terminals import Terminals
@@ -59,6 +62,7 @@ class Expr(VtlVisitor):
59
62
  | left=expr op=AND right=expr # booleanExpr # noqa E501
60
63
  | left=expr op=(OR|XOR) right=expr # booleanExpr # noqa E501
61
64
  | IF conditionalExpr=expr THEN thenExpr=expr ELSE elseExpr=expr # ifExpr # noqa E501
65
+ | CASE WHEN expr THEN expr ELSE expr END # caseExpr # noqa E501
62
66
  | constant # constantExpr # noqa E501
63
67
  | varID # varIdExpr # noqa E501
64
68
  ;
@@ -115,6 +119,26 @@ class Expr(VtlVisitor):
115
119
 
116
120
  return if_node
117
121
 
122
+ # CASE WHEN expr THEN expr ELSE expr END # caseExpr
123
+ elif isinstance(c, TerminalNodeImpl) and (c.getSymbol().type == Parser.CASE):
124
+
125
+ if len(ctx_list) % 4 != 3:
126
+ raise ValueError("Syntax error.")
127
+
128
+ else_node = self.visitExpr(ctx_list[-1])
129
+ ctx_list = ctx_list[1:-2]
130
+ cases = []
131
+
132
+ for i in range(0, len(ctx_list), 4):
133
+ condition = self.visitExpr(ctx_list[i + 1])
134
+ thenOp = self.visitExpr(ctx_list[i + 3])
135
+ case_obj = CaseObj(condition, thenOp)
136
+ cases.append(case_obj)
137
+
138
+ case_node = Case(cases, else_node)
139
+
140
+ return case_node
141
+
118
142
  # constant
119
143
  elif isinstance(ctx, Parser.ConstantExprContext):
120
144
  return Terminals().visitConstant(c)
@@ -755,7 +779,8 @@ class Expr(VtlVisitor):
755
779
 
756
780
  def visitTimeFunctions(self, ctx: Parser.TimeFunctionsContext):
757
781
  if isinstance(ctx, Parser.PeriodAtomContext):
758
- return self.visitPeriodAtom(ctx)
782
+ # return self.visitPeriodAtom(ctx)
783
+ return self.visitTimeUnaryAtom(ctx)
759
784
  elif isinstance(ctx, Parser.FillTimeAtomContext):
760
785
  return self.visitFillTimeAtom(ctx)
761
786
  elif isinstance(ctx, Parser.FlowAtomContext):
@@ -766,13 +791,30 @@ class Expr(VtlVisitor):
766
791
  return self.visitTimeAggAtom(ctx)
767
792
  elif isinstance(ctx, Parser.CurrentDateAtomContext):
768
793
  return self.visitCurrentDateAtom(ctx)
794
+ elif isinstance(ctx, Parser.DateDiffAtomContext):
795
+ return self.visitTimeDiffAtom(ctx)
796
+ elif isinstance(ctx, Parser.DateAddAtomContext):
797
+ return self.visitTimeAddAtom(ctx)
798
+ elif isinstance(ctx, Parser.YearAtomContext):
799
+ return self.visitTimeUnaryAtom(ctx)
800
+ elif isinstance(ctx, Parser.MonthAtomContext):
801
+ return self.visitTimeUnaryAtom(ctx)
802
+ elif isinstance(ctx, Parser.DayOfMonthAtomContext):
803
+ return self.visitTimeUnaryAtom(ctx)
804
+ elif isinstance(ctx, Parser.DayOfYearAtomContext):
805
+ return self.visitTimeUnaryAtom(ctx)
806
+ elif isinstance(ctx, Parser.DayToYearAtomContext):
807
+ return self.visitTimeUnaryAtom(ctx)
808
+ elif isinstance(ctx, Parser.DayToMonthAtomContext):
809
+ return self.visitTimeUnaryAtom(ctx)
810
+ elif isinstance(ctx, Parser.YearTodayAtomContext):
811
+ return self.visitTimeUnaryAtom(ctx)
812
+ elif isinstance(ctx, Parser.MonthTodayAtomContext):
813
+ return self.visitTimeUnaryAtom(ctx)
769
814
  else:
770
815
  raise NotImplementedError
771
816
 
772
- def visitPeriodAtom(self, ctx: Parser.PeriodAtomContext):
773
- """
774
- periodExpr: PERIOD_INDICATOR '(' expr? ')' ;
775
- """
817
+ def visitTimeUnaryAtom(self, ctx: Any):
776
818
  ctx_list = list(ctx.getChildren())
777
819
  c = ctx_list[0]
778
820
 
@@ -789,6 +831,26 @@ class Expr(VtlVisitor):
789
831
 
790
832
  return UnaryOp(op=op, operand=operand_node[0])
791
833
 
834
+ # def visitPeriodAtom(self, ctx: Parser.PeriodAtomContext):
835
+ # """
836
+ # periodExpr: PERIOD_INDICATOR '(' expr? ')' ;
837
+ # """
838
+ # ctx_list = list(ctx.getChildren())
839
+ # c = ctx_list[0]
840
+ #
841
+ # op = c.getSymbol().text
842
+ # operand_node = [
843
+ # self.visitExpr(operand)
844
+ # for operand in ctx_list
845
+ # if isinstance(operand, Parser.ExprContext)
846
+ # ]
847
+ #
848
+ # if len(operand_node) == 0:
849
+ # # AST_ASTCONSTRUCTOR.15
850
+ # raise NotImplementedError
851
+ #
852
+ # return UnaryOp(op=op, operand=operand_node[0])
853
+
792
854
  def visitTimeShiftAtom(self, ctx: Parser.TimeShiftAtomContext):
793
855
  """
794
856
  timeShiftExpr: TIMESHIFT '(' expr ',' INTEGER_CONSTANT ')' ;
@@ -872,6 +934,35 @@ class Expr(VtlVisitor):
872
934
  c = list(ctx.getChildren())[0]
873
935
  return MulOp(op=c.getSymbol().text, children=[])
874
936
 
937
+ def visitTimeDiffAtom(self, ctx: Parser.TimeShiftAtomContext):
938
+ """ """
939
+ ctx_list = list(ctx.getChildren())
940
+ c = ctx_list[0]
941
+
942
+ op = c.getSymbol().text
943
+ left_node = self.visitExpr(ctx_list[2])
944
+ right_node = self.visitExpr(ctx_list[4])
945
+
946
+ return BinOp(left=left_node, op=op, right=right_node)
947
+
948
+ def visitTimeAddAtom(self, ctx: Parser.TimeShiftAtomContext):
949
+ """ """
950
+
951
+ ctx_list = list(ctx.getChildren())
952
+ c = ctx_list[0]
953
+
954
+ op = c.getSymbol().text
955
+ children_node = [self.visitExpr(ctx_list[2])]
956
+
957
+ param_constant_node = []
958
+
959
+ if len(ctx_list) > 4:
960
+ param_constant_node = [self.visitExpr(ctx_list[4])]
961
+ if len(ctx_list) > 6:
962
+ param_constant_node.append(self.visitExpr(ctx_list[6]))
963
+
964
+ return ParamOp(op=op, children=children_node, params=param_constant_node)
965
+
875
966
  """
876
967
  -----------------------------------
877
968
  Conditional Functions
@@ -16,6 +16,8 @@ from vtlengine.AST import (
16
16
  VarID,
17
17
  Analytic,
18
18
  UDOCall,
19
+ Case,
20
+ CaseObj,
19
21
  )
20
22
  from vtlengine.AST.ASTConstructorModules.Terminals import Terminals
21
23
  from vtlengine.AST.Grammar.parser import Parser
@@ -87,6 +89,10 @@ class ExprComp(VtlVisitor):
87
89
  elif isinstance(ctx, Parser.IfExprCompContext):
88
90
  return self.visitIfExprComp(ctx)
89
91
 
92
+ # CASE WHEN conditionalExpr=expr THEN thenExpr=expr ELSE elseExpr=expr END # caseExpr
93
+ elif isinstance(ctx, Parser.CaseExprCompContext):
94
+ return self.visitCaseExprComp(ctx)
95
+
90
96
  # constant
91
97
  elif isinstance(ctx, Parser.ConstantExprCompContext):
92
98
  return Terminals().visitConstant(c)
@@ -169,6 +175,26 @@ class ExprComp(VtlVisitor):
169
175
 
170
176
  return if_node
171
177
 
178
+ def visitCaseExprComp(self, ctx: Parser.CaseExprCompContext):
179
+ ctx_list = list(ctx.getChildren())
180
+
181
+ if len(ctx_list) % 4 != 3:
182
+ raise ValueError("Syntax error.")
183
+
184
+ else_node = self.visitExprComponent(ctx_list[-1])
185
+ ctx_list = ctx_list[1:-2]
186
+ cases = []
187
+
188
+ for i in range(0, len(ctx_list), 4):
189
+ condition = self.visitExprComponent(ctx_list[i + 1])
190
+ thenOp = self.visitExprComponent(ctx_list[i + 3])
191
+ case_obj = CaseObj(condition, thenOp)
192
+ cases.append(case_obj)
193
+
194
+ case_node = Case(cases, else_node)
195
+
196
+ return case_node
197
+
172
198
  def visitOptionalExprComponent(self, ctx: Parser.OptionalExprComponentContext):
173
199
  """
174
200
  optionalExpr: expr
@@ -541,7 +567,7 @@ class ExprComp(VtlVisitor):
541
567
 
542
568
  def visitTimeFunctionsComponents(self, ctx: Parser.TimeFunctionsComponentsContext):
543
569
  if isinstance(ctx, Parser.PeriodAtomComponentContext):
544
- return self.visitPeriodAtomComponent(ctx)
570
+ return self.visitTimeUnaryAtomComponent(ctx)
545
571
  elif isinstance(ctx, Parser.FillTimeAtomComponentContext):
546
572
  return self.visitFillTimeAtomComponent(ctx)
547
573
  elif isinstance(ctx, Parser.FlowAtomComponentContext):
@@ -552,10 +578,30 @@ class ExprComp(VtlVisitor):
552
578
  return self.visitTimeAggAtomComponent(ctx)
553
579
  elif isinstance(ctx, Parser.CurrentDateAtomComponentContext):
554
580
  return self.visitCurrentDateAtomComponent(ctx)
581
+ elif isinstance(ctx, Parser.DateDiffAtomComponentContext):
582
+ return self.visitDateAddAtomComponentContext(ctx)
583
+ elif isinstance(ctx, Parser.DateAddAtomComponentContext):
584
+ return self.visitDateAddAtomComponentContext(ctx)
585
+ elif isinstance(ctx, Parser.YearAtomComponentContext):
586
+ return self.visitTimeUnaryAtomComponent(ctx)
587
+ elif isinstance(ctx, Parser.MonthAtomComponentContext):
588
+ return self.visitTimeUnaryAtomComponent(ctx)
589
+ elif isinstance(ctx, Parser.DayOfMonthAtomComponentContext):
590
+ return self.visitTimeUnaryAtomComponent(ctx)
591
+ elif isinstance(ctx, Parser.DayOfYearAtomComponentContext):
592
+ return self.visitTimeUnaryAtomComponent(ctx)
593
+ elif isinstance(ctx, Parser.DayToYearAtomComponentContext):
594
+ return self.visitTimeUnaryAtomComponent(ctx)
595
+ elif isinstance(ctx, Parser.DayToMonthAtomComponentContext):
596
+ return self.visitTimeUnaryAtomComponent(ctx)
597
+ elif isinstance(ctx, Parser.YearToDayAtomComponentContext):
598
+ return self.visitTimeUnaryAtomComponent(ctx)
599
+ elif isinstance(ctx, Parser.MonthToDayAtomComponentContext):
600
+ return self.visitTimeUnaryAtomComponent(ctx)
555
601
  else:
556
602
  raise NotImplementedError
557
603
 
558
- def visitPeriodAtomComponent(self, ctx: Parser.PeriodAtomComponentContext):
604
+ def visitTimeUnaryAtomComponent(self, ctx: Parser.PeriodAtomComponentContext):
559
605
  """
560
606
  periodExpr: PERIOD_INDICATOR '(' expr? ')' ;
561
607
  """
@@ -653,6 +699,34 @@ class ExprComp(VtlVisitor):
653
699
  c = list(ctx.getChildren())[0]
654
700
  return MulOp(op=c.getSymbol().text, children=[])
655
701
 
702
+ def visitDateDiffAtomComponent(self, ctx: Parser.TimeShiftAtomComponentContext):
703
+ """ """
704
+ ctx_list = list(ctx.getChildren())
705
+ c = ctx_list[0]
706
+
707
+ op = c.getSymbol().text
708
+ left_node = self.visitExprComponent(ctx_list[2])
709
+ right_node = Constant("INTEGER_CONSTANT", int(ctx_list[4].getSymbol().text))
710
+
711
+ return BinOp(left=left_node, op=op, right=right_node)
712
+
713
+ def visitDateAddAtomComponentContext(self, ctx: Parser.DateAddAtomComponentContext):
714
+ """ """
715
+ ctx_list = list(ctx.getChildren())
716
+ c = ctx_list[0]
717
+
718
+ op = c.getSymbol().text
719
+ children_node = [self.visitExprComponent(ctx_list[2])]
720
+
721
+ param_constant_node = []
722
+
723
+ if len(ctx_list) > 4:
724
+ param_constant_node = [self.visitExprComponent(ctx_list[4])]
725
+ if len(ctx_list) > 6:
726
+ param_constant_node.append(self.visitExprComponent(ctx_list[6]))
727
+
728
+ return ParamOp(op=op, children=children_node, params=param_constant_node)
729
+
656
730
  """
657
731
  -----------------------------------
658
732
  Conditional Functions
@@ -314,6 +314,22 @@ class ASTTemplate(NodeVisitor):
314
314
  self.visit(node.thenOp)
315
315
  self.visit(node.elseOp)
316
316
 
317
+ def visit_Case(self, node: AST.Case) -> Any:
318
+ """
319
+ Case: (conditions, thenOp, elseOp)
320
+
321
+ Basic usage:
322
+
323
+ for condition in node.conditions:
324
+ self.visit(condition)
325
+ self.visit(node.thenOp)
326
+ self.visit(node.elseOp)
327
+ """
328
+ for case in node.cases:
329
+ self.visit(case.condition)
330
+ self.visit(case.thenOp)
331
+ self.visit(node.elseOp)
332
+
317
333
  def visit_Validation(self, node: AST.Validation) -> Any:
318
334
  """
319
335
  Validation: (op, validation, params, inbalance, invalid)
@@ -21,30 +21,33 @@ expr:
21
21
  | op=(PLUS|MINUS|NOT) right=expr # unaryExpr
22
22
  | left=expr op=(MUL|DIV) right=expr # arithmeticExpr
23
23
  | left=expr op=(PLUS|MINUS|CONCAT) right=expr # arithmeticExprOrConcat
24
- | left=expr op=comparisonOperand right=expr # comparisonExpr
24
+ | left=expr op=comparisonOperand right=expr # comparisonExpr
25
25
  | left=expr op=(IN|NOT_IN)(lists|valueDomainID) # inNotInExpr
26
26
  | left=expr op=AND right=expr # booleanExpr
27
27
  | left=expr op=(OR|XOR) right=expr # booleanExpr
28
28
  | IF conditionalExpr=expr THEN thenExpr=expr ELSE elseExpr=expr # ifExpr
29
+ | CASE (WHEN expr THEN expr)+ ELSE expr # caseExpr
29
30
  | constant # constantExpr
30
31
  | varID # varIdExpr
31
32
 
33
+
32
34
  ;
33
35
 
34
36
 
35
37
  exprComponent:
36
- LPAREN exprComponent RPAREN # parenthesisExprComp
37
- | functionsComponents # functionsExpressionComp
38
- | op=(PLUS|MINUS|NOT) right=exprComponent # unaryExprComp
39
- | left=exprComponent op=(MUL|DIV) right=exprComponent # arithmeticExprComp
40
- | left=exprComponent op=(PLUS|MINUS|CONCAT) right=exprComponent # arithmeticExprOrConcatComp
41
- | left=exprComponent comparisonOperand right=exprComponent # comparisonExprComp
42
- | left=exprComponent op=(IN|NOT_IN)(lists|valueDomainID) # inNotInExprComp
43
- | left=exprComponent op=AND right=exprComponent # booleanExprComp
44
- | left=exprComponent op=(OR|XOR) right=exprComponent # booleanExprComp
45
- | IF conditionalExpr=exprComponent THEN thenExpr=exprComponent ELSE elseExpr=exprComponent # ifExprComp
46
- | constant # constantExprComp
47
- | componentID # compId
38
+ LPAREN exprComponent RPAREN # parenthesisExprComp
39
+ | functionsComponents # functionsExpressionComp
40
+ | op=(PLUS|MINUS|NOT) right=exprComponent # unaryExprComp
41
+ | left=exprComponent op=(MUL|DIV) right=exprComponent # arithmeticExprComp
42
+ | left=exprComponent op=(PLUS|MINUS|CONCAT) right=exprComponent # arithmeticExprOrConcatComp
43
+ | left=exprComponent comparisonOperand right=exprComponent # comparisonExprComp
44
+ | left=exprComponent op=(IN|NOT_IN)(lists|valueDomainID) # inNotInExprComp
45
+ | left=exprComponent op=AND right=exprComponent # booleanExprComp
46
+ | left=exprComponent op=(OR|XOR) right=exprComponent # booleanExprComp
47
+ | IF conditionalExpr=exprComponent THEN thenExpr=exprComponent ELSE elseExpr=exprComponent # ifExprComp
48
+ | CASE (WHEN exprComponent THEN exprComponent)+ ELSE exprComponent # caseExprComp
49
+ | constant # constantExprComp
50
+ | componentID # compId
48
51
  ;
49
52
 
50
53
  functionsComponents:
@@ -84,6 +87,7 @@ datasetClause:
84
87
  | calcClause
85
88
  | keepOrDropClause
86
89
  | pivotOrUnpivotClause
90
+ /* | customPivotClause */
87
91
  | subspaceClause
88
92
  ;
89
93
 
@@ -112,6 +116,10 @@ pivotOrUnpivotClause:
112
116
  op=(PIVOT|UNPIVOT) id_=componentID COMMA mea=componentID
113
117
  ;
114
118
 
119
+ customPivotClause:
120
+ CUSTOMPIVOT id_=componentID COMMA mea=componentID IN constant (COMMA constant)*
121
+ ;
122
+
115
123
  subspaceClause:
116
124
  SUBSPACE subspaceClauseItem (COMMA subspaceClauseItem)*
117
125
  ;
@@ -138,7 +146,7 @@ defOperators:
138
146
  /*---------------------------------------------------FUNCTIONS-------------------------------------------------*/
139
147
  genericOperators:
140
148
  operatorID LPAREN (parameter (COMMA parameter)*)? RPAREN # callDataset
141
- | EVAL LPAREN routineName LPAREN (varID|scalarItem)? (COMMA (varID|scalarItem))* RPAREN (LANGUAGE STRING_CONSTANT)? (RETURNS evalDatasetType)? RPAREN # evalAtom
149
+ | EVAL LPAREN routineName LPAREN (varID|scalarItem)? (COMMA (varID|scalarItem))* RPAREN (LANGUAGE STRING_CONSTANT)? (RETURNS evalDatasetType)? RPAREN # evalAtom
142
150
  | CAST LPAREN expr COMMA (basicScalarType|valueDomainName) (COMMA STRING_CONSTANT)? RPAREN # castExprDataset
143
151
  ;
144
152
 
@@ -149,6 +157,7 @@ genericOperatorsComponent:
149
157
 
150
158
  ;
151
159
 
160
+
152
161
  parameterComponent:
153
162
  exprComponent
154
163
  | OPTIONAL
@@ -176,13 +185,13 @@ stringOperatorsComponent:
176
185
  numericOperators:
177
186
  op=(CEIL | FLOOR | ABS | EXP | LN | SQRT) LPAREN expr RPAREN # unaryNumeric
178
187
  | op=(ROUND | TRUNC) LPAREN expr (COMMA optionalExpr)? RPAREN # unaryWithOptionalNumeric
179
- | op=(MOD | POWER|LOG) LPAREN left=expr COMMA right=expr RPAREN # binaryNumeric
188
+ | op=(MOD | POWER | LOG | RANDOM) LPAREN left=expr COMMA right=expr RPAREN # binaryNumeric
180
189
  ;
181
190
 
182
191
  numericOperatorsComponent:
183
- op=(CEIL | FLOOR | ABS | EXP | LN | SQRT) LPAREN exprComponent RPAREN # unaryNumericComponent
184
- | op=(ROUND | TRUNC) LPAREN exprComponent (COMMA optionalExprComponent)? RPAREN # unaryWithOptionalNumericComponent
185
- | op=(MOD | POWER | LOG) LPAREN left=exprComponent COMMA right=exprComponent RPAREN # binaryNumericComponent
192
+ op=(CEIL | FLOOR | ABS | EXP | LN | SQRT) LPAREN exprComponent RPAREN # unaryNumericComponent
193
+ | op=(ROUND | TRUNC) LPAREN exprComponent (COMMA optionalExprComponent)? RPAREN # unaryWithOptionalNumericComponent
194
+ | op=(MOD | POWER | LOG | RANDOM) LPAREN left=exprComponent COMMA right=exprComponent RPAREN # binaryNumericComponent
186
195
  ;
187
196
 
188
197
  comparisonOperators:
@@ -205,6 +214,16 @@ timeOperators:
205
214
  | TIMESHIFT LPAREN expr COMMA signedInteger RPAREN # timeShiftAtom
206
215
  | TIME_AGG LPAREN periodIndTo=STRING_CONSTANT (COMMA periodIndFrom=(STRING_CONSTANT| OPTIONAL ))? (COMMA op=optionalExpr)? (COMMA (FIRST|LAST))? RPAREN # timeAggAtom
207
216
  | CURRENT_DATE LPAREN RPAREN # currentDateAtom
217
+ | DATEDIFF LPAREN dateFrom=expr COMMA dateTo=expr RPAREN # dateDiffAtom
218
+ | DATEADD LPAREN op=expr COMMA shiftNumber=expr COMMA periodInd=expr RPAREN # dateAddAtom
219
+ | YEAR_OP LPAREN expr RPAREN # yearAtom
220
+ | MONTH_OP LPAREN expr RPAREN # monthAtom
221
+ | DAYOFMONTH LPAREN expr RPAREN # dayOfMonthAtom
222
+ | DAYOFYEAR LPAREN expr RPAREN # datOfYearAtom
223
+ | DAYTOYEAR LPAREN expr RPAREN # dayToYearAtom
224
+ | DAYTOMONTH LPAREN expr RPAREN # dayToMonthAtom
225
+ | YEARTODAY LPAREN expr RPAREN # yearTodayAtom
226
+ | MONTHTODAY LPAREN expr RPAREN # monthTodayAtom
208
227
  ;
209
228
 
210
229
  timeOperatorsComponent:
@@ -213,7 +232,17 @@ timeOperatorsComponent:
213
232
  | op=(FLOW_TO_STOCK | STOCK_TO_FLOW) LPAREN exprComponent RPAREN # flowAtomComponent
214
233
  | TIMESHIFT LPAREN exprComponent COMMA signedInteger RPAREN # timeShiftAtomComponent
215
234
  | TIME_AGG LPAREN periodIndTo=STRING_CONSTANT (COMMA periodIndFrom=(STRING_CONSTANT| OPTIONAL ))? (COMMA op=optionalExprComponent)? (COMMA (FIRST|LAST))? RPAREN # timeAggAtomComponent
216
- | CURRENT_DATE LPAREN RPAREN # currentDateAtomComponent
235
+ | CURRENT_DATE LPAREN RPAREN # currentDateAtomComponent
236
+ | DATEDIFF LPAREN dateFrom=exprComponent COMMA dateTo=exprComponent RPAREN # dateDiffAtomComponent
237
+ | DATEADD LPAREN op=exprComponent COMMA shiftNumber=exprComponent COMMA periodInd=exprComponent RPAREN # dateAddAtomComponent
238
+ | YEAR_OP LPAREN exprComponent RPAREN # yearAtomComponent
239
+ | MONTH_OP LPAREN exprComponent RPAREN # monthAtomComponent
240
+ | DAYOFMONTH LPAREN exprComponent RPAREN # dayOfMonthAtomComponent
241
+ | DAYOFYEAR LPAREN exprComponent RPAREN # datOfYearAtomComponent
242
+ | DAYTOYEAR LPAREN exprComponent RPAREN # dayToYearAtomComponent
243
+ | DAYTOMONTH LPAREN exprComponent RPAREN # dayToMonthAtomComponent
244
+ | YEARTODAY LPAREN exprComponent RPAREN # yearTodayAtomComponent
245
+ | MONTHTODAY LPAREN exprComponent RPAREN # monthTodayAtomComponent
217
246
  ;
218
247
 
219
248
  setOperators:
@@ -284,7 +313,7 @@ aggrOperatorsGrouping:
284
313
  | FIRST_VALUE
285
314
  | LAST_VALUE)
286
315
  LPAREN expr OVER LPAREN (partition=partitionByClause? orderBy=orderByClause? windowing=windowingClause?)RPAREN RPAREN #anSimpleFunction
287
- | op=(LAG |LEAD) LPAREN expr (COMMA offet=signedInteger(COMMA defaultValue=scalarItem)?)? OVER LPAREN (partition=partitionByClause? orderBy=orderByClause) RPAREN RPAREN # lagOrLeadAn
316
+ | op=(LAG |LEAD) LPAREN expr (COMMA offset=signedInteger(COMMA defaultValue=scalarItem)?)? OVER LPAREN (partition=partitionByClause? orderBy=orderByClause) RPAREN RPAREN # lagOrLeadAn
288
317
  | op=RATIO_TO_REPORT LPAREN expr OVER LPAREN (partition=partitionByClause) RPAREN RPAREN # ratioToReportAn
289
318
  ;
290
319