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.
Files changed (30) hide show
  1. pylegend/core/database/sql_to_string/db_extension.py +177 -1
  2. pylegend/core/language/pandas_api/pandas_api_groupby_series.py +357 -0
  3. pylegend/core/language/pandas_api/pandas_api_series.py +202 -8
  4. pylegend/core/language/shared/expression.py +5 -0
  5. pylegend/core/language/shared/literal_expressions.py +22 -1
  6. pylegend/core/language/shared/operations/boolean_operation_expressions.py +144 -0
  7. pylegend/core/language/shared/operations/date_operation_expressions.py +91 -0
  8. pylegend/core/language/shared/operations/integer_operation_expressions.py +183 -1
  9. pylegend/core/language/shared/operations/string_operation_expressions.py +31 -1
  10. pylegend/core/language/shared/primitives/boolean.py +40 -0
  11. pylegend/core/language/shared/primitives/date.py +39 -0
  12. pylegend/core/language/shared/primitives/datetime.py +18 -0
  13. pylegend/core/language/shared/primitives/integer.py +54 -1
  14. pylegend/core/language/shared/primitives/strictdate.py +25 -1
  15. pylegend/core/language/shared/primitives/string.py +16 -2
  16. pylegend/core/sql/metamodel.py +50 -1
  17. pylegend/core/sql/metamodel_extension.py +77 -1
  18. pylegend/core/tds/pandas_api/frames/functions/aggregate_function.py +21 -11
  19. pylegend/core/tds/pandas_api/frames/functions/iloc.py +99 -0
  20. pylegend/core/tds/pandas_api/frames/functions/loc.py +136 -0
  21. pylegend/core/tds/pandas_api/frames/pandas_api_applied_function_tds_frame.py +3 -0
  22. pylegend/core/tds/pandas_api/frames/pandas_api_base_tds_frame.py +50 -2
  23. pylegend/core/tds/pandas_api/frames/pandas_api_groupby_tds_frame.py +87 -27
  24. pylegend/core/tds/pandas_api/frames/pandas_api_tds_frame.py +12 -0
  25. {pylegend-0.12.0.dist-info → pylegend-0.14.0.dist-info}/METADATA +1 -1
  26. {pylegend-0.12.0.dist-info → pylegend-0.14.0.dist-info}/RECORD +30 -27
  27. {pylegend-0.12.0.dist-info → pylegend-0.14.0.dist-info}/WHEEL +1 -1
  28. {pylegend-0.12.0.dist-info → pylegend-0.14.0.dist-info}/licenses/LICENSE +0 -0
  29. {pylegend-0.12.0.dist-info → pylegend-0.14.0.dist-info}/licenses/LICENSE.spdx +0 -0
  30. {pylegend-0.12.0.dist-info → pylegend-0.14.0.dist-info}/licenses/NOTICE +0 -0
@@ -30,10 +30,15 @@ from pylegend.core.sql.metamodel import (
30
30
  ArithmeticExpression,
31
31
  NegativeExpression,
32
32
  FunctionCall,
33
- QualifiedName
33
+ QualifiedName,
34
+ BitwiseBinaryExpression,
35
+ BitwiseBinaryOperator,
36
+ BitwiseShiftExpression,
37
+ BitwiseShiftDirection
34
38
  )
35
39
  from pylegend.core.sql.metamodel_extension import (
36
40
  AbsoluteExpression,
41
+ BitwiseNotExpression,
37
42
  )
38
43
  from pylegend.core.tds.tds_frame import FrameToSqlConfig
39
44
  from pylegend.core.tds.tds_frame import FrameToPureConfig
@@ -47,6 +52,12 @@ __all__: PyLegendSequence[str] = [
47
52
  "PyLegendIntegerMultiplyExpression",
48
53
  "PyLegendIntegerModuloExpression",
49
54
  "PyLegendIntegerCharExpression",
55
+ "PyLegendIntegerBitAndExpression",
56
+ "PyLegendIntegerBitOrExpression",
57
+ "PyLegendIntegerBitXorExpression",
58
+ "PyLegendIntegerBitShiftLeftExpression",
59
+ "PyLegendIntegerBitShiftRightExpression",
60
+ "PyLegendIntegerBitNotExpression"
50
61
  ]
51
62
 
52
63
 
@@ -253,3 +264,174 @@ class PyLegendIntegerCharExpression(PyLegendUnaryExpression, PyLegendExpressionS
253
264
  non_nullable=True,
254
265
  operand_needs_to_be_non_nullable=True,
255
266
  )
