4.1 KiB
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();