oximod 0.1.5

MongoDB ODM for Rust inspired by Mongoose
Documentation
# 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 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.

- **Clear Error Handling**  
  Strongly typed, developer-friendly errors based on `thiserror`.

---

## 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.

```rust
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:

```bash
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:
>
> ```env
> MONGODB_URI=mongodb://localhost:27017
> ```

---

## License


[MIT](./LICENSE) © 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!