267
+
268
+
269
+ class PyLegendIntegerBitAndExpression(PyLegendBinaryExpression, PyLegendExpressionIntegerReturn):
270
+
271
+ @staticmethod
272
+ def __to_sql_func(
273
+ expression1: Expression,
274
+ expression2: Expression,
275
+ frame_name_to_base_query_map: PyLegendDict[str, QuerySpecification],
276
+ config: FrameToSqlConfig
277
+ ) -> Expression:
278
+ return BitwiseBinaryExpression(expression1, expression2, BitwiseBinaryOperator.AND)
279
+
280
+ @staticmethod
281
+ def __to_pure_func(op1_expr: str, op2_expr: str, config: FrameToPureConfig) -> str:
282
+ return generate_pure_functional_call("bitAnd", [op1_expr, op2_expr])
283
+
284
+ def __init__(self, operand1: PyLegendExpressionIntegerReturn, operand2: PyLegendExpressionIntegerReturn) -> None:
285
+ PyLegendExpressionIntegerReturn.__init__(self)
286
+ PyLegendBinaryExpression.__init__(
287
+ self,
288
+ operand1,
289
+ operand2,
290
+ PyLegendIntegerBitAndExpression.__to_sql_func,
291
+ PyLegendIntegerBitAndExpression.__to_pure_func,
292
+ non_nullable=True,
293
+ first_operand_needs_to_be_non_nullable=True,
294
+ second_operand_needs_to_be_non_nullable=True
295
+ )
296
+
297
+
298
+ class PyLegendIntegerBitOrExpression(PyLegendBinaryExpression, PyLegendExpressionIntegerReturn):
299
+
300
+ @staticmethod
301
+ def __to_sql_func(
302
+ expression1: Expression,
303
+ expression2: Expression,
304
+ frame_name_to_base_query_map: PyLegendDict[str, QuerySpecification],
305
+ config: FrameToSqlConfig
306
+ ) -> Expression:
307
+ return BitwiseBinaryExpression(expression1, expression2, BitwiseBinaryOperator.OR)
308
+
309
+ @staticmethod
310
+ def __to_pure_func(op1_expr: str, op2_expr: str, config: FrameToPureConfig) -> str:
311
+ return generate_pure_functional_call("bitOr", [op1_expr, op2_expr])
312
+
313
+ def __init__(self, operand1: PyLegendExpressionIntegerReturn, operand2: PyLegendExpressionIntegerReturn) -> None:
314
+ PyLegendExpressionIntegerReturn.__init__(self)
315
+ PyLegendBinaryExpression.__init__(
316
+ self,
317
+ operand1,
318
+ operand2,
319
+ PyLegendIntegerBitOrExpression.__to_sql_func,
320
+ PyLegendIntegerBitOrExpression.__to_pure_func,
321
+ non_nullable=True,
322
+ first_operand_needs_to_be_non_nullable=True,
323
+ second_operand_needs_to_be_non_nullable=True
324
+ )
325
+
326
+
327
+ class PyLegendIntegerBitXorExpression(PyLegendBinaryExpression, PyLegendExpressionIntegerReturn):
328
+
329
+ @staticmethod
330
+ def __to_sql_func(
331
+ expression1: Expression,
332
+ expression2: Expression,
333
+ frame_name_to_base_query_map: PyLegendDict[str, QuerySpecification],
334
+ config: FrameToSqlConfig
335
+ ) -> Expression:
336
+ return BitwiseBinaryExpression(expression1, expression2, BitwiseBinaryOperator.XOR)
337
+
338
+ @staticmethod
339
+ def __to_pure_func(op1_expr: str, op2_expr: str, config: FrameToPureConfig) -> str:
340
+ return generate_pure_functional_call("bitXor", [op1_expr, op2_expr])
341
+
342
+ def __init__(self, operand1: PyLegendExpressionIntegerReturn, operand2: PyLegendExpressionIntegerReturn) -> None:
343
+ PyLegendExpressionIntegerReturn.__init__(self)
344
+ PyLegendBinaryExpression.__init__(
345
+ self,
346
+ operand1,
347
+ operand2,
348
+ PyLegendIntegerBitXorExpression.__to_sql_func,
349
+ PyLegendIntegerBitXorExpression.__to_pure_func,
350
+ non_nullable=True,
351
+ first_operand_needs_to_be_non_nullable=True,
352
+ second_operand_needs_to_be_non_nullable=True
353
+ )
354
+
355
+
356
+ class PyLegendIntegerBitShiftLeftExpression(PyLegendBinaryExpression, PyLegendExpressionIntegerReturn):
357
+
358
+ @staticmethod
359
+ def __to_sql_func(
360
+ expression1: Expression,
361
+ expression2: Expression,
362
+ frame_name_to_base_query_map: PyLegendDict[str, QuerySpecification],
363
+ config: FrameToSqlConfig
364
+ ) -> Expression:
365
+ return BitwiseShiftExpression(expression1, expression2, BitwiseShiftDirection.LEFT)
366
+
367
+ @staticmethod
368
+ def __to_pure_func(op1_expr: str, op2_expr: str, config: FrameToPureConfig) -> str:
369
+ return generate_pure_functional_call("bitShiftLeft", [op1_expr, op2_expr])
370
+
371
+ def __init__(self, operand1: PyLegendExpressionIntegerReturn, operand2: PyLegendExpressionIntegerReturn) -> None:
372
+ PyLegendExpressionIntegerReturn.__init__(self)
373
+ PyLegendBinaryExpression.__init__(
374
+ self,
375
+ operand1,
376
+ operand2,
377
+ PyLegendIntegerBitShiftLeftExpression.__to_sql_func,
378
+ PyLegendIntegerBitShiftLeftExpression.__to_pure_func,
379
+ non_nullable=True,
380
+ first_operand_needs_to_be_non_nullable=True,
381
+ second_operand_needs_to_be_non_nullable=True
382
+ )
383
+
384
+
385
+ class PyLegendIntegerBitShiftRightExpression(PyLegendBinaryExpression, PyLegendExpressionIntegerReturn):
386
+
387
+ @staticmethod
388
+ def __to_sql_func(
389
+ expression1: Expression,
390
+ expression2: Expression,
391
+ frame_name_to_base_query_map: PyLegendDict[str, QuerySpecification],
392
+ config: FrameToSqlConfig
393
+ ) -> Expression:
394
+ return BitwiseShiftExpression(expression1, expression2, BitwiseShiftDirection.RIGHT)
395
+
396
+ @staticmethod
397
+ def __to_pure_func(op1_expr: str, op2_expr: str, config: FrameToPureConfig) -> str:
398
+ return generate_pure_functional_call("bitShiftRight", [op1_expr, op2_expr])
399
+
400
+ def __init__(self, operand1: PyLegendExpressionIntegerReturn, operand2: PyLegendExpressionIntegerReturn) -> None:
401
+ PyLegendExpressionIntegerReturn.__init__(self)
402
+ PyLegendBinaryExpression.__init__(
403
+ self,
404
+ operand1,
405
+ operand2,
406
+ PyLegendIntegerBitShiftRightExpression.__to_sql_func,
407
+ PyLegendIntegerBitShiftRightExpression.__to_pure_func,
408
+ non_nullable=True,
409
+ first_operand_needs_to_be_non_nullable=True,
410
+ second_operand_needs_to_be_non_nullable=True
411
+ )
412
+
413
+
414
+ class PyLegendIntegerBitNotExpression(PyLegendUnaryExpression, PyLegendExpressionIntegerReturn):
415
+
416
+ @staticmethod
417
+ def __to_sql_func(
418
+ expression: Expression,
419
+ frame_name_to_base_query_map: PyLegendDict[str, QuerySpecification],
420
+ config: FrameToSqlConfig
421
+ ) -> Expression:
422
+ return BitwiseNotExpression(expression)
423
+
424
+ @staticmethod
425
+ def __to_pure_func(op_expr: str, config: FrameToPureConfig) -> str:
426
+ return generate_pure_functional_call("bitNot", [op_expr])
427
+
428
+ def __init__(self, operand: PyLegendExpressionIntegerReturn) -> None:
429
+ PyLegendExpressionIntegerReturn.__init__(self)
430
+ PyLegendUnaryExpression.__init__(
431
+ self,
432
+ operand,
433
+ PyLegendIntegerBitNotExpression.__to_sql_func,
434
+ PyLegendIntegerBitNotExpression.__to_pure_func,
435
+ non_nullable=True,
436
+ operand_needs_to_be_non_nullable=True,
437
+ )
@@ -92,7 +92,8 @@ __all__: PyLegendSequence[str] = [
92
92
  "PyLegendStringSplitPartExpression",
93
93
  "PyLegendStringRepeatStringExpression",
94
94
  "PyLegendStringFullMatchExpression",
95
- "PyLegendStringMatchExpression"
95
+ "PyLegendStringMatchExpression",
96
+ "PyLegendStringCoalesceExpression"
96
97
  ]
