open_kioku_storage/
lib.rs1use open_kioku_core::{
2 AnalysisFact, CodeChunk, EvidenceSourceType, File, FileId, GraphEdge, GraphNode, ImpactReport,
3 Import, IndexManifest, 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 analysis_facts(
23 &self,
24 _source_type: Option<EvidenceSourceType>,
25 _limit: usize,
26 ) -> Result<Vec<AnalysisFact>> {
27 Ok(Vec::new())
28 }
29 fn references_for_symbol(&self, id: &SymbolId, limit: usize) -> Result<Vec<SymbolOccurrence>>;
30 fn occurrences_for_file(&self, file_id: &FileId) -> Result<Vec<SymbolOccurrence>>;
31 fn symbols_for_file(&self, _file_id: &FileId) -> Result<Vec<Symbol>> {
32 Ok(Vec::new())
33 }
34 fn find_chunks_containing(&self, query: &str, limit: usize) -> Result<Vec<CodeChunk>> {
35 let chunks = self.all_chunks()?;
36 let mut results = Vec::new();
37 for chunk in chunks {
38 if chunk.text.contains(query) {
39 results.push(chunk);
40 if results.len() >= limit {
41 break;
42 }
43 }
44 }
45 Ok(results)
46 }
47 fn find_files_by_path_pattern(&self, pattern: &str) -> Result<Vec<File>> {
48 let files = self.list_files(usize::MAX, 0)?;
49 let lower_pattern = pattern.to_ascii_lowercase();
50 Ok(files
51 .into_iter()
52 .filter(|f| {
53 f.path
54 .to_string_lossy()
55 .to_ascii_lowercase()
56 .contains(&lower_pattern)
57 })
58 .collect())
59 }
60 fn tests_for_files(&self, file_ids: &[FileId]) -> Result<Vec<TestTarget>> {
61 let tests = self.tests()?;
62 let set = file_ids.iter().collect::<std::collections::HashSet<_>>();
63 Ok(tests
64 .into_iter()
65 .filter(|t| set.contains(&t.file_id))
66 .collect())
67 }
68}
69
70pub struct IndexData<'a> {
71 pub manifest: &'a IndexManifest,
72 pub files: &'a [File],
73 pub symbols: &'a [Symbol],
74 pub chunks: &'a [CodeChunk],
75 pub tests: &'a [TestTarget],
76 pub imports: &'a [Import],
77 pub occurrences: &'a [SymbolOccurrence],
78 pub analysis_facts: &'a [AnalysisFact],
79}
80
81pub trait GraphStore: Send + Sync {
82 fn replace_graph(&self, nodes: &[GraphNode], edges: &[GraphEdge]) -> Result<()>;
83 fn neighbors(&self, node: &str, limit: usize) -> Result<(Vec<GraphNode>, Vec<GraphEdge>)>;
84 fn shortest_path(&self, from: &str, to: &str, max_depth: usize) -> Result<Vec<GraphEdge>>;
85}
86
87pub trait SearchIndex: Send + Sync {
88 fn rebuild(&mut self, chunks: &[CodeChunk], files: &[File], symbols: &[Symbol]) -> Result<()>;
89 fn search(&self, query: &str, limit: usize) -> Result<Vec<SearchResult>>;
90}
91
92pub trait ImpactStore: Send + Sync {
93 fn impact_for_file(&self, path: &Path) -> Result<ImpactReport>;
94}
95
96pub trait OkStore: MetadataStore + GraphStore {}
98impl<T: MetadataStore + GraphStore> OkStore for T {}