Skip to content

Commit d0bba95

Browse files
cleanup some cast stuff
1 parent 2875bca commit d0bba95

3 files changed

Lines changed: 39 additions & 16 deletions

File tree

packages/bigframes/bigframes/core/compile/lowering.py

Lines changed: 39 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
# limitations under the License.
1414

1515
import dataclasses
16-
from typing import cast
16+
from typing import Literal, cast
1717

1818
import numpy as np
1919
import pandas as pd
@@ -36,14 +36,17 @@
3636
@dataclasses.dataclass
3737
class CoerceArgsRule(op_lowering.OpLoweringRule):
3838
op_type: type[ops.BinaryOp]
39+
dialect: Literal["polars", "substrait"]
3940

4041
@property
4142
def op(self) -> type[ops.ScalarOp]:
4243
return self.op_type
4344

4445
def lower(self, expr: expression.OpExpression) -> expression.Expression:
4546
assert isinstance(expr.op, self.op_type)
46-
larg, rarg = _coerce_comparables(expr.children[0], expr.children[1])
47+
larg, rarg = _coerce_comparables(
48+
expr.children[0], expr.children[1], dialect=self.dialect
49+
)
4750
return expr.op.as_expr(larg, rarg)
4851

4952

@@ -285,14 +288,20 @@ def lower(self, expr: expression.OpExpression) -> expression.Expression:
285288
return wo_bools
286289

287290

291+
@dataclasses.dataclass
288292
class LowerAsTypeRule(op_lowering.OpLoweringRule):
293+
dialect: Literal["polars", "substrait"]
294+
289295
@property
290296
def op(self) -> type[ops.ScalarOp]:
291297
return ops.AsTypeOp
292298

293299
def lower(self, expr: expression.OpExpression) -> expression.Expression:
294300
assert isinstance(expr.op, ops.AsTypeOp)
295-
return _lower_cast(expr.op, expr.inputs[0])
301+
if self.dialect == "polars":
302+
return _lower_cast_to_polars(expr.op, expr.inputs[0])
303+
elif self.dialect == "substrait":
304+
return _lower_cast_to_substrait(expr.op, expr.inputs[0])
296305

297306

