Skip to content

Commit a24dfbc

Browse files
committed
adds test for type vs ftd and test for enums
1 parent 6a340ff commit a24dfbc

File tree

3 files changed

+41
-15
lines changed

3 files changed

+41
-15
lines changed

google/cloud/bigquery/enums.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,11 @@ class KeyResultStatementKind:
246246

247247

248248
class StandardSqlTypeNames(str, enum.Enum):
249+
"""Enum of allowed SQL type names in schema.SchemaField.
250+
251+
Datatype used in GoogleSQL.
252+
"""
253+
249254
def _generate_next_value_(name, start, count, last_values):
250255
return name
251256

@@ -287,7 +292,10 @@ class EntityTypes(str, enum.Enum):
287292
# See also: https://cloud.google.com/bigquery/data-types#legacy_sql_data_types
288293
# and https://cloud.google.com/bigquery/docs/reference/standard-sql/data-types
289294
class SqlTypeNames(str, enum.Enum):
290-
"""Enum of allowed SQL type names in schema.SchemaField."""
295+
"""Enum of allowed SQL type names in schema.SchemaField.
296+
297+
Datatype used in Legacy SQL.
298+
"""
291299

292300
STRING = "STRING"
293301
BYTES = "BYTES"
@@ -309,7 +317,7 @@ class SqlTypeNames(str, enum.Enum):
309317
INTERVAL = "INTERVAL" # NOTE: not available in legacy types
310318
RANGE = "RANGE" # NOTE: not available in legacy types
311319
FOREIGN = "FOREIGN" # NOTE: FOREIGN acts as a wrapper for data types
312-
# not natively understood by BigQuery unless translated
320+
# not natively understood by BigQuery unless translated
313321

314322

315323
class WriteDisposition(object):

google/cloud/bigquery/schema.py

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,8 @@
3232
_STRUCT_TYPES = ("RECORD", "STRUCT")
3333

