use vibesql_storage::Row;
use vibesql_types::SqlValue;
pub struct ColumnarScan<'a> {
rows: &'a [Row],
}
impl<'a> ColumnarScan<'a> {
pub fn new(rows: &'a [Row]) -> Self {
Self { rows }
}
pub fn column(&self, index: usize) -> ColumnIterator<'a> {
ColumnIterator { rows: self.rows, column_index: index, row_index: 0 }
}
pub fn len(&self) -> usize {
self.rows.len()
}
pub fn is_empty(&self) -> bool {
self.rows.is_empty()
}
pub fn row(&self, index: usize) -> Option<&'a Row> {
self.rows.get(index)
}
}
pub struct ColumnIterator<'a> {
rows: &'a [Row],
column_index: usize,
row_index: usize,
}
impl<'a> Iterator for ColumnIterator<'a> {
type Item = Option<&'a SqlValue>;
fn next(&mut self) -> Option<Self::Item> {
if self.row_index >= self.rows.len() {
return None;
}
let row = &self.rows[self.row_index];
self.row_index += 1;
Some(row.get(self.column_index))
}
fn size_hint(&self) -> (usize, Option<usize>) {
let remaining = self.rows.len() - self.row_index;
(remaining, Some(remaining))
}
}
impl<'a> ExactSizeIterator for ColumnIterator<'a> {}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_columnar_scan() {
let rows = vec![
Row::new(vec![
SqlValue::Integer(1),
SqlValue::Double(10.5),
SqlValue::Varchar(arcstr::ArcStr::from("A")),
]),
Row::new(vec![
SqlValue::Integer(2),
SqlValue::Double(20.5),
SqlValue::Varchar(arcstr::ArcStr::from("B")),
]),
];
let scan = ColumnarScan::new(&rows);
assert_eq!(scan.len(), 2);
let col0: Vec<Option<&SqlValue>> = scan.column(0).collect();
assert_eq!(col0.len(), 2);
assert!(matches!(col0[0], Some(&SqlValue::Integer(1))));
assert!(matches!(col0[1], Some(&SqlValue::Integer(2))));
let col1: Vec<Option<&SqlValue>> = scan.column(1).collect();
assert!(matches!(col1[0], Some(&SqlValue::Double(10.5))));
assert!(matches!(col1[1], Some(&SqlValue::Double(20.5))));
}
#[test]
fn test_column_iterator_size_hint() {
let rows = vec![
Row::new(vec![SqlValue::Integer(1)]),
Row::new(vec![SqlValue::Integer(2)]),
Row::new(vec![SqlValue::Integer(3)]),
];
let scan = ColumnarScan::new(&rows);
let mut iter = scan.column(0);
assert_eq!(iter.size_hint(), (3, Some(3)));
iter.next();
assert_eq!(iter.size_hint(), (2, Some(2)));
}
}