Expand description
Struct DB is a Rust library that provides a simple, fast, and embedded database solution, focusing on maintaining coherence between Rust types and stored data with minimal boilerplate. It supports multiple indexes, real-time watch with filters, schema migration.
Use macro struct_db
:
- required:
fn_primary_key(<function name>)
associates a function of the struct that generates the primary key of the struct. Allows only onefn_primary_key
declaration. - optional:
fn_secondary_key(<function name>)
associates a function of the struct that generates a secondary key of the struct. Allows multiplefn_secondary_key
declarations.
struct_db
generates an enum <your_type>
with the suffix Key
that contains all the secondary keys like: E.g. <your_type>Key::<your_secondary_key>
more details here
.
API
- Initialize a database:
Db::init_tmp(<database name>)
initializes a database at a temporary path.Db::init(<path>)
initializes a database at a given path.
- Initialize schema
Db::add_schema(
<your_item>::struct_db_schema()
)
initializes a schema.
- Transactions
db.transaction()
starts a read-write transaction.db.read_transaction()
starts a read-only transaction.
- Tables
transaction.tables()
returns aTables
read_only_transaction::tables()
returns aReadOnlyTables
.
- Write operations
tables.insert(&txn,<item>)
inserts an item into the database.tables.update(&txn,<old_item>, <new_item>)
updates an item in the database.tables.remove(&txn,<item>)
removes an item from the database.tables.migrate::<old_type, new_type>(&txn)
migrates the schema fromold_type
tonew_type
.
- Read operations by
- Primary key
tables.primary_get(&txn,<value>)
get an item.tables.primary_iter(&txn)
iterate all items.tables.primary_iter_range(&txn,<start_value>..<end_value>)
all items in range.tables.primary_iter_start_with(&txn,<prefix_value>)
all items with prefix.
- Secondary key
tables.secondary_get(&txn,<key_def>,<value>)
get an item.tables.secondary_iter(&txn,<key_def>,<key_def>)
iterate all items.tables.secondary_iter_range(&txn,<key_def>,<start_value>..<end_value>)
all items in range.tables.secondary_iter_start_with(&txn,<key_def>,<prefix_value>)
all items with prefix.
- Global
- Primary key
- Watch use
std::sync::mpsc::Receiver
to receivewatch::Event
.- Primary key
db.primary_watch(Option<<value>>)
watch all or a specific item.db.primary_watch_start_with(<prefix_value>)
watch all items with prefix.
- Secondary key
db.secondary_watch(<key_def>,Option<value>)
watch all or a specific item.db.secondary_watch_start_with(<key_def>,<prefix_value>)
watch all items with prefix.
- Global
db.unwatch(<watcher_id>)
stop watching a specific watcher.
- Primary key
Example
use serde::{Deserialize, Serialize};
use struct_db::*;
#[derive(Serialize, Deserialize, PartialEq, Debug)]
#[struct_db(
fn_primary_key(p_key),
fn_secondary_key(s_key),
)]
struct Data(u32, String);
impl Data {
// `p_key` returns the primary key of the `Data` struct as a vector of bytes.
// In this case, it is the big-endian byte representation of the `i32` value.
// Using big-endian representation for the primary key maintains a consistent
// lexicographical ordering of the keys, which is useful for ordered key-value
// stores and efficient range queries.
pub fn p_key(&self) -> Vec<u8> {
self.0.to_be_bytes().to_vec()
}
// `s_key` generates a secondary key for the `Data` struct as a vector of bytes.
// The secondary key consists of the big-endian byte representation of the `i32` value
// (the primary key) followed by the String field. This combined key allows for more
// versatile querying options.
pub fn s_key(&self) -> Vec<u8> {
let mut p_key = self.p_key();
p_key.extend(self.1.as_bytes());
p_key
}
}
fn main() {
let mut db = Db::init_tmp("my_db_example").unwrap();
// Initialize the schema
db.add_schema(Data::struct_db_schema());
let data = Data(1,"test".to_string());
// Insert data
let txn = db.transaction().unwrap();
{
let mut tables = txn.tables();
tables.insert(&txn, data).unwrap();
}
txn.commit().unwrap();
// Get data
let txn_read = db.read_transaction().unwrap();
let retrieve_data: Data = txn_read.tables().primary_get(&txn_read, &1_u32.to_be_bytes()).unwrap().unwrap();
assert_eq!(&retrieve_data, &Data(1,"test".to_string()));
// Remove data
let txn = db.transaction().unwrap();
{
let mut tables = txn.tables();
tables.remove(&txn, retrieve_data).unwrap();
}
txn.commit().unwrap();
}
Modules
Structs
- The
Db
struct represents a database instance. It allows add schema, create transactions and watcher. - Provides a way to iterate over the values stored in a database and automatically deserialize them into items of type
T
. - Same as
Iterator
but only returns values that match the given secondary key. - Same as
Iterator
but only returns values which primary key starts with the given prefix. - Same as
Iterator
but only returns values with secondary keys that start with the given prefix. - A collection of read-only tables. Only read operations available through the
ReadableTable
trait are allowed. - Can open only
ReadOnlyTables
. - Schema of the Item. Returned by the
<your_item>::struct_db_schema()
method. - A collection of read-write tables. Read operation from
ReadableTable
and write operationsinsert
,update
,remove
andmigrate
are available. - Can open only
Tables
.