pylegend 0.3.0__py3-none-any.whl → 0.5.0__py3-none-any.whl

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.
Files changed (124) hide show
  1. pylegend/__init__.py +16 -6
  2. pylegend/core/{databse → database}/sql_to_string/__init__.py +3 -3
  3. pylegend/core/{databse → database}/sql_to_string/db_extension.py +14 -5
  4. pylegend/core/{databse → database}/sql_to_string/generator.py +2 -2
  5. pylegend/core/language/__init__.py +12 -10
  6. pylegend/core/language/legacy_api/__init__.py +13 -0
  7. pylegend/core/language/{aggregate_specification.py → legacy_api/aggregate_specification.py} +10 -10
  8. pylegend/core/language/legacy_api/legacy_api_tds_row.py +32 -0
  9. pylegend/core/language/legendql_api/__init__.py +13 -0
  10. pylegend/core/language/legendql_api/legendql_api_custom_expressions.py +541 -0
  11. pylegend/core/language/legendql_api/legendql_api_tds_row.py +292 -0
  12. pylegend/core/language/shared/__init__.py +13 -0
  13. pylegend/core/language/{column_expressions.py → shared/column_expressions.py} +32 -31
  14. pylegend/core/language/{expression.py → shared/expression.py} +8 -0
  15. pylegend/core/language/{functions.py → shared/functions.py} +12 -3
  16. pylegend/core/language/shared/helpers.py +75 -0
  17. pylegend/core/language/{literal_expressions.py → shared/literal_expressions.py} +39 -1
  18. pylegend/core/language/{operations → shared/operations}/binary_expression.py +34 -2
  19. pylegend/core/language/{operations → shared/operations}/boolean_operation_expressions.py +34 -6
  20. pylegend/core/language/{operations → shared/operations}/collection_operation_expressions.py +146 -26
  21. pylegend/core/language/{operations → shared/operations}/date_operation_expressions.py +288 -24
  22. pylegend/core/language/{operations → shared/operations}/float_operation_expressions.py +53 -8
  23. pylegend/core/language/{operations → shared/operations}/integer_operation_expressions.py +62 -9
  24. pylegend/core/language/{operations → shared/operations}/nullary_expression.py +9 -2
  25. pylegend/core/language/{operations → shared/operations}/number_operation_expressions.py +211 -30
  26. pylegend/core/language/shared/operations/primitive_operation_expressions.py +155 -0
  27. pylegend/core/language/{operations → shared/operations}/string_operation_expressions.py +194 -21
  28. pylegend/core/language/{operations → shared/operations}/unary_expression.py +10 -2
  29. pylegend/core/language/{primitive_collection.py → shared/primitive_collection.py} +2 -2
  30. pylegend/core/language/{primitives → shared/primitives}/__init__.py +9 -9
  31. pylegend/core/language/{primitives → shared/primitives}/boolean.py +9 -5
  32. pylegend/core/language/{primitives → shared/primitives}/date.py +60 -15
  33. pylegend/core/language/{primitives → shared/primitives}/datetime.py +4 -5
  34. pylegend/core/language/{primitives → shared/primitives}/float.py +6 -6
  35. pylegend/core/language/{primitives → shared/primitives}/integer.py +6 -6
  36. pylegend/core/language/{primitives → shared/primitives}/number.py +16 -13
  37. pylegend/core/language/{primitives → shared/primitives}/primitive.py +41 -5
  38. pylegend/core/language/{primitives → shared/primitives}/strictdate.py +4 -5
  39. pylegend/core/language/{primitives → shared/primitives}/string.py +18 -19
  40. pylegend/core/language/{tds_row.py → shared/tds_row.py} +46 -16
  41. pylegend/core/request/__init__.py +7 -1
  42. pylegend/core/request/auth.py +55 -1
  43. pylegend/core/request/legend_client.py +32 -0
  44. pylegend/core/sql/metamodel_extension.py +28 -0
  45. pylegend/core/tds/abstract/__init__.py +13 -0
  46. pylegend/core/tds/abstract/frames/__init__.py +13 -0
  47. pylegend/core/tds/{legend_api/frames/legend_api_applied_function_tds_frame.py → abstract/frames/applied_function_tds_frame.py} +19 -13
  48. pylegend/core/tds/abstract/frames/base_tds_frame.py +125 -0
  49. pylegend/core/tds/{legend_api/frames/legend_api_input_tds_frame.py → abstract/frames/input_tds_frame.py} +9 -12
  50. pylegend/core/tds/{legend_api/frames/functions → abstract}/function_helpers.py +1 -1
  51. pylegend/core/tds/{legend_api/frames/functions/concatenate_function.py → legacy_api/frames/functions/legacy_api_concatenate_function.py} +25 -13
  52. pylegend/core/tds/{legend_api/frames/functions/distinct_function.py → legacy_api/frames/functions/legacy_api_distinct_function.py} +13 -8
  53. pylegend/core/tds/{legend_api/frames/functions/drop_function.py → legacy_api/frames/functions/legacy_api_drop_function.py} +13 -8
  54. pylegend/core/tds/{legend_api/frames/functions/extend_function.py → legacy_api/frames/functions/legacy_api_extend_function.py} +36 -16
  55. pylegend/core/tds/{legend_api/frames/functions/filter_function.py → legacy_api/frames/functions/legacy_api_filter_function.py} +25 -13
  56. pylegend/core/tds/{legend_api/frames/functions/group_by_function.py → legacy_api/frames/functions/legacy_api_group_by_function.py} +44 -17
  57. pylegend/core/tds/{legend_api/frames/functions/head_function.py → legacy_api/frames/functions/legacy_api_head_function.py} +13 -8
  58. pylegend/core/tds/{legend_api/frames/functions/join_by_columns_function.py → legacy_api/frames/functions/legacy_api_join_by_columns_function.py} +40 -13
  59. pylegend/core/tds/{legend_api/frames/functions/join_function.py → legacy_api/frames/functions/legacy_api_join_function.py} +44 -20
  60. pylegend/core/tds/{legend_api/frames/functions/rename_columns_function.py → legacy_api/frames/functions/legacy_api_rename_columns_function.py} +20 -8
  61. pylegend/core/tds/{legend_api/frames/functions/restrict_function.py → legacy_api/frames/functions/legacy_api_restrict_function.py} +17 -8
  62. pylegend/core/tds/{legend_api/frames/functions/slice_function.py → legacy_api/frames/functions/legacy_api_slice_function.py} +13 -8
  63. pylegend/core/tds/{legend_api/frames/functions/sort_function.py → legacy_api/frames/functions/legacy_api_sort_function.py} +19 -8
  64. pylegend/core/tds/legacy_api/frames/legacy_api_applied_function_tds_frame.py +37 -0
  65. pylegend/core/tds/legacy_api/frames/legacy_api_base_tds_frame.py +204 -0
  66. pylegend/core/tds/legacy_api/frames/legacy_api_input_tds_frame.py +51 -0
  67. pylegend/core/tds/{legend_api/frames/legend_api_tds_frame.py → legacy_api/frames/legacy_api_tds_frame.py} +28 -28
  68. pylegend/core/tds/legendql_api/__init__.py +13 -0
  69. pylegend/core/tds/legendql_api/frames/__init__.py +13 -0
  70. pylegend/core/tds/legendql_api/frames/functions/__init__.py +13 -0
  71. pylegend/core/tds/legendql_api/frames/functions/legendql_api_asofjoin_function.py +156 -0
  72. pylegend/core/tds/legendql_api/frames/functions/legendql_api_concatenate_function.py +139 -0
  73. pylegend/core/tds/legendql_api/frames/functions/legendql_api_distinct_function.py +69 -0
  74. pylegend/core/tds/legendql_api/frames/functions/legendql_api_drop_function.py +74 -0
  75. pylegend/core/tds/legendql_api/frames/functions/legendql_api_extend_function.py +256 -0
  76. pylegend/core/tds/legendql_api/frames/functions/legendql_api_filter_function.py +121 -0
  77. pylegend/core/tds/legendql_api/frames/functions/legendql_api_function_helpers.py +137 -0
  78. pylegend/core/tds/legendql_api/frames/functions/legendql_api_groupby_function.py +256 -0
  79. pylegend/core/tds/legendql_api/frames/functions/legendql_api_head_function.py +74 -0
  80. pylegend/core/tds/legendql_api/frames/functions/legendql_api_join_function.py +214 -0
  81. pylegend/core/tds/legendql_api/frames/functions/legendql_api_project_function.py +169 -0
  82. pylegend/core/tds/legendql_api/frames/functions/legendql_api_rename_function.py +189 -0
  83. pylegend/core/tds/legendql_api/frames/functions/legendql_api_select_function.py +131 -0
  84. pylegend/core/tds/legendql_api/frames/functions/legendql_api_slice_function.py +82 -0
  85. pylegend/core/tds/legendql_api/frames/functions/legendql_api_sort_function.py +93 -0
  86. pylegend/core/tds/legendql_api/frames/functions/legendql_api_window_extend_function.py +283 -0
  87. pylegend/core/tds/legendql_api/frames/legendql_api_applied_function_tds_frame.py +37 -0
  88. pylegend/core/tds/legendql_api/frames/legendql_api_base_tds_frame.py +419 -0
  89. pylegend/core/tds/legendql_api/frames/legendql_api_input_tds_frame.py +50 -0
  90. pylegend/core/tds/legendql_api/frames/legendql_api_tds_frame.py +327 -0
  91. pylegend/core/tds/pandas_api/frames/functions/assign_function.py +6 -6
  92. pylegend/core/tds/pandas_api/frames/pandas_api_applied_function_tds_frame.py +4 -0
  93. pylegend/core/tds/pandas_api/frames/pandas_api_base_tds_frame.py +11 -3
  94. pylegend/core/tds/pandas_api/frames/pandas_api_tds_frame.py +2 -2
  95. pylegend/core/tds/tds_frame.py +32 -2
  96. pylegend/extensions/database/vendors/postgres/postgres_sql_to_string.py +1 -1
  97. pylegend/extensions/tds/abstract/legend_function_input_frame.py +4 -0
  98. pylegend/extensions/tds/abstract/legend_service_input_frame.py +4 -0
  99. pylegend/extensions/tds/abstract/table_spec_input_frame.py +4 -0
  100. pylegend/extensions/tds/{legend_api/frames/legend_api_legend_function_input_frame.py → legacy_api/frames/legacy_api_legend_function_input_frame.py} +5 -5
  101. pylegend/extensions/tds/{legend_api/frames/legend_api_legend_service_input_frame.py → legacy_api/frames/legacy_api_legend_service_input_frame.py} +6 -6
  102. pylegend/extensions/tds/{legend_api/frames/legend_api_table_spec_input_frame.py → legacy_api/frames/legacy_api_table_spec_input_frame.py} +5 -5
  103. pylegend/extensions/tds/legendql_api/__init__.py +13 -0
  104. pylegend/extensions/tds/legendql_api/frames/__init__.py +13 -0
  105. pylegend/extensions/tds/legendql_api/frames/legendql_api_legend_service_input_frame.py +46 -0
  106. pylegend/extensions/tds/legendql_api/frames/legendql_api_table_spec_input_frame.py +36 -0
  107. pylegend/{legend_api_tds_client.py → legacy_api_tds_client.py} +15 -15
  108. {pylegend-0.3.0.dist-info → pylegend-0.5.0.dist-info}/METADATA +7 -8
  109. pylegend-0.5.0.dist-info/NOTICE +5 -0
  110. pylegend-0.5.0.dist-info/RECORD +155 -0
  111. {pylegend-0.3.0.dist-info → pylegend-0.5.0.dist-info}/WHEEL +1 -1
  112. pylegend/core/language/operations/primitive_operation_expressions.py +0 -56
  113. pylegend/core/tds/legend_api/frames/legend_api_base_tds_frame.py +0 -294
  114. pylegend-0.3.0.dist-info/RECORD +0 -115
  115. /pylegend/core/{databse → database}/__init__.py +0 -0
  116. /pylegend/core/{databse → database}/sql_to_string/config.py +0 -0
  117. /pylegend/core/language/{operations → shared/operations}/__init__.py +0 -0
  118. /pylegend/core/tds/{legend_api → legacy_api}/__init__.py +0 -0
  119. /pylegend/core/tds/{legend_api → legacy_api}/frames/__init__.py +0 -0
  120. /pylegend/core/tds/{legend_api → legacy_api}/frames/functions/__init__.py +0 -0
  121. /pylegend/extensions/tds/{legend_api → legacy_api}/__init__.py +0 -0
  122. /pylegend/extensions/tds/{legend_api → legacy_api}/frames/__init__.py +0 -0
  123. {pylegend-0.3.0.dist-info → pylegend-0.5.0.dist-info}/LICENSE +0 -0
  124. {pylegend-0.3.0.dist-info → pylegend-0.5.0.dist-info}/LICENSE.spdx +0 -0
