use crate::app_state_container::AppStateContainer;
use crate::config::config::BehaviorConfig;
use crate::data::data_view::DataView;
use crate::services::{QueryExecutionResult, QueryExecutionService};
use crate::ui::search::vim_search_adapter::VimSearchAdapter;
use anyhow::Result;
use std::cell::RefCell;
use tracing::{debug, info};
pub struct QueryOrchestrator {
query_execution_service: QueryExecutionService,
}
impl QueryOrchestrator {
#[must_use]
pub fn new(case_insensitive: bool, auto_hide_empty: bool) -> Self {
Self {
query_execution_service: QueryExecutionService::new(case_insensitive, auto_hide_empty),
}
}
#[must_use]
pub fn with_behavior_config(behavior_config: BehaviorConfig) -> Self {
Self {
query_execution_service: QueryExecutionService::with_behavior_config(behavior_config),
}
}
pub fn execute_query(
&mut self,
query: &str,
state_container: &mut AppStateContainer,
vim_search_adapter: &RefCell<VimSearchAdapter>,
) -> Result<QueryExecutionContext> {
info!(target: "query", "Executing query: {}", query);
self.clear_all_search_state(state_container, vim_search_adapter);
self.record_query_execution(query, state_container);
state_container.set_status_message(format!("Executing query: '{query}'..."));
let current_dataview = state_container.get_buffer_dataview();
let original_source = state_container.get_original_source();
if let Some(orig) = original_source {
debug!(
"QueryOrchestrator: Have original source with {} columns",
orig.column_count()
);
} else {
debug!("QueryOrchestrator: WARNING - No original source available!");
}
if let Some(view) = current_dataview {
debug!(
"QueryOrchestrator: Current view has {} columns, source has {} columns",
view.column_count(),
view.source().column_count()
);
}
let result =
self.query_execution_service
.execute(query, current_dataview, original_source)?;
self.clear_all_filters(state_container);
Ok(QueryExecutionContext {
result,
query: query.to_string(),
})
}
fn clear_all_search_state(
&self,
state_container: &mut AppStateContainer,
vim_search_adapter: &RefCell<VimSearchAdapter>,
) {
state_container.clear_search();
state_container.clear_column_search();
vim_search_adapter.borrow_mut().cancel_search();
}
fn record_query_execution(&self, query: &str, state_container: &mut AppStateContainer) {
state_container.set_last_query(query.to_string());
state_container.set_last_executed_query(query.to_string());
}
fn clear_all_filters(&self, state_container: &mut AppStateContainer) {
state_container.set_filter_pattern(String::new());
state_container.set_fuzzy_filter_pattern(String::new());
state_container.set_filter_active(false);
state_container.set_fuzzy_filter_active(false);
}
pub fn set_case_insensitive(&mut self, case_insensitive: bool) {
self.query_execution_service
.set_case_insensitive(case_insensitive);
}
pub fn set_auto_hide_empty(&mut self, auto_hide: bool) {
self.query_execution_service.set_auto_hide_empty(auto_hide);
}
}
pub struct QueryExecutionContext {
pub result: QueryExecutionResult,
pub query: String,
}
impl QueryExecutionContext {
pub fn apply_to_tui(
self,
state_container: &mut AppStateContainer,
update_viewport: impl FnOnce(DataView),
calculate_widths: impl FnOnce(),
reset_table: impl FnOnce(),
) -> Result<()> {
state_container.set_dataview(Some(self.result.dataview.clone()));
update_viewport(self.result.dataview.clone());
state_container
.update_data_size(self.result.stats.row_count, self.result.stats.column_count);
calculate_widths();
state_container.set_status_message(self.result.status_message());
state_container
.command_history_mut()
.add_entry_with_schema(
self.query.clone(),
true,
Some(self.result.stats.execution_time.as_millis() as u64),
self.result.column_names(),
Some(self.result.table_name()),
)?;
state_container.set_mode(crate::buffer::AppMode::Results);
reset_table();
Ok(())
}
}