geographdb_core/storage/
sectioned_symbol.rs1use anyhow::{Context, Result};
6
7use super::sectioned::SectionedStorage;
8use super::symbol_metadata::SymbolMetadataStore;
9
10#[cfg(test)]
11use super::symbol_metadata::SymbolMetadata;
12
13pub struct SymbolMetadataSectionAdapter;
17
18impl SymbolMetadataSectionAdapter {
19 pub const SECTION_NAME: &'static str = "SYMBOL_METADATA";
20
21 pub fn load(storage: &mut SectionedStorage) -> Result<SymbolMetadataStore> {
23 let bytes = storage
24 .read_section(Self::SECTION_NAME)
25 .context("SYMBOL_METADATA section not found or empty")?;
26 SymbolMetadataStore::from_bytes(&bytes).context("Failed to parse SYMBOL_METADATA section")
27 }
28
29 pub fn save(storage: &mut SectionedStorage, store: &SymbolMetadataStore) -> Result<()> {
33 let bytes = store.to_bytes();
34 let required = bytes.len() as u64;
35
36 if storage.get_section(Self::SECTION_NAME).is_some() {
37 let result = storage.write_section(Self::SECTION_NAME, &bytes);
38
39 if let Err(e) = result {
40 if e.to_string().contains("overflow") || e.to_string().contains("capacity") {
42 let current = storage.get_section(Self::SECTION_NAME).unwrap();
44 let new_capacity = (current.capacity * 2).max(required * 2);
45 storage
46 .resize_section(Self::SECTION_NAME, new_capacity)
47 .context("Failed to resize SYMBOL_METADATA section")?;
48 storage.write_section(Self::SECTION_NAME, &bytes)?;
50 } else {
51 return Err(e);
52 }
53 }
54 } else {
55 let section_capacity = (1024 * 1024).max(required * 2);
57 storage.create_section(Self::SECTION_NAME, section_capacity, 0)?;
58 storage.write_section(Self::SECTION_NAME, &bytes)?;
59 }
60
61 storage.flush()?;
62 Ok(())
63 }
64
65 pub fn init(storage: &mut SectionedStorage) -> Result<()> {
67 let default_capacity = 1024 * 1024; storage.create_section(Self::SECTION_NAME, default_capacity, 0)?;
70
71 let empty = SymbolMetadataStore::new();
73 let bytes = empty.to_bytes();
74 storage.write_section(Self::SECTION_NAME, &bytes)?;
75 storage.flush()?;
76
77 Ok(())
78 }
79
80 pub fn exists(storage: &SectionedStorage) -> bool {
82 storage.get_section(Self::SECTION_NAME).is_some()
83 }
84}
85
86#[cfg(test)]
87mod tests {
88 use super::*;
89 use tempfile::tempdir;
90
91 #[test]
92 fn test_symbol_metadata_section_roundtrip() {
93 let temp_dir = tempdir().unwrap();
94 let db_path = temp_dir.path().join("test_symbols.geo");
95
96 let mut storage = SectionedStorage::create(&db_path).unwrap();
98 SymbolMetadataSectionAdapter::init(&mut storage).unwrap();
99
100 let mut store = SymbolMetadataStore::new();
102 store.add(SymbolMetadata {
103 symbol_id: 1,
104 name: "my_func".to_string(),
105 fqn: "crate::my_func".to_string(),
106 file_path: "/src/lib.rs".to_string(),
107 kind: 1,
108 language: 1,
109 byte_start: 100,
110 byte_end: 200,
111 start_line: 10,
112 start_col: 0,
113 end_line: 20,
114 end_col: 1,
115 });
116
117 SymbolMetadataSectionAdapter::save(&mut storage, &store).unwrap();
119 drop(storage);
120
121 let mut storage = SectionedStorage::open(&db_path).unwrap();
123 let restored = SymbolMetadataSectionAdapter::load(&mut storage).unwrap();
124
125 assert_eq!(restored.symbol_count(), 1);
127 let meta = restored.get(1).unwrap();
128 assert_eq!(meta.name, "my_func");
129 assert_eq!(meta.fqn, "crate::my_func");
130 assert_eq!(meta.file_path, "/src/lib.rs");
131 }
132
133 #[test]
134 fn test_symbol_metadata_section_exists() {
135 let temp_dir = tempdir().unwrap();
136 let db_path = temp_dir.path().join("test_exists.geo");
137
138 let mut storage = SectionedStorage::create(&db_path).unwrap();
140 assert!(!SymbolMetadataSectionAdapter::exists(&storage));
141
142 SymbolMetadataSectionAdapter::init(&mut storage).unwrap();
144 assert!(SymbolMetadataSectionAdapter::exists(&storage));
145 }
146}