diff --git a/google/cloud/bigquery/schema.py b/google/cloud/bigquery/schema.py index 8d62b2b5b..b278b686a 100644 --- a/google/cloud/bigquery/schema.py +++ b/google/cloud/bigquery/schema.py @@ -560,6 +560,63 @@ def to_api_repr(self) -> dict: return answer +class ForeignTypeInfo: + """Metadata about the foreign data type definition such as the system in which the + type is defined. + + Args: + type_system (str): Required. Specifies the system which defines the + foreign data type. + + TypeSystem enum currently includes: + * "TYPE_SYSTEM_UNSPECIFIED" + * "HIVE" + """ + + def __init__(self, type_system: Optional[str] = None): + self._properties: Dict[str, Any] = {} + self.type_system = type_system + + @property + def type_system(self) -> Optional[str]: + """Required. Specifies the system which defines the foreign data + type.""" + + return self._properties.get("typeSystem") + + @type_system.setter + def type_system(self, value: Optional[str]): + value = _helpers._isinstance_or_raise(value, str, none_allowed=True) + self._properties["typeSystem"] = value + + def to_api_repr(self) -> dict: + """Build an API representation of this object. + + Returns: + Dict[str, Any]: + A dictionary in the format used by the BigQuery API. + """ + + return self._properties + + @classmethod + def from_api_repr(cls, api_repr: Dict[str, Any]) -> "ForeignTypeInfo": + """Factory: constructs an instance of the class (cls) + given its API representation. + + Args: + api_repr (Dict[str, Any]): + API representation of the object to be instantiated. + + Returns: + An instance of the class initialized with data from 'api_repr'. + """ + + config = cls() + config._properties = api_repr + return config + + class SerDeInfo: """Serializer and deserializer information. @@ -625,6 +682,7 @@ def parameters(self, value: Optional[dict[str, str]] = None): def to_api_repr(self) -> dict: """Build an API representation of this object. + Returns: Dict[str, Any]: A dictionary in the format used by the BigQuery API. @@ -635,11 +693,13 @@ def to_api_repr(self) -> dict: def from_api_repr(cls, api_repr: dict) -> SerDeInfo: """Factory: constructs an instance of the class (cls) given its API representation. + Args: - resource (Dict[str, Any]): + api_repr (Dict[str, Any]): API representation of the object to be instantiated. + Returns: - An instance of the class initialized with data from 'resource'. + An instance of the class initialized with data from 'api_repr'. """ config = cls("PLACEHOLDER") config._properties = api_repr diff --git a/tests/unit/test_schema.py b/tests/unit/test_schema.py index 7e84dd63f..efbc5d26f 100644 --- a/tests/unit/test_schema.py +++ b/tests/unit/test_schema.py @@ -1128,6 +1128,73 @@ def test_to_api_repr_parameterized(field, api): assert SchemaField(**field).to_api_repr() == api +class TestForeignTypeInfo: + """Tests for ForeignTypeInfo objects.""" + + @staticmethod + def _get_target_class(): + from google.cloud.bigquery.schema import ForeignTypeInfo + + return ForeignTypeInfo + + def _make_one(self, *args, **kw): + return self._get_target_class()(*args, **kw) + + @pytest.mark.parametrize( + "type_system,expected", + [ + (None, None), + ("TYPE_SYSTEM_UNSPECIFIED", "TYPE_SYSTEM_UNSPECIFIED"), + ("HIVE", "HIVE"), + ], + ) + def test_ctor_valid_input(self, type_system, expected): + result = self._make_one(type_system=type_system) + + assert result.type_system == expected + + def test_ctor_invalid_input(self): + with pytest.raises(TypeError) as e: + self._make_one(type_system=123) + + # Looking for the first word from the string "Pass as..." + assert "Pass " in str(e.value) + + @pytest.mark.parametrize( + "type_system,expected", + [ + ("TYPE_SYSTEM_UNSPECIFIED", {"typeSystem": "TYPE_SYSTEM_UNSPECIFIED"}), + ("HIVE", {"typeSystem": "HIVE"}), + (None, {"typeSystem": None}), + ], + ) + def test_to_api_repr(self, type_system, expected): + result = self._make_one(type_system=type_system) + + assert result.to_api_repr() == expected + + def test_from_api_repr(self): + """GIVEN an api representation of a ForeignTypeInfo object (i.e. api_repr) + WHEN converted into a ForeignTypeInfo object using from_api_repr() + THEN it will have the same representation in dict format as a ForeignTypeInfo + object made directly (via _make_one()) and represented in dict format. + """ + api_repr = { + "typeSystem": "TYPE_SYSTEM_UNSPECIFIED", + } + + expected = self._make_one( + type_system="TYPE_SYSTEM_UNSPECIFIED", + ) + + klass = self._get_target_class() + result = klass.from_api_repr(api_repr) + + # We convert both to dict format because these classes do not have a + # __eq__() method to facilitate direct equality comparisons. + assert result.to_api_repr() == expected.to_api_repr() + + class TestSerDeInfo: """Tests for the SerDeInfo class.""" @@ -1190,9 +1257,9 @@ def test_to_api_repr(self): assert serde_info.to_api_repr() == expected_repr def test_from_api_repr(self): - """GIVEN an api representation of a SerDeInfo object (i.e. resource) + """GIVEN an api representation of a SerDeInfo object (i.e. api_repr) WHEN converted into a SerDeInfo object using from_api_repr() - THEN it will have the representation in dict format as a SerDeInfo + THEN it will have the same representation in dict format as a SerDeInfo object made directly (via _make_one()) and represented in dict format. """ api_repr = {