1#![warn(missing_docs)]
33#![warn(clippy::all)]
34#![allow(clippy::module_name_repetitions)]
35
36pub mod cache;
37pub mod error;
38pub mod executor;
39pub mod explain;
40pub mod index;
41pub mod optimizer;
42pub mod parallel;
43pub mod parser;
44
45pub use cache::{CacheConfig, QueryCache};
46pub use error::{QueryError, Result};
47pub use executor::Executor;
48pub use explain::ExplainPlan;
49pub use optimizer::{OptimizedQuery, Optimizer, OptimizerConfig};
50pub use parser::{Statement, parse_sql};
51
52pub struct QueryEngine {
54 _parser_marker: std::marker::PhantomData<()>,
56 optimizer: Optimizer,
58 executor: Executor,
60 cache: QueryCache,
62}
63
64impl QueryEngine {
65 pub fn new() -> Self {
67 Self {
68 _parser_marker: std::marker::PhantomData,
69 optimizer: Optimizer::new(),
70 executor: Executor::new(),
71 cache: QueryCache::new(CacheConfig::default()),
72 }
73 }
74
75 pub fn with_config(optimizer_config: OptimizerConfig, cache_config: CacheConfig) -> Self {
77 Self {
78 _parser_marker: std::marker::PhantomData,
79 optimizer: Optimizer::with_config(optimizer_config),
80 executor: Executor::new(),
81 cache: QueryCache::new(cache_config),
82 }
83 }
84
85 pub fn optimizer(&self) -> &Optimizer {
87 &self.optimizer
88 }
89
90 pub fn executor(&mut self) -> &mut Executor {
92 &mut self.executor
93 }
94
95 pub fn cache(&self) -> &QueryCache {
97 &self.cache
98 }
99
100 pub async fn execute_sql(&mut self, sql: &str) -> Result<Vec<executor::scan::RecordBatch>> {
102 let statement = parse_sql(sql)?;
104
105 if let Some(cached) = self.cache.get(&statement) {
107 return Ok(cached);
108 }
109
110 let optimized = self.optimizer.optimize(statement.clone())?;
112
113 let results = self.executor.execute(&optimized.statement).await?;
115
116 self.cache.put(&statement, results.clone());
118
119 Ok(results)
120 }
121
122 pub fn explain_sql(&self, sql: &str) -> Result<ExplainPlan> {
124 let statement = parse_sql(sql)?;
125 let optimized = self.optimizer.optimize(statement)?;
126 Ok(ExplainPlan::from_optimized(&optimized))
127 }
128
129 pub fn register_data_source(
131 &mut self,
132 name: String,
133 source: std::sync::Arc<dyn executor::scan::DataSource>,
134 ) {
135 self.executor.register_data_source(name, source);
136 }
137
138 pub fn clear_cache(&self) {
140 self.cache.clear();
141 }
142
143 pub fn cache_statistics(&self) -> cache::CacheStatistics {
145 self.cache.statistics()
146 }
147}
148
149impl Default for QueryEngine {
150 fn default() -> Self {
151 Self::new()
152 }
153}
154
155#[cfg(test)]
156mod tests {
157 use super::*;
158
159 #[test]
160 fn test_query_engine_creation() {
161 let engine = QueryEngine::new();
162 assert!(engine.cache_statistics().hits == 0);
163 }
164
165 #[test]
166 fn test_parse_simple_query() -> Result<()> {
167 let sql = "SELECT id, name FROM users";
168 let statement = parse_sql(sql)?;
169
170 match statement {
171 Statement::Select(select) => {
172 assert_eq!(select.projection.len(), 2);
173 assert!(select.from.is_some());
174 }
175 }
176
177 Ok(())
178 }
179
180 #[test]
181 fn test_optimizer() -> Result<()> {
182 let sql = "SELECT * FROM users WHERE 1 + 1 = 2";
183 let statement = parse_sql(sql)?;
184
185 let optimizer = Optimizer::new();
186 let optimized = optimizer.optimize(statement)?;
187
188 assert!(optimized.original_cost.total() >= 0.0);
189 assert!(optimized.optimized_cost.total() >= 0.0);
190
191 Ok(())
192 }
193}