google-cloud-bigquery 3.31.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. google/cloud/bigquery/__init__.py +249 -0
  2. google/cloud/bigquery/_helpers.py +1102 -0
  3. google/cloud/bigquery/_http.py +47 -0
  4. google/cloud/bigquery/_job_helpers.py +600 -0
  5. google/cloud/bigquery/_pandas_helpers.py +1181 -0
  6. google/cloud/bigquery/_pyarrow_helpers.py +147 -0
  7. google/cloud/bigquery/_tqdm_helpers.py +137 -0
  8. google/cloud/bigquery/_versions_helpers.py +264 -0
  9. google/cloud/bigquery/client.py +4406 -0
  10. google/cloud/bigquery/dataset.py +1076 -0
  11. google/cloud/bigquery/dbapi/__init__.py +87 -0
  12. google/cloud/bigquery/dbapi/_helpers.py +522 -0
  13. google/cloud/bigquery/dbapi/connection.py +128 -0
  14. google/cloud/bigquery/dbapi/cursor.py +586 -0
  15. google/cloud/bigquery/dbapi/exceptions.py +58 -0
  16. google/cloud/bigquery/dbapi/types.py +96 -0
  17. google/cloud/bigquery/encryption_configuration.py +84 -0
  18. google/cloud/bigquery/enums.py +389 -0
  19. google/cloud/bigquery/exceptions.py +35 -0
  20. google/cloud/bigquery/external_config.py +1188 -0
  21. google/cloud/bigquery/format_options.py +147 -0
  22. google/cloud/bigquery/iam.py +38 -0
  23. google/cloud/bigquery/job/__init__.py +87 -0
  24. google/cloud/bigquery/job/base.py +1116 -0
  25. google/cloud/bigquery/job/copy_.py +282 -0
  26. google/cloud/bigquery/job/extract.py +271 -0
  27. google/cloud/bigquery/job/load.py +985 -0
  28. google/cloud/bigquery/job/query.py +2498 -0
  29. google/cloud/bigquery/magics/__init__.py +20 -0
  30. google/cloud/bigquery/magics/line_arg_parser/__init__.py +34 -0
  31. google/cloud/bigquery/magics/line_arg_parser/exceptions.py +25 -0
  32. google/cloud/bigquery/magics/line_arg_parser/lexer.py +200 -0
  33. google/cloud/bigquery/magics/line_arg_parser/parser.py +484 -0
  34. google/cloud/bigquery/magics/line_arg_parser/visitors.py +159 -0
  35. google/cloud/bigquery/magics/magics.py +776 -0
  36. google/cloud/bigquery/model.py +517 -0
  37. google/cloud/bigquery/opentelemetry_tracing.py +164 -0
  38. google/cloud/bigquery/py.typed +2 -0
  39. google/cloud/bigquery/query.py +1344 -0
  40. google/cloud/bigquery/retry.py +207 -0
  41. google/cloud/bigquery/routine/__init__.py +33 -0
  42. google/cloud/bigquery/routine/routine.py +744 -0
  43. google/cloud/bigquery/schema.py +896 -0
  44. google/cloud/bigquery/standard_sql.py +389 -0
  45. google/cloud/bigquery/table.py +3594 -0
  46. google/cloud/bigquery/version.py +15 -0
  47. google/cloud/bigquery_v2/__init__.py +56 -0
  48. google/cloud/bigquery_v2/types/__init__.py +54 -0
  49. google/cloud/bigquery_v2/types/encryption_config.py +48 -0
  50. google/cloud/bigquery_v2/types/model.py +1994 -0
  51. google/cloud/bigquery_v2/types/model_reference.py +57 -0
  52. google/cloud/bigquery_v2/types/standard_sql.py +156 -0
  53. google/cloud/bigquery_v2/types/table_reference.py +80 -0
  54. google_cloud_bigquery-3.31.0.dist-info/LICENSE +202 -0
  55. google_cloud_bigquery-3.31.0.dist-info/METADATA +203 -0
  56. google_cloud_bigquery-3.31.0.dist-info/RECORD +58 -0
  57. google_cloud_bigquery-3.31.0.dist-info/WHEEL +5 -0
  58. google_cloud_bigquery-3.31.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,1344 @@
1
+ # Copyright 2015 Google LLC
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ """BigQuery query processing."""
16
+
17
+ from collections import OrderedDict
18
+ import copy
19
+ import datetime
20
+ import decimal
21
+ from typing import Any, cast, Optional, Dict, Union
22
+
23
+ from google.cloud.bigquery.table import _parse_schema_resource
24
+ from google.cloud.bigquery import _helpers
25
+ from google.cloud.bigquery._helpers import _rows_from_json
26
+ from google.cloud.bigquery._helpers import _SCALAR_VALUE_TO_JSON_PARAM
27
+ from google.cloud.bigquery._helpers import _SUPPORTED_RANGE_ELEMENTS
28
+
29
+
30
+ _SCALAR_VALUE_TYPE = Optional[
31
+ Union[str, int, float, decimal.Decimal, bool, datetime.datetime, datetime.date]
32
+ ]
33
+
34
+
35
+ class ConnectionProperty:
36
+ """A connection-level property to customize query behavior.
37
+
38
+ See
39
+ https://cloud.google.com/bigquery/docs/reference/rest/v2/ConnectionProperty
40
+
41
+ Args:
42
+ key:
43
+ The key of the property to set, for example, ``'time_zone'`` or
44
+ ``'session_id'``.
45
+ value: The value of the property to set.
46
+ """
47
+
48
+ def __init__(self, key: str = "", value: str = ""):
49
+ self._properties = {
50
+ "key": key,
51
+ "value": value,
52
+ }
53
+
54
+ @property
55
+ def key(self) -> str:
56
+ """Name of the property.
57
+
58
+ For example:
59
+
60
+ * ``time_zone``
61
+ * ``session_id``
62
+ """
63
+ return self._properties["key"]
64
+
65
+ @property
66
+ def value(self) -> str:
67
+ """Value of the property."""
68
+ return self._properties["value"]
69
+
70
+ @classmethod
71
+ def from_api_repr(cls, resource) -> "ConnectionProperty":
72
+ """Construct :class:`~google.cloud.bigquery.query.ConnectionProperty`
73
+ from JSON resource.
74
+
75
+ Args:
76
+ resource: JSON representation.
77
+
78
+ Returns:
79
+ A connection property.
80
+ """
81
+ value = cls()
82
+ value._properties = resource
83
+ return value
84
+
85
+ def to_api_repr(self) -> Dict[str, Any]:
86
+ """Construct JSON API representation for the connection property.
87
+
88
+ Returns:
89
+ JSON mapping
90
+ """
91
+ return self._properties
92
+
93
+
94
+ class UDFResource(object):
95
+ """Describe a single user-defined function (UDF) resource.
96
+
97
+ Args:
98
+ udf_type (str): The type of the resource ('inlineCode' or 'resourceUri')
99
+
100
+ value (str): The inline code or resource URI.
101
+
102
+ See:
103
+ https://cloud.google.com/bigquery/user-defined-functions#api
104
+ """
105
+
106
+ def __init__(self, udf_type, value):
107
+ self.udf_type = udf_type
108
+ self.value = value
109
+
110
+ def __eq__(self, other):
111
+ if not isinstance(other, UDFResource):
112
+ return NotImplemented
113
+ return self.udf_type == other.udf_type and self.value == other.value
114
+
115
+ def __ne__(self, other):
116
+ return not self == other
117
+
118
+
119
+ class _AbstractQueryParameterType:
120
+ """Base class for representing query parameter types.
121
+
122
+ https://cloud.google.com/bigquery/docs/reference/rest/v2/QueryParameter#queryparametertype
123
+ """
124
+
125
+ @classmethod
126
+ def from_api_repr(cls, resource):
127
+ """Factory: construct parameter type from JSON resource.
128
+
129
+ Args:
130
+ resource (Dict): JSON mapping of parameter
131
+
132
+ Returns:
133
+ google.cloud.bigquery.query.QueryParameterType: Instance
134
+ """
135
+ raise NotImplementedError
136
+
137
+ def to_api_repr(self):
138
+ """Construct JSON API representation for the parameter type.
139
+
140
+ Returns:
141
+ Dict: JSON mapping
142
+ """
143
+ raise NotImplementedError
144
+
145
+
146
+ class ScalarQueryParameterType(_AbstractQueryParameterType):
147
+ """Type representation for scalar query parameters.
148
+
149
+ Args:
150
+ type_ (str):
151
+ One of 'STRING', 'INT64', 'FLOAT64', 'NUMERIC', 'BOOL', 'TIMESTAMP',
152
+ 'DATETIME', or 'DATE'.
153
+ name (Optional[str]):
154
+ The name of the query parameter. Primarily used if the type is
155
+ one of the subfields in ``StructQueryParameterType`` instance.
156
+ description (Optional[str]):
157
+ The query parameter description. Primarily used if the type is
158
+ one of the subfields in ``StructQueryParameterType`` instance.
159
+ """
160
+
161
+ def __init__(self, type_, *, name=None, description=None):
162
+ self._type = type_
163
+ self.name = name
164
+ self.description = description
165
+
166
+ @classmethod
167
+ def from_api_repr(cls, resource):
168
+ """Factory: construct parameter type from JSON resource.
169
+
170
+ Args:
171
+ resource (Dict): JSON mapping of parameter
172
+
173
+ Returns:
174
+ google.cloud.bigquery.query.ScalarQueryParameterType: Instance
175
+ """
176
+ type_ = resource["type"]
177
+ return cls(type_)
178
+
179
+ def to_api_repr(self):
180
+ """Construct JSON API representation for the parameter type.
181
+
182
+ Returns:
183
+ Dict: JSON mapping
184
+ """
185
+ # Name and description are only used if the type is a field inside a struct
186
+ # type, but it's StructQueryParameterType's responsibilty to use these two
187
+ # attributes in the API representation when needed. Here we omit them.
188
+ return {"type": self._type}
189
+
190
+ def with_name(self, new_name: Union[str, None]):
191
+ """Return a copy of the instance with ``name`` set to ``new_name``.
192
+
193
+ Args:
194
+ name (Union[str, None]):
195
+ The new name of the query parameter type. If ``None``, the existing
196
+ name is cleared.
197
+
198
+ Returns:
199
+ google.cloud.bigquery.query.ScalarQueryParameterType:
200
+ A new instance with updated name.
201
+ """
202
+ return type(self)(self._type, name=new_name, description=self.description)
203
+
204
+ def __repr__(self):
205
+ name = f", name={self.name!r}" if self.name is not None else ""
206
+ description = (
207
+ f", description={self.description!r}"
208
+ if self.description is not None
209
+ else ""
210
+ )
211
+ return f"{self.__class__.__name__}({self._type!r}{name}{description})"
212
+
213
+
214
+ class ArrayQueryParameterType(_AbstractQueryParameterType):
215
+ """Type representation for array query parameters.
216
+
217
+ Args:
218
+ array_type (Union[ScalarQueryParameterType, StructQueryParameterType]):
219
+ The type of array elements.
220
+ name (Optional[str]):
221
+ The name of the query parameter. Primarily used if the type is
222
+ one of the subfields in ``StructQueryParameterType`` instance.
223
+ description (Optional[str]):
224
+ The query parameter description. Primarily used if the type is
225
+ one of the subfields in ``StructQueryParameterType`` instance.
226
+ """
227
+
228
+ def __init__(self, array_type, *, name=None, description=None):
229
+ self._array_type = array_type
230
+ self.name = name
231
+ self.description = description
232
+
233
+ @classmethod
234
+ def from_api_repr(cls, resource):
235
+ """Factory: construct parameter type from JSON resource.
236
+
237
+ Args:
238
+ resource (Dict): JSON mapping of parameter
239
+
240
+ Returns:
241
+ google.cloud.bigquery.query.ArrayQueryParameterType: Instance
242
+ """
243
+ array_item_type = resource["arrayType"]["type"]
244
+
245
+ if array_item_type in {"STRUCT", "RECORD"}:
246
+ klass = StructQueryParameterType
247
+ else:
248
+ klass = ScalarQueryParameterType
249
+
250
+ item_type_instance = klass.from_api_repr(resource["arrayType"])
251
+ return cls(item_type_instance)
252
+
253
+ def to_api_repr(self):
254
+ """Construct JSON API representation for the parameter type.
255
+
256
+ Returns:
257
+ Dict: JSON mapping
258
+ """
259
+ # Name and description are only used if the type is a field inside a struct
260
+ # type, but it's StructQueryParameterType's responsibilty to use these two
261
+ # attributes in the API representation when needed. Here we omit them.
262
+ return {
263
+ "type": "ARRAY",
264
+ "arrayType": self._array_type.to_api_repr(),
265
+ }
266
+
267
+ def __repr__(self):
268
+ name = f", name={self.name!r}" if self.name is not None else ""
269
+ description = (
270
+ f", description={self.description!r}"
271
+ if self.description is not None
272
+ else ""
273
+ )
274
+ return f"{self.__class__.__name__}({self._array_type!r}{name}{description})"
275
+
276
+
277
+ class StructQueryParameterType(_AbstractQueryParameterType):
278
+ """Type representation for struct query parameters.
279
+
280
+ Args:
281
+ fields (Iterable[Union[ \
282
+ ArrayQueryParameterType, ScalarQueryParameterType, StructQueryParameterType \
283
+ ]]):
284
+ An non-empty iterable describing the struct's field types.
285
+ name (Optional[str]):
286
+ The name of the query parameter. Primarily used if the type is
287
+ one of the subfields in ``StructQueryParameterType`` instance.
288
+ description (Optional[str]):
289
+ The query parameter description. Primarily used if the type is
290
+ one of the subfields in ``StructQueryParameterType`` instance.
291
+ """
292
+
293
+ def __init__(self, *fields, name=None, description=None):
294
+ if not fields:
295
+ raise ValueError("Struct type must have at least one field defined.")
296
+
297
+ self._fields = fields # fields is a tuple (immutable), no shallow copy needed
298
+ self.name = name
299
+ self.description = description
300
+
301
+ @property
302
+ def fields(self):
303
+ return self._fields # no copy needed, self._fields is an immutable sequence
304
+
305
+ @classmethod
306
+ def from_api_repr(cls, resource):
307
+ """Factory: construct parameter type from JSON resource.
308
+
309
+ Args:
310
+ resource (Dict): JSON mapping of parameter
311
+
312
+ Returns:
313
+ google.cloud.bigquery.query.StructQueryParameterType: Instance
314
+ """
315
+ fields = []
316
+
317
+ for struct_field in resource["structTypes"]:
318
+ type_repr = struct_field["type"]
319
+ if type_repr["type"] in {"STRUCT", "RECORD"}:
320
+ klass = StructQueryParameterType
321
+ elif type_repr["type"] == "ARRAY":
322
+ klass = ArrayQueryParameterType
323
+ else:
324
+ klass = ScalarQueryParameterType
325
+
326
+ type_instance = klass.from_api_repr(type_repr)
327
+ type_instance.name = struct_field.get("name")
328
+ type_instance.description = struct_field.get("description")
329
+ fields.append(type_instance)
330
+
331
+ return cls(*fields)
332
+
333
+ def to_api_repr(self):
334
+ """Construct JSON API representation for the parameter type.
335
+
336
+ Returns:
337
+ Dict: JSON mapping
338
+ """
339
+ fields = []
340
+
341
+ for field in self._fields:
342
+ item = {"type": field.to_api_repr()}
343
+ if field.name is not None:
344
+ item["name"] = field.name
345
+ if field.description is not None:
346
+ item["description"] = field.description
347
+
348
+ fields.append(item)
349
+
350
+ return {
351
+ "type": "STRUCT",
352
+ "structTypes": fields,
353
+ }
354
+
355
+ def __repr__(self):
356
+ name = f", name={self.name!r}" if self.name is not None else ""
357
+ description = (
358
+ f", description={self.description!r}"
359
+ if self.description is not None
360
+ else ""
361
+ )
362
+ items = ", ".join(repr(field) for field in self._fields)
363
+ return f"{self.__class__.__name__}({items}{name}{description})"
364
+
365
+
366
+ class RangeQueryParameterType(_AbstractQueryParameterType):
367
+ """Type representation for range query parameters.
368
+
369
+ Args:
370
+ type_ (Union[ScalarQueryParameterType, str]):
371
+ Type of range element, must be one of 'TIMESTAMP', 'DATETIME', or
372
+ 'DATE'.
373
+ name (Optional[str]):
374
+ The name of the query parameter. Primarily used if the type is
375
+ one of the subfields in ``StructQueryParameterType`` instance.
376
+ description (Optional[str]):
377
+ The query parameter description. Primarily used if the type is
378
+ one of the subfields in ``StructQueryParameterType`` instance.
379
+ """
380
+
381
+ @classmethod
382
+ def _parse_range_element_type(self, type_):
383
+ """Helper method that parses the input range element type, which may
384
+ be a string, or a ScalarQueryParameterType object.
385
+
386
+ Returns:
387
+ google.cloud.bigquery.query.ScalarQueryParameterType: Instance
388
+ """
389
+ if isinstance(type_, str):
390
+ if type_ not in _SUPPORTED_RANGE_ELEMENTS:
391
+ raise ValueError(
392
+ "If given as a string, range element type must be one of "
393
+ "'TIMESTAMP', 'DATE', or 'DATETIME'."
394
+ )
395
+ return ScalarQueryParameterType(type_)
396
+ elif isinstance(type_, ScalarQueryParameterType):
397
+ if type_._type not in _SUPPORTED_RANGE_ELEMENTS:
398
+ raise ValueError(
399
+ "If given as a ScalarQueryParameter object, range element "
400
+ "type must be one of 'TIMESTAMP', 'DATE', or 'DATETIME' "
401
+ "type."
402
+ )
403
+ return type_
404
+ else:
405
+ raise ValueError(
406
+ "range_type must be a string or ScalarQueryParameter object, "
407
+ "of 'TIMESTAMP', 'DATE', or 'DATETIME' type."
408
+ )
409
+
410
+ def __init__(self, type_, *, name=None, description=None):
411
+ self.type_ = self._parse_range_element_type(type_)
412
+ self.name = name
413
+ self.description = description
414
+
415
+ @classmethod
416
+ def from_api_repr(cls, resource):
417
+ """Factory: construct parameter type from JSON resource.
418
+
419
+ Args:
420
+ resource (Dict): JSON mapping of parameter
421
+
422
+ Returns:
423
+ google.cloud.bigquery.query.RangeQueryParameterType: Instance
424
+ """
425
+ type_ = resource["rangeElementType"]["type"]
426
+ name = resource.get("name")
427
+ description = resource.get("description")
428
+
429
+ return cls(type_, name=name, description=description)
430
+
431
+ def to_api_repr(self):
432
+ """Construct JSON API representation for the parameter type.
433
+
434
+ Returns:
435
+ Dict: JSON mapping
436
+ """
437
+ # Name and description are only used if the type is a field inside a struct
438
+ # type, but it's StructQueryParameterType's responsibilty to use these two
439
+ # attributes in the API representation when needed. Here we omit them.
440
+ return {
441
+ "type": "RANGE",
442
+ "rangeElementType": self.type_.to_api_repr(),
443
+ }
444
+
445
+ def with_name(self, new_name: Union[str, None]):
446
+ """Return a copy of the instance with ``name`` set to ``new_name``.
447
+
448
+ Args:
449
+ name (Union[str, None]):
450
+ The new name of the range query parameter type. If ``None``,
451
+ the existing name is cleared.
452
+
453
+ Returns:
454
+ google.cloud.bigquery.query.RangeQueryParameterType:
455
+ A new instance with updated name.
456
+ """
457
+ return type(self)(self.type_, name=new_name, description=self.description)
458
+
459
+ def __repr__(self):
460
+ name = f", name={self.name!r}" if self.name is not None else ""
461
+ description = (
462
+ f", description={self.description!r}"
463
+ if self.description is not None
464
+ else ""
465
+ )
466
+ return f"{self.__class__.__name__}({self.type_!r}{name}{description})"
467
+
468
+ def _key(self):
469
+ """A tuple key that uniquely describes this field.
470
+
471
+ Used to compute this instance's hashcode and evaluate equality.
472
+
473
+ Returns:
474
+ Tuple: The contents of this
475
+ :class:`~google.cloud.bigquery.query.RangeQueryParameterType`.
476
+ """
477
+ type_ = self.type_.to_api_repr()
478
+ return (self.name, type_, self.description)
479
+
480
+ def __eq__(self, other):
481
+ if not isinstance(other, RangeQueryParameterType):
482
+ return NotImplemented
483
+ return self._key() == other._key()
484
+
485
+ def __ne__(self, other):
486
+ return not self == other
487
+
488
+
489
+ class _AbstractQueryParameter(object):
490
+ """Base class for named / positional query parameters."""
491
+
492
+ @classmethod
493
+ def from_api_repr(cls, resource: dict) -> "_AbstractQueryParameter":
494
+ """Factory: construct parameter from JSON resource.
495
+
496
+ Args:
497
+ resource (Dict): JSON mapping of parameter
498
+
499
+ Returns:
500
+ A new instance of _AbstractQueryParameter subclass.
501
+ """
502
+ raise NotImplementedError
503
+
504
+ def to_api_repr(self) -> dict:
505
+ """Construct JSON API representation for the parameter.
506
+
507
+ Returns:
508
+ Dict: JSON representation for the parameter.
509
+ """
510
+ raise NotImplementedError
511
+
512
+
513
+ class ScalarQueryParameter(_AbstractQueryParameter):
514
+ """Named / positional query parameters for scalar values.
515
+
516
+ Args:
517
+ name:
518
+ Parameter name, used via ``@foo`` syntax. If None, the
519
+ parameter can only be addressed via position (``?``).
520
+
521
+ type_:
522
+ Name of parameter type. See
523
+ :class:`google.cloud.bigquery.enums.SqlTypeNames` and
524
+ :class:`google.cloud.bigquery.query.SqlParameterScalarTypes` for
525
+ supported types.
526
+
527
+ value:
528
+ The scalar parameter value.
529
+ """
530
+
531
+ def __init__(
532
+ self,
533
+ name: Optional[str],
534
+ type_: Optional[Union[str, ScalarQueryParameterType]],
535
+ value: _SCALAR_VALUE_TYPE,
536
+ ):
537
+ self.name = name
538
+ if isinstance(type_, ScalarQueryParameterType):
539
+ self.type_ = type_._type
540
+ else:
541
+ self.type_ = type_
542
+ self.value = value
543
+
544
+ @classmethod
545
+ def positional(
546
+ cls, type_: Union[str, ScalarQueryParameterType], value: _SCALAR_VALUE_TYPE
547
+ ) -> "ScalarQueryParameter":
548
+ """Factory for positional paramater.
549
+
550
+ Args:
551
+ type_:
552
+ Name of parameter type. One of 'STRING', 'INT64',
553
+ 'FLOAT64', 'NUMERIC', 'BIGNUMERIC', 'BOOL', 'TIMESTAMP', 'DATETIME', or
554
+ 'DATE'.
555
+
556
+ value:
557
+ The scalar parameter value.
558
+
559
+ Returns:
560
+ google.cloud.bigquery.query.ScalarQueryParameter: Instance without name
561
+ """
562
+ return cls(None, type_, value)
563
+
564
+ @classmethod
565
+ def from_api_repr(cls, resource: dict) -> "ScalarQueryParameter":
566
+ """Factory: construct parameter from JSON resource.
567
+
568
+ Args:
569
+ resource (Dict): JSON mapping of parameter
570
+
571
+ Returns:
572
+ google.cloud.bigquery.query.ScalarQueryParameter: Instance
573
+ """
574
+ # Import here to avoid circular imports.
575
+ from google.cloud.bigquery import schema
576
+
577
+ name = resource.get("name")
578
+ type_ = resource["parameterType"]["type"]
579
+
580
+ # parameterValue might not be present if JSON resource originates
581
+ # from the back-end - the latter omits it for None values.
582
+ value = resource.get("parameterValue", {}).get("value")
583
+ if value is not None:
584
+ converted = _helpers.SCALAR_QUERY_PARAM_PARSER.to_py(
585
+ value, schema.SchemaField(cast(str, name), type_)
586
+ )
587
+ else:
588
+ converted = None
589
+
590
+ return cls(name, type_, converted)
591
+
592
+ def to_api_repr(self) -> dict:
593
+ """Construct JSON API representation for the parameter.
594
+
595
+ Returns:
596
+ Dict: JSON mapping
597
+ """
598
+ value = self.value
599
+ converter = _SCALAR_VALUE_TO_JSON_PARAM.get(self.type_, lambda value: value)
600
+ value = converter(value) # type: ignore
601
+ resource: Dict[str, Any] = {
602
+ "parameterType": {"type": self.type_},
603
+ "parameterValue": {"value": value},
604
+ }
605
+ if self.name is not None:
606
+ resource["name"] = self.name
607
+ return resource
608
+
609
+ def _key(self):
610
+ """A tuple key that uniquely describes this field.
611
+
612
+ Used to compute this instance's hashcode and evaluate equality.
613
+
614
+ Returns:
615
+ Tuple: The contents of this :class:`~google.cloud.bigquery.query.ScalarQueryParameter`.
616
+ """
617
+ return (self.name, self.type_.upper(), self.value)
618
+
619
+ def __eq__(self, other):
620
+ if not isinstance(other, ScalarQueryParameter):
621
+ return NotImplemented
622
+ return self._key() == other._key()
623
+
624
+ def __ne__(self, other):
625
+ return not self == other
626
+
627
+ def __repr__(self):
628
+ return "ScalarQueryParameter{}".format(self._key())
629
+
630
+
631
+ class ArrayQueryParameter(_AbstractQueryParameter):
632
+ """Named / positional query parameters for array values.
633
+
634
+ Args:
635
+ name (Optional[str]):
636
+ Parameter name, used via ``@foo`` syntax. If None, the
637
+ parameter can only be addressed via position (``?``).
638
+
639
+ array_type (Union[str, ScalarQueryParameterType, StructQueryParameterType]):
640
+ The type of array elements. If given as a string, it must be one of
641
+ `'STRING'`, `'INT64'`, `'FLOAT64'`, `'NUMERIC'`, `'BIGNUMERIC'`, `'BOOL'`,
642
+ `'TIMESTAMP'`, `'DATE'`, or `'STRUCT'`/`'RECORD'`.
643
+ If the type is ``'STRUCT'``/``'RECORD'`` and ``values`` is empty,
644
+ the exact item type cannot be deduced, thus a ``StructQueryParameterType``
645
+ instance needs to be passed in.
646
+
647
+ values (List[appropriate type]): The parameter array values.
648
+ """
649
+
650
+ def __init__(self, name, array_type, values) -> None:
651
+ self.name = name
652
+ self.values = values
653
+
654
+ if isinstance(array_type, str):
655
+ if not values and array_type in {"RECORD", "STRUCT"}:
656
+ raise ValueError(
657
+ "Missing detailed struct item type info for an empty array, "
658
+ "please provide a StructQueryParameterType instance."
659
+ )
660
+ self.array_type = array_type
661
+
662
+ @classmethod
663
+ def positional(cls, array_type: str, values: list) -> "ArrayQueryParameter":
664
+ """Factory for positional parameters.
665
+
666
+ Args:
667
+ array_type (Union[str, ScalarQueryParameterType, StructQueryParameterType]):
668
+ The type of array elements. If given as a string, it must be one of
669
+ `'STRING'`, `'INT64'`, `'FLOAT64'`, `'NUMERIC'`, `'BIGNUMERIC'`,
670
+ `'BOOL'`, `'TIMESTAMP'`, `'DATE'`, or `'STRUCT'`/`'RECORD'`.
671
+ If the type is ``'STRUCT'``/``'RECORD'`` and ``values`` is empty,
672
+ the exact item type cannot be deduced, thus a ``StructQueryParameterType``
673
+ instance needs to be passed in.
674
+
675
+ values (List[appropriate type]): The parameter array values.
676
+
677
+ Returns:
678
+ google.cloud.bigquery.query.ArrayQueryParameter: Instance without name
679
+ """
680
+ return cls(None, array_type, values)
681
+
682
+ @classmethod
683
+ def _from_api_repr_struct(cls, resource):
684
+ name = resource.get("name")
685
+ converted = []
686
+ # We need to flatten the array to use the StructQueryParameter
687
+ # parse code.
688
+ resource_template = {
689
+ # The arrayType includes all the types of the fields of the STRUCT
690
+ "parameterType": resource["parameterType"]["arrayType"]
691
+ }
692
+ for array_value in resource["parameterValue"]["arrayValues"]:
693
+ struct_resource = copy.deepcopy(resource_template)
694
+ struct_resource["parameterValue"] = array_value
695
+ struct_value = StructQueryParameter.from_api_repr(struct_resource)
696
+ converted.append(struct_value)
697
+ return cls(name, "STRUCT", converted)
698
+
699
+ @classmethod
700
+ def _from_api_repr_scalar(cls, resource):
701
+ """Converts REST resource into a list of scalar values."""
702
+ # Import here to avoid circular imports.
703
+ from google.cloud.bigquery import schema
704
+
705
+ name = resource.get("name")
706
+ array_type = resource["parameterType"]["arrayType"]["type"]
707
+ parameter_value = resource.get("parameterValue", {})
708
+ array_values = parameter_value.get("arrayValues", ())
709
+ values = [value["value"] for value in array_values]
710
+ converted = [
711
+ _helpers.SCALAR_QUERY_PARAM_PARSER.to_py(
712
+ value, schema.SchemaField(name, array_type)
713
+ )
714
+ for value in values
715
+ ]
716
+ return cls(name, array_type, converted)
717
+
718
+ @classmethod
719
+ def from_api_repr(cls, resource: dict) -> "ArrayQueryParameter":
720
+ """Factory: construct parameter from JSON resource.
721
+
722
+ Args:
723
+ resource (Dict): JSON mapping of parameter
724
+
725
+ Returns:
726
+ google.cloud.bigquery.query.ArrayQueryParameter: Instance
727
+ """
728
+ array_type = resource["parameterType"]["arrayType"]["type"]
729
+ if array_type == "STRUCT":
730
+ return cls._from_api_repr_struct(resource)
731
+ return cls._from_api_repr_scalar(resource)
732
+
733
+ def to_api_repr(self) -> dict:
734
+ """Construct JSON API representation for the parameter.
735
+
736
+ Returns:
737
+ Dict: JSON mapping
738
+ """
739
+ values = self.values
740
+
741
+ if self.array_type in {"RECORD", "STRUCT"} or isinstance(
742
+ self.array_type, StructQueryParameterType
743
+ ):
744
+ reprs = [value.to_api_repr() for value in values]
745
+ a_values = [repr_["parameterValue"] for repr_ in reprs]
746
+
747
+ if reprs:
748
+ a_type = reprs[0]["parameterType"]
749
+ else:
750
+ # This assertion always evaluates to True because the
751
+ # constructor disallows STRUCT/RECORD type defined as a
752
+ # string with empty values.
753
+ assert isinstance(self.array_type, StructQueryParameterType)
754
+ a_type = self.array_type.to_api_repr()
755
+ else:
756
+ # Scalar array item type.
757
+ if isinstance(self.array_type, str):
758
+ a_type = {"type": self.array_type}
759
+ else:
760
+ a_type = self.array_type.to_api_repr()
761
+
762
+ converter = _SCALAR_VALUE_TO_JSON_PARAM.get(
763
+ a_type["type"], lambda value: value
764
+ )
765
+ values = [converter(value) for value in values] # type: ignore
766
+ a_values = [{"value": value} for value in values]
767
+
768
+ resource = {
769
+ "parameterType": {"type": "ARRAY", "arrayType": a_type},
770
+ "parameterValue": {"arrayValues": a_values},
771
+ }
772
+ if self.name is not None:
773
+ resource["name"] = self.name
774
+
775
+ return resource
776
+
777
+ def _key(self):
778
+ """A tuple key that uniquely describes this field.
779
+
780
+ Used to compute this instance's hashcode and evaluate equality.
781
+
782
+ Returns:
783
+ Tuple: The contents of this :class:`~google.cloud.bigquery.query.ArrayQueryParameter`.
784
+ """
785
+ if isinstance(self.array_type, str):
786
+ item_type = self.array_type
787
+ elif isinstance(self.array_type, ScalarQueryParameterType):
788
+ item_type = self.array_type._type
789
+ else:
790
+ item_type = "STRUCT"
791
+
792
+ return (self.name, item_type.upper(), self.values)
793
+
794
+ def __eq__(self, other):
795
+ if not isinstance(other, ArrayQueryParameter):
796
+ return NotImplemented
797
+ return self._key() == other._key()
798
+
799
+ def __ne__(self, other):
800
+ return not self == other
801
+
802
+ def __repr__(self):
803
+ return "ArrayQueryParameter{}".format(self._key())
804
+
805
+
806
+ class StructQueryParameter(_AbstractQueryParameter):
807
+ """Name / positional query parameters for struct values.
808
+
809
+ Args:
810
+ name (Optional[str]):
811
+ Parameter name, used via ``@foo`` syntax. If None, the
812
+ parameter can only be addressed via position (``?``).
813
+
814
+ sub_params (Union[Tuple[
815
+ google.cloud.bigquery.query.ScalarQueryParameter,
816
+ google.cloud.bigquery.query.ArrayQueryParameter,
817
+ google.cloud.bigquery.query.StructQueryParameter
818
+ ]]): The sub-parameters for the struct
819
+ """
820
+
821
+ def __init__(self, name, *sub_params) -> None:
822
+ self.name = name
823
+ self.struct_types: Dict[str, Any] = OrderedDict()
824
+ self.struct_values: Dict[str, Any] = {}
825
+
826
+ types = self.struct_types
827
+ values = self.struct_values
828
+ for sub in sub_params:
829
+ if isinstance(sub, self.__class__):
830
+ types[sub.name] = "STRUCT"
831
+ values[sub.name] = sub
832
+ elif isinstance(sub, ArrayQueryParameter):
833
+ types[sub.name] = "ARRAY"
834
+ values[sub.name] = sub
835
+ else:
836
+ types[sub.name] = sub.type_
837
+ values[sub.name] = sub.value
838
+
839
+ @classmethod
840
+ def positional(cls, *sub_params):
841
+ """Factory for positional parameters.
842
+
843
+ Args:
844
+ sub_params (Union[Tuple[
845
+ google.cloud.bigquery.query.ScalarQueryParameter,
846
+ google.cloud.bigquery.query.ArrayQueryParameter,
847
+ google.cloud.bigquery.query.StructQueryParameter
848
+ ]]): The sub-parameters for the struct
849
+
850
+ Returns:
851
+ google.cloud.bigquery.query.StructQueryParameter: Instance without name
852
+ """
853
+ return cls(None, *sub_params)
854
+
855
+ @classmethod
856
+ def from_api_repr(cls, resource: dict) -> "StructQueryParameter":
857
+ """Factory: construct parameter from JSON resource.
858
+
859
+ Args:
860
+ resource (Dict): JSON mapping of parameter
861
+
862
+ Returns:
863
+ google.cloud.bigquery.query.StructQueryParameter: Instance
864
+ """
865
+ # Import here to avoid circular imports.
866
+ from google.cloud.bigquery import schema
867
+
868
+ name = resource.get("name")
869
+ instance = cls(name)
870
+ type_resources = {}
871
+ types = instance.struct_types
872
+ for item in resource["parameterType"]["structTypes"]:
873
+ types[item["name"]] = item["type"]["type"]
874
+ type_resources[item["name"]] = item["type"]
875
+ struct_values = resource["parameterValue"]["structValues"]
876
+ for key, value in struct_values.items():
877
+ type_ = types[key]
878
+ converted: Optional[Union[ArrayQueryParameter, StructQueryParameter]] = None
879
+ if type_ == "STRUCT":
880
+ struct_resource = {
881
+ "name": key,
882
+ "parameterType": type_resources[key],
883
+ "parameterValue": value,
884
+ }
885
+ converted = StructQueryParameter.from_api_repr(struct_resource)
886
+ elif type_ == "ARRAY":
887
+ struct_resource = {
888
+ "name": key,
889
+ "parameterType": type_resources[key],
890
+ "parameterValue": value,
891
+ }
892
+ converted = ArrayQueryParameter.from_api_repr(struct_resource)
893
+ else:
894
+ value = value["value"]
895
+ converted = _helpers.SCALAR_QUERY_PARAM_PARSER.to_py(
896
+ value, schema.SchemaField(cast(str, name), type_)
897
+ )
898
+ instance.struct_values[key] = converted
899
+ return instance
900
+
901
+ def to_api_repr(self) -> dict:
902
+ """Construct JSON API representation for the parameter.
903
+
904
+ Returns:
905
+ Dict: JSON mapping
906
+ """
907
+ s_types = {}
908
+ values = {}
909
+ for name, value in self.struct_values.items():
910
+ type_ = self.struct_types[name]
911
+ if type_ in ("STRUCT", "ARRAY"):
912
+ repr_ = value.to_api_repr()
913
+ s_types[name] = {"name": name, "type": repr_["parameterType"]}
914
+ values[name] = repr_["parameterValue"]
915
+ else:
916
+ s_types[name] = {"name": name, "type": {"type": type_}}
917
+ converter = _SCALAR_VALUE_TO_JSON_PARAM.get(type_, lambda value: value)
918
+ values[name] = {"value": converter(value)}
919
+
920
+ resource = {
921
+ "parameterType": {
922
+ "type": "STRUCT",
923
+ "structTypes": [s_types[key] for key in self.struct_types],
924
+ },
925
+ "parameterValue": {"structValues": values},
926
+ }
927
+ if self.name is not None:
928
+ resource["name"] = self.name
929
+ return resource
930
+
931
+ def _key(self):
932
+ """A tuple key that uniquely describes this field.
933
+
934
+ Used to compute this instance's hashcode and evaluate equality.
935
+
936
+ Returns:
937
+ Tuple: The contents of this :class:`~google.cloud.bigquery.ArrayQueryParameter`.
938
+ """
939
+ return (self.name, self.struct_types, self.struct_values)
940
+
941
+ def __eq__(self, other):
942
+ if not isinstance(other, StructQueryParameter):
943
+ return NotImplemented
944
+ return self._key() == other._key()
945
+
946
+ def __ne__(self, other):
947
+ return not self == other
948
+
949
+ def __repr__(self):
950
+ return "StructQueryParameter{}".format(self._key())
951
+
952
+
953
+ class RangeQueryParameter(_AbstractQueryParameter):
954
+ """Named / positional query parameters for range values.
955
+
956
+ Args:
957
+ range_element_type (Union[str, RangeQueryParameterType]):
958
+ The type of range elements. It must be one of 'TIMESTAMP',
959
+ 'DATE', or 'DATETIME'.
960
+
961
+ start (Optional[Union[ScalarQueryParameter, str]]):
962
+ The start of the range value. Must be the same type as
963
+ range_element_type. If not provided, it's interpreted as UNBOUNDED.
964
+
965
+ end (Optional[Union[ScalarQueryParameter, str]]):
966
+ The end of the range value. Must be the same type as
967
+ range_element_type. If not provided, it's interpreted as UNBOUNDED.
968
+
969
+ name (Optional[str]):
970
+ Parameter name, used via ``@foo`` syntax. If None, the
971
+ parameter can only be addressed via position (``?``).
972
+ """
973
+
974
+ @classmethod
975
+ def _parse_range_element_type(self, range_element_type):
976
+ if isinstance(range_element_type, str):
977
+ if range_element_type not in _SUPPORTED_RANGE_ELEMENTS:
978
+ raise ValueError(
979
+ "If given as a string, range_element_type must be one of "
980
+ f"'TIMESTAMP', 'DATE', or 'DATETIME'. Got {range_element_type}."
981
+ )
982
+ return RangeQueryParameterType(range_element_type)
983
+ elif isinstance(range_element_type, RangeQueryParameterType):
984
+ if range_element_type.type_._type not in _SUPPORTED_RANGE_ELEMENTS:
985
+ raise ValueError(
986
+ "If given as a RangeQueryParameterType object, "
987
+ "range_element_type must be one of 'TIMESTAMP', 'DATE', "
988
+ "or 'DATETIME' type."
989
+ )
990
+ return range_element_type
991
+ else:
992
+ raise ValueError(
993
+ "range_element_type must be a string or "
994
+ "RangeQueryParameterType object, of 'TIMESTAMP', 'DATE', "
995
+ "or 'DATETIME' type. Got "
996
+ f"{type(range_element_type)}:{range_element_type}"
997
+ )
998
+
999
+ @classmethod
1000
+ def _serialize_range_element_value(self, value, type_):
1001
+ if value is None or isinstance(value, str):
1002
+ return value
1003
+ else:
1004
+ converter = _SCALAR_VALUE_TO_JSON_PARAM.get(type_)
1005
+ if converter is not None:
1006
+ return converter(value) # type: ignore
1007
+ else:
1008
+ raise ValueError(
1009
+ f"Cannot convert range element value from type {type_}, "
1010
+ "must be one of the strings 'TIMESTAMP', 'DATE' "
1011
+ "'DATETIME' or a RangeQueryParameterType object."
1012
+ )
1013
+
1014
+ def __init__(
1015
+ self,
1016
+ range_element_type,
1017
+ start=None,
1018
+ end=None,
1019
+ name=None,
1020
+ ):
1021
+ self.name = name
1022
+ self.range_element_type = self._parse_range_element_type(range_element_type)
1023
+ print(self.range_element_type.type_._type)
1024
+ self.start = start
1025
+ self.end = end
1026
+
1027
+ @classmethod
1028
+ def positional(
1029
+ cls, range_element_type, start=None, end=None
1030
+ ) -> "RangeQueryParameter":
1031
+ """Factory for positional parameters.
1032
+
1033
+ Args:
1034
+ range_element_type (Union[str, RangeQueryParameterType]):
1035
+ The type of range elements. It must be one of `'TIMESTAMP'`,
1036
+ `'DATE'`, or `'DATETIME'`.
1037
+
1038
+ start (Optional[Union[ScalarQueryParameter, str]]):
1039
+ The start of the range value. Must be the same type as
1040
+ range_element_type. If not provided, it's interpreted as
1041
+ UNBOUNDED.
1042
+
1043
+ end (Optional[Union[ScalarQueryParameter, str]]):
1044
+ The end of the range value. Must be the same type as
1045
+ range_element_type. If not provided, it's interpreted as
1046
+ UNBOUNDED.
1047
+
1048
+ Returns:
1049
+ google.cloud.bigquery.query.RangeQueryParameter: Instance without
1050
+ name.
1051
+ """
1052
+ return cls(range_element_type, start, end)
1053
+
1054
+ @classmethod
1055
+ def from_api_repr(cls, resource: dict) -> "RangeQueryParameter":
1056
+ """Factory: construct parameter from JSON resource.
1057
+
1058
+ Args:
1059
+ resource (Dict): JSON mapping of parameter
1060
+
1061
+ Returns:
1062
+ google.cloud.bigquery.query.RangeQueryParameter: Instance
1063
+ """
1064
+ name = resource.get("name")
1065
+ range_element_type = (
1066
+ resource.get("parameterType", {}).get("rangeElementType", {}).get("type")
1067
+ )
1068
+ range_value = resource.get("parameterValue", {}).get("rangeValue", {})
1069
+ start = range_value.get("start", {}).get("value")
1070
+ end = range_value.get("end", {}).get("value")
1071
+
1072
+ return cls(range_element_type, start=start, end=end, name=name)
1073
+
1074
+ def to_api_repr(self) -> dict:
1075
+ """Construct JSON API representation for the parameter.
1076
+
1077
+ Returns:
1078
+ Dict: JSON mapping
1079
+ """
1080
+ range_element_type = self.range_element_type.to_api_repr()
1081
+ type_ = self.range_element_type.type_._type
1082
+ start = self._serialize_range_element_value(self.start, type_)
1083
+ end = self._serialize_range_element_value(self.end, type_)
1084
+ resource = {
1085
+ "parameterType": range_element_type,
1086
+ "parameterValue": {
1087
+ "rangeValue": {
1088
+ "start": {"value": start},
1089
+ "end": {"value": end},
1090
+ },
1091
+ },
1092
+ }
1093
+
1094
+ # distinguish between name not provided vs. name being empty string
1095
+ if self.name is not None:
1096
+ resource["name"] = self.name
1097
+
1098
+ return resource
1099
+
1100
+ def _key(self):
1101
+ """A tuple key that uniquely describes this field.
1102
+
1103
+ Used to compute this instance's hashcode and evaluate equality.
1104
+
1105
+ Returns:
1106
+ Tuple: The contents of this
1107
+ :class:`~google.cloud.bigquery.query.RangeQueryParameter`.
1108
+ """
1109
+
1110
+ range_element_type = self.range_element_type.to_api_repr()
1111
+ return (self.name, range_element_type, self.start, self.end)
1112
+
1113
+ def __eq__(self, other):
1114
+ if not isinstance(other, RangeQueryParameter):
1115
+ return NotImplemented
1116
+ return self._key() == other._key()
1117
+
1118
+ def __ne__(self, other):
1119
+ return not self == other
1120
+
1121
+ def __repr__(self):
1122
+ return "RangeQueryParameter{}".format(self._key())
1123
+
1124
+
1125
+ class SqlParameterScalarTypes:
1126
+ """Supported scalar SQL query parameter types as type objects."""
1127
+
1128
+ BOOL = ScalarQueryParameterType("BOOL")
1129
+ BOOLEAN = ScalarQueryParameterType("BOOL")
1130
+ BIGDECIMAL = ScalarQueryParameterType("BIGNUMERIC")
1131
+ BIGNUMERIC = ScalarQueryParameterType("BIGNUMERIC")
1132
+ BYTES = ScalarQueryParameterType("BYTES")
1133
+ DATE = ScalarQueryParameterType("DATE")
1134
+ DATETIME = ScalarQueryParameterType("DATETIME")
1135
+ DECIMAL = ScalarQueryParameterType("NUMERIC")
1136
+ FLOAT = ScalarQueryParameterType("FLOAT64")
1137
+ FLOAT64 = ScalarQueryParameterType("FLOAT64")
1138
+ GEOGRAPHY = ScalarQueryParameterType("GEOGRAPHY")
1139
+ INT64 = ScalarQueryParameterType("INT64")
1140
+ INTEGER = ScalarQueryParameterType("INT64")
1141
+ NUMERIC = ScalarQueryParameterType("NUMERIC")
1142
+ STRING = ScalarQueryParameterType("STRING")
1143
+ TIME = ScalarQueryParameterType("TIME")
1144
+ TIMESTAMP = ScalarQueryParameterType("TIMESTAMP")
1145
+
1146
+
1147
+ class _QueryResults(object):
1148
+ """Results of a query.
1149
+
1150
+ See:
1151
+ https://g.co/cloud/bigquery/docs/reference/rest/v2/jobs/getQueryResults
1152
+ """
1153
+
1154
+ def __init__(self, properties):
1155
+ self._properties = {}
1156
+ self._set_properties(properties)
1157
+
1158
+ @classmethod
1159
+ def from_api_repr(cls, api_response):
1160
+ return cls(api_response)
1161
+
1162
+ @property
1163
+ def project(self):
1164
+ """Project bound to the query job.
1165
+
1166
+ Returns:
1167
+ str: The project that the query job is associated with.
1168
+ """
1169
+ return self._properties.get("jobReference", {}).get("projectId")
1170
+
1171
+ @property
1172
+ def cache_hit(self):
1173
+ """Query results served from cache.
1174
+
1175
+ See:
1176
+ https://cloud.google.com/bigquery/docs/reference/rest/v2/jobs/query#body.QueryResponse.FIELDS.cache_hit
1177
+
1178
+ Returns:
1179
+ Optional[bool]:
1180
+ True if the query results were served from cache (None
1181
+ until set by the server).
1182
+ """
1183
+ return self._properties.get("cacheHit")
1184
+
1185
+ @property
1186
+ def complete(self):
1187
+ """Server completed query.
1188
+
1189
+ See:
1190
+ https://cloud.google.com/bigquery/docs/reference/rest/v2/jobs/query#body.QueryResponse.FIELDS.job_complete
1191
+
1192
+ Returns:
1193
+ Optional[bool]:
1194
+ True if the query completed on the server (None
1195
+ until set by the server).
1196
+ """
1197
+ return self._properties.get("jobComplete")
1198
+
1199
+ @property
1200
+ def errors(self):
1201
+ """Errors generated by the query.
1202
+
1203
+ See:
1204
+ https://cloud.google.com/bigquery/docs/reference/rest/v2/jobs/query#body.QueryResponse.FIELDS.errors
1205
+
1206
+ Returns:
1207
+ Optional[List[Mapping]]:
1208
+ Mappings describing errors generated on the server (None
1209
+ until set by the server).
1210
+ """
1211
+ return self._properties.get("errors")
1212
+
1213
+ @property
1214
+ def job_id(self):
1215
+ """Job ID of the query job these results are from.
1216
+
1217
+ See:
1218
+ https://cloud.google.com/bigquery/docs/reference/rest/v2/jobs/query#body.QueryResponse.FIELDS.job_reference
1219
+
1220
+ Returns:
1221
+ str: Job ID of the query job.
1222
+ """
1223
+ return self._properties.get("jobReference", {}).get("jobId")
1224
+
1225
+ @property
1226
+ def location(self):
1227
+ """Location of the query job these results are from.
1228
+
1229
+ See:
1230
+ https://cloud.google.com/bigquery/docs/reference/rest/v2/jobs/query#body.QueryResponse.FIELDS.job_reference
1231
+
1232
+ Returns:
1233
+ str: Job ID of the query job.
1234
+ """
1235
+ return self._properties.get("jobReference", {}).get("location")
1236
+
1237
+ @property
1238
+ def query_id(self) -> Optional[str]:
1239
+ """[Preview] ID of a completed query.
1240
+
1241
+ This ID is auto-generated and not guaranteed to be populated.
1242
+ """
1243
+ return self._properties.get("queryId")
1244
+
1245
+ @property
1246
+ def page_token(self):
1247
+ """Token for fetching next bach of results.
1248
+
1249
+ See:
1250
+ https://cloud.google.com/bigquery/docs/reference/rest/v2/jobs/query#body.QueryResponse.FIELDS.page_token
1251
+
1252
+ Returns:
1253
+ Optional[str]: Token generated on the server (None until set by the server).
1254
+ """
1255
+ return self._properties.get("pageToken")
1256
+
1257
+ @property
1258
+ def total_rows(self):
1259
+ """Total number of rows returned by the query.
1260
+
1261
+ See:
1262
+ https://cloud.google.com/bigquery/docs/reference/rest/v2/jobs/query#body.QueryResponse.FIELDS.total_rows
1263
+
1264
+ Returns:
1265
+ Optional[int]: Count generated on the server (None until set by the server).
1266
+ """
1267
+ total_rows = self._properties.get("totalRows")
1268
+ if total_rows is not None:
1269
+ return int(total_rows)
1270
+
1271
+ @property
1272
+ def total_bytes_processed(self):
1273
+ """Total number of bytes processed by the query.
1274
+
1275
+ See:
1276
+ https://cloud.google.com/bigquery/docs/reference/rest/v2/jobs/query#body.QueryResponse.FIELDS.total_bytes_processed
1277
+
1278
+ Returns:
1279
+ Optional[int]: Count generated on the server (None until set by the server).
1280
+ """
1281
+ total_bytes_processed = self._properties.get("totalBytesProcessed")
1282
+ if total_bytes_processed is not None:
1283
+ return int(total_bytes_processed)
1284
+
1285
+ @property
1286
+ def num_dml_affected_rows(self):
1287
+ """Total number of rows affected by a DML query.
1288
+
1289
+ See:
1290
+ https://cloud.google.com/bigquery/docs/reference/rest/v2/jobs/query#body.QueryResponse.FIELDS.num_dml_affected_rows
1291
+
1292
+ Returns:
1293
+ Optional[int]: Count generated on the server (None until set by the server).
1294
+ """
1295
+ num_dml_affected_rows = self._properties.get("numDmlAffectedRows")
1296
+ if num_dml_affected_rows is not None:
1297
+ return int(num_dml_affected_rows)
1298
+
1299
+ @property
1300
+ def rows(self):
1301
+ """Query results.
1302
+
1303
+ See:
1304
+ https://cloud.google.com/bigquery/docs/reference/rest/v2/jobs/query#body.QueryResponse.FIELDS.rows
1305
+
1306
+ Returns:
1307
+ Optional[List[google.cloud.bigquery.table.Row]]:
1308
+ Rows containing the results of the query.
1309
+ """
1310
+ return _rows_from_json(self._properties.get("rows", ()), self.schema)
1311
+
1312
+ @property
1313
+ def schema(self):
1314
+ """Schema for query results.
1315
+
1316
+ See:
1317
+ https://cloud.google.com/bigquery/docs/reference/rest/v2/jobs/query#body.QueryResponse.FIELDS.schema
1318
+
1319
+ Returns:
1320
+ Optional[List[SchemaField]]:
1321
+ Fields describing the schema (None until set by the server).
1322
+ """
1323
+ return _parse_schema_resource(self._properties.get("schema", {}))
1324
+
1325
+ def _set_properties(self, api_response):
1326
+ """Update properties from resource in body of ``api_response``
1327
+
1328
+ Args:
1329
+ api_response (Dict): Response returned from an API call
1330
+ """
1331
+ self._properties.clear()
1332
+ self._properties.update(copy.deepcopy(api_response))
1333
+
1334
+
1335
+ def _query_param_from_api_repr(resource):
1336
+ """Helper: Construct concrete query parameter from JSON resource."""
1337
+ qp_type = resource["parameterType"]
1338
+ if "arrayType" in qp_type:
1339
+ klass = ArrayQueryParameter
1340
+ elif "structTypes" in qp_type:
1341
+ klass = StructQueryParameter
1342
+ else:
1343
+ klass = ScalarQueryParameter
1344
+ return klass.from_api_repr(resource)