Expand description
–> /!\ Important Update: This crate struct_db
has been renamed to native_db
to better reflect its functionality and purpose. Please update your dependencies to use native_db
for the latest features and updates. <–
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.
- Define schema
db.define::<your_type>()
initializes a schema.
- Transactions
db.transaction()
starts aread-write transaction
.db.read_transaction()
starts aread-only transaction
.
- Tables (
txn
is aTransaction
andread_only_txn
aReadOnlyTransaction
)txn.tables()
returns aTables
read_only_txn.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
- Primary key
tables.primary_get(&txn,<key>)
get an item.tables.primary_iter(&txn)
iterate all items.tables.primary_iter_range(&txn,<start_key>..<end_key>)
all items in range.tables.primary_iter_start_with(&txn,<key_prefix>)
all items with prefix.
- Secondary key
tables.secondary_get(&txn,<key_def>,<key>)
get an item.tables.secondary_iter(&txn,<key_def>,<key_def>)
iterate all items.tables.secondary_iter_range(&txn,<key_def>,<start_key>..<end_key>)
all items in range.tables.secondary_iter_start_with(&txn,<key_def>,<key_prefix>)
all items with prefix.
- Global
- Primary key
- Watch (details
here
)- Primary key
db.primary_watch(Option<key>)
watch all or a specific item.db.primary_watch_start_with(<key_prefix>)
watch all items with prefix.
- Secondary key
db.secondary_watch(<key_def>,Option<key>)
watch all or a specific item.db.secondary_watch_start_with(<key_def>,<key_prefix>)
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), // required
fn_secondary_key(s_key), // optional
// ... other fn_secondary_key ...
)]
struct Data(u32, String);
impl Data {
// Returns primary key as big-endian bytes for consistent lexicographical ordering.
pub fn p_key(&self) -> Vec<u8> {
self.0.to_be_bytes().to_vec()
}
// Generates a secondary key combining the String field and the big-endian bytes of
// the primary key for versatile queries.
pub fn s_key(&self) -> Vec<u8> {
let mut s_key = self.1.as_bytes().to_vec();
s_key.extend_from_slice(&self.p_key().as_slice());
s_key
}
}
fn main() {
let mut db = Db::create_tmp("my_db_example").unwrap();
// Initialize the schema
db.define::<Data>();
// Insert data
let txn = db.transaction().unwrap();
{
let mut tables = txn.tables();
tables.insert(&txn, Data(1,"red".to_string())).unwrap();
tables.insert(&txn, Data(2,"red".to_string())).unwrap();
tables.insert(&txn, Data(3,"blue".to_string())).unwrap();
}
txn.commit().unwrap();
let txn_read = db.read_transaction().unwrap();
let mut tables = txn_read.tables();
// Retrieve data with p_key=3
let retrieve_data: Data = tables.primary_get(&txn_read, &3_u32.to_be_bytes()).unwrap().unwrap();
println!("data p_key='3' : {:?}", retrieve_data);
// Iterate data with s_key="red" String
for item in tables.secondary_iter_start_with::<Data>(&txn_read, DataKey::s_key, "red".as_bytes()).unwrap() {
println!("data s_key='1': {:?}", item);
}
// Remove data
let txn = db.transaction().unwrap();
{
let mut tables = txn.tables();
tables.remove(&txn, retrieve_data).unwrap();
}
txn.commit().unwrap();
}
Modules
Structs
- Builder for the
Db
instance. - 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
PrimaryIterator
but only returns values which primary key starts 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. - Same as
PrimaryIterator
but only returns values that match the given secondary key. - Same as
PrimaryIterator
but only returns values with secondary keys that start with the given prefix. - A collection of read-write tables. Read operation from
ReadableTable
and write operationsinsert
,update
,remove
andmigrate
are available. - Can open only
Tables
.