db_rs/lib.rs
1//! An ergonomic, embedded, single-threaded database for Rustaceans.
2//!
3//! ## Strengths
4//!
5//! - Define a schema in Rust.
6//! - Use **your** types in the database as long as they implement `Serialize` and `Deserialize`. You don't have to fuss around
7//! with converting your data to database-specific types.
8//! - All your database interactions are typesafe. When you type `db.`, your tooling will suggest a list of your tables. When you
9//! select a table, you'll be greeted with that table-type's contract populated with your types. No need to wrap your db
10//! in a handwritten type safe contract.
11//! - Supports a variety of simple data-structures, including LookupTables, Lists, and many more. Implementing your own
12//! table types is trivial.
13//! - All table mutations are persisted to an append only log using the fast & compact bincode representation of your types.
14//! - You can `begin_transaction()`s to express atomic updates to multiple tables.
15//!
16//! ## Quickstart
17//!
18//! Add the following to your `Cargo.toml`:
19//!
20//! ```toml
21//! db-rs = "0.2.1"
22//! db-rs-derive = "0.2.1"
23//! ```
24//!
25//! Define your schema:
26//!
27//! ```ignore
28//! use db_rs_derive::Schema;
29//! use db_rs::{Single, List, LookupTable};
30//!
31//! #[derive(Schema)]
32//! struct SchemaV1 {
33//! owner: Single<Username>,
34//! admins: List<Username>,
35//! users: LookupTable<Username, Account>,
36//! }
37//! ```
38//!
39//! Initialize your DB:
40//!
41//! ```ignore
42//! use db_rs::Db;
43//! use db_rs::Config;
44//!
45//! let mut db = SchemaV1::init(Config::in_folder("/tmp/test/"))?;
46//! db.owner.insert("Parth".to_string())?;
47//!
48//! println!("{}", db.owner.data().unwrap());
49//! ```
50//!
51//! ## Table Types
52//!
53//! Each table has an in-memory representation and a corresponding log entry format. For instance
54//! [List]'s in memory format is a [Vec], and you can look at it's corresponding [list::LogEntry]
55//! to see how writes will be written to disk.
56//!
57//! Tables that start with `Lookup` have a `HashMap` as part of their in memory format.
58//! [LookupTable] is the most general form, while [LookupList] and [LookupSet] are specializations
59//! for people who want `HashMap<K, Vec<V>>` or `HashMap<K, HashSet<V>>`. Their reason for
60//! existence is better log performance in the case of small modifications to the `Vec` or
61//! `HashSet` in question (see [lookup_list::LogEntry] or [lookup_set::LogEntry]).
62//!
63//!
64//! ## Log Compaction
65//!
66//! At any point you can call [Db::compact_log] on your database. This will atomically write a
67//! compact representation of all your current tables. For example if there's a key in a
68//! LookupTable that was written to many times, the compact representation will only contain the
69//! last value. Each table type descibes it's own compact representation.
70//!
71//! If your database is in an `Arc<Mutex>>` you can additionally use the [BackgroundCompacter]
72//! which will perform compactions periodically in a separate thread.
73//!
74//! ## TXs and Batch Writing
75//!
76//! You can [Db::begin_transaction] which will allow you to express batch operations that can be
77//! discarded as a set if your program is interrupted. Presently there is no way to abort a
78//! transaction. TXs are also a mechanism for batch writing, log entries are kept in memory until
79//! the transaction completes and written once to disk.
80//!
81//! ## Active areas of thought and research
82//!
83//! - Because the db implementation (like redis) is single threaded, it forces you to achieve application throughput via low
84//! latency rather than concurrency. Currently, this suits our needs. Simply being embedded gives us more than enough
85//! throughput compared to something like Postgres. For use in a server-style setting put the database in
86//! an `Arc<Mutex<>>`.
87//! - The database offers no tools at the moment to define integrity constraints beyond what the Rust type system implicitly
88//! enforces (non-null for instance). At the moment for us, this is simply an application side concern.
89//!
90//! ## Features
91//!
92//! `clone` - derive clone on all table types. Consistency between cloned database is not provided.
93//! Useful in testing situations.
94//!
95//! ## Used by
96//!
97//! - [Lockbook](https://github.com/lockbook/lockbook)
98//!
99
100pub use crate::compacter::BackgroundCompacter;
101pub use crate::compacter::CancelSig;
102pub use crate::config::Config;
103pub use crate::db::Db;
104pub use crate::errors::DbError;
105pub use crate::errors::DbResult;
106pub use crate::logger::Logger;
107pub use crate::logger::TxHandle;
108
109pub use crate::list::List;
110pub use crate::lookup::LookupTable;
111pub use crate::lookup_list::LookupList;
112pub use crate::lookup_set::LookupSet;
113pub use crate::single::Single;
114
115pub mod compacter;
116pub mod config;
117pub mod db;
118pub mod errors;
119pub mod list;
120pub mod logger;
121pub mod lookup;
122pub mod lookup_list;
123pub mod lookup_set;
124pub mod single;
125pub mod table;
126
127pub type TableId = u8;
128pub type ByteCount = u32;