Repository: googleapis/python-bigquery

Issue:
Add require_partition_filter in bigquery.external_config.HivePartitioningOptions
I want to force partition filters when user run queries on external tables that uses HivePartitioning.

Please add property require_partition_filter within bigquery.external_config.HivePartitioningOptions()

I tried using table.require_partition_filter = True, but I get an error when my table contains hive_partitioning within external_data_configuration:


> google.api_core.exceptions.BadRequest: 400 POST require_partition_filter has been set for a hive-partitioned table without using the HivePartitioningOptions. To configure external, hive-partitioned tables -- including setting require_partition_filter -- please use the HivePartitioningOptions. Setting require_partition_filter on the top-level table definition, or via the TimePartitioning field, does not configure hive-partitioned tables.


Discussion:

Patch:
diff --git a/google/cloud/bigquery/external_config.py b/google/cloud/bigquery/external_config.py
index d702d9d8..112dfdba 100644
--- a/google/cloud/bigquery/external_config.py
+++ b/google/cloud/bigquery/external_config.py
@@ -586,6 +586,21 @@ class HivePartitioningOptions(object):
     def source_uri_prefix(self, value):
         self._properties["sourceUriPrefix"] = value
 
+    @property
+    def require_partition_filter(self):
+        """Optional[bool]: If set to true, queries over the partitioned table require a
+        partition filter that can be used for partition elimination to be
+        specified.
+
+        See
+        https://cloud.google.com/bigquery/docs/reference/rest/v2/tables#HivePartitioningOptions.FIELDS.mode
+        """
+        return self._properties.get("requirePartitionFilter")
+
+    @require_partition_filter.setter
+    def require_partition_filter(self, value):
+        self._properties["requirePartitionFilter"] = value
+
     def to_api_repr(self):
         """Build an API representation of this object.
 


Test patch:
diff --git a/tests/unit/test_external_config.py b/tests/unit/test_external_config.py
index 6028d069..4b6ef511 100644
--- a/tests/unit/test_external_config.py
+++ b/tests/unit/test_external_config.py
@@ -181,6 +181,7 @@ class TestExternalConfig(unittest.TestCase):
                 "hivePartitioningOptions": {
                     "sourceUriPrefix": "http://foo/bar",
                     "mode": "STRINGS",
+                    "requirePartitionFilter": True,
                 },
             },
         )
@@ -194,6 +195,7 @@ class TestExternalConfig(unittest.TestCase):
         )
         self.assertEqual(ec.hive_partitioning.source_uri_prefix, "http://foo/bar")
         self.assertEqual(ec.hive_partitioning.mode, "STRINGS")
+        self.assertEqual(ec.hive_partitioning.require_partition_filter, True)
 
         # converting back to API representation should yield the same result
         got_resource = ec.to_api_repr()
@@ -210,6 +212,7 @@ class TestExternalConfig(unittest.TestCase):
         hive_partitioning = external_config.HivePartitioningOptions()
         hive_partitioning.source_uri_prefix = "http://foo/bar"
         hive_partitioning.mode = "STRINGS"
+        hive_partitioning.require_partition_filter = False
 
         ec = external_config.ExternalConfig("FORMAT_FOO")
         ec.hive_partitioning = hive_partitioning
@@ -221,6 +224,7 @@ class TestExternalConfig(unittest.TestCase):
             "hivePartitioningOptions": {
                 "sourceUriPrefix": "http://foo/bar",
                 "mode": "STRINGS",
+                "requirePartitionFilter": False,
             },
         }
         self.assertEqual(got_resource, expected_resource)