16
16
17
17
import dataclasses
18
18
import typing
19
- from typing import TYPE_CHECKING
19
+
20
+ import google .cloud .bigquery as bigquery
20
21
21
22
import bigframes .core .compile .googlesql .abc as abc
22
23
import bigframes .core .compile .googlesql .expression as expr
23
24
24
- if TYPE_CHECKING :
25
- import google .cloud .bigquery as bigquery
26
-
27
25
"""This module provides a structured representation of GoogleSQL syntax using nodes.
28
26
Each node's name and child nodes are designed to strictly follow the official GoogleSQL
29
27
syntax rules outlined in the documentation:
30
28
https://cloud.google.com/bigquery/docs/reference/standard-sql/query-syntax"""
31
29
30
+ TABLE_SOURCE_TYPE = typing .Union [str , bigquery .TableReference ]
31
+
32
32
33
33
@dataclasses .dataclass
34
34
class QueryExpr (abc .SQLSyntax ):
@@ -53,11 +53,47 @@ def sql(self) -> str:
53
53
class Select (abc .SQLSyntax ):
54
54
"""This class represents GoogleSQL `select` syntax."""
55
55
56
- select_list : typing .Sequence [typing .Union [SelectExpression , SelectAll ]]
57
- from_clause_list : typing .Sequence [FromClause ] = ()
56
+ select_list : typing .Sequence [
57
+ typing .Union [SelectExpression , SelectAll ]
58
+ ] = dataclasses .field (default_factory = list )
59
+ from_clause_list : typing .Sequence [FromClause ] = dataclasses .field (
60
+ default_factory = list
61
+ )
58
62
distinct : bool = False
59
63
64
+ def select (
65
+ self ,
66
+ columns : typing .Union [typing .Iterable [str ], str , None ] = None ,
67
+ distinct : bool = False ,
68
+ ) -> Select :
69
+ if isinstance (columns , str ):
70
+ columns = [columns ]
71
+ self .select_list : typing .List [typing .Union [SelectExpression , SelectAll ]] = (
72
+ [
73
+ SelectExpression (expression = expr .ColumnExpression (name = column ))
74
+ for column in columns
75
+ ]
76
+ if columns
77
+ else [SelectAll (expression = expr .StarExpression ())]
78
+ )
79
+ self .distinct = distinct
80
+ return self
81
+
82
+ def from_ (
83
+ self ,
84
+ sources : typing .Union [TABLE_SOURCE_TYPE , typing .Iterable [TABLE_SOURCE_TYPE ]],
85
+ ) -> Select :
86
+ if (not isinstance (sources , typing .Iterable )) or isinstance (sources , str ):
87
+ sources = [sources ]
88
+ self .from_clause_list = [
89
+ FromClause (FromItem .from_source (source )) for source in sources
90
+ ]
91
+ return self
92
+
60
93
def sql (self ) -> str :
94
+ if (self .select_list is not None ) and (not self .select_list ):
95
+ raise ValueError ("Select clause has not been properly initialized." )
96
+
61
97
text = ["SELECT" ]
62
98
63
99
if self .distinct :
@@ -66,7 +102,7 @@ def sql(self) -> str:
66
102
select_list_sql = ",\n " .join ([select .sql () for select in self .select_list ])
67
103
text .append (select_list_sql )
68
104
69
- if self .from_clause_list is not None :
105
+ if self .from_clause_list :
70
106
from_clauses_sql = ",\n " .join (
71
107
[clause .sql () for clause in self .from_clause_list ]
72
108
)
@@ -118,19 +154,27 @@ class FromItem(abc.SQLSyntax):
118
154
as_alias : typing .Optional [AsAlias ] = None
119
155
120
156
@classmethod
121
- def from_table_ref (
157
+ def from_source (
122
158
cls ,
123
- table_ref : bigquery .TableReference ,
159
+ subquery_or_tableref : typing . Union [ bigquery .TableReference , str ] ,
124
160
as_alias : typing .Optional [AsAlias ] = None ,
125
161
):
126
- return cls (
127
- expression = expr .TableExpression (
128
- table_id = table_ref .table_id ,
129
- dataset_id = table_ref .dataset_id ,
130
- project_id = table_ref .project ,
131
- ),
132
- as_alias = as_alias ,
133
- )
162
+ if isinstance (subquery_or_tableref , bigquery .TableReference ):
163
+ return cls (
164
+ expression = expr .TableExpression (
165
+ table_id = subquery_or_tableref .table_id ,
166
+ dataset_id = subquery_or_tableref .dataset_id ,
167
+ project_id = subquery_or_tableref .project ,
168
+ ),
169
+ as_alias = as_alias ,
170
+ )
171
+ elif isinstance (subquery_or_tableref , str ):
172
+ return cls (
173
+ expression = subquery_or_tableref ,
174
+ as_alias = as_alias ,
175
+ )
176
+ else :
177
+ raise ValueError ("The source must be bigquery.TableReference or str." )
134
178
135
179
def sql (self ) -> str :
136
180
if isinstance (self .expression , (expr .TableExpression , expr .CTEExpression )):
0 commit comments