BonsaiDb
Formerly known as PliantDb
. Not yet released on crates.io as BonsaiDb
.
BonsaiDb aims to be a Rust-written, ACID-compliant, document-database inspired by CouchDB. While it is inspired by CouchDB, this project will not aim to be compatible with existing CouchDB servers, and it will be implementing its own replication, clustering, and sharding strategies.
Project Goals
The high-level goals for this project are:
-
☑️ Be able to build a document-based database's schema using Rust types. -
☑️ Run within your Rust binary, simplifying basic deployments. -
☑️ Run as a local-only file-based database with no networking involved. -
☑️ Run as a networked server using QUIC with TLS enabled by default. -
☑️ Expose a Publish/Subscribe eventing system. - ☐ Expose a Job queue and scheduling system -- a la Sidekiq or SQS (tracking issue #78)
- ☐ Easily set up read-replicas between multiple servers (tracking issue #90)
- ☐ Easily run a highly-available quorum-based cluster across at least 3 servers (tracking issue #104)
⚠️
Status of this project
You should not attempt to use this software in anything except for experiments. This project is under active development (), but at the point of writing this README, the project is too early to be used.
If you're interested in chatting about this project or potentially wanting to contribute, come chat with us on Discord: .
Example
Check out ./examples for examples. To get an idea of how it works, this is a simple schema:
#[derive(Debug, Serialize, Deserialize)]
struct Shape {
pub sides: u32,
}
impl Collection for Shape {
fn collection_name() -> Result<CollectionName, InvalidNameError> {
CollectionName::new("khonsulabs", "shapes")
}
fn define_views(schema: &mut Schematic) -> Result<(), Error> {
schema.define_view(ShapesByNumberOfSides)
}
}
#[derive(Debug)]
struct ShapesByNumberOfSides;
impl CollectionView for ShapesByNumberOfSides {
type Collection = Shape;
type Key = u32;
type Value = usize;
fn version(&self) -> u64 {
1
}
fn name(&self) -> Result<Name, InvalidNameError> {
Name::new("by-number-of-sides")
}
fn map(&self, document: CollectionDocument<Shape>) -> MapResult<Self::Key, Self::Value> {
Ok(document.emit_key_and_value(document.contents.sides, 1))
}
fn reduce(
&self,
mappings: &[MappedValue<Self::Key, Self::Value>],
_rereduce: bool,
) -> Result<Self::Value, view::Error> {
Ok(mappings.iter().map(|m| m.value).sum())
}
}
After you have your collection(s) defined, you can open up a database and insert documents:
let db = Database::open::<Shape>(StorageConfiguration::new("view-examples.bonsaidb")).await?;
// Insert a new document into the Shape collection.
Shape::new(3).insert_into(&db).await?;
And query data using the Map-Reduce-powered view:
let triangles = db
.view::<ShapesByNumberOfSides>()
.with_key(3)
.query()
.await?;
println!("Number of triangles: {}", triangles.len());
See the examples README for a list of all available examples.
Why write another database?
- Deploying highly-available databases is hard (and often expensive). It doesn't need to be.
- We are passionate Rustaceans and are striving for an ideal of supporting a 100% Rust-based deployment ecosystem for newly written software.
- Specifically for the founding author @ecton, the idea for this design dates back to thoughts of fun side-projects while running my last business which was built atop CouchDB. Working on this project is fulfilling a long-time desire of his.
Feature Flags
No feature flags are enabled by default in the bonsaidb
crate. This is because in most Rust executables, you will only need a subset of the functionality. If you'd prefer to enable everything, you can use the full
feature:
[dependencies]
bonsaidb = { version = "*", default-features = false, features = "full" }
full
: Enableslocal-full
,server-full
, andclient-full
.cli
: Enables thebonsaidb
executable.
Local databases only
[dependencies]
bonsaidb = { version = "*", default-features = false, features = "local-full" }
local-full
: Enables all the flags belowlocal
: Enables thelocal
module, which re-exports the cratebonsaidb-local
.local-cli
: Enables theStructOpt
structures for embedding database management commands into your own command-line interface.local-encryption
: Enables at-rest encryption.local-instrument
: Enables instrumenting withtracing
.local-multiuser
: Enables multi-user support.
BonsaiDb
server
[dependencies]
bonsaidb = { version = "*", default-features = false, features = "server-full" }
server-full
: Enables all the flags below,server
: Enables theserver
module, which re-exports the cratebonsaidb-server
.server-acme
: Enables automtic certificate acquisition through ACME/LetsEncrypt.server-cli
: Enables thecli
module.server-encryption
: Enables at-rest encryption.server-hyper
: Enables convenience functions for upgrading websockets usinghyper
.server-instrument
: Enables instrumenting withtracing
.server-pem
: Enables the ability to install a certificate using the PEM format.server-websockets
: EnablesWebSocket
support.
BonsaiDb
server
Client for accessing a [dependencies]
bonsaidb = { version = "*", default-features = false, features = "client-full" }
client-full
: Enablesclient
,client-trusted-dns
andclient-websockets
client
: Enables theclient
module, which re-exports the cratebonsaidb-client
.client-trusted-dns
: Enables using trust-dns for DNS resolution. If not enabled, all DNS resolution is done with the OS's default name resolver.client-websockets
: EnablesWebSocket
support forbonsaidb-client
.
Developing BonsaiDb
Pre-commit hook
Our CI processes require that some commands succeed without warnings or errors. These checks can be performed manually by running:
cargo xtask test --fail-on-warnings
Or, if you would like to run all these checks before each commit, you can install the check as a pre-commit hook:
cargo xtask install-pre-commit-hook
Open-source Licenses
This project, like all projects from Khonsu Labs, are open-source. This repository is available under the MIT License or the Apache License 2.0.
To learn more about contributing, please see CONTRIBUTING.md.