Husky is an abstraction around sled that allows for the creation of views with an API similar to iterators. Its aim is to make cache and indexing easier.
Below is a list of features. For examples, check the documentation.
To use husky with rkyv
toml
husky = "0.2"
To use husky with serde
toml
husky = { version = "0.2", default-features = false, features = ["serde"] }
Open a database with
rust
let db = husky::open("db_name").unwrap();
or
rust
let db = husky::open_temp().unwrap();
You can open a single entry in the database
rust
let single = db.open_single("key").unwrap();
A key-value tree on disk
rust
let tree = db.open_tree("name").unwrap();
Or a temporary key-value tree
rust
let temp = db.open_temp();
Through the View trait you can query entries in the tree.
rust
use husky::View;
rust
assert_eq!(tree.is_empty(), Some(false));
rust
assert_eq!(tree.contains_key(1), Ok(true));
assert_eq!(tree.contains_key(2), Ok(true));
rust
assert_eq!(tree.get(1), Ok(Some("first value")));
assert_eq!(tree.get(2), Ok(Some("last value")));
rust
assert_eq!(tree.get_lt(2), Ok(Some("first value"));
assert_eq!(tree.get_gt(1), Ok(Some("last value"));
rust
let mut range = tree.range(..).unwrap();
assert_eq!(range.next(), Ok(Some((1, "first value"))));
assert_eq!(range.next(), Ok(Some((2, "last value"))));
rust
let mut iter = tree.iter();
assert_eq!(iter.next(), Ok(Some((1, "first value"))));
assert_eq!(iter.next(), Ok(Some((2, "last value"))));
rust
assert_eq!(tree.first(), Ok(Some((1, "first value"))));
assert_eq!(tree.last() , Ok(Some((2, "last value"))));
Through the Change trait you can manipulate the entries in the tree
rust
use husky::Change;
rust
let previous = tree.insert("key", "value").unwrap();
rust
let previous = tree.remove("key").unwrap();
rust
tree.clear().unwrap();
If the key type has the AutoInc trait implemented, you can push values.
By default it is implemented for all unsigned integers and usize.
rust
tree.push("value").unwrap()
Through the Operate trait you can create new views.
They are lazy wrappers around the original, but you can store their results.
rust
use husky::Operate;
rust
let map = tree.map(|key, value| "new_value");
rust
let transform = tree.map(|key, value| vec![
("first key", "first value"),
("second key", "second value")
]);
rust
let index = tree.map(|key, value| vec![
"first key",
"second key"
]);
rust
let chain = tree.chain(&other_tree);
rust
let zip = tree.zip(&other_tree);
let (a, b) = zip.unzip();
rust
let filter = tree.filter(|key, value| false);
let filter = tree.filter_map(|key, value| Some(value));
rust
let reducer = tree.reducer(|value, add| value.unwrap_or(0) + add);
rust
let reducer = tree.filter_reducer(|value, add| value.map(|v| v + add));
rust
let inserter = tree.inserter(|insert| insert);
rust
let inserter = tree.filter_inserter(|insert| Some(insert));
rust
tree.pipe(&other_tree);
Note that transform and index will also change the value type to a vector, because overwrites can happen. To further operate a transform or index, you must store or load them, as they require a key map.
You can store a view on the database through the Store trait
rust
use husky::Store;
let stored = tree.store("tree name").unwrap();
Or load it in memory through the Load trait
rust
use husky::Load;
let loaded = tree.load().unwrap();
Once you load or store a tree its results will be cached, and it will spawn new threads on each operation to propagate events from the original tree.
The Watch trait provides you with access to a BusReader that listens to events in a view.
rust
use husky::Watch.
let reader = tree.watch();
A function to get the original tree's database.
rust
let db = tree.db();
And methods to synchronize changes.
rust
let sync = tree.sync();
assert_eq!(sync.incoming(), 0);
assert_eq!(sync.is_sync(), true);
sync.wait();
tree.wait();