@@ -18,7 +18,8 @@ from pylegend._typing import (
18
18
  PyLegendSequence,
19
19
  PyLegendCallable,
20
20
  )
21
- from pylegend.core.tds.legend_api.frames.legend_api_applied_function_tds_frame import LegendApiAppliedFunction
21
+ from pylegend.core.tds.abstract.function_helpers import tds_column_for_primitive
22
+ from pylegend.core.tds.legacy_api.frames.legacy_api_applied_function_tds_frame import LegacyApiAppliedFunction
22
23
  from pylegend.core.tds.sql_query_helpers import copy_query, create_sub_query
23
24
  from pylegend.core.sql.metamodel import (
24
25
  QuerySpecification,
@@ -26,23 +27,24 @@ from pylegend.core.sql.metamodel import (
26
27
  )
27
28
  from pylegend.core.tds.tds_column import TdsColumn
28
29
  from pylegend.core.tds.tds_frame import FrameToSqlConfig
29
- from pylegend.core.tds.legend_api.frames.legend_api_base_tds_frame import LegendApiBaseTdsFrame
30
+ from pylegend.core.tds.tds_frame import FrameToPureConfig
31
+ from pylegend.core.tds.legacy_api.frames.legacy_api_base_tds_frame import LegacyApiBaseTdsFrame
30
32
  from pylegend.core.language import (
31
- TdsRow,
33
+ LegacyApiTdsRow,
32
34
  PyLegendPrimitive,
33
35
  PyLegendPrimitiveOrPythonPrimitive,
34
36
  convert_literal_to_literal_expression,
35
37
  )
36
- from pylegend.core.tds.legend_api.frames.functions.function_helpers import tds_column_for_primitive
38
+ from pylegend.core.language.shared.helpers import generate_pure_lambda, escape_column_name
37
39
 
38
40
  __all__: PyLegendSequence[str] = [
39
- "ExtendFunction"
41
+ "LegacyApiExtendFunction"
40
42
  ]
41
43
 
42
44
 
43
- class ExtendFunction(LegendApiAppliedFunction):
44
- __base_frame: LegendApiBaseTdsFrame
45
- __functions_list: PyLegendList[PyLegendCallable[[TdsRow], PyLegendPrimitiveOrPythonPrimitive]]
45
+ class LegacyApiExtendFunction(LegacyApiAppliedFunction):
46
+ __base_frame: LegacyApiBaseTdsFrame
47
+ __functions_list: PyLegendList[PyLegendCallable[[LegacyApiTdsRow], PyLegendPrimitiveOrPythonPrimitive]]
46
48
  __column_names_list: PyLegendList[str]
47
49
 
48
50
  @classmethod
@@ -51,8 +53,8 @@ class ExtendFunction(LegendApiAppliedFunction):
51
53
 
52
54
  def __init__(
53
55
  self,
54
- base_frame: LegendApiBaseTdsFrame,
55
- functions_list: PyLegendList[PyLegendCallable[[TdsRow], PyLegendPrimitiveOrPythonPrimitive]],
56
+ base_frame: LegacyApiBaseTdsFrame,
57
+ functions_list: PyLegendList[PyLegendCallable[[LegacyApiTdsRow], PyLegendPrimitiveOrPythonPrimitive]],
56
58
  column_names_list: PyLegendList[str]
57
59
  ) -> None:
58
60
  self.__base_frame = base_frame
@@ -69,7 +71,7 @@ class ExtendFunction(LegendApiAppliedFunction):
69
71
  copy_query(base_query)
70
72
  )
