mongod/README.md

139 lines
4.1 KiB
Markdown
Raw Normal View History

2024-07-17 07:40:59 +00:00
# mongod
mongod is a rust crate for a model based database on top of MongoDB.
2024-07-17 14:49:35 +00:00
## Usage
2024-07-21 20:01:17 +00:00
`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.
2024-07-17 14:49:35 +00:00
### 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;
2024-09-11 09:29:20 +00:00
use mongod::derive::{Model, Referencable};
2024-07-17 14:49:35 +00:00
2024-09-11 09:29:20 +00:00
#[derive(Debug, Clone, Serialize, Deserialize, Model, Referencable)]
2024-07-17 14:49:35 +00:00
struct MyStruct {
_id: String,
name: String,
other: Option<Reference>,
}
impl Validate for MyStruct {
2024-07-19 09:35:24 +00:00
async fn validate(&self) -> Result<(), String> {
Ok(())
2024-07-17 14:49:35 +00:00
}
}
```
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 {
2024-07-19 09:35:24 +00:00
async fn validate(&self) -> Result<(), String> {
2024-07-17 14:49:35 +00:00
if let Some(other) = self.other {
assert_reference_of!(other, OtherStruct, YetAnotherStruct);
}
2024-07-19 09:35:24 +00:00
Ok(())
2024-07-17 14:49:35 +00:00
}
}
2024-07-18 14:48:21 +00:00
```
### 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!
```
2024-09-11 09:09:38 +00:00
### 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();
```