Skip to main content

open_kioku_storage/
lib.rs

1use open_kioku_core::{
2    CodeChunk, File, FileId, GraphEdge, GraphNode, ImpactReport, Import, IndexManifest,
3    SearchResult, Symbol, SymbolId, SymbolOccurrence, TestTarget,
4};
5use open_kioku_errors::Result;
6use std::path::Path;
7
8pub trait MetadataStore: Send + Sync {
9    fn initialize(&self) -> Result<()>;
10    fn put_manifest(&self, manifest: &IndexManifest) -> Result<()>;
11    fn manifest(&self) -> Result<Option<IndexManifest>>;
12    fn replace_index(&self, data: IndexData<'_>) -> Result<()>;
13    fn list_files(&self, limit: usize, offset: usize) -> Result<Vec<File>>;
14    fn get_file_by_path(&self, path: &Path) -> Result<Option<File>>;
15    fn list_symbols(&self, query: Option<&str>, limit: usize, offset: usize)
16        -> Result<Vec<Symbol>>;
17    fn symbol_by_id(&self, id: &SymbolId) -> Result<Option<Symbol>>;
18    fn chunks_for_file(&self, file_id: &FileId) -> Result<Vec<CodeChunk>>;
19    fn all_chunks(&self) -> Result<Vec<CodeChunk>>;
20    fn tests(&self) -> Result<Vec<TestTarget>>;
21    fn imports(&self) -> Result<Vec<Import>>;
22    fn references_for_symbol(&self, id: &SymbolId, limit: usize) -> Result<Vec<SymbolOccurrence>>;
23    fn occurrences_for_file(&self, file_id: &FileId) -> Result<Vec<SymbolOccurrence>>;
24    fn symbols_for_file(&self, _file_id: &FileId) -> Result<Vec<Symbol>> {
25        Ok(Vec::new())
26    }
27    fn find_chunks_containing(&self, query: &str, limit: usize) -> Result<Vec<CodeChunk>> {
28        let chunks = self.all_chunks()?;
29        let mut results = Vec::new();
30        for chunk in chunks {
31            if chunk.text.contains(query) {
32                results.push(chunk);
33                if results.len() >= limit {
34                    break;
35                }
36            }
37        }
38        Ok(results)
39    }
40    fn find_files_by_path_pattern(&self, pattern: &str) -> Result<Vec<File>> {
41        let files = self.list_files(usize::MAX, 0)?;
42        let lower_pattern = pattern.to_ascii_lowercase();
43        Ok(files
44            .into_iter()
45            .filter(|f| {
46                f.path
47                    .to_string_lossy()
48                    .to_ascii_lowercase()
49                    .contains(&lower_pattern)
50            })
51            .collect())
52    }
53    fn tests_for_files(&self, file_ids: &[FileId]) -> Result<Vec<TestTarget>> {
54        let tests = self.tests()?;
55        let set = file_ids.iter().collect::<std::collections::HashSet<_>>();
56        Ok(tests
57            .into_iter()
58            .filter(|t| set.contains(&t.file_id))
59            .collect())
60    }
61}
62
63pub struct IndexData<'a> {
64    pub manifest: &'a IndexManifest,
65    pub files: &'a [File],
66    pub symbols: &'a [Symbol],
67    pub chunks: &'a [CodeChunk],
68    pub tests: &'a [TestTarget],
69    pub imports: &'a [Import],
70    pub occurrences: &'a [SymbolOccurrence],
71}
72
73pub trait GraphStore: Send + Sync {
74    fn replace_graph(&self, nodes: &[GraphNode], edges: &[GraphEdge]) -> Result<()>;
75    fn neighbors(&self, node: &str, limit: usize) -> Result<(Vec<GraphNode>, Vec<GraphEdge>)>;
76    fn shortest_path(&self, from: &str, to: &str, max_depth: usize) -> Result<Vec<GraphEdge>>;
77}
78
79pub trait SearchIndex: Send + Sync {
80    fn rebuild(&mut self, chunks: &[CodeChunk], files: &[File], symbols: &[Symbol]) -> Result<()>;
81    fn search(&self, query: &str, limit: usize) -> Result<Vec<SearchResult>>;
82}
83
84pub trait ImpactStore: Send + Sync {
85    fn impact_for_file(&self, path: &Path) -> Result<ImpactReport>;
86}
87
88/// Combined store trait for types that implement both metadata and graph storage.
89pub trait OkStore: MetadataStore + GraphStore {}
90impl<T: MetadataStore + GraphStore> OkStore for T {}