71
73
 
72
- tds_row = TdsRow.from_tds_frame("frame", self.__base_frame)
74
+ tds_row = LegacyApiTdsRow.from_tds_frame("frame", self.__base_frame)
73
75
  for (func, name) in zip(self.__functions_list, self.__column_names_list):
74
76
  col_expr = func(tds_row)
75
77
 
@@ -87,16 +89,34 @@ class ExtendFunction(LegendApiAppliedFunction):
87
89
 
88
90
  return new_query
89
91
 
90
- def base_frame(self) -> LegendApiBaseTdsFrame:
92
+ def to_pure(self, config: FrameToPureConfig) -> str:
93
+ tds_row = LegacyApiTdsRow.from_tds_frame("r", self.__base_frame)
94
+ rendered_columns = []
95
+ for (func, col_name) in zip(self.__functions_list, self.__column_names_list):
96
+ col_expr = func(tds_row)
97
+ escaped_col_name = escape_column_name(col_name)
98
+ pure_expr = (col_expr.to_pure_expression(config) if isinstance(col_expr, PyLegendPrimitive) else
99
+ convert_literal_to_literal_expression(col_expr).to_pure_expression(config))
100
+ rendered_columns.append(f"{escaped_col_name}:{generate_pure_lambda('r', pure_expr)}")
101
+
102
+ return (f"{self.__base_frame.to_pure(config)}{config.separator(1)}" +
103
+ (
104
+ (f"->extend(~{rendered_columns[0]})") if len(rendered_columns) == 1 else
105
+ (f"->extend(~[{config.separator(2)}"
106
+ f"{(',' + config.separator(2, True)).join(rendered_columns)}"
107
+ f"{config.separator(1)}])")
108
+ ))
109
+
110
+ def base_frame(self) -> LegacyApiBaseTdsFrame:
91
111
  return self.__base_frame
92
112
 
93
- def tds_frame_parameters(self) -> PyLegendList["LegendApiBaseTdsFrame"]:
113
+ def tds_frame_parameters(self) -> PyLegendList["LegacyApiBaseTdsFrame"]:
94
114
  return []
95
115
 
96
116
  def calculate_columns(self) -> PyLegendSequence["TdsColumn"]:
97
117
  new_columns = [c.copy() for c in self.__base_frame.columns()]
98
118
 
