#mongo-db #mongoose #odm

bin+lib oximod

MongoDB ODM for Rust inspired by Mongoose

8 releases

new 0.1.9 Jun 5, 2025
0.1.8 May 31, 2025
0.1.4 Apr 21, 2025

#765 in Database interfaces

Download history 412/week @ 2025-04-15 74/week @ 2025-04-22 132/week @ 2025-04-29 18/week @ 2025-05-06 7/week @ 2025-05-13 73/week @ 2025-05-20 287/week @ 2025-05-27 141/week @ 2025-06-03

511 downloads per month

MIT license

55KB
241 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.

🚀 Highlighted Feature (since v0.1.7) – Fluent API Builders

OxiMod now supports fluent API builders and a new() method for ergonomic model creation:

let user = User::new()
    .name("Alice".to_string())
    .age(30)
    .active(true);
  • Supports Option<T> and non-optional fields.
  • Works with #[default("...")] for seamless defaults.
  • Customize _id setter via #[document_id_setter_ident("...")].

Use user.save().await? just like before!


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 the mongodb driver.

  • Built-in CRUD Operations
    Use save(), 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.

  • Validation Support
    Add field-level validation using #[validate(...)]. Supports length, email, pattern, positivity, and more.

  • Default Values
    Use #[default(...)] to specify field defaults for strings, numbers, and enums.

  • Builder API & new() Support
    Use Model::default() or Model::new() to initialize structs and chain fluent setters. Customize _id setter name with #[document_id_setter_ident(...)].

  • Clear Error Handling
    Strongly typed, developer-friendly errors based on thiserror. Includes optional debugging output with backtrace and human-readable suggestions when used with RUST_BACKTRACE=full.


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.
  • #[document_id_setter_ident("name")]: Optional. Renames the _id builder function for fluent .new()/.default() APIs.

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).
  • expire_after_secs = ...: Time-to-live for the index in seconds.

Field-Level Validation Attributes

You can apply validations on fields using the #[validate(...)] attribute.

Supported Validators:

  • min_length = N: Minimum length for String values.
  • max_length = N: Maximum length for String values.
  • required: Ensures the field is not None.
  • email: Validates the format of an email.
  • pattern = "regex": Validates the value against a regex pattern.
  • non_empty: Ensures a String is not empty or whitespace.
  • positive: Ensures numeric value is greater than 0.
  • negative: Ensures numeric value is less than 0.
  • non_negative: Ensures numeric value is 0 or greater.
  • min = N: Ensures numeric value is at least N.
  • max = N: Ensures numeric value is at most N.

💡 Use native Rust enums instead of enum_values.

Field-Level Default Attributes

  • #[default("value")]: Assigns a default value for strings.
  • #[default(42)]: Sets default for numbers.
  • #[default(MyEnum::Variant)]: Sets default for enums.

Accessible via Model::new() or Model::default().


Example

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>,

    #[validate(min_length = 3)]
    name: String,

    #[validate(non_negative)]
    age: i32,

    #[default(false)]
    active: bool,
}

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).
  • The name field must be at least 3 characters long.
  • The age field must be non-negative.
  • The active field defaults to false.

Running Examples

OxiMod includes a growing set of usage examples:

cargo run --example basic_usage
cargo run --example aggregate_usage
cargo run --example validate_usage
cargo run --example query
cargo run --example update
cargo run --example delete
cargo run --example hook_usage
cargo run --example by_id
cargo run --example default_usage

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

~17–29MB
~446K SLoC