sql_cli/data/
simple_where.rs

1use anyhow::Result;
2
3use crate::data::data_view::DataView;
4use crate::data::datatable::DataValue;
5
6/// Simple WHERE clause implementation for testing
7/// This extracts the WHERE clause as a string from the original SQL
8pub struct SimpleWhereFilter;
9
10impl SimpleWhereFilter {
11    /// Apply a simple WHERE clause filter from SQL string
12    pub fn apply_from_sql(view: DataView, sql: &str) -> Result<DataView> {
13        // Extract WHERE clause from SQL
14        let upper_sql = sql.to_uppercase();
15        let where_start = upper_sql.find(" WHERE ");
16
17        if where_start.is_none() {
18            return Ok(view);
19        }
20
21        let where_start = where_start.unwrap() + 7; // Skip " WHERE "
22        let sql_after_where = &sql[where_start..];
23
24        // Find the end of WHERE clause (before ORDER BY, GROUP BY, LIMIT, etc.)
25        let mut where_end = sql_after_where.len();
26        for keyword in &[" ORDER BY", " GROUP BY", " LIMIT", " OFFSET"] {
27            if let Some(pos) = sql_after_where.to_uppercase().find(keyword) {
28                where_end = where_end.min(pos);
29            }
30        }
31
32        let where_clause = sql_after_where[..where_end].trim();
33
34        // Parse simple WHERE conditions
35        Self::apply_simple_where(view, where_clause)
36    }
37
38    /// Apply a simple WHERE clause (supports basic = and > operators)
39    fn apply_simple_where(view: DataView, where_clause: &str) -> Result<DataView> {
40        // Handle AND/OR by splitting
41        if where_clause.to_uppercase().contains(" AND ") {
42            let parts: Vec<&str> = where_clause.split_terminator(" AND ").collect();
43            let mut result = view;
44            for part in parts {
45                result = Self::apply_single_condition(result, part.trim())?;
46            }
47            return Ok(result);
48        }
49
50        if where_clause.to_uppercase().contains(" OR ") {
51            // For OR, we'd need to combine results - skip for now
52            return Ok(view);
53        }
54
55        // Single condition
56        Self::apply_single_condition(view, where_clause)
57    }
58
59    /// Apply a single WHERE condition
60    fn apply_single_condition(view: DataView, condition: &str) -> Result<DataView> {
61        // Check for LIKE operator first
62        if let Some(like_pos) = condition.to_uppercase().find(" LIKE ") {
63            let column = condition[..like_pos].trim();
64            let pattern_str = condition[like_pos + 6..].trim();
65
66            // Remove quotes from pattern
67            let pattern = if pattern_str.starts_with('\'') && pattern_str.ends_with('\'') {
68                pattern_str[1..pattern_str.len() - 1].to_string()
69            } else {
70                pattern_str.to_string()
71            };
72
73            // Get column index
74            let col_index = view
75                .source()
76                .get_column_index(column)
77                .ok_or_else(|| anyhow::anyhow!("Column '{}' not found", column))?;
78
79            // Convert SQL LIKE pattern to regex
80            let regex_pattern = pattern.replace('%', ".*").replace('_', ".");
81
82            let regex = regex::RegexBuilder::new(&format!("^{regex_pattern}$"))
83                .case_insensitive(true)
84                .build()
85                .map_err(|e| anyhow::anyhow!("Invalid LIKE pattern: {}", e))?;
86
87            return Ok(view.filter(move |table, row_idx| {
88                if let Some(DataValue::String(s)) = table.get_value(row_idx, col_index) {
89                    regex.is_match(s)
90                } else {
91                    false
92                }
93            }));
94        }
95
96        // Parse condition: column operator value
97        let operators = vec![">=", "<=", "!=", "<>", "=", ">", "<"];
98        let mut op = "";
99        let mut op_pos = 0;
100
101        for operator in operators {
102            if let Some(pos) = condition.find(operator) {
103                op = operator;
104                op_pos = pos;
105                break;
106            }
107        }
108
109        if op.is_empty() {
110            return Ok(view);
111        }
112
113        let column = condition[..op_pos].trim();
114        let value_str = condition[op_pos + op.len()..].trim();
115
116        // Get column index
117        let col_index = view
118            .source()
119            .get_column_index(column)
120            .ok_or_else(|| anyhow::anyhow!("Column '{}' not found", column))?;
121
122        // Parse value (remove quotes if string)
123        let value = if value_str.starts_with('\'') && value_str.ends_with('\'') {
124            // String value
125            value_str[1..value_str.len() - 1].to_string()
126        } else {
127            // Number or other value
128            value_str.to_string()
129        };
130
131        // Apply filter
132        Ok(view.filter(move |table, row_idx| {
133            if let Some(cell_value) = table.get_value(row_idx, col_index) {
134                match (cell_value, op) {
135                    (DataValue::String(s), "=") => s == &value,
136                    (DataValue::String(s), "!=" | "<>") => s != &value,
137                    (DataValue::Integer(n), "=") => {
138                        if let Ok(v) = value.parse::<i64>() {
139                            *n == v
140                        } else {
141                            false
142                        }
143                    }
144                    (DataValue::Integer(n), ">") => {
145                        if let Ok(v) = value.parse::<i64>() {
146                            *n > v
147                        } else {
148                            false
149                        }
150                    }
151                    (DataValue::Integer(n), "<") => {
152                        if let Ok(v) = value.parse::<i64>() {
153                            *n < v
154                        } else {
155                            false
156                        }
157                    }
158                    (DataValue::Integer(n), ">=") => {
159                        if let Ok(v) = value.parse::<i64>() {
160                            *n >= v
161                        } else {
162                            false
163                        }
164                    }
165                    (DataValue::Integer(n), "<=") => {
166                        if let Ok(v) = value.parse::<i64>() {
167                            *n <= v
168                        } else {
169                            false
170                        }
171                    }
172                    (DataValue::Float(n), "=") => {
173                        if let Ok(v) = value.parse::<f64>() {
174                            (*n - v).abs() < f64::EPSILON
175                        } else {
176                            false
177                        }
178                    }
179                    (DataValue::Float(n), ">") => {
180                        if let Ok(v) = value.parse::<f64>() {
181                            *n > v
182                        } else {
183                            false
184                        }
185                    }
186                    _ => false,
187                }
188            } else {
189                false
190            }
191        }))
192    }
193}