FeatherDB
The embedded SQL database for AI agents — MVCC, encryption, sessions.
Overview
This crate provides the primary user-facing API through Database and Transaction. It re-exports types from all subsystem crates so you only need one dependency.
Key Features
- Full SQL: JOINs, subqueries, CTEs, window functions, 30+ built-in functions — passes all 22 TPC-H queries
- MVCC: Snapshot isolation — readers never block writers
- Durability: Write-ahead logging with crash recovery
- Encryption: AES-256-GCM at rest with hardware acceleration
- Embedded: Single-file database, zero C dependencies
- Prepared Statements: Plan caching for 5–10x speedup on repeated queries
Quick Start
use ;
Public API Overview
Database
The main entry point for all operations.
Transaction
Explicit transaction control with ACID guarantees.
Prepared Statements
Prepared statements parse and plan SQL once, then execute multiple times with different parameters. This provides 5-10x speedup for repeated queries.
use ;
let db = open?;
db.execute?;
// Prepare once - plan is cached
let stmt = db.prepare?;
// Execute many times with different parameters
let rows1 = db.query_prepared?;
let rows2 = db.query_prepared?;
// For INSERT/UPDATE/DELETE, use execute_prepared_mut
let insert_stmt = db.prepare?;
let affected = db.execute_prepared_mut?;
// Check cache statistics
let stats = db.plan_cache.stats;
println!;
Parameter Placeholders
Use PostgreSQL-style $1, $2, etc. or SQLite-style ?1, ?2, etc.:
// PostgreSQL style
let stmt = db.prepare?;
// Query with two parameters
let rows = db.query_prepared?;
Plan Cache Management
The plan cache is automatically invalidated when schema changes occur (CREATE, DROP, ALTER). You can also manually manage it:
// Invalidate all cached plans
db.invalidate_plan_cache;
// Invalidate plans for a specific table
db.invalidate_plans_for_table;
// Get cache statistics
let cache = db.plan_cache;
println!;
Query Builder
Type-safe query construction without writing raw SQL strings.
use ;
// SELECT with conditions
let rows = select
.from
.where_eq
.where_gt
.order_by
.limit
.execute?;
// SELECT all columns
let rows = select_all
.from
.build;
// SELECT DISTINCT
let statuses = select
.distinct
.from
.execute?;
// INSERT
insert_into
.columns
.values
.execute?;
// UPDATE
update
.set
.set
.where_eq
.execute?;
// DELETE
delete_from
.where_eq
.execute?;
Available WHERE Conditions
.where_eq // column = value
.where_ne // column != value
.where_gt // column > value
.where_gte // column >= value
.where_lt // column < value
.where_lte // column <= value
.where_null // column IS NULL
.where_not_null // column IS NOT NULL
.where_like // column LIKE '%pat%'
.where_clause // arbitrary WHERE clause
Derive Macros
Type-safe table definitions.
use Table;
// Automatic schema information
println!;
println!;
println!;
// Convert to/from database rows
let user = User ;
let values = user.to_values;
let restored = from_values?;
Configuration
use ;
let config = new
.create_if_missing // Create if doesn't exist
.buffer_pool_size_mb; // Buffer pool size in MB
let db = open_with_config?;
Eviction Policies
Configure the buffer pool eviction policy:
use ;
// Clock algorithm (default) - good general-purpose performance
let config = new;
// LRU-2 - better for scan-heavy workloads
let config = new.with_lru2_eviction;
// LIRS - better for workloads with recency and frequency patterns
let config = new.with_lirs_eviction;
Transactions
Auto-commit
Single statements are auto-committed:
db.execute?;
// Automatically committed
Explicit Transactions
Multiple statements in one transaction:
let mut txn = db.begin?;
txn.execute?;
txn.execute?;
txn.commit?; // Both inserts committed atomically
Savepoints
Partial rollback within transaction:
let mut txn = db.begin?;
txn.execute?;
txn.savepoint?;
txn.execute?;
// Oops, rollback just the items
txn.rollback_to_savepoint?;
// Order is still there, items are gone
// Savepoint is still valid - can be used again
txn.execute?; // Try again
txn.commit?;
You can also release savepoints to remove them:
txn.savepoint?;
txn.savepoint?;
// Release sp1 (also releases sp2 since it was created after)
txn.release_savepoint?;
// List active savepoints
let names = txn.savepoint_names;
Read-Only Transactions
Consistent snapshot reads:
let txn = db.begin_read_only?;
let count1 = txn.query_one?;
// Other transactions can't affect what we see
let count2 = txn.query_one?;
// count1 and count2 will be equal - snapshot isolation
txn.commit?;
Automatic Rollback
Transactions automatically rollback on drop if not committed:
// The insert is NOT visible
Error Handling
FeatherDB uses a unified Error type with variants for different error conditions:
use ;
match db.execute
Common Error Types
| Error | Description |
|---|---|
InvalidQuery |
SQL syntax error or semantic error |
TableNotFound |
Referenced table does not exist |
ReadOnly |
Write operation in read-only transaction |
TransactionEnded |
Operation on committed/rolled-back transaction |
SavepointNotFound |
Referenced savepoint does not exist |
IoError |
File system or I/O error |
ParseError |
SQL parsing failed |
Database Metrics
Storage Limits
Control database size to prevent runaway disk usage:
use ;
// Set maximum database size
let config = new
.with_max_database_size_mb; // 100MB limit
let db = open_with_config?;
// Monitor storage usage
let quota = db.storage_quota;
println!;
println!;
if let Some = quota.remaining
// Check current size
let size = db.size;
let max = db.max_size; // None if unlimited
// Handle limit errors
match db.execute
Observability
Monitor database health and performance with comprehensive metrics:
let metrics = db.metrics;
// Quick health check
println!;
println!;
println!;
// Storage metrics
println!;
println!;
println!;
println!;
println!;
println!;
// WAL metrics
println!;
println!;
println!;
println!;
// Query metrics
println!;
println!;
println!;
println!;
println!;
println!;
// Plan cache metrics
println!;
println!;
println!;
// Transaction metrics
println!;
println!;
println!;
println!;
println!;
println!;
// GC metrics
println!;
println!;
println!;
println!;
// Pretty-print all metrics
println!;
DatabaseMetrics API
The DatabaseMetrics struct provides:
Storage Subsystem:
buffer_pool: BufferPoolStatsSnapshot- Cache hits, misses, evictionswal: WalStatsSnapshot- WAL records, group commits, fsync countcompression: CompressionStatsSnapshot- Compression ratio, space savings
Query Subsystem:
query: QueryMetricsSnapshot- Parse/plan/exec times, rows scanned/returnedplan_cache: PlanCacheSnapshot- Plan cache hits, misses, size
Transaction Subsystem:
transaction: TransactionMetricsSnapshot- Active count, commits, rollbacksgc: GcMetricsSnapshot- GC runs, versions created/cleaned
Helper Methods:
health_score() -> f64- Overall health (0-1, weighted by buffer hits, plan cache, txn success)storage_efficiency() -> f64- Compression ratio (0-1, lower is better)avg_query_time_us() -> u64- Average total query time in microsecondstotal_transactions() -> u64- Total transactions (commits + rollbacks)gc_efficiency() -> f64- Versions cleaned / versions created
Metric Snapshots
All metrics are snapshots taken at a point in time, so they're consistent:
let metrics = db.metrics;
// These values are from the same snapshot
let health = metrics.health_score;
let efficiency = metrics.storage_efficiency;
// Query metrics have helper methods
let query = metrics.query;
println!;
println!;
println!;
println!;
Display Implementation
The DatabaseMetrics struct implements Display for pretty-printing:
let metrics = db.metrics;
println!;
Output:
=== FeatherDB Metrics ===
Storage:
Buffer Pool Hit Ratio: 90.91%
Cache Hits: 100
Cache Misses: 10
Pages Evicted: 5
Compression Ratio: 0.50x
Space Savings: 50.0%
WAL:
Total Records: 1000
Group Commits: 50
Fsync Count: 50
Avg Batch Size: 10.0
Query:
Queries Executed: 200
Avg Parse Time: 50 us
Avg Plan Time: 100 us
Avg Exec Time: 250 us
Rows Scanned: 5000
Rows Returned: 1000
Plan Cache:
Size: 50/100
Hit Ratio: 90.00%
Hits: 90
Misses: 10
Transaction:
Active: 2
Committed: 450
Rolled Back: 50
Long Running: 1
Avg Duration: 1000 us
Garbage Collection:
GC Runs: 10
Versions Created: 1000
Versions Cleaned: 800
Versions Pending: 200
GC Time: 100000 us
GC Efficiency: 80.00%
Overall Health Score: 90.36%
Re-exports
This crate re-exports types from all subsystem crates:
// Core types
pub use ;
// Catalog types
pub use ;
// Query types
pub use ;
// MVCC types
pub use ;
// Derive macros
pub use Table;
Integration with Other Crates
Using Lower-Level APIs
For advanced use cases, you can access the underlying components:
// Access the catalog directly
let catalog = db.catalog;
let table = catalog.get_table?;
println!;
// Access the optimizer
let optimizer = db.optimizer;
Custom Query Execution
use ;
// Parse SQL
let stmt = parse_one?;
// Plan query
let planner = new;
let plan = planner.plan?;
// Optimize
let optimized = db.optimizer.optimize;
// Execute within a transaction for proper isolation
let txn = db.begin_read_only?;
// ... execution with proper context
Testing
# Run all tests (using Make)
# Or with cargo directly
# Run specific test
# Run with output
# Run coverage (from project root)
Crate Structure
featherdb/
├── src/
│ ├── lib.rs # Re-exports and module declarations
│ ├── database.rs # Database handle and main API
│ ├── transaction.rs # Transaction with savepoint support
│ └── query_builder.rs # Type-safe query construction
└── tests/
├── derive_test.rs # Derive macro integration tests
└── query_builder_test.rs