Skip to content

Commit da357cf

Browse files
wprzytulapiodul
andcommitted
deser/result: introduce RowIterator
This is an iterator over rows, allowing lazy and flexible deserialization. Returns ColumnIterator for each row. Co-authored-by: Piotr Dulikowski <[email protected]>
1 parent c1f81e4 commit da357cf

File tree

2 files changed

+116
-0
lines changed

2 files changed

+116
-0
lines changed

scylla-cql/src/types/deserialize/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,7 @@
163163
// TODO: in the above module docstring, stop abusing ParseError once errors are refactored.
164164

165165
pub mod frame_slice;
166+
pub mod result;
166167
pub mod row;
167168
pub mod value;
168169

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
use crate::frame::response::result::ColumnSpec;
2+
3+
use super::row::{mk_deser_err, BuiltinDeserializationErrorKind, ColumnIterator};
4+
use super::{DeserializationError, FrameSlice};
5+
6+
/// Iterates over the whole result, returning rows.
7+
pub struct RowIterator<'frame> {
8+
specs: &'frame [ColumnSpec],
9+
remaining: usize,
10+
slice: FrameSlice<'frame>,
11+
}
12+
13+
impl<'frame> RowIterator<'frame> {
14+
/// Creates a new iterator over rows from a serialized response.
15+
///
16+
/// - `remaining` - number of the remaining rows in the serialized response,
17+
/// - `specs` - information about columns of the serialized response,
18+
/// - `slice` - a [FrameSlice] that points to the serialized rows data.
19+
#[inline]
20+
pub fn new(remaining: usize, specs: &'frame [ColumnSpec], slice: FrameSlice<'frame>) -> Self {
21+
Self {
22+
specs,
23+
remaining,
24+
slice,
25+
}
26+
}
27+
28+
/// Returns information about the columns of rows that are iterated over.
29+
#[inline]
30+
pub fn specs(&self) -> &'frame [ColumnSpec] {
31+
self.specs
32+
}
33+
34+
/// Returns the remaining number of rows that this iterator is supposed
35+
/// to return.
36+
#[inline]
37+
pub fn rows_remaining(&self) -> usize {
38+
self.remaining
39+
}
40+
}
41+
42+
impl<'frame> Iterator for RowIterator<'frame> {
43+
type Item = Result<ColumnIterator<'frame>, DeserializationError>;
44+
45+
#[inline]
46+
fn next(&mut self) -> Option<Self::Item> {
47+
self.remaining = self.remaining.checked_sub(1)?;
48+
49+
let iter = ColumnIterator::new(self.specs, self.slice);
50+
51+
// Skip the row here, manually
52+
for (column_index, spec) in self.specs.iter().enumerate() {
53+
if let Err(err) = self.slice.read_cql_bytes() {
54+
return Some(Err(mk_deser_err::<Self>(
55+
BuiltinDeserializationErrorKind::RawColumnDeserializationFailed {
56+
column_index,
57+
column_name: spec.name.clone(),
58+
err: DeserializationError::new(err),
59+
},
60+
)));
61+
}
62+
}
63+
64+
Some(Ok(iter))
65+
}
66+
67+
#[inline]
68+
fn size_hint(&self) -> (usize, Option<usize>) {
69+
// The iterator will always return exactly `self.remaining`
70+
// elements: Oks until an error is encountered and then Errs
71+
// containing that same first encountered error.
72+
(self.remaining, Some(self.remaining))
73+
}
74+
}
75+
76+
#[cfg(test)]
77+
mod tests {
78+
use crate::frame::response::result::ColumnType;
79+
80+
use super::super::tests::{serialize_cells, spec, CELL1, CELL2};
81+
use super::{FrameSlice, RowIterator};
82+
83+
#[test]
84+
fn test_row_iterator_basic_parse() {
85+
let raw_data = serialize_cells([Some(CELL1), Some(CELL2), Some(CELL2), Some(CELL1)]);
86+
let specs = [spec("b1", ColumnType::Blob), spec("b2", ColumnType::Blob)];
87+
let mut iter = RowIterator::new(2, &specs, FrameSlice::new(&raw_data));
88+
89+
let mut row1 = iter.next().unwrap().unwrap();
90+
let c11 = row1.next().unwrap().unwrap();
91+
assert_eq!(c11.slice.unwrap().as_slice(), CELL1);
92+
let c12 = row1.next().unwrap().unwrap();
93+
assert_eq!(c12.slice.unwrap().as_slice(), CELL2);
94+
assert!(row1.next().is_none());
95+
96+
let mut row2 = iter.next().unwrap().unwrap();
97+
let c21 = row2.next().unwrap().unwrap();
98+
assert_eq!(c21.slice.unwrap().as_slice(), CELL2);
99+
let c22 = row2.next().unwrap().unwrap();
100+
assert_eq!(c22.slice.unwrap().as_slice(), CELL1);
101+
assert!(row2.next().is_none());
102+
103+
assert!(iter.next().is_none());
104+
}
105+
106+
#[test]
107+
fn test_row_iterator_too_few_rows() {
108+
let raw_data = serialize_cells([Some(CELL1), Some(CELL2)]);
109+
let specs = [spec("b1", ColumnType::Blob), spec("b2", ColumnType::Blob)];
110+
let mut iter = RowIterator::new(2, &specs, FrameSlice::new(&raw_data));
111+
112+
iter.next().unwrap().unwrap();
113+
assert!(iter.next().unwrap().is_err());
114+
}
115+
}

0 commit comments

Comments
 (0)