vibesql_executor/select/columnar/
scan.rs1use vibesql_storage::Row;
4use vibesql_types::SqlValue;
5
6pub struct ColumnarScan<'a> {
19 rows: &'a [Row],
20}
21
22impl<'a> ColumnarScan<'a> {
23 pub fn new(rows: &'a [Row]) -> Self {
25 Self { rows }
26 }
27
28 pub fn column(&self, index: usize) -> ColumnIterator<'a> {
33 ColumnIterator { rows: self.rows, column_index: index, row_index: 0 }
34 }
35
36 pub fn len(&self) -> usize {
38 self.rows.len()
39 }
40
41 pub fn is_empty(&self) -> bool {
43 self.rows.is_empty()
44 }
45
46 pub fn row(&self, index: usize) -> Option<&'a Row> {
48 self.rows.get(index)
49 }
50}
51
52pub struct ColumnIterator<'a> {
56 rows: &'a [Row],
57 column_index: usize,
58 row_index: usize,
59}
60
61impl<'a> Iterator for ColumnIterator<'a> {
62 type Item = Option<&'a SqlValue>;
63
64 fn next(&mut self) -> Option<Self::Item> {
65 if self.row_index >= self.rows.len() {
66 return None;
67 }
68
69 let row = &self.rows[self.row_index];
70 self.row_index += 1;
71
72 Some(row.get(self.column_index))
74 }
75
76 fn size_hint(&self) -> (usize, Option<usize>) {
77 let remaining = self.rows.len() - self.row_index;
78 (remaining, Some(remaining))
79 }
80}
81
82impl<'a> ExactSizeIterator for ColumnIterator<'a> {}
83
84#[cfg(test)]
85mod tests {
86 use super::*;
87
88 #[test]
89 fn test_columnar_scan() {
90 let rows = vec![
91 Row::new(vec![
92 SqlValue::Integer(1),
93 SqlValue::Double(10.5),
94 SqlValue::Varchar(arcstr::ArcStr::from("A")),
95 ]),
96 Row::new(vec![
97 SqlValue::Integer(2),
98 SqlValue::Double(20.5),
99 SqlValue::Varchar(arcstr::ArcStr::from("B")),
100 ]),
101 ];
102
103 let scan = ColumnarScan::new(&rows);
104 assert_eq!(scan.len(), 2);
105
106 let col0: Vec<Option<&SqlValue>> = scan.column(0).collect();
108 assert_eq!(col0.len(), 2);
109 assert!(matches!(col0[0], Some(&SqlValue::Integer(1))));
110 assert!(matches!(col0[1], Some(&SqlValue::Integer(2))));
111
112 let col1: Vec<Option<&SqlValue>> = scan.column(1).collect();
114 assert!(matches!(col1[0], Some(&SqlValue::Double(10.5))));
115 assert!(matches!(col1[1], Some(&SqlValue::Double(20.5))));
116 }
117
118 #[test]
119 fn test_column_iterator_size_hint() {
120 let rows = vec![
121 Row::new(vec![SqlValue::Integer(1)]),
122 Row::new(vec![SqlValue::Integer(2)]),
123 Row::new(vec![SqlValue::Integer(3)]),
124 ];
125
126 let scan = ColumnarScan::new(&rows);
127 let mut iter = scan.column(0);
128
129 assert_eq!(iter.size_hint(), (3, Some(3)));
130 iter.next();
131 assert_eq!(iter.size_hint(), (2, Some(2)));
132 }
133}