agcodex_core/code_tools/
queries.rs

1//! Comprehensive tree-sitter query library for AGCodex
2//!
3//! This module provides language-specific query patterns for extracting:
4//! - Functions and methods
5//! - Classes, structs, interfaces, traits
6//! - Import/export statements
7//! - Symbol definitions (variables, constants, types)
8//!
9//! # Architecture
10//!
11//! ```text
12//! QueryLibrary
13//! ├── QueryBuilder    - Generates language-specific queries
14//! ├── QueryTemplates  - Pre-defined query patterns
15//! ├── QueryCache      - Compiled query caching
16//! └── QueryExecutor   - Optimized execution engine
17//! ```
18//!
19//! # Performance Characteristics
20//! - Query compilation: <10ms (cached: <1ms)
21//! - Cache hit rate: >90% for common patterns
22//! - Memory usage: O(languages × query_types)
23//! - Concurrency: Lock-free via DashMap
24
25use crate::code_tools::ToolError;
26use agcodex_ast::Language;
27use dashmap::DashMap;
28use std::collections::HashMap;
29use std::sync::Arc;
30use thiserror::Error;
31use tree_sitter::Query;
32
33/// Errors specific to query operations
34#[derive(Debug, Error)]
35pub enum QueryError {
36    #[error("unsupported language: {language}")]
37    UnsupportedLanguage { language: String },
38
39    #[error("invalid query type: {query_type} for language {language}")]
40    InvalidQueryType {
41        query_type: String,
42        language: String,
43    },
44
45    #[error("query compilation failed: {details}")]
46    CompilationFailed { details: String },
47
48    #[error("template not found: {template_name}")]
49    TemplateNotFound { template_name: String },
50
51    #[error("query execution failed: {reason}")]
52    ExecutionFailed { reason: String },
53}
54
55impl From<QueryError> for ToolError {
56    fn from(err: QueryError) -> Self {
57        ToolError::InvalidQuery(err.to_string())
58    }
59}
60
61/// Types of structural queries supported
62#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
63pub enum QueryType {
64    /// Extract function definitions and declarations
65    Functions,
66    /// Extract class/struct/interface/trait definitions
67    Classes,
68    /// Extract import/export/use statements
69    Imports,
70    /// Extract variable/constant/type symbol definitions
71    Symbols,
72    /// Extract method definitions within classes
73    Methods,
74    /// Extract constructor/destructor definitions
75    Constructors,
76    /// Extract interface/trait method signatures
77    Signatures,
78    /// Extract module/package declarations
79    Modules,
80}
81
82/// A compiled query result with metadata
83#[derive(Debug, Clone)]
84pub struct CompiledQuery {
85    /// The compiled tree-sitter query
86    pub query: Arc<Query>,
87    /// Language this query is compiled for
88    pub language: Language,
89    /// Type of structural elements this query extracts
90    pub query_type: QueryType,
91    /// Human-readable description
92    pub description: String,
93    /// Capture names used in the query
94    pub capture_names: Vec<String>,
95}
96
97/// Cache key for compiled queries
98#[derive(Debug, Clone, Hash, PartialEq, Eq)]
99struct CacheKey {
100    language: Language,
101    query_type: QueryType,
102    variant: Option<String>, // For parameterized queries
103}
104
105/// Thread-safe cache for compiled queries
106#[derive(Debug)]
107pub struct QueryCache {
108    /// Compiled queries indexed by (language, query_type, variant)
109    cache: DashMap<CacheKey, Arc<CompiledQuery>>,
110    /// Cache statistics for monitoring
111    stats: DashMap<String, u64>,
112}
113
114impl QueryCache {
115    /// Create a new query cache
116    pub fn new() -> Self {
117        Self {
118            cache: DashMap::new(),
119            stats: DashMap::new(),
120        }
121    }
122
123    /// Get a compiled query from cache
124    pub fn get(
125        &self,
126        language: Language,
127        query_type: QueryType,
128        variant: Option<&str>,
129    ) -> Option<Arc<CompiledQuery>> {
130        let key = CacheKey {
131            language,
132            query_type,
133            variant: variant.map(|s| s.to_string()),
134        };
135
136        if let Some(query) = self.cache.get(&key) {
137            self.increment_stat("cache_hits");
138            Some(query.clone())
139        } else {
140            self.increment_stat("cache_misses");
141            None
142        }
143    }
144
145    /// Store a compiled query in cache
146    pub fn insert(&self, compiled: Arc<CompiledQuery>, variant: Option<&str>) {
147        let key = CacheKey {
148            language: compiled.language,
149            query_type: compiled.query_type,
150            variant: variant.map(|s| s.to_string()),
151        };
152
153        self.cache.insert(key, compiled);
154        self.increment_stat("cache_insertions");
155    }
156
157    /// Get cache statistics
158    pub fn stats(&self) -> HashMap<String, u64> {
159        self.stats
160            .iter()
161            .map(|entry| (entry.key().clone(), *entry.value()))
162            .collect()
163    }
164
165    /// Clear all cached queries
166    pub fn clear(&self) {
167        self.cache.clear();
168        self.increment_stat("cache_clears");
169    }
170
171    /// Get cache size
172    pub fn size(&self) -> usize {
173        self.cache.len()
174    }
175
176    fn increment_stat(&self, stat_name: &str) {
177        *self.stats.entry(stat_name.to_string()).or_insert(0) += 1;
178    }
179}
180
181impl Default for QueryCache {
182    fn default() -> Self {
183        Self::new()
184    }
185}
186
187/// Language-specific query templates
188#[derive(Debug, Clone)]
189pub struct QueryTemplates {
190    /// Templates for each language and query type
191    templates: HashMap<(Language, QueryType), &'static str>,
192}
193
194impl QueryTemplates {
195    /// Create a new query templates collection
196    pub fn new() -> Self {
197        let mut templates = HashMap::new();
198
199        // === RUST QUERIES ===
200        Self::add_rust_templates(&mut templates);
201
202        // === PYTHON QUERIES ===
203        Self::add_python_templates(&mut templates);
204
205        // === JAVASCRIPT/TYPESCRIPT QUERIES ===
206        Self::add_javascript_templates(&mut templates);
207
208        // === GO QUERIES ===
209        Self::add_go_templates(&mut templates);
210
211        // === JAVA QUERIES ===
212        Self::add_java_templates(&mut templates);
213
214        // === C/C++ QUERIES ===
215        Self::add_c_cpp_templates(&mut templates);
216
217        Self { templates }
218    }
219
220    /// Get a query template for a language and query type
221    pub fn get(&self, language: Language, query_type: &QueryType) -> Option<&'static str> {
222        self.templates.get(&(language, *query_type)).copied()
223    }
224
225    /// Get all supported query types for a language
226    pub fn supported_queries(&self, language: Language) -> Vec<QueryType> {
227        self.templates
228            .keys()
229            .filter(|(lang, _)| *lang == language)
230            .map(|(_, query_type)| *query_type)
231            .collect()
232    }
233
234    // === RUST QUERY TEMPLATES ===
235    fn add_rust_templates(templates: &mut HashMap<(Language, QueryType), &'static str>) {
236        templates.insert(
237            (Language::Rust, QueryType::Functions),
238            r#"
239[
240  (function_item 
241    name: (identifier) @name
242    parameters: (parameters) @params
243    body: (block)? @body) @function
244  (associated_item
245    (function_item 
246      name: (identifier) @name
247      parameters: (parameters) @params
248      body: (block)? @body) @function)
249]
250"#,
251        );
252
253        templates.insert(
254            (Language::Rust, QueryType::Classes),
255            r#"
256[
257  (struct_item 
258    name: (type_identifier) @name
259    body: (field_declaration_list)? @body) @struct
260  (enum_item 
261    name: (type_identifier) @name
262    body: (enum_variant_list) @body) @enum
263  (union_item 
264    name: (type_identifier) @name
265    body: (field_declaration_list) @body) @union
266  (trait_item 
267    name: (type_identifier) @name
268    body: (declaration_list) @body) @trait
269  (impl_item 
270    trait: (type_identifier)? @trait_name
271    type: (type_identifier) @type_name
272    body: (declaration_list) @body) @impl
273]
274"#,
275        );
276
277        templates.insert(
278            (Language::Rust, QueryType::Imports),
279            r#"
280[
281  (use_declaration
282    argument: (use_clause) @clause) @import
283  (extern_crate_declaration
284    name: (identifier) @name
285    rename: (identifier)? @rename) @extern_crate
286  (mod_item
287    name: (identifier) @name) @module
288]
289"#,
290        );
291
292        templates.insert(
293            (Language::Rust, QueryType::Symbols),
294            r#"
295[
296  (let_declaration
297    pattern: (identifier) @name
298    type: (_)? @type
299    value: (_)? @value) @variable
300  (const_item
301    name: (identifier) @name
302    type: (_) @type
303    value: (_) @value) @constant
304  (static_item
305    name: (identifier) @name
306    type: (_) @type
307    value: (_) @value) @static
308  (type_item
309    name: (type_identifier) @name
310    type: (_) @type) @type_alias
311]
312"#,
313        );
314
315        templates.insert(
316            (Language::Rust, QueryType::Methods),
317            r#"
318(impl_item
319  body: (declaration_list
320    (function_item
321      name: (identifier) @name
322      parameters: (parameters) @params
323      body: (block)? @body) @method))
324"#,
325        );
326    }
327
328    // === PYTHON QUERY TEMPLATES ===
329    fn add_python_templates(templates: &mut HashMap<(Language, QueryType), &'static str>) {
330        templates.insert(
331            (Language::Python, QueryType::Functions),
332            r#"
333[
334  (function_definition
335    name: (identifier) @name
336    parameters: (parameters) @params
337    body: (block) @body) @function
338  (async_function_definition
339    name: (identifier) @name
340    parameters: (parameters) @params
341    body: (block) @body) @async_function
342]
343"#,
344        );
345
346        templates.insert(
347            (Language::Python, QueryType::Classes),
348            r#"
349(class_definition
350  name: (identifier) @name
351  superclasses: (argument_list)? @superclasses
352  body: (block) @body) @class
353"#,
354        );
355
356        templates.insert(
357            (Language::Python, QueryType::Imports),
358            r#"
359[
360  (import_statement
361    name: (dotted_name) @module) @import
362  (import_from_statement
363    module_name: (dotted_name)? @module
364    name: (dotted_name) @name) @import_from
365  (import_from_statement
366    module_name: (dotted_name)? @module
367    name: (aliased_import) @name) @import_from_alias
368]
369"#,
370        );
371
372        templates.insert(
373            (Language::Python, QueryType::Symbols),
374            r#"
375[
376  (assignment
377    left: (identifier) @name
378    right: (_) @value) @variable
379  (assignment
380    left: (pattern_list) @names
381    right: (_) @value) @multiple_assignment
382  (augmented_assignment
383    left: (identifier) @name
384    right: (_) @value) @augmented_variable
385]
386"#,
387        );
388
389        templates.insert(
390            (Language::Python, QueryType::Methods),
391            r#"
392(class_definition
393  body: (block
394    (function_definition
395      name: (identifier) @name
396      parameters: (parameters) @params
397      body: (block) @body) @method))
398"#,
399        );
400    }
401
402    // === JAVASCRIPT/TYPESCRIPT QUERY TEMPLATES ===
403    fn add_javascript_templates(templates: &mut HashMap<(Language, QueryType), &'static str>) {
404        let languages = [Language::JavaScript, Language::TypeScript];
405
406        for &lang in &languages {
407            templates.insert(
408                (lang, QueryType::Functions),
409                r#"
410[
411  (function_declaration
412    name: (identifier) @name
413    parameters: (formal_parameters) @params
414    body: (statement_block) @body) @function
415  (function_expression
416    name: (identifier)? @name
417    parameters: (formal_parameters) @params
418    body: (statement_block) @body) @function_expr
419  (arrow_function
420    parameters: (formal_parameters) @params
421    body: (_) @body) @arrow_function
422  (generator_function_declaration
423    name: (identifier) @name
424    parameters: (formal_parameters) @params
425    body: (statement_block) @body) @generator
426]
427"#,
428            );
429
430            templates.insert(
431                (lang, QueryType::Classes),
432                r#"
433[
434  (class_declaration
435    name: (identifier) @name
436    superclass: (class_heritage)? @superclass
437    body: (class_body) @body) @class
438  (class_expression
439    name: (identifier)? @name
440    superclass: (class_heritage)? @superclass
441    body: (class_body) @body) @class_expr
442]
443"#,
444            );
445
446            templates.insert(
447                (lang, QueryType::Imports),
448                r#"
449[
450  (import_statement
451    source: (string) @source
452    (import_clause
453      (named_imports) @named)?) @import
454  (import_statement
455    source: (string) @source
456    (import_clause
457      (namespace_import) @namespace)?) @import_namespace
458  (export_statement) @export
459]
460"#,
461            );
462
463            templates.insert(
464                (lang, QueryType::Methods),
465                r#"
466(class_body
467  (method_definition
468    name: (property_name) @name
469    parameters: (formal_parameters) @params
470    body: (statement_block) @body) @method)
471"#,
472            );
473
474            templates.insert(
475                (lang, QueryType::Symbols),
476                r#"
477[
478  (variable_declaration
479    (variable_declarator
480      name: (identifier) @name
481      value: (_)? @value)) @variable
482  (lexical_declaration
483    (variable_declarator
484      name: (identifier) @name
485      value: (_)? @value)) @lexical_variable
486]
487"#,
488            );
489        }
490    }
491
492    // === GO QUERY TEMPLATES ===
493    fn add_go_templates(templates: &mut HashMap<(Language, QueryType), &'static str>) {
494        templates.insert(
495            (Language::Go, QueryType::Functions),
496            r#"
497[
498  (function_declaration
499    name: (identifier) @name
500    parameters: (parameter_list) @params
501    result: (_)? @return_type
502    body: (block) @body) @function
503  (method_declaration
504    receiver: (parameter_list) @receiver
505    name: (identifier) @name
506    parameters: (parameter_list) @params
507    result: (_)? @return_type
508    body: (block) @body) @method
509]
510"#,
511        );
512
513        templates.insert(
514            (Language::Go, QueryType::Classes),
515            r#"
516[
517  (type_declaration
518    (type_spec
519      name: (type_identifier) @name
520      type: (struct_type) @struct_body)) @struct
521  (type_declaration
522    (type_spec
523      name: (type_identifier) @name
524      type: (interface_type) @interface_body)) @interface
525]
526"#,
527        );
528
529        templates.insert(
530            (Language::Go, QueryType::Imports),
531            r#"
532[
533  (import_declaration
534    (import_spec
535      name: (package_identifier)? @alias
536      path: (interpreted_string_literal) @path)) @import
537  (package_clause
538    (package_identifier) @package_name) @package
539]
540"#,
541        );
542
543        templates.insert(
544            (Language::Go, QueryType::Symbols),
545            r#"
546[
547  (var_declaration
548    (var_spec
549      name: (identifier) @name
550      type: (_)? @type
551      value: (_)? @value)) @variable
552  (const_declaration
553    (const_spec
554      name: (identifier) @name
555      type: (_)? @type
556      value: (_) @value)) @constant
557]
558"#,
559        );
560    }
561
562    // === JAVA QUERY TEMPLATES ===
563    fn add_java_templates(templates: &mut HashMap<(Language, QueryType), &'static str>) {
564        templates.insert(
565            (Language::Java, QueryType::Functions),
566            r#"
567(method_declaration
568  (modifiers)? @modifiers
569  type: (_) @return_type
570  name: (identifier) @name
571  parameters: (formal_parameters) @params
572  body: (block)? @body) @method
573"#,
574        );
575
576        templates.insert(
577            (Language::Java, QueryType::Classes),
578            r#"
579[
580  (class_declaration
581    (modifiers)? @modifiers
582    name: (identifier) @name
583    superclass: (superclass)? @superclass
584    interfaces: (super_interfaces)? @interfaces
585    body: (class_body) @body) @class
586  (interface_declaration
587    (modifiers)? @modifiers
588    name: (identifier) @name
589    extends: (extends_interfaces)? @extends
590    body: (interface_body) @body) @interface
591  (enum_declaration
592    (modifiers)? @modifiers
593    name: (identifier) @name
594    interfaces: (super_interfaces)? @interfaces
595    body: (enum_body) @body) @enum
596]
597"#,
598        );
599
600        templates.insert(
601            (Language::Java, QueryType::Imports),
602            r#"
603[
604  (import_declaration
605    (scoped_identifier) @import_path) @import
606  (import_declaration
607    (asterisk) @wildcard) @wildcard_import
608  (package_declaration
609    (scoped_identifier) @package_name) @package
610]
611"#,
612        );
613
614        templates.insert(
615            (Language::Java, QueryType::Symbols),
616            r#"
617[
618  (field_declaration
619    (modifiers)? @modifiers
620    type: (_) @type
621    (variable_declarator
622      name: (identifier) @name
623      value: (_)? @value)) @field
624  (local_variable_declaration
625    type: (_) @type
626    (variable_declarator
627      name: (identifier) @name
628      value: (_)? @value)) @local_variable
629]
630"#,
631        );
632
633        templates.insert(
634            (Language::Java, QueryType::Constructors),
635            r#"
636(constructor_declaration
637  (modifiers)? @modifiers
638  name: (identifier) @name
639  parameters: (formal_parameters) @params
640  body: (constructor_body) @body) @constructor
641"#,
642        );
643    }
644
645    // === C/C++ QUERY TEMPLATES ===
646    fn add_c_cpp_templates(templates: &mut HashMap<(Language, QueryType), &'static str>) {
647        let languages = [Language::C, Language::Cpp];
648
649        for &lang in &languages {
650            templates.insert(
651                (lang, QueryType::Functions),
652                r#"
653[
654  (function_definition
655    type: (_) @return_type
656    declarator: (function_declarator
657      declarator: (_) @name
658      parameters: (parameter_list) @params)
659    body: (compound_statement) @body) @function
660  (declaration
661    type: (_) @return_type
662    declarator: (function_declarator
663      declarator: (_) @name
664      parameters: (parameter_list) @params)) @function_declaration
665]
666"#,
667            );
668
669            templates.insert(
670                (lang, QueryType::Classes),
671                r#"
672[
673  (struct_specifier
674    name: (type_identifier) @name
675    body: (field_declaration_list) @body) @struct
676  (union_specifier
677    name: (type_identifier) @name
678    body: (field_declaration_list) @body) @union
679  (enum_specifier
680    name: (type_identifier) @name
681    body: (enumerator_list) @body) @enum
682]
683"#,
684            );
685
686            templates.insert(
687                (lang, QueryType::Imports),
688                r#"
689[
690  (preproc_include
691    path: (string_literal) @path) @include
692  (preproc_include
693    path: (system_lib_string) @path) @include_system
694]
695"#,
696            );
697
698            templates.insert(
699                (lang, QueryType::Symbols),
700                r#"
701[
702  (declaration
703    type: (_) @type
704    declarator: (identifier) @name) @variable
705  (init_declarator
706    declarator: (identifier) @name
707    value: (_) @value) @initialized_variable
708  (preproc_def
709    name: (identifier) @name
710    value: (_)? @value) @macro
711]
712"#,
713            );
714        }
715
716        // C++ specific templates
717        templates.insert(
718            (Language::Cpp, QueryType::Classes),
719            r#"
720[
721  (class_specifier
722    name: (type_identifier) @name
723    base: (base_class_clause)? @base_classes
724    body: (field_declaration_list) @body) @class
725  (struct_specifier
726    name: (type_identifier) @name
727    base: (base_class_clause)? @base_classes
728    body: (field_declaration_list) @body) @struct
729  (union_specifier
730    name: (type_identifier) @name
731    body: (field_declaration_list) @body) @union
732  (enum_specifier
733    name: (type_identifier) @name
734    body: (enumerator_list) @body) @enum
735]
736"#,
737        );
738
739        templates.insert(
740            (Language::Cpp, QueryType::Imports),
741            r#"
742[
743  (preproc_include
744    path: (string_literal) @path) @include
745  (preproc_include
746    path: (system_lib_string) @path) @include_system
747  (using_declaration
748    (qualified_identifier) @name) @using
749  (namespace_definition
750    name: (identifier) @name
751    body: (declaration_list) @body) @namespace
752]
753"#,
754        );
755    }
756}
757
758impl Default for QueryTemplates {
759    fn default() -> Self {
760        Self::new()
761    }
762}
763
764/// Builder for constructing and compiling tree-sitter queries
765#[derive(Debug, Clone)]
766pub struct QueryBuilder {
767    /// Query templates for different languages
768    templates: Arc<QueryTemplates>,
769    /// Cache for compiled queries
770    cache: Arc<QueryCache>,
771}
772
773impl QueryBuilder {
774    /// Create a new query builder
775    pub fn new() -> Self {
776        Self {
777            templates: Arc::new(QueryTemplates::new()),
778            cache: Arc::new(QueryCache::new()),
779        }
780    }
781
782    /// Create with custom templates and cache
783    pub fn with_cache(cache: Arc<QueryCache>) -> Self {
784        Self {
785            templates: Arc::new(QueryTemplates::new()),
786            cache,
787        }
788    }
789
790    /// Build and compile a query for a specific language and type
791    pub fn build_query(
792        &self,
793        language: Language,
794        query_type: QueryType,
795        custom_template: Option<&str>,
796    ) -> Result<Arc<CompiledQuery>, QueryError> {
797        // Check cache first
798        if let Some(cached) = self.cache.get(language, query_type, None) {
799            return Ok(cached);
800        }
801
802        // Get query template
803        let template = if let Some(custom) = custom_template {
804            custom
805        } else {
806            self.templates.get(language, &query_type).ok_or_else(|| {
807                QueryError::InvalidQueryType {
808                    query_type: format!("{:?}", query_type),
809                    language: language.name().to_string(),
810                }
811            })?
812        };
813
814        // Compile the query
815        let ts_language = language.parser();
816        let query =
817            Query::new(&ts_language, template).map_err(|e| QueryError::CompilationFailed {
818                details: format!("Tree-sitter compilation error: {}", e),
819            })?;
820
821        // Extract capture names
822        let capture_names = query
823            .capture_names()
824            .iter()
825            .map(|&s| s.to_string())
826            .collect();
827
828        // Create compiled query
829        let compiled = Arc::new(CompiledQuery {
830            query: Arc::new(query),
831            language,
832            query_type,
833            description: format!("{:?} queries for {}", query_type, language.name()),
834            capture_names,
835        });
836
837        // Cache the result
838        self.cache.insert(compiled.clone(), None);
839
840        Ok(compiled)
841    }
842
843    /// Build a custom parameterized query
844    pub fn build_custom_query(
845        &self,
846        language: Language,
847        query_type: QueryType,
848        template: &str,
849        variant: &str,
850    ) -> Result<Arc<CompiledQuery>, QueryError> {
851        // Check cache with variant
852        if let Some(cached) = self.cache.get(language, query_type, Some(variant)) {
853            return Ok(cached);
854        }
855
856        // Compile the custom query
857        let ts_language = language.parser();
858        let query =
859            Query::new(&ts_language, template).map_err(|e| QueryError::CompilationFailed {
860                details: format!("Custom query compilation error: {}", e),
861            })?;
862
863        // Extract capture names
864        let capture_names = query
865            .capture_names()
866            .iter()
867            .map(|&s| s.to_string())
868            .collect();
869
870        // Create compiled query
871        let compiled = Arc::new(CompiledQuery {
872            query: Arc::new(query),
873            language,
874            query_type,
875            description: format!(
876                "Custom {:?} query ({}) for {}",
877                query_type,
878                variant,
879                language.name()
880            ),
881            capture_names,
882        });
883
884        // Cache with variant
885        self.cache.insert(compiled.clone(), Some(variant));
886
887        Ok(compiled)
888    }
889
890    /// Get all supported query types for a language
891    pub fn supported_queries(&self, language: Language) -> Vec<QueryType> {
892        self.templates.supported_queries(language)
893    }
894
895    /// Get cache statistics
896    pub fn cache_stats(&self) -> HashMap<String, u64> {
897        self.cache.stats()
898    }
899
900    /// Clear query cache
901    pub fn clear_cache(&self) {
902        self.cache.clear();
903    }
904}
905
906impl Default for QueryBuilder {
907    fn default() -> Self {
908        Self::new()
909    }
910}
911
912/// Main query library providing unified access to tree-sitter queries
913#[derive(Debug, Clone)]
914pub struct QueryLibrary {
915    /// Query builder for compiling queries
916    builder: QueryBuilder,
917    /// Shared cache across all operations
918    cache: Arc<QueryCache>,
919    /// Query templates
920    templates: Arc<QueryTemplates>,
921}
922
923impl QueryLibrary {
924    /// Create a new query library
925    pub fn new() -> Self {
926        let cache = Arc::new(QueryCache::new());
927        Self {
928            builder: QueryBuilder::with_cache(cache.clone()),
929            cache,
930            templates: Arc::new(QueryTemplates::new()),
931        }
932    }
933
934    /// Get a compiled query for a language and query type
935    pub fn get_query(
936        &self,
937        language: Language,
938        query_type: QueryType,
939    ) -> Result<Arc<CompiledQuery>, QueryError> {
940        self.builder.build_query(language, query_type, None)
941    }
942
943    /// Get a custom compiled query with specific template
944    pub fn get_custom_query(
945        &self,
946        language: Language,
947        query_type: QueryType,
948        template: &str,
949        variant: &str,
950    ) -> Result<Arc<CompiledQuery>, QueryError> {
951        self.builder
952            .build_custom_query(language, query_type, template, variant)
953    }
954
955    /// Check if a language supports a specific query type
956    pub fn supports_query(&self, language: Language, query_type: &QueryType) -> bool {
957        self.templates.get(language, query_type).is_some()
958    }
959
960    /// Get all supported languages
961    pub fn supported_languages(&self) -> Vec<Language> {
962        // This would typically come from the language registry
963        vec![
964            Language::Rust,
965            Language::Python,
966            Language::JavaScript,
967            Language::TypeScript,
968            Language::Go,
969            Language::Java,
970            Language::C,
971            Language::Cpp,
972        ]
973    }
974
975    /// Get all supported query types for a language
976    pub fn supported_query_types(&self, language: Language) -> Vec<QueryType> {
977        self.builder.supported_queries(language)
978    }
979
980    /// Get query library statistics
981    pub fn stats(&self) -> QueryLibraryStats {
982        let cache_stats = self.cache.stats();
983        QueryLibraryStats {
984            cache_size: self.cache.size(),
985            cache_hits: cache_stats.get("cache_hits").copied().unwrap_or(0),
986            cache_misses: cache_stats.get("cache_misses").copied().unwrap_or(0),
987            total_queries: cache_stats.get("cache_insertions").copied().unwrap_or(0),
988            supported_languages: self.supported_languages().len(),
989        }
990    }
991
992    /// Clear all cached queries
993    pub fn clear_cache(&self) {
994        self.cache.clear();
995    }
996
997    /// Precompile common queries for a language
998    pub fn precompile_language(&self, language: Language) -> Result<usize, QueryError> {
999        let query_types = self.supported_query_types(language);
1000        let mut compiled_count = 0;
1001
1002        for query_type in query_types {
1003            match self.get_query(language, query_type) {
1004                Ok(_) => compiled_count += 1,
1005                Err(e) => {
1006                    // Log warning but continue with other queries
1007                    eprintln!(
1008                        "Warning: Failed to precompile {:?} for {}: {}",
1009                        query_type,
1010                        language.name(),
1011                        e
1012                    );
1013                }
1014            }
1015        }
1016
1017        Ok(compiled_count)
1018    }
1019
1020    /// Precompile all supported queries
1021    pub fn precompile_all(&self) -> Result<usize, QueryError> {
1022        let languages = self.supported_languages();
1023        let mut total_compiled = 0;
1024
1025        for language in languages {
1026            match self.precompile_language(language) {
1027                Ok(count) => total_compiled += count,
1028                Err(e) => {
1029                    eprintln!(
1030                        "Warning: Failed to precompile queries for {}: {}",
1031                        language.name(),
1032                        e
1033                    );
1034                }
1035            }
1036        }
1037
1038        Ok(total_compiled)
1039    }
1040}
1041
1042impl Default for QueryLibrary {
1043    fn default() -> Self {
1044        Self::new()
1045    }
1046}
1047
1048/// Statistics about the query library
1049#[derive(Debug, Clone)]
1050pub struct QueryLibraryStats {
1051    /// Number of cached queries
1052    pub cache_size: usize,
1053    /// Number of cache hits
1054    pub cache_hits: u64,
1055    /// Number of cache misses
1056    pub cache_misses: u64,
1057    /// Total queries compiled
1058    pub total_queries: u64,
1059    /// Number of supported languages
1060    pub supported_languages: usize,
1061}
1062
1063impl QueryLibraryStats {
1064    /// Calculate cache hit rate
1065    pub fn hit_rate(&self) -> f64 {
1066        let total_requests = self.cache_hits + self.cache_misses;
1067        if total_requests == 0 {
1068            0.0
1069        } else {
1070            self.cache_hits as f64 / total_requests as f64
1071        }
1072    }
1073}
1074
1075#[cfg(test)]
1076mod tests {
1077    use super::*;
1078
1079    #[test]
1080    fn test_query_cache_basic_operations() {
1081        let cache = QueryCache::new();
1082        assert_eq!(cache.size(), 0);
1083
1084        // Test cache miss
1085        assert!(
1086            cache
1087                .get(Language::Rust, QueryType::Functions, None)
1088                .is_none()
1089        );
1090
1091        // Test stats
1092        let stats = cache.stats();
1093        assert_eq!(stats.get("cache_misses"), Some(&1));
1094    }
1095
1096    #[test]
1097    fn test_query_templates_rust() {
1098        let templates = QueryTemplates::new();
1099
1100        // Test Rust function template exists
1101        assert!(
1102            templates
1103                .get(Language::Rust, &QueryType::Functions)
1104                .is_some()
1105        );
1106        assert!(templates.get(Language::Rust, &QueryType::Classes).is_some());
1107        assert!(templates.get(Language::Rust, &QueryType::Imports).is_some());
1108
1109        // Test supported queries
1110        let supported = templates.supported_queries(Language::Rust);
1111        assert!(supported.contains(&QueryType::Functions));
1112        assert!(supported.contains(&QueryType::Classes));
1113        assert!(supported.contains(&QueryType::Imports));
1114    }
1115
1116    #[test]
1117    fn test_query_library_creation() {
1118        let library = QueryLibrary::new();
1119
1120        // Test supported languages
1121        let languages = library.supported_languages();
1122        assert!(languages.contains(&Language::Rust));
1123        assert!(languages.contains(&Language::Python));
1124        assert!(languages.contains(&Language::JavaScript));
1125
1126        // Test initial stats
1127        let stats = library.stats();
1128        assert_eq!(stats.cache_size, 0);
1129        assert_eq!(stats.cache_hits, 0);
1130        assert_eq!(stats.cache_misses, 0);
1131    }
1132
1133    #[test]
1134    fn test_query_library_support_check() {
1135        let library = QueryLibrary::new();
1136
1137        // Test known supported combinations
1138        assert!(library.supports_query(Language::Rust, &QueryType::Functions));
1139        assert!(library.supports_query(Language::Python, &QueryType::Classes));
1140        assert!(library.supports_query(Language::JavaScript, &QueryType::Imports));
1141
1142        // Test query types for specific language
1143        let rust_queries = library.supported_query_types(Language::Rust);
1144        assert!(!rust_queries.is_empty());
1145        assert!(rust_queries.contains(&QueryType::Functions));
1146    }
1147
1148    #[test]
1149    fn test_stats_hit_rate_calculation() {
1150        let stats = QueryLibraryStats {
1151            cache_size: 10,
1152            cache_hits: 8,
1153            cache_misses: 2,
1154            total_queries: 10,
1155            supported_languages: 5,
1156        };
1157
1158        assert_eq!(stats.hit_rate(), 0.8);
1159
1160        let empty_stats = QueryLibraryStats {
1161            cache_size: 0,
1162            cache_hits: 0,
1163            cache_misses: 0,
1164            total_queries: 0,
1165            supported_languages: 0,
1166        };
1167
1168        assert_eq!(empty_stats.hit_rate(), 0.0);
1169    }
1170}