4
4
5
5
import ibis .expr .datatypes as dt
6
6
7
-
8
- class TypeTranslationContext :
9
- """A tag class to alter the way a type is translated.
10
-
11
- This is used to raise an exception when INT64 types are encountered to
12
- avoid suprising results due to BigQuery's handling of INT64 types in
13
- JavaScript UDFs.
14
- """
15
-
16
- __slots__ = ()
17
-
18
-
19
- class UDFContext (TypeTranslationContext ):
20
- __slots__ = ()
21
-
22
-
23
- UDF_CONTEXT = UDFContext ()
24
-
25
7
ibis_type_to_bigquery_type = Dispatcher ("ibis_type_to_bigquery_type" )
26
8
27
9
@@ -30,81 +12,60 @@ def trans_string_default(datatype):
30
12
return ibis_type_to_bigquery_type (dt .dtype (datatype ))
31
13
32
14
33
- @ibis_type_to_bigquery_type .register (dt .DataType )
34
- def trans_default (t ):
35
- return ibis_type_to_bigquery_type (t , TypeTranslationContext ())
36
-
37
-
38
- @ibis_type_to_bigquery_type .register (str , TypeTranslationContext )
39
- def trans_string_context (datatype , context ):
40
- return ibis_type_to_bigquery_type (dt .dtype (datatype ), context )
41
-
42
-
43
- @ibis_type_to_bigquery_type .register (dt .Floating , TypeTranslationContext )
44
- def trans_float64 (t , context ):
15
+ @ibis_type_to_bigquery_type .register (dt .Floating )
16
+ def trans_float64 (t ):
45
17
return "FLOAT64"
46
18
47
19
48
- @ibis_type_to_bigquery_type .register (dt .Integer , TypeTranslationContext )
49
- def trans_integer (t , context ):
20
+ @ibis_type_to_bigquery_type .register (dt .Integer )
21
+ def trans_integer (t ):
50
22
return "INT64"
51
23
52
24
53
- @ibis_type_to_bigquery_type .register (dt .Binary , TypeTranslationContext )
54
- def trans_binary (t , context ):
25
+ @ibis_type_to_bigquery_type .register (dt .Binary )
26
+ def trans_binary (t ):
55
27
return "BYTES"
56
28
57
29
58
- @ibis_type_to_bigquery_type .register (dt .UInt64 , ( TypeTranslationContext , UDFContext ) )
59
- def trans_lossy_integer (t , context ):
30
+ @ibis_type_to_bigquery_type .register (dt .UInt64 )
31
+ def trans_lossy_integer (t ):
60
32
raise TypeError ("Conversion from uint64 to BigQuery integer type (int64) is lossy" )
61
33
62
34
63
- @ibis_type_to_bigquery_type .register (dt .Array , TypeTranslationContext )
64
- def trans_array (t , context ):
65
- return f"ARRAY<{ ibis_type_to_bigquery_type (t .value_type , context )} >"
35
+ @ibis_type_to_bigquery_type .register (dt .Array )
36
+ def trans_array (t ):
37
+ return f"ARRAY<{ ibis_type_to_bigquery_type (t .value_type )} >"
66
38
67
39
68
- @ibis_type_to_bigquery_type .register (dt .Struct , TypeTranslationContext )
69
- def trans_struct (t , context ):
40
+ @ibis_type_to_bigquery_type .register (dt .Struct )
41
+ def trans_struct (t ):
70
42
return "STRUCT<{}>" .format (
71
43
", " .join (
72
- f"{ name } { ibis_type_to_bigquery_type (dt .dtype (type ), context )} "
73
- for name , type in zip (t .names , t .types )
44
+ f"{ name } { ibis_type_to_bigquery_type (dt .dtype (type_ ) )} "
45
+ for name , type_ in zip (t .names , t .types )
74
46
)
75
47
)
76
48
77
49
78
- @ibis_type_to_bigquery_type .register (dt .Date , TypeTranslationContext )
79
- def trans_date (t , context ):
50
+ @ibis_type_to_bigquery_type .register (dt .Date )
51
+ def trans_date (t ):
80
52
return "DATE"
81
53
82
54
83
- @ibis_type_to_bigquery_type .register (dt .Timestamp , TypeTranslationContext )
84
- def trans_timestamp (t , context ):
55
+ @ibis_type_to_bigquery_type .register (dt .Timestamp )
56
+ def trans_timestamp (t ):
85
57
if t .timezone is not None :
86
58
raise TypeError ("BigQuery does not support timestamps with timezones" )
87
59
return "TIMESTAMP"
88
60
89
61
90
- @ibis_type_to_bigquery_type .register (dt .DataType , TypeTranslationContext )
91
- def trans_type (t , context ):
62
+ @ibis_type_to_bigquery_type .register (dt .DataType )
63
+ def trans_type (t ):
92
64
return str (t ).upper ()
93
65
94
66
95
- @ibis_type_to_bigquery_type .register (dt .Integer , UDFContext )
96
- def trans_integer_udf (t , context ):
97
- # JavaScript does not have integers, only a Number class. BigQuery doesn't
98
- # behave as expected with INT64 inputs or outputs
99
- raise TypeError (
100
- "BigQuery does not support INT64 as an argument type or a return type "
101
- "for UDFs. Replace INT64 with FLOAT64 in your UDF signature and "
102
- "cast all INT64 inputs to FLOAT64."
103
- )
104
-
105
-
106
- @ibis_type_to_bigquery_type .register (dt .Decimal , TypeTranslationContext )
107
- def trans_numeric (t , context ):
67
+ @ibis_type_to_bigquery_type .register (dt .Decimal )
68
+ def trans_numeric (t ):
108
69
if (t .precision , t .scale ) != (38 , 9 ):
109
70
raise TypeError (
110
71
"BigQuery only supports decimal types with precision of 38 and "
@@ -113,11 +74,22 @@ def trans_numeric(t, context):
113
74
return "NUMERIC"
114
75
115
76
116
- @ibis_type_to_bigquery_type .register (dt .Decimal , UDFContext )
117
- def trans_numeric_udf ( t , context ):
118
- raise TypeError ( "Decimal types are not supported in BigQuery UDFs" )
77
+ @ibis_type_to_bigquery_type .register (dt .JSON )
78
+ def trans_json ( t ):
79
+ return "JSON"
119
80
120
81
121
- @ibis_type_to_bigquery_type .register (dt .JSON , TypeTranslationContext )
122
- def trans_json (t , context ):
123
- return "JSON"
82
+ def spread_type (dt : dt .DataType ):
83
+ """Returns a generator that contains all the types in the given type.
84
+
85
+ For complex types like set and array, it returns the types of the elements.
86
+ """
87
+ if dt .is_array ():
88
+ yield from spread_type (dt .value_type )
89
+ elif dt .is_struct ():
90
+ for type_ in dt .types :
91
+ yield from spread_type (type_ )
92
+ elif dt .is_map ():
93
+ yield from spread_type (dt .key_type )
94
+ yield from spread_type (dt .value_type )
95
+ yield dt
0 commit comments