sql_cli/data/
simple_where.rs1use anyhow::Result;
2
3use crate::data::data_view::DataView;
4use crate::data::datatable::DataValue;
5
6pub struct SimpleWhereFilter;
9
10impl SimpleWhereFilter {
11 pub fn apply_from_sql(view: DataView, sql: &str) -> Result<DataView> {
13 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; let sql_after_where = &sql[where_start..];
23
24 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 Self::apply_simple_where(view, where_clause)
36 }
37
38 fn apply_simple_where(view: DataView, where_clause: &str) -> Result<DataView> {
40 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 return Ok(view);
53 }
54
55 Self::apply_single_condition(view, where_clause)
57 }
58
59 fn apply_single_condition(view: DataView, condition: &str) -> Result<DataView> {
61 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 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 let col_index = view
75 .source()
76 .get_column_index(column)
77 .ok_or_else(|| anyhow::anyhow!("Column '{}' not found", column))?;
78
79 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 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 let col_index = view
118 .source()
119 .get_column_index(column)
120 .ok_or_else(|| anyhow::anyhow!("Column '{}' not found", column))?;
121
122 let value = if value_str.starts_with('\'') && value_str.ends_with('\'') {
124 value_str[1..value_str.len() - 1].to_string()
126 } else {
127 value_str.to_string()
129 };
130
131 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}