sql_cli/services/
query_orchestrator.rs

1use 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
9/// Orchestrates the entire query execution flow
10/// This handles all the side effects and state management around query execution
11pub 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    /// Execute a query with all necessary state management
23    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        // 1. Clear all search-related state before executing new query
32        self.clear_all_search_state(state_container, vim_search_adapter);
33
34        // 2. Record the query being executed
35        self.record_query_execution(query, state_container);
36
37        // 3. Set executing status
38        state_container.set_status_message(format!("Executing query: '{}'...", query));
39
40        // 4. Execute the query
41        let current_dataview = state_container.get_buffer_dataview();
42        let original_source = state_container.get_original_source();
43
44        // Debug: log what we're passing to the query service
45        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        // 5. Clear any active filters (new query should start with clean state)
67        self.clear_all_filters(state_container);
68
69        // 6. Return the context for the TUI to apply
70        Ok(QueryExecutionContext {
71            result,
72            query: query.to_string(),
73        })
74    }
75
76    /// Clear all search-related state
77    fn clear_all_search_state(
78        &self,
79        state_container: &mut AppStateContainer,
80        vim_search_adapter: &RefCell<VimSearchAdapter>,
81    ) {
82        // Clear container search states
83        state_container.clear_search();
84        state_container.clear_column_search();
85
86        // Clear vim search adapter state
87        vim_search_adapter.borrow_mut().cancel_search();
88    }
89
90    /// Record that a query is being executed
91    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    /// Clear all filter-related state
97    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    /// Update service configuration
105    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
115/// Context returned from query execution
116pub struct QueryExecutionContext {
117    pub result: QueryExecutionResult,
118    pub query: String,
119}
120
121impl QueryExecutionContext {
122    /// Apply this context to the TUI state
123    /// This is what the TUI will call to update its state after query execution
124    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        // Apply the new DataView
132        state_container.set_dataview(Some(self.result.dataview.clone()));
133
134        // Update viewport (delegate to TUI)
135        update_viewport(self.result.dataview.clone());
136
137        // Update navigation state
138        state_container
139            .update_data_size(self.result.stats.row_count, self.result.stats.column_count);
140
141        // Calculate column widths (delegate to TUI)
142        calculate_widths();
143
144        // Update status message
145        state_container.set_status_message(self.result.status_message());
146
147        // Add to history
148        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        // Switch to results mode
159        state_container.set_mode(crate::buffer::AppMode::Results);
160
161        // Reset table (delegate to TUI)
162        reset_table();
163
164        Ok(())
165    }
166}