feat: support timestamp_precision in table schema (#2333) · googleapis/python-bigquery@8d5785a
@@ -52,6 +52,9 @@ def test_constructor_defaults(self):
5252self.assertIsNone(field.default_value_expression)
5353self.assertEqual(field.rounding_mode, None)
5454self.assertEqual(field.foreign_type_definition, None)
55+self.assertEqual(
56+field.timestamp_precision, enums.TimestampPrecision.MICROSECOND
57+ )
55585659def test_constructor_explicit(self):
5760FIELD_DEFAULT_VALUE_EXPRESSION = "This is the default value for this field"
@@ -69,6 +72,7 @@ def test_constructor_explicit(self):
6972default_value_expression=FIELD_DEFAULT_VALUE_EXPRESSION,
7073rounding_mode=enums.RoundingMode.ROUNDING_MODE_UNSPECIFIED,
7174foreign_type_definition="INTEGER",
75+timestamp_precision=enums.TimestampPrecision.PICOSECOND,
7276 )
7377self.assertEqual(field.name, "test")
7478self.assertEqual(field.field_type, "STRING")
@@ -87,6 +91,10 @@ def test_constructor_explicit(self):
8791 )
8892self.assertEqual(field.rounding_mode, "ROUNDING_MODE_UNSPECIFIED")
8993self.assertEqual(field.foreign_type_definition, "INTEGER")
94+self.assertEqual(
95+field.timestamp_precision,
96+enums.TimestampPrecision.PICOSECOND,
97+ )
90989199def test_constructor_explicit_none(self):
92100field = self._make_one("test", "STRING", description=None, policy_tags=None)
@@ -189,6 +197,23 @@ def test_to_api_repr_with_subfield(self):
189197 },
190198 )
191199200+def test_to_api_repr_w_timestamp_precision(self):
201+field = self._make_one(
202+"foo",
203+"TIMESTAMP",
204+"NULLABLE",
205+timestamp_precision=enums.TimestampPrecision.PICOSECOND,
206+ )
207+self.assertEqual(
208+field.to_api_repr(),
209+ {
210+"mode": "NULLABLE",
211+"name": "foo",
212+"type": "TIMESTAMP",
213+"timestampPrecision": 12,
214+ },
215+ )
216+192217def test_from_api_repr(self):
193218field = self._get_target_class().from_api_repr(
194219 {
@@ -198,6 +223,7 @@ def test_from_api_repr(self):
198223"name": "foo",
199224"type": "record",
200225"roundingMode": "ROUNDING_MODE_UNSPECIFIED",
226+"timestampPrecision": 12,
201227 }
202228 )
203229self.assertEqual(field.name, "foo")
@@ -210,6 +236,10 @@ def test_from_api_repr(self):
210236self.assertEqual(field.fields[0].mode, "NULLABLE")
211237self.assertEqual(field.range_element_type, None)
212238self.assertEqual(field.rounding_mode, "ROUNDING_MODE_UNSPECIFIED")
239+self.assertEqual(
240+field.timestamp_precision,
241+enums.TimestampPrecision.PICOSECOND,
242+ )
213243214244def test_from_api_repr_policy(self):
215245field = self._get_target_class().from_api_repr(
@@ -264,6 +294,17 @@ def test_from_api_repr_defaults(self):
264294self.assertNotIn("policyTags", field._properties)
265295self.assertNotIn("rangeElementType", field._properties)
266296297+def test_from_api_repr_timestamp_precision_str(self):
298+# The backend would return timestampPrecision field as a string, even
299+# if we send over an integer. This test verifies we manually converted
300+# it into integer to ensure resending could succeed.
301+field = self._get_target_class().from_api_repr(
302+ {
303+"timestampPrecision": "12",
304+ }
305+ )
306+self.assertEqual(field._properties["timestampPrecision"], 12)
307+267308def test_name_property(self):
268309name = "lemon-ness"
269310schema_field = self._make_one(name, "INTEGER")
@@ -323,6 +364,22 @@ def test_foreign_type_definition_property_str(self):
323364schema_field._properties["foreignTypeDefinition"] = FOREIGN_TYPE_DEFINITION
324365self.assertEqual(schema_field.foreign_type_definition, FOREIGN_TYPE_DEFINITION)
325366367+def test_timestamp_precision_unsupported_type(self):
368+with pytest.raises(ValueError) as e:
369+self._make_one("test", "TIMESTAMP", timestamp_precision=12)
370+371+assert "timestamp_precision must be class enums.TimestampPrecision" in str(
372+e.value
373+ )
374+375+def test_timestamp_precision_property(self):
376+TIMESTAMP_PRECISION = enums.TimestampPrecision.PICOSECOND
377+schema_field = self._make_one("test", "TIMESTAMP")
378+schema_field._properties[
379+"timestampPrecision"
380+ ] = enums.TimestampPrecision.PICOSECOND.value
381+self.assertEqual(schema_field.timestamp_precision, TIMESTAMP_PRECISION)
382+326383def test_to_standard_sql_simple_type(self):
327384examples = (
328385# a few legacy types
@@ -637,7 +694,9 @@ def test___hash__not_equals(self):
637694638695def test___repr__(self):
639696field1 = self._make_one("field1", "STRING")
640-expected = "SchemaField('field1', 'STRING', 'NULLABLE', None, None, (), None)"
697+expected = (
698+"SchemaField('field1', 'STRING', 'NULLABLE', None, None, (), None, None)"
699+ )
641700self.assertEqual(repr(field1), expected)
642701643702def test___repr__evaluable_no_policy_tags(self):