-
Notifications
You must be signed in to change notification settings - Fork 54
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
11 changed files
with
381 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,3 +3,4 @@ | |
Cargo.lock | ||
db_path | ||
bindings/python/target | ||
guide/book |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
[book] | ||
authors = ["crwen"] | ||
language = "en" | ||
multilingual = false | ||
src = "src" | ||
title = "The Tonbo Guide" | ||
|
||
[output.html] | ||
git-repository-url = "https://github.com/tonbo-io/tonbo" | ||
[output.html.playground] | ||
runnable = false |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
# Summary | ||
|
||
[Introduction](./introduction.md) | ||
|
||
- [Getting started](./start.md) | ||
- [Examples](./examples/index.md) | ||
- [Using Tonbo](./examples/declare.md) | ||
- [Integrate with Datafusio](./examples/datafusion.md) | ||
- [Using under Wasm](./examples/wasm.md) | ||
- [Contribution](./contribution/index.md) | ||
- [Building](./contribution/build.md) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
# Building Tonbo | ||
|
||
TODO |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
# Integrate with Datafusio | ||
|
||
TODO |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
# Using Tonbo | ||
|
||
define your schema | ||
|
||
```rust | ||
use tonbo::Record; | ||
|
||
/// Use macro to define schema of column family just like ORM | ||
/// It provides type-safe read & write API | ||
#[derive(Record, Debug)] | ||
pub struct User { | ||
#[record(primary_key)] | ||
name: String, | ||
email: Option<String>, | ||
age: u8, | ||
bytes: Bytes, | ||
} | ||
``` | ||
|
||
```rust | ||
use std::ops::Bound; | ||
|
||
use bytes::Bytes; | ||
use fusio::path::Path; | ||
use futures_util::stream::StreamExt; | ||
use tokio::fs; | ||
use tonbo::{executor::tokio::TokioExecutor, DbOption, Projection, Record, DB}; | ||
|
||
|
||
#[tokio::main] | ||
async fn main() { | ||
// make sure the path exists | ||
let _ = fs::create_dir_all("./db_path/users").await; | ||
|
||
let options = DbOption::new( | ||
Path::from_filesystem_path("./db_path/users").unwrap(), | ||
&UserSchema, | ||
); | ||
// pluggable async runtime and I/O | ||
let db = DB::new(options, TokioExecutor::current(), UserSchema) | ||
.await | ||
.unwrap(); | ||
|
||
// insert with owned value | ||
db.insert(User { | ||
name: "Alice".into(), | ||
email: Some("[email protected]".into()), | ||
age: 22, | ||
bytes: Bytes::from(vec![0, 1, 2]), | ||
}) | ||
.await | ||
.unwrap(); | ||
|
||
{ | ||
// tonbo supports transaction | ||
let txn = db.transaction().await; | ||
|
||
// get from primary key | ||
let name = "Alice".into(); | ||
|
||
// get the zero-copy reference of record without any allocations. | ||
let user = txn | ||
.get( | ||
&name, | ||
// tonbo supports pushing down projection | ||
Projection::All, | ||
) | ||
.await | ||
.unwrap(); | ||
assert!(user.is_some()); | ||
assert_eq!(user.unwrap().get().age, Some(22)); | ||
|
||
{ | ||
let upper = "Blob".into(); | ||
// range scan of user | ||
let mut scan = txn | ||
.scan((Bound::Included(&name), Bound::Excluded(&upper))) | ||
// tonbo supports pushing down projection | ||
.projection(vec![1, 3]) | ||
// push down limitation | ||
.limit(1) | ||
.take() | ||
.await | ||
.unwrap(); | ||
while let Some(entry) = scan.next().await.transpose().unwrap() { | ||
assert_eq!( | ||
entry.value(), | ||
Some(UserRef { | ||
name: "Alice", | ||
email: Some("[email protected]"), | ||
age: None, | ||
bytes: Some(&[0, 1, 2]), | ||
}) | ||
); | ||
} | ||
} | ||
|
||
// commit transaction | ||
txn.commit().await.unwrap(); | ||
} | ||
} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
# Examples of using Tonbo |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
|
||
# Using under Wasm | ||
|
||
This is the Wasm example of tonbo showing how to use tonbo under Wasm. | ||
|
||
## `Cargo.toml` | ||
|
||
Since only limited features of tokio can be used in wasm, we need to disable tokio and use `wasm` feature in tonbo. | ||
|
||
```toml | ||
fusio = { git = "https://github.com/tonbo-io/fusio.git", rev = "216eb446fb0a0c6e5e85bfac51a6f6ed8e5ed606", package = "fusio", version = "0.3.3", features = [ | ||
"dyn", | ||
"fs", | ||
] } | ||
tonbo = { git = "https://github.com/tonbo-io/tonbo", default-features = false, features = ["wasm"] } | ||
``` | ||
|
||
## Create DB | ||
|
||
Tonbo provide [OPFS(origin private file system)](https://developer.mozilla.org/en-US/docs/Web/API/File_System_API/Origin_private_file_system) as storage backend, but the path is a little different. You should use `Path::from_opfs_path` or `Path::parse` rather than `Path::from_filesystem_path` and it is not permitted to use paths that temporarily step outside the sandbox with something like `../foo` or `./bar`. | ||
|
||
```rust | ||
use fusio::path::Path; | ||
use tonbo::{executor::opfs::OpfsExecutor, DbOption, DB}; | ||
|
||
async fn main() { | ||
|
||
let options = DbOption::new( | ||
Path::from_opfs_path("db_path/users").unwrap(), | ||
&UserSchema, | ||
); | ||
let db = DB::<User, OpfsExecutor>::new(options, OpfsExecutor::new(), UserSchema) | ||
.await | ||
.unwrap(); | ||
} | ||
``` | ||
|
||
## Operations on DB | ||
|
||
After create `DB` instance, you can operate it as usual | ||
|
||
```rust | ||
let txn = db.transaction().await; | ||
|
||
// get from primary key | ||
let name = "Alice".into(); | ||
|
||
let user = txn.get(&name, Projection::All).await.unwrap(); | ||
|
||
let upper = "Blob".into(); | ||
// range scan of user | ||
let mut scan = txn | ||
.scan((Bound::Included(&name), Bound::Excluded(&upper))) | ||
// tonbo supports pushing down projection | ||
.projection(vec![1]) | ||
// push down limitation | ||
.limit(1) | ||
.take() | ||
.await | ||
.unwrap(); | ||
|
||
while let Some(entry) = scan.next().await.transpose().unwrap() { | ||
assert_eq!( | ||
entry.value(), | ||
Some(UserRef { | ||
name: "Alice", | ||
email: Some("[email protected]"), | ||
age: None, | ||
}) | ||
); | ||
} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
# The Tonbo user guide | ||
Welcome to the tonbo user guide! This book is about [tonbo](https://github.com/tonbo-io/tonbo). Tonbo is an embedded, persistent database offering fast KV-like methods for conveniently writing and scanning type-safe structured data. Tonbo can be used to build data-intensive applications, including other types of databases. | ||
|
||
|
||
The rough order of material in this user guide is as follows: | ||
1. Getting started | ||
2. Examples on using tonbo | ||
3. How to make contributions to Tonbo | ||
|
||
|
||
If you want to learn the design of tonbo, you can see this [blog](https://tonbo.io/blog/introducing-tonbo). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,166 @@ | ||
## Installation | ||
|
||
To get started using tonbo you should make sure you have Rust installed on your system. If you haven't alreadly done yet, try following the instructions [here](https://www.rust-lang.org/tools/install). | ||
|
||
## Adding dependencies | ||
|
||
```toml | ||
fusio = { git = "https://github.com/tonbo-io/fusio.git", rev = "216eb446fb0a0c6e5e85bfac51a6f6ed8e5ed606", package = "fusio", version = "0.3.3", features = [ | ||
"dyn", | ||
"fs", | ||
] } | ||
tokio = { version = "1", features = ["full"] } | ||
tonbo = { git = "https://github.com/tonbo-io/tonbo" } | ||
``` | ||
|
||
## Defining Schema | ||
|
||
You can use `Record` macro to define schema of column family just like ORM. Tonbo will generate all relevant files for you at compile time. | ||
|
||
```rust | ||
use tonbo::Record; | ||
|
||
#[derive(Record, Debug)] | ||
pub struct User { | ||
#[record(primary_key)] | ||
name: String, | ||
email: Option<String>, | ||
age: u8, | ||
bytes: Bytes, | ||
} | ||
``` | ||
|
||
- `Record`: Declare this struct as a Tonbo Schema | ||
- `#[record(primary_key)]`: Declare this key as primary key. Compound primary key is not supported now. | ||
- `Option` type represents this field can be null, otherwise it can not be null. | ||
|
||
Now, Tonbo support these types: | ||
|
||
- Number type: `i8`, `i16`, `i32`, `i64`, `u8`, `u16`, `u32`, `u64` | ||
- Boolean type: `bool` | ||
- String type: `bool` | ||
- Bytes: `bytes::Bytes` | ||
|
||
## Create DB | ||
|
||
After define you schema, you can create `DB` with a customized `DbOption` | ||
|
||
```rust | ||
use std::fs; | ||
use fusio::path::Path; | ||
use tonbo::{executor::tokio::TokioExecutor, DbOption, DB}; | ||
|
||
#[tokio::main] | ||
async fn main() { | ||
// make sure the path exists | ||
fs::create_dir_all("./db_path/users").unwrap(); | ||
|
||
let options = DbOption::new( | ||
Path::from_filesystem_path("./db_path/users").unwrap(), | ||
&UserSchema, | ||
); | ||
let db = DB::<User, TokioExecutor>::new(options, TokioExecutor::current(), UserSchema) | ||
.await | ||
.unwrap(); | ||
} | ||
``` | ||
|
||
`UserSchema` is a struct that tonbo generates for you in the compile time, so you do not need to import it. | ||
|
||
## Read/Write data | ||
|
||
After create `DB`, you can execute `insert`, `remove`, `get` now. But remember that you will get a `UserRef` object rather than the `User`, if you get record from tonbo. This is a struct that tonbo generates for you in the compile time. | ||
|
||
```rust | ||
db.insert(User { | ||
name: "Alice".into(), | ||
email: Some("[email protected]".into()), | ||
age: 22, | ||
}) | ||
.await | ||
.unwrap(); | ||
|
||
let age = db | ||
.get(&"Alice".into(), |entry| { | ||
// entry.get() will get a `UserRef` | ||
let user = entry.get(); | ||
println!("{:#?}", user); | ||
user.age | ||
}) | ||
.await | ||
.unwrap(); | ||
assert!(age.is_some()); | ||
assert_eq!(age, Some(22)); | ||
``` | ||
|
||
## Using transaction | ||
|
||
Tonbo supports transaction. You can also push down filter, limit and projection operators in query. | ||
|
||
```rust | ||
let txn = db.transaction().await; | ||
|
||
// get from primary key | ||
let name = "Alice".into(); | ||
|
||
// get the zero-copy reference of record without any allocations. | ||
let user = txn.get(&name, Projection::All).await.unwrap(); | ||
|
||
let upper = "Blob".into(); | ||
// range scan of user | ||
let mut scan = txn | ||
.scan((Bound::Included(&name), Bound::Excluded(&upper))) | ||
// tonbo supports pushing down projection | ||
.projection(vec![1]) | ||
// push down limitation | ||
.limit(1) | ||
.take() | ||
.await | ||
.unwrap(); | ||
|
||
while let Some(entry) = scan.next().await.transpose().unwrap() { | ||
assert_eq!( | ||
entry.value(), | ||
Some(UserRef { | ||
name: "Alice", | ||
email: Some("[email protected]"), | ||
age: None, | ||
}) | ||
); | ||
} | ||
``` | ||
|
||
## Using S3 backends | ||
|
||
Tonbo supports various storage backends, such as OPFS, S3, and maybe more in the future. You can use `DbOption::level_path` to specify which backend to use. | ||
|
||
For local storage, you can use `FsOptions::Local` as the parameter. And you can use `FsOptions::S3` for S3 storage. After create `DB`, you can then operator it like normal. | ||
|
||
```rust | ||
use fusio::{path::Path, remotes::aws::AwsCredential}; | ||
use fusio_dispatch::FsOptions; | ||
use tonbo::{executor::tokio::TokioExecutor, DbOption, DB}; | ||
|
||
#[tokio::main] | ||
async fn main() { | ||
let fs_option = FsOptions::S3 { | ||
bucket: "wasm-data".to_string(), | ||
credential: Some(AwsCredential { | ||
key_id: "key_id".to_string(), | ||
secret_key: "secret_key".to_string(), | ||
token: None, | ||
}), | ||
endpoint: None, | ||
sign_payload: None, | ||
checksum: None, | ||
region: Some("region".to_string()), | ||
}; | ||
|
||
let options = DbOption::new(Path::from_filesystem_path("s3_path").unwrap(), &UserSchema) | ||
.level_path(2, "l2", fs_option); | ||
|
||
let db = DB::<User, TokioExecutor>::new(options, TokioExecutor::current(), UserSchema) | ||
.await | ||
.unwrap(); | ||
} | ||
``` |