1use crate::{RELATIONSHIPS_TABLE, RedbStorage, Result};
4#[allow(unused_imports)] use do_memory_core::Error;
6use do_memory_core::episode::{Direction, EpisodeRelationship, RelationshipType};
7use redb::{ReadableDatabase, ReadableTable, ReadableTableMetadata};
8use tracing::debug;
9use uuid::Uuid;
10
11impl RedbStorage {
12 pub async fn store_relationship(&self, relationship: &EpisodeRelationship) -> Result<()> {
16 self.cache_relationship(relationship)
17 }
18
19 pub async fn remove_relationship(&self, relationship_id: Uuid) -> Result<()> {
21 self.remove_cached_relationship(relationship_id)
22 }
23
24 pub async fn get_relationships(
26 &self,
27 episode_id: Uuid,
28 direction: Direction,
29 ) -> Result<Vec<EpisodeRelationship>> {
30 self.get_cached_relationships(episode_id, direction)
31 }
32
33 pub async fn relationship_exists(
35 &self,
36 from_episode_id: Uuid,
37 to_episode_id: Uuid,
38 relationship_type: RelationshipType,
39 ) -> Result<bool> {
40 let relationships = self.get_cached_relationships(from_episode_id, Direction::Outgoing)?;
41 Ok(relationships
42 .iter()
43 .any(|r| r.to_episode_id == to_episode_id && r.relationship_type == relationship_type))
44 }
45
46 pub fn cache_relationship(&self, relationship: &EpisodeRelationship) -> Result<()> {
50 let write_txn = self
51 .db
52 .begin_write()
53 .map_err(|e| do_memory_core::Error::Storage(format!("Begin write failed: {}", e)))?;
54 {
55 let mut table = write_txn
56 .open_table(RELATIONSHIPS_TABLE)
57 .map_err(|e| do_memory_core::Error::Storage(format!("Open table failed: {}", e)))?;
58 let key = relationship.id.to_string();
59 let value = postcard::to_allocvec(relationship).map_err(|e| {
60 do_memory_core::Error::Storage(format!("Serialization error: {}", e))
61 })?;
62 table
63 .insert(key.as_str(), value.as_slice())
64 .map_err(|e| do_memory_core::Error::Storage(format!("Insert failed: {}", e)))?;
65 }
66 write_txn
67 .commit()
68 .map_err(|e| do_memory_core::Error::Storage(format!("Commit failed: {}", e)))?;
69
70 debug!("Cached relationship {} in redb", relationship.id);
71 Ok(())
72 }
73
74 pub fn get_cached_relationship(
76 &self,
77 relationship_id: Uuid,
78 ) -> Result<Option<EpisodeRelationship>> {
79 let read_txn = self
80 .db
81 .begin_read()
82 .map_err(|e| do_memory_core::Error::Storage(format!("Begin read failed: {}", e)))?;
83 let table = read_txn
84 .open_table(RELATIONSHIPS_TABLE)
85 .map_err(|e| do_memory_core::Error::Storage(format!("Open table failed: {}", e)))?;
86 let key = relationship_id.to_string();
87
88 match table
89 .get(key.as_str())
90 .map_err(|e| do_memory_core::Error::Storage(format!("Get failed: {}", e)))?
91 {
92 Some(value) => {
93 let bytes = value.value();
94 let relationship: EpisodeRelationship =
95 postcard::from_bytes(bytes).map_err(|e| {
96 do_memory_core::Error::Storage(format!("Deserialization error: {}", e))
97 })?;
98 Ok(Some(relationship))
99 }
100 None => Ok(None),
101 }
102 }
103
104 pub fn remove_cached_relationship(&self, relationship_id: Uuid) -> Result<()> {
106 let write_txn = self
107 .db
108 .begin_write()
109 .map_err(|e| do_memory_core::Error::Storage(format!("Begin write failed: {}", e)))?;
110 {
111 let mut table = write_txn
112 .open_table(RELATIONSHIPS_TABLE)
113 .map_err(|e| do_memory_core::Error::Storage(format!("Open table failed: {}", e)))?;
114 let key = relationship_id.to_string();
115 table
116 .remove(key.as_str())
117 .map_err(|e| do_memory_core::Error::Storage(format!("Remove failed: {}", e)))?;
118 }
119 write_txn
120 .commit()
121 .map_err(|e| do_memory_core::Error::Storage(format!("Commit failed: {}", e)))?;
122
123 debug!("Removed relationship {} from cache", relationship_id);
124 Ok(())
125 }
126
127 pub fn get_cached_relationships(
129 &self,
130 episode_id: Uuid,
131 direction: Direction,
132 ) -> Result<Vec<EpisodeRelationship>> {
133 let read_txn = self
134 .db
135 .begin_read()
136 .map_err(|e| do_memory_core::Error::Storage(format!("Begin read failed: {}", e)))?;
137 let table = read_txn
138 .open_table(RELATIONSHIPS_TABLE)
139 .map_err(|e| do_memory_core::Error::Storage(format!("Open table failed: {}", e)))?;
140
141 let mut relationships = Vec::new();
142 let iter = table.iter().map_err(|e| {
143 do_memory_core::Error::Storage(format!("Iterator creation failed: {}", e))
144 })?;
145
146 for item in iter {
147 let (_, value) = item.map_err(|e| {
148 do_memory_core::Error::Storage(format!("Iterator next failed: {}", e))
149 })?;
150 let bytes = value.value();
151 let relationship: EpisodeRelationship = postcard::from_bytes(bytes).map_err(|e| {
152 do_memory_core::Error::Storage(format!("Deserialization error: {}", e))
153 })?;
154
155 let matches = match direction {
156 Direction::Outgoing => relationship.from_episode_id == episode_id,
157 Direction::Incoming => relationship.to_episode_id == episode_id,
158 Direction::Both => {
159 relationship.from_episode_id == episode_id
160 || relationship.to_episode_id == episode_id
161 }
162 };
163
164 if matches {
165 relationships.push(relationship);
166 }
167 }
168
169 debug!(
170 "Found {} cached relationships for episode {} (direction: {:?})",
171 relationships.len(),
172 episode_id,
173 direction
174 );
175
176 Ok(relationships)
177 }
178
179 pub fn clear_relationships_cache(&self) -> Result<()> {
181 let write_txn = self
182 .db
183 .begin_write()
184 .map_err(|e| do_memory_core::Error::Storage(format!("Begin write failed: {}", e)))?;
185 {
186 let mut table = write_txn
187 .open_table(RELATIONSHIPS_TABLE)
188 .map_err(|e| do_memory_core::Error::Storage(format!("Open table failed: {}", e)))?;
189 let keys: Vec<String> = {
191 let iter = table.iter().map_err(|e| {
192 do_memory_core::Error::Storage(format!("Iterator creation failed: {}", e))
193 })?;
194 let mut keys = Vec::new();
195 for item in iter {
196 let (key, _) = item.map_err(|e| {
197 do_memory_core::Error::Storage(format!("Iterator next failed: {}", e))
198 })?;
199 keys.push(key.value().to_string());
200 }
201 keys
202 };
203
204 for key in keys {
205 table
206 .remove(key.as_str())
207 .map_err(|e| do_memory_core::Error::Storage(format!("Remove failed: {}", e)))?;
208 }
209 }
210 write_txn
211 .commit()
212 .map_err(|e| do_memory_core::Error::Storage(format!("Commit failed: {}", e)))?;
213
214 debug!("Cleared all cached relationships");
215 Ok(())
216 }
217
218 pub fn count_cached_relationships(&self) -> Result<usize> {
220 let read_txn = self
221 .db
222 .begin_read()
223 .map_err(|e| do_memory_core::Error::Storage(format!("Begin read failed: {}", e)))?;
224 let table = read_txn
225 .open_table(RELATIONSHIPS_TABLE)
226 .map_err(|e| do_memory_core::Error::Storage(format!("Open table failed: {}", e)))?;
227 let count = table.len().map_err(|e| {
228 do_memory_core::Error::Storage(format!("Failed to get table length: {}", e))
229 })? as usize;
230 Ok(count)
231 }
232}
233
234#[cfg(test)]
235mod tests {
236 use super::*;
237 use do_memory_core::episode::RelationshipType;
238 use tempfile::TempDir;
239
240 async fn create_test_storage() -> (RedbStorage, TempDir) {
241 let dir = TempDir::new().expect("Failed to create temp dir");
242 let db_path = dir.path().join("test.redb");
243 let storage = RedbStorage::new(&db_path)
244 .await
245 .expect("Failed to create storage");
246 (storage, dir)
247 }
248
249 fn create_test_relationship(from_id: Uuid, to_id: Uuid) -> EpisodeRelationship {
250 EpisodeRelationship::with_reason(
251 from_id,
252 to_id,
253 RelationshipType::ParentChild,
254 "Test relationship".to_string(),
255 )
256 }
257
258 #[tokio::test]
259 async fn test_cache_and_get_relationship() {
260 let (storage, _dir) = create_test_storage().await;
261 let from_id = Uuid::new_v4();
262 let to_id = Uuid::new_v4();
263 let relationship = create_test_relationship(from_id, to_id);
264 let rel_id = relationship.id;
265
266 storage
268 .cache_relationship(&relationship)
269 .expect("Failed to cache relationship");
270
271 let cached = storage
273 .get_cached_relationship(rel_id)
274 .expect("Failed to get relationship");
275 assert!(cached.is_some());
276 let cached_rel = cached.unwrap();
277 assert_eq!(cached_rel.id, rel_id);
278 assert_eq!(cached_rel.from_episode_id, from_id);
279 assert_eq!(cached_rel.to_episode_id, to_id);
280 }
281
282 #[tokio::test]
283 async fn test_remove_cached_relationship() {
284 let (storage, _dir) = create_test_storage().await;
285 let from_id = Uuid::new_v4();
286 let to_id = Uuid::new_v4();
287 let relationship = create_test_relationship(from_id, to_id);
288 let rel_id = relationship.id;
289
290 storage
291 .cache_relationship(&relationship)
292 .expect("Failed to cache relationship");
293
294 storage
296 .remove_cached_relationship(rel_id)
297 .expect("Failed to remove relationship");
298
299 let cached = storage
301 .get_cached_relationship(rel_id)
302 .expect("Failed to get relationship");
303 assert!(cached.is_none());
304 }
305
306 #[tokio::test]
307 async fn test_get_cached_relationships_outgoing() {
308 let (storage, _dir) = create_test_storage().await;
309 let from_id = Uuid::new_v4();
310 let to_id1 = Uuid::new_v4();
311 let to_id2 = Uuid::new_v4();
312
313 let rel1 = create_test_relationship(from_id, to_id1);
314 let rel2 = create_test_relationship(from_id, to_id2);
315
316 storage.cache_relationship(&rel1).expect("Failed to cache");
317 storage.cache_relationship(&rel2).expect("Failed to cache");
318
319 let relationships = storage
320 .get_cached_relationships(from_id, Direction::Outgoing)
321 .expect("Failed to get relationships");
322
323 assert_eq!(relationships.len(), 2);
324 assert!(relationships.iter().any(|r| r.to_episode_id == to_id1));
325 assert!(relationships.iter().any(|r| r.to_episode_id == to_id2));
326 }
327
328 #[tokio::test]
329 async fn test_get_cached_relationships_incoming() {
330 let (storage, _dir) = create_test_storage().await;
331 let to_id = Uuid::new_v4();
332 let from_id1 = Uuid::new_v4();
333 let from_id2 = Uuid::new_v4();
334
335 let rel1 = create_test_relationship(from_id1, to_id);
336 let rel2 = create_test_relationship(from_id2, to_id);
337
338 storage.cache_relationship(&rel1).expect("Failed to cache");
339 storage.cache_relationship(&rel2).expect("Failed to cache");
340
341 let relationships = storage
342 .get_cached_relationships(to_id, Direction::Incoming)
343 .expect("Failed to get relationships");
344
345 assert_eq!(relationships.len(), 2);
346 assert!(relationships.iter().any(|r| r.from_episode_id == from_id1));
347 assert!(relationships.iter().any(|r| r.from_episode_id == from_id2));
348 }
349
350 #[tokio::test]
351 async fn test_clear_relationships_cache() {
352 let (storage, _dir) = create_test_storage().await;
353 let from_id = Uuid::new_v4();
354 let to_id = Uuid::new_v4();
355
356 for _ in 0..5 {
357 let rel = create_test_relationship(from_id, to_id);
358 storage.cache_relationship(&rel).expect("Failed to cache");
359 }
360
361 let count_before = storage
362 .count_cached_relationships()
363 .expect("Failed to count");
364 assert_eq!(count_before, 5);
365
366 storage
367 .clear_relationships_cache()
368 .expect("Failed to clear cache");
369
370 let count_after = storage
371 .count_cached_relationships()
372 .expect("Failed to count");
373 assert_eq!(count_after, 0);
374 }
375
376 #[tokio::test]
377 async fn test_count_cached_relationships() {
378 let (storage, _dir) = create_test_storage().await;
379
380 let from_id = Uuid::new_v4();
382 let to_id = Uuid::new_v4();
383 let rel = create_test_relationship(from_id, to_id);
384 storage.cache_relationship(&rel).expect("Failed to cache");
385
386 let count_initial = storage
387 .count_cached_relationships()
388 .expect("Failed to count");
389 assert_eq!(count_initial, 1);
390
391 for i in 0..2 {
393 let from_id = Uuid::new_v4();
394 let to_id = Uuid::new_v4();
395 let rel = create_test_relationship(from_id, to_id);
396 storage.cache_relationship(&rel).expect("Failed to cache");
397
398 let count = storage
399 .count_cached_relationships()
400 .expect("Failed to count");
401 assert_eq!(count, i + 2); }
403 }
404}