BonsaiDb v0.3.0: Optimized views, bug fixes, and more

Written by Jonathan Johnson. Published 2022-03-03.

What is BonsaiDb?

BonsaiDb is a new database aiming to be the most developer-friendly Rust database. BonsaiDb has a unique feature set geared at solving many common data problems. We have a page dedicated to answering the question: What is BonsaiDb?. All source code is dual-licensed under the MIT and Apache License 2.0 licenses.

BonsaiDb v0.3.0 has been released featuring optimized view processing, bug fixes, and a few new features -- including one from a new contributor!

Optimization of the view processing system has been covered in the previous blog post.

Deleting users via StorageConnection

A new function, delete_user() has been added to StorageConnection, allowing for users to not only be created but also deleted without direct database access. This feature was added by @vbmade2000 -- now the third contributor to the BonsaiDb repository!

BonsaiDb provides open-access its admin schema types. This meant that users could still be deleted, but it required doing so directly through Storage::admin(), and couldn't be done over a networked client, for example.

Querying Data by Prefix

A user on Discord requested an easier way to be able to query data using a prefix. For example, if the key type is a String or Vec<u8>, a query should be able to be made for any matches that start with a given prefix. Collections now support listing documents with a given prefix:

#[derive(Debug, Serialize, Deserialize, Default, Collection)]
#[collection(name = "MyCollection", primary_key = String)]
pub struct MyCollection;

let results = MyCollection::list_with_prefix(String::from("a"), db).await?;

results will contain all documents whose id's start with a. The same capability is also available for views:

#[derive(View, Debug, Clone)]
#[view(name = "by-name", key = String, collection = MyCollection)]
struct ByName;

for mapping in db
    .view::<ByName>()
    .with_key_prefix(String::from("a"))
    .query()
    .await?
{
    assert!(mapping.key.starts_with("a"));
    println!("{} in document {:?}", mapping.key, mapping.source);
}

This functionality is powered by a new trait, IntoPrefixRange, which allows any custom key type to provide this functionality if possible. BonsaiDb currently only provides implementations for String and the Vec<u8> types.

Nebari Bug Fixes

This release updates Nebari to v0.4.0. It contains an important fix to ensure the transaction log is always written sequentially. This edge case was discovered while running unit tests "one more time" before preparing a release. A unit test that never failed suddenly failed. Here's the code in question that failed:

let mut handles = Vec::new();
for _ in 0..10 {
    let manager = manager.clone();
    handles.push(std::thread::spawn(move || {
        for id in 0_u32..1_000 {
            let tx = manager.new_transaction([&id.to_be_bytes()[..]]);
            tx.commit().unwrap();
        }
    }));
}

The test then proceeds to wait for all the threads to finish and verify the results. One thing it does is attempt to load each transaction one by one. At first glance, this seems innocuous, but due to how Nebari is designed, new_transaction() allocates a transaction id, but it isn't written to the transaction log until commit() occurs. I was lucky to have this test fail, as it was a legitimate edge case that I hadn't tested against. Needless to say, there's now a dedicated unit test to out-of-order writing.

While working on this fix, however, I now have enough of a reason to implement the next version of the transaction log to address a few design issues I've thought of since writing it originally. The good news is that even if the transaction log your database has currently is out of order, I plan to have the upgrade process to the new format fix any ordering issues.

Getting Started

Our homepage has basic setup instructions and a list of examples. We have started writing a user's guide, and we have tried to write good documentation.

We would love to hear from you if you have questions or feedback. We have community Discourse forums and a Discord server, but also welcome anyone to open an issue with any questions or feedback.

We dream big with BonsaiDb, and we believe that it can simplify writing and deploying complex, data-driven applications in Rust. We would love additional contributors who have similar passions and ambitions.

Lastly, if you build something with one of our libraries, we would love to hear about it. Nothing makes us happier than hearing people are building things with our crates!