20
20
import numbers
21
21
22
22
from google .cloud import bigquery
23
- from google .cloud .bigquery import table
23
+ from google .cloud .bigquery import table , enums
24
24
from google .cloud .bigquery .dbapi import exceptions
25
25
26
26
27
27
_NUMERIC_SERVER_MIN = decimal .Decimal ("-9.9999999999999999999999999999999999999E+28" )
28
28
_NUMERIC_SERVER_MAX = decimal .Decimal ("9.9999999999999999999999999999999999999E+28" )
29
29
30
30
31
- def scalar_to_query_parameter (value , name = None ):
31
+ def _parameter_type (name , value , query_parameter_type = None , value_doc = "" ):
32
+ if query_parameter_type :
33
+ try :
34
+ parameter_type = getattr (
35
+ enums .SqlParameterScalarTypes , query_parameter_type .upper ()
36
+ )._type
37
+ except AttributeError :
38
+ raise exceptions .ProgrammingError (
39
+ f"The given parameter type, { query_parameter_type } ,"
40
+ f" for { name } is not a valid BigQuery scalar type."
41
+ )
42
+ else :
43
+ parameter_type = bigquery_scalar_type (value )
44
+ if parameter_type is None :
45
+ raise exceptions .ProgrammingError (
46
+ f"Encountered parameter { name } with "
47
+ f"{ value_doc } value { value } of unexpected type."
48
+ )
49
+ return parameter_type
50
+
51
+
52
+ def scalar_to_query_parameter (value , name = None , query_parameter_type = None ):
32
53
"""Convert a scalar value into a query parameter.
33
54
34
55
Args:
@@ -37,6 +58,7 @@ def scalar_to_query_parameter(value, name=None):
37
58
38
59
name (str):
39<
A93C
/code>
60
(Optional) Name of the query parameter.
61
+ query_parameter_type (Optional[str]): Given type for the parameter.
40
62
41
63
Returns:
42
64
google.cloud.bigquery.ScalarQueryParameter:
@@ -47,24 +69,19 @@ def scalar_to_query_parameter(value, name=None):
47
69
google.cloud.bigquery.dbapi.exceptions.ProgrammingError:
48
70
if the type cannot be determined.
49
71
"""
50
- parameter_type = bigquery_scalar_type (value )
51
-
52
- if parameter_type is None :
53
- raise exceptions .ProgrammingError (
54
- "encountered parameter {} with value {} of unexpected type" .format (
55
- name , value
56
- )
57
- )
58
- return bigquery .ScalarQueryParameter (name , parameter_type , value )
72
+ return bigquery .ScalarQueryParameter (
73
+ name , _parameter_type (name , value , query_parameter_type ), value
74
+ )
59
75
60
76
61
- def array_to_query_parameter (value , name = None ):
77
+ def array_to_query_parameter (value , name = None , query_parameter_type = None ):
62
78
"""Convert an array-like value into a query parameter.
63
79
64
80
Args:
65
81
value (Sequence[Any]): The elements of the array (should not be a
66
82
string-like Sequence).
67
83
name (Optional[str]): Name of the query parameter.
84
+ query_parameter_type (Optional[str]): Given type for the parameter.
68
85
69
86
Returns:
70
87
A query parameter corresponding with the type and value of the plain
@@ -80,53 +97,58 @@ def array_to_query_parameter(value, name=None):
80
97
"not string-like." .format (name )
81
98
)
82
99
83
- if not value :
100
+ if query_parameter_type or value :
101
+ array_type = _parameter_type (
102
+ name ,
103
+ value [0 ] if value else None ,
104
+ query_parameter_type ,
105
+ value_doc = "array element " ,
106
+ )
107
+ else :
84
108
rai
A93C
se exceptions .ProgrammingError (
85
109
"Encountered an empty array-like value of parameter {}, cannot "
86
110
"determine array elements type." .format (name )
87
111
)
88
112
89
- # Assume that all elements are of the same type, and let the backend handle
90
- # any type incompatibilities among the array elements
91
- array_type = bigquery_scalar_type (value [0 ])
92
- if array_type is None :
93
- raise exceptions .ProgrammingError (
94
- "Encountered unexpected first array element of parameter {}, "
95
- "cannot determine array elements type." .format (name )
96
- )
97
-
98
113
return bigquery .ArrayQueryParameter (name , array_type , value )
99
114
100
115
101
- def to_query_parameters_list (parameters ):
116
+ def to_query_parameters_list (parameters , parameter_types ):
102
117
"""Converts a sequence of parameter values into query parameters.
103
118
104
119
Args:
105
120
parameters (Sequence[Any]): Sequence of query parameter values.
121
+ parameter_types:
122
+ A list of parameter types, one for each parameter.
123
+ Unknown types are provided as None.
106
124
107
125
Returns:
108
126
List[google.cloud.bigquery.query._AbstractQueryParameter]:
109
127
A list of query parameters.
110
128
"""
111
129
result = []
112
130
113
- for value in parameters :
131
+ for value , type_ in zip ( parameters , parameter_types ) :
114
132
if isinstance (value , collections_abc .Mapping ):
115
133
raise NotImplementedError ("STRUCT-like parameter values are not supported." )
116
134
elif array_like (value ):
117
- param = array_to_query_parameter (value )
135
+ param = array_to_query_parameter (value , None , type_ )
118
136
else :
119
- param = scalar_to_query_parameter (value )
137
+ param = scalar_to_query_parameter (value , None , type_ )
138
+
120
139
result .append (param )
121
140
122
141
return result
123
142
124
143
125
- def to_query_parameters_dict (parameters ):
144
+ def to_query_parameters_dict (parameters , query_parameter_types ):
126
145
"""Converts a dictionary of parameter values into query parameters.
127
146
128
147
Args:
129
148
parameters (Mapping[str, Any]): Dictionary of query parameter values.
149
+ parameter_types:
150
+ A dictionary of parameter types. It needn't have a key for each
151
+ parameter.
130
152
131
153
Returns:
132
154
List[google.cloud.bigquery.query._AbstractQueryParameter]:
@@ -140,21 +162,38 @@ def to_query_parameters_dict(parameters):
140
162
"STRUCT-like parameter values are not supported "
141
163
"(parameter {})." .format (name )
142
164
)
143
- elif array_like (value ):
144
- param = array_to_query_parameter (value , name = name )
145
165
else :
146
- param = scalar_to_query_parameter (value , name = name )
166
+ query_parameter_type = query_parameter_types .get (name )
167
+ if array_like (value ):
168
+ param = array_to_query_parameter (
169
+ value , name = name , query_parameter_type = query_parameter_type
170
+ )
171
+ else :
172
+ param = scalar_to_query_parameter (
173
+ value , name = name , query_parameter_type = query_parameter_type ,
174
+ )
175
+
147
176
result .append (param )
148
177
149
178
return result
150
179
151
180
152
- def to_query_parameters (parameters ):
181
+ def to_query_parameters (parameters , parameter_types ):
153
182
"""Converts DB-API parameter values into query parameters.
154
183
155
184
Args:
156
185
parameters (Union[Mapping[str, Any], Sequence[Any]]):
157
186
A dictionary or sequence of query parameter values.
187
+ parameter_types (Union[Mapping[str, str], Sequence[str]]):
188
+ A dictionary or list of parameter types.
189
+
190
+ If parameters is a mapping, then this must be a dictionary
191
+ of parameter types. It needn't have a key for each
192
+ parameter.
193
+
194
+ If parameters is a sequence, then this must be a list of
195
+ parameter types, one for each paramater. Unknown types
196
+ are provided as None.
158
197
159
198
Returns:
160
199
List[google.cloud.bigquery.query._AbstractQueryParameter]:
@@ -164,9 +203,9 @@ def to_query_parameters(parameters):
164
203
return []
165
204
166
205
if isinstance (parameters , collections_abc .Mapping ):
167
- return to_query_parameters_dict (parameters )
168
-
169
- return to_query_parameters_list (parameters )
206
+ return to_query_parameters_dict (parameters , parameter_types )
207
+ else :
208
+ return to_query_parameters_list (parameters , parameter_types )
170
209
171
210
172
211
def bigquery_scalar_type (value ):
0 commit comments