sql_cli/services/
application_orchestrator.rs

1use crate::services::{DataLoaderService, QueryOrchestrator};
2use crate::ui::enhanced_tui::EnhancedTuiApp;
3use anyhow::Result;
4use tracing::info;
5
6/// Orchestrates the entire application lifecycle
7/// This removes file loading knowledge from the TUI
8pub struct ApplicationOrchestrator {
9    data_loader: DataLoaderService,
10    query_orchestrator: QueryOrchestrator,
11}
12
13impl ApplicationOrchestrator {
14    #[must_use]
15    pub fn new(case_insensitive: bool, auto_hide_empty: bool) -> Self {
16        Self {
17            data_loader: DataLoaderService::new(case_insensitive),
18            query_orchestrator: QueryOrchestrator::new(case_insensitive, auto_hide_empty),
19        }
20    }
21
22    /// Create a TUI with an initial file loaded
23    /// The TUI doesn't need to know about file types or loading
24    pub fn create_tui_with_file(&self, file_path: &str) -> Result<EnhancedTuiApp> {
25        info!("Creating TUI with file: {}", file_path);
26
27        // Load the file using the data loader service
28        let load_result = self.data_loader.load_file(file_path)?;
29
30        // Get the status message before moving dataview
31        let status_message = load_result.status_message();
32        let source_path = load_result.source_path.clone();
33        let table_name = load_result.table_name.clone();
34        let raw_table_name = load_result.raw_table_name.clone();
35
36        // Create the TUI with just a DataView
37        let mut app = EnhancedTuiApp::new_with_dataview(load_result.dataview, &source_path)?;
38
39        // Set the initial status message
40        app.set_status_message(status_message);
41
42        // Pre-populate the SQL command with SELECT * FROM table
43        app.set_sql_query(&table_name, &raw_table_name);
44
45        Ok(app)
46    }
47
48    /// Load additional files into existing TUI
49    pub fn load_additional_file(&self, app: &mut EnhancedTuiApp, file_path: &str) -> Result<()> {
50        info!("Loading additional file: {}", file_path);
51
52        // Load the file
53        let load_result = self.data_loader.load_file(file_path)?;
54
55        // Get the status message before moving dataview
56        let status_message = load_result.status_message();
57        let source_path = load_result.source_path.clone();
58        let table_name = load_result.table_name.clone();
59        let raw_table_name = load_result.raw_table_name.clone();
60
61        // Add to the TUI (it will create a new buffer)
62        app.add_dataview(load_result.dataview, &source_path)?;
63
64        // Set status message
65        app.set_status_message(status_message);
66
67        // Pre-populate the SQL command with SELECT * FROM table for new buffer
68        app.set_sql_query(&table_name, &raw_table_name);
69
70        Ok(())
71    }
72
73    /// Execute a query in the TUI
74    /// Note: This is a simplified version - the TUI itself should use `execute_query_v2`
75    /// which properly handles the closures for `apply_to_tui`
76    pub fn execute_query(&mut self, app: &mut EnhancedTuiApp, query: &str) -> Result<()> {
77        // For now, just delegate to the TUI's own execute_query_v2 method
78        // This avoids the borrowing issues with closures
79        app.execute_query_v2(query)
80    }
81}
82
83/// Builder pattern for creating the orchestrator with configuration
84pub struct ApplicationOrchestratorBuilder {
85    case_insensitive: bool,
86    auto_hide_empty: bool,
87}
88
89impl Default for ApplicationOrchestratorBuilder {
90    fn default() -> Self {
91        Self::new()
92    }
93}
94
95impl ApplicationOrchestratorBuilder {
96    #[must_use]
97    pub fn new() -> Self {
98        Self {
99            case_insensitive: false,
100            auto_hide_empty: false,
101        }
102    }
103
104    #[must_use]
105    pub fn with_case_insensitive(mut self, value: bool) -> Self {
106        self.case_insensitive = value;
107        self
108    }
109
110    #[must_use]
111    pub fn with_auto_hide_empty(mut self, value: bool) -> Self {
112        self.auto_hide_empty = value;
113        self
114    }
115
116    #[must_use]
117    pub fn build(self) -> ApplicationOrchestrator {
118        ApplicationOrchestrator::new(self.case_insensitive, self.auto_hide_empty)
119    }
120}