sql_cli/data/
query_executor.rs1use anyhow::Result;
2
3use crate::api_client::QueryResponse;
4use crate::csv_datasource::CsvApiClient;
5use crate::data::datatable::DataTable;
6
7pub trait QueryExecutor {
9 fn execute(&self, query: &str) -> Result<QueryResponse>;
11
12 fn can_handle(&self, query: &str) -> bool;
14
15 fn row_count(&self) -> usize;
17
18 fn column_count(&self) -> usize;
20}
21
22pub struct DataTableExecutor {
24 datatable: std::sync::Arc<DataTable>,
25 table_name: String,
26}
27
28impl DataTableExecutor {
29 pub fn new(datatable: std::sync::Arc<DataTable>, table_name: String) -> Self {
30 Self {
31 datatable,
32 table_name,
33 }
34 }
35}
36
37impl QueryExecutor for DataTableExecutor {
38 fn execute(&self, query: &str) -> Result<QueryResponse> {
39 let upper_query = query.trim().to_uppercase();
41 if !self.can_handle(query) {
42 return Err(anyhow::anyhow!(
43 "DataTableExecutor can only handle simple SELECT * queries"
44 ));
45 }
46
47 Ok(QueryResponse {
50 data: vec![], count: self.datatable.row_count(),
52 query: crate::api_client::QueryInfo {
53 select: vec!["*".to_string()],
54 where_clause: None,
55 order_by: None,
56 },
57 source: Some("datatable".to_string()),
58 table: Some(self.table_name.clone()),
59 cached: Some(false),
60 })
61 }
62
63 fn can_handle(&self, query: &str) -> bool {
64 let upper_query = query.trim().to_uppercase();
65 upper_query.starts_with("SELECT *")
66 && !upper_query.contains(" WHERE ")
67 && !upper_query.contains(" ORDER BY ")
68 && !upper_query.contains(" LIMIT ")
69 && !upper_query.contains(" GROUP BY ")
70 }
71
72 fn row_count(&self) -> usize {
73 self.datatable.row_count()
74 }
75
76 fn column_count(&self) -> usize {
77 self.datatable.column_count()
78 }
79}
80
81pub struct CsvClientExecutor {
83 csv_client: CsvApiClient,
84 table_name: String,
85}
86
87impl CsvClientExecutor {
88 pub fn new(csv_client: CsvApiClient, table_name: String) -> Self {
89 Self {
90 csv_client,
91 table_name,
92 }
93 }
94
95 pub fn from_csv(path: &str, table_name: &str, case_insensitive: bool) -> Result<Self> {
96 let mut csv_client = CsvApiClient::new();
97 csv_client.set_case_insensitive(case_insensitive);
98 csv_client.load_csv(path, table_name)?;
99 Ok(Self {
100 csv_client,
101 table_name: table_name.to_string(),
102 })
103 }
104
105 pub fn from_json(path: &str, table_name: &str, case_insensitive: bool) -> Result<Self> {
106 let mut csv_client = CsvApiClient::new();
107 csv_client.set_case_insensitive(case_insensitive);
108 csv_client.load_json(path, table_name)?;
109 Ok(Self {
110 csv_client,
111 table_name: table_name.to_string(),
112 })
113 }
114}
115
116impl QueryExecutor for CsvClientExecutor {
117 fn execute(&self, query: &str) -> Result<QueryResponse> {
118 let result = self.csv_client.query_csv(query)?;
119 Ok(QueryResponse {
120 data: result.data,
121 count: result.count,
122 query: crate::api_client::QueryInfo {
123 select: result.query.select,
124 where_clause: result.query.where_clause,
125 order_by: result.query.order_by,
126 },
127 source: Some("csv_client".to_string()),
128 table: Some(self.table_name.clone()),
129 cached: Some(false),
130 })
131 }
132
133 fn can_handle(&self, _query: &str) -> bool {
134 true
136 }
137
138 fn row_count(&self) -> usize {
139 0
141 }
142
143 fn column_count(&self) -> usize {
144 0
146 }
147}
148
149pub struct CompositeQueryExecutor {
151 executors: Vec<Box<dyn QueryExecutor>>,
152}
153
154impl CompositeQueryExecutor {
155 pub fn new() -> Self {
156 Self {
157 executors: Vec::new(),
158 }
159 }
160
161 pub fn add_executor(&mut self, executor: Box<dyn QueryExecutor>) {
162 self.executors.push(executor);
163 }
164}
165
166impl QueryExecutor for CompositeQueryExecutor {
167 fn execute(&self, query: &str) -> Result<QueryResponse> {
168 for executor in &self.executors {
170 if executor.can_handle(query) {
171 return executor.execute(query);
172 }
173 }
174 Err(anyhow::anyhow!("No executor can handle query: {}", query))
175 }
176
177 fn can_handle(&self, query: &str) -> bool {
178 self.executors.iter().any(|e| e.can_handle(query))
179 }
180
181 fn row_count(&self) -> usize {
182 self.executors.first().map(|e| e.row_count()).unwrap_or(0)
184 }
185
186 fn column_count(&self) -> usize {
187 self.executors
189 .first()
190 .map(|e| e.column_count())
191 .unwrap_or(0)
192 }
193}