Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add support for Dataset.isCaseInsensitive #1671

Merged
20 changes: 20 additions & 0 deletions google/cloud/bigquery/dataset.py
Original file line number Diff line number Diff line change
Expand Up @@ -527,6 +527,7 @@ class Dataset(object):
"default_table_expiration_ms": "defaultTableExpirationMs",
"friendly_name": "friendlyName",
"default_encryption_configuration": "defaultEncryptionConfiguration",
"is_case_insensitive": "isCaseInsensitive",
"storage_billing_model": "storageBillingModel",
}

Expand Down Expand Up @@ -764,6 +765,25 @@ def default_encryption_configuration(self, value):
api_repr = value.to_api_repr()
self._properties["defaultEncryptionConfiguration"] = api_repr

@property
def is_case_insensitive(self):
"""Optional[bool]: TRUE if the dataset and its table names are case-insensitive, otherwise FALSE.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: use True and False, following Python convention

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed to True and False

By default, this is FALSE, which means the dataset and its table names are case-sensitive.
This field does not affect routine references.

Raises:
ValueError: for invalid value types.
"""
return self._properties.get("isCaseInsensitive") or False

@is_case_insensitive.setter
def is_case_insensitive(self, value):
if not isinstance(value, bool) and value is not None:
raise ValueError("Pass a boolean value, or None")
if value is None:
value = False
self._properties["isCaseInsensitive"] = value

@property
def storage_billing_model(self):
"""Union[str, None]: StorageBillingModel of the dataset as set by the user
Expand Down
60 changes: 58 additions & 2 deletions tests/system/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,17 @@ def test_create_dataset(self):
self.assertTrue(_dataset_exists(dataset))
self.assertEqual(dataset.dataset_id, DATASET_ID)
self.assertEqual(dataset.project, Config.CLIENT.project)
self.assertIs(dataset.is_case_insensitive, False)

def test_create_dataset_case_sensitive(self):
DATASET_ID = _make_dataset_id("create_cs_dataset")
dataset = self.temp_dataset(DATASET_ID, is_case_insensitive=False)
self.assertIs(dataset.is_case_insensitive, False)

def test_create_dataset_case_insensitive(self):
DATASET_ID = _make_dataset_id("create_ci_dataset")
dataset = self.temp_dataset(DATASET_ID, is_case_insensitive=True)
self.assertIs(dataset.is_case_insensitive, True)

def test_get_dataset(self):
dataset_id = _make_dataset_id("get_dataset")
Expand Down Expand Up @@ -271,16 +282,19 @@ def test_update_dataset(self):
self.assertIsNone(dataset.friendly_name)
self.assertIsNone(dataset.description)
self.assertEqual(dataset.labels, {})
self.assertIs(dataset.is_case_insensitive, False)

dataset.friendly_name = "Friendly"
dataset.description = "Description"
dataset.labels = {"priority": "high", "color": "blue"}
dataset.is_case_insensitive = True
ds2 = Config.CLIENT.update_dataset(
dataset, ("friendly_name", "description", "labels")
dataset, ("friendly_name", "description", "labels", "is_case_insensitive")
)
self.assertEqual(ds2.friendly_name, "Friendly")
self.assertEqual(ds2.description, "Description")
self.assertEqual(ds2.labels, {"priority": "high", "color": "blue"})
self.assertIs(ds2.is_case_insensitive, True)

ds2.labels = {
"color": "green", # change
Expand Down Expand Up @@ -335,6 +349,46 @@ def test_create_table(self):
self.assertTrue(_table_exists(table))
self.assertEqual(table.table_id, table_id)

def test_create_tables_in_case_insensitive_dataset(self):
ci_dataset = self.temp_dataset(
_make_dataset_id("create_table"), is_case_insensitive=True
)
table_arg = Table(ci_dataset.table("test_table2"), schema=SCHEMA)
tablemc_arg = Table(ci_dataset.table("Test_taBLe2"))

table = helpers.retry_403(Config.CLIENT.create_table)(table_arg)
self.to_delete.insert(0, table)

self.assertTrue(_table_exists(table_arg))
self.assertTrue(_table_exists(tablemc_arg))
self.assertIs(ci_dataset.is_case_insensitive, True)

def test_create_tables_in_case_sensitive_dataset(self):
ci_dataset = self.temp_dataset(
_make_dataset_id("create_table"), is_case_insensitive=False
)
table_arg = Table(ci_dataset.table("test_table3"), schema=SCHEMA)
tablemc_arg = Table(ci_dataset.table("Test_taBLe3"))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

another nit: what does mc stand for in the variable tablemc_arg? Could we use something easier to understand?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mc = mixed case; added a comment about that


table = helpers.retry_403(Config.CLIENT.create_table)(table_arg)
self.to_delete.insert(0, table)

self.assertTrue(_table_exists(table_arg))
self.assertFalse(_table_exists(tablemc_arg))
self.assertIs(ci_dataset.is_case_insensitive, False)

def test_create_tables_in_default_sensitivity_dataset(self):
dataset = self.temp_dataset(_make_dataset_id("create_table"))
table_arg = Table(dataset.table("test_table4"), schema=SCHEMA)
tablemc_arg = Table(dataset.table("Test_taBLe4"))

table = helpers.retry_403(Config.CLIENT.create_table)(table_arg)
self.to_delete.insert(0, table)

self.assertTrue(_table_exists(table_arg))
self.assertFalse(_table_exists(tablemc_arg))
self.assertIs(dataset.is_case_insensitive, False)

def test_create_table_with_real_custom_policy(self):
from google.cloud.bigquery.schema import PolicyTagList

Expand Down Expand Up @@ -2286,12 +2340,14 @@ def test_nested_table_to_arrow(self):
self.assertTrue(pyarrow.types.is_list(record_col[1].type))
self.assertTrue(pyarrow.types.is_int64(record_col[1].type.value_type))

def temp_dataset(self, dataset_id, location=None):
def temp_dataset(self, dataset_id, location=None, is_case_insensitive=None):
project = Config.CLIENT.project
dataset_ref = bigquery.DatasetReference(project, dataset_id)
dataset = Dataset(dataset_ref)
if location:
dataset.location = location
if is_case_insensitive is not None:
dataset.is_case_insensitive = is_case_insensitive
dataset = helpers.retry_403(Config.CLIENT.create_dataset)(dataset)
self.to_delete.append(dataset)
return dataset
Expand Down