138 lines
4.1 KiB
Markdown
138 lines
4.1 KiB
Markdown
# 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.
|
|
|
|
```rust
|
|
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:
|
|
|
|
```rust
|
|
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.
|
|
|
|
```rust
|
|
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.
|
|
|
|
```rust
|
|
#[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:
|
|
|
|
```rust
|
|
// 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.
|
|
|
|
```rust
|
|
[...]
|
|
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();
|
|
```
|