298307
def invert_bytes(byte_string):
@@ -392,6 +401,7 @@ def _coerce_comparables(
392401
expr2: expression.Expression,
393402
*,
394403
bools_only: bool = False,
404+
dialect: Literal["polars", "substrait"],
395405
):
396406
if bools_only:
397407
if (
@@ -402,13 +412,19 @@ def _coerce_comparables(
402412

403413
target_type = dtypes.coerce_to_common(expr1.output_type, expr2.output_type)
404414
if expr1.output_type != target_type:
405-
expr1 = _lower_cast(ops.AsTypeOp(target_type), expr1)
415+
if dialect == "polars":
416+
expr1 = _lower_cast_to_polars(ops.AsTypeOp(target_type), expr1)
417+
elif dialect == "substrait":
418+
expr1 = _lower_cast_to_substrait(ops.AsTypeOp(target_type), expr1)
406419
if expr2.output_type != target_type:
407-
expr2 = _lower_cast(ops.AsTypeOp(target_type), expr2)
420+
if dialect == "polars":
421+
expr2 = _lower_cast_to_polars(ops.AsTypeOp(target_type), expr2)
422+
elif dialect == "substrait":
423+
expr2 = _lower_cast_to_substrait(ops.AsTypeOp(target_type), expr2)
408424
return expr1, expr2
409425

410426

411-
def _lower_cast(cast_op: ops.AsTypeOp, arg: expression.Expression):
427+
def _lower_cast_to_polars(cast_op: ops.AsTypeOp, arg: expression.Expression):
412428
if arg.output_type == cast_op.to_type:
413429
return arg
414430
if (
@@ -435,8 +451,6 @@ def _lower_cast(cast_op: ops.AsTypeOp, arg: expression.Expression):
435451
):
436452
return datetime_ops.StrftimeOp("%Y-%m-%d %H:%M:%S%.6f%:::z").as_expr(arg)
437453
if arg.output_type == dtypes.BOOL_DTYPE and cast_op.to_type == dtypes.STRING_DTYPE:
438-
# bool -> decimal needs two-step cast
439-
new_arg = ops.AsTypeOp(to_type=dtypes.INT_DTYPE).as_expr(arg)
440454
is_true_cond = ops.eq_op.as_expr(arg, expression.const(True))
441455
is_false_cond = ops.eq_op.as_expr(arg, expression.const(False))
442456
return ops.CaseWhenOp().as_expr(
@@ -459,6 +473,19 @@ def _lower_cast(cast_op: ops.AsTypeOp, arg: expression.Expression):
459473
return cast_op.as_expr(arg)
460474

461475

476+
def _lower_cast_to_substrait(cast_op: ops.AsTypeOp, arg: expression.Expression):
477+
if arg.output_type == dtypes.BOOL_DTYPE and cast_op.to_type == dtypes.STRING_DTYPE:
478+
is_true_cond = ops.eq_op.as_expr(arg, expression.const(True))
479+
is_false_cond = ops.eq_op.as_expr(arg, expression.const(False))
480+
return ops.CaseWhenOp().as_expr(
481+
is_true_cond,
482+
expression.const("True"),
483+
is_false_cond,
484+
expression.const("False"),
485+
)
486+
return cast_op.as_expr(arg)
487+
488+
462489
class LowerEqNullsMatchRule(op_lowering.OpLoweringRule):
463490
@property
464491
def op(self) -> type[ops.ScalarOp]:
@@ -500,7 +527,7 @@ def lower(self, expr: expression.OpExpression) -> expression.Expression:
500527

501528

502529
POLARS_LOWER_COMPARISONS = tuple(
503-
CoerceArgsRule(op)
530+
CoerceArgsRule(op, dialect="polars")
504531
for op in (
505532
comparison_ops.EqOp,
506533
comparison_ops.EqNullsMatchOp,
@@ -513,7 +540,7 @@ def lower(self, expr: expression.OpExpression) -> expression.Expression:
513540
)
514541

515542
SUBSTRAIT_LOWER_COMPARISONS = tuple(
516-
CoerceArgsRule(op)
543+
CoerceArgsRule(op, dialect="substrait")
517544
for op in (
518545
comparison_ops.EqOp,
519546
comparison_ops.NeOp,
@@ -532,7 +559,7 @@ def lower(self, expr: expression.OpExpression) -> expression.Expression:
532559
LowerDivRule(),
533560
LowerFloorDivRule(),
534561
LowerModRule(),
535-
LowerAsTypeRule(),
562+
LowerAsTypeRule(dialect="polars"),
536563
LowerInvertOp(),
537564
LowerIsinOp(),
538565
LowerLenOp(),
@@ -543,6 +570,7 @@ def lower(self, expr: expression.OpExpression) -> expression.Expression:
543570
SUBSTRAIT_LOWERING_RULES = (
544571
LowerEqNullsMatchRule(),
545572
*SUBSTRAIT_LOWER_COMPARISONS,
573+
LowerAsTypeRule(dialect="substrait"),
546574
)
547575

548576

packages/bigframes/tests/system/small/engines/test_generic_ops.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -410,8 +410,6 @@ def test_engines_astype_time(scalars_array_value: array_value.ArrayValue, engine
410410
"polars",
411411
"bq",
412412
"bq-sqlglot",
413-
"substrait-datafusion",
414-
"substrait-acero",
415413
],
416414
indirect=True,
417415
)
@@ -441,8 +439,6 @@ def test_engines_astype_from_json(scalars_array_value: array_value.ArrayValue, e
441439
"polars",
442440
"bq",
443441
"bq-sqlglot",
444-
"substrait-datafusion",
445-
"substrait-acero",
446442
],
447443
indirect=True,
448444
)

packages/bigframes/tests/system/small/engines/test_slicing.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@
3131
"bq",
3232
"bq-sqlglot",
3333
"substrait-datafusion",
34-
"substrait-acero",
3534
],
3635
indirect=True,
3736
)

0 commit comments

Comments
 (0)