feat: support timestamp_precision in table schema (#2333) · googleapis/python-bigquery@8d5785a

@@ -52,6 +52,9 @@ def test_constructor_defaults(self):

5252

self.assertIsNone(field.default_value_expression)

5353

self.assertEqual(field.rounding_mode, None)

5454

self.assertEqual(field.foreign_type_definition, None)

55+

self.assertEqual(

56+

field.timestamp_precision, enums.TimestampPrecision.MICROSECOND

57+

)

55585659

def test_constructor_explicit(self):

5760

FIELD_DEFAULT_VALUE_EXPRESSION = "This is the default value for this field"

@@ -69,6 +72,7 @@ def test_constructor_explicit(self):

6972

default_value_expression=FIELD_DEFAULT_VALUE_EXPRESSION,

7073

rounding_mode=enums.RoundingMode.ROUNDING_MODE_UNSPECIFIED,

7174

foreign_type_definition="INTEGER",

75+

timestamp_precision=enums.TimestampPrecision.PICOSECOND,

7276

)

7377

self.assertEqual(field.name, "test")

7478

self.assertEqual(field.field_type, "STRING")

@@ -87,6 +91,10 @@ def test_constructor_explicit(self):

8791

)

8892

self.assertEqual(field.rounding_mode, "ROUNDING_MODE_UNSPECIFIED")

8993

self.assertEqual(field.foreign_type_definition, "INTEGER")

94+

self.assertEqual(

95+

field.timestamp_precision,

96+

enums.TimestampPrecision.PICOSECOND,

97+

)

90989199

def test_constructor_explicit_none(self):

92100

field = 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+192217

def test_from_api_repr(self):

193218

field = 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

)

203229

self.assertEqual(field.name, "foo")

@@ -210,6 +236,10 @@ def test_from_api_repr(self):

210236

self.assertEqual(field.fields[0].mode, "NULLABLE")

211237

self.assertEqual(field.range_element_type, None)

212238

self.assertEqual(field.rounding_mode, "ROUNDING_MODE_UNSPECIFIED")

239+

self.assertEqual(

240+

field.timestamp_precision,

241+

enums.TimestampPrecision.PICOSECOND,

242+

)

213243214244

def test_from_api_repr_policy(self):

215245

field = self._get_target_class().from_api_repr(

@@ -264,6 +294,17 @@ def test_from_api_repr_defaults(self):

264294

self.assertNotIn("policyTags", field._properties)

265295

self.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+267308

def test_name_property(self):

268309

name = "lemon-ness"

269310

schema_field = self._make_one(name, "INTEGER")

@@ -323,6 +364,22 @@ def test_foreign_type_definition_property_str(self):

323364

schema_field._properties["foreignTypeDefinition"] = FOREIGN_TYPE_DEFINITION

324365

self.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+326383

def test_to_standard_sql_simple_type(self):

327384

examples = (

328385

# a few legacy types

@@ -637,7 +694,9 @@ def test___hash__not_equals(self):

637694638695

def test___repr__(self):

639696

field1 = 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+

)

641700

self.assertEqual(repr(field1), expected)

642701643702

def test___repr__evaluable_no_policy_tags(self):