Skip to content

Commit 37b1a38

Browse files
committed
Merge pull request #1492 from dhermes/bigtable-row-response-parsing
Adding Bigtable RowResponse parsing helpers.
2 parents d332809 + 4487827 commit 37b1a38

2 files changed

Lines changed: 150 additions & 0 deletions

File tree

gcloud/bigtable/row_data.py

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,67 @@ def clear(self):
147147
self._chunks_encountered = False
148148
self._cells.clear()
149149

150+
def _handle_commit_row(self, chunk, index, last_chunk_index):
151+
"""Handles a ``commit_row`` chunk.
152+
153+
:type chunk: ``ReadRowsResponse.Chunk``
154+
:param chunk: The chunk being handled.
155+
156+
:type index: int
157+
:param index: The current index of the chunk.
158+
159+
:type last_chunk_index: int
160+
:param last_chunk_index: The index of the last chunk.
161+
162+
:raises: :class:`ValueError <exceptions.ValueError>` if the value of
163+
``commit_row`` is :data:`False` or if the chunk passed is not
164+
the last chunk in a response.
165+
"""
166+
# NOTE: We assume the caller has checked that the ``ONEOF`` property
167+
# for ``chunk`` is ``commit_row``.
168+
if not chunk.commit_row:
169+
raise ValueError('Received commit_row that was False.')
170+
171+
if index != last_chunk_index:
172+
raise ValueError('Commit row chunk was not the last chunk')
173+
else:
174+
self._committed = True
175+
176+
def _handle_reset_row(self, chunk):
177+
"""Handles a ``reset_row`` chunk.
178+
179+
:type chunk: ``ReadRowsResponse.Chunk``
180+
:param chunk: The chunk being handled.
181+
182+
:raises: :class:`ValueError <exceptions.ValueError>` if the value of
183+
``reset_row`` is :data:`False`
184+
"""
185+
# NOTE: We assume the caller has checked that the ``ONEOF`` property
186+
# for ``chunk`` is ``reset_row``.
187+
if not chunk.reset_row:
188+
raise ValueError('Received reset_row that was False.')
189+
190+
self.clear()
191+
192+
def _handle_row_contents(self, chunk):
193+
"""Handles a ``row_contents`` chunk.
194+
195+
:type chunk: ``ReadRowsResponse.Chunk``
196+
:param chunk: The chunk being handled.
197+
"""
198+
# NOTE: We assume the caller has checked that the ``ONEOF`` property
199+
# for ``chunk`` is ``row_contents``.
200+
201+
# chunk.row_contents is ._generated.bigtable_data_pb2.Family
202+
column_family_id = chunk.row_contents.name
203+
column_family_dict = self._cells.setdefault(column_family_id, {})
204+
for column in chunk.row_contents.columns:
205+
cells = [Cell.from_pb(cell) for cell in column.cells]
206+
207+
column_name = column.qualifier
208+
column_cells = column_family_dict.setdefault(column_name, [])
209+
column_cells.extend(cells)
210+
150211

151212
class PartialRowsData(object):
152213
"""Convenience wrapper for consuming a ``ReadRows`` streaming response.

gcloud/bigtable/test_row_data.py

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,95 @@ def test_clear(self):
207207
self.assertFalse(partial_row_data._chunks_encountered)
208208
self.assertEqual(partial_row_data.cells, {})
209209

210+
def test__handle_commit_row(self):
211+
from gcloud.bigtable._generated import (
212+
bigtable_service_messages_pb2 as messages_pb2)
213+
214+
partial_row_data = self._makeOne(None)
215+
chunk = messages_pb2.ReadRowsResponse.Chunk(commit_row=True)
216+
217+
index = last_chunk_index = 1
218+
self.assertFalse(partial_row_data.committed)
219+
partial_row_data._handle_commit_row(chunk, index, last_chunk_index)
220+
self.assertTrue(partial_row_data.committed)
221+
222+
def test__handle_commit_row_false(self):
223+
from gcloud.bigtable._generated import (
224+
bigtable_service_messages_pb2 as messages_pb2)
225+
226+
partial_row_data = self._makeOne(None)
227+
chunk = messages_pb2.ReadRowsResponse.Chunk(commit_row=False)
228+
229+
with self.assertRaises(ValueError):
230+
partial_row_data._handle_commit_row(chunk, None, None)
231+
232+
def test__handle_commit_row_not_last_chunk(self):
233+
from gcloud.bigtable._generated import (
234+
bigtable_service_messages_pb2 as messages_pb2)
235+
236+
partial_row_data = self._makeOne(None)
237+
chunk = messages_pb2.ReadRowsResponse.Chunk(commit_row=True)
238+
239+
with self.assertRaises(ValueError):
240+
index = 0
241+
last_chunk_index = 1
242+
self.assertNotEqual(index, last_chunk_index)
243+
partial_row_data._handle_commit_row(chunk, index, last_chunk_index)
244+
245+
def test__handle_reset_row(self):
246+
from gcloud.bigtable._generated import (
247+
bigtable_service_messages_pb2 as messages_pb2)
248+
249+
partial_row_data = self._makeOne(None)
250+
chunk = messages_pb2.ReadRowsResponse.Chunk(reset_row=True)
251+
252+
# Modify the PartialRowData object so we can check it's been cleared.
253+
partial_row_data._cells = {1: 2}
254+
partial_row_data._committed = True
255+
partial_row_data._handle_reset_row(chunk)
256+
self.assertEqual(partial_row_data.cells, {})
257+
self.assertFalse(partial_row_data.committed)
258+
259+
def test__handle_reset_row_failure(self):
260+
from gcloud.bigtable._generated import (
261+
bigtable_service_messages_pb2 as messages_pb2)
262+
263+
partial_row_data = self._makeOne(None)
264+
chunk = messages_pb2.ReadRowsResponse.Chunk(reset_row=False)
265+
266+
with self.assertRaises(ValueError):
267+
partial_row_data._handle_reset_row(chunk)
268+
269+
def test__handle_row_contents(self):
270+
from gcloud.bigtable._generated import bigtable_data_pb2 as data_pb2
271+
from gcloud.bigtable._generated import (
272+
bigtable_service_messages_pb2 as messages_pb2)
273+
from gcloud.bigtable.row_data import Cell
274+
275+
partial_row_data = self._makeOne(None)
276+
cell1_pb = data_pb2.Cell(timestamp_micros=1, value=b'val1')
277+
cell2_pb = data_pb2.Cell(timestamp_micros=200, value=b'val2')
278+
cell3_pb = data_pb2.Cell(timestamp_micros=300000, value=b'val3')
279+
col1 = b'col1'
280+
col2 = b'col2'
281+
columns = [
282+
data_pb2.Column(qualifier=col1, cells=[cell1_pb, cell2_pb]),
283+
data_pb2.Column(qualifier=col2, cells=[cell3_pb]),
284+
]
285+
family_name = u'name'
286+
row_contents = data_pb2.Family(name=family_name, columns=columns)
287+
chunk = messages_pb2.ReadRowsResponse.Chunk(row_contents=row_contents)
288+
289+
self.assertEqual(partial_row_data.cells, {})
290+
partial_row_data._handle_row_contents(chunk)
291+
expected_cells = {
292+
family_name: {
293+
col1: [Cell.from_pb(cell1_pb), Cell.from_pb(cell2_pb)],
294+
col2: [Cell.from_pb(cell3_pb)],
295+
}
296+
}
297+
self.assertEqual(partial_row_data.cells, expected_cells)
298+
210299

211300
class TestPartialRowsData(unittest2.TestCase):
212301

0 commit comments

Comments
 (0)