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}