Skip to content

Commit 55e75af

Browse files
authored
Merge branch 'main' into migrate-manhatton-dist
2 parents 5fbc3fa + 9f497a6 commit 55e75af

File tree

13 files changed

+152
-9
lines changed

13 files changed

+152
-9
lines changed

bigframes/core/compile/sqlglot/compiler.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,7 @@ def compile_readtable(node: nodes.ReadTableNode, child: ir.SQLGlotIR):
172172
col_names=[col.source_id for col in node.scan_list.items],
173173
alias_names=[col.id.sql for col in node.scan_list.items],
174174
uid_gen=child.uid_gen,
175+
system_time=node.source.at_time,
175176
)
176177

177178

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,11 @@ def _(
134134
)
135135

136136

137+
@register_binary_op(ops.fillna_op)
138+
def _(left: TypedExpr, right: TypedExpr) -> sge.Expression:
139+
return sge.Coalesce(this=left.expr, expressions=[right.expr])
140+
141+
137142
@register_nary_op(ops.case_when_op)
138143
def _(*cases_and_outputs: TypedExpr) -> sge.Expression:
139144
# Need to upcast BOOL to INT if any output is numeric

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,18 @@ def _(left: TypedExpr, right: TypedExpr) -> sge.Expression:
305305
return result
306306

307307

308+
@register_binary_op(ops.euclidean_distance_op)
309+
def _(left: TypedExpr, right: TypedExpr) -> sge.Expression:
310+
return sge.Anonymous(
311+
this="ML.DISTANCE",
312+
expressions=[
313+
left.expr,
314+
right.expr,
315+
sge.Literal.string("EUCLIDEAN"),
316+
],
317+
)
318+
319+
308320
@register_binary_op(ops.floordiv_op)
309321
def _(left: TypedExpr, right: TypedExpr) -> sge.Expression:
310322
left_expr = _coerce_bool_to_int(left)

bigframes/core/compile/sqlglot/sqlglot_ir.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
from __future__ import annotations
1616

1717
import dataclasses
18+
import datetime
1819
import functools
1920
import typing
2021

