Skip to content

Commit 2ebb618

Browse files
authored
refactor: add googlesql cast function (#794)
1 parent 2b38236 commit 2ebb618

File tree

9 files changed

+134
-1
lines changed

9 files changed

+134
-1
lines changed

bigframes/core/compile/googlesql/__init__.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
from __future__ import annotations
1919

20+
from bigframes.core.compile.googlesql.datatype import DataType
2021
from bigframes.core.compile.googlesql.expression import (
2122
_escape_chars,
2223
AliasExpression,
@@ -26,6 +27,7 @@
2627
StarExpression,
2728
TableExpression,
2829
)
30+
from bigframes.core.compile.googlesql.function import Cast
2931
from bigframes.core.compile.googlesql.query import (
3032
AsAlias,
3133
FromClause,
@@ -42,8 +44,10 @@
4244
"identifier",
4345
"AliasExpression",
4446
"AsAlias",
47+
"Cast",
4548
"ColumnExpression",
4649
"CTEExpression",
50+
"DataType",
4751
"FromClause",
4852
"FromItem",
4953
"NonRecursiveCTE",
@@ -52,5 +56,6 @@
5256
"SelectAll",
5357
"SelectExpression",
5458
"StarExpression",
59+
"StringType",
5560
"TableExpression",
5661
]
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Copyright 2024 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
import enum
16+
17+
"""This module represents all GoogleSQL for BigQuery data types:
18+
https://cloud.google.com/bigquery/docs/reference/standard-sql/data-types"""
19+
20+
21+
class DataType(enum.Enum):
22+
STRING = 1
23+
FLOAT64 = 2
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# Copyright 2024 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
import dataclasses
16+
17+
import bigframes.core.compile.googlesql.datatype as datatype
18+
import bigframes.core.compile.googlesql.expression as expr
19+
20+
# Conversion functions:
21+
# https://cloud.google.com/bigquery/docs/reference/standard-sql/conversion_functions
22+
23+
24+
@dataclasses.dataclass
25+
class Cast(expr.Expression):
26+
"""This class represents the `cast` function."""
27+
28+
expression: expr.ColumnExpression
29+
type: datatype.DataType
30+
31+
def sql(self) -> str:
32+
return f"CAST ({self.expression.sql()} AS {self.type.name})"

bigframes/core/sql.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,9 @@ def multi_literal(*values: str):
6161
def cast_as_string(column_name: str) -> str:
6262
"""Return a string representing string casting of a column."""
6363

64-
return f"CAST({googlesql.identifier(column_name)} AS STRING)"
64+
return googlesql.Cast(
65+
googlesql.ColumnExpression(column_name), googlesql.DataType.STRING
66+
).sql()
6567

6668

6769
def to_json_string(column_name: str) -> str:
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Copyright 2024 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# Copyright 2024 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
import pytest
16+
17+
import bigframes.core.compile.googlesql as sql
18+
19+
20+
@pytest.mark.parametrize(
21+
("table_id", "dataset_id", "project_id", "expected"),
22+
[
23+
pytest.param("a", None, None, "`a`"),
24+
pytest.param("a", "b", None, "`b`.`a`"),
25+
pytest.param("a", "b", "c", "`c`.`b`.`a`"),
26+
pytest.param("a", None, "c", None, marks=pytest.mark.xfail(raises=ValueError)),
27+
],
28+
)
29+
def test_table_expression(table_id, dataset_id, project_id, expected):
30+
expr = sql.TableExpression(
31+
table_id=table_id, dataset_id=dataset_id, project_id=project_id
32+
)
33+
assert expr.sql() == expected
34+
35+
36+
def test_escape_chars():
37+
assert sql._escape_chars("\a\b\f\n\r\t\v\\?'\"`") == r"\a\b\f\n\r\t\v\\\?\'\"\`"
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Copyright 2024 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
import bigframes.core.compile.googlesql as sql
16+
17+
18+
def test_cast():
19+
col = sql.ColumnExpression("col")
20+
assert sql.Cast(col, sql.DataType.STRING).sql() == "CAST (`col` AS STRING)"
21+
assert sql.Cast(col, sql.DataType.FLOAT64).sql() == "CAST (`col` AS FLOAT64)"

0 commit comments

Comments
 (0)