1313# limitations under the License.
1414
1515from typing import (
16+ List ,
1617 TypeVar ,
1718 Generic ,
1819 Iterable ,
@@ -54,14 +55,13 @@ class _Reader(ABC, Generic[T]):
5455
5556 @abstractmethod
5657 def consume (
57- self , bytes_to_consume : bytes , metadata : Metadata
58+ self , batches_to_consume : List [ bytes ] , metadata : Metadata
5859 ) -> Optional [Iterable [T ]]:
59- """This method receives a parsable chunk of bytes and returns either a None if there is
60- not enough chunks to return to the user yet (e.g. we haven't received all columns in a
61- row yet), or a list of appropriate values gathered from one or more parsable chunks.
62-
60+ """This method receives a list of batches of bytes to be parsed as ProtoRows messages.
61+ It then uses the metadata to group the values in the parsed messages into rows. Returns
62+ None if batches_to_consume is empty
6363 Args:
64- bytes_to_consume (bytes): chunk of parsable bytes received from
64+ bytes_to_consume (bytes): chunk of parsable byte batches received from
6565 :meth:`google.cloud.bigtable.byte_cursor._ByteCursor.consume`
6666 method.
6767 metadata: metadata used to transform values to rows
@@ -85,11 +85,9 @@ class _QueryResultRowReader(_Reader[QueryResultRow]):
8585 :class:`google.cloud.bigtable.byte_cursor._ByteCursor` passed in the constructor.
8686 """
8787
88- def __init__ (self ):
89- """
90- Constructs new instance of ``_QueryResultRowReader``.
91- """
92- self ._values = []
88+ def _parse_proto_rows (self , bytes_to_parse : bytes ) -> Iterable [PBValue ]:
89+ proto_rows = ProtoRows .pb ().FromString (bytes_to_parse )
90+ return proto_rows .values
9391
9492 def _construct_query_result_row (
9593 self , values : Sequence [PBValue ], metadata : ProtoMetadata
@@ -106,36 +104,23 @@ def _construct_query_result_row(
106104 result .add_field (column .column_name , parsed_value )
107105 return result
108106
109- def _parse_proto_rows (self , bytes_to_parse : bytes ) -> Iterable [PBValue ]:
110- proto_rows = ProtoRows .pb ().FromString (bytes_to_parse )
111- return proto_rows .values
112-
113107 def consume (
114- self , bytes_to_consume : bytes , metadata : Metadata
108+ self , batches_to_consume : List [ bytes ] , metadata : Metadata
115109 ) -> Optional [Iterable [QueryResultRow ]]:
116- if bytes_to_consume is None :
117- raise ValueError ("bytes_to_consume shouldn't be None" )
118-
119- self ._values .extend (self ._parse_proto_rows (bytes_to_consume ))
120-
121- # The logic, not defined by mypy types, ensures that the value of
122- # "metadata" is never null at the time it is retrieved here
123110 proto_metadata = cast (ProtoMetadata , metadata )
124111 num_columns = len (proto_metadata .columns )
125-
126- if len (self ._values ) < num_columns :
127- return None
128-
129112 rows = []
130- for batch in batched (self ._values , n = num_columns ):
131- if len (batch ) == num_columns :
132- rows .append (self ._construct_query_result_row (batch , proto_metadata ))
133- else :
134- raise ValueError (
135- "Server error, recieved bad number of values. "
136- f"Expected { num_columns } got { len (batch )} ."
137- )
138-
139- self ._values = []
113+ for batch_bytes in batches_to_consume :
114+ values = self ._parse_proto_rows (batch_bytes )
115+ for row_data in batched (values , n = num_columns ):
116+ if len (row_data ) == num_columns :
117+ rows .append (
118+ self ._construct_query_result_row (row_data , proto_metadata )
119+ )
120+ else :
121+ raise ValueError (
122+ "Unexpected error, recieved bad number of values. "
123+ f"Expected { num_columns } got { len (row_data )} ."
124+ )
140125
141126 return rows
0 commit comments