@@ -118,6 +119,7 @@ def from_table(
118119
col_names: typing.Sequence[str],
119120
alias_names: typing.Sequence[str],
120121
uid_gen: guid.SequentialUIDGenerator,
122+
system_time: typing.Optional[datetime.datetime] = None,
121123
) -> SQLGlotIR:
122124
"""Builds a SQLGlotIR expression from a BigQuery table.
123125
@@ -128,6 +130,7 @@ def from_table(
128130
col_names (typing.Sequence[str]): The names of the columns to select.
129131
alias_names (typing.Sequence[str]): The aliases for the selected columns.
130132
uid_gen (guid.SequentialUIDGenerator): A generator for unique identifiers.
133+
system_time (typing.Optional[str]): An optional system time for time-travel queries.
131134
"""
132135
selections = [
133136
sge.Alias(
@@ -138,10 +141,20 @@ def from_table(
138141
else sge.to_identifier(col_name, quoted=cls.quoted)
139142
for col_name, alias_name in zip(col_names, alias_names)
140143
]
144+
version = (
145+
sge.Version(
146+
this="TIMESTAMP",
147+
expression=sge.Literal(this=system_time.isoformat(), is_string=True),
148+
kind="AS OF",
149+
)
150+
if system_time
151+
else None
152+
)
141153
table_expr = sge.Table(
142154
this=sg.to_identifier(table_id, quoted=cls.quoted),
143155
db=sg.to_identifier(dataset_id, quoted=cls.quoted),
144156
catalog=sg.to_identifier(project_id, quoted=cls.quoted),
157+
version=version,
145158
)
146159
select_expr = sge.Select().select(*selections).from_(table_expr)
147160
return cls(expr=select_expr, uid_gen=uid_gen)

tests/system/small/engines/test_generic_ops.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -343,7 +343,7 @@ def test_engines_coalesce_op(scalars_array_value: array_value.ArrayValue, engine
343343
assert_equivalence_execution(arr.node, REFERENCE_ENGINE, engine)
344344

345345

346-
@pytest.mark.parametrize("engine", ["polars", "bq"], indirect=True)
346+
@pytest.mark.parametrize("engine", ["polars", "bq", "bq-sqlglot"], indirect=True)
347347
def test_engines_fillna_op(scalars_array_value: array_value.ArrayValue, engine):
348348
arr, _ = scalars_array_value.compute_values(
349349
[

tests/unit/core/compile/sqlglot/conftest.py

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,10 @@ def scalar_types_table_schema() -> typing.Sequence[bigquery.SchemaField]:
9797
def scalar_types_df(compiler_session) -> bpd.DataFrame:
9898
"""Returns a BigFrames DataFrame containing all scalar types and using the `rowindex`
9999
column as the index."""
100-
bf_df = compiler_session.read_gbq_table("bigframes-dev.sqlglot_test.scalar_types")
100+
bf_df = compiler_session._loader.read_gbq_table(
101+
"bigframes-dev.sqlglot_test.scalar_types",
102+
enable_snapshot=False,
103+
)
101104
bf_df = bf_df.set_index("rowindex", drop=False)
102105
return bf_df
103106

@@ -154,8 +157,9 @@ def nested_structs_types_table_schema() -> typing.Sequence[bigquery.SchemaField]
154157
def nested_structs_types_df(compiler_session_w_nested_structs_types) -> bpd.DataFrame:
155158
"""Returns a BigFrames DataFrame containing all scalar types and using the `rowindex`
156159
column as the index."""
157-
bf_df = compiler_session_w_nested_structs_types.read_gbq_table(
158-
"bigframes-dev.sqlglot_test.nested_structs_types"
160+
bf_df = compiler_session_w_nested_structs_types._loader.read_gbq_table(
161+
"bigframes-dev.sqlglot_test.nested_structs_types",
162+
enable_snapshot=False,
159163
)
160164
bf_df = bf_df.set_index("id", drop=False)
161165
return bf_df
@@ -204,8 +208,9 @@ def repeated_types_table_schema() -> typing.Sequence[bigquery.SchemaField]:
204208
def repeated_types_df(compiler_session_w_repeated_types) -> bpd.DataFrame:
205209
"""Returns a BigFrames DataFrame containing all scalar types and using the `rowindex`
206210
column as the index."""
207-
bf_df = compiler_session_w_repeated_types.read_gbq_table(
208-
"bigframes-dev.sqlglot_test.repeated_types"
211+
bf_df = compiler_session_w_repeated_types._loader.read_gbq_table(
212+
"bigframes-dev.sqlglot_test.repeated_types",
213+
enable_snapshot=False,
209214
)
210215
bf_df = bf_df.set_index("rowindex", drop=False)
211216
return bf_df
@@ -237,8 +242,9 @@ def json_types_table_schema() -> typing.Sequence[bigquery.SchemaField]:
237242
def json_types_df(compiler_session_w_json_types) -> bpd.DataFrame:
238243
"""Returns a BigFrames DataFrame containing JSON types and using the `rowindex`
239244
column as the index."""
240-
bf_df = compiler_session_w_json_types.read_gbq_table(
241-
"bigframes-dev.sqlglot_test.json_types"
245+
bf_df = compiler_session_w_json_types._loader.read_gbq_table(
246+
"bigframes-dev.sqlglot_test.json_types",
247+
enable_snapshot=False,
242248
)
243249
# TODO(b/427305807): Why `drop=False` will produce two "rowindex" columns?
244250
bf_df = bf_df.set_index("rowindex", drop=True)
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
WITH `bfcte_0` AS (
2+
SELECT
3+
`float64_col`,
4+
`int64_col`
5+
FROM `bigframes-dev`.`sqlglot_test`.`scalar_types`
6+
), `bfcte_1` AS (
7+
SELECT
8+
*,
9+
COALESCE(`int64_col`, `float64_col`) AS `bfcol_2`
10+
FROM `bfcte_0`
11+
)
12+
SELECT
13+
`bfcol_2` AS `int64_col`
14+
FROM `bfcte_1`
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
WITH `bfcte_0` AS (
2+
SELECT
3+
`int_list_col`,
4+
`numeric_list_col`
5+
FROM `bigframes-dev`.`sqlglot_test`.`repeated_types`
6+
), `bfcte_1` AS (
7+
SELECT
8+
*,
9+
ML.DISTANCE(`int_list_col`, `int_list_col`, 'EUCLIDEAN') AS `bfcol_2`,
10+
ML.DISTANCE(`numeric_list_col`, `numeric_list_col`, 'EUCLIDEAN') AS `bfcol_3`
11+
FROM `bfcte_0`
12+
)
13+
SELECT
14+
`bfcol_2` AS `int_list_col`,
15+
`bfcol_3` AS `numeric_list_col`
16+
FROM `bfcte_1`

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,12 @@ def test_clip(scalar_types_df: bpd.DataFrame, snapshot):
239239
snapshot.assert_match(sql, "out.sql")
240240

241241

242+
def test_fillna(scalar_types_df: bpd.DataFrame, snapshot):
243+
bf_df = scalar_types_df[["int64_col", "float64_col"]]
244+
sql = utils._apply_binary_op(bf_df, ops.fillna_op, "int64_col", "float64_col")
245+
snapshot.assert_match(sql, "out.sql")
246+
247+
242248
def test_hash(scalar_types_df: bpd.DataFrame, snapshot):
243249
col_name = "string_col"
244250
bf_df = scalar_types_df[[col_name]]

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

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,21 @@ def test_div_timedelta(scalar_types_df: bpd.DataFrame, snapshot):
315315
snapshot.assert_match(bf_df.sql, "out.sql")
316316

317317

318+
def test_euclidean_distance(repeated_types_df: bpd.DataFrame, snapshot):
319+
col_names = ["int_list_col", "numeric_list_col"]
320+
bf_df = repeated_types_df[col_names]
321+
322+
sql = utils._apply_ops_to_sql(
323+
bf_df,
324+
[
325+
ops.euclidean_distance_op.as_expr("int_list_col", "int_list_col"),
326+
ops.euclidean_distance_op.as_expr("numeric_list_col", "numeric_list_col"),
327+
],
328+
["int_list_col", "numeric_list_col"],
329+
)
330+
snapshot.assert_match(sql, "out.sql")
331+
332+
318333
def test_floordiv_numeric(scalar_types_df: bpd.DataFrame, snapshot):
319334
bf_df = scalar_types_df[["int64_col", "bool_col", "float64_col"]]
320335

0 commit comments

Comments
 (0)