Skip to content

Commit bc48efc

Browse files
committed
(WIP) adjust routines logic, fix tests
1 parent 413186a commit bc48efc

File tree

2 files changed

+91
-22
lines changed

2 files changed

+91
-22
lines changed

google/cloud/bigquery/routine/routine.py

Lines changed: 34 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,10 @@
1616

1717
"""Define resources for the BigQuery Routines API."""
1818

19-
from google.protobuf import json_format
20-
2119
import google.cloud._helpers
2220
from google.cloud.bigquery import _helpers
2321
from google.cloud.bigquery.types import StandardSqlDataType
22+
from google.cloud.bigquery.types import StandardSqlField
2423
from google.cloud.bigquery.types import StandardSqlTableType
2524

2625

@@ -206,16 +205,12 @@ def return_type(self):
206205
if not resource:
207206
return resource
208207

209-
output = StandardSqlDataType()
210-
raw_protobuf = json_format.ParseDict(
211-
resource, output._pb, ignore_unknown_fields=True
212-
)
213-
return type(output).wrap(raw_protobuf)
208+
return StandardSqlDataType.from_api_repr(resource)
214209

215210
@return_type.setter
216-
def return_type(self, value):
211+
def return_type(self, value: StandardSqlDataType):
217212
if value:
218-
resource = json_format.MessageToDict(value._pb)
213+
resource = value.to_api_repr()
219214
else:
220215
resource = None
221216
self._properties[self._PROPERTY_TO_API_FIELD["return_type"]] = resource
@@ -232,20 +227,36 @@ def return_table_type(self) -> StandardSqlTableType:
232227
if not resource:
233228
return resource
234229

235-
output = StandardSqlTableType()
236-
raw_protobuf = json_format.ParseDict(
237-
resource, output._pb, ignore_unknown_fields=True
230+
# TODO: this should be StandardSqlTableType.from_api_repr()
231+
columns = (
232+
StandardSqlField(
233+
name=column.get("name"),
234+
type=StandardSqlDataType.from_api_repr(column["type"]),
235+
)
236+
for column in resource.get("columns")
238237
)
239-
return type(output).wrap(raw_protobuf)
238+
# output = StandardSqlTableType()
239+
# raw_protobuf = json_format.ParseDict(
240+
# resource, output._pb, ignore_unknown_fields=True
241+
# )
242+
# return type(output).wrap(raw_protobuf)
243+
return StandardSqlTableType(columns=columns)
240244

241245
@return_table_type.setter
242246
def return_table_type(self, value):
243247
if not value:
244248
resource = None
245249
else:
246-
resource = {
247-
"columns": [json_format.MessageToDict(col._pb) for col in value.columns]
248-
}
250+
columns = [
251+
# TODO: this should really be StandardSqlField.to_api_repr()
252+
# ACTUALLY, all this thould be wrapped in StandardSqlTableType.to_api_repr()
253+
{"name": col.name, "type": col.type.to_api_repr()}
254+
for col in value.columns
255+
]
256+
# resource = {
257+
# "columns": [json_format.MessageToDict(col._pb) for col in value.columns]
258+
# }
259+
resource = {"columns": columns}
249260

250261
self._properties[self._PROPERTY_TO_API_FIELD["return_table_type"]] = resource
251262

@@ -417,16 +428,17 @@ def data_type(self):
417428
if not resource:
418429
return resource
419430

420-
output = StandardSqlDataType()
421-
raw_protobuf = json_format.ParseDict(
422-
resource, output._pb, ignore_unknown_fields=True
423-
)
424-
return type(output).wrap(raw_protobuf)
431+
# output = StandardSqlDataType()
432+
# raw_protobuf = json_format.ParseDict(
433+
# resource, output._pb, ignore_unknown_fields=True
434+
# )
435+
# return type(output).wrap(raw_protobuf)
436+
return StandardSqlDataType.from_api_repr(resource)
425437

426438
@data_type.setter
427439
def data_type(self, value):
428440
if value:
429-
resource = json_format.MessageToDict(value._pb)
441+
resource = value.to_api_repr()
430442
else:
431443
resource = None
432444
self._properties[self._PROPERTY_TO_API_FIELD["data_type"]] = resource

google/cloud/bigquery/types/standard_sql.py

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,63 @@ def __post_init__(self):
7878
"array_element_type and struct_type are mutally exclusive."
7979
)
8080

81+
def to_api_repr(self):
82+
"""TODO: docstirng... and tests
83+
84+
mention link in class docstring? https://cloud.google.com/bigqPuery/docs/reference/rest/v2/StandardSqlDataType
85+
"""
86+
if not self.type_kind:
87+
type_kind = self.TypeKind.TYPE_KIND_UNSPECIFIED.value
88+
else:
89+
type_kind = self.type_kind.value
90+
91+
result = {"typeKind": type_kind}
92+
93+
if self.type_kind == self.TypeKind.ARRAY:
94+
if not self.array_element_type:
95+
array_type = None
96+
else:
97+
array_type = self.array_element_type.to_api_repr()
98+
result["arrayElementType"] = array_type
99+
elif self.type_kind == self.TypeKind.STRUCT:
100+
if not self.struct_type:
101+
struct_type = None
102+
else:
103+
struct_type = self.struct_type.to_api_repr()
104+
result["structType"] = struct_type
105+
106+
return result
107+
108+
@classmethod
109+
def from_api_repr(cls, resource):
110+
"""TODO: type annotations, tests..."""
111+
type_kind = resource.get("typeKind")
112+
if type_kind not in cls.TypeKind.__members__:
113+
type_kind = cls.TypeKind.TYPE_KIND_UNSPECIFIED
114+
else:
115+
type_kind = cls.TypeKind[type_kind] # From string to enum member.
116+
117+
array_element_type = None
118+
if type_kind == cls.type_kind.ARRAY:
119+
array_element_type = cls.from_api_repr(resource["arrayElementType"])
120+
121+
struct_type = None
122+
if type_kind == cls.TypeKind.STRUCT:
123+
# TODO: this logic belongs to StandardSqlStructType.to_api_repr()
124+
struct_info = resource["structType"]
125+
fields = struct_info.get("fields", [])
126+
127+
fields = (
128+
StandardSqlField(
129+
name=field.get("name"),
130+
type=StandardSqlDataType.from_api_repr(field.get["type"]),
131+
)
132+
for field in struct_info.get("fields", [])
133+
)
134+
struct_type = StandardSqlStructType(fields=fields)
135+
136+
return cls(type_kind, array_element_type, struct_type)
137+
81138

82139
@dataclass
83140
class StandardSqlField:

0 commit comments

Comments
 (0)