Skip to main content

agentic_evolve_core/storage/
index.rs

1//! PatternIndex — fast lookup by signature, domain, tags.
2
3use std::collections::{HashMap, HashSet};
4
5use crate::types::pattern::Pattern;
6
7/// In-memory index for fast pattern lookup.
8#[derive(Debug, Default)]
9pub struct PatternIndex {
10    by_name: HashMap<String, HashSet<String>>,
11    by_domain: HashMap<String, HashSet<String>>,
12    by_language: HashMap<String, HashSet<String>>,
13    by_tag: HashMap<String, HashSet<String>>,
14    by_return_type: HashMap<String, HashSet<String>>,
15}
16
17impl PatternIndex {
18    pub fn new() -> Self {
19        Self::default()
20    }
21
22    pub fn add(&mut self, pattern: &Pattern) {
23        let id = pattern.id.as_str().to_string();
24
25        self.by_name
26            .entry(pattern.name.to_lowercase())
27            .or_default()
28            .insert(id.clone());
29
30        self.by_domain
31            .entry(pattern.domain.to_lowercase())
32            .or_default()
33            .insert(id.clone());
34
35        self.by_language
36            .entry(pattern.language.as_str().to_string())
37            .or_default()
38            .insert(id.clone());
39
40        for tag in &pattern.tags {
41            self.by_tag
42                .entry(tag.to_lowercase())
43                .or_default()
44                .insert(id.clone());
45        }
46
47        if let Some(ret) = &pattern.signature.return_type {
48            self.by_return_type
49                .entry(ret.to_lowercase())
50                .or_default()
51                .insert(id.clone());
52        }
53    }
54
55    pub fn remove(&mut self, pattern: &Pattern) {
56        let id = pattern.id.as_str();
57        self.by_name.values_mut().for_each(|s| {
58            s.remove(id);
59        });
60        self.by_domain.values_mut().for_each(|s| {
61            s.remove(id);
62        });
63        self.by_language.values_mut().for_each(|s| {
64            s.remove(id);
65        });
66        self.by_tag.values_mut().for_each(|s| {
67            s.remove(id);
68        });
69        self.by_return_type.values_mut().for_each(|s| {
70            s.remove(id);
71        });
72    }
73
74    pub fn find_by_name(&self, name: &str) -> Vec<String> {
75        self.by_name
76            .get(&name.to_lowercase())
77            .map(|s| s.iter().cloned().collect())
78            .unwrap_or_default()
79    }
80
81    pub fn find_by_domain(&self, domain: &str) -> Vec<String> {
82        self.by_domain
83            .get(&domain.to_lowercase())
84            .map(|s| s.iter().cloned().collect())
85            .unwrap_or_default()
86    }
87
88    pub fn find_by_language(&self, language: &str) -> Vec<String> {
89        self.by_language
90            .get(language)
91            .map(|s| s.iter().cloned().collect())
92            .unwrap_or_default()
93    }
94
95    pub fn find_by_tag(&self, tag: &str) -> Vec<String> {
96        self.by_tag
97            .get(&tag.to_lowercase())
98            .map(|s| s.iter().cloned().collect())
99            .unwrap_or_default()
100    }
101
102    pub fn find_by_return_type(&self, return_type: &str) -> Vec<String> {
103        self.by_return_type
104            .get(&return_type.to_lowercase())
105            .map(|s| s.iter().cloned().collect())
106            .unwrap_or_default()
107    }
108
109    pub fn search(&self, query: &str) -> HashSet<String> {
110        let query_lower = query.to_lowercase();
111        let mut results = HashSet::new();
112
113        for (key, ids) in &self.by_name {
114            if key.contains(&query_lower) {
115                results.extend(ids.iter().cloned());
116            }
117        }
118        for (key, ids) in &self.by_domain {
119            if key.contains(&query_lower) {
120                results.extend(ids.iter().cloned());
121            }
122        }
123        for (key, ids) in &self.by_tag {
124            if key.contains(&query_lower) {
125                results.extend(ids.iter().cloned());
126            }
127        }
128        results
129    }
130
131    pub fn total_indexed(&self) -> usize {
132        let mut all = HashSet::new();
133        for ids in self.by_name.values() {
134            all.extend(ids.iter().cloned());
135        }
136        all.len()
137    }
138
139    pub fn clear(&mut self) {
140        self.by_name.clear();
141        self.by_domain.clear();
142        self.by_language.clear();
143        self.by_tag.clear();
144        self.by_return_type.clear();
145    }
146}