From 79cb9246db3d6cfc01ecfcdbd0d3ce11402486b7 Mon Sep 17 00:00:00 2001 From: larkee Date: Tue, 23 Mar 2021 09:58:33 +1100 Subject: [PATCH 1/3] test: add test for string array with pending null --- tests/unit/test_streamed.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/unit/test_streamed.py b/tests/unit/test_streamed.py index 63f3bf81fe..a96595ccae 100644 --- a/tests/unit/test_streamed.py +++ b/tests/unit/test_streamed.py @@ -360,6 +360,20 @@ def test__merge_chunk_array_of_string_with_null(self): self.assertEqual(merged, expected) self.assertIsNone(streamed._pending_chunk) + def test__merge_chunk_array_of_string_with_null_pending(self): + from google.cloud.spanner_v1 import TypeCode + + iterator = _MockCancellableIterator() + streamed = self._make_one(iterator) + FIELDS = [self._make_array_field("name", element_type_code=TypeCode.STRING)] + streamed._metadata = self._make_result_set_metadata(FIELDS) + streamed._pending_chunk = self._make_list_value([u"A", u"B", u"C", None]) + chunk = self._make_list_value([u"D", u"E"]) + merged = streamed._merge_chunk(chunk) + expected = self._make_list_value([u"A", u"B", u"C", None, u"D", u"E"]) + self.assertEqual(merged, expected) + self.assertIsNone(streamed._pending_chunk) + def test__merge_chunk_array_of_array_of_int(self): from google.cloud.spanner_v1 import StructType from google.cloud.spanner_v1 import Type From c36479364a4c922a34569bf1d4cb7aefec39217b Mon Sep 17 00:00:00 2001 From: larkee Date: Tue, 23 Mar 2021 10:06:21 +1100 Subject: [PATCH 2/3] fix: avoid consuming pending null values when merging --- google/cloud/spanner_v1/streamed.py | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/google/cloud/spanner_v1/streamed.py b/google/cloud/spanner_v1/streamed.py index 88677f668b..a1a30d8094 100644 --- a/google/cloud/spanner_v1/streamed.py +++ b/google/cloud/spanner_v1/streamed.py @@ -258,13 +258,17 @@ def _merge_array(lhs, rhs, type_): lhs.append(first) else: last = lhs.pop() - try: - merged = _merge_by_type(last, first, element_type) - except Unmergeable: + if last.HasField("null_value"): lhs.append(last) lhs.append(first) else: - lhs.append(merged) + try: + merged = _merge_by_type(last, first, element_type) + except Unmergeable: + lhs.append(last) + lhs.append(first) + else: + lhs.append(merged) return Value(list_value=ListValue(values=(lhs + rhs))) @@ -284,13 +288,17 @@ def _merge_struct(lhs, rhs, type_): lhs.append(first) else: last = lhs.pop() - try: - merged = _merge_by_type(last, first, candidate_type) - except Unmergeable: + if last.HasField("null_value"): lhs.append(last) lhs.append(first) else: - lhs.append(merged) + try: + merged = _merge_by_type(last, first, candidate_type) + except Unmergeable: + lhs.append(last) + lhs.append(first) + else: + lhs.append(merged) return Value(list_value=ListValue(values=lhs + rhs)) From cefe8888e6c599c4d02529bead6effdcc4d4a651 Mon Sep 17 00:00:00 2001 From: larkee Date: Tue, 23 Mar 2021 10:09:36 +1100 Subject: [PATCH 3/3] test: match implementation to test names --- tests/unit/test_streamed.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/unit/test_streamed.py b/tests/unit/test_streamed.py index a96595ccae..7b12f6a94b 100644 --- a/tests/unit/test_streamed.py +++ b/tests/unit/test_streamed.py @@ -336,11 +336,11 @@ def test__merge_chunk_array_of_string(self): FIELDS = [self._make_array_field("name", element_type_code=TypeCode.STRING)] streamed._metadata = self._make_result_set_metadata(FIELDS) streamed._pending_chunk = self._make_list_value([u"A", u"B", u"C"]) - chunk = self._make_list_value([None, u"D", u"E"]) + chunk = self._make_list_value([u"D", u"E"]) merged = streamed._merge_chunk(chunk) - expected = self._make_list_value([u"A", u"B", u"C", None, u"D", u"E"]) + expected = self._make_list_value([u"A", u"B", u"CD", u"E"]) self.assertEqual(merged, expected) self.assertIsNone(streamed._pending_chunk) @@ -352,11 +352,11 @@ def test__merge_chunk_array_of_string_with_null(self): FIELDS = [self._make_array_field("name", element_type_code=TypeCode.STRING)] streamed._metadata = self._make_result_set_metadata(FIELDS) streamed._pending_chunk = self._make_list_value([u"A", u"B", u"C"]) - chunk = self._make_list_value([u"D", u"E"]) + chunk = self._make_list_value([None, u"D", u"E"]) merged = streamed._merge_chunk(chunk) - expected = self._make_list_value([u"A", u"B", u"CD", u"E"]) + expected = self._make_list_value([u"A", u"B", u"C", None, u"D", u"E"]) self.assertEqual(merged, expected) self.assertIsNone(streamed._pending_chunk)