1 unstable release

0.3.0 May 25, 2022
0.2.0 May 22, 2022
0.1.1 May 13, 2022
0.1.0 May 13, 2022

#2813 in Database interfaces

MIT license

150KB
4.5K SLoC

Husky

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.

Sections

Getting Started

Add Dependency

To use husky with rkyv

husky = "0.2"

To use husky with serde

husky = { version = "0.2", default-features = false, features = ["serde"] }

Open a Database

Open a database with

let db = husky::open("db_name").unwrap();

or

let db = husky::open_temp().unwrap();

Open a Tree

You can open a single entry in the database

let single = db.open_single("key").unwrap();

A key-value tree on disk

let tree = db.open_tree("name").unwrap();

Or a temporary key-value tree

let temp = db.open_temp();

Viewing

Through the View trait you can query entries in the tree.

use husky::View;

Check if a view is empty

assert_eq!(tree.is_empty(), Some(false));

Check if a key exists

assert_eq!(tree.contains_key(1),  Ok(true));
assert_eq!(tree.contains_key(2),  Ok(true));

Get individual values

assert_eq!(tree.get(1),  Ok(Some("first value")));
assert_eq!(tree.get(2),  Ok(Some("last  value")));

Get entries before and after

assert_eq!(tree.get_lt(2), Ok(Some("first value"));
assert_eq!(tree.get_gt(1), Ok(Some("last  value"));

Get a range of entries

let mut range = tree.range(..).unwrap();
assert_eq!(range.next(),  Ok(Some((1, "first value"))));
assert_eq!(range.next(),  Ok(Some((2, "last  value"))));

Get all the entries

let mut iter = tree.iter();
assert_eq!(iter.next(),  Ok(Some((1, "first value"))));
assert_eq!(iter.next(),  Ok(Some((2, "last  value"))));

Get the first and last entries

assert_eq!(tree.first(),  Ok(Some((1, "first value"))));
assert_eq!(tree.last() ,  Ok(Some((2, "last  value"))));

Changing

Through the Change trait you can manipulate the entries in the tree

use husky::Change;

Insert an entry

let previous = tree.insert("key", "value").unwrap();

Remove an entry

let previous = tree.remove("key").unwrap();

Clear all entries

tree.clear().unwrap();

Insert with auto increment

If the key type has the AutoInc trait implemented, you can push values. By default it is implemented for all unsigned integers and usize.

tree.push("value").unwrap()

Operating

Through the Operate trait you can create new views. They are lazy wrappers around the original, but you can store their results.

use husky::Operate;

Map entries

let map = tree.map(|key, value| "new_value");

Transform entries

let transform = tree.map(|key, value| vec![
  ("first  key", "first  value"),
  ("second key", "second value")
]);

Reindex entries

let index = tree.map(|key, value| vec![
  "first  key",
  "second key"
]);

Chain two views

let chain = tree.chain(&other_tree);

Zip two views

let zip = tree.zip(&other_tree);
let (a, b) = zip.unzip();

Filter entries

let filter = tree.filter(|key, value| false);
let filter = tree.filter_map(|key, value| Some(value));

Reduce inserts

let reducer = tree.reducer(|value, add| value.unwrap_or(0) + add);

Filter and reduce inserts

let reducer = tree.filter_reducer(|value, add| value.map(|v| v + add));

Parse inserts

let inserter = tree.inserter(|insert| insert);

Filter and parse inserts

let inserter = tree.filter_inserter(|insert| Some(insert));

Pipe changes to another tree

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.

Storing

You can store a view on the database through the Store trait

use husky::Store;
let stored = tree.store("tree name").unwrap();

Or load it in memory through the Load trait

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.

Listening

The Watch trait provides you with access to a BusReader that listens to events in a view.

use husky::Watch.
let reader = tree.watch();

A function to get the original tree's database.

let db = tree.db();

And methods to synchronize changes.

let sync = tree.sync();
assert_eq!(sync.incoming(), 0);
assert_eq!(sync.is_sync(), true);
sync.wait();
tree.wait();

Dependencies

~4–9.5MB
~106K SLoC