Content-Length: 637723 | pFad | https://github.com/googleapis/python-bigquery/commit/f8572dd86595361bae82c3232b2c0d159690a7b7

A9 fix: adding property setter for table constraints, #1990 (#2092) · googleapis/python-bigquery@f8572dd · GitHub
Skip to content

Commit f8572dd

Browse files
fix: adding property setter for table constraints, #1990 (#2092)
* fix: adding property setter for table constraints, #1990 * fix: adding unit test for to_api_repr() method * fix: adding system test for bigquery table update * fix: adding more test case for table constraints property * fix: adding more test case for table constraints property * fix: linting code * fix: adding unit tests for test table, table constraint and foreign key * fix: linting based on noxfile * fix: linting based on noxfile * fix: adding unit tests and system test * fix: clearing lint error * fix: adding table constraint eq unit tests * fix: adding type to to_api_repr resource
1 parent fb7de39 commit f8572dd

File tree

3 files changed

+562
-2
lines changed

3 files changed

+562
-2
lines changed

google/cloud/bigquery/table.py

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1058,6 +1058,17 @@ def table_constraints(self) -> Optional["TableConstraints"]:
10581058
table_constraints = TableConstraints.from_api_repr(table_constraints)
10591059
return table_constraints
10601060

1061+
@table_constraints.setter
1062+
def table_constraints(self, value):
1063+
"""Tables Primary Key and Foreign Key information."""
1064+
api_repr = value
1065+
if not isinstance(value, TableConstraints) and value is not None:
1066+
raise ValueError(
1067+
"value must be google.cloud.bigquery.table.TableConstraints or None"
1068+
)
1069+
api_repr = value.to_api_repr() if value else None
1070+
self._properties[self._PROPERTY_TO_API_FIELD["table_constraints"]] = api_repr
1071+
10611072
@property
10621073
def resource_tags(self):
10631074
"""Dict[str, str]: Resource tags for the table.
@@ -1111,11 +1122,9 @@ def external_catalog_table_options(
11111122
def foreign_type_info(self) -> Optional[_schema.ForeignTypeInfo]:
11121123
"""Optional. Specifies metadata of the foreign data type definition in
11131124
field schema (TableFieldSchema.foreign_type_definition).
1114-
11151125
Returns:
11161126
Optional[schema.ForeignTypeInfo]:
11171127
Foreign type information, or :data:`None` if not set.
1118-
11191128
.. Note::
11201129
foreign_type_info is only required if you are referencing an
11211130
external catalog such as a Hive table.
@@ -3404,6 +3413,20 @@ def from_api_repr(cls, api_repr: Dict[str, Any]) -> "ForeignKey":
34043413
],
34053414
)
34063415

3416+
def to_api_repr(self) -> Dict[str, Any]:
3417+
"""Return a dictionary representing this object."""
3418+
return {
3419+
"name": self.name,
3420+
"referencedTable": self.referenced_table.to_api_repr(),
3421+
"columnReferences": [
3422+
{
3423+
"referencingColumn": column_reference.referencing_column,
3424+
"referencedColumn": column_reference.referenced_column,
3425+
}
3426+
for column_reference in self.column_references
3427+
],
3428+
}
3429+
34073430

34083431
class TableConstraints:
34093432
"""The TableConstraints defines the primary key and foreign key.
@@ -3425,6 +3448,13 @@ def __init__(
34253448
self.primary_key = primary_key
34263449
self.foreign_keys = foreign_keys
34273450

3451+
def __eq__(self, other):
3452+
if not isinstance(other, TableConstraints) and other is not None:
3453+
raise TypeError("The value provided is not a BigQuery TableConstraints.")
3454+
return (
3455+
self.primary_key == other.primary_key if other.primary_key else None
3456+
) and (self.foreign_keys == other.foreign_keys if other.foreign_keys else None)
3457+
34283458
@classmethod
34293459
def from_api_repr(cls, resource: Dict[str, Any]) -> "TableConstraints":
34303460
"""Create an instance from API representation."""
@@ -3440,6 +3470,17 @@ def from_api_repr(cls, resource: Dict[str, Any]) -> "TableConstraints":
34403470
]
34413471
return cls(primary_key, foreign_keys)
34423472

3473+
def to_api_repr(self) -> Dict[str, Any]:
3474+
"""Return a dictionary representing this object."""
3475+
resource: Dict[str, Any] = {}
3476+
if self.primary_key:
3477+
resource["primaryKey"] = {"columns": self.primary_key.columns}
3478+
if self.foreign_keys:
3479+
resource["foreignKeys"] = [
3480+
foreign_key.to_api_repr() for foreign_key in self.foreign_keys
3481+
]
3482+
return resource
3483+
34433484

34443485
def _item_to_row(iterator, resource):
34453486
"""Convert a JSON row to the native object.

