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