99
- tds_row = TdsRow.from_tds_frame("frame", self.__base_frame)
119
+ tds_row = LegacyApiTdsRow.from_tds_frame("frame", self.__base_frame)
100
120
  for (func, name) in zip(self.__functions_list, self.__column_names_list):
101
121
  result = func(tds_row)
102
122
  new_columns.append(tds_column_for_primitive(name, result))
@@ -111,7 +131,7 @@ class ExtendFunction(LegendApiAppliedFunction):
111
131
  f"Column names: {len(self.__column_names_list)}"
112
132
  )
113
133
 
114
- tds_row = TdsRow.from_tds_frame("frame", self.__base_frame)
134
+ tds_row = LegacyApiTdsRow.from_tds_frame("frame", self.__base_frame)
115
135
  index = 0
116
136
  for (func, name) in zip(self.__functions_list, self.__column_names_list):
117
137
  copy = func # For MyPy
@@ -134,7 +154,7 @@ class ExtendFunction(LegendApiAppliedFunction):
134
154
  f"Error occurred while evaluating. Message: {str(e)}"
135
155
  ) from e
136
156
 
137
- if not isinstance(result, (int, float, bool, str, PyLegendPrimitive)):
157
+ if not isinstance(result, (int, float, bool, str, date, datetime, PyLegendPrimitive)):
138
158
  raise ValueError(
139
159
  f"Extend function at index {index} (0-indexed) incompatible. "
140
160
  f"Returns non-primitive - {str(type(result))}"
@@ -18,7 +18,7 @@ from pylegend._typing import (
18
18
  PyLegendCallable,
19
19
  PyLegendUnion,
20
20
  )
21
- from pylegend.core.tds.legend_api.frames.legend_api_applied_function_tds_frame import LegendApiAppliedFunction
21
+ from pylegend.core.tds.legacy_api.frames.legacy_api_applied_function_tds_frame import LegacyApiAppliedFunction
22
22
  from pylegend.core.tds.sql_query_helpers import copy_query, create_sub_query
23
23
  from pylegend.core.sql.metamodel import (
24
24
  QuerySpecification,
@@ -27,21 +27,25 @@ from pylegend.core.sql.metamodel import (
27
27
  )
28
28
  from pylegend.core.tds.tds_column import TdsColumn
29
29
  from pylegend.core.tds.tds_frame import FrameToSqlConfig
30
- from pylegend.core.tds.legend_api.frames.legend_api_base_tds_frame import LegendApiBaseTdsFrame
30
+ from pylegend.core.tds.tds_frame import FrameToPureConfig
31
+ from pylegend.core.tds.legacy_api.frames.legacy_api_base_tds_frame import LegacyApiBaseTdsFrame
31
32
  from pylegend.core.language import (
32
- TdsRow,
33
+ LegacyApiTdsRow,
33
34
  PyLegendBoolean,
34
35
  PyLegendBooleanLiteralExpression,
36
+ PyLegendPrimitive,
37
+ convert_literal_to_literal_expression,
35
38
  )
39
+ from pylegend.core.language.shared.helpers import generate_pure_lambda
36
40
 
37
41
  __all__: PyLegendSequence[str] = [
38
- "FilterFunction"
42
+ "LegacyApiFilterFunction"
39
43
  ]
40
44
 
41
45
 
42
- class FilterFunction(LegendApiAppliedFunction):
43
- __base_frame: LegendApiBaseTdsFrame
44
- __filter_function: PyLegendCallable[[TdsRow], PyLegendUnion[bool, PyLegendBoolean]]
46
+ class LegacyApiFilterFunction(LegacyApiAppliedFunction):
47
+ __base_frame: LegacyApiBaseTdsFrame
48
+ __filter_function: PyLegendCallable[[LegacyApiTdsRow], PyLegendUnion[bool, PyLegendBoolean]]
45
49
 
46
50
  @classmethod
47
51
  def name(cls) -> str:
@@ -49,8 +53,8 @@ class FilterFunction(LegendApiAppliedFunction):
49
53
 
50
54
  def __init__(
51
55
  self,
52
- base_frame: LegendApiBaseTdsFrame,
53
- filter_function: PyLegendCallable[[TdsRow], PyLegendUnion[bool, PyLegendBoolean]]
56
+ base_frame: LegacyApiBaseTdsFrame,
57
+ filter_function: PyLegendCallable[[LegacyApiTdsRow], PyLegendUnion[bool, PyLegendBoolean]]
54
58
  ) -> None:
55
59
  self.__base_frame = base_frame
56
60
  self.__filter_function = filter_function
@@ -64,7 +68,7 @@ class FilterFunction(LegendApiAppliedFunction):
64
68
  copy_query(base_query)
65
69
  )
66
70
 
67
- tds_row = TdsRow.from_tds_frame("frame", self.__base_frame)
71
+ tds_row = LegacyApiTdsRow.from_tds_frame("frame", self.__base_frame)
68
72
  filter_expr = self.__filter_function(tds_row)
69
73
  if isinstance(filter_expr, bool):
70
74
  filter_expr = PyLegendBoolean(PyLegendBooleanLiteralExpression(filter_expr))
@@ -80,17 +84,25 @@ class FilterFunction(LegendApiAppliedFunction):
80
84
 
81
85
  return new_query
82
86
 
83
- def base_frame(self) -> LegendApiBaseTdsFrame:
87
+ def to_pure(self, config: FrameToPureConfig) -> str:
88
+ tds_row = LegacyApiTdsRow.from_tds_frame("r", self.__base_frame)
89
+ filter_expr = self.__filter_function(tds_row)
90
+ filter_expr_string = (filter_expr.to_pure_expression(config) if isinstance(filter_expr, PyLegendPrimitive) else
91
+ convert_literal_to_literal_expression(filter_expr).to_pure_expression(config))
92
+ return (f"{self.__base_frame.to_pure(config)}{config.separator(1)}" +
93
+ f"->filter({generate_pure_lambda('r', filter_expr_string)})")
94
+
95
+ def base_frame(self) -> LegacyApiBaseTdsFrame:
84
96
  return self.__base_frame
85
97
 
86
- def tds_frame_parameters(self) -> PyLegendList["LegendApiBaseTdsFrame"]:
98
+ def tds_frame_parameters(self) -> PyLegendList["LegacyApiBaseTdsFrame"]:
87
99
  return []
88
100
 
89
101
  def calculate_columns(self) -> PyLegendSequence["TdsColumn"]:
90
102
  return [c.copy() for c in self.__base_frame.columns()]
91
103
 
92
104
  def validate(self) -> bool:
93
- tds_row = TdsRow.from_tds_frame("frame", self.__base_frame)
105
+ tds_row = LegacyApiTdsRow.from_tds_frame("frame", self.__base_frame)
94
106
 
95
107
  copy = self.__filter_function # For MyPy
96
108
  if not isinstance(copy, type(lambda x: 0)) or (copy.__code__.co_argcount != 1):
@@ -12,12 +12,15 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
+ from datetime import date, datetime
15
16
  from pylegend._typing import (
16
17
  PyLegendList,
17
18
  PyLegendSequence,
18
19
  PyLegendTuple,
19
20
  )
20
- from pylegend.core.tds.legend_api.frames.legend_api_applied_function_tds_frame import LegendApiAppliedFunction
21
+ from pylegend.core.language.shared.helpers import generate_pure_lambda, escape_column_name
22
+ from pylegend.core.tds.abstract.function_helpers import tds_column_for_primitive
23
+ from pylegend.core.tds.legacy_api.frames.legacy_api_applied_function_tds_frame import LegacyApiAppliedFunction
21
24
  from pylegend.core.tds.sql_query_helpers import copy_query, create_sub_query
22
25
  from pylegend.core.sql.metamodel import (
23
26
  QuerySpecification,
@@ -26,26 +29,26 @@ from pylegend.core.sql.metamodel import (
26
29
  )
27
30
  from pylegend.core.tds.tds_column import TdsColumn
28
31
  from pylegend.core.tds.tds_frame import FrameToSqlConfig
29
- from pylegend.core.tds.legend_api.frames.legend_api_base_tds_frame import LegendApiBaseTdsFrame
32
+ from pylegend.core.tds.tds_frame import FrameToPureConfig
33
+ from pylegend.core.tds.legacy_api.frames.legacy_api_base_tds_frame import LegacyApiBaseTdsFrame
30
34
  from pylegend.core.language import (
31
- TdsRow,
32
- AggregateSpecification,
35
+ LegacyApiTdsRow,
36
+ LegacyApiAggregateSpecification,
33
37
  PyLegendPrimitive,
34
38
  create_primitive_collection,
35
39
  convert_literal_to_literal_expression,
36
40
  )
37
- from pylegend.core.tds.legend_api.frames.functions.function_helpers import tds_column_for_primitive
38
41
 
39
42
 
40
43
  __all__: PyLegendSequence[str] = [
41
- "GroupByFunction"
44
+ "LegacyApiGroupByFunction"
42
45
  ]
43
46
 
44
47
 
45
- class GroupByFunction(LegendApiAppliedFunction):
46
- __base_frame: LegendApiBaseTdsFrame
48
+ class LegacyApiGroupByFunction(LegacyApiAppliedFunction):
49
+ __base_frame: LegacyApiBaseTdsFrame
47
50
  __grouping_columns: PyLegendList[str]
48
- __aggregations: PyLegendList[AggregateSpecification]
51
+ __aggregations: PyLegendList[LegacyApiAggregateSpecification]
49
52
 
50
53
  @classmethod
51
54
  def name(cls) -> str:
@@ -53,9 +56,9 @@ class GroupByFunction(LegendApiAppliedFunction):
53
56
 
54
57
  def __init__(
55
58
  self,
56
- base_frame: LegendApiBaseTdsFrame,
59
+ base_frame: LegacyApiBaseTdsFrame,
57
60
  grouping_columns: PyLegendList[str],
58
- aggregations: PyLegendList[AggregateSpecification],
61
+ aggregations: PyLegendList[LegacyApiAggregateSpecification],
59
62
  ) -> None:
60
63
  self.__base_frame = base_frame
61
64
  self.__grouping_columns = grouping_columns
@@ -87,7 +90,7 @@ class GroupByFunction(LegendApiAppliedFunction):
87
90
 
88
91
  new_select_items = [y[1] for y in sorted(new_cols_with_index, key=lambda x: x[0])]
89
92
 
90
- tds_row = TdsRow.from_tds_frame("frame", self.__base_frame)
93
+ tds_row = LegacyApiTdsRow.from_tds_frame("frame", self.__base_frame)
91
94
  for agg in self.__aggregations:
92
95
  map_result = agg.get_map_fn()(tds_row)
93
96
  collection = create_primitive_collection(map_result)
@@ -111,10 +114,34 @@ class GroupByFunction(LegendApiAppliedFunction):
111
114
  ]
112
115
  return new_query
113
116
 
114
- def base_frame(self) -> LegendApiBaseTdsFrame:
117
+ def to_pure(self, config: FrameToPureConfig) -> str:
118
+ group_strings = []
119
+ for col_name in self.__grouping_columns:
120
+ group_strings.append(escape_column_name(col_name))
121
+
122
+ agg_strings = []
123
+ tds_row = LegacyApiTdsRow.from_tds_frame("r", self.__base_frame)
124
+ for agg in self.__aggregations:
125
+ agg_name = escape_column_name(agg.get_name())
126
+ map_expr = agg.get_map_fn()(tds_row)
127
+ collection = create_primitive_collection(map_expr)
128
+ agg_expr = agg.get_aggregate_fn()(collection)
129
+ map_expr_string = (map_expr.to_pure_expression(config) if isinstance(map_expr, PyLegendPrimitive) else
130
+ convert_literal_to_literal_expression(map_expr).to_pure_expression(config))
131
+ agg_expr_string = agg_expr.to_pure_expression(config).replace(map_expr_string, "$c")
132
+ agg_strings.append(f"{agg_name}:{generate_pure_lambda('r', map_expr_string)}:"
133
+ f"{generate_pure_lambda('c', agg_expr_string)}")
134
+
135
+ return (f"{self.__base_frame.to_pure(config)}{config.separator(1)}" +
136
+ f"->groupBy({config.separator(2)}"
137
+ f"~[{', '.join(group_strings)}],{config.separator(2, True)}"
138
+ f"~[{', '.join(agg_strings)}]{config.separator(1)}"
139
+ f")")
140
+
141
+ def base_frame(self) -> LegacyApiBaseTdsFrame:
115
142
  return self.__base_frame
116
143
 
117
- def tds_frame_parameters(self) -> PyLegendList["LegendApiBaseTdsFrame"]:
144
+ def tds_frame_parameters(self) -> PyLegendList["LegacyApiBaseTdsFrame"]:
118
145
  return []
119
146
 
120
147
  def calculate_columns(self) -> PyLegendSequence["TdsColumn"]:
@@ -125,7 +152,7 @@ class GroupByFunction(LegendApiAppliedFunction):
125
152
  if base_col.get_name() == c:
126
153
  new_columns.append(base_col.copy())
127
154
 
128
- tds_row = TdsRow.from_tds_frame("frame", self.__base_frame)
155
+ tds_row = LegacyApiTdsRow.from_tds_frame("frame", self.__base_frame)
129
156
  for agg in self.__aggregations:
130
157
  map_result = agg.get_map_fn()(tds_row)
131
158
  collection = create_primitive_collection(map_result)
@@ -159,7 +186,7 @@ class GroupByFunction(LegendApiAppliedFunction):
159
186
  raise ValueError("Found duplicate column names in grouping columns and aggregation columns. "
160
187
  f"Grouping columns - {self.__grouping_columns}, Aggregation columns - {agg_cols}")
161
188
 
162
- tds_row = TdsRow.from_tds_frame("frame", self.__base_frame)
189
+ tds_row = LegacyApiTdsRow.from_tds_frame("frame", self.__base_frame)
163
190
  index = 0
164
191
  for agg in self.__aggregations:
165
192
  map_fn_copy = agg.get_map_fn() # For MyPy
@@ -176,7 +203,7 @@ class GroupByFunction(LegendApiAppliedFunction):
176
203
  f"Error occurred while evaluating map function. Message: {str(e)}"
177
204
  ) from e
178
205
 
179
- if not isinstance(map_result, (int, float, bool, str, PyLegendPrimitive)):
206
+ if not isinstance(map_result, (int, float, bool, str, date, datetime, PyLegendPrimitive)):
180
207
  raise ValueError(
181
208
  f"AggregateSpecification at index {index} (0-indexed) incompatible. "
182
209
  f"Map function returns non-primitive - {str(type(map_result))}"
@@ -16,7 +16,7 @@ from pylegend._typing import (
16
16
  PyLegendList,
17
17
  PyLegendSequence,
18
18
  )
19
- from pylegend.core.tds.legend_api.frames.legend_api_applied_function_tds_frame import LegendApiAppliedFunction
19
+ from pylegend.core.tds.legacy_api.frames.legacy_api_applied_function_tds_frame import LegacyApiAppliedFunction
20
20
  from pylegend.core.tds.sql_query_helpers import copy_query, create_sub_query
21
21
  from pylegend.core.sql.metamodel import (
22
22
  QuerySpecification,
@@ -24,23 +24,24 @@ from pylegend.core.sql.metamodel import (
24
24
  )
25
25
  from pylegend.core.tds.tds_column import TdsColumn
26
26
  from pylegend.core.tds.tds_frame import FrameToSqlConfig
27
- from pylegend.core.tds.legend_api.frames.legend_api_base_tds_frame import LegendApiBaseTdsFrame
27
+ from pylegend.core.tds.tds_frame import FrameToPureConfig
28
+ from pylegend.core.tds.legacy_api.frames.legacy_api_base_tds_frame import LegacyApiBaseTdsFrame
28
29
 
29
30
 
30
31
  __all__: PyLegendSequence[str] = [
31
- "HeadFunction"
32
+ "LegacyApiHeadFunction"
32
33
  ]
33
34
 
34
35
 
35
- class HeadFunction(LegendApiAppliedFunction):
36
- __base_frame: LegendApiBaseTdsFrame
36
+ class LegacyApiHeadFunction(LegacyApiAppliedFunction):
37
+ __base_frame: LegacyApiBaseTdsFrame
37
38
  __row_count: int
38
39
 
39
40
  @classmethod
40
41
  def name(cls) -> str:
41
42
  return "head"
42
43
 
43
- def __init__(self, base_frame: LegendApiBaseTdsFrame, row_count: int) -> None:
44
+ def __init__(self, base_frame: LegacyApiBaseTdsFrame, row_count: int) -> None:
44
45
  self.__base_frame = base_frame
45
46
  self.__row_count = row_count
46
47
 
@@ -54,10 +55,14 @@ class HeadFunction(LegendApiAppliedFunction):
54
55
  new_query.limit = LongLiteral(value=self.__row_count)
55
56
  return new_query
56
57
 
57
- def base_frame(self) -> LegendApiBaseTdsFrame:
58
+ def to_pure(self, config: FrameToPureConfig) -> str:
59
+ return (f"{self.__base_frame.to_pure(config)}{config.separator(1)}"
60
+ f"->limit({self.__row_count})")
61
+
62
+ def base_frame(self) -> LegacyApiBaseTdsFrame:
58
63
  return self.__base_frame
59
64
 
60
- def tds_frame_parameters(self) -> PyLegendList["LegendApiBaseTdsFrame"]:
65
+ def tds_frame_parameters(self) -> PyLegendList["LegacyApiBaseTdsFrame"]:
61
66
  return []
62
67
 
63
68
  def calculate_columns(self) -> PyLegendSequence["TdsColumn"]:
@@ -17,7 +17,7 @@ from pylegend._typing import (
17
17
  PyLegendList,
18
18
  PyLegendSequence,
19
19
  )
20
- from pylegend.core.tds.legend_api.frames.legend_api_applied_function_tds_frame import LegendApiAppliedFunction
20
+ from pylegend.core.tds.legacy_api.frames.legacy_api_applied_function_tds_frame import LegacyApiAppliedFunction
21
21
  from pylegend.core.tds.sql_query_helpers import copy_query, create_sub_query, extract_columns_for_subquery
22
22
  from pylegend.core.sql.metamodel import (
23
23
  QuerySpecification,
@@ -40,18 +40,20 @@ from pylegend.core.sql.metamodel import (
40
40
  )
41
41
  from pylegend.core.tds.tds_column import TdsColumn
42
42
  from pylegend.core.tds.tds_frame import FrameToSqlConfig
43
- from pylegend.core.tds.legend_api.frames.legend_api_base_tds_frame import LegendApiBaseTdsFrame
44
- from pylegend.core.tds.legend_api.frames.legend_api_tds_frame import LegendApiTdsFrame
43
+ from pylegend.core.tds.tds_frame import FrameToPureConfig
44
+ from pylegend.core.tds.legacy_api.frames.legacy_api_base_tds_frame import LegacyApiBaseTdsFrame
45
+ from pylegend.core.tds.legacy_api.frames.legacy_api_tds_frame import LegacyApiTdsFrame
46
+ from pylegend.core.language.shared.helpers import generate_pure_lambda, escape_column_name
45
47
 
46
48
 
47
49
  __all__: PyLegendSequence[str] = [
48
- "JoinByColumnsFunction"
50
+ "LegacyApiJoinByColumnsFunction"
49
51
  ]
50
52
 
51
53
 
52
- class JoinByColumnsFunction(LegendApiAppliedFunction):
53
- __base_frame: LegendApiBaseTdsFrame
54
- __other_frame: LegendApiBaseTdsFrame
54
+ class LegacyApiJoinByColumnsFunction(LegacyApiAppliedFunction):
55
+ __base_frame: LegacyApiBaseTdsFrame
56
+ __other_frame: LegacyApiBaseTdsFrame
55
57
  __column_names_self: PyLegendList[str]
56
58
  __column_names_other: PyLegendList[str]
57
59
  __join_type: str
@@ -62,15 +64,15 @@ class JoinByColumnsFunction(LegendApiAppliedFunction):
62
64
 
63
65
  def __init__(
64
66
  self,
65
- base_frame: LegendApiBaseTdsFrame,
66
- other_frame: LegendApiTdsFrame,
67
+ base_frame: LegacyApiBaseTdsFrame,
68
+ other_frame: LegacyApiTdsFrame,
67
69
  column_names_self: PyLegendList[str],
68
70
  column_names_other: PyLegendList[str],
69
71
  join_type: str
70
72
  ) -> None:
71
73
  self.__base_frame = base_frame
72
- if not isinstance(other_frame, LegendApiBaseTdsFrame):
73
- raise ValueError("Expected LegendApiBaseTdsFrame") # pragma: no cover
74
+ if not isinstance(other_frame, LegacyApiBaseTdsFrame):
75
+ raise ValueError("Expected LegacyApiBaseTdsFrame") # pragma: no cover
74
76
  self.__other_frame = other_frame
75
77
  self.__column_names_self = column_names_self
76
78
  self.__column_names_other = column_names_other
@@ -160,10 +162,35 @@ class JoinByColumnsFunction(LegendApiAppliedFunction):
160
162
  wrapped_join_query = create_sub_query(join_query, config, "root")
161
163
  return wrapped_join_query
162
164
 
163
- def base_frame(self) -> LegendApiBaseTdsFrame:
165
+ def to_pure(self, config: FrameToPureConfig) -> str:
166
+ common_join_cols = [x for x, y in zip(self.__column_names_self, self.__column_names_other) if x == y]
167
+ other_frame = (self.__other_frame if (len(common_join_cols) == 0) else
168
+ self.__other_frame.rename_columns(common_join_cols, [c + "_gen_r" for c in common_join_cols]))
169
+ sub_expressions = []
170
+ for x, y in zip(self.__column_names_self, self.__column_names_other):
171
+ left = "$l." + escape_column_name(x)
172
+ y = (y + "_gen_r") if y in common_join_cols else y
173
+ right = "$r." + escape_column_name(y)
174
+ sub_expressions.append(f"({left} == {right})")
175
+
176
+ join_expr_string = " && ".join(sub_expressions)
177
+ join_kind = (
178
+ "INNER" if self.__join_type.lower() == 'inner' else
179
+ "LEFT" if self.__join_type.lower() in ('left_outer', 'leftouter') else
180
+ "RIGHT" if self.__join_type.lower() in ('right_outer', 'rightouter') else
181
+ "FULL"
182
+ )
183
+ return (f"{self.__base_frame.to_pure(config)}{config.separator(1)}" +
184
+ f"->join({config.separator(2)}"
185
+ f"{other_frame.to_pure(config.push_indent(2))},{config.separator(2, True)}" # type: ignore
186
+ f"JoinKind.{join_kind},{config.separator(2, True)}"
187
+ f"{generate_pure_lambda('l, r', join_expr_string)}{config.separator(1)}"
188
+ f")")
189
+
190
+ def base_frame(self) -> LegacyApiBaseTdsFrame:
164
191
  return self.__base_frame
165
192
 
166
- def tds_frame_parameters(self) -> PyLegendList["LegendApiBaseTdsFrame"]:
193
+ def tds_frame_parameters(self) -> PyLegendList["LegacyApiBaseTdsFrame"]:
167
194
  return [self.__other_frame]
168
195
 
169
196
  def calculate_columns(self) -> PyLegendSequence["TdsColumn"]:
@@ -18,7 +18,7 @@ from pylegend._typing import (
18
18
  PyLegendUnion,
19
19
  PyLegendCallable,
20
20
  )
21
- from pylegend.core.tds.legend_api.frames.legend_api_applied_function_tds_frame import LegendApiAppliedFunction
21
+ from pylegend.core.tds.legacy_api.frames.legacy_api_applied_function_tds_frame import LegacyApiAppliedFunction
22
22
  from pylegend.core.tds.sql_query_helpers import copy_query, create_sub_query, extract_columns_for_subquery
23
23
  from pylegend.core.sql.metamodel import (
24
24
  QuerySpecification,
@@ -36,24 +36,28 @@ from pylegend.core.sql.metamodel import (
36
36
  )
37
37
  from pylegend.core.tds.tds_column import TdsColumn
38
38
  from pylegend.core.tds.tds_frame import FrameToSqlConfig
39
- from pylegend.core.tds.legend_api.frames.legend_api_base_tds_frame import LegendApiBaseTdsFrame
40
- from pylegend.core.tds.legend_api.frames.legend_api_tds_frame import LegendApiTdsFrame
39
+ from pylegend.core.tds.tds_frame import FrameToPureConfig
40
+ from pylegend.core.tds.legacy_api.frames.legacy_api_base_tds_frame import LegacyApiBaseTdsFrame
41
+ from pylegend.core.tds.legacy_api.frames.legacy_api_tds_frame import LegacyApiTdsFrame
41
42
  from pylegend.core.language import (
42
43
  PyLegendBoolean,
43
- TdsRow,
44
+ LegacyApiTdsRow,
44
45
  PyLegendBooleanLiteralExpression,
46
+ PyLegendPrimitive,
47
+ convert_literal_to_literal_expression,
45
48
  )
49
+ from pylegend.core.language.shared.helpers import generate_pure_lambda
46
50
 
47
51
 
48
52
  __all__: PyLegendSequence[str] = [
49
- "JoinFunction"
53
+ "LegacyApiJoinFunction"
50
54
  ]
51
55
 
52
56
 
53
- class JoinFunction(LegendApiAppliedFunction):
54
- __base_frame: LegendApiBaseTdsFrame
55
- __other_frame: LegendApiBaseTdsFrame
56
- __join_condition: PyLegendCallable[[TdsRow, TdsRow], PyLegendUnion[bool, PyLegendBoolean]]
57
+ class LegacyApiJoinFunction(LegacyApiAppliedFunction):
58
+ __base_frame: LegacyApiBaseTdsFrame
59
+ __other_frame: LegacyApiBaseTdsFrame
60
+ __join_condition: PyLegendCallable[[LegacyApiTdsRow, LegacyApiTdsRow], PyLegendUnion[bool, PyLegendBoolean]]
57
61
  __join_type: str
58
62
 
59
63
  @classmethod
@@ -62,14 +66,14 @@ class JoinFunction(LegendApiAppliedFunction):
62
66
 
63
67
  def __init__(
64
68
  self,
65
- base_frame: LegendApiBaseTdsFrame,
66
- other_frame: LegendApiTdsFrame,
67
- join_condition: PyLegendCallable[[TdsRow, TdsRow], PyLegendUnion[bool, PyLegendBoolean]],
69
+ base_frame: LegacyApiBaseTdsFrame,
70
+ other_frame: LegacyApiTdsFrame,
71
+ join_condition: PyLegendCallable[[LegacyApiTdsRow, LegacyApiTdsRow], PyLegendUnion[bool, PyLegendBoolean]],
68
72
  join_type: str
69
73
  ) -> None:
70
74
  self.__base_frame = base_frame
71
- if not isinstance(other_frame, LegendApiBaseTdsFrame):
72
- raise ValueError("Expected LegendApiBaseTdsFrame") # pragma: no cover
75
+ if not isinstance(other_frame, LegacyApiBaseTdsFrame):
76
+ raise ValueError("Expected LegacyApiBaseTdsFrame") # pragma: no cover
73
77
  self.__other_frame = other_frame
74
78
  self.__join_condition = join_condition
75
79
  self.__join_type = join_type
@@ -86,8 +90,8 @@ class JoinFunction(LegendApiAppliedFunction):
86
90
  )
87
91
  )
88
92
 
89
- left_row = TdsRow.from_tds_frame('left', self.__base_frame)
90
- right_row = TdsRow.from_tds_frame('right', self.__other_frame)
93
+ left_row = LegacyApiTdsRow.from_tds_frame('left', self.__base_frame)
94
+ right_row = LegacyApiTdsRow.from_tds_frame('right', self.__other_frame)
91
95
 
92
96
  join_expr = self.__join_condition(left_row, right_row)
93
97
  if isinstance(join_expr, bool):
@@ -142,10 +146,30 @@ class JoinFunction(LegendApiAppliedFunction):
142
146
  wrapped_join_query = create_sub_query(join_query, config, "root")
143
147
  return wrapped_join_query
144
148
 
145
- def base_frame(self) -> LegendApiBaseTdsFrame:
149
+ def to_pure(self, config: FrameToPureConfig) -> str:
150
+ left_row = LegacyApiTdsRow.from_tds_frame("l", self.__base_frame)
151
+ right_row = LegacyApiTdsRow.from_tds_frame("r", self.__other_frame)
152
+ join_expr = self.__join_condition(left_row, right_row)
153
+ join_expr_string = (join_expr.to_pure_expression(config.push_indent(2))
154
+ if isinstance(join_expr, PyLegendPrimitive) else
155
+ convert_literal_to_literal_expression(join_expr).to_pure_expression(config.push_indent(2)))
156
+ join_kind = (
157
+ "INNER" if self.__join_type.lower() == 'inner' else
158
+ "LEFT" if self.__join_type.lower() in ('left_outer', 'leftouter') else
159
+ "RIGHT" if self.__join_type.lower() in ('right_outer', 'rightouter') else
160
+ "FULL"
161
+ )
162
+ return (f"{self.__base_frame.to_pure(config)}{config.separator(1)}" +
163
+ f"->join({config.separator(2)}"
164
+ f"{self.__other_frame.to_pure(config.push_indent(2))},{config.separator(2, True)}"
165
+ f"JoinKind.{join_kind},{config.separator(2, True)}"
166
+ f"{generate_pure_lambda('l, r', join_expr_string)}{config.separator(1)}"
167
+ f")")
168
+
169
+ def base_frame(self) -> LegacyApiBaseTdsFrame:
146
170
  return self.__base_frame
147
171
 
148
- def tds_frame_parameters(self) -> PyLegendList["LegendApiBaseTdsFrame"]:
172
+ def tds_frame_parameters(self) -> PyLegendList["LegacyApiBaseTdsFrame"]:
149
173
  return [self.__other_frame]
150
174
 
151
175
  def calculate_columns(self) -> PyLegendSequence["TdsColumn"]:
@@ -159,8 +183,8 @@ class JoinFunction(LegendApiAppliedFunction):
159
183
  if not isinstance(copy, type(lambda x: 0)) or (copy.__code__.co_argcount != 2):
160
184
  raise TypeError("Join condition function should be a lambda which takes two arguments (TDSRow, TDSRow)")
161
185
 
162
- left_row = TdsRow.from_tds_frame("left", self.__base_frame)
163
- right_row = TdsRow.from_tds_frame("right", self.__other_frame)
186
+ left_row = LegacyApiTdsRow.from_tds_frame("left", self.__base_frame)
187
+ right_row = LegacyApiTdsRow.from_tds_frame("right", self.__other_frame)
164
188
 
165
189
  try:
166
190
  result = self.__join_condition(left_row, right_row)