add derive + docs

This commit is contained in:
JMARyA 2024-07-17 16:49:35 +02:00
parent 5da65fb603
commit ca2b0036f0
Signed by: jmarya
GPG key ID: 901B2ADDF27C2263
11 changed files with 400 additions and 43 deletions

View file

@ -1,4 +1,9 @@
pub mod model;
pub use model::historic::Historic;
pub use model::reference::*;
pub use model::valid::Validate;
pub use model::Model;
pub use mongod_derive as derive;
/// Get a `MongoDB` Client from the environment
#[macro_export]

View file

@ -23,52 +23,83 @@ pub enum UpdateError {
pub trait Model:
Sized + Referencable + Validate + serde::Serialize + for<'a> serde::Deserialize<'a>
{
/// Insert the model into the database
async fn insert(&self) {
let db = get_mongo!();
let collection = col!(db, Self::collection_name());
collection
.insert_one(mongodb::bson::to_document(self).unwrap(), None)
.await
.unwrap();
/// Insert the `Model` into the database
fn insert(&self) -> impl std::future::Future<Output = ()> + Send
where
Self: Sync,
{
async {
let db = get_mongo!();
let collection = col!(db, Self::collection_name());
collection
.insert_one(mongodb::bson::to_document(self).unwrap(), None)
.await
.unwrap();
}
}
/// Get a model by id from the database
async fn get(id: &str) -> Option<Self> {
let db = get_mongo!();
let collection = col!(db, Self::collection_name());
let doc = collection.find_one(id_of!(id), None).await.ok()??;
mongodb::bson::from_document(doc).ok()
/// Remove a `Model` from the database.
fn remove(id: &str) -> impl std::future::Future<Output = ()> + Send {
async move {
let db = get_mongo!();
let collection = col!(db, Self::collection_name());
collection.delete_one(id_of!(id), None).await.unwrap();
}
}
/// Update values of model into database
async fn update(&mut self, data: &serde_json::Value) -> Result<(), UpdateError> {
// get db collection
let db = get_mongo!();
let collection = col!(db, Self::collection_name());
let mut update = mongodb::bson::Document::new();
/// Remove a `Model` from the database.
///
/// This is a convenience function to let you call `remove()` on a `Model` you have at hand.
fn delete(&self) -> impl std::future::Future<Output = ()> + Send
where
Self: Sync,
{
async { Self::remove(self.id()).await }
}
if let Some(obj) = data.as_object() {
// run model specific update
self.update_values(obj, &mut update).await;
/// Get a `Model` by id from the database
#[must_use]
fn get(id: &str) -> impl std::future::Future<Output = Option<Self>> {
async move {
let db = get_mongo!();
let collection = col!(db, Self::collection_name());
let doc = collection.find_one(id_of!(id), None).await.ok()??;
mongodb::bson::from_document(doc).ok()
}
}
// validate and update
if self.validate().await {
collection
.update_one(
id_of!(self.id()),
mongodb::bson::doc! {"$set": update },
None,
)
.await
.map_err(|_| UpdateError::Database)?;
return Ok(());
} else {
/// Update values of `Model` into database
fn update(
&mut self,
data: &serde_json::Value,
) -> impl std::future::Future<Output = Result<(), UpdateError>> {
async {
// get db collection
let db = get_mongo!();
let collection = col!(db, Self::collection_name());
let mut update = mongodb::bson::Document::new();
if let Some(obj) = data.as_object() {
// run model specific update
self.update_values(obj, &mut update).await;
// validate and update
if self.validate().await {
collection
.update_one(
id_of!(self.id()),
mongodb::bson::doc! {"$set": update },
None,
)
.await
.map_err(|_| UpdateError::Database)?;
return Ok(());
}
return Err(UpdateError::Validation);
}
}
Err(UpdateError::NoObject)
Err(UpdateError::NoObject)
}
}
/// Update the `Model` based on the provided JSON Object.
@ -77,9 +108,9 @@ pub trait Model:
/// For every updated value in the JSON Object the `Model`s fields should be updated and the value should be put in the `update` `Document`
///
/// To avoid making mistakes in the Update logic use the macros from `update.rs`
async fn update_values(
fn update_values(
&mut self,
obj: &Map<String, Value>,
update: &mut mongodb::bson::Document,
);
) -> impl std::future::Future<Output = ()> + Send;
}

View file

@ -9,8 +9,8 @@ use super::valid::Validate;
pub struct Reference(String);
impl Reference {
/// Create a new reference
pub async fn new(reference: &str) -> Option<Self> {
/// Create a new reference from String
pub async fn new_raw(reference: &str) -> Option<Self> {
let r = Self(reference.to_string());
if r.validate().await {
Some(r)
@ -19,7 +19,13 @@ impl Reference {
}
}
/// Create a new reference
pub async fn new(model: &str, id: &str) -> Option<Self> {
Self::new_raw(&format!("{model}::{id}")).await
}
/// Checks if a reference is part of a model collection.
#[must_use]
pub fn is_of_collection(&self, col: &str) -> bool {
self.0.starts_with(col)
}

View file

@ -43,7 +43,7 @@ macro_rules! update_historic_ref_option {
($entity:ident, $json:ident, $key:literal, $field:ident, $update:ident) => {
if let Some(val) = $json.get($key) {
if let Some(val_str) = val.as_str() {
let value = Historic::new(Reference::new(val_str).await.unwrap());
let value = Historic::new(Reference::new_raw(val_str).await.unwrap());
let field = $entity.$field.clone().unwrap_or_else(|| value);
$entity.$field = Some(field);
$update.insert($key, mongodb::bson::to_bson(&$entity.$field).unwrap());

View file

@ -1,7 +1,7 @@
/// This trait allows a `Model` to be validated.
pub trait Validate {
/// Validate the `Model`
async fn validate(&self) -> bool;
fn validate(&self) -> impl std::future::Future<Output = bool> + Send;
}
/// Validate a value and return `false` if validation fails.