8 releases

0.3.1 Jul 23, 2024
0.3.0 Jul 5, 2024
0.2.5 Jun 17, 2024
0.2.3 May 22, 2024
0.1.0 May 1, 2024

#956 in Database interfaces

Download history 11/week @ 2024-09-12 2/week @ 2024-09-19 62/week @ 2024-09-26 38/week @ 2024-10-03 1/week @ 2024-10-10

793 downloads per month

MIT/Apache

28KB
495 lines

Spark-ORM: MongoDB ORM for Rust

Spark-ORM is a high-performance, open-source Object-Relational Mapping (ORM) library designed specifically for MongoDB in Rust. It seamlessly bridges Rust structs with MongoDB collections, effortlessly converting structs into models.

Features

  • Derive Models: Effortlessly convert Rust structs into MongoDB models using the Model trait derivation.

  • Custom Collection Names: Tailor collection names for your models with the #[coll_name] attribute.

  • Memory Efficiency: Built for speed and memory efficiency, Spark-ORM offers a non-heap copy ORM solution for MongoDB.

Getting Started

  1. Define your model by simply applying the Model attribute and setting the collection name with coll_name:

    #[Model(coll_name = "users")]
    #[derive(Serialize, Deserialize, Default, Debug)]
    struct User {
    age: u32,
    name: String,
    email: String,
    }
    
  2. Connect to the database in one of two ways:

    a. Establish a global connection:

    Spark::global_connect("root", "123", "localhost", "6789", "rm_orm_db").await;
    

    b. Or connect locally:

    Spark::connect("root", "123", "localhost", "6789", "rm_orm_db").await;
    

    For the global connection, Spark retains it throughout the program, accessible via: Spark::get_db();

Usage

Instantiate the model:

    let mut user = User::new_model(Some(&db));

OR you can use the global connection :

 let mut user = User::new_model(None);

if you didn't set global connection , the new_model function will panic


Update attributes:

   user.name = "Hossein".to_string();
   user.age = 22;

Save to the database:

   user.save().await.unwrap();

Find a model:

        let mut user_model = User::new_model(Some(&db)); 
        let mut sample = User::default ();
        sample.name = "Hossein".to_string();
        let founded = user_model.find_one(
            sample,
            None,
            ).await.unwrap();
        println!("The founded object {:?} ", founded);

Update and save:

    let mut user = User::new_model(Some(&db));
    user.name = "Hossein".to_string();
    user.email = "spark_orm_test".to_string();

    user.save().await;

    user.name = "Nothing".to_string();

    user.save().await;

or

      let db = get_db().await;
      let user_model = User::new_model(Some(&db));
      let updated = user_model.update(
      doc! {
                  "name": "Hossein",
              },
      doc! {
                  "$set": {
                      "name": "Hossein 33"
                  }
              },
      None,
      ).await.unwrap();
       println!("The Updated info {:?}", updated);

Delete a record:

        let mut user = User::new_model(Some(&db));
        user.delete().await;

Note: you can use the ? instead of unwrap

Model

The model trait adds _id , timestamps (created_at , updated_at , deleted_at) to your struct and fill automatically

Attributes

Define index or unique attributes for struct fields:

   #[Model(coll_name = "products")]
   #[derive(Serialize, Deserialize, Default, Debug)]
   struct Product {
       #[index]
       age: u32,
       #[index]
       name: String,
       #[unique]
       email: String,
   }

These indexes are registered during the first initiation of Product.

The Model Observer

you call set observer for some operations in model

to use the observer you just need to put observer in Model macro ex : #[Model(coll_name='users' , observer)]

and implement the Observer<T> for your model , supported method are created , updated , deleted

    
#[Model(coll_name = "users", observer)]
#[derive(Serialize, Deserialize, Debug, Default)]
struct User {
    name: String,
}

#[Model(coll_name = "persons", observer)]
#[derive(Serialize, Deserialize, Debug, Default)]
struct Person {
    name: String,
}


impl Observer<User> for User {
    async fn created(model: &mut Model<'_, User>) -> MongodbResult<()> {
        let mut person_model = Person::new_model(None);
        if model.name == "Hello".to_string() {
            model.name = "Something".to_string();
            model.save(None).await?;
        }
        person_model.name = "Naruto".to_string();
        person_model.save(None).await?;
        Ok(())
    }
}

#[allow(clippy::assigning_clones)]
impl Observer<Person> for Person {
    async fn created(model: &mut Model<'_, Person>) -> MongodbResult<()> {
        let mut jobs = Jobs::new_model(None);
        jobs.person.name = model.name.clone();
        jobs.save(None).await?;
        Ok(())
    }

    async fn updated(model: &mut Model<'_, Person>) -> MongodbResult<()> {
        Ok(())
    }

    async fn deleted(model: &mut Model<'_, Person>) -> MongodbResult<()> {
        Ok(())
    }
}

I would greatly appreciate your support on GitHub. Please consider giving me a star to show your support. Thank you!

Note the library is under development and may have lots of changes in the future, even in its basics

Dependencies

~27–38MB
~704K SLoC