sql_cli/services/
query_execution_service.rs1use crate::data::data_view::DataView;
2use crate::data::query_engine::QueryEngine;
3use anyhow::Result;
4use std::sync::Arc;
5use std::time::Duration;
6use tracing::{debug, info};
7
8pub struct QueryExecutionResult {
10 pub dataview: DataView,
12
13 pub stats: QueryStats,
15
16 pub hidden_columns: Vec<String>,
18
19 pub query: String,
21}
22
23pub struct QueryStats {
25 pub row_count: usize,
26 pub column_count: usize,
27 pub execution_time: Duration,
28 pub query_engine_time: Duration,
29}
30
31pub struct QueryExecutionService {
33 case_insensitive: bool,
34 auto_hide_empty: bool,
35}
36
37impl QueryExecutionService {
38 pub fn new(case_insensitive: bool, auto_hide_empty: bool) -> Self {
39 Self {
40 case_insensitive,
41 auto_hide_empty,
42 }
43 }
44
45 pub fn execute(
48 &self,
49 query: &str,
50 current_dataview: Option<&DataView>,
51 original_source: Option<&crate::data::datatable::DataTable>,
52 ) -> Result<QueryExecutionResult> {
53 let source_table = if let Some(original) = original_source {
55 info!(
57 "QueryExecutionService: Using original source with {} columns: {:?}",
58 original.column_count(),
59 original.column_names()
60 );
61 debug!(
62 "QueryExecutionService: DEBUG - Using original source with {} columns for query",
63 original.column_count()
64 );
65 original.clone()
66 } else if let Some(view) = current_dataview {
67 info!(
69 "QueryExecutionService: WARNING - No original source, using current view's source with {} columns: {:?}",
70 view.source().column_count(),
71 view.source().column_names()
72 );
73 debug!(
74 "QueryExecutionService: DEBUG WARNING - No original source, using view source with {} columns",
75 view.source().column_count()
76 );
77 view.source().clone()
78 } else {
79 return Err(anyhow::anyhow!("No data loaded"));
80 };
81
82 let table_arc = Arc::new(source_table);
84
85 let query_start = std::time::Instant::now();
87 let engine = QueryEngine::with_case_insensitive(self.case_insensitive);
88 let mut new_dataview = engine.execute(table_arc, query)?;
89 let query_engine_time = query_start.elapsed();
90
91 let mut hidden_columns = Vec::new();
93 if self.auto_hide_empty {
94 let hidden = new_dataview.hide_empty_columns();
95 if hidden > 0 {
96 info!("Auto-hidden {} empty columns after query execution", hidden);
97 hidden_columns = vec![format!("{} columns", hidden)];
100 }
101 }
102
103 let stats = QueryStats {
105 row_count: new_dataview.row_count(),
106 column_count: new_dataview.column_count(),
107 execution_time: query_start.elapsed(),
108 query_engine_time,
109 };
110
111 Ok(QueryExecutionResult {
112 dataview: new_dataview,
113 stats,
114 hidden_columns,
115 query: query.to_string(),
116 })
117 }
118
119 pub fn set_case_insensitive(&mut self, case_insensitive: bool) {
121 self.case_insensitive = case_insensitive;
122 }
123
124 pub fn set_auto_hide_empty(&mut self, auto_hide: bool) {
125 self.auto_hide_empty = auto_hide;
126 }
127}
128
129impl QueryExecutionResult {
130 pub fn status_message(&self) -> String {
132 let hidden_msg = if !self.hidden_columns.is_empty() {
133 format!(" ({} auto-hidden)", self.hidden_columns.len())
134 } else {
135 String::new()
136 };
137
138 format!(
139 "Query executed: {} rows, {} columns{} ({} ms)",
140 self.stats.row_count,
141 self.stats.column_count,
142 hidden_msg,
143 self.stats.execution_time.as_millis()
144 )
145 }
146
147 pub fn column_names(&self) -> Vec<String> {
149 self.dataview.column_names()
150 }
151
152 pub fn table_name(&self) -> String {
154 self.dataview.source().name.clone()
155 }
156}