swiftide_integrations/redb/
node_cache.rs1use anyhow::Result;
2use async_trait::async_trait;
3use swiftide_core::{NodeCache, indexing::TextNode};
4
5use super::Redb;
6
7macro_rules! unwrap_or_log {
13 ($result:expr) => {
14 match $result {
15 Ok(value) => value,
16 Err(e) => {
17 tracing::error!("Error: {:#}", e);
18 debug_assert!(
19 true,
20 "Redb should not give errors unless in very weird situations; this is a bug: {:#}",
21 e
22 );
23 return false;
24 }
25 }
26 };
27}
28#[async_trait]
29impl NodeCache for Redb {
30 type Input = String;
31
32 async fn get(&self, node: &TextNode) -> bool {
33 let table_definition = self.table_definition();
34 let read_txn = unwrap_or_log!(self.database.begin_read());
35
36 let result = read_txn.open_table(table_definition);
37
38 let table = match result {
39 Ok(table) => table,
40 Err(redb::TableError::TableDoesNotExist { .. }) => {
41 {
43 let write_txn = unwrap_or_log!(self.database.begin_write());
44
45 unwrap_or_log!(write_txn.open_table(table_definition));
46 unwrap_or_log!(write_txn.commit());
47 }
48
49 let read_tx = unwrap_or_log!(self.database.begin_read());
50 unwrap_or_log!(read_tx.open_table(table_definition))
51 }
52 Err(e) => {
53 tracing::error!("Failed to open table: {e:#}");
54 return false;
55 }
56 };
57
58 match table.get(self.node_key(node)).unwrap() {
59 Some(access_guard) => access_guard.value(),
60 None => false,
61 }
62 }
63
64 async fn set(&self, node: &TextNode) {
65 let write_txn = self.database.begin_write().unwrap();
66
67 {
68 let mut table = write_txn.open_table(self.table_definition()).unwrap();
69
70 table.insert(self.node_key(node), true).unwrap();
71 }
72 write_txn.commit().unwrap();
73 }
74
75 async fn clear(&self) -> Result<()> {
77 let write_txn = self.database.begin_write().unwrap();
78 let _ = write_txn.delete_table(self.table_definition());
79
80 write_txn.commit().unwrap();
81
82 Ok(())
83 }
84}
85
86#[cfg(test)]
87mod tests {
88 use super::*;
89 use swiftide_core::indexing::TextNode;
90 use temp_dir::TempDir;
91
92 fn setup_redb() -> Redb {
93 let tempdir = TempDir::new().unwrap();
94 Redb::builder()
95 .database_path(tempdir.child("test_clear"))
96 .build()
97 .unwrap()
98 }
99
100 #[tokio::test]
101 async fn test_get_set() {
102 let redb = setup_redb();
103 let node = TextNode::new("test_get_set");
104 assert!(!redb.get(&node).await);
105 redb.set(&node).await;
106 assert!(redb.get(&node).await);
107 }
108 #[tokio::test]
109 async fn test_clear() {
110 let redb = setup_redb();
111 let node = TextNode::new("test_clear");
112 redb.set(&node).await;
113 assert!(redb.get(&node).await);
114 redb.clear().await.unwrap();
115 assert!(!redb.get(&node).await);
116 }
117}