Persistent storage
Lets start with designing the disk storage format. The non-goal Writing low level code stears off designing a file format and using direct file access. A good alternative is SQLite. Lets set it up first.
Bootstrapping the project
I'll call the project sakkosekk, which is Norwegian for bean bag chair.
Bootstrapping with Cargo:
~/g/build-your-own-couchdb $ cargo init sakkosekk
Created binary (application) package
~/g/build-your-own-couchdb $ cd sakkosekk/
~/g/b/sakkosekk $ cargo run
Compiling sakkosekk v0.1.0 (/Users/arve/git/build-your-own-couchdb/sakkosekk)
Finished dev [unoptimized + debuginfo] target(s) in 10.24s
Running `target/debug/sakkosekk`
Hello, world!
Adding SQLite
Bindings for SQLite is available through the rusqlite crate:
~/g/b/sakkosekk $ echo '[dependencies]' >> Cargo.toml
~/g/b/sakkosekk $ echo 'rusqlite = { version = "0.20", features = ["bundled"] }' >> Cargo.toml
The bundled feature is enabled for hassle free sqlite3 linking.
Database schema
Documents in the database will have the columns:
- indentifier,
- revision,
- hash and
- document data.
Open database:
use rusqlite::{named_params, Connection};
fn main() {
let db = Connection::open("database.sqlite").expect("Unable to open 'database.sqlite'.");
Creating table:
#![allow(unused_variables)]
fn main() {
db.execute_batch(
"create table documents (
id text primary key not null,
revision integer not null,
hash blob not null,
data text not null
)",
)
.expect("Unable to create documents table.");
}
Inserting document:
#![allow(unused_variables)]
fn main() {
db.execute_named(
"insert into documents (id, revision, hash, data)
values (:id, :revision, :hash, :data)",
named_params!(
":id": "asdf",
":revision": 0,
":hash": vec![0u8],
":data": r#"{ "a": 1, "b": 123 }"#
),
)
.expect("Unable to insert document.");
}
Reading document by the identifier:
#![allow(unused_variables)]
fn main() {
let data: String = db
.query_row_named(
"select data from documents where id=:id",
named_params!(":id": "asdf"),
|row| row.get(0),
)
.expect("Unable to get document with id 'asdf'");
println!("data: {}", data);
}
}
Result:
~/g/b/sakkosekk $ cargo run
Finished dev [unoptimized + debuginfo] target(s) in 0.31s
Running `target/debug/sakkosekk`
data: { "a": 1, "b": 123 }
Next up: Abstractions around creating the database schema, inserting documents and reading documents.