No description
Find a file
2024-09-13 22:29:34 +02:00
mongod_derive builder update 2024-09-11 11:09:38 +02:00
src fix 2024-09-13 22:29:34 +02:00
.gitignore update 2024-07-18 14:10:29 +02:00
Cargo.lock update 2024-09-13 14:00:28 +02:00
Cargo.toml update 2024-09-13 14:00:28 +02:00
README.md fix 2024-09-11 11:29:20 +02:00

mongod

mongod is a rust crate for a model based database on top of MongoDB.

Usage

mongod allows you to use structs as models with data. it is build upon a MongoDB database. You need to pass a Connection URI for the database to use via the $DB_URI environment variable. The database to use can be configured via $DB environment variable.

Models

You can derive the Model and Referencable traits for your struct. This will provide you with functions like insert(), delete(), update(), get(), etc for your struct. Additionally you have to manually implement the Validate trait which ensures a consistent valid state of your struct in order to never insert invalid data into the database.

use serde::{Deserialize, Serialize};
use mongod::Validate;
use mongod::Reference;
use mongod::derive::{Model, Referencable};

#[derive(Debug, Clone, Serialize, Deserialize, Model, Referencable)]
struct MyStruct {
    _id: String,
    name: String,
    other: Option<Reference>,
}

impl Validate for MyStruct {
    async fn validate(&self) -> Result<(), String> {
        Ok(())
    }
}

This allows you to use your struct like this:

let a = MyStruct{
    _id: "someid".to_string(),
    name: "hello".to_string(),
    other: None
};

a.insert().await;
a.update(serde_json::json!({"name": "bye"})).await.unwrap();

let new_a = MyStruct::get("someid");

Historic data

If you want certain fields to remember a history of changes you can use the Historic<T> type.
This type will retain previous changes along with a timestamp when updates happen.

References

A Models field can be a reference to another model using the Reference type.

let m = MyStruct::get("someid").await.unwrap();

// get a reference from model
// `reference()` is a convenience function and is exactly the same as the two references below
let myref = m.reference();
let sec_ref = Reference::new(MyStruct::collection_name(), "someid").await.unwrap();
let third_ref = Reference::new("my_struct", "someid").await.unwrap();


struct OtherStruct {
    link: Reference
}

// store a reference
let other = OtherStruct{
    link: myref
}

let m: MyStruct = other.link.get().await; // get back a model from reference

With the assert_reference_of!() macro you can limit the models your reference can represent at validation. You can specify as many models as you want, but the reference must match one of them.

#[derive(Debug, Clone, Serialize, Deserialize, Module, Referencable)]
struct OtherStruct {
    /* *** */
}

#[derive(Debug, Clone, Serialize, Deserialize, Module, Referencable)]
struct YetAnotherStruct {
    /* *** */
}

impl Validate for MyStruct {
    async fn validate(&self) -> Result<(), String> {
        if let Some(other) = self.other {
            assert_reference_of!(other, OtherStruct, YetAnotherStruct);
        }

        Ok(())
    }
}

Partials

Sometimes you need only some fields of your Model. When deriving the Model trait you automatically get a Partial of your model. Partials are only meant for reading values so you cant call functions like update(), but you can still get a Reference to the original Model. This saves bandwidth and memory. You can access it like this:

// say you are only interested in the reference field `other` of `MyStruct`
let ms = MyStruct::get_partial("someid", &serde_json::json!({"other": 1})).await.unwrap();

let myref = ms.other.unwrap(); // will be there
let name = ms.name.unwrap() // will panic!

Updating values

You can either update the values by passing a JSON object overwriting the current values or update the values using a builder pattern.

[...]
struct MyStruct {
    _id: String,
    name: String,
    age: u32,
    other: Option<Reference>,
}

let mut a = MyStruct::get("someid").await.unwrap();

// JSON
a.update(serde_json::json!({"name": "bye"})).await.unwrap();

// Builder
let mut changes = a.change();

// Set fields
changes = changes.name("bye");

// There are type specific functions
// Increment age by 1
changes = changes.age_increment(1);

// Finalize
let changed_model: MyStruct = changes.update().await.unwrap();