97
98
 
98
99
 
@@ -1149,6 +1150,35 @@ class PyLegendStringSplitPartExpression(PyLegendNaryExpression, PyLegendExpressi
1149
1150
  )
1150
1151
 
1151
1152
 
1153
+ class PyLegendStringCoalesceExpression(PyLegendNaryExpression, PyLegendExpressionStringReturn):
1154
+
1155
+ @staticmethod
1156
+ def __to_sql_func(
1157
+ expressions: list[Expression],
1158
+ frame_name_to_base_query_map: PyLegendDict[str, QuerySpecification],
1159
+ config: FrameToSqlConfig
1160
+ ) -> Expression:
1161
+ return FunctionCall(
1162
+ name=QualifiedName(parts=["COALESCE"]),
1163
+ distinct=False,
1164
+ arguments=expressions,
1165
+ filter_=None, window=None
1166
+ )
1167
+
1168
+ @staticmethod
1169
+ def __to_pure_func(op_expr: list[str], config: FrameToPureConfig) -> str:
1170
+ return generate_pure_functional_call("meta::pure::functions::flow::coalesce", op_expr)
1171
+
1172
+ def __init__(self, operands: list[PyLegendExpression]) -> None:
1173
+ PyLegendExpressionStringReturn.__init__(self)
1174
+ PyLegendNaryExpression.__init__(
1175
+ self,
1176
+ operands,
1177
+ PyLegendStringCoalesceExpression.__to_sql_func,
1178
+ PyLegendStringCoalesceExpression.__to_pure_func
1179
+ )
1180
+
1181
+
1152
1182
  class PyLegendCurrentUserExpression(PyLegendNullaryExpression, PyLegendExpressionStringReturn):
