Skip to content

Commit

Permalink
fix(bigquery): fix inserting missing repeated fields (#10196)
Browse files Browse the repository at this point in the history
* fix(bigquery): do not insert missing fields as explicit None

* Omit all None values from JSON request body

* Add an extra test for all missing row values

* Flatten a block of code a bit
  • Loading branch information
plamut authored Jan 31, 2020
1 parent 77dd923 commit f0bcbd6
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 16 deletions.
11 changes: 6 additions & 5 deletions bigquery/google/cloud/bigquery/_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -424,11 +424,12 @@ def _record_field_to_json(fields, row_value):

for subindex, subfield in enumerate(fields):
subname = subfield.name
if isdict:
subvalue = row_value.get(subname)
else:
subvalue = row_value[subindex]
record[subname] = _field_to_json(subfield, subvalue)
subvalue = row_value.get(subname) if isdict else row_value[subindex]

# None values are unconditionally omitted
if subvalue is not None:
record[subname] = _field_to_json(subfield, subvalue)

return record


Expand Down
29 changes: 27 additions & 2 deletions bigquery/tests/unit/test__helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -856,14 +856,39 @@ def test_w_non_empty_dict(self):
converted = self._call_fut(fields, original)
self.assertEqual(converted, {"one": "42", "two": "two"})

def test_w_missing_nullable(self):
def test_w_some_missing_nullables(self):
fields = [
_make_field("INT64", name="one", mode="NULLABLE"),
_make_field("STRING", name="two", mode="NULLABLE"),
]
original = {"one": 42}
converted = self._call_fut(fields, original)
self.assertEqual(converted, {"one": "42", "two": None})

# missing fields should not be converted to an explicit None
self.assertEqual(converted, {"one": "42"})

def test_w_all_missing_nullables(self):
fields = [
_make_field("INT64", name="one", mode="NULLABLE"),
_make_field("STRING", name="two", mode="NULLABLE"),
]
original = {}
converted = self._call_fut(fields, original)

# we should get an empty dict, not None
self.assertEqual(converted, {})

def test_w_explicit_none_value(self):
fields = [
_make_field("INT64", name="one", mode="NULLABLE"),
_make_field("STRING", name="two", mode="NULLABLE"),
_make_field("BOOL", name="three", mode="REPEATED"),
]
original = {"three": None, "one": 42, "two": None}
converted = self._call_fut(fields, original)

# None values should be dropped regardless of the field type
self.assertEqual(converted, {"one": "42"})


class Test_field_to_json(unittest.TestCase):
Expand Down
20 changes: 11 additions & 9 deletions bigquery/tests/unit/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -4668,10 +4668,13 @@ def test_insert_rows_w_schema(self):
]

def _row_data(row):
result = {"full_name": row[0], "age": str(row[1])}
joined = row[2]
if isinstance(row[2], datetime.datetime):
if isinstance(joined, datetime.datetime):
joined = _microseconds_from_datetime(joined) * 1e-6
return {"full_name": row[0], "age": str(row[1]), "joined": joined}
if joined is not None:
result["joined"] = joined
return result

SENT = {
"rows": [
Expand Down Expand Up @@ -4740,7 +4743,10 @@ def test_insert_rows_w_list_of_dictionaries(self):

def _row_data(row):
joined = row["joined"]
if isinstance(joined, datetime.datetime):
if joined is None:
row = copy.deepcopy(row)
del row["joined"]
elif isinstance(joined, datetime.datetime):
row["joined"] = _microseconds_from_datetime(joined) * 1e-6
row["age"] = str(row["age"])
return row
Expand Down Expand Up @@ -4959,9 +4965,8 @@ def test_insert_rows_w_repeated_fields(self):
},
{
"json": {
"color": None,
"items": [],
"structs": [{"score": None, "times": [], "distances": [3.5]}],
"structs": [{"times": [], "distances": [3.5]}],
},
"insertId": "1",
},
Expand Down Expand Up @@ -5028,10 +5033,7 @@ def test_insert_rows_w_record_schema(self):
},
"insertId": "1",
},
{
"json": {"full_name": "Wylma Phlyntstone", "phone": None},
"insertId": "2",
},
{"json": {"full_name": "Wylma Phlyntstone"}, "insertId": "2"},
]
}

Expand Down

0 comments on commit f0bcbd6

Please sign in to comment.