@@ -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+ )
5558
5659 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+ )
9098
9199 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 )
191199
200+ 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+ )
213243
214244 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 )
266296
297+ 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 )
325366
367+ 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):
637694
638695 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 )
642701
643702 def test___repr__evaluable_no_policy_tags (self ):
0 commit comments