rlm_rs/storage/traits.rs
1//! Storage trait definition.
2//!
3//! Defines the interface for persistent storage backends, enabling
4//! pluggable storage implementations.
5
6use crate::core::{Buffer, Chunk, Context};
7use crate::error::Result;
8use serde::Serialize;
9
10/// Trait for persistent storage backends.
11///
12/// Implementations handle storage of RLM state including contexts,
13/// buffers, and chunks. All operations should be atomic where appropriate.
14///
15/// Note: This trait does not require `Send + Sync` as rlm-rs is a
16/// single-threaded CLI application. Implementations are not guaranteed
17/// to be thread-safe.
18pub trait Storage {
19 /// Initializes storage (creates schema, runs migrations).
20 ///
21 /// Should be idempotent - safe to call multiple times.
22 ///
23 /// # Errors
24 ///
25 /// Returns an error if schema creation or migration fails.
26 fn init(&mut self) -> Result<()>;
27
28 /// Checks if storage is initialized.
29 ///
30 /// # Errors
31 ///
32 /// Returns an error if the check cannot be performed.
33 fn is_initialized(&self) -> Result<bool>;
34
35 /// Resets all stored state.
36 ///
37 /// Deletes all data but preserves the schema.
38 ///
39 /// # Errors
40 ///
41 /// Returns an error if deletion fails.
42 fn reset(&mut self) -> Result<()>;
43
44 // ==================== Context Operations ====================
45
46 /// Saves the current context state.
47 ///
48 /// Creates or updates the context in storage.
49 ///
50 /// # Errors
51 ///
52 /// Returns an error if serialization or database write fails.
53 fn save_context(&mut self, context: &Context) -> Result<()>;
54
55 /// Loads the context state.
56 ///
57 /// Returns `None` if no context exists.
58 ///
59 /// # Errors
60 ///
61 /// Returns an error if database read or deserialization fails.
62 fn load_context(&self) -> Result<Option<Context>>;
63
64 /// Deletes the current context.
65 ///
66 /// # Errors
67 ///
68 /// Returns an error if deletion fails.
69 fn delete_context(&mut self) -> Result<()>;
70
71 // ==================== Buffer Operations ====================
72
73 /// Adds a buffer to storage.
74 ///
75 /// Returns the assigned buffer ID.
76 ///
77 /// # Errors
78 ///
79 /// Returns an error if the buffer cannot be inserted.
80 fn add_buffer(&mut self, buffer: &Buffer) -> Result<i64>;
81
82 /// Retrieves a buffer by ID.
83 ///
84 /// # Errors
85 ///
86 /// Returns an error if the query fails.
87 fn get_buffer(&self, id: i64) -> Result<Option<Buffer>>;
88
89 /// Retrieves a buffer by name.
90 ///
91 /// # Errors
92 ///
93 /// Returns an error if the query fails.
94 fn get_buffer_by_name(&self, name: &str) -> Result<Option<Buffer>>;
95
96 /// Lists all buffers.
97 ///
98 /// # Errors
99 ///
100 /// Returns an error if the query fails.
101 fn list_buffers(&self) -> Result<Vec<Buffer>>;
102
103 /// Updates an existing buffer.
104 ///
105 /// # Errors
106 ///
107 /// Returns an error if the buffer does not exist or update fails.
108 fn update_buffer(&mut self, buffer: &Buffer) -> Result<()>;
109
110 /// Deletes a buffer by ID.
111 ///
112 /// Also deletes associated chunks.
113 ///
114 /// # Errors
115 ///
116 /// Returns an error if deletion fails.
117 fn delete_buffer(&mut self, id: i64) -> Result<()>;
118
119 /// Returns the count of buffers.
120 ///
121 /// # Errors
122 ///
123 /// Returns an error if the count query fails.
124 fn buffer_count(&self) -> Result<usize>;
125
126 // ==================== Chunk Operations ====================
127
128 /// Adds chunks for a buffer.
129 ///
130 /// Should be called after buffer is created.
131 ///
132 /// # Errors
133 ///
134 /// Returns an error if chunk insertion fails.
135 fn add_chunks(&mut self, buffer_id: i64, chunks: &[Chunk]) -> Result<()>;
136
137 /// Retrieves all chunks for a buffer.
138 ///
139 /// # Errors
140 ///
141 /// Returns an error if the query fails.
142 fn get_chunks(&self, buffer_id: i64) -> Result<Vec<Chunk>>;
143
144 /// Retrieves a specific chunk by ID.
145 ///
146 /// # Errors
147 ///
148 /// Returns an error if the query fails.
149 fn get_chunk(&self, id: i64) -> Result<Option<Chunk>>;
150
151 /// Deletes all chunks for a buffer.
152 ///
153 /// # Errors
154 ///
155 /// Returns an error if deletion fails.
156 fn delete_chunks(&mut self, buffer_id: i64) -> Result<()>;
157
158 /// Returns the count of chunks for a buffer.
159 ///
160 /// # Errors
161 ///
162 /// Returns an error if the count query fails.
163 fn chunk_count(&self, buffer_id: i64) -> Result<usize>;
164
165 // ==================== Utility Operations ====================
166
167 /// Exports all buffers as a concatenated string.
168 ///
169 /// Used for the `export-buffers` command.
170 ///
171 /// # Errors
172 ///
173 /// Returns an error if buffer retrieval fails.
174 fn export_buffers(&self) -> Result<String>;
175
176 /// Gets storage statistics.
177 ///
178 /// # Errors
179 ///
180 /// Returns an error if statistics cannot be gathered.
181 fn stats(&self) -> Result<StorageStats>;
182}
183
184/// Storage statistics.
185#[derive(Debug, Clone, Default, Serialize)]
186pub struct StorageStats {
187 /// Number of buffers stored.
188 pub buffer_count: usize,
189 /// Total number of chunks across all buffers.
190 pub chunk_count: usize,
191 /// Total size of all buffer content in bytes.
192 pub total_content_size: usize,
193 /// Whether a context is stored.
194 pub has_context: bool,
195 /// Schema version.
196 pub schema_version: u32,
197 /// Database file size in bytes (if applicable).
198 pub db_size: Option<u64>,
199}
200
201/// Trait for vector-based semantic search (feature-gated).
202#[cfg(feature = "usearch-hnsw")]
203pub trait VectorStorage: Storage {
204 /// Indexes a chunk with embeddings for semantic search.
205 ///
206 /// # Errors
207 ///
208 /// Returns an error if indexing fails.
209 fn index_chunk(&mut self, chunk_id: i64, embedding: &[f32]) -> Result<()>;
210
211 /// Performs semantic search for similar chunks.
212 ///
213 /// Returns chunk IDs and similarity scores.
214 ///
215 /// # Errors
216 ///
217 /// Returns an error if the search fails.
218 fn search_similar(&self, query_embedding: &[f32], limit: usize) -> Result<Vec<(i64, f32)>>;
219
220 /// Removes vector index for a chunk.
221 ///
222 /// # Errors
223 ///
224 /// Returns an error if removal fails.
225 fn remove_index(&mut self, chunk_id: i64) -> Result<()>;
226}