|
1 | 1 | use crate::frame::response::result::ColumnSpec; |
2 | 2 |
|
3 | | -use super::row::{mk_deser_err, BuiltinDeserializationErrorKind, ColumnIterator}; |
4 | | -use super::{DeserializationError, FrameSlice}; |
| 3 | +use super::row::{mk_deser_err, BuiltinDeserializationErrorKind, ColumnIterator, DeserializeRow}; |
| 4 | +use super::{DeserializationError, FrameSlice, TypeCheckError}; |
| 5 | +use std::marker::PhantomData; |
5 | 6 |
|
6 | 7 | /// Iterates over the whole result, returning rows. |
7 | 8 | pub struct RowIterator<'frame> { |
@@ -73,12 +74,70 @@ impl<'frame> Iterator for RowIterator<'frame> { |
73 | 74 | } |
74 | 75 | } |
75 | 76 |
|
| 77 | +/// A typed version of [RowIterator] which deserializes the rows before |
| 78 | +/// returning them. |
| 79 | +pub struct TypedRowIterator<'frame, R> { |
| 80 | + inner: RowIterator<'frame>, |
| 81 | + _phantom: PhantomData<R>, |
| 82 | +} |
| 83 | + |
| 84 | +impl<'frame, R> TypedRowIterator<'frame, R> |
| 85 | +where |
| 86 | + R: DeserializeRow<'frame>, |
| 87 | +{ |
| 88 | + /// Creates a new [TypedRowIterator] from given [RowIterator]. |
| 89 | + /// |
| 90 | + /// Calls `R::type_check` and fails if the type check fails. |
| 91 | + #[inline] |
| 92 | + pub fn new(raw: RowIterator<'frame>) -> Result<Self, TypeCheckError> { |
| 93 | + R::type_check(raw.specs())?; |
| 94 | + Ok(Self { |
| 95 | + inner: raw, |
| 96 | + _phantom: PhantomData, |
| 97 | + }) |
| 98 | + } |
| 99 | + |
| 100 | + /// Returns information about the columns of rows that are iterated over. |
| 101 | + #[inline] |
| 102 | + pub fn specs(&self) -> &'frame [ColumnSpec] { |
| 103 | + self.inner.specs() |
| 104 | + } |
| 105 | + |
| 106 | + /// Returns the remaining number of rows that this iterator is supposed |
| 107 | + /// to return. |
| 108 | + #[inline] |
| 109 | + pub fn rows_remaining(&self) -> usize { |
| 110 | + self.inner.rows_remaining() |
| 111 | + } |
| 112 | +} |
| 113 | + |
| 114 | +impl<'frame, R> Iterator for TypedRowIterator<'frame, R> |
| 115 | +where |
| 116 | + R: DeserializeRow<'frame>, |
| 117 | +{ |
| 118 | + type Item = Result<R, DeserializationError>; |
| 119 | + |
| 120 | + #[inline] |
| 121 | + fn next(&mut self) -> Option<Self::Item> { |
| 122 | + self.inner |
| 123 | + .next() |
| 124 | + .map(|raw| raw.and_then(|raw| R::deserialize(raw))) |
| 125 | + } |
| 126 | + |
| 127 | + #[inline] |
| 128 | + fn size_hint(&self) -> (usize, Option<usize>) { |
| 129 | + self.inner.size_hint() |
| 130 | + } |
| 131 | +} |
| 132 | + |
76 | 133 | #[cfg(test)] |
77 | 134 | mod tests { |
| 135 | + use bytes::Bytes; |
| 136 | + |
78 | 137 | use crate::frame::response::result::ColumnType; |
79 | 138 |
|
80 | 139 | use super::super::tests::{serialize_cells, spec, CELL1, CELL2}; |
81 | | - use super::{FrameSlice, RowIterator}; |
| 140 | + use super::{FrameSlice, RowIterator, TypedRowIterator}; |
82 | 141 |
|
83 | 142 | #[test] |
84 | 143 | fn test_row_iterator_basic_parse() { |
@@ -112,4 +171,30 @@ mod tests { |
112 | 171 | iter.next().unwrap().unwrap(); |
113 | 172 | assert!(iter.next().unwrap().is_err()); |
114 | 173 | } |
| 174 | + |
| 175 | + #[test] |
| 176 | + fn test_typed_row_iterator_basic_parse() { |
| 177 | + let raw_data = serialize_cells([Some(CELL1), Some(CELL2), Some(CELL2), Some(CELL1)]); |
| 178 | + let specs = [spec("b1", ColumnType::Blob), spec("b2", ColumnType::Blob)]; |
| 179 | + let iter = RowIterator::new(2, &specs, FrameSlice::new(&raw_data)); |
| 180 | + let mut iter = TypedRowIterator::<'_, (&[u8], Vec<u8>)>::new(iter).unwrap(); |
| 181 | + |
| 182 | + let (c11, c12) = iter.next().unwrap().unwrap(); |
| 183 | + assert_eq!(c11, CELL1); |
| 184 | + assert_eq!(c12, CELL2); |
| 185 | + |
| 186 | + let (c21, c22) = iter.next().unwrap().unwrap(); |
| 187 | + assert_eq!(c21, CELL2); |
| 188 | + assert_eq!(c22, CELL1); |
| 189 | + |
| 190 | + assert!(iter.next().is_none()); |
| 191 | + } |
| 192 | + |
| 193 | + #[test] |
| 194 | + fn test_typed_row_iterator_wrong_type() { |
| 195 | + let raw_data = Bytes::new(); |
| 196 | + let specs = [spec("b1", ColumnType::Blob), spec("b2", ColumnType::Blob)]; |
| 197 | + let iter = RowIterator::new(0, &specs, FrameSlice::new(&raw_data)); |
| 198 | + assert!(TypedRowIterator::<'_, (i32, i64)>::new(iter).is_err()); |
| 199 | + } |
115 | 200 | } |
0 commit comments