Netabase Store
A type-safe, multi-backend key-value storage library for Rust with support for native (Sled, Redb) and WASM (IndexedDB) environments.
⚠️ Early Development: This crate is still in early development and will change frequently as it stabilizes. It is not advised to use this in a production environment until it stabilizes.
Installation
Add to your Cargo.toml:
[]
= "0.0.3"
# Required dependencies for macros to work
= { = "2.0", = ["serde"] }
= { = "1.0", = ["derive"] }
= { = "0.27.2", = ["derive"] }
= { = "2.0.1", = ["from", "try_into", "into"] }
= "1.0" # Optional, for error handling
# For WASM support
[]
= { = "0.0.2", = false, = ["wasm"] }
Feature Flags
native(default): Enable Sled and Redb backendssled: Enable Sled backend onlyredb: Enable Redb backend onlyredb-zerocopy: Enable zero-copy Redb backend (high-performance variant)wasm: Enable IndexedDB backend for WASMlibp2p: Enable libp2p integrationrecord-store: Enable RecordStore trait (requireslibp2p)
Quick Start
1. Define Your Schema
use netabase_definition_module;
use NetabaseModelTrait;
use *;
2. Create a Store with Unified Configuration API (Recommended)
The unified configuration system provides consistent backend initialization:
use FileConfig;
use BackendStore;
use SledStore;
3. Alternative: Simple Configuration for Quick Setup
For simple use cases, use the convenience constructors:
use FileConfig;
use BackendStore;
use SledStore;
// Simple constructor with defaults
let config = new;
let store = open?;
// Or create a temporary database for testing
let store = temp?;
4. Use with IndexedDB (WASM)
use IndexedDBConfig;
use BackendStore;
use IndexedDBStore;
use NetabaseTreeAsync;
async
Advanced Usage
Configuration API
The new unified configuration system provides consistent backend initialization across all database types:
FileConfig - For File-Based Backends
use FileConfig;
use BackendStore;
use SledStore;
// Method 1: Builder pattern (recommended)
let config = builder
.path
.cache_size_mb
.truncate
.build;
let store = new?;
// Method 2: Simple constructor
let config = new;
let store = open?;
// Method 3: Temporary database
let store = temp?;
Switching Backends with Same Config
The power of the configuration API is that you can switch backends without changing your code:
use FileConfig;
use BackendStore;
let config = builder
.path
.cache_size_mb
.build;
// Try different backends - same config!
let store = new?;
let store = new?;
let store = new?;
// All have the same API from this point on!
let user_tree = store.;
Configuration Options Reference
FileConfig (for Sled, Redb, RedbZeroCopy):
path: PathBuf- Database file/directory pathcache_size_mb: usize- Cache size in megabytes (default: 256)create_if_missing: bool- Create if doesn't exist (default: true)truncate: bool- Delete existing data (default: false)read_only: bool- Open read-only (default: false)use_fsync: bool- Fsync for durability (default: true)
MemoryConfig (for in-memory backend):
capacity: Option<usize>- Optional capacity hint
IndexedDBConfig (for WASM):
database_name: String- IndexedDB database nameversion: u32- Schema version (default: 1)
Batch Operations & Bulk Methods
For high-performance bulk operations, use the convenient bulk methods:
use FileConfig;
use BackendStore;
use SledStore;
// Create store with temporary database
let store = temp?;
let user_tree = store.;
// Bulk insert - 8-9x faster than loop!
let users: =
.map
.collect;
user_tree.put_many?; // Single transaction
// Bulk read
let keys: = .map.collect;
let users: = user_tree.get_many?;
// Bulk secondary key queries
let email_keys = vec!;
let results: = user_tree.get_many_by_secondary_keys?;
Bulk Methods:
put_many(Vec<M>)- Insert multiple models in one transactionget_many(Vec<M::Keys>)- Read multiple models in one transactionget_many_by_secondary_keys(Vec<SecondaryKey>)- Query multiple secondary keys in one transaction
Or use the batch API for more control:
use Batchable;
// Create a batch
let mut batch = user_tree.create_batch?;
// Add many operations
for i in 0..1000
// Commit atomically - all or nothing
batch.commit?;
3. Choose the Right API for Your Use Case
| Use Case | Recommended API | Reason |
|---|---|---|
| Simple CRUD, few operations | Standard wrapper | Simplest API, auto-commit |
| Bulk inserts/reads (100+ items) | Bulk methods | 8-9x faster than loops |
| Complex transactions | Explicit transactions | Full control, atomic commits |
| Read-heavy queries | ZeroCopy API | Up to 54x faster for secondary queries |
Serialization Overhead
The read-path overhead in Redb comes from type system limitations with Generic Associated Types (GATs). We prioritize safety over unsafe transmutes. For applications where this matters:
- Use bulk methods to amortize overhead
- Use explicit transactions for better performance
- Consider Sled backend for read-heavy workloads
See benchmark results and visualizations in docs/benchmarks/ for detailed performance analysis.
For 1.0.0
- Transaction support across multiple operations (COMPLETED)
- Zero-copy reads for redb backend (via
redb-zerocopyfeature) - Phase 1 Complete - Allow modules to define more than one definition for flexible organization
- Migration utilities for schema changes
- Query builder for complex queries
- Range queries on ordered keys
- Compression support
- Encryption at rest
- Improved documentation and examples
Future Plans
- Distributed systems support with automatic sync
- CRDT-based conflict resolution
- WebRTC backend for peer-to-peer storage
- SQL-like query language
- GraphQL integration
Acknowledgments
Built with: