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
@@ -0,0 +1,155 @@
1
+ # Copyright 2023 Goldman Sachs
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ from pylegend._typing import (
16
+ PyLegendSequence,
17
+ PyLegendDict,
18
+ )
19
+ from pylegend.core.language.shared.expression import (
20
+ PyLegendExpression,
21
+ PyLegendExpressionBooleanReturn,
22
+ )
23
+ from pylegend.core.language.shared.helpers import generate_pure_functional_call
24
+ from pylegend.core.language.shared.operations.binary_expression import PyLegendBinaryExpression
25
+ from pylegend.core.language.shared.operations.unary_expression import PyLegendUnaryExpression
26
+ from pylegend.core.sql.metamodel import (
27
+ Expression,
28
+ QuerySpecification,
29
+ ComparisonExpression,
30
+ ComparisonOperator,
31
+ IsNullPredicate,
32
+ IsNotNullPredicate,
33
+ )
34
+ from pylegend.core.tds.tds_frame import FrameToSqlConfig
35
+ from pylegend.core.tds.tds_frame import FrameToPureConfig
36
+
37
+
38
+ __all__: PyLegendSequence[str] = [
39
+ "PyLegendPrimitiveEqualsExpression",
40
+ "PyLegendPrimitiveNotEqualsExpression",
41
+ "PyLegendIsEmptyExpression",
42
+ "PyLegendIsNotEmptyExpression",
43
+ ]
44
+
45
+
46
+ class PyLegendPrimitiveEqualsExpression(PyLegendBinaryExpression, PyLegendExpressionBooleanReturn):
47
+
48
+ @staticmethod
49
+ def __to_sql_func(
50
+ expression1: Expression,
51
+ expression2: Expression,
52
+ frame_name_to_base_query_map: PyLegendDict[str, QuerySpecification],
53
+ config: FrameToSqlConfig
54
+ ) -> Expression:
55
+ return ComparisonExpression(expression1, expression2, ComparisonOperator.EQUAL)
56
+
57
+ @staticmethod
58
+ def __to_pure_func(op1_expr: str, op2_expr: str, config: FrameToPureConfig) -> str:
59
+ return f"({op1_expr} == {op2_expr})"
60
+
61
+ def __init__(self, operand1: PyLegendExpression, operand2: PyLegendExpression) -> None:
62
+ PyLegendExpressionBooleanReturn.__init__(self)
63
+ PyLegendBinaryExpression.__init__(
64
+ self,
65
+ operand1,
66
+ operand2,
67
+ PyLegendPrimitiveEqualsExpression.__to_sql_func,
68
+ PyLegendPrimitiveEqualsExpression.__to_pure_func
69
+ )
70
+
71
+ def is_non_nullable(self) -> bool:
72
+ return True
73
+
74
+
75
+ class PyLegendPrimitiveNotEqualsExpression(PyLegendBinaryExpression, PyLegendExpressionBooleanReturn):
76
+
77
+ @staticmethod
78
+ def __to_sql_func(
79
+ expression1: Expression,
80
+ expression2: Expression,
81
+ frame_name_to_base_query_map: PyLegendDict[str, QuerySpecification],
82
+ config: FrameToSqlConfig
83
+ ) -> Expression:
84
+ return ComparisonExpression(expression1, expression2, ComparisonOperator.NOT_EQUAL)
85
+
86
+ @staticmethod
87
+ def __to_pure_func(op1_expr: str, op2_expr: str, config: FrameToPureConfig) -> str:
88
+ return f"({op1_expr} != {op2_expr})"
89
+
90
+ def __init__(self, operand1: PyLegendExpression, operand2: PyLegendExpression) -> None:
91
+ PyLegendExpressionBooleanReturn.__init__(self)
92
+ PyLegendBinaryExpression.__init__(
93
+ self,
94
+ operand1,
95
+ operand2,
96
+ PyLegendPrimitiveNotEqualsExpression.__to_sql_func,
97
+ PyLegendPrimitiveNotEqualsExpression.__to_pure_func
98
+ )
99
+
100
+ def is_non_nullable(self) -> bool:
101
+ return True
102
+
103
+
104
+ class PyLegendIsEmptyExpression(PyLegendUnaryExpression, PyLegendExpressionBooleanReturn):
105
+
106
+ @staticmethod
107
+ def __to_sql_func(
108
+ expression: Expression,
109
+ frame_name_to_base_query_map: PyLegendDict[str, QuerySpecification],
110
+ config: FrameToSqlConfig
111
+ ) -> Expression:
112
+ return IsNullPredicate(expression)
113
+
114
+ @staticmethod
115
+ def __to_pure_func(op_expr: str, config: FrameToPureConfig) -> str:
116
+ return generate_pure_functional_call("isEmpty", [op_expr])
117
+
118
+ def __init__(self, operand: PyLegendExpression) -> None:
119
+ PyLegendExpressionBooleanReturn.__init__(self)
120
+ PyLegendUnaryExpression.__init__(
121
+ self,
122
+ operand,
123
+ PyLegendIsEmptyExpression.__to_sql_func,
124
+ PyLegendIsEmptyExpression.__to_pure_func
125
+ )
126
+
127
+ def is_non_nullable(self) -> bool:
128
+ return True
129
+
130
+
131
+ class PyLegendIsNotEmptyExpression(PyLegendUnaryExpression, PyLegendExpressionBooleanReturn):
132
+
133
+ @staticmethod
134
+ def __to_sql_func(
135
+ expression: Expression,
136
+ frame_name_to_base_query_map: PyLegendDict[str, QuerySpecification],
137
+ config: FrameToSqlConfig
138
+ ) -> Expression:
139
+ return IsNotNullPredicate(expression)
140
+
141
+ @staticmethod
142
+ def __to_pure_func(op_expr: str, config: FrameToPureConfig) -> str:
143
+ return generate_pure_functional_call("isNotEmpty", [op_expr])
144
+
145
+ def __init__(self, operand: PyLegendExpression) -> None:
146
+ PyLegendExpressionBooleanReturn.__init__(self)
147
+ PyLegendUnaryExpression.__init__(
148
+ self,
149
+ operand,
150
+ PyLegendIsNotEmptyExpression.__to_sql_func,
151
+ PyLegendIsNotEmptyExpression.__to_pure_func
152
+ )
153
+
154
+ def is_non_nullable(self) -> bool:
155
+ return True
@@ -16,14 +16,16 @@ from pylegend._typing import (
16
16
  PyLegendSequence,
17
17
  PyLegendDict,
18
18
  )
19
- from pylegend.core.language.expression import (
19
+ from pylegend.core.language.shared.expression import (
20
20
  PyLegendExpressionStringReturn,
21
21
  PyLegendExpressionIntegerReturn,
22
22
  PyLegendExpressionFloatReturn,
23
23
  PyLegendExpressionBooleanReturn,
24
24
  )
25
- from pylegend.core.language.operations.binary_expression import PyLegendBinaryExpression
26
- from pylegend.core.language.operations.unary_expression import PyLegendUnaryExpression
25
+ from pylegend.core.language.shared.operations.binary_expression import PyLegendBinaryExpression
26
+ from pylegend.core.language.shared.operations.nullary_expression import PyLegendNullaryExpression
27
+ from pylegend.core.language.shared.operations.unary_expression import PyLegendUnaryExpression
28
+ from pylegend.core.language.shared.helpers import generate_pure_functional_call
27
29
  from pylegend.core.sql.metamodel import (
28
30
  Expression,
29
31
  QuerySpecification,
@@ -31,6 +33,7 @@ from pylegend.core.sql.metamodel import (
31
33
  Cast,
32
34
  ComparisonOperator,
33
35
  ComparisonExpression,
36
+ StringLiteral,
34
37
  )
35
38
  from pylegend.core.sql.metamodel_extension import (
36
39
  StringLengthExpression,
@@ -41,13 +44,17 @@ from pylegend.core.sql.metamodel_extension import (
41
44
  StringTrimExpression,
42
45
  StringPosExpression,
43
46
  StringConcatExpression,
47
+ ConstantExpression,
44
48
  )
45
49
  from pylegend.core.tds.tds_frame import FrameToSqlConfig
50
+ from pylegend.core.tds.tds_frame import FrameToPureConfig
46
51
 
47
52
 
48
53
  __all__: PyLegendSequence[str] = [
49
54
  "PyLegendStringLengthExpression",
50
- "PyLegendStringLikeExpression",
55
+ "PyLegendStringStartsWithExpression",
56
+ "PyLegendStringEndsWithExpression",
57
+ "PyLegendStringContainsExpression",
51
58
  "PyLegendStringUpperExpression",
52
59
  "PyLegendStringLowerExpression",
53
60
  "PyLegendStringLTrimExpression",
@@ -61,6 +68,7 @@ __all__: PyLegendSequence[str] = [
61
68
  "PyLegendStringLessThanEqualExpression",
62
69
  "PyLegendStringGreaterThanExpression",
63
70
  "PyLegendStringGreaterThanEqualExpression",
71
+ "PyLegendCurrentUserExpression",
64
72
  ]
65
73
 
66
74
 
@@ -74,16 +82,49 @@ class PyLegendStringLengthExpression(PyLegendUnaryExpression, PyLegendExpression
74
82
  ) -> Expression:
75
83
  return StringLengthExpression(expression)
76
84
 
85
+ @staticmethod
86
+ def __to_pure_func(op_expr: str, config: FrameToPureConfig) -> str:
87
+ return generate_pure_functional_call("length", [op_expr], auto_map=True)
88
+
77
89
  def __init__(self, operand: PyLegendExpressionStringReturn) -> None:
78
90
  PyLegendExpressionIntegerReturn.__init__(self)
79
91
  PyLegendUnaryExpression.__init__(
80
92
  self,
81
93
  operand,
82
- PyLegendStringLengthExpression.__to_sql_func
94
+ PyLegendStringLengthExpression.__to_sql_func,
95
+ PyLegendStringLengthExpression.__to_pure_func
96
+ )
97
+
98
+
99
+ class PyLegendStringStartsWithExpression(PyLegendBinaryExpression, PyLegendExpressionBooleanReturn):
100
+
101
+ @staticmethod
102
+ def __to_sql_func(
103
+ expression1: Expression,
104
+ expression2: Expression,
105
+ frame_name_to_base_query_map: PyLegendDict[str, QuerySpecification],
106
+ config: FrameToSqlConfig
107
+ ) -> Expression:
108
+ assert isinstance(expression2, StringLiteral)
109
+ escaped = _escape_like_param(expression2.value)
110
+ return StringLikeExpression(expression1, StringLiteral(value=escaped + "%", quoted=False))
111
+
112
+ @staticmethod
113
+ def __to_pure_func(op1_expr: str, op2_expr: str, config: FrameToPureConfig) -> str:
114
+ return generate_pure_functional_call("startsWith", [op1_expr, op2_expr])
115
+
116
+ def __init__(self, operand1: PyLegendExpressionStringReturn, operand2: PyLegendExpressionStringReturn) -> None:
117
+ PyLegendExpressionBooleanReturn.__init__(self)
118
+ PyLegendBinaryExpression.__init__(
119
+ self,
120
+ operand1,
121
+ operand2,
122
+ PyLegendStringStartsWithExpression.__to_sql_func,
123
+ PyLegendStringStartsWithExpression.__to_pure_func
83
124
  )
84
125
 
85
126
 
86
- class PyLegendStringLikeExpression(PyLegendBinaryExpression, PyLegendExpressionBooleanReturn):
127
+ class PyLegendStringEndsWithExpression(PyLegendBinaryExpression, PyLegendExpressionBooleanReturn):
87
128
 
88
129
  @staticmethod
89
130
  def __to_sql_func(
@@ -92,7 +133,41 @@ class PyLegendStringLikeExpression(PyLegendBinaryExpression, PyLegendExpressionB
92
133
  frame_name_to_base_query_map: PyLegendDict[str, QuerySpecification],
93
134
  config: FrameToSqlConfig
94
135
  ) -> Expression:
95
- return StringLikeExpression(expression1, expression2)
136
+ assert isinstance(expression2, StringLiteral)
137
+ escaped = _escape_like_param(expression2.value)
138
+ return StringLikeExpression(expression1, StringLiteral(value="%" + escaped, quoted=False))
139
+
140
+ @staticmethod
141
+ def __to_pure_func(op1_expr: str, op2_expr: str, config: FrameToPureConfig) -> str:
142
+ return generate_pure_functional_call("endsWith", [op1_expr, op2_expr])
143
+
144
+ def __init__(self, operand1: PyLegendExpressionStringReturn, operand2: PyLegendExpressionStringReturn) -> None:
145
+ PyLegendExpressionBooleanReturn.__init__(self)
146
+ PyLegendBinaryExpression.__init__(
147
+ self,
148
+ operand1,
149
+ operand2,
150
+ PyLegendStringEndsWithExpression.__to_sql_func,
151
+ PyLegendStringEndsWithExpression.__to_pure_func
152
+ )
153
+
154
+
155
+ class PyLegendStringContainsExpression(PyLegendBinaryExpression, PyLegendExpressionBooleanReturn):
156
+
157
+ @staticmethod
158
+ def __to_sql_func(
159
+ expression1: Expression,
160
+ expression2: Expression,
161
+ frame_name_to_base_query_map: PyLegendDict[str, QuerySpecification],
162
+ config: FrameToSqlConfig
163
+ ) -> Expression:
164
+ assert isinstance(expression2, StringLiteral)
165
+ escaped = _escape_like_param(expression2.value)
166
+ return StringLikeExpression(expression1, StringLiteral(value="%" + escaped + "%", quoted=False))
167
+
168
+ @staticmethod
169
+ def __to_pure_func(op1_expr: str, op2_expr: str, config: FrameToPureConfig) -> str:
170
+ return generate_pure_functional_call("contains", [op1_expr, op2_expr])
96
171
 
97
172
  def __init__(self, operand1: PyLegendExpressionStringReturn, operand2: PyLegendExpressionStringReturn) -> None:
98
173
  PyLegendExpressionBooleanReturn.__init__(self)
@@ -100,7 +175,8 @@ class PyLegendStringLikeExpression(PyLegendBinaryExpression, PyLegendExpressionB
100
175
  self,
101
176
  operand1,
102
177
  operand2,
103
- PyLegendStringLikeExpression.__to_sql_func
178
+ PyLegendStringContainsExpression.__to_sql_func,
179
+ PyLegendStringContainsExpression.__to_pure_func
104
180
  )
105
181
 
106
182
 
@@ -114,12 +190,17 @@ class PyLegendStringUpperExpression(PyLegendUnaryExpression, PyLegendExpressionS
114
190
  ) -> Expression:
115
191
  return StringUpperExpression(expression)
116
192
 
193
+ @staticmethod
194
+ def __to_pure_func(op_expr: str, config: FrameToPureConfig) -> str:
195
+ return generate_pure_functional_call("toUpper", [op_expr], auto_map=True)
196
+
117
197
  def __init__(self, operand: PyLegendExpressionStringReturn) -> None:
118
198
  PyLegendExpressionStringReturn.__init__(self)
119
199
  PyLegendUnaryExpression.__init__(
120
200
  self,
121
201
  operand,
122
- PyLegendStringUpperExpression.__to_sql_func
202
+ PyLegendStringUpperExpression.__to_sql_func,
203
+ PyLegendStringUpperExpression.__to_pure_func
123
204
  )
124
205
 
125
206
 
@@ -133,12 +214,17 @@ class PyLegendStringLowerExpression(PyLegendUnaryExpression, PyLegendExpressionS
133
214
  ) -> Expression:
134
215
  return StringLowerExpression(expression)
135
216
 
217
+ @staticmethod
218
+ def __to_pure_func(op_expr: str, config: FrameToPureConfig) -> str:
219
+ return generate_pure_functional_call("toLower", [op_expr], auto_map=True)
220
+
136
221
  def __init__(self, operand: PyLegendExpressionStringReturn) -> None:
137
222
  PyLegendExpressionStringReturn.__init__(self)
138
223
  PyLegendUnaryExpression.__init__(
139
224
  self,
140
225
  operand,
141
- PyLegendStringLowerExpression.__to_sql_func
226
+ PyLegendStringLowerExpression.__to_sql_func,
227
+ PyLegendStringLowerExpression.__to_pure_func
142
228
  )
143
229
 
144
230
 
@@ -152,12 +238,17 @@ class PyLegendStringLTrimExpression(PyLegendUnaryExpression, PyLegendExpressionS
152
238
  ) -> Expression:
153
239
  return StringTrimExpression(expression, trim_type=TrimType.Left)
154
240
 
241
+ @staticmethod
242
+ def __to_pure_func(op_expr: str, config: FrameToPureConfig) -> str:
243
+ return generate_pure_functional_call("ltrim", [op_expr], auto_map=True)
244
+
155
245
  def __init__(self, operand: PyLegendExpressionStringReturn) -> None:
156
246
  PyLegendExpressionStringReturn.__init__(self)
157
247
  PyLegendUnaryExpression.__init__(
158
248
  self,
159
249
  operand,
160
- PyLegendStringLTrimExpression.__to_sql_func
250
+ PyLegendStringLTrimExpression.__to_sql_func,
251
+ PyLegendStringLTrimExpression.__to_pure_func
161
252
  )
162
253
 
163
254
 
@@ -171,12 +262,17 @@ class PyLegendStringRTrimExpression(PyLegendUnaryExpression, PyLegendExpressionS
171
262
  ) -> Expression:
172
263
  return StringTrimExpression(expression, trim_type=TrimType.Right)
173
264
 
265
+ @staticmethod
266
+ def __to_pure_func(op_expr: str, config: FrameToPureConfig) -> str:
267
+ return generate_pure_functional_call("rtrim", [op_expr], auto_map=True)
268
+
174
269
  def __init__(self, operand: PyLegendExpressionStringReturn) -> None:
175
270
  PyLegendExpressionStringReturn.__init__(self)
176
271
  PyLegendUnaryExpression.__init__(
177
272
  self,
178
273
  operand,
179
- PyLegendStringRTrimExpression.__to_sql_func
274
+ PyLegendStringRTrimExpression.__to_sql_func,
275
+ PyLegendStringRTrimExpression.__to_pure_func
180
276
  )
181
277
 
182
278
 
@@ -190,12 +286,17 @@ class PyLegendStringBTrimExpression(PyLegendUnaryExpression, PyLegendExpressionS
190
286
  ) -> Expression:
191
287
  return StringTrimExpression(expression, trim_type=TrimType.Both)
192
288
 
289
+ @staticmethod
290
+ def __to_pure_func(op_expr: str, config: FrameToPureConfig) -> str:
291
+ return generate_pure_functional_call("trim", [op_expr], auto_map=True)
292
+
193
293
  def __init__(self, operand: PyLegendExpressionStringReturn) -> None:
194
294
  PyLegendExpressionStringReturn.__init__(self)
195
295
  PyLegendUnaryExpression.__init__(
196
296
  self,
197
297
  operand,
198
- PyLegendStringBTrimExpression.__to_sql_func
298
+ PyLegendStringBTrimExpression.__to_sql_func,
299
+ PyLegendStringBTrimExpression.__to_pure_func
199
300
  )
200
301
 
201
302
 
@@ -210,15 +311,23 @@ class PyLegendStringPosExpression(PyLegendBinaryExpression, PyLegendExpressionIn
210
311
  ) -> Expression:
211
312
  return StringPosExpression(expression1, expression2)
212
313
 
314
+ @staticmethod
315
+ def __to_pure_func(op1_expr: str, op2_expr: str, config: FrameToPureConfig) -> str:
316
+ return generate_pure_functional_call("indexOf", [op1_expr, op2_expr], auto_map=True)
317
+
213
318
  def __init__(self, operand1: PyLegendExpressionStringReturn, operand2: PyLegendExpressionStringReturn) -> None:
214
319
  PyLegendExpressionIntegerReturn.__init__(self)
215
320
  PyLegendBinaryExpression.__init__(
216
321
  self,
217
322
  operand1,
218
323
  operand2,
219
- PyLegendStringPosExpression.__to_sql_func
324
+ PyLegendStringPosExpression.__to_sql_func,
325
+ PyLegendStringPosExpression.__to_pure_func
220
326
  )
221
327
 
328
+ def to_pure_expression(self, config: FrameToPureConfig) -> str:
329
+ return PyLegendBinaryExpression.to_pure_expression_with_to_one_on_second_operand(self, config)
330
+
222
331
 
223
332
  class PyLegendStringParseIntExpression(PyLegendUnaryExpression, PyLegendExpressionIntegerReturn):
224
333
 
@@ -230,12 +339,17 @@ class PyLegendStringParseIntExpression(PyLegendUnaryExpression, PyLegendExpressi
230
339
  ) -> Expression:
231
340
  return Cast(expression, ColumnType(name="INTEGER", parameters=[]))
232
341
 
342
+ @staticmethod
343
+ def __to_pure_func(op_expr: str, config: FrameToPureConfig) -> str:
344
+ return generate_pure_functional_call("parseInteger", [op_expr], auto_map=True)
345
+
233
346
  def __init__(self, operand: PyLegendExpressionStringReturn) -> None:
234
347
  PyLegendExpressionIntegerReturn.__init__(self)
235
348
  PyLegendUnaryExpression.__init__(
236
349
  self,
237
350
  operand,
238
- PyLegendStringParseIntExpression.__to_sql_func
351
+ PyLegendStringParseIntExpression.__to_sql_func,
352
+ PyLegendStringParseIntExpression.__to_pure_func
239
353
  )
240
354
 
241
355
 
@@ -249,12 +363,17 @@ class PyLegendStringParseFloatExpression(PyLegendUnaryExpression, PyLegendExpres
249
363
  ) -> Expression:
250
364
  return Cast(expression, ColumnType(name="DOUBLE PRECISION", parameters=[]))
251
365
 
366
+ @staticmethod
367
+ def __to_pure_func(op_expr: str, config: FrameToPureConfig) -> str:
368
+ return generate_pure_functional_call("parseFloat", [op_expr], auto_map=True)
369
+
252
370
  def __init__(self, operand: PyLegendExpressionStringReturn) -> None:
253
371
  PyLegendExpressionFloatReturn.__init__(self)
254
372
  PyLegendUnaryExpression.__init__(
255
373
  self,
256
374
  operand,
257
- PyLegendStringParseFloatExpression.__to_sql_func
375
+ PyLegendStringParseFloatExpression.__to_sql_func,
376
+ PyLegendStringParseFloatExpression.__to_pure_func
258
377
  )
259
378
 
260
379
 
@@ -269,15 +388,23 @@ class PyLegendStringConcatExpression(PyLegendBinaryExpression, PyLegendExpressio
269
388
  ) -> Expression:
270
389
  return StringConcatExpression(expression1, expression2)
271
390
 
391
+ @staticmethod
392
+ def __to_pure_func(op1_expr: str, op2_expr: str, config: FrameToPureConfig) -> str:
393
+ return f"({op1_expr} + {op2_expr})"
394
+
272
395
  def __init__(self, operand1: PyLegendExpressionStringReturn, operand2: PyLegendExpressionStringReturn) -> None:
273
396
  PyLegendExpressionStringReturn.__init__(self)
274
397
  PyLegendBinaryExpression.__init__(
275
398
  self,
276
399
  operand1,
277
400
  operand2,
278
- PyLegendStringConcatExpression.__to_sql_func
401
+ PyLegendStringConcatExpression.__to_sql_func,
402
+ PyLegendStringConcatExpression.__to_pure_func
279
403
  )
280
404
 
405
+ def to_pure_expression(self, config: FrameToPureConfig) -> str:
406
+ return PyLegendBinaryExpression.to_pure_expression_with_to_one_on_both_operands(self, config)
407
+
281
408
 
282
409
  class PyLegendStringLessThanExpression(PyLegendBinaryExpression, PyLegendExpressionBooleanReturn):
283
410
 
@@ -290,13 +417,18 @@ class PyLegendStringLessThanExpression(PyLegendBinaryExpression, PyLegendExpress
290
417
  ) -> Expression:
291
418
  return ComparisonExpression(expression1, expression2, ComparisonOperator.LESS_THAN)
292
419
 
420
+ @staticmethod
421
+ def __to_pure_func(op1_expr: str, op2_expr: str, config: FrameToPureConfig) -> str:
422
+ return f"({op1_expr} < {op2_expr})"
423
+
293
424
  def __init__(self, operand1: PyLegendExpressionStringReturn, operand2: PyLegendExpressionStringReturn) -> None:
294
425
  PyLegendExpressionBooleanReturn.__init__(self)
295
426
  PyLegendBinaryExpression.__init__(
296
427
  self,
297
428
  operand1,
298
429
  operand2,
299
- PyLegendStringLessThanExpression.__to_sql_func
430
+ PyLegendStringLessThanExpression.__to_sql_func,
431
+ PyLegendStringLessThanExpression.__to_pure_func
300
432
  )
301
433
 
302
434
 
@@ -311,13 +443,18 @@ class PyLegendStringLessThanEqualExpression(PyLegendBinaryExpression, PyLegendEx
311
443
  ) -> Expression:
312
444
  return ComparisonExpression(expression1, expression2, ComparisonOperator.LESS_THAN_OR_EQUAL)
313
445
 
446
+ @staticmethod
447
+ def __to_pure_func(op1_expr: str, op2_expr: str, config: FrameToPureConfig) -> str:
448
+ return f"({op1_expr} <= {op2_expr})"
449
+
314
450
  def __init__(self, operand1: PyLegendExpressionStringReturn, operand2: PyLegendExpressionStringReturn) -> None:
315
451
  PyLegendExpressionBooleanReturn.__init__(self)
316
452
  PyLegendBinaryExpression.__init__(
317
453
  self,
318
454
  operand1,
319
455
  operand2,
320
- PyLegendStringLessThanEqualExpression.__to_sql_func
456
+ PyLegendStringLessThanEqualExpression.__to_sql_func,
457
+ PyLegendStringLessThanEqualExpression.__to_pure_func
321
458
  )
322
459
 
323
460
 
@@ -332,13 +469,18 @@ class PyLegendStringGreaterThanExpression(PyLegendBinaryExpression, PyLegendExpr
332
469
  ) -> Expression:
333
470
  return ComparisonExpression(expression1, expression2, ComparisonOperator.GREATER_THAN)
334
471
 
472
+ @staticmethod
473
+ def __to_pure_func(op1_expr: str, op2_expr: str, config: FrameToPureConfig) -> str:
474
+ return f"({op1_expr} > {op2_expr})"
475
+
335
476
  def __init__(self, operand1: PyLegendExpressionStringReturn, operand2: PyLegendExpressionStringReturn) -> None:
336
477
  PyLegendExpressionBooleanReturn.__init__(self)
337
478
  PyLegendBinaryExpression.__init__(
338
479
  self,
339
480
  operand1,
340
481
  operand2,
341
- PyLegendStringGreaterThanExpression.__to_sql_func
482
+ PyLegendStringGreaterThanExpression.__to_sql_func,
483
+ PyLegendStringGreaterThanExpression.__to_pure_func
342
484
  )
343
485
 
344
486
 
@@ -353,11 +495,42 @@ class PyLegendStringGreaterThanEqualExpression(PyLegendBinaryExpression, PyLegen
353
495
  ) -> Expression:
354
496
  return ComparisonExpression(expression1, expression2, ComparisonOperator.GREATER_THAN_OR_EQUAL)
355
497
 
498
+ @staticmethod
499
+ def __to_pure_func(op1_expr: str, op2_expr: str, config: FrameToPureConfig) -> str:
500
+ return f"({op1_expr} >= {op2_expr})"
501
+
356
502
  def __init__(self, operand1: PyLegendExpressionStringReturn, operand2: PyLegendExpressionStringReturn) -> None:
357
503
  PyLegendExpressionBooleanReturn.__init__(self)
358
504
  PyLegendBinaryExpression.__init__(
359
505
  self,
360
506
  operand1,
361
507
  operand2,
362
- PyLegendStringGreaterThanEqualExpression.__to_sql_func
508
+ PyLegendStringGreaterThanEqualExpression.__to_sql_func,
509
+ PyLegendStringGreaterThanEqualExpression.__to_pure_func
510
+ )
511
+
512
+
513
+ class PyLegendCurrentUserExpression(PyLegendNullaryExpression, PyLegendExpressionStringReturn):
514
+
515
+ @staticmethod
516
+ def __to_sql_func(
517
+ frame_name_to_base_query_map: PyLegendDict[str, QuerySpecification],
518
+ config: FrameToSqlConfig
519
+ ) -> Expression:
520
+ return ConstantExpression('CURRENT_USER')
521
+
522
+ @staticmethod
523
+ def __to_pure_func(config: FrameToPureConfig) -> str:
524
+ return "currentUserId()"
525
+
526
+ def __init__(self) -> None:
527
+ PyLegendExpressionStringReturn.__init__(self)
528
+ PyLegendNullaryExpression.__init__(
529
+ self,
530
+ PyLegendCurrentUserExpression.__to_sql_func,
531
+ PyLegendCurrentUserExpression.__to_pure_func
363
532
  )
533
+
534
+
535
+ def _escape_like_param(param: str) -> str:
536
+ return param.replace("_", "\\_").replace("%", "\\%")
@@ -18,7 +18,7 @@ from pylegend._typing import (
18
18
  PyLegendDict,
19
19
  PyLegendCallable,
20
20
  )
21
- from pylegend.core.language.expression import (
21
+ from pylegend.core.language.shared.expression import (
22
22
  PyLegendExpression,
23
23
  )
24
24
  from pylegend.core.sql.metamodel import (
@@ -26,6 +26,7 @@ from pylegend.core.sql.metamodel import (
26
26
  QuerySpecification,
27
27
  )
28
28
  from pylegend.core.tds.tds_frame import FrameToSqlConfig
29
+ from pylegend.core.tds.tds_frame import FrameToPureConfig
29
30
 
30
31
 
31
32
  __all__: PyLegendSequence[str] = [
@@ -39,6 +40,7 @@ class PyLegendUnaryExpression(PyLegendExpression, metaclass=ABCMeta):
39
40
  [Expression, PyLegendDict[str, QuerySpecification], FrameToSqlConfig],
40
41
  Expression
41
42
  ]
43
+ __to_pure_func: PyLegendCallable[[str, FrameToPureConfig], str]
42
44
 
43
45
  def __init__(
44
46
  self,
@@ -46,10 +48,12 @@ class PyLegendUnaryExpression(PyLegendExpression, metaclass=ABCMeta):
46
48
  to_sql_func: PyLegendCallable[
47
49
  [Expression, PyLegendDict[str, QuerySpecification], FrameToSqlConfig],
48
50
  Expression
49
- ]
51
+ ],
52
+ to_pure_func: PyLegendCallable[[str, FrameToPureConfig], str]
50
53
  ) -> None:
51
54
  self.__operand = operand
52
55
  self.__to_sql_func = to_sql_func
56
+ self.__to_pure_func = to_pure_func
53
57
 
54
58
  def to_sql_expression(
55
59
  self,
@@ -62,3 +66,7 @@ class PyLegendUnaryExpression(PyLegendExpression, metaclass=ABCMeta):
62
66
  frame_name_to_base_query_map,
63
67
  config
64
68
  )
69
+
70
+ def to_pure_expression(self, config: FrameToPureConfig) -> str:
71
+ op_expr = self.__operand.to_pure_expression(config)
72
+ return self.__to_pure_func(op_expr, config)
@@ -18,7 +18,7 @@ from pylegend._typing import (
18
18
  PyLegendSequence,
19
19
  PyLegendUnion,
20
20
  )
21
- from pylegend.core.language.primitives.primitive import PyLegendPrimitiveOrPythonPrimitive
21
+ from pylegend.core.language.shared.primitives.primitive import PyLegendPrimitiveOrPythonPrimitive
22
22
  from pylegend.core.language import (
23
23
  PyLegendInteger,
24
24
  PyLegendFloat,
@@ -30,7 +30,7 @@ from pylegend.core.language import (
30
30
  PyLegendStrictDate,
31
31
  convert_literal_to_literal_expression,
32
32
  )
33
- from pylegend.core.language.operations.collection_operation_expressions import (
33
+ from pylegend.core.language.shared.operations.collection_operation_expressions import (
34
34
  PyLegendCountExpression,
35
35
  PyLegendDistinctCountExpression,
36
36
  PyLegendAverageExpression,
@@ -16,15 +16,15 @@
16
16
  from pylegend._typing import (
17
17
  PyLegendSequence,
18
18
  )
19
- from pylegend.core.language.primitives.primitive import PyLegendPrimitive, PyLegendPrimitiveOrPythonPrimitive
20
- from pylegend.core.language.primitives.boolean import PyLegendBoolean
21
- from pylegend.core.language.primitives.string import PyLegendString
22
- from pylegend.core.language.primitives.number import PyLegendNumber
23
- from pylegend.core.language.primitives.integer import PyLegendInteger
24
- from pylegend.core.language.primitives.float import PyLegendFloat
25
- from pylegend.core.language.primitives.date import PyLegendDate
26
- from pylegend.core.language.primitives.datetime import PyLegendDateTime
27
- from pylegend.core.language.primitives.strictdate import PyLegendStrictDate
19
+ from pylegend.core.language.shared.primitives.primitive import PyLegendPrimitive, PyLegendPrimitiveOrPythonPrimitive
20
+ from pylegend.core.language.shared.primitives.boolean import PyLegendBoolean
21
+ from pylegend.core.language.shared.primitives.string import PyLegendString
22
+ from pylegend.core.language.shared.primitives.number import PyLegendNumber
23
+ from pylegend.core.language.shared.primitives.integer import PyLegendInteger
24
+ from pylegend.core.language.shared.primitives.float import PyLegendFloat
25
+ from pylegend.core.language.shared.primitives.date import PyLegendDate
26
+ from pylegend.core.language.shared.primitives.datetime import PyLegendDateTime
27
+ from pylegend.core.language.shared.primitives.strictdate import PyLegendStrictDate
28
28
 
29
29
 
30
30
  __all__: PyLegendSequence[str] = [