A MongoDB ODM for Rust
OxiMod is a schema-based Object-Document Mapper (ODM) for MongoDB, designed for Rust developers who want a familiar and expressive way to model and interact with their data.
Inspired by Mongoose, OxiMod brings a structured modeling experience while embracing Rust's type safety and performance. It works with any async runtime and is currently tested using tokio.
OxiMod supports new() and fluent builder-style setters:
let user = User::new()
.name("Alice".to_string())
.age(30)
.active(true);- Works with
Option<T>and non-option field - Uses
#[default("...")]when defined - Supports renaming the
_idsetter via#[document_id_setter_ident("...")]
Use:
user.save().await?;#[index_max_retries(N)]#[index_max_init_seconds(N)]
These provide robust, retry-aware index creation using OxiMod’s internal OnceAsync.
alphanumericnow checks ASCII-only- Prevents contradictory validators (e.g., min > max)
- Flamegraph analysis
- Fewer allocations
- Optimized execution paths
OxiMod now ships with a MongoDB client wrapper: OxiClient.
This enables:
use oximod::OxiClient;
dotenv::dotenv().ok();
let mongodb_uri = std::env::var("MONGODB_URI").expect("Missing MONGODB_URI");
OxiClient::init_global(mongodb_uri).await?;Once set, any Model::save(), Model::find(), etc. will automatically use the global client.
Every CRUD operation now has a client-aware variant:
| Purpose | Auto Client | Manual Client |
|---|---|---|
| Insert | save() |
save_with_client(&Client) |
| Update | update() |
update_with_client(_, _, &Client) |
| Query | find() |
find_with_client(_, &Client) |
| Find One | find_one() |
find_one_with_client(_, &Client) |
| Delete | delete() |
delete_with_client(_, &Client) |
| By ID | find_by_id() |
find_by_id_with_client(_, &Client) |
| Clear | clear() |
clear_with_client(&Client) |
Useful for:
- Multi-tenant systems
- Test isolation
- Cluster routing
- Advanced architectures
Located in:
examples/update_with_client.rs
Demonstrates:
- Using
OxiClient::new() - Using
*_with_clientCRUD variants - Updating documents with explicit clients
- Schema Modeling with Macros
- Async-friendly (Tokio tested)
- Built‑in CRUD operations
- Direct
get_collection()access - Indexing support (
#[index(...)]) - Validation support (
#[validate(...)]) - Default values (
#[default(...)]) - Fluent builder API
- Clear and typed error handling
#[db("name")]#[collection("name")]#[document_id_setter_ident("name")]#[index_max_retries(N)]#[index_max_init_seconds(N)]
#[index(unique, sparse, name = "...", order = 1 | -1, hidden, expire_after_secs = N, ...)]
min_length,max_lengthrequiredemailpattern = "regex"positive,negative,non_negativemin = N,max = Nstarts_with,ends_with,includesalphanumericmultiple_of
#[default("string")], #[default(42)], #[default(Enum::Variant)]
use oximod::{Model, OxiClient};
use serde::{Serialize, Deserialize};
use mongodb::bson::{doc, oid::ObjectId};
use anyhow::Result;
#[derive(Debug, Serialize, Deserialize, Model)]
#[db("my_app_db")]
#[collection("users")]
struct User {
#[serde(skip_serializing_if = "Option::is_none")]
_id: Option<ObjectId>,
#[index(unique)]
#[validate(email)]
email: String,
#[validate(min_length = 3)]
name: String,
#[validate(non_negative)]
age: i32,
#[default(false)]
active: bool,
}
#[tokio::main]
async fn main() -> Result<()> {
dotenv::dotenv().ok();
let mongodb_uri =
std::env::var("MONGODB_URI").expect("Missing MONGODB_URI");
OxiClient::init_global(mongodb_uri).await?;
let user = User::new()
.email("alice@example.com".to_string())
.name("Alice".to_string())
.age(30)
.active(true);
let id = user.save().await?;
println!("Inserted user: {:?}", id);
let found = User::find_by_id(id).await?;
println!("Found: {:?}", found);
Ok(())
}cargo run --example basic_usage
cargo run --example validate_usage
cargo run --example query
cargo run --example update
cargo run --example update_with_client
cargo run --example delete
cargo run --example hook_usage
cargo run --example by_id
cargo run --example default_usageEnsure:
MONGODB_URI=mongodb://localhost:27017We welcome all contributions, suggestions, and feedback!
If you discover a bug or want to request a feature, please open an issue on GitHub.
Your input helps improve OxiMod for everyone — thank you for your support.
MIT © 2025 OxiMod Contributors
⚠️ The name OxiMod and this repository represent the official version of the project.
Forks are welcome, but please do not use the name or create similarly named organizations to avoid confusion with the original.
We hope OxiMod helps bring joy and structure to your MongoDB experience in Rust.
Contributions welcome!