stupid_simple_kv/lib.rs
1//! # stupid-simple-kv
2//!
3//! A dead-simple, pluggable, and binary-sorted key-value store for Rust.
4//!
5//! ## Features
6//!
7//! - **Order-preserving tuple-style keys**: Compose keys using `u64`, `i64`, `bool`, `String`, tuples, or your own struct if it implements [`IntoKey`].
8//! - **Pluggable design**: Swap between memory or SQLite backends, or define your own by implementing [`KvBackend`].
9//! - **Automatic value serialization**: Store any serde-serializable value as a [`KvValue`].
10//! - **List/query API**: Filter or range-scan with [`KvListBuilder`].
11//! - **Easy JSON import/export**: Dump or restore the store's contents for debugging or migration.
12//! - **Typed errors** and strict Rust interface.
13//!
14//! ## Quickstart
15//!
16//! ```rust
17//! use stupid_simple_kv::{Kv, MemoryBackend, KvValue, IntoKey};
18//!
19//! let backend = Box::new(MemoryBackend::new());
20//! let mut kv = Kv::new(backend);
21//!
22//! let key = (42u64, true, -17i64, "foo").to_key();
23//! kv.set(&key, "value".into()).unwrap();
24//! assert_eq!(kv.get(&key).unwrap(), Some("value".into()));
25//! kv.delete(&key).unwrap();
26//! ```
27//!
28//! ## Listing and Filtering
29//!
30//! ```rust
31//! use stupid_simple_kv::{Kv, MemoryBackend, KvValue, IntoKey};
32//! let backend = Box::new(MemoryBackend::new());
33//! let mut kv = Kv::new(backend);
34//! for i in 0..5 as i64 {
35//! let key = (1u64, i, true).to_key();
36//! kv.set(&key, i.into()).unwrap();
37//! }
38//!
39//! // Fetch all records with prefix (1, _, true)
40//! let items = kv.list().prefix(&(1u64,)).entries().unwrap();
41//! assert!(items.len() >= 1);
42//! ```
43//!
44//! ## Implementing a Backend
45//!
46//! For custom persistence, implement [`KvBackend`]. See [`backends/mod.rs`](backends/mod.rs) or the SQLite backend for real examples.
47//!
48//! ## Value Types
49//!
50//! All values are stored as [`KvValue`] (enum, supports u64, i64, f64, string, bool, null, arrays, objects, binary data).
51//!
52//! ## JSON Import/Export
53//!
54//! ```rust
55//! use stupid_simple_kv::{Kv, MemoryBackend, KvValue, IntoKey};
56//! let mut kv = Kv::new(Box::new(MemoryBackend::new()));
57//! let json = kv.dump_json().unwrap();
58//! let mut loaded = Kv::from_json_string(Box::new(MemoryBackend::new()), json).unwrap();
59//! ```
60
61mod backends;
62mod keys;
63mod kv_error;
64mod kv_value;
65mod list_builder;
66mod tests;
67
68use std::sync::{Arc, RwLock};
69
70pub use crate::backends::{KvBackend, memory_backend::MemoryBackend};
71pub use crate::keys::{KvKey, display};
72pub use crate::kv_error::{KvError, KvResult};
73pub use crate::kv_value::KvValue;
74pub use crate::list_builder::KvListBuilder;
75pub use keys::IntoKey;
76use keys::display::{parse_display_string_to_key, to_display_string};
77
78#[cfg(feature = "sqlite")]
79pub use crate::backends::sqlite_backend::SqliteBackend;
80
81/// Main key-value store abstraction.
82///
83/// Holds a boxed backend and exposes get/set/delete/query APIs.
84/// Instantiate with [`Kv::new`], and use [`KvListBuilder`] for advanced listing/filtering.
85///
86/// # Example
87/// ```rust
88/// use stupid_simple_kv::{Kv, MemoryBackend, IntoKey};
89/// let mut kv = Kv::new(Box::new(MemoryBackend::new()));
90/// kv.set(&(123u64, true, "foo"), "bar".into()).unwrap();
91/// let out = kv.get(&(123u64, true, "foo")).unwrap();
92/// assert_eq!(out, Some("bar".into()));
93/// ```
94pub struct Kv {
95 backend: Arc<RwLock<Box<dyn KvBackend>>>,
96}
97
98impl Kv {
99 /// Create a new [`Kv`] with the given backend.
100 ///
101 /// Example:
102 /// ```rust
103 /// use stupid_simple_kv::{Kv, MemoryBackend, KvValue, IntoKey};
104 /// let mut kv = Kv::new(Box::new(MemoryBackend::new()));
105 /// ```
106 pub fn new(backend: Box<dyn KvBackend>) -> Self {
107 let backend = Arc::new(RwLock::new(backend));
108 Self { backend }
109 }
110
111 /// Retrieve the value for a given key. Returns `Ok(Some(KvValue))` if present, `Ok(None)` if not present.
112 ///
113 /// Example:
114 /// ```rust
115 /// use stupid_simple_kv::{Kv, MemoryBackend, KvValue, IntoKey};
116 /// let mut kv = Kv::new(Box::new(MemoryBackend::new()));
117 /// let val = kv.get(&(42u64, "x")).unwrap();
118 /// ```
119 pub fn get(&self, key: &dyn IntoKey) -> KvResult<Option<KvValue>> {
120 let key = key.to_key();
121 let pairs = self
122 .backend
123 .try_read()?
124 .get_range(Some(key.clone()), key.successor())?;
125 if pairs.is_empty() {
126 Ok(None)
127 } else {
128 let (decoded, _) =
129 bincode::decode_from_slice::<KvValue, _>(&pairs[0].1, bincode::config::standard())
130 .map_err(KvError::ValDecodeError)?;
131 Ok(Some(decoded))
132 }
133 }
134
135 /// Set the value for a given key, overwriting it if present.
136 ///
137 /// Example:
138 /// ```rust
139 /// use stupid_simple_kv::{Kv, MemoryBackend, KvValue, IntoKey};
140 /// let mut kv = Kv::new(Box::new(MemoryBackend::new()));
141 /// kv.set(&(7u64, true, "foo"), 123i64.into()).unwrap();
142 /// ```
143 pub fn set(&mut self, key: &dyn IntoKey, value: KvValue) -> KvResult<()> {
144 self.set_optional(key, Some(value))
145 }
146
147 pub(crate) fn set_optional(
148 &mut self,
149 key: &dyn IntoKey,
150 value: Option<KvValue>,
151 ) -> KvResult<()> {
152 let key = key.to_key();
153 if let Some(v) = value {
154 let encoded = bincode::encode_to_vec(v, bincode::config::standard())
155 .map_err(KvError::ValEncodeError)?;
156 self.backend.try_write()?.set(key, Some(encoded))
157 } else {
158 // Remove the key completely!
159 self.backend.try_write()?.set(key, None)
160 }
161 }
162
163 /// Delete the value for a given key. Returns the key and previous value if present.
164 ///
165 /// Example:
166 /// ```rust
167 /// use stupid_simple_kv::{Kv, MemoryBackend, IntoKey};
168 /// let mut kv = Kv::new(Box::new(MemoryBackend::new()));
169 /// let maybe_pair = kv.delete(&(3u64, false));
170 /// ```
171 pub fn delete(&mut self, key: &dyn IntoKey) -> KvResult<Option<(KvKey, KvValue)>> {
172 let made = key.to_key();
173 let val = self.get(key)?;
174 if let Some(val) = val {
175 self.set_optional(key, None)?;
176 Ok(Some((made, val)))
177 } else {
178 Ok(None)
179 }
180 }
181
182 /// List all entries in the keyspace.
183 /// Usually, you should use [`Self::list`] with filters for efficient selects.
184 ///
185 /// Example:
186 /// ```rust
187 /// use stupid_simple_kv::{Kv, MemoryBackend, KvValue, IntoKey};
188 /// let mut kv = Kv::new(Box::new(MemoryBackend::new()));
189 /// let all = kv.entries().unwrap();
190 /// ```
191 pub fn entries(&mut self) -> KvResult<Vec<(KvKey, KvValue)>> {
192 KvListBuilder {
193 backend: self.backend.clone(),
194 start: None,
195 end: None,
196 prefix: None,
197 }
198 .entries()
199 }
200
201 /// Build a query for scanning/filtering the key-value space.
202 /// Use methods like [`KvListBuilder::prefix`], [`KvListBuilder::start`], [`KvListBuilder::end`] for range scans.
203 ///
204 /// Example:
205 /// ```rust
206 /// use stupid_simple_kv::{Kv, MemoryBackend, KvValue, IntoKey};
207 /// let mut kv = Kv::new(Box::new(MemoryBackend::new()));
208 /// // List all keys starting with (1, _)
209 /// let results = kv.list().prefix(&(1u64,)).entries().unwrap();
210 /// ```
211 pub fn list(&self) -> KvListBuilder {
212 KvListBuilder::new(self.backend.clone())
213 }
214
215 /// Dump all keys and values as a pretty, parseable JSON value.
216 /// Useful for debugging or migration. Keys are debug-formatted.
217 pub fn to_serde_json(&mut self) -> KvResult<serde_json::Value> {
218 let mut map = serde_json::Map::new();
219 for (key, value) in self.entries()? {
220 let display = to_display_string(&key.0).ok_or(KvError::KeyDecodeError(format!(
221 "Invalid key {key:#?}.\nThis should never happen, please file a bug report."
222 )))?;
223 map.insert(display, serde_json::Value::from(&value));
224 }
225 Ok(serde_json::Value::Object(map))
226 }
227
228 /// Construct a new `Kv` from a serde-compatible JSON value (from [`to_serde_json`]).
229 /// Fails if any key or value is incompatible.
230 pub fn from_serde_json(backend: Box<dyn KvBackend>, json: serde_json::Value) -> KvResult<Self> {
231 if let Some(obj) = json.as_object() {
232 let mut kv = Self::new(backend);
233 for (display, value) in obj.iter() {
234 let key = parse_display_string_to_key(display).ok_or(KvError::KeyDecodeError(
235 format!("Could not decode JSON key {display} to KvKey."),
236 ))?;
237 kv.set(&key, KvValue::from(value))?;
238 }
239 Ok(kv)
240 } else {
241 Err(KvError::Other(format!(
242 "Invalid JSON value while trying to make Kv from serde_json::Value: {json}"
243 )))
244 }
245 }
246
247 /// Dump the entire database to a JSON string.
248 /// See [`from_json_string`] for restoring.
249 pub fn dump_json(&mut self) -> KvResult<String> {
250 let json = self.to_serde_json()?;
251 Ok(json.to_string())
252 }
253
254 /// Restore a `Kv` from a JSON string previously written by [`dump_json`].
255 ///
256 /// Example:
257 /// ```rust
258 /// use stupid_simple_kv::{Kv, MemoryBackend, KvValue, IntoKey};
259 /// let mut kv = Kv::new(Box::new(MemoryBackend::new()));
260 /// let json = kv.dump_json().unwrap();
261 /// let backend = Box::new(MemoryBackend::new());
262 /// let mut loaded = Kv::from_json_string(backend, json).unwrap();
263 /// ```
264 pub fn from_json_string(backend: Box<dyn KvBackend>, json: String) -> KvResult<Self> {
265 let json: serde_json::Map<String, serde_json::Value> = serde_json::from_str(&json)
266 .map_err(|e| KvError::Other(format!("serde error parsing json: {e}")))?;
267 Self::from_serde_json(backend, serde_json::Value::Object(json))
268 }
269
270 pub fn clear(&mut self) -> KvResult<()> {
271 self.backend.try_write()?.clear()
272 }
273}