Skip to main content

surrealism_runtime/
kv.rs

1use std::collections::BTreeMap;
2use std::ops::Bound;
3use std::sync::RwLock;
4
5use anyhow::Result;
6use async_trait::async_trait;
7
8#[async_trait]
9pub trait KVStore: Send + Sync {
10	async fn get(&self, key: String) -> Result<Option<surrealdb_types::Value>>;
11	async fn set(&self, key: String, value: surrealdb_types::Value) -> Result<()>;
12	async fn del(&self, key: String) -> Result<()>;
13	async fn exists(&self, key: String) -> Result<bool>;
14
15	async fn del_rng(&self, start: Bound<String>, end: Bound<String>) -> Result<()>;
16
17	async fn get_batch(&self, keys: Vec<String>) -> Result<Vec<Option<surrealdb_types::Value>>>;
18	async fn set_batch(&self, entries: Vec<(String, surrealdb_types::Value)>) -> Result<()>;
19	async fn del_batch(&self, keys: Vec<String>) -> Result<()>;
20
21	async fn keys(&self, start: Bound<String>, end: Bound<String>) -> Result<Vec<String>>;
22	async fn values(
23		&self,
24		start: Bound<String>,
25		end: Bound<String>,
26	) -> Result<Vec<surrealdb_types::Value>>;
27	async fn entries(
28		&self,
29		start: Bound<String>,
30		end: Bound<String>,
31	) -> Result<Vec<(String, surrealdb_types::Value)>>;
32	async fn count(&self, start: Bound<String>, end: Bound<String>) -> Result<u64>;
33}
34
35/// In-memory BTreeMap implementation of KVStore
36pub struct BTreeMapStore {
37	inner: RwLock<BTreeMap<String, surrealdb_types::Value>>,
38}
39
40impl BTreeMapStore {
41	/// Create a new empty BTreeMap store
42	pub fn new() -> Self {
43		Self {
44			inner: RwLock::new(BTreeMap::new()),
45		}
46	}
47
48	/// Create a BTreeMap store with initial capacity
49	pub fn with_capacity(_capacity: usize) -> Self {
50		// BTreeMap doesn't have with_capacity, but we keep the method for API compatibility
51		Self {
52			inner: RwLock::new(BTreeMap::new()),
53		}
54	}
55
56	/// Helper function to check if a key falls within a range
57	fn in_range(&self, key: &str, start: &Bound<String>, end: &Bound<String>) -> bool {
58		match start {
59			Bound::Included(start_key) => {
60				if key < start_key.as_str() {
61					return false;
62				}
63			}
64			Bound::Excluded(start_key) => {
65				if key <= start_key.as_str() {
66					return false;
67				}
68			}
69			Bound::Unbounded => {}
70		}
71
72		match end {
73			Bound::Included(end_key) => {
74				if key > end_key.as_str() {
75					return false;
76				}
77			}
78			Bound::Excluded(end_key) => {
79				if key >= end_key.as_str() {
80					return false;
81				}
82			}
83			Bound::Unbounded => {}
84		}
85		true
86	}
87}
88
89impl Default for BTreeMapStore {
90	fn default() -> Self {
91		Self::new()
92	}
93}
94
95#[async_trait]
96impl KVStore for BTreeMapStore {
97	async fn get(&self, key: String) -> Result<Option<surrealdb_types::Value>> {
98		let map = self
99			.inner
100			.read()
101			.map_err(|_| anyhow::anyhow!("Failed to get from KV store: Could not acquire lock"))?;
102		Ok(map.get(&key).cloned())
103	}
104
105	async fn set(&self, key: String, value: surrealdb_types::Value) -> Result<()> {
106		let mut map = self
107			.inner
108			.write()
109			.map_err(|_| anyhow::anyhow!("Failed to set in KV store: Could not acquire lock"))?;
110		map.insert(key, value);
111		Ok(())
112	}
113
114	async fn del(&self, key: String) -> Result<()> {
115		let mut map = self.inner.write().map_err(|_| {
116			anyhow::anyhow!("Failed to delete from KV store: Could not acquire lock")
117		})?;
118		map.remove(&key);
119		Ok(())
120	}
121
122	async fn exists(&self, key: String) -> Result<bool> {
123		let map = self.inner.read().map_err(|_| {
124			anyhow::anyhow!("Failed to check if key exists in KV store: Could not acquire lock")
125		})?;
126		Ok(map.contains_key(&key))
127	}
128
129	async fn del_rng(&self, start: Bound<String>, end: Bound<String>) -> Result<()> {
130		let mut map = self.inner.write().map_err(|_| {
131			anyhow::anyhow!("Failed to delete range from KV store: Could not acquire lock")
132		})?;
133		let keys_to_remove: Vec<String> =
134			map.keys().filter(|key| self.in_range(key, &start, &end)).cloned().collect();
135		for key in keys_to_remove {
136			map.remove(&key);
137		}
138		Ok(())
139	}
140
141	async fn get_batch(&self, keys: Vec<String>) -> Result<Vec<Option<surrealdb_types::Value>>> {
142		let map = self.inner.read().map_err(|_| {
143			anyhow::anyhow!("Failed to get batch from KV store: Could not acquire lock")
144		})?;
145		let mut results = Vec::with_capacity(keys.len());
146		for key in keys {
147			results.push(map.get(&key).cloned());
148		}
149		Ok(results)
150	}
151
152	async fn set_batch(&self, entries: Vec<(String, surrealdb_types::Value)>) -> Result<()> {
153		let mut map = self.inner.write().map_err(|_| {
154			anyhow::anyhow!("Failed to set batch in KV store: Could not acquire lock")
155		})?;
156		for (key, value) in entries {
157			map.insert(key, value);
158		}
159		Ok(())
160	}
161
162	async fn del_batch(&self, keys: Vec<String>) -> Result<()> {
163		let mut map = self.inner.write().map_err(|_| {
164			anyhow::anyhow!("Failed to delete batch from KV store: Could not acquire lock")
165		})?;
166		for key in keys {
167			map.remove(&key);
168		}
169		Ok(())
170	}
171
172	async fn keys(&self, start: Bound<String>, end: Bound<String>) -> Result<Vec<String>> {
173		let map = self.inner.read().map_err(|_| {
174			anyhow::anyhow!("Failed to collect keys from KV store: Could not acquire lock")
175		})?;
176		let keys: Vec<String> =
177			map.keys().filter(|key| self.in_range(key, &start, &end)).cloned().collect();
178		Ok(keys)
179	}
180
181	async fn values(
182		&self,
183		start: Bound<String>,
184		end: Bound<String>,
185	) -> Result<Vec<surrealdb_types::Value>> {
186		let map = self.inner.read().map_err(|_| {
187			anyhow::anyhow!("Failed to collect values from KV store: Could not acquire lock")
188		})?;
189		let values: Vec<surrealdb_types::Value> = map
190			.iter()
191			.filter(|(key, _)| self.in_range(key, &start, &end))
192			.map(|(_, value)| value.clone())
193			.collect();
194		Ok(values)
195	}
196
197	async fn entries(
198		&self,
199		start: Bound<String>,
200		end: Bound<String>,
201	) -> Result<Vec<(String, surrealdb_types::Value)>> {
202		let map = self.inner.read().map_err(|_| {
203			anyhow::anyhow!("Failed to collect entries from KV store: Could not acquire lock")
204		})?;
205		let entries: Vec<(String, surrealdb_types::Value)> = map
206			.iter()
207			.filter(|(key, _)| self.in_range(key, &start, &end))
208			.map(|(key, value)| (key.clone(), value.clone()))
209			.collect();
210		Ok(entries)
211	}
212
213	async fn count(&self, start: Bound<String>, end: Bound<String>) -> Result<u64> {
214		let map = self.inner.read().map_err(|_| {
215			anyhow::anyhow!("Failed to get count from KV store: Could not acquire lock")
216		})?;
217		let count = map.keys().filter(|key| self.in_range(key, &start, &end)).count();
218		Ok(count as u64)
219	}
220}