tests/system/test_client.py

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,10 @@
9797
],
9898
),
9999
]
100+
TABLE_CONSTRAINTS_SCHEMA = [
101+
bigquery.SchemaField("id", "INTEGER", mode="REQUIRED"),
102+
bigquery.SchemaField("fk_id", "STRING", mode="REQUIRED"),
103+
]
100104

101105
SOURCE_URIS_AVRO = [
102106
"gs://cloud-samples-data/bigquery/federated-formats-reference-file-schema/a-twitter.avro",
@@ -901,6 +905,79 @@ def test_update_table_clustering_configuration(self):
901905
table3 = Config.CLIENT.update_table(table2, ["clustering_fields"])
902906
self.assertIsNone(table3.clustering_fields, None)
903907

908+
def test_update_table_constraints(self):
909+
from google.cloud.bigquery.table import TableConstraints
910+
from google.cloud.bigquery.table import (
911+
PrimaryKey,
912+
ForeignKey,
913+
TableReference,
914+
ColumnReference,
915+
)
916+
917+
dataset = self.temp_dataset(_make_dataset_id("update_table"))
918+
919+
TABLE_NAME = "test_table"
920+
table_arg = Table(dataset.table(TABLE_NAME), schema=TABLE_CONSTRAINTS_SCHEMA)
921+
self.assertFalse(_table_exists(table_arg))
922+
923+
table = helpers.retry_403(Config.CLIENT.create_table)(table_arg)
924+
self.to_delete.insert(0, table)
925+
self.assertTrue(_table_exists(table))
926+
927+
REFERENCE_TABLE_NAME = "test_table2"
928+
reference_table_arg = Table(
929+
dataset.table(REFERENCE_TABLE_NAME),
930+
schema=[
931+
bigquery.SchemaField("id", "INTEGER", mode="REQUIRED"),
932+
],
933+
)
934+
reference_table = helpers.retry_403(Config.CLIENT.create_table)(
935+
reference_table_arg
936+
)
937+
self.to_delete.insert(0, reference_table)
938+
self.assertTrue(_table_exists(reference_table))
939+
940+
reference_table.table_constraints = TableConstraints(
941+
primary_key=PrimaryKey(columns=["id"]), foreign_keys=None
942+
)
943+
reference_table2 = Config.CLIENT.update_table(
944+
reference_table, ["table_constraints"]
945+
)
946+
self.assertEqual(
947+
reference_table2.table_constraints.primary_key,
948+
reference_table.table_constraints.primary_key,
949+
)
950+
951+
table_constraints = TableConstraints(
952+
primary_key=PrimaryKey(columns=["id"]),
953+
foreign_keys=[
954+
ForeignKey(
955+
name="fk_id",
956+
referenced_table=TableReference(dataset, "test_table2"),
957+
column_references=[
958+
ColumnReference(referencing_column="id", referenced_column="id")
959+
],
960+
),
961+
],
962+
)
963+
964+
table.table_constraints = table_constraints
965+
table2 = Config.CLIENT.update_table(table, ["table_constraints"])
966+
self.assertEqual(
967+
table2.table_constraints,
968+
table_constraints,
969+
)
970+
971+
table2.table_constraints = None
972+
table3 = Config.CLIENT.update_table(table2, ["table_constraints"])
973+
self.assertIsNone(table3.table_constraints, None)
974+
975+
reference_table2.table_constraints = None
976+
reference_table3 = Config.CLIENT.update_table(
977+
reference_table2, ["table_constraints"]
978+
)
979+
self.assertIsNone(reference_table3.table_constraints, None)
980+
904981
@staticmethod
905982
def _fetch_single_page(table, selected_fields=None):
906983
iterator = Config.CLIENT.list_rows(table, selected_fields=selected_fields)

0 commit comments

Comments
 (0)








ApplySandwichStrip

pFad - (p)hone/(F)rame/(a)nonymizer/(d)eclutterfier!      Saves Data!


--- a PPN by Garber Painting Akron. With Image Size Reduction included!

Fetched URL: https://github.com/googleapis/python-bigquery/commit/f8572dd86595361bae82c3232b2c0d159690a7b7

Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy