pylegend 0.12.0__py3-none-any.whl → 0.14.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.
- pylegend/core/database/sql_to_string/db_extension.py +177 -1
- pylegend/core/language/pandas_api/pandas_api_groupby_series.py +357 -0
- pylegend/core/language/pandas_api/pandas_api_series.py +202 -8
- pylegend/core/language/shared/expression.py +5 -0
- pylegend/core/language/shared/literal_expressions.py +22 -1
- pylegend/core/language/shared/operations/boolean_operation_expressions.py +144 -0
- pylegend/core/language/shared/operations/date_operation_expressions.py +91 -0
- pylegend/core/language/shared/operations/integer_operation_expressions.py +183 -1
- pylegend/core/language/shared/operations/string_operation_expressions.py +31 -1
- pylegend/core/language/shared/primitives/boolean.py +40 -0
- pylegend/core/language/shared/primitives/date.py +39 -0
- pylegend/core/language/shared/primitives/datetime.py +18 -0
- pylegend/core/language/shared/primitives/integer.py +54 -1
- pylegend/core/language/shared/primitives/strictdate.py +25 -1
- pylegend/core/language/shared/primitives/string.py +16 -2
- pylegend/core/sql/metamodel.py +50 -1
- pylegend/core/sql/metamodel_extension.py +77 -1
- pylegend/core/tds/pandas_api/frames/functions/aggregate_function.py +21 -11
- pylegend/core/tds/pandas_api/frames/functions/iloc.py +99 -0
- pylegend/core/tds/pandas_api/frames/functions/loc.py +136 -0
- pylegend/core/tds/pandas_api/frames/pandas_api_applied_function_tds_frame.py +3 -0
- pylegend/core/tds/pandas_api/frames/pandas_api_base_tds_frame.py +50 -2
- pylegend/core/tds/pandas_api/frames/pandas_api_groupby_tds_frame.py +87 -27
- pylegend/core/tds/pandas_api/frames/pandas_api_tds_frame.py +12 -0
- {pylegend-0.12.0.dist-info → pylegend-0.14.0.dist-info}/METADATA +1 -1
- {pylegend-0.12.0.dist-info → pylegend-0.14.0.dist-info}/RECORD +30 -27
- {pylegend-0.12.0.dist-info → pylegend-0.14.0.dist-info}/WHEEL +1 -1
- {pylegend-0.12.0.dist-info → pylegend-0.14.0.dist-info}/licenses/LICENSE +0 -0
- {pylegend-0.12.0.dist-info → pylegend-0.14.0.dist-info}/licenses/LICENSE.spdx +0 -0
- {pylegend-0.12.0.dist-info → pylegend-0.14.0.dist-info}/licenses/NOTICE +0 -0
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
# See the License for the specific language governing permissions and
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
|
-
from typing import TYPE_CHECKING
|
|
15
|
+
from typing import TYPE_CHECKING, runtime_checkable, Protocol
|
|
16
16
|
|
|
17
17
|
import pandas as pd
|
|
18
18
|
|
|
@@ -22,8 +22,10 @@ from pylegend._typing import (
|
|
|
22
22
|
from pylegend._typing import (
|
|
23
23
|
PyLegendSequence,
|
|
24
24
|
PyLegendOptional,
|
|
25
|
-
PyLegendTypeVar
|
|
25
|
+
PyLegendTypeVar,
|
|
26
|
+
PyLegendUnion
|
|
26
27
|
)
|
|
28
|
+
from pylegend.core.language.pandas_api.pandas_api_aggregate_specification import PyLegendAggInput
|
|
27
29
|
from pylegend.core.language.pandas_api.pandas_api_tds_row import PandasApiTdsRow
|
|
28
30
|
from pylegend.core.language.shared.column_expressions import PyLegendColumnExpression
|
|
29
31
|
from pylegend.core.language.shared.expression import (
|
|
@@ -42,7 +44,7 @@ from pylegend.core.language.shared.primitives.datetime import PyLegendDateTime
|
|
|
42
44
|
from pylegend.core.language.shared.primitives.float import PyLegendFloat
|
|
43
45
|
from pylegend.core.language.shared.primitives.integer import PyLegendInteger
|
|
44
46
|
from pylegend.core.language.shared.primitives.number import PyLegendNumber
|
|
45
|
-
from pylegend.core.language.shared.primitives.primitive import PyLegendPrimitive
|
|
47
|
+
from pylegend.core.language.shared.primitives.primitive import PyLegendPrimitive, PyLegendPrimitiveOrPythonPrimitive
|
|
46
48
|
from pylegend.core.language.shared.primitives.strictdate import PyLegendStrictDate
|
|
47
49
|
from pylegend.core.language.shared.primitives.string import PyLegendString
|
|
48
50
|
from pylegend.core.sql.metamodel import (
|
|
@@ -50,6 +52,8 @@ from pylegend.core.sql.metamodel import (
|
|
|
50
52
|
)
|
|
51
53
|
from pylegend.core.sql.metamodel import QuerySpecification
|
|
52
54
|
from pylegend.core.tds.abstract.frames.base_tds_frame import BaseTdsFrame
|
|
55
|
+
from pylegend.core.tds.pandas_api.frames.functions.filter import PandasApiFilterFunction
|
|
56
|
+
from pylegend.core.tds.pandas_api.frames.pandas_api_applied_function_tds_frame import PandasApiAppliedFunctionTdsFrame
|
|
53
57
|
from pylegend.core.tds.result_handler import ResultHandler
|
|
54
58
|
from pylegend.core.tds.tds_column import TdsColumn
|
|
55
59
|
from pylegend.core.tds.tds_frame import FrameToPureConfig
|
|
@@ -60,19 +64,39 @@ if TYPE_CHECKING:
|
|
|
60
64
|
from pylegend.core.tds.pandas_api.frames.pandas_api_tds_frame import PandasApiTdsFrame
|
|
61
65
|
|
|
62
66
|
__all__: PyLegendSequence[str] = [
|
|
63
|
-
"Series"
|
|
67
|
+
"Series",
|
|
68
|
+
"SupportsToSqlExpression",
|
|
69
|
+
"SupportsToPureExpression",
|
|
64
70
|
]
|
|
65
71
|
|
|
66
72
|
R = PyLegendTypeVar('R')
|
|
67
73
|
|
|
68
74
|
|
|
75
|
+
@runtime_checkable
|
|
76
|
+
class SupportsToSqlExpression(Protocol):
|
|
77
|
+
def to_sql_expression(
|
|
78
|
+
self,
|
|
79
|
+
frame_name_to_base_query_map: PyLegendDict[str, QuerySpecification],
|
|
80
|
+
config: FrameToSqlConfig
|
|
81
|
+
) -> Expression:
|
|
82
|
+
...
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
@runtime_checkable
|
|
86
|
+
class SupportsToPureExpression(Protocol):
|
|
87
|
+
def to_pure_expression(self, config: FrameToPureConfig) -> str:
|
|
88
|
+
...
|
|
89
|
+
|
|
90
|
+
|
|
69
91
|
class Series(PyLegendColumnExpression, PyLegendPrimitive, BaseTdsFrame):
|
|
70
92
|
def __init__(self, base_frame: "PandasApiTdsFrame", column: str):
|
|
71
93
|
row = PandasApiTdsRow.from_tds_frame("c", base_frame)
|
|
72
94
|
PyLegendColumnExpression.__init__(self, row=row, column=column)
|
|
73
95
|
|
|
74
96
|
self.__base_frame = base_frame
|
|
75
|
-
|
|
97
|
+
filtered = base_frame.filter(items=[column])
|
|
98
|
+
assert isinstance(filtered, PandasApiAppliedFunctionTdsFrame)
|
|
99
|
+
self._filtered_frame: PandasApiAppliedFunctionTdsFrame = filtered
|
|
76
100
|
|
|
77
101
|
def value(self) -> PyLegendColumnExpression:
|
|
78
102
|
return self
|
|
@@ -85,9 +109,27 @@ class Series(PyLegendColumnExpression, PyLegendPrimitive, BaseTdsFrame):
|
|
|
85
109
|
frame_name_to_base_query_map: PyLegendDict[str, QuerySpecification],
|
|
86
110
|
config: FrameToSqlConfig
|
|
87
111
|
) -> Expression:
|
|
112
|
+
applied_func = self._filtered_frame.get_applied_function()
|
|
113
|
+
if not isinstance(applied_func, PandasApiFilterFunction): # pragma: no cover
|
|
114
|
+
if isinstance(applied_func, SupportsToSqlExpression):
|
|
115
|
+
return applied_func.to_sql_expression(frame_name_to_base_query_map, config)
|
|
116
|
+
else:
|
|
117
|
+
raise NotImplementedError(
|
|
118
|
+
f"The '{applied_func.name()}' function cannot provide a SQL expression"
|
|
119
|
+
)
|
|
120
|
+
|
|
88
121
|
return super().to_sql_expression(frame_name_to_base_query_map, config)
|
|
89
122
|
|
|
90
123
|
def to_pure_expression(self, config: FrameToPureConfig) -> str:
|
|
124
|
+
applied_func = self._filtered_frame.get_applied_function()
|
|
125
|
+
if not isinstance(applied_func, PandasApiFilterFunction): # pragma: no cover
|
|
126
|
+
if isinstance(applied_func, SupportsToPureExpression):
|
|
127
|
+
return applied_func.to_pure_expression(config)
|
|
128
|
+
else:
|
|
129
|
+
raise NotImplementedError(
|
|
130
|
+
f"The '{applied_func.name()}' function cannot provide a pure expression"
|
|
131
|
+
)
|
|
132
|
+
|
|
91
133
|
return super().to_pure_expression(config)
|
|
92
134
|
|
|
93
135
|
def columns(self) -> PyLegendSequence[TdsColumn]:
|
|
@@ -120,13 +162,165 @@ class Series(PyLegendColumnExpression, PyLegendPrimitive, BaseTdsFrame):
|
|
|
120
162
|
return self._filtered_frame.execute_frame_to_pandas_df(chunk_size, pandas_df_read_config) # pragma: no cover
|
|
121
163
|
|
|
122
164
|
def to_sql_query_object(self, config: FrameToSqlConfig) -> QuerySpecification:
|
|
123
|
-
return self._filtered_frame.to_sql_query_object(config)
|
|
165
|
+
return self._filtered_frame.to_sql_query_object(config)
|
|
124
166
|
|
|
125
167
|
def to_pure(self, config: FrameToPureConfig) -> str:
|
|
126
|
-
return self._filtered_frame.to_pure(config)
|
|
168
|
+
return self._filtered_frame.to_pure(config)
|
|
127
169
|
|
|
128
170
|
def get_all_tds_frames(self) -> PyLegendSequence["BaseTdsFrame"]:
|
|
129
|
-
return self._filtered_frame.get_all_tds_frames()
|
|
171
|
+
return self._filtered_frame.get_all_tds_frames()
|
|
172
|
+
|
|
173
|
+
def aggregate(
|
|
174
|
+
self,
|
|
175
|
+
func: PyLegendAggInput,
|
|
176
|
+
axis: PyLegendUnion[int, str] = 0,
|
|
177
|
+
*args: PyLegendPrimitiveOrPythonPrimitive,
|
|
178
|
+
**kwargs: PyLegendPrimitiveOrPythonPrimitive
|
|
179
|
+
) -> "PandasApiTdsFrame":
|
|
180
|
+
return self._filtered_frame.aggregate(func, axis, *args, **kwargs)
|
|
181
|
+
|
|
182
|
+
def agg(
|
|
183
|
+
self,
|
|
184
|
+
func: PyLegendAggInput,
|
|
185
|
+
axis: PyLegendUnion[int, str] = 0,
|
|
186
|
+
*args: PyLegendPrimitiveOrPythonPrimitive,
|
|
187
|
+
**kwargs: PyLegendPrimitiveOrPythonPrimitive
|
|
188
|
+
) -> "PandasApiTdsFrame":
|
|
189
|
+
return self.aggregate(func, axis, *args, **kwargs)
|
|
190
|
+
|
|
191
|
+
def sum(
|
|
192
|
+
self,
|
|
193
|
+
axis: PyLegendUnion[int, str] = 0,
|
|
194
|
+
skipna: bool = True,
|
|
195
|
+
numeric_only: bool = False,
|
|
196
|
+
min_count: int = 0,
|
|
197
|
+
**kwargs: PyLegendPrimitiveOrPythonPrimitive
|
|
198
|
+
) -> "PandasApiTdsFrame":
|
|
199
|
+
if axis not in [0, "index"]:
|
|
200
|
+
raise NotImplementedError(f"The 'axis' parameter must be 0 or 'index' in sum function, but got: {axis}")
|
|
201
|
+
if skipna is not True:
|
|
202
|
+
raise NotImplementedError("skipna=False is not currently supported in sum function. "
|
|
203
|
+
"SQL aggregation ignores nulls by default.")
|
|
204
|
+
if numeric_only is not False:
|
|
205
|
+
raise NotImplementedError("numeric_only=True is not currently supported in sum function.")
|
|
206
|
+
if min_count != 0:
|
|
207
|
+
raise NotImplementedError(f"min_count must be 0 in sum function, but got: {min_count}")
|
|
208
|
+
if len(kwargs) > 0:
|
|
209
|
+
raise NotImplementedError(
|
|
210
|
+
f"Additional keyword arguments not supported in sum function: {list(kwargs.keys())}")
|
|
211
|
+
return self.aggregate("sum", 0)
|
|
212
|
+
|
|
213
|
+
def mean(
|
|
214
|
+
self,
|
|
215
|
+
axis: PyLegendUnion[int, str] = 0,
|
|
216
|
+
skipna: bool = True,
|
|
217
|
+
numeric_only: bool = False,
|
|
218
|
+
**kwargs: PyLegendPrimitiveOrPythonPrimitive
|
|
219
|
+
) -> "PandasApiTdsFrame":
|
|
220
|
+
if axis not in [0, "index"]:
|
|
221
|
+
raise NotImplementedError(f"The 'axis' parameter must be 0 or 'index' in mean function, but got: {axis}")
|
|
222
|
+
if skipna is not True:
|
|
223
|
+
raise NotImplementedError("skipna=False is not currently supported in mean function.")
|
|
224
|
+
if numeric_only is not False:
|
|
225
|
+
raise NotImplementedError("numeric_only=True is not currently supported in mean function.")
|
|
226
|
+
if len(kwargs) > 0:
|
|
227
|
+
raise NotImplementedError(
|
|
228
|
+
f"Additional keyword arguments not supported in mean function: {list(kwargs.keys())}")
|
|
229
|
+
return self.aggregate("mean", 0)
|
|
230
|
+
|
|
231
|
+
def min(
|
|
232
|
+
self,
|
|
233
|
+
axis: PyLegendUnion[int, str] = 0,
|
|
234
|
+
skipna: bool = True,
|
|
235
|
+
numeric_only: bool = False,
|
|
236
|
+
**kwargs: PyLegendPrimitiveOrPythonPrimitive
|
|
237
|
+
) -> "PandasApiTdsFrame":
|
|
238
|
+
if axis not in [0, "index"]:
|
|
239
|
+
raise NotImplementedError(f"The 'axis' parameter must be 0 or 'index' in min function, but got: {axis}")
|
|
240
|
+
if skipna is not True:
|
|
241
|
+
raise NotImplementedError("skipna=False is not currently supported in min function.")
|
|
242
|
+
if numeric_only is not False:
|
|
243
|
+
raise NotImplementedError("numeric_only=True is not currently supported in min function.")
|
|
244
|
+
if len(kwargs) > 0:
|
|
245
|
+
raise NotImplementedError(
|
|
246
|
+
f"Additional keyword arguments not supported in min function: {list(kwargs.keys())}")
|
|
247
|
+
return self.aggregate("min", 0)
|
|
248
|
+
|
|
249
|
+
def max(
|
|
250
|
+
self,
|
|
251
|
+
axis: PyLegendUnion[int, str] = 0,
|
|
252
|
+
skipna: bool = True,
|
|
253
|
+
numeric_only: bool = False,
|
|
254
|
+
**kwargs: PyLegendPrimitiveOrPythonPrimitive
|
|
255
|
+
) -> "PandasApiTdsFrame":
|
|
256
|
+
if axis not in [0, "index"]:
|
|
257
|
+
raise NotImplementedError(f"The 'axis' parameter must be 0 or 'index' in max function, but got: {axis}")
|
|
258
|
+
if skipna is not True:
|
|
259
|
+
raise NotImplementedError("skipna=False is not currently supported in max function.")
|
|
260
|
+
if numeric_only is not False:
|
|
261
|
+
raise NotImplementedError("numeric_only=True is not currently supported in max function.")
|
|
262
|
+
if len(kwargs) > 0:
|
|
263
|
+
raise NotImplementedError(
|
|
264
|
+
f"Additional keyword arguments not supported in max function: {list(kwargs.keys())}")
|
|
265
|
+
return self.aggregate("max", 0)
|
|
266
|
+
|
|
267
|
+
def std(
|
|
268
|
+
self,
|
|
269
|
+
axis: PyLegendUnion[int, str] = 0,
|
|
270
|
+
skipna: bool = True,
|
|
271
|
+
ddof: int = 1,
|
|
272
|
+
numeric_only: bool = False,
|
|
273
|
+
**kwargs: PyLegendPrimitiveOrPythonPrimitive
|
|
274
|
+
) -> "PandasApiTdsFrame":
|
|
275
|
+
if axis not in [0, "index"]:
|
|
276
|
+
raise NotImplementedError(f"The 'axis' parameter must be 0 or 'index' in std function, but got: {axis}")
|
|
277
|
+
if skipna is not True:
|
|
278
|
+
raise NotImplementedError("skipna=False is not currently supported in std function.")
|
|
279
|
+
if ddof != 1:
|
|
280
|
+
raise NotImplementedError(
|
|
281
|
+
f"Only ddof=1 (Sample Standard Deviation) is supported in std function, but got: {ddof}")
|
|
282
|
+
if numeric_only is not False:
|
|
283
|
+
raise NotImplementedError("numeric_only=True is not currently supported in std function.")
|
|
284
|
+
if len(kwargs) > 0:
|
|
285
|
+
raise NotImplementedError(
|
|
286
|
+
f"Additional keyword arguments not supported in std function: {list(kwargs.keys())}")
|
|
287
|
+
return self.aggregate("std", 0)
|
|
288
|
+
|
|
289
|
+
def var(
|
|
290
|
+
self,
|
|
291
|
+
axis: PyLegendUnion[int, str] = 0,
|
|
292
|
+
skipna: bool = True,
|
|
293
|
+
ddof: int = 1,
|
|
294
|
+
numeric_only: bool = False,
|
|
295
|
+
**kwargs: PyLegendPrimitiveOrPythonPrimitive
|
|
296
|
+
) -> "PandasApiTdsFrame":
|
|
297
|
+
if axis not in [0, "index"]:
|
|
298
|
+
raise NotImplementedError(f"The 'axis' parameter must be 0 or 'index' in var function, but got: {axis}")
|
|
299
|
+
if skipna is not True:
|
|
300
|
+
raise NotImplementedError("skipna=False is not currently supported in var function.")
|
|
301
|
+
if ddof != 1:
|
|
302
|
+
raise NotImplementedError(f"Only ddof=1 (Sample Variance) is supported in var function, but got: {ddof}")
|
|
303
|
+
if numeric_only is not False:
|
|
304
|
+
raise NotImplementedError("numeric_only=True is not currently supported in var function.")
|
|
305
|
+
if len(kwargs) > 0:
|
|
306
|
+
raise NotImplementedError(
|
|
307
|
+
f"Additional keyword arguments not supported in var function: {list(kwargs.keys())}")
|
|
308
|
+
return self.aggregate("var", 0)
|
|
309
|
+
|
|
310
|
+
def count(
|
|
311
|
+
self,
|
|
312
|
+
axis: PyLegendUnion[int, str] = 0,
|
|
313
|
+
numeric_only: bool = False,
|
|
314
|
+
**kwargs: PyLegendPrimitiveOrPythonPrimitive
|
|
315
|
+
) -> "PandasApiTdsFrame":
|
|
316
|
+
if axis not in [0, "index"]:
|
|
317
|
+
raise NotImplementedError(f"The 'axis' parameter must be 0 or 'index' in count function, but got: {axis}")
|
|
318
|
+
if numeric_only is not False:
|
|
319
|
+
raise NotImplementedError("numeric_only=True is not currently supported in count function.")
|
|
320
|
+
if len(kwargs) > 0:
|
|
321
|
+
raise NotImplementedError(
|
|
322
|
+
f"Additional keyword arguments not supported in count function: {list(kwargs.keys())}")
|
|
323
|
+
return self.aggregate("count", 0)
|
|
130
324
|
|
|
131
325
|
|
|
132
326
|
class BooleanSeries(Series, PyLegendBoolean, PyLegendExpressionBooleanReturn): # type: ignore
|
|
@@ -36,6 +36,7 @@ __all__: PyLegendSequence[str] = [
|
|
|
36
36
|
"PyLegendExpressionDateReturn",
|
|
37
37
|
"PyLegendExpressionDateTimeReturn",
|
|
38
38
|
"PyLegendExpressionStrictDateReturn",
|
|
39
|
+
"PyLegendExpressionNullReturn"
|
|
39
40
|
]
|
|
40
41
|
|
|
41
42
|
|
|
@@ -86,3 +87,7 @@ class PyLegendExpressionDateTimeReturn(PyLegendExpressionDateReturn, metaclass=A
|
|
|
86
87
|
|
|
87
88
|
class PyLegendExpressionStrictDateReturn(PyLegendExpressionDateReturn, metaclass=ABCMeta):
|
|
88
89
|
pass
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
class PyLegendExpressionNullReturn(PyLegendExpression, metaclass=ABCMeta):
|
|
93
|
+
pass
|
|
@@ -27,6 +27,7 @@ from pylegend.core.language.shared.expression import (
|
|
|
27
27
|
PyLegendExpressionFloatReturn,
|
|
28
28
|
PyLegendExpressionDateTimeReturn,
|
|
29
29
|
PyLegendExpressionStrictDateReturn,
|
|
30
|
+
PyLegendExpressionNullReturn,
|
|
30
31
|
)
|
|
31
32
|
from pylegend.core.sql.metamodel import (
|
|
32
33
|
Expression,
|
|
@@ -37,6 +38,7 @@ from pylegend.core.sql.metamodel import (
|
|
|
37
38
|
QuerySpecification,
|
|
38
39
|
Cast,
|
|
39
40
|
ColumnType,
|
|
41
|
+
NullLiteral,
|
|
40
42
|
)
|
|
41
43
|
from pylegend.core.tds.tds_frame import FrameToSqlConfig
|
|
42
44
|
from pylegend.core.tds.tds_frame import FrameToPureConfig
|
|
@@ -180,8 +182,25 @@ class PyLegendStrictDateLiteralExpression(PyLegendExpressionStrictDateReturn):
|
|
|
180
182
|
return True
|
|
181
183
|
|
|
182
184
|
|
|
185
|
+
class PyLegendNullLiteralExpression(PyLegendExpressionNullReturn):
|
|
186
|
+
__value: None
|
|
187
|
+
|
|
188
|
+
def __init__(self) -> None:
|
|
189
|
+
return
|
|
190
|
+
|
|
191
|
+
def to_sql_expression(
|
|
192
|
+
self,
|
|
193
|
+
frame_name_to_base_query_map: PyLegendDict[str, QuerySpecification],
|
|
194
|
+
config: FrameToSqlConfig
|
|
195
|
+
) -> Expression:
|
|
196
|
+
return NullLiteral()
|
|
197
|
+
|
|
198
|
+
def to_pure_expression(self, config: FrameToPureConfig) -> str:
|
|
199
|
+
return "[]"
|
|
200
|
+
|
|
201
|
+
|
|
183
202
|
def convert_literal_to_literal_expression(
|
|
184
|
-
literal: PyLegendUnion[int, float, bool, str, datetime, date]
|
|
203
|
+
literal: PyLegendUnion[int, float, bool, str, datetime, date, None]
|
|
185
204
|
) -> PyLegendExpression:
|
|
186
205
|
if isinstance(literal, bool):
|
|
187
206
|
return PyLegendBooleanLiteralExpression(literal)
|
|
@@ -195,5 +214,7 @@ def convert_literal_to_literal_expression(
|
|
|
195
214
|
return PyLegendDateTimeLiteralExpression(literal)
|
|
196
215
|
if isinstance(literal, date):
|
|
197
216
|
return PyLegendStrictDateLiteralExpression(literal)
|
|
217
|
+
if isinstance(literal, type(None)):
|
|
218
|
+
return PyLegendNullLiteralExpression()
|
|
198
219
|
|
|
199
220
|
raise TypeError(f"Cannot convert value - {literal} of type {type(literal)} to literal expression")
|
|
@@ -28,6 +28,8 @@ from pylegend.core.sql.metamodel import (
|
|
|
28
28
|
LogicalBinaryExpression,
|
|
29
29
|
LogicalBinaryType,
|
|
30
30
|
NotExpression,
|
|
31
|
+
ComparisonExpression,
|
|
32
|
+
ComparisonOperator,
|
|
31
33
|
)
|
|
32
34
|
from pylegend.core.tds.tds_frame import FrameToSqlConfig
|
|
33
35
|
from pylegend.core.tds.tds_frame import FrameToPureConfig
|
|
@@ -37,6 +39,11 @@ __all__: PyLegendSequence[str] = [
|
|
|
37
39
|
"PyLegendBooleanOrExpression",
|
|
38
40
|
"PyLegendBooleanAndExpression",
|
|
39
41
|
"PyLegendBooleanNotExpression",
|
|
42
|
+
"PyLegendBooleanLessThanExpression",
|
|
43
|
+
"PyLegendBooleanLessThanEqualExpression",
|
|
44
|
+
"PyLegendBooleanGreaterThanExpression",
|
|
45
|
+
"PyLegendBooleanGreaterThanEqualExpression",
|
|
46
|
+
"PyLegendBooleanXorExpression"
|
|
40
47
|
]
|
|
41
48
|
|
|
42
49
|
|
|
@@ -98,6 +105,143 @@ class PyLegendBooleanAndExpression(PyLegendBinaryExpression, PyLegendExpressionB
|
|
|
98
105
|
)
|
|
99
106
|
|
|
100
107
|
|
|
108
|
+
class PyLegendBooleanLessThanExpression(PyLegendBinaryExpression, PyLegendExpressionBooleanReturn):
|
|
109
|
+
|
|
110
|
+
@staticmethod
|
|
111
|
+
def __to_sql_func(
|
|
112
|
+
expression1: Expression,
|
|
113
|
+
expression2: Expression,
|
|
114
|
+
frame_name_to_base_query_map: PyLegendDict[str, QuerySpecification],
|
|
115
|
+
config: FrameToSqlConfig
|
|
116
|
+
) -> Expression:
|
|
117
|
+
return ComparisonExpression(expression1, expression2, ComparisonOperator.LESS_THAN)
|
|
118
|
+
|
|
119
|
+
@staticmethod
|
|
120
|
+
def __to_pure_func(op1_expr: str, op2_expr: str, config: FrameToPureConfig) -> str:
|
|
121
|
+
return f"({op1_expr} < {op2_expr})"
|
|
122
|
+
|
|
123
|
+
def __init__(self, operand1: PyLegendExpressionBooleanReturn, operand2: PyLegendExpressionBooleanReturn) -> None:
|
|
124
|
+
PyLegendExpressionBooleanReturn.__init__(self)
|
|
125
|
+
PyLegendBinaryExpression.__init__(
|
|
126
|
+
self,
|
|
127
|
+
operand1,
|
|
128
|
+
operand2,
|
|
129
|
+
PyLegendBooleanLessThanExpression.__to_sql_func,
|
|
130
|
+
PyLegendBooleanLessThanExpression.__to_pure_func,
|
|
131
|
+
non_nullable=True
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
class PyLegendBooleanLessThanEqualExpression(PyLegendBinaryExpression, PyLegendExpressionBooleanReturn):
|
|
136
|
+
|
|
137
|
+
@staticmethod
|
|
138
|
+
def __to_sql_func(
|
|
139
|
+
expression1: Expression,
|
|
140
|
+
expression2: Expression,
|
|
141
|
+
frame_name_to_base_query_map: PyLegendDict[str, QuerySpecification],
|
|
142
|
+
config: FrameToSqlConfig
|
|
143
|
+
) -> Expression:
|
|
144
|
+
return ComparisonExpression(expression1, expression2, ComparisonOperator.LESS_THAN_OR_EQUAL)
|
|
145
|
+
|
|
146
|
+
@staticmethod
|
|
147
|
+
def __to_pure_func(op1_expr: str, op2_expr: str, config: FrameToPureConfig) -> str:
|
|
148
|
+
return f"({op1_expr} <= {op2_expr})"
|
|
149
|
+
|
|
150
|
+
def __init__(self, operand1: PyLegendExpressionBooleanReturn, operand2: PyLegendExpressionBooleanReturn) -> None:
|
|
151
|
+
PyLegendExpressionBooleanReturn.__init__(self)
|
|
152
|
+
PyLegendBinaryExpression.__init__(
|
|
153
|
+
self,
|
|
154
|
+
operand1,
|
|
155
|
+
operand2,
|
|
156
|
+
PyLegendBooleanLessThanEqualExpression.__to_sql_func,
|
|
157
|
+
PyLegendBooleanLessThanEqualExpression.__to_pure_func,
|
|
158
|
+
non_nullable=True
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
class PyLegendBooleanGreaterThanExpression(PyLegendBinaryExpression, PyLegendExpressionBooleanReturn):
|
|
163
|
+
|
|
164
|
+
@staticmethod
|
|
165
|
+
def __to_sql_func(
|
|
166
|
+
expression1: Expression,
|
|
167
|
+
expression2: Expression,
|
|
168
|
+
frame_name_to_base_query_map: PyLegendDict[str, QuerySpecification],
|
|
169
|
+
config: FrameToSqlConfig
|
|
170
|
+
) -> Expression:
|
|
171
|
+
return ComparisonExpression(expression1, expression2, ComparisonOperator.GREATER_THAN)
|
|
172
|
+
|
|
173
|
+
@staticmethod
|
|
174
|
+
def __to_pure_func(op1_expr: str, op2_expr: str, config: FrameToPureConfig) -> str:
|
|
175
|
+
return f"({op1_expr} > {op2_expr})"
|
|
176
|
+
|
|
177
|
+
def __init__(self, operand1: PyLegendExpressionBooleanReturn, operand2: PyLegendExpressionBooleanReturn) -> None:
|
|
178
|
+
PyLegendExpressionBooleanReturn.__init__(self)
|
|
179
|
+
PyLegendBinaryExpression.__init__(
|
|
180
|
+
self,
|
|
181
|
+
operand1,
|
|
182
|
+
operand2,
|
|
183
|
+
PyLegendBooleanGreaterThanExpression.__to_sql_func,
|
|
184
|
+
PyLegendBooleanGreaterThanExpression.__to_pure_func,
|
|
185
|
+
non_nullable=True
|
|
186
|
+
)
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
class PyLegendBooleanGreaterThanEqualExpression(PyLegendBinaryExpression, PyLegendExpressionBooleanReturn):
|
|
190
|
+
|
|
191
|
+
@staticmethod
|
|
192
|
+
def __to_sql_func(
|
|
193
|
+
expression1: Expression,
|
|
194
|
+
expression2: Expression,
|
|
195
|
+
frame_name_to_base_query_map: PyLegendDict[str, QuerySpecification],
|
|
196
|
+
config: FrameToSqlConfig
|
|
197
|
+
) -> Expression:
|
|
198
|
+
return ComparisonExpression(expression1, expression2, ComparisonOperator.GREATER_THAN_OR_EQUAL)
|
|
199
|
+
|
|
200
|
+
@staticmethod
|
|
201
|
+
def __to_pure_func(op1_expr: str, op2_expr: str, config: FrameToPureConfig) -> str:
|
|
202
|
+
return f"({op1_expr} >= {op2_expr})"
|
|
203
|
+
|
|
204
|
+
def __init__(self, operand1: PyLegendExpressionBooleanReturn, operand2: PyLegendExpressionBooleanReturn) -> None:
|
|
205
|
+
PyLegendExpressionBooleanReturn.__init__(self)
|
|
206
|
+
PyLegendBinaryExpression.__init__(
|
|
207
|
+
self,
|
|
208
|
+
operand1,
|
|
209
|
+
operand2,
|
|
210
|
+
PyLegendBooleanGreaterThanEqualExpression.__to_sql_func,
|
|
211
|
+
PyLegendBooleanGreaterThanEqualExpression.__to_pure_func,
|
|
212
|
+
non_nullable=True
|
|
213
|
+
)
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
class PyLegendBooleanXorExpression(PyLegendBinaryExpression, PyLegendExpressionBooleanReturn):
|
|
217
|
+
|
|
218
|
+
@staticmethod
|
|
219
|
+
def __to_sql_func(
|
|
220
|
+
expression1: Expression,
|
|
221
|
+
expression2: Expression,
|
|
222
|
+
frame_name_to_base_query_map: PyLegendDict[str, QuerySpecification],
|
|
223
|
+
config: FrameToSqlConfig
|
|
224
|
+
) -> Expression:
|
|
225
|
+
return ComparisonExpression(expression1, expression2, ComparisonOperator.NOT_EQUAL)
|
|
226
|
+
|
|
227
|
+
@staticmethod
|
|
228
|
+
def __to_pure_func(op1_expr: str, op2_expr: str, config: FrameToPureConfig) -> str:
|
|
229
|
+
return generate_pure_functional_call("xor", [op1_expr, op2_expr])
|
|
230
|
+
|
|
231
|
+
def __init__(self, operand1: PyLegendExpressionBooleanReturn, operand2: PyLegendExpressionBooleanReturn) -> None:
|
|
232
|
+
PyLegendExpressionBooleanReturn.__init__(self)
|
|
233
|
+
PyLegendBinaryExpression.__init__(
|
|
234
|
+
self,
|
|
235
|
+
operand1,
|
|
236
|
+
operand2,
|
|
237
|
+
PyLegendBooleanXorExpression.__to_sql_func,
|
|
238
|
+
PyLegendBooleanXorExpression.__to_pure_func,
|
|
239
|
+
non_nullable=True,
|
|
240
|
+
first_operand_needs_to_be_non_nullable=True,
|
|
241
|
+
second_operand_needs_to_be_non_nullable=True
|
|
242
|
+
)
|
|
243
|
+
|
|
244
|
+
|
|
101
245
|
class PyLegendBooleanNotExpression(PyLegendUnaryExpression, PyLegendExpressionBooleanReturn):
|
|
102
246
|
|
|
103
247
|
@staticmethod
|
|
@@ -22,8 +22,10 @@ from pylegend.core.language.shared.expression import (
|
|
|
22
22
|
PyLegendExpressionStrictDateReturn,
|
|
23
23
|
PyLegendExpressionIntegerReturn,
|
|
24
24
|
PyLegendExpressionBooleanReturn,
|
|
25
|
+
PyLegendExpression
|
|
25
26
|
)
|
|
26
27
|
from pylegend.core.language.shared.operations.binary_expression import PyLegendBinaryExpression
|
|
28
|
+
from pylegend.core.language.shared.operations.nary_expression import PyLegendNaryExpression
|
|
27
29
|
from pylegend.core.language.shared.operations.nullary_expression import PyLegendNullaryExpression
|
|
28
30
|
from pylegend.core.language.shared.operations.unary_expression import PyLegendUnaryExpression
|
|
29
31
|
from pylegend.core.language.shared.helpers import generate_pure_functional_call
|
|
@@ -61,6 +63,10 @@ from pylegend.core.sql.metamodel_extension import (
|
|
|
61
63
|
MinuteExpression,
|
|
62
64
|
SecondExpression,
|
|
63
65
|
EpochExpression,
|
|
66
|
+
DateAdjustExpression,
|
|
67
|
+
DateDiffExpression,
|
|
68
|
+
DateTimeBucketExpression,
|
|
69
|
+
DateType,
|
|
64
70
|
)
|
|
65
71
|
|
|
66
72
|
|
|
@@ -91,6 +97,9 @@ __all__: PyLegendSequence[str] = [
|
|
|
91
97
|
"PyLegendDateLessThanEqualExpression",
|
|
92
98
|
"PyLegendDateGreaterThanExpression",
|
|
93
99
|
"PyLegendDateGreaterThanEqualExpression",
|
|
100
|
+
"PyLegendDateAdjustExpression",
|
|
101
|
+
"PyLegendDateDiffExpression",
|
|
102
|
+
"PyLegendDateTimeBucketExpression",
|
|
94
103
|
]
|
|
95
104
|
|
|
96
105
|
|
|
@@ -780,3 +789,85 @@ class PyLegendDateGreaterThanEqualExpression(PyLegendBinaryExpression, PyLegendE
|
|
|
780
789
|
|
|
781
790
|
def is_non_nullable(self) -> bool:
|
|
782
791
|
return True
|
|
792
|
+
|
|
793
|
+
|
|
794
|
+
class PyLegendDateAdjustExpression(PyLegendNaryExpression, PyLegendExpressionDateReturn):
|
|
795
|
+
|
|
796
|
+
@staticmethod
|
|
797
|
+
def __to_sql_func(
|
|
798
|
+
expressions: list[Expression],
|
|
799
|
+
frame_name_to_base_query_map: PyLegendDict[str, QuerySpecification],
|
|
800
|
+
config: FrameToSqlConfig
|
|
801
|
+
) -> Expression:
|
|
802
|
+
return DateAdjustExpression(expressions[0], expressions[1], expressions[2]) # type:ignore
|
|
803
|
+
|
|
804
|
+
@staticmethod
|
|
805
|
+
def __to_pure_func(op_expr: list[str], config: FrameToPureConfig) -> str:
|
|
806
|
+
return generate_pure_functional_call("adjust", [op_expr[0], op_expr[1], f"DurationUnit.{op_expr[2]}"])
|
|
807
|
+
|
|
808
|
+
def __init__(self, operands: list[PyLegendExpression]) -> None:
|
|
809
|
+
PyLegendExpressionDateReturn.__init__(self)
|
|
810
|
+
PyLegendNaryExpression.__init__(
|
|
811
|
+
self,
|
|
812
|
+
operands,
|
|
813
|
+
PyLegendDateAdjustExpression.__to_sql_func,
|
|
814
|
+
PyLegendDateAdjustExpression.__to_pure_func,
|
|
815
|
+
non_nullable=True,
|
|
816
|
+
operands_non_nullable_flags=[True, True, True]
|
|
817
|
+
)
|
|
818
|
+
|
|
819
|
+
|
|
820
|
+
class PyLegendDateDiffExpression(PyLegendNaryExpression, PyLegendExpressionIntegerReturn):
|
|
821
|
+
|
|
822
|
+
@staticmethod
|
|
823
|
+
def __to_sql_func(
|
|
824
|
+
expressions: list[Expression],
|
|
825
|
+
frame_name_to_base_query_map: PyLegendDict[str, QuerySpecification],
|
|
826
|
+
config: FrameToSqlConfig
|
|
827
|
+
) -> Expression:
|
|
828
|
+
return DateDiffExpression(expressions[0], expressions[1], expressions[2]) # type: ignore
|
|
829
|
+
|
|
830
|
+
@staticmethod
|
|
831
|
+
def __to_pure_func(op_expr: list[str], config: FrameToPureConfig) -> str:
|
|
832
|
+
return generate_pure_functional_call("dateDiff", [op_expr[0], op_expr[1], f"DurationUnit.{op_expr[2]}"])
|
|
833
|
+
|
|
834
|
+
def __init__(self, operands: list[PyLegendExpression]) -> None:
|
|
835
|
+
PyLegendExpressionIntegerReturn.__init__(self)
|
|
836
|
+
PyLegendNaryExpression.__init__(
|
|
837
|
+
self,
|
|
838
|
+
operands,
|
|
839
|
+
PyLegendDateDiffExpression.__to_sql_func,
|
|
840
|
+
PyLegendDateDiffExpression.__to_pure_func,
|
|
841
|
+
non_nullable=True,
|
|
842
|
+
operands_non_nullable_flags=[True, True, True]
|
|
843
|
+
)
|
|
844
|
+
|
|
845
|
+
|
|
846
|
+
class PyLegendDateTimeBucketExpression(PyLegendNaryExpression, PyLegendExpressionDateReturn):
|
|
847
|
+
|
|
848
|
+
@staticmethod
|
|
849
|
+
def __to_sql_func(
|
|
850
|
+
expressions: list[Expression],
|
|
851
|
+
frame_name_to_base_query_map: PyLegendDict[str, QuerySpecification],
|
|
852
|
+
config: FrameToSqlConfig
|
|
853
|
+
) -> Expression:
|
|
854
|
+
return DateTimeBucketExpression(
|
|
855
|
+
expressions[0],
|
|
856
|
+
expressions[1],
|
|
857
|
+
expressions[2], # type: ignore
|
|
858
|
+
DateType.DateTime if expressions[3].value == "DATETIME" else DateType.StrictDate) # type: ignore
|
|
859
|
+
|
|
860
|
+
@staticmethod
|
|
861
|
+
def __to_pure_func(op_expr: list[str], config: FrameToPureConfig) -> str:
|
|
862
|
+
return generate_pure_functional_call("timeBucket", [op_expr[0], op_expr[1], f"DurationUnit.{op_expr[2]}"])
|
|
863
|
+
|
|
864
|
+
def __init__(self, operands: list[PyLegendExpression]) -> None:
|
|
865
|
+
PyLegendExpressionDateReturn.__init__(self)
|
|
866
|
+
PyLegendNaryExpression.__init__(
|
|
867
|
+
self,
|
|
868
|
+
operands,
|
|
869
|
+
PyLegendDateTimeBucketExpression.__to_sql_func,
|
|
870
|
+
PyLegendDateTimeBucketExpression.__to_pure_func,
|
|
871
|
+
non_nullable=True,
|
|
872
|
+
operands_non_nullable_flags=[True, True, True]
|
|
873
|
+
)
|