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 {
34 rows: self.rows,
35 column_index: index,
36 row_index: 0,
37 }
38 }
39
40 pub fn len(&self) -> usize {
42 self.rows.len()
43 }
44
45 pub fn is_empty(&self) -> bool {
47 self.rows.is_empty()
48 }
49
50 pub fn row(&self, index: usize) -> Option<&'a Row> {
52 self.rows.get(index)
53 }
54}
55
56pub struct ColumnIterator<'a> {
60 rows: &'a [Row],
61 column_index: usize,
62 row_index: usize,
63}
64
65impl<'a> Iterator for ColumnIterator<'a> {
66 type Item = Option<&'a SqlValue>;
67
68 fn next(&mut self) -> Option<Self::Item> {
69 if self.row_index >= self.rows.len() {
70 return None;
71 }
72
73 let row = &self.rows[self.row_index];
74 self.row_index += 1;
75
76 Some(row.get(self.column_index))
78 }
79
80 fn size_hint(&self) -> (usize, Option<usize>) {
81 let remaining = self.rows.len() - self.row_index;
82 (remaining, Some(remaining))
83 }
84}
85
86impl<'a> ExactSizeIterator for ColumnIterator<'a> {}
87
88#[cfg(test)]
89mod tests {
90 use super::*;
91
92 #[test]
93 fn test_columnar_scan() {
94 let rows = vec![
95 Row::new(vec![
96 SqlValue::Integer(1),
97 SqlValue::Double(10.5),
98 SqlValue::Varchar("A".to_string()),
99 ]),
100 Row::new(vec![
101 SqlValue::Integer(2),
102 SqlValue::Double(20.5),
103 SqlValue::Varchar("B".to_string()),
104 ]),
105 ];
106
107 let scan = ColumnarScan::new(&rows);
108 assert_eq!(scan.len(), 2);
109
110 let col0: Vec<Option<&SqlValue>> = scan.column(0).collect();
112 assert_eq!(col0.len(), 2);
113 assert!(matches!(col0[0], Some(&SqlValue::Integer(1))));
114 assert!(matches!(col0[1], Some(&SqlValue::Integer(2))));
115
116 let col1: Vec<Option<&SqlValue>> = scan.column(1).collect();
118 assert!(matches!(col1[0], Some(&SqlValue::Double(10.5))));
119 assert!(matches!(col1[1], Some(&SqlValue::Double(20.5))));
120 }
121
122 #[test]
123 fn test_column_iterator_size_hint() {
124 let rows = vec![
125 Row::new(vec![SqlValue::Integer(1)]),
126 Row::new(vec![SqlValue::Integer(2)]),
127 Row::new(vec![SqlValue::Integer(3)]),
128 ];
129
130 let scan = ColumnarScan::new(&rows);
131 let mut iter = scan.column(0);
132
133 assert_eq!(iter.size_hint(), (3, Some(3)));
134 iter.next();
135 assert_eq!(iter.size_hint(), (2, Some(2)));
136 }
137}