Repository: googleapis/google-cloud-python

Issue:
BigQuery: query_parameters fails if empty array is bound as parameter
OS Type & Version: Ubuntu 18.10 x64
Python version: Python 3.7.1
Packges: latest up to this date:
```
(...)
google-cloud-bigquery==1.9.0
(...)
```

#### Steps to reproduce

  1. Create a query, bind empty array as parameter
  2. Execute it
  3. Call query_parameters

#### Code example

```
from google.cloud import bigquery

client = bigquery.Client()
job = client.query(
    "SELECT ARRAY_LENGTH(@empty_array)",
    job_config=bigquery.QueryJobConfig(
        query_parameters=[
            bigquery.ArrayQueryParameter('empty_array', 'INT64', [])
        ]
    )
)
result = list(job.result())
query_parameters = job.query_parameters
```

#### Stack trace
```
Traceback (most recent call last):
  File "test.py", line 13, in <module>
    query_parameters = job.query_parameters()
  File "python-bigquery-bug/venv/lib/python3.7/site-packages/google/cloud/bigquery/job.py", line 2373, in query_parameters
    return self._configuration.query_parameters
  File "python-bigquery-bug/venv/lib/python3.7/site-packages/google/cloud/bigquery/job.py", line 2115, in query_parameters
    return _from_api_repr_query_parameters(prop)
  File "python-bigquery-bug/venv/lib/python3.7/site-packages/google/cloud/bigquery/job.py", line 1908, in _from_api_repr_query_parameters
    return [_query_param_from_api_repr(mapping) for mapping in resource]
  File "python-bigquery-bug/venv/lib/python3.7/site-packages/google/cloud/bigquery/job.py", line 1908, in <listcomp>
    return [_query_param_from_api_repr(mapping) for mapping in resource]
  File "python-bigquery-bug/venv/lib/python3.7/site-packages/google/cloud/bigquery/query.py", line 623, in _query_param_from_api_repr
    return klass.from_api_repr(resource)
  File "python-bigquery-bug/venv/lib/python3.7/site-packages/google/cloud/bigquery/query.py", line 252, in from_api_repr
    return cls._from_api_repr_scalar(resource)
  File "python-bigquery-bug/venv/lib/python3.7/site-packages/google/cloud/bigquery/query.py", line 233, in _from_api_repr_scalar
    values = [value["value"] for value in resource["parameterValue"]["arrayValues"]]
KeyError: 'parameterValue'
```

`from_api_repr` in ArrayQueryParameter is called with resource = `{'name': 'empty_array', 'parameterType': {'arrayType': {'type': 'INT64'}, 'type': 'ARRAY'}}`
For empty array this value does not contain `parameterValue` which leads to KeyError


Discussion:
@peku33 Thank you for the report!

Resolving patch:
diff --git a/bigquery/google/cloud/bigquery/query.py b/bigquery/google/cloud/bigquery/query.py
--- a/bigquery/google/cloud/bigquery/query.py
+++ b/bigquery/google/cloud/bigquery/query.py
@@ -230,7 +230,9 @@ def _from_api_repr_struct(cls, resource):
     def _from_api_repr_scalar(cls, resource):
         name = resource.get("name")
         array_type = resource["parameterType"]["arrayType"]["type"]
-        values = [value["value"] for value in resource["parameterValue"]["arrayValues"]]
+        parameter_value = resource.get("parameterValue", {})
+        array_values = parameter_value.get("arrayValues", ())
+        values = [value["value"] for value in array_values]
         converted = [
             _QUERY_PARAMS_FROM_JSON[array_type](value, None) for value in values
         ]


Test patch:
diff --git a/bigquery/tests/unit/test_query.py b/bigquery/tests/unit/test_query.py
--- a/bigquery/tests/unit/test_query.py
+++ b/bigquery/tests/unit/test_query.py
@@ -362,6 +362,18 @@ def test_from_api_repr_wo_name(self):
         self.assertEqual(param.array_type, "INT64")
         self.assertEqual(param.values, [1, 2])
 
+    def test_from_api_repr_wo_values(self):
+        # Back-end may not send back values for empty array params. See #7309
+        RESOURCE = {
+            "name": "foo",
+            "parameterType": {"type": "ARRAY", "arrayType": {"type": "INT64"}},
+        }
+        klass = self._get_target_class()
+        param = klass.from_api_repr(RESOURCE)
+        self.assertEqual(param.name, "foo")
+        self.assertEqual(param.array_type, "INT64")
+        self.assertEqual(param.values, [])
+
     def test_from_api_repr_w_struct_type(self):
         from google.cloud.bigquery.query import StructQueryParameter