sql_cli/services/
query_orchestrator.rs1use crate::app_state_container::AppStateContainer;
2use crate::data::data_view::DataView;
3use crate::services::{QueryExecutionResult, QueryExecutionService};
4use crate::ui::search::vim_search_adapter::VimSearchAdapter;
5use anyhow::Result;
6use std::cell::RefCell;
7use tracing::{debug, info};
8
9pub struct QueryOrchestrator {
12 query_execution_service: QueryExecutionService,
13}
14
15impl QueryOrchestrator {
16 pub fn new(case_insensitive: bool, auto_hide_empty: bool) -> Self {
17 Self {
18 query_execution_service: QueryExecutionService::new(case_insensitive, auto_hide_empty),
19 }
20 }
21
22 pub fn execute_query(
24 &mut self,
25 query: &str,
26 state_container: &mut AppStateContainer,
27 vim_search_adapter: &RefCell<VimSearchAdapter>,
28 ) -> Result<QueryExecutionContext> {
29 info!(target: "query", "Executing query: {}", query);
30
31 self.clear_all_search_state(state_container, vim_search_adapter);
33
34 self.record_query_execution(query, state_container);
36
37 state_container.set_status_message(format!("Executing query: '{}'...", query));
39
40 let current_dataview = state_container.get_buffer_dataview();
42 let original_source = state_container.get_original_source();
43
44 if let Some(ref orig) = original_source {
46 debug!(
47 "QueryOrchestrator: Have original source with {} columns",
48 orig.column_count()
49 );
50 } else {
51 debug!("QueryOrchestrator: WARNING - No original source available!");
52 }
53
54 if let Some(ref view) = current_dataview {
55 debug!(
56 "QueryOrchestrator: Current view has {} columns, source has {} columns",
57 view.column_count(),
58 view.source().column_count()
59 );
60 }
61
62 let result =
63 self.query_execution_service
64 .execute(query, current_dataview, original_source)?;
65
66 self.clear_all_filters(state_container);
68
69 Ok(QueryExecutionContext {
71 result,
72 query: query.to_string(),
73 })
74 }
75
76 fn clear_all_search_state(
78 &self,
79 state_container: &mut AppStateContainer,
80 vim_search_adapter: &RefCell<VimSearchAdapter>,
81 ) {
82 state_container.clear_search();
84 state_container.clear_column_search();
85
86 vim_search_adapter.borrow_mut().cancel_search();
88 }
89
90 fn record_query_execution(&self, query: &str, state_container: &mut AppStateContainer) {
92 state_container.set_last_query(query.to_string());
93 state_container.set_last_executed_query(query.to_string());
94 }
95
96 fn clear_all_filters(&self, state_container: &mut AppStateContainer) {
98 state_container.set_filter_pattern(String::new());
99 state_container.set_fuzzy_filter_pattern(String::new());
100 state_container.set_filter_active(false);
101 state_container.set_fuzzy_filter_active(false);
102 }
103
104 pub fn set_case_insensitive(&mut self, case_insensitive: bool) {
106 self.query_execution_service
107 .set_case_insensitive(case_insensitive);
108 }
109
110 pub fn set_auto_hide_empty(&mut self, auto_hide: bool) {
111 self.query_execution_service.set_auto_hide_empty(auto_hide);
112 }
113}
114
115pub struct QueryExecutionContext {
117 pub result: QueryExecutionResult,
118 pub query: String,
119}
120
121impl QueryExecutionContext {
122 pub fn apply_to_tui(
125 self,
126 state_container: &mut AppStateContainer,
127 update_viewport: impl FnOnce(DataView),
128 calculate_widths: impl FnOnce(),
129 reset_table: impl FnOnce(),
130 ) -> Result<()> {
131 state_container.set_dataview(Some(self.result.dataview.clone()));
133
134 update_viewport(self.result.dataview.clone());
136
137 state_container
139 .update_data_size(self.result.stats.row_count, self.result.stats.column_count);
140
141 calculate_widths();
143
144 state_container.set_status_message(self.result.status_message());
146
147 state_container
149 .command_history_mut()
150 .add_entry_with_schema(
151 self.query.clone(),
152 true,
153 Some(self.result.stats.execution_time.as_millis() as u64),
154 self.result.column_names(),
155 Some(self.result.table_name()),
156 )?;
157
158 state_container.set_mode(crate::buffer::AppMode::Results);
160
161 reset_table();
163
164 Ok(())
165 }
166}