sql_cli/data/
computed_view.rs1use crate::data::datatable::{DataTable, DataValue};
2use crate::sql::parser::ast::ColumnRef;
3use crate::sql::recursive_parser::SqlExpression;
4use std::sync::Arc;
5
6#[derive(Debug, Clone)]
8pub enum ViewColumn {
9 Original {
11 source_index: usize, name: String, },
14 Derived {
16 name: String,
17 expression: SqlExpression,
18 cached_values: Vec<DataValue>, },
20}
21
22#[derive(Debug, Clone)]
25pub struct ComputedDataView {
26 source_table: Arc<DataTable>,
28
29 columns: Vec<ViewColumn>,
31
32 visible_rows: Vec<usize>,
35}
36
37impl ComputedDataView {
38 #[must_use]
40 pub fn new(
41 source_table: Arc<DataTable>,
42 columns: Vec<ViewColumn>,
43 visible_rows: Vec<usize>,
44 ) -> Self {
45 Self {
46 source_table,
47 columns,
48 visible_rows,
49 }
50 }
51
52 #[must_use]
54 pub fn row_count(&self) -> usize {
55 self.visible_rows.len()
56 }
57
58 #[must_use]
60 pub fn column_count(&self) -> usize {
61 self.columns.len()
62 }
63
64 #[must_use]
66 pub fn column_names(&self) -> Vec<String> {
67 self.columns
68 .iter()
69 .map(|col| match col {
70 ViewColumn::Original { name, .. } => name.clone(),
71 ViewColumn::Derived { name, .. } => name.clone(),
72 })
73 .collect()
74 }
75
76 #[must_use]
78 pub fn get_value(&self, row_idx: usize, col_idx: usize) -> Option<DataValue> {
79 if row_idx >= self.visible_rows.len() || col_idx >= self.columns.len() {
81 return None;
82 }
83
84 match &self.columns[col_idx] {
85 ViewColumn::Original { source_index, .. } => {
86 let source_row_idx = self.visible_rows[row_idx];
88
89 self.source_table
91 .get_row(source_row_idx)
92 .and_then(|row| row.get(*source_index))
93 .cloned()
94 }
95 ViewColumn::Derived { cached_values, .. } => {
96 cached_values.get(row_idx).cloned()
98 }
99 }
100 }
101
102 #[must_use]
104 pub fn get_row_values(&self, row_idx: usize) -> Option<Vec<DataValue>> {
105 if row_idx >= self.visible_rows.len() {
106 return None;
107 }
108
109 let mut values = Vec::new();
110 for col_idx in 0..self.columns.len() {
111 values.push(self.get_value(row_idx, col_idx)?);
112 }
113 Some(values)
114 }
115
116 #[must_use]
118 pub fn source_table(&self) -> &Arc<DataTable> {
119 &self.source_table
120 }
121
122 #[must_use]
124 pub fn visible_rows(&self) -> &[usize] {
125 &self.visible_rows
126 }
127
128 #[must_use]
130 pub fn is_derived_column(&self, col_idx: usize) -> bool {
131 matches!(self.columns.get(col_idx), Some(ViewColumn::Derived { .. }))
132 }
133
134 #[must_use]
136 pub fn from_source_all_columns(source: Arc<DataTable>) -> Self {
137 let columns: Vec<ViewColumn> = source
138 .column_names()
139 .into_iter()
140 .enumerate()
141 .map(|(idx, name)| ViewColumn::Original {
142 source_index: idx,
143 name,
144 })
145 .collect();
146
147 let visible_rows: Vec<usize> = (0..source.row_count()).collect();
148
149 Self::new(source, columns, visible_rows)
150 }
151
152 #[must_use]
154 pub fn with_filtered_rows(mut self, row_indices: Vec<usize>) -> Self {
155 self.visible_rows = row_indices;
156
157 for col in &mut self.columns {
159 if let ViewColumn::Derived { cached_values, .. } = col {
160 let mut new_cache = Vec::new();
162 for &row_idx in &self.visible_rows {
163 if row_idx < cached_values.len() {
164 new_cache.push(cached_values[row_idx].clone());
165 }
166 }
167 *cached_values = new_cache;
168 }
169 }
170
171 self
172 }
173}
174
175#[cfg(test)]
176mod tests {
177 use super::*;
178 use crate::data::datatable::{DataColumn, DataRow};
179
180 fn create_test_table() -> Arc<DataTable> {
181 let mut table = DataTable::new("test");
182 table.add_column(DataColumn::new("a"));
183 table.add_column(DataColumn::new("b"));
184
185 table
186 .add_row(DataRow::new(vec![
187 DataValue::Integer(10),
188 DataValue::Float(2.5),
189 ]))
190 .unwrap();
191
192 table
193 .add_row(DataRow::new(vec![
194 DataValue::Integer(20),
195 DataValue::Float(3.5),
196 ]))
197 .unwrap();
198
199 Arc::new(table)
200 }
201
202 #[test]
203 fn test_original_columns_view() {
204 let table = create_test_table();
205 let view = ComputedDataView::from_source_all_columns(table);
206
207 assert_eq!(view.row_count(), 2);
208 assert_eq!(view.column_count(), 2);
209 assert_eq!(view.column_names(), vec!["a", "b"]);
210
211 assert_eq!(view.get_value(0, 0), Some(DataValue::Integer(10)));
213 assert_eq!(view.get_value(0, 1), Some(DataValue::Float(2.5)));
214 assert_eq!(view.get_value(1, 0), Some(DataValue::Integer(20)));
215 }
216
217 #[test]
218 fn test_mixed_columns() {
219 let table = create_test_table();
220
221 let columns = vec![
223 ViewColumn::Original {
224 source_index: 0,
225 name: "a".to_string(),
226 },
227 ViewColumn::Derived {
228 name: "doubled".to_string(),
229 expression: SqlExpression::Column(ColumnRef::unquoted("a".to_string())), cached_values: vec![
231 DataValue::Integer(20), DataValue::Integer(40), ],
234 },
235 ];
236
237 let view = ComputedDataView::new(table, columns, vec![0, 1]);
238
239 assert_eq!(view.column_count(), 2);
240 assert_eq!(view.column_names(), vec!["a", "doubled"]);
241
242 assert_eq!(view.get_value(0, 0), Some(DataValue::Integer(10)));
244
245 assert_eq!(view.get_value(0, 1), Some(DataValue::Integer(20)));
247 assert_eq!(view.get_value(1, 1), Some(DataValue::Integer(40)));
248 }
249
250 #[test]
251 fn test_filtered_rows() {
252 let table = create_test_table();
253 let view = ComputedDataView::from_source_all_columns(table).with_filtered_rows(vec![1]); assert_eq!(view.row_count(), 1);
256 assert_eq!(view.get_value(0, 0), Some(DataValue::Integer(20)));
257 }
258}