Skip to content
This repository was archived by the owner on Mar 6, 2026. It is now read-only.

Commit adcaa03

Browse files
committed
Refactor SQL models to use shared state
Modifying a sub-type should be automatically reflected on the parent type referencing that subtype.
1 parent 1b29ac2 commit adcaa03

File tree

1 file changed

+49
-35
lines changed

1 file changed

+49
-35
lines changed

google/cloud/bigquery/standard_sql.py

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

1515
import copy
16-
from typing import Any, Dict, Generator, Iterable, List, Optional
16+
from typing import Any, Dict, Iterable, List, Optional
1717

1818
from google.cloud.bigquery.enums import StandardSqlTypeNames
1919

@@ -89,11 +89,13 @@ def array_element_type(self) -> Optional["StandardSqlDataType"]:
8989
"""The type of the array's elements, if type_kind is ARRAY."""
9090
element_type = self._properties.get("arrayElementType")
9191

92-
if element_type is not None:
93-
return StandardSqlDataType.from_api_repr(element_type)
94-
else:
92+
if element_type is None:
9593
return None
9694

95+
result = StandardSqlDataType()
96+
result._properties = element_type # We do not use a copy on purpose.
97+
return result
98+
9799
@array_element_type.setter
98100
def array_element_type(self, value: Optional["StandardSqlDataType"]):
99101
element_type = None if value is None else value.to_api_repr()
@@ -108,11 +110,13 @@ def struct_type(self) -> Optional["StandardSqlStructType"]:
108110
"""The fields of this struct, in order, if type_kind is STRUCT."""
109111
struct_info = self._properties.get("structType")
110112

111-
if struct_info is not None:
112-
return StandardSqlStructType.from_api_repr(struct_info)
113-
else:
113+
if struct_info is None:
114114
return None
115115

116+
result = StandardSqlStructType()
117+
result._properties = struct_info # We do not use a copy on purpose.
118+
return result
119+
116120
@struct_type.setter
117121
def struct_type(self, value: Optional["StandardSqlStructType"]):
118122
struct_type = None if value is None else value.to_api_repr()
@@ -190,7 +194,7 @@ def __init__(
190194
self._properties = {"name": name, "type": type}
191195

192196
@property
193-
def name(self):
197+
def name(self) -> Optional[str]:
194198
"""The name of this field. Can be absent for struct fields."""
195199
return self._properties["name"]
196200

@@ -199,15 +203,19 @@ def name(self, value: Optional[str]):
199203
self._properties["name"] = value
200204

201205
@property
202-
def type(self):
206+
def type(self) -> Optional[StandardSqlDataType]:
203207
"""The type of this parameter. Absent if not explicitly specified.
204208
205209
For example, CREATE FUNCTION statement can omit the return type; in this
206210
case the output parameter does not have this "type" field).
207211
"""
208-
result = self._properties["type"]
209-
if result is not None:
210-
result = StandardSqlDataType.from_api_repr(result)
212+
type_info = self._properties["type"]
213+
214+
if type_info is None:
215+
return None
216+
217+
result = StandardSqlDataType()
218+
result._properties = type_info # We do not use a copy on purpose.
211219
return result
212220

213221
@type.setter
@@ -256,8 +264,14 @@ def __init__(self, fields: Optional[Iterable[StandardSqlField]] = None):
256264
@property
257265
def fields(self) -> List[StandardSqlField]:
258266
"""The fields in this struct."""
259-
result = self._fields_from_resource(self._properties)
260-
return list(result)
267+
result = []
268+
269+
for field_resource in self._properties.get("fields", []):
270+
field = StandardSqlField()
271+
field._properties = field_resource # We do not use a copy on purpose.
272+
result.append(field)
273+
274+
return result
261275

262276
@fields.setter
263277
def fields(self, value: Iterable[StandardSqlField]):
@@ -270,17 +284,12 @@ def to_api_repr(self) -> Dict[str, Any]:
270284
@classmethod
271285
def from_api_repr(cls, resource: Dict[str, Any]) -> "StandardSqlStructType":
272286
"""Construct an SQL struct type instance given its API representation."""
273-
fields = cls._fields_from_resource(resource)
287+
fields = (
288+
StandardSqlField.from_api_repr(field_resource)
289+
for field_resource in resource.get("fields", [])
290+
)
274291
return cls(fields=fields)
275292

276-
@staticmethod
277-
def _fields_from_resource(
278-
resource: Dict[str, Any]
279-
) -> Generator[StandardSqlField, None, None]:
280-
"""Yield field instancess based on the resource info."""
281-
for field_resource in resource.get("fields", []):
282-
yield StandardSqlField.from_api_repr(field_resource)
283-
284293
def __eq__(self, other):
285294
if not isinstance(other, StandardSqlStructType):
286295
return NotImplemented
@@ -306,7 +315,14 @@ def __init__(self, columns: Iterable[StandardSqlField]):
306315
@property
307316
def columns(self) -> List[StandardSqlField]:
308317
"""The columns in this table type."""
309-
return list(self._columns_from_resource(self._properties))
318+
result = []
319+
320+
for column_resource in self._properties.get("columns", []):
321+
column = StandardSqlField()
322+
column._properties = column_resource # We do not use a copy on purpose.
323+
result.append(column)
324+
325+
return result
310326

311327
@columns.setter
312328
def columns(self, value: Iterable[StandardSqlField]):
@@ -319,22 +335,20 @@ def to_api_repr(self) -> Dict[str, Any]:
319335
@classmethod
320336
def from_api_repr(cls, resource: Dict[str, Any]) -> "StandardSqlTableType":
321337
"""Construct an SQL table type instance given its API representation."""
322-
columns = cls._columns_from_resource(resource)
323-
return cls(columns=columns)
338+
columns = []
324339

325-
@staticmethod
326-
def _columns_from_resource(
327-
resource: Dict[str, Any]
328-
) -> Generator[StandardSqlField, None, None]:
329-
"""Yield column instances based on the resource info."""
330-
for column in resource.get("columns", []):
331-
type_ = column.get("type")
340+
for column_resource in resource.get("columns", []):
341+
type_ = column_resource.get("type")
332342
if type_ is None:
333343
type_ = {}
334344

335-
yield StandardSqlField(
336-
name=column.get("name"), type=StandardSqlDataType.from_api_repr(type_),
345+
column = StandardSqlField(
346+
name=column_resource.get("name"),
347+
type=StandardSqlDataType.from_api_repr(type_),
337348
)
349+
columns.append(column)
350+
351+
return cls(columns=columns)
338352

339353
def __eq__(self, other):
340354
if not isinstance(other, StandardSqlTableType):

0 commit comments

Comments
 (0)