Tiny ergonomic rust database
Find a file
2025-09-15 16:15:50 +02:00
src Add u64 key 2025-09-15 16:15:50 +02:00
.gitignore Initial version 2025-09-12 14:20:16 +02:00
Cargo.lock Add serde option 2025-09-15 11:04:13 +02:00
Cargo.toml fix ulid 2025-09-15 11:08:41 +02:00
README.md Initial version 2025-09-12 14:20:16 +02:00

FeoxDB

A tiny rust-native kv oriented database, with columnar indexes.

Under the hood it uses:

Like fjall it's thread-safe, but not multi-process safe.

Status

The database is still very experimental. Things that are needed for production workloads:

  • Expose the transactional api.
  • Use facet to handle auto-migrations (and/or prevent usage without migration)
  • Add hooks for indexes (maybe combine with transactional api?)
  • Add shared indexes (queued writes, instant read across threads)
  • Improve key ergonomics (discourage incompatible key types)

Usage

  1. Define a model:
use rkyv::{Archive, Serialize, Deserialize}
use facet::Facet;

#[derive(PartialEq, Debug, Archive, Serialize, Deserialize, Facet)]
pub struct User {
    pub email: String,
    pub password_hash: u128,
    pub role: ulid::Ulid,
}

// TODO: This should either be part of `Table::new()` (multi-tables) or derived (singletons)
impl DatabaseModel for User {
    fn partition() -> &'static str {
        "user"
    }
}
  1. Use the database:
let table = Table::<User>::new();

let user_id = Ulid::new();
let user = User { email: "example@example.com".to_string(), password_hash: 0u128, role: Ulid::new() };
table.set_one(user_id, &user).unwrap();

// Note entry values are by default `rkyv::Archived`
let user_entry = table.get_one(user_id).unwrap();
let user_retrieved = user_entry.unarchived();

assert_eq!(Ulid::try_from(user_id.key).unwrap(), user_id);
assert_eq!(user_retrieved, user);

  1. Scale with indexes:
// TODO: add index update strategy (hooks w/ deferred option)

let index = CuckooUniqueIndex::<User, String>::new_empty("email").rebuild();
let user_id = index.get("example@example.com");
assert_eq!(Ulid::try_from(user_id.key).unwrap(), user_id);