diff --git a/bigquery/google/cloud/bigquery/job.py b/bigquery/google/cloud/bigquery/job.py index f582868f4730..663d77501694 100644 --- a/bigquery/google/cloud/bigquery/job.py +++ b/bigquery/google/cloud/bigquery/job.py @@ -28,7 +28,10 @@ from google.cloud.bigquery.table import Table from google.cloud.bigquery.table import _build_schema_resource from google.cloud.bigquery.table import _parse_schema_resource +from google.cloud.bigquery._helpers import ArrayQueryParameter from google.cloud.bigquery._helpers import QueryParametersProperty +from google.cloud.bigquery._helpers import ScalarQueryParameter +from google.cloud.bigquery._helpers import StructQueryParameter from google.cloud.bigquery._helpers import UDFResourcesProperty from google.cloud.bigquery._helpers import _EnumProperty from google.cloud.bigquery._helpers import _TypedProperty @@ -1416,6 +1419,36 @@ def referenced_tables(self): return tables + @property + def undeclared_query_paramters(self): + """Return undeclared query parameters from job statistics, if present. + + See: + https://cloud.google.com/bigquery/docs/reference/rest/v2/jobs#statistics.query.undeclaredQueryParamters + + :rtype: + list of + :class:`~google.cloud.bigquery._helpers.AbstractQueryParameter` + :returns: undeclared parameters, or an empty list if the query has + not yet completed. + """ + parameters = [] + undeclared = self._job_statistics().get('undeclaredQueryParamters', ()) + + for parameter in undeclared: + p_type = parameter['parameterType'] + + if 'arrayType' in p_type: + klass = ArrayQueryParameter + elif 'structTypes' in p_type: + klass = StructQueryParameter + else: + klass = ScalarQueryParameter + + parameters.append(klass.from_api_repr(parameter)) + + return parameters + def query_results(self): """Construct a QueryResults instance, bound to this job. diff --git a/bigquery/tests/unit/test_job.py b/bigquery/tests/unit/test_job.py index 379373e6ab7e..01745aa494c9 100644 --- a/bigquery/tests/unit/test_job.py +++ b/bigquery/tests/unit/test_job.py @@ -1845,6 +1845,81 @@ def test_referenced_tables(self): self.assertEqual(remote.project, 'other-project-123') self.assertIs(remote._dataset._client, client) + def test_undeclared_query_paramters(self): + from google.cloud.bigquery._helpers import ArrayQueryParameter + from google.cloud.bigquery._helpers import ScalarQueryParameter + from google.cloud.bigquery._helpers import StructQueryParameter + + undeclared = [{ + 'name': 'my_scalar', + 'parameterType': { + 'type': 'STRING', + }, + 'parameterValue': { + 'value': 'value', + }, + }, { + 'name': 'my_array', + 'parameterType': { + 'type': 'ARRAY', + 'arrayType': { + 'type': 'INT64', + }, + }, + 'parameterValue': { + 'arrayValues': [ + {'value': '1066'}, + {'value': '1745'}, + ], + }, + }, { + 'name': 'my_struct', + 'parameterType': { + 'type': 'STRUCT', + 'structTypes': [{ + 'name': 'count', + 'type': { + 'type': 'INT64', + } + }], + }, + 'parameterValue': { + 'structValues': { + 'count': { + 'value': '123', + }, + } + }, + }] + client = _Client(self.PROJECT) + job = self._make_one(self.JOB_NAME, self.QUERY, client) + self.assertEqual(job.undeclared_query_paramters, []) + + statistics = job._properties['statistics'] = {} + self.assertEqual(job.undeclared_query_paramters, []) + + query_stats = statistics['query'] = {} + self.assertEqual(job.undeclared_query_paramters, []) + + query_stats['undeclaredQueryParamters'] = undeclared + + scalar, array, struct = job.undeclared_query_paramters + + self.assertIsInstance(scalar, ScalarQueryParameter) + self.assertEqual(scalar.name, 'my_scalar') + self.assertEqual(scalar.type_, 'STRING') + self.assertEqual(scalar.value, 'value') + + self.assertIsInstance(array, ArrayQueryParameter) + self.assertEqual(array.name, 'my_array') + self.assertEqual(array.array_type, 'INT64') + self.assertEqual(array.values, [1066, 1745]) + + self.assertIsInstance(struct, StructQueryParameter) + self.assertEqual(struct.name, 'my_struct') + self.assertEqual(struct.struct_types, {'count': 'INT64'}) + self.assertEqual(struct.struct_values, {'count': 123}) + def test_query_results(self): from google.cloud.bigquery.query import QueryResults