4 releases
new 0.1.5 | May 3, 2025 |
---|---|
0.1.4 | Apr 21, 2025 |
#583 in Database interfaces
602 downloads per month
47KB
189 lines
OxiMod
A MongoDB ODM for Rust
Overview
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
.
Features
-
Schema Modeling with Macros
Define your collections using idiomatic Rust structs and a simple derive macro. -
Async-Friendly
Built for asynchronous Rust. Integrates seamlessly with themongodb
driver. -
Built-in CRUD Operations
Usesave()
,find()
,update()
,delete()
, and more directly on your types. -
Minimal Boilerplate
Declare a model in seconds with#[derive(Model)]
,#[db]
, and#[collection]
attributes. -
Indexing Support
Add indexes declaratively via field-level#[index(...)]
attributes. -
Clear Error Handling
Strongly typed, developer-friendly errors based onthiserror
.
Model Attributes
OxiMod supports attributes at both the struct level and field level.
Struct-Level Attributes
#[db("name")]
: Specifies the MongoDB database the model belongs to.#[collection("name")]
: Specifies the collection name within the database.
Field-Level Index Attributes
You can add indexes to fields using the #[index(...)]
attribute.
Supported Options:
unique
: Ensures values in this field are unique.sparse
: Indexes only documents that contain the field.name = "...""
: Custom name for the index.background
: Builds index in the background without locking the database.order = 1 | -1
: Index sort order (1 = ascending, -1 = descending).
Example
This example demonstrates how to define a model with schema-level and field-level metadata.
use oximod::{set_global_client, Model};
use serde::{Serialize, Deserialize};
use mongodb::bson::{doc, oid::ObjectId};
#[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, name = "email_idx", order = -1)]
email: String,
#[index(sparse)]
phone: Option<String>,
name: String,
age: i32,
active: bool,
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
dotenv::dotenv().ok();
let mongodb_uri = std::env::var("MONGODB_URI")?;
set_global_client(mongodb_uri).await?;
let user = User {
_id: None,
email: "example@example.com".into(),
phone: Some("123-456-7890".into()),
name: "User1".into(),
age: 29,
active: true,
};
let id = user.save().await?;
println!("Inserted user with _id: {}", id);
Ok(())
}
In this example:
#[db("my_app_db")]
and#[collection("users")]
configure the database and collection.- The
email
field has a descending, unique index with a custom name. - The
phone
field is indexed only when it exists in the document (sparse).
Running Examples
OxiMod includes a growing set of usage examples:
cargo run --example basic_usage
cargo run --example aggregate_usage
cargo run --example query
cargo run --example update
cargo run --example delete
cargo run --example by_id
Each file clears previous data on run and demonstrates isolated functionality.
Don't forget to create a
.env
file:MONGODB_URI=mongodb://localhost:27017
License
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!
Dependencies
~18–27MB
~430K SLoC