Skip to content

Commit 39481a5

Browse files
authored
chore: Migrate RemoteFunctionOp operator to SQLGlot (#2377)
Thank you for opening a Pull Request! Before submitting your PR, there are a few things you can do to make sure it goes smoothly: - [ ] Make sure to open an issue as a [bug/issue](https://github.com/googleapis/python-bigquery-dataframes/issues/new/choose) before writing your code! That way we can discuss the change, evaluate designs, and agree on the general idea - [ ] Ensure the tests and linter pass - [ ] Code coverage does not decrease (if any source code was changed) - [ ] Appropriate docs were updated (if necessary) Fixes b/452130300
1 parent e156660 commit 39481a5

File tree

3 files changed

+74
-0
lines changed

3 files changed

+74
-0
lines changed

bigframes/core/compile/sqlglot/expressions/generic_ops.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,25 @@ def _(left: TypedExpr, right: TypedExpr) -> sge.Expression:
152152
return sge.Coalesce(this=left.expr, expressions=[right.expr])
153153

154154

155+
@register_unary_op(ops.RemoteFunctionOp, pass_op=True)
156+
def _(expr: TypedExpr, op: ops.RemoteFunctionOp) -> sge.Expression:
157+
routine_ref = op.function_def.routine_ref
158+
# Quote project, dataset, and routine IDs to avoid keyword clashes.
159+
func_name = (
160+
f"`{routine_ref.project}`.`{routine_ref.dataset_id}`.`{routine_ref.routine_id}`"
161+
)
162+
func = sge.func(func_name, expr.expr)
163+
164+
if not op.apply_on_null:
165+
return sge.If(
166+
this=sge.Is(this=expr.expr, expression=sge.Null()),
167+
true=expr.expr,
168+
false=func,
169+
)
170+
171+
return func
172+
173+
155174
@register_binary_op(ops.BinaryRemoteFunctionOp, pass_op=True)
156175
def _(
157176
left: TypedExpr, right: TypedExpr, op: ops.BinaryRemoteFunctionOp
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
WITH `bfcte_0` AS (
2+
SELECT
3+
`int64_col`
4+
FROM `bigframes-dev`.`sqlglot_test`.`scalar_types`
5+
), `bfcte_1` AS (
6+
SELECT
7+
*,
8+
`my_project`.`my_dataset`.`my_routine`(`int64_col`) AS `bfcol_1`,
9+
IF(
10+
`int64_col` IS NULL,
11+
`int64_col`,
12+
`my_project`.`my_dataset`.`my_routine`(`int64_col`)
13+
) AS `bfcol_2`
14+
FROM `bfcte_0`
15+
)
16+
SELECT
17+
`bfcol_1` AS `apply_on_null_true`,
18+
`bfcol_2` AS `apply_on_null_false`
19+
FROM `bfcte_1`

tests/unit/core/compile/sqlglot/expressions/test_generic_ops.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,42 @@ def test_astype_json_invalid(
169169
)
170170

171171

172+
def test_remote_function_op(scalar_types_df: bpd.DataFrame, snapshot):
173+
from google.cloud import bigquery
174+
175+
from bigframes.functions import udf_def
176+
177+
bf_df = scalar_types_df[["int64_col"]]
178+
function_def = udf_def.BigqueryUdf(
179+
routine_ref=bigquery.RoutineReference.from_string(
180+
"my_project.my_dataset.my_routine"
181+
),
182+
signature=udf_def.UdfSignature(
183+
input_types=(
184+
udf_def.UdfField(
185+
"x",
186+
bigquery.StandardSqlDataType(
187+
type_kind=bigquery.StandardSqlTypeNames.INT64
188+
),
189+
),
190+
),
191+
output_bq_type=bigquery.StandardSqlDataType(
192+
type_kind=bigquery.StandardSqlTypeNames.FLOAT64
193+
),
194+
),
195+
)
196+
ops_map = {
197+
"apply_on_null_true": ops.RemoteFunctionOp(
198+
function_def=function_def, apply_on_null=True
199+
).as_expr("int64_col"),
200+
"apply_on_null_false": ops.RemoteFunctionOp(
201+
function_def=function_def, apply_on_null=False
202+
).as_expr("int64_col"),
203+
}
204+
sql = utils._apply_ops_to_sql(bf_df, list(ops_map.values()), list(ops_map.keys()))
205+
snapshot.assert_match(sql, "out.sql")
206+
207+
172208
def test_binary_remote_function_op(scalar_types_df: bpd.DataFrame, snapshot):
173209
from google.cloud import bigquery
174210

0 commit comments

Comments
 (0)