1use crate::error::{Error, Result};
7use std::sync::{Arc, Mutex, OnceLock};
8
9use super::{
10 config::{ParserBackend, ParserConfig},
11 nom_backend::NomParser,
12 traits::{CqlParser, CqlParserFactory, FactoryInfo, ParserBackendInfo},
13};
14
15#[derive(Debug, Default)]
17pub struct ParserFactory;
18
19impl ParserFactory {
20 pub fn create_default() -> Result<Arc<dyn CqlParser + Send + Sync>> {
22 Self::create(ParserConfig::default())
23 }
24
25 pub fn create(mut config: ParserConfig) -> Result<Arc<dyn CqlParser + Send + Sync>> {
27 config.validate().map_err(Error::configuration)?;
28
29 if matches!(config.backend, ParserBackend::Auto) {
30 config.backend = Self::select_optimal_backend(&config);
31 }
32
33 match config.backend.clone() {
34 ParserBackend::Nom => Ok(Arc::new(NomParser::new(config)?)),
35 ParserBackend::Auto => unreachable!("Auto resolved above"),
36 ParserBackend::Custom(name) => Err(Error::configuration(format!(
37 "Custom parser '{}' not available",
38 name
39 ))),
40 }
41 }
42
43 fn select_optimal_backend(_config: &ParserConfig) -> ParserBackend {
47 ParserBackend::Nom
48 }
49
50 pub fn get_available_backends() -> Vec<ParserBackendInfo> {
52 vec![NomParser::backend_info()]
53 }
54
55 pub fn is_backend_available(backend: &ParserBackend) -> bool {
60 match backend {
61 ParserBackend::Nom | ParserBackend::Auto => true,
62 ParserBackend::Custom(_) => false,
63 }
64 }
65
66 pub fn recommend_backend(use_case: UseCase) -> ParserBackend {
70 match use_case {
71 UseCase::HighPerformance
72 | UseCase::Embedded
73 | UseCase::Batch
74 | UseCase::Development
75 | UseCase::Interactive
76 | UseCase::Production => ParserBackend::Nom,
77 }
78 }
79
80 pub fn create_for_use_case(use_case: UseCase) -> Result<Arc<dyn CqlParser + Send + Sync>> {
82 let backend = Self::recommend_backend(use_case.clone());
83 Self::create(Self::create_config_for_use_case(use_case, backend))
84 }
85
86 fn create_config_for_use_case(use_case: UseCase, backend: ParserBackend) -> ParserConfig {
87 use super::config::ParserFeature;
88 use std::time::Duration;
89
90 match use_case {
91 UseCase::HighPerformance => ParserConfig::fast().with_backend(backend),
92 UseCase::Development => ParserConfig::development().with_backend(backend),
93 UseCase::Production => ParserConfig::default().with_backend(backend),
94 UseCase::Embedded => ParserConfig::minimal().with_backend(backend),
95 UseCase::Interactive => ParserConfig::development()
96 .with_backend(backend)
97 .with_timeout(Duration::from_millis(100)),
98 UseCase::Batch => ParserConfig::fast()
99 .with_backend(backend)
100 .with_feature(ParserFeature::Parallel)
101 .with_timeout(Duration::from_secs(300)),
102 }
103 }
104}
105
106impl CqlParserFactory for ParserFactory {
107 fn create_parser(&self) -> Result<Box<dyn CqlParser>> {
108 self.create_parser_with_config(ParserConfig::default())
109 }
110
111 fn create_parser_with_config(&self, config: ParserConfig) -> Result<Box<dyn CqlParser>> {
112 Ok(Box::new(ParserWrapper {
113 inner: Self::create(config)?,
114 }))
115 }
116
117 fn factory_info(&self) -> FactoryInfo {
118 FactoryInfo {
119 name: "DefaultParserFactory".to_string(),
120 supported_backends: vec!["nom".to_string()],
121 default_backend: "auto".to_string(),
122 }
123 }
124}
125
126#[derive(Debug)]
130struct ParserWrapper {
131 inner: Arc<dyn CqlParser + Send + Sync>,
132}
133
134#[async_trait::async_trait]
135impl CqlParser for ParserWrapper {
136 async fn parse(&self, input: &str) -> Result<super::ast::CqlStatement> {
137 self.inner.parse(input).await
138 }
139
140 async fn parse_type(&self, input: &str) -> Result<super::ast::CqlDataType> {
141 self.inner.parse_type(input).await
142 }
143
144 async fn parse_expression(&self, input: &str) -> Result<super::ast::CqlExpression> {
145 self.inner.parse_expression(input).await
146 }
147
148 async fn parse_identifier(&self, input: &str) -> Result<super::ast::CqlIdentifier> {
149 self.inner.parse_identifier(input).await
150 }
151
152 async fn parse_literal(&self, input: &str) -> Result<super::ast::CqlLiteral> {
153 self.inner.parse_literal(input).await
154 }
155
156 async fn parse_column_definitions(&self, input: &str) -> Result<Vec<super::ast::CqlColumnDef>> {
157 self.inner.parse_column_definitions(input).await
158 }
159
160 async fn parse_table_options(&self, input: &str) -> Result<super::ast::CqlTableOptions> {
161 self.inner.parse_table_options(input).await
162 }
163
164 fn validate_syntax(&self, input: &str) -> bool {
165 self.inner.validate_syntax(input)
166 }
167
168 fn backend_info(&self) -> super::traits::ParserBackendInfo {
169 self.inner.backend_info()
170 }
171}
172
173#[derive(Debug, Clone, PartialEq)]
175pub enum UseCase {
176 HighPerformance,
178 Development,
180 Production,
182 Embedded,
184 Interactive,
186 Batch,
188}
189
190#[derive(Debug, Default)]
192pub struct ParserRegistry {
193 custom_factories: std::collections::HashMap<String, Box<dyn CqlParserFactory + Send + Sync>>,
194}
195
196impl ParserRegistry {
197 pub fn new() -> Self {
198 Self::default()
199 }
200
201 pub fn register_factory(
202 &mut self,
203 name: String,
204 factory: Box<dyn CqlParserFactory + Send + Sync>,
205 ) {
206 self.custom_factories.insert(name, factory);
207 }
208
209 pub fn get_factory(&self, name: &str) -> Option<&(dyn CqlParserFactory + Send + Sync)> {
210 self.custom_factories.get(name).map(|f| f.as_ref())
211 }
212
213 pub fn list_factories(&self) -> Vec<&str> {
214 self.custom_factories.keys().map(|s| s.as_str()).collect()
215 }
216
217 pub fn create_with_factory(
219 &self,
220 factory_name: &str,
221 config: ParserConfig,
222 ) -> Result<Box<dyn CqlParser>> {
223 self.get_factory(factory_name)
224 .ok_or_else(|| Error::configuration(format!("Factory '{}' not found", factory_name)))?
225 .create_parser_with_config(config)
226 }
227}
228
229static GLOBAL_REGISTRY: OnceLock<Mutex<ParserRegistry>> = OnceLock::new();
230
231pub fn register_global_factory(name: String, factory: Box<dyn CqlParserFactory + Send + Sync>) {
233 let registry = GLOBAL_REGISTRY.get_or_init(|| Mutex::new(ParserRegistry::new()));
234 let mut guard = registry.lock().unwrap_or_else(|e| e.into_inner());
235 guard.register_factory(name, factory);
236}
237
238pub mod benchmarks {
240 use super::*;
241 use std::time::{Duration, Instant};
242
243 #[derive(Debug, Clone)]
244 pub struct BenchmarkResult {
245 pub backend: String,
246 pub avg_parse_time: Duration,
247 pub min_parse_time: Duration,
248 pub max_parse_time: Duration,
249 pub success_rate: f64,
250 pub errors: Vec<String>,
251 }
252
253 impl BenchmarkResult {
254 fn failed(backend: &ParserBackend, error: String) -> Self {
255 Self {
256 backend: format!("{:?}", backend),
257 avg_parse_time: Duration::ZERO,
258 min_parse_time: Duration::ZERO,
259 max_parse_time: Duration::ZERO,
260 success_rate: 0.0,
261 errors: vec![error],
262 }
263 }
264 }
265
266 #[derive(Debug, Clone)]
267 pub struct BenchmarkConfig {
268 pub iterations: u32,
269 pub timeout: Duration,
270 pub test_cases: Vec<String>,
271 }
272
273 impl Default for BenchmarkConfig {
274 fn default() -> Self {
275 Self {
276 iterations: 100,
277 timeout: Duration::from_secs(1),
278 test_cases: vec![
279 "SELECT * FROM users".to_string(),
280 "INSERT INTO users (id, name) VALUES (?, ?)".to_string(),
281 "UPDATE users SET name = ? WHERE id = ?".to_string(),
282 "DELETE FROM users WHERE id = ?".to_string(),
283 "CREATE TABLE test (id UUID PRIMARY KEY, data TEXT)".to_string(),
284 ],
285 }
286 }
287 }
288
289 pub async fn benchmark_parsers(config: BenchmarkConfig) -> Vec<BenchmarkResult> {
291 let mut results = Vec::new();
292 for backend in [ParserBackend::Nom] {
293 if ParserFactory::is_backend_available(&backend) {
294 results.push(benchmark_backend(backend, &config).await);
295 }
296 }
297 results
298 }
299
300 async fn benchmark_backend(
301 backend: ParserBackend,
302 config: &BenchmarkConfig,
303 ) -> BenchmarkResult {
304 let parser_config = ParserConfig::default().with_backend(backend.clone());
305 let parser = match ParserFactory::create(parser_config) {
306 Ok(p) => p,
307 Err(e) => {
308 return BenchmarkResult::failed(&backend, format!("Failed to create parser: {}", e))
309 }
310 };
311
312 let mut times = Vec::new();
313 let mut errors = Vec::new();
314 let mut successes: u32 = 0;
315
316 for _ in 0..config.iterations {
317 for test_case in &config.test_cases {
318 let start = Instant::now();
319 match tokio::time::timeout(config.timeout, parser.parse(test_case)).await {
320 Ok(Ok(_)) => {
321 successes += 1;
322 times.push(start.elapsed());
323 }
324 Ok(Err(e)) => errors.push(format!("Parse error: {}", e)),
325 Err(_) => errors.push("Timeout".to_string()),
326 }
327 }
328 }
329
330 let total_attempts = config.iterations * config.test_cases.len() as u32;
331 let success_rate = f64::from(successes) / f64::from(total_attempts);
332 let avg_parse_time = if times.is_empty() {
333 Duration::ZERO
334 } else {
335 times.iter().sum::<Duration>() / times.len() as u32
336 };
337
338 BenchmarkResult {
339 backend: format!("{:?}", backend),
340 avg_parse_time,
341 min_parse_time: times.iter().min().copied().unwrap_or_default(),
342 max_parse_time: times.iter().max().copied().unwrap_or_default(),
343 success_rate,
344 errors,
345 }
346 }
347}
348
349#[cfg(test)]
350mod tests {
351 use super::*;
352
353 #[test]
354 fn test_factory_creation() {
355 let factory = ParserFactory;
356 let info = factory.factory_info();
357 assert_eq!(info.name, "DefaultParserFactory");
358 assert!(!info.supported_backends.is_empty());
359 }
360
361 #[test]
362 fn test_backend_availability() {
363 assert!(ParserFactory::is_backend_available(&ParserBackend::Nom));
364 assert!(ParserFactory::is_backend_available(&ParserBackend::Auto));
365 assert!(!ParserFactory::is_backend_available(
366 &ParserBackend::Custom("unknown".to_string())
367 ));
368 }
369
370 #[test]
371 fn test_backend_recommendation() {
372 for use_case in [
374 UseCase::HighPerformance,
375 UseCase::Development,
376 UseCase::Production,
377 UseCase::Embedded,
378 UseCase::Interactive,
379 UseCase::Batch,
380 ] {
381 assert_eq!(
382 ParserFactory::recommend_backend(use_case),
383 ParserBackend::Nom
384 );
385 }
386 }
387
388 #[test]
389 fn test_auto_backend_selection() {
390 let config = ParserConfig::fast();
392 assert_eq!(
393 ParserFactory::select_optimal_backend(&config),
394 ParserBackend::Nom
395 );
396
397 let config = ParserConfig::strict();
398 assert_eq!(
399 ParserFactory::select_optimal_backend(&config),
400 ParserBackend::Nom
401 );
402 }
403
404 #[test]
405 fn test_create_for_every_use_case_succeeds() {
406 for use_case in [
411 UseCase::HighPerformance,
412 UseCase::Development,
413 UseCase::Production,
414 UseCase::Embedded,
415 UseCase::Interactive,
416 UseCase::Batch,
417 ] {
418 let parser = ParserFactory::create_for_use_case(use_case.clone())
419 .unwrap_or_else(|e| panic!("create failed for {:?}: {}", use_case, e));
420 assert_eq!(parser.backend_info().name, "nom", "use case {:?}", use_case);
421 }
422 }
423
424 #[test]
425 fn test_parser_registry() {
426 let registry = ParserRegistry::new();
427 assert!(registry.list_factories().is_empty());
428 }
429}