1153
1183
 
1154
1184
  @staticmethod
@@ -24,6 +24,11 @@ from pylegend.core.language.shared.operations.boolean_operation_expressions impo
24
24
  PyLegendBooleanOrExpression,
25
25
  PyLegendBooleanAndExpression,
26
26
  PyLegendBooleanNotExpression,
27
+ PyLegendBooleanLessThanExpression,
28
+ PyLegendBooleanLessThanEqualExpression,
29
+ PyLegendBooleanGreaterThanExpression,
30
+ PyLegendBooleanGreaterThanEqualExpression,
31
+ PyLegendBooleanXorExpression,
27
32
  )
28
33
  from pylegend.core.sql.metamodel import (
29
34
  Expression,
@@ -83,6 +88,41 @@ class PyLegendBoolean(PyLegendPrimitive):
83
88
  def __invert__(self) -> "PyLegendBoolean":
84
89
  return PyLegendBoolean(PyLegendBooleanNotExpression(self.__value))
85
90
 
91
+ def __lt__(self, other: PyLegendUnion[bool, "PyLegendBoolean"]) -> "PyLegendBoolean":
92
+ return self._create_binary_expression(other, PyLegendBooleanLessThanExpression, "less than (<)")
93
+
94
+ def __le__(self, other: PyLegendUnion[bool, "PyLegendBoolean"]) -> "PyLegendBoolean":
95
+ return self._create_binary_expression(other, PyLegendBooleanLessThanEqualExpression, "less than equal (<=)")
96
+
97
+ def __gt__(self, other: PyLegendUnion[bool, "PyLegendBoolean"]) -> "PyLegendBoolean":
98
+ return self._create_binary_expression(other, PyLegendBooleanGreaterThanExpression, "greater than (>)")
99
+
100
+ def __ge__(self, other: PyLegendUnion[bool, "PyLegendBoolean"]) -> "PyLegendBoolean":
101
+ return self._create_binary_expression(
102
+ other,
103
+ PyLegendBooleanGreaterThanEqualExpression,
104
+ "greater than equal (>=)")
105
+
106
+ def __xor__(self, other: PyLegendUnion[bool, "PyLegendBoolean"]) -> "PyLegendBoolean":
107
+ return self._create_binary_expression(other, PyLegendBooleanXorExpression, "xor (^)")
108
+
109
+ def __rxor__(self, other: PyLegendUnion[bool, "PyLegendBoolean"]) -> "PyLegendBoolean":
110
+ return self._create_binary_expression(other, PyLegendBooleanXorExpression, "xor (^)", reverse=True)
111
+
112
+ def _create_binary_expression(
113
+ self,
114
+ other: PyLegendUnion[bool, "PyLegendBoolean"],
115
+ expression_class: type,
116
+ operation_name: str,
117
+ reverse: bool = False
118
+ ) -> "PyLegendBoolean":
119
+ PyLegendBoolean.__validate__param_to_be_bool(other, f"Boolean {operation_name} parameter")
120
+ other_op = PyLegendBooleanLiteralExpression(other) if isinstance(other, bool) else other.__value
121
+
122
+ if reverse:
123
+ return PyLegendBoolean(expression_class(other_op, self.__value))
124
+ return PyLegendBoolean(expression_class(self.__value, other_op))
125
+
86
126
  @staticmethod
87
127
  def __validate__param_to_be_bool(param: PyLegendUnion[bool, "PyLegendBoolean"], desc: str) -> None:
88
128
  if not isinstance(param, (bool, PyLegendBoolean)):
@@ -28,6 +28,8 @@ from pylegend.core.language.shared.expression import (
28
28
  from pylegend.core.language.shared.literal_expressions import (
29
29
  PyLegendDateTimeLiteralExpression,
30
30
  PyLegendStrictDateLiteralExpression,
31
+ PyLegendIntegerLiteralExpression,
32
+ PyLegendStringLiteralExpression,
31
33
  )
32
34
  from pylegend.core.language.shared.operations.date_operation_expressions import (
33
35
  PyLegendFirstDayOfYearExpression,
@@ -54,6 +56,8 @@ from pylegend.core.language.shared.operations.date_operation_expressions import
54
56
  PyLegendDateLessThanEqualExpression,
55
57
  PyLegendDateGreaterThanExpression,
56
58
  PyLegendDateGreaterThanEqualExpression,
59
+ PyLegendDateAdjustExpression,
60
+ PyLegendDateDiffExpression,
57
61
  )
58
62
  from pylegend.core.sql.metamodel import (
59
63
  Expression,
@@ -158,6 +162,23 @@ class PyLegendDate(PyLegendPrimitive):
158
162
  from pylegend.core.language.shared.primitives.strictdate import PyLegendStrictDate
159
163
  return PyLegendStrictDate(PyLegendDatePartExpression(self.__value))
160
164
 
165
+ def timedelta(self, number: PyLegendUnion[int, "PyLegendInteger"], duration_unit: str) -> "PyLegendDate":
166
+ self.validate_param_to_be_int_or_int_expr(number, "timedelta number parameter")
167
+ number_op = PyLegendIntegerLiteralExpression(number) if isinstance(number, int) else number.value()
168
+ self.validate_duration_unit_param(duration_unit)
169
+ duration_unit_op = PyLegendStringLiteralExpression(duration_unit.upper())
170
+ return PyLegendDate(PyLegendDateAdjustExpression([self.__value, number_op, duration_unit_op]))
171
+
172
+ def diff(
173
+ self,
174
+ other: PyLegendUnion[date, datetime, "PyLegendStrictDate", "PyLegendDateTime", "PyLegendDate"],
175
+ duration_unit: str) -> "PyLegendInteger":
176
+ self.validate_param_to_be_date(other, "Diff parameter")
177
+ other_op = PyLegendDate.__convert_to_date_expr(other)
178
+ self.validate_duration_unit_param(duration_unit)
179
+ duration_unit_op = PyLegendStringLiteralExpression(duration_unit.upper())
180
+ return PyLegendInteger(PyLegendDateDiffExpression([self.__value, other_op, duration_unit_op]))
181
+
161
182
  def __lt__(
162
183
  self,
163
184
  other: PyLegendUnion[date, datetime, "PyLegendStrictDate", "PyLegendDateTime", "PyLegendDate"]
@@ -211,3 +232,21 @@ class PyLegendDate(PyLegendPrimitive):
211
232
  raise TypeError(desc + " should be a datetime.date/datetime.datetime or a Date expression"
212
233
  " (PyLegendDateTime/PyLegendStrictDate/PyLegendDate)."
213
234
  " Got value " + str(param) + " of type: " + str(type(param)))
235
+
236
+ @staticmethod
237
+ def validate_duration_unit_param(duration_unit: str) -> None:
238
+ if duration_unit.lower() not in ('years', 'months', 'weeks', 'days', 'hours', 'minutes', 'seconds',
239
+ 'milliseconds', 'microseconds', 'nanoseconds'):
240
+ raise ValueError(
241
+ f"Unknown duration unit - {duration_unit}. Supported values are - YEARS, MONTHS, WEEKS, DAYS, HOURS,"
242
+ " MINUTES, SECONDS, MILLISECONDS, MICROSECONDS, NANOSECONDS"
243
+ )
244
+
245
+ @staticmethod
246
+ def validate_param_to_be_int_or_int_expr(
247
+ param: PyLegendUnion[int, "PyLegendInteger"],
248
+ desc: str
249
+ ) -> None:
250
+ if not isinstance(param, (int, PyLegendInteger)):
251
+ raise TypeError(desc + " should be a int or an integer expression (PyLegendInteger)."
252
+ " Got value " + str(param) + " of type: " + str(type(param)))
@@ -18,12 +18,16 @@ from pylegend._typing import (
18
18
  PyLegendDict,
19
19
  PyLegendUnion,
20
20
  )
21
+ from pylegend.core.language.shared.operations.date_operation_expressions import PyLegendDateTimeBucketExpression
22
+ from pylegend.core.language.shared.primitives.integer import PyLegendInteger
21
23
  from pylegend.core.language.shared.primitives.date import PyLegendDate
22
24
  from pylegend.core.language.shared.expression import (
23
25
  PyLegendExpressionDateTimeReturn,
24
26
  )
25
27
  from pylegend.core.language.shared.literal_expressions import (
26
28
  PyLegendDateTimeLiteralExpression,
29
+ PyLegendIntegerLiteralExpression,
30
+ PyLegendStringLiteralExpression,
27
31
  )
28
32
  from pylegend.core.sql.metamodel import (
29
33
  Expression,
@@ -57,6 +61,20 @@ class PyLegendDateTime(PyLegendDate):
57
61
  def value(self) -> PyLegendExpressionDateTimeReturn:
58
62
  return self.__value
59
63
 
64
+ def time_bucket(
65
+ self,
66
+ quantity: PyLegendUnion[int, "PyLegendInteger"],
67
+ duration_unit: str) -> "PyLegendDate":
68
+ self.validate_param_to_be_int_or_int_expr(quantity, "time bucket quantity parameter")
69
+ quantity_op = PyLegendIntegerLiteralExpression(quantity) if isinstance(quantity, int) else quantity.value()
70
+ self.validate_duration_unit_param(duration_unit)
71
+ duration_unit_op = PyLegendStringLiteralExpression(duration_unit.upper())
72
+ return PyLegendDate(PyLegendDateTimeBucketExpression([
73
+ self.__value,
74
+ quantity_op,
75
+ duration_unit_op,
76
+ PyLegendStringLiteralExpression("DATETIME")]))
77
+
60
78
  @staticmethod
61
79
  def __convert_to_datetime_expr(
62
80
  val: PyLegendUnion[datetime, "PyLegendDateTime"]
@@ -33,7 +33,13 @@ from pylegend.core.language.shared.operations.integer_operation_expressions impo
33
33
  PyLegendIntegerSubtractExpression,
34
34
  PyLegendIntegerMultiplyExpression,
35
35
  PyLegendIntegerModuloExpression,
36
- PyLegendIntegerCharExpression
36
+ PyLegendIntegerCharExpression,
37
+ PyLegendIntegerBitAndExpression,
38
+ PyLegendIntegerBitOrExpression,
39
+ PyLegendIntegerBitXorExpression,
40
+ PyLegendIntegerBitShiftLeftExpression,
41
+ PyLegendIntegerBitShiftRightExpression,
42
+ PyLegendIntegerBitNotExpression
37
43
  )
38
44
  if TYPE_CHECKING:
39
45
  from pylegend.core.language.shared.primitives import PyLegendFloat
@@ -159,6 +165,53 @@ class PyLegendInteger(PyLegendNumber):
159
165
  def __pos__(self) -> "PyLegendInteger":
160
166
  return self
161
167
 
168
+ def __invert__(self) -> "PyLegendInteger":
169
+ return PyLegendInteger(PyLegendIntegerBitNotExpression(self.__value_copy))
170
+
171
+ def __and__(self, other: PyLegendUnion[int, "PyLegendInteger"]) -> "PyLegendInteger":
172
+ return self._create_binary_expression(other, PyLegendIntegerBitAndExpression, "and (&)")
173
+
174
+ def __rand__(self, other: PyLegendUnion[int, "PyLegendInteger"]) -> "PyLegendInteger":
175
+ return self._create_binary_expression(other, PyLegendIntegerBitAndExpression, "and (&)", reverse=True)
176
+
177
+ def __or__(self, other: PyLegendUnion[int, "PyLegendInteger"]) -> "PyLegendInteger":
178
+ return self._create_binary_expression(other, PyLegendIntegerBitOrExpression, "or (|)")
179
+
180
+ def __ror__(self, other: PyLegendUnion[int, "PyLegendInteger"]) -> "PyLegendInteger":
181
+ return self._create_binary_expression(other, PyLegendIntegerBitOrExpression, "or (|)", reverse=True)
182
+
183
+ def __xor__(self, other: PyLegendUnion[int, "PyLegendInteger"]) -> "PyLegendInteger":
184
+ return self._create_binary_expression(other, PyLegendIntegerBitXorExpression, "xor (^)")
185
+
186
+ def __rxor__(self, other: PyLegendUnion[int, "PyLegendInteger"]) -> "PyLegendInteger":
187
+ return self._create_binary_expression(other, PyLegendIntegerBitXorExpression, "xor (^)", reverse=True)
188
+
189
+ def __lshift__(self, other: PyLegendUnion[int, "PyLegendInteger"]) -> "PyLegendInteger":
190
+ return self._create_binary_expression(other, PyLegendIntegerBitShiftLeftExpression, "left shift (<<)")
191
+
192
+ def __rlshift__(self, other: PyLegendUnion[int, "PyLegendInteger"]) -> "PyLegendInteger":
193
+ return self._create_binary_expression(other, PyLegendIntegerBitShiftLeftExpression, "left shift (<<)", reverse=True)
194
+
195
+ def __rshift__(self, other: PyLegendUnion[int, "PyLegendInteger"]) -> "PyLegendInteger":
196
+ return self._create_binary_expression(other, PyLegendIntegerBitShiftRightExpression, "right shift (>>)")
197
+
198
+ def __rrshift__(self, other: PyLegendUnion[int, "PyLegendInteger"]) -> "PyLegendInteger":
199
+ return self._create_binary_expression(other, PyLegendIntegerBitShiftRightExpression, "right shift (>>)", reverse=True)
200
+
201
+ def _create_binary_expression(
202
+ self,
203
+ other: PyLegendUnion[int, "PyLegendInteger"],
204
+ expression_class: type,
205
+ operation_name: str,
206
+ reverse: bool = False
207
+ ) -> "PyLegendInteger":
208
+ PyLegendInteger.__validate__param_to_be_integer(other, f"Integer {operation_name} parameter")
209
+ other_op = PyLegendInteger.__convert_to_integer_expr(other)
210
+
211
+ if reverse:
212
+ return PyLegendInteger(expression_class(other_op, self.__value_copy))
213
+ return PyLegendInteger(expression_class(self.__value_copy, other_op))
214
+
162
215
  @staticmethod
163
216
  def __convert_to_integer_expr(
164
217
  val: PyLegendUnion[int, "PyLegendInteger"]
@@ -24,13 +24,16 @@ from pylegend.core.language.shared.expression import (
24
24
  )
25
25
  from pylegend.core.language.shared.literal_expressions import (
26
26
  PyLegendStrictDateLiteralExpression,
27
+ PyLegendIntegerLiteralExpression,
28
+ PyLegendStringLiteralExpression
27
29
  )
28
30
  from pylegend.core.sql.metamodel import (
29
31
  Expression,
30
32
  QuerySpecification
31
33
  )
32
34
  from pylegend.core.tds.tds_frame import FrameToSqlConfig
33
-
35
+ from pylegend.core.language.shared.operations.date_operation_expressions import PyLegendDateTimeBucketExpression
36
+ from pylegend.core.language.shared.primitives.integer import PyLegendInteger
34
37
 
35
38
  __all__: PyLegendSequence[str] = [
36
39
  "PyLegendStrictDate"
@@ -57,6 +60,20 @@ class PyLegendStrictDate(PyLegendDate):
57
60
  def value(self) -> PyLegendExpressionStrictDateReturn:
58
61
  return self.__value
59
62
 
63
+ def time_bucket(
64
+ self,
65
+ quantity: PyLegendUnion[int, "PyLegendInteger"],
66
+ duration_unit: str) -> "PyLegendDate":
67
+ self.validate_param_to_be_int_or_int_expr(quantity, "time bucket quantity parameter")
68
+ quantity_op = PyLegendIntegerLiteralExpression(quantity) if isinstance(quantity, int) else quantity.value()
69
+ self.validate_duration_unit_param(duration_unit)
70
+ duration_unit_op = PyLegendStringLiteralExpression(duration_unit.upper())
71
+ return PyLegendDate(PyLegendDateTimeBucketExpression([
72
+ self.__value,
73
+ quantity_op,
74
+ duration_unit_op,
75
+ PyLegendStringLiteralExpression("STRICTDATE")]))
76
+
60
77
  @staticmethod
61
78
  def __convert_to_strictdate_expr(
62
79
  val: PyLegendUnion[date, "PyLegendStrictDate"]
@@ -73,3 +90,10 @@ class PyLegendStrictDate(PyLegendDate):
73
90
  if not isinstance(param, (date, PyLegendStrictDate)):
74
91
  raise TypeError(desc + " should be a datetime.date or a StrictDate expression (PyLegendStrictDate)."
75
92
  " Got value " + str(param) + " of type: " + str(type(param)))
93
+
94
+ @staticmethod
95
+ def validate_duration_unit_param(duration_unit: str) -> None:
96
+ if duration_unit.lower() not in ('years', 'months', 'weeks', 'days'):
97
+ raise ValueError(
98
+ f"Unknown duration unit - {duration_unit}. Supported values are - YEARS, MONTHS, WEEKS, DAYS"
99
+ )
@@ -18,7 +18,10 @@ from pylegend._typing import (
18
18
  PyLegendUnion,
19
19
  PyLegendOptional
20
20
  )
21
- from pylegend.core.language.shared.literal_expressions import PyLegendIntegerLiteralExpression
21
+ from pylegend.core.language.shared.literal_expressions import (
22
+ PyLegendIntegerLiteralExpression,
23
+ convert_literal_to_literal_expression
24
+ )
22
25
  from pylegend.core.language.shared.primitives.primitive import PyLegendPrimitive
23
26
  from pylegend.core.language.shared.primitives.integer import PyLegendInteger
24
27
  from pylegend.core.language.shared.primitives.float import PyLegendFloat
@@ -67,7 +70,8 @@ from pylegend.core.language.shared.operations.string_operation_expressions impor
67
70
  PyLegendStringSplitPartExpression,
68
71
  PyLegendStringFullMatchExpression,
69
72
  PyLegendStringRepeatStringExpression,
70
- PyLegendStringMatchExpression
73
+ PyLegendStringMatchExpression,
74
+ PyLegendStringCoalesceExpression
71
75
  )
72
76
 
73
77
  __all__: PyLegendSequence[str] = [
@@ -242,6 +246,16 @@ class PyLegendString(PyLegendPrimitive):
242
246
  times_op = PyLegendIntegerLiteralExpression(times) if isinstance(times, int) else times.value()
243
247
  return PyLegendString(PyLegendStringRepeatStringExpression(self.__value, times_op))
244
248
 
249
+ def coalesce(self, *other: PyLegendOptional[PyLegendUnion[str, "PyLegendString"]]) -> "PyLegendString":
250
+ other_op = []
251
+ for op in other:
252
+ if op is not None:
253
+ PyLegendString.__validate_param_to_be_str_or_str_expr(op, "coalesce parameter")
254
+ other_op.append(
255
+ convert_literal_to_literal_expression(op) if not isinstance(op, PyLegendString) else op.__value)
256
+
257
+ return PyLegendString(PyLegendStringCoalesceExpression([self.__value, *other_op]))
258
+
245
259
  def __add__(self, other: PyLegendUnion[str, "PyLegendString"]) -> "PyLegendString":
246
260
  PyLegendString.__validate_param_to_be_str_or_str_expr(other, "String plus (+) parameter")
247
261
  other_op = PyLegendStringLiteralExpression(other) if isinstance(other, str) else other.__value
@@ -87,7 +87,11 @@ __all__: PyLegendSequence[str] = [
87
87
  'InPredicate',
88
88
  'Window',
89
89
  'WindowFrame',
90
- 'FrameBound'
90
+ 'FrameBound',
91
+ 'BitwiseShiftDirection',
92
+ 'BitwiseBinaryOperator',
93
+ 'BitwiseBinaryExpression',
94
+ 'BitwiseShiftExpression',
91
95
  ]
92
96
 
93
97
 
@@ -179,6 +183,17 @@ class ExtractField(Enum):
179
183
  EPOCH = 17
180
184
 
181
185
 
186
+ class BitwiseShiftDirection(Enum):
187
+ LEFT = 1
188
+ RIGHT = 2
189
+
190
+
191
+ class BitwiseBinaryOperator(Enum):
192
+ AND = 1
193
+ OR = 2
194
+ XOR = 3
195
+
196
+
182
197
  class Node:
183
198
  _type: str
184
199
 
@@ -930,3 +945,37 @@ class FrameBound(Node):
930
945
  self.type_ = type_
931
946
  self.value = value
932
947
  self.duration_unit = duration_unit
948
+
949
+
950
+ class BitwiseBinaryExpression(Expression):
951
+ left: "Expression"
952
+ right: "Expression"
953
+ operator: "BitwiseBinaryOperator"
954
+
955
+ def __init__(
956
+ self,
957
+ left: "Expression",
958
+ right: "Expression",
959
+ operator: "BitwiseBinaryOperator"
960
+ ) -> None:
961
+ super().__init__(_type="bitwiseBinaryExpression")
962
+ self.left = left
963
+ self.right = right
964
+ self.operator = operator
965
+
966
+
967
+ class BitwiseShiftExpression(Expression):
968
+ value: "Expression"
969
+ shift: "Expression"
970
+ direction: "BitwiseShiftDirection"
971
+
972
+ def __init__(
973
+ self,
974
+ value: "Expression",
975
+ shift: "Expression",
976
+ direction: "BitwiseShiftDirection"
977
+ ) -> None:
978
+ super().__init__(_type="bitwiseShiftExpression")
979
+ self.value = value
980
+ self.shift = shift
981
+ self.direction = direction