3434
# SQL types reference:
35-
# https://cloud.google.com/bigquery/data-types#legacy_sql_data_types
36-
# https://cloud.google.com/bigquery/docs/reference/standard-sql/data-types
35+
# LEGACY SQL: https://cloud.google.com/bigquery/data-types#legacy_sql_data_types
36+
# GoogleSQL: https://cloud.google.com/bigquery/docs/reference/standard-sql/data-types
3737
LEGACY_TO_STANDARD_TYPES = {
3838
"STRING": StandardSqlTypeNames.STRING,
3939
"BYTES": StandardSqlTypeNames.BYTES,
@@ -52,6 +52,7 @@
5252
"DATE": StandardSqlTypeNames.DATE,
5353
"TIME": StandardSqlTypeNames.TIME,
5454
"DATETIME": StandardSqlTypeNames.DATETIME,
55+
"FOREIGN": StandardSqlTypeNames.FOREIGN,
5556
# no direct conversion from ARRAY, the latter is represented by mode="REPEATED"
5657
}
5758
"""String names of the legacy SQL types to integer codes of Standard SQL standard_sql."""
@@ -170,6 +171,7 @@ class SchemaField(object):
170171
the type is RANGE, this field is required. Possible values for the
171172
field element type of a RANGE include `DATE`, `DATETIME` and
172173
`TIMESTAMP`.
174+
TODO: add docstring here.
173175
"""
174176

175177
def __init__(
@@ -188,10 +190,9 @@ def __init__(
188190
rounding_mode: Union[RoundingMode, str, None] = None,
189191
foreign_type_definition: Optional[str] = None,
190192
):
191-
self._properties: Dict[str, Any] = {
192-
"name": name,
193-
"type": field_type,
194-
}
193+
self._properties: Dict[str, Any] = {}
194+
195+
self._properties["name"] = name
195196
if mode is not None:
196197
self._properties["mode"] = mode.upper()
197198
if description is not _DEFAULT_VALUE:
@@ -218,7 +219,16 @@ def __init__(
218219
self._properties["roundingMode"] = rounding_mode
219220
if isinstance(foreign_type_definition, str):
220221
self._properties["foreignTypeDefinition"] = foreign_type_definition
221-
222+
223+
# The order of operations is important:
224+
# If field_type is FOREIGN, then foreign_type_definition must be set.
225+
if field_type != "FOREIGN":
226+
self._properties["type"] = field_type
227+
else:
228+
if self._properties.get("foreignTypeDefinition") is None:
229+
raise ValueError("If the 'field_type' is 'FOREIGN', then 'foreign_type_definition' is required.")
230+
self._properties["type"] = field_type
231+
222232
self._fields = tuple(fields)
223233

224234
@staticmethod

tests/unit/test_schema.py

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -163,9 +163,9 @@ def test_to_api_repr(self):
163163
description="hello world",
164164
policy_tags=policy,
165165
rounding_mode=ROUNDINGMODE,
166-
foreign_type_definition="INTEGER",
166+
foreign_type_definition=None,
167167
)
168-
168+
print(f"DINOSAUR: {field}\n\n{field.to_api_repr()}")
169169
self.assertEqual(
170170
field.to_api_repr(),
171171
{
@@ -175,7 +175,6 @@ def test_to_api_repr(self):
175175
"description": "hello world",
176176
"policyTags": {"names": ["foo", "bar"]},
177177
"roundingMode": "ROUNDING_MODE_UNSPECIFIED",
178-
"foreignTypeDefinition": "INTEGER",
179178
},
180179
)
181180

@@ -210,7 +209,6 @@ def test_from_api_repr(self):
210209
"name": "foo",
211210
"type": "record",
212211
"roundingMode": "ROUNDING_MODE_UNSPECIFIED",
213-
"foreignTypeDefinition": "INTEGER",
214212
}
215213
)
216214
self.assertEqual(field.name, "foo")
@@ -223,7 +221,6 @@ def test_from_api_repr(self):
223221
self.assertEqual(field.fields[0].mode, "NULLABLE")
224222
self.assertEqual(field.range_element_type, None)
225223
self.assertEqual(field.rounding_mode, "ROUNDING_MODE_UNSPECIFIED")
226-
self.assertEqual(field.foreign_type_definition, "INTEGER")
227224

228225
def test_from_api_repr_policy(self):
229226
field = self._get_target_class().from_api_repr(
@@ -329,7 +326,8 @@ def test_to_standard_sql_simple_type(self):
329326
("GEOGRAPHY", bigquery.StandardSqlTypeNames.GEOGRAPHY),
330327
)
331328
for legacy_type, standard_type in examples:
332-
field = self._make_one("some_field", legacy_type)
329+
330+
field = self._make_one("some_field", legacy_type)
333331
standard_field = field.to_standard_sql()
334332
self.assertEqual(standard_field.name, "some_field")
335333
self.assertEqual(standard_field.type.type_kind, standard_type)
@@ -489,6 +487,16 @@ def test_to_standard_sql_unknown_type(self):
489487
bigquery.StandardSqlTypeNames.TYPE_KIND_UNSPECIFIED,
490488
)
491489

490+
def test_to_standard_sql_foreign_type(self):
491+
examples = (
492+
("FOREIGN", bigquery.StandardSqlTypeNames.FOREIGN, "INTEGER"),
493+
)
494+
for legacy_type, standard_type, foreign_type_definition in examples:
495+
field = self._make_one("some_field", legacy_type, foreign_type_definition=foreign_type_definition)
496+
standard_field = field.to_standard_sql()
497+
self.assertEqual(standard_field.name, "some_field")
498+
self.assertEqual(standard_field.type.type_kind, standard_type)
499+
492500
def test___eq___wrong_type(self):
493501
field = self._make_one("test", "STRING")
494502
other = object()

0 commit comments

Comments
 (0)