Here's a drop-in, fast, embedded database for multi-platform apps (server, desktop, mobile). Sync Rust types effortlessly. Enjoy! ππ.
- Simple API π¦.
- Support for multiple indexes (primary, secondary, unique, non-unique, optional).
- Note: Optional secondary keys with
Nonevalues cannot be queried using range syntax. See documentation for details.
- Note: Optional secondary keys with
- Fast, see
sqlitevsredbvsnative_dbbenchmarks. - Transparent serialization/deserialization using native_model. You can use any serialization library you want (
bincode,postcard, your own etc.). - Ensure query type safety to prevent unexpected results caused by selecting with an incorrect type.
- Automatic model migration π.
- Thread-safe and fully ACID-compliant transactions provided by redb.
- Real-time subscription with filters for
insert,updateanddeleteoperations. - Compatible with all Rust types (
enum,struct,tupleetc.). - Hot snapshots.
Add this to your Cargo.toml:
[dependencies] native_db = "0.8.1" native_model = "0.4.20"Active development. The API is not stable yet and may change in the future.
- Documentation API
- Quick Start
- Major Version Upgrade Guide
- Full example with Tauri: native_db_tauri_vanilla
If you want to propose your project or company that uses Native DB, please open a PR.
use serde::{Deserialize, Serialize}; use native_db::*; use native_db::native_model::{native_model, Model}; use once_cell::sync::Lazy; #[derive(Serialize, Deserialize, PartialEq, Debug)] #[native_model(id = 1, version = 1)] #[native_db] struct Item { #[primary_key] id: u32, #[secondary_key] name: String, } // Define the models // The lifetime of the models needs to be longer or equal to the lifetime of the database. // In many cases, it is simpler to use a static variable but it is not mandatory. static MODELS: Lazy<Models> = Lazy::new(|| { let mut models = Models::new(); models.define::<Item>().unwrap(); models }); fn main() -> Result<(), db_type::Error> { // Create a database in memory let mut db = Builder::new().create_in_memory(&MODELS)?; // Insert data (open a read-write transaction) let rw = db.rw_transaction()?; rw.insert(Item { id: 1, name: "red".to_string() })?; rw.insert(Item { id: 2, name: "green".to_string() })?; rw.insert(Item { id: 3, name: "blue".to_string() })?; rw.commit()?; // Open a read-only transaction let r = db.r_transaction()?; // Retrieve data with id=3 let retrieve_data: Item = r.get().primary(3_u32)?.unwrap(); println!("data id='3': {:?}", retrieve_data); // Iterate items with name starting with "red" for item in r.scan().secondary::<Item>(ItemKey::name)?.start_with("red")? { println!("data name=\"red\": {:?}", item); } // Remove data (open a read-write transaction) let rw = db.rw_transaction()?; rw.remove(retrieve_data)?; rw.commit()?; Ok(()) }