| Crates.io | saberdb |
| lib.rs | saberdb |
| version | 1.1.0 |
| created_at | 2025-12-30 05:37:08.814506+00 |
| updated_at | 2025-12-30 06:00:41.490974+00 |
| description | A blazingly fast, simple JSON database for Rust |
| homepage | |
| repository | https://github.com/simplysabir/saberdb |
| max_upload_size | |
| id | 2012137 |
| size | 41,394 |
A blazingly fast, simple JSON database for Rust.
Add to your Cargo.toml:
[dependencies]
saberdb = "1.1"
use saberdb::{JsonFileSync, SaberDBSync};
use serde::{Deserialize, Serialize};
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
struct Database {
posts: Vec<Post>,
users: Vec<User>,
}
#[derive(Debug, Serialize, Deserialize, Clone)]
struct Post {
id: u32,
title: String,
views: u32,
}
fn main() -> saberdb::Result<()> {
// Create database
let adapter = JsonFileSync::new("db.json");
let mut db = SaberDBSync::new(adapter, Database::default())?;
// Create
db.data_mut().posts.push(Post {
id: 1,
title: "Hello SaberDB!".to_string(),
views: 0,
});
db.write()?;
// Read
let post = db.data().posts.first().unwrap();
println!("Post: {}", post.title);
// Update
db.update(|data| {
if let Some(post) = data.posts.iter_mut().find(|p| p.id == 1) {
post.views += 1;
}
})?;
// Delete
db.update(|data| {
data.posts.retain(|p| p.id != 1);
})?;
Ok(())
}
use saberdb::{JsonFile, SaberDB};
use serde::{Deserialize, Serialize};
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
struct Database {
posts: Vec<Post>,
}
#[tokio::main]
async fn main() -> saberdb::Result<()> {
// Create async database
let adapter = JsonFile::new("db.json");
let db = SaberDB::new(adapter, Database::default()).await?;
// Create
{
let mut data = db.data_mut().await;
data.posts.push(Post {
id: 1,
title: "Hello Async!".to_string(),
views: 0,
});
}
db.write().await?;
// Read with concurrent access
let data = db.data().await;
println!("Posts: {}", data.posts.len());
// Update atomically
db.update(|data| {
data.posts[0].views += 1;
}).await?;
Ok(())
}
Use native Rust iterators - no special query language needed:
// Filter
let popular: Vec<_> = db.data()
.posts
.iter()
.filter(|p| p.views > 100)
.collect();
// Find
let post = db.data()
.posts
.iter()
.find(|p| p.id == 1);
// Sort
let mut sorted = db.data().posts.clone();
sorted.sort_by_key(|p| p.views);
// Map
let titles: Vec<_> = db.data()
.posts
.iter()
.map(|p| &p.title)
.collect();
Two ways to update:
1. Manual update + write:
// Sync
db.data_mut().posts.push(new_post);
db.write()?;
// Async
{
let mut data = db.data_mut().await;
data.posts.push(new_post);
}
db.write().await?;
2. Atomic update (recommended):
// Sync
db.update(|data| {
data.posts.push(new_post);
})?;
// Async
db.update(|data| {
data.posts.push(new_post);
}).await?;
Implement your own storage backend:
use saberdb::{AdapterSync, Result};
use serde::{Serialize, de::DeserializeOwned};
struct CustomAdapter;
impl<T> AdapterSync<T> for CustomAdapter
where
T: Serialize + DeserializeOwned,
{
fn read(&self) -> Result<Option<T>> {
// Your read logic
todo!()
}
fn write(&self, data: &T) -> Result<()> {
// Your write logic
todo!()
}
}
SaberDBSync<T, A> - Synchronous database
new(adapter, default) -> Result<Self> - Create new databasedata(&self) -> &T - Get immutable referencedata_mut(&mut self) -> &mut T - Get mutable referencewrite(&self) -> Result<()> - Write to storageupdate<F>(&mut self, f: F) -> Result<()> - Update and write atomicallySaberDB<T, A> - Asynchronous database
new(adapter, default) -> Result<Self> - Create new databasedata(&self) -> RwLockReadGuard<T> - Get immutable referencedata_mut(&self) -> RwLockWriteGuard<T> - Get mutable referencewrite(&self) -> Result<()> - Write to storageupdate<F>(&self, f: F) -> Result<()> - Update and write atomicallyJsonFileSync - Sync JSON file adapterJsonFile - Async JSON file adapterMemorySync - Sync in-memory adapter (perfect for testing)Memory - Async in-memory adapter (perfect for testing)AdapterSync<T> - Trait for sync storage backendsAdapter<T> - Trait for async storage backendsCheck out the examples/ directory:
basic.rs - Synchronous CRUD operationsasync_basic.rs - Asynchronous CRUD operationsmemory.rs - Using in-memory adapters for testingRun examples:
cargo run --example basic
cargo run --example async_basic
cargo run --example memory
cargo test
MIT
Contributions welcome! Please feel free to submit issues and pull requests.