From 3f251a224fe3fbcd798d9fdf66cf007978b3520d Mon Sep 17 00:00:00 2001 From: JMARyA Date: Fri, 19 Jul 2024 10:38:39 +0200 Subject: [PATCH] better validation --- src/model/mod.rs | 24 ++++++++++++------------ src/model/reference.rs | 14 +++++++++++--- src/model/valid.rs | 23 ++++++++++++++++++----- 3 files changed, 41 insertions(+), 20 deletions(-) diff --git a/src/model/mod.rs b/src/model/mod.rs index 7c826f8..f0b22c7 100644 --- a/src/model/mod.rs +++ b/src/model/mod.rs @@ -24,7 +24,7 @@ pub enum UpdateError { /// Database related error Database(mongodb::error::Error), /// Validation failed - Validation, + Validation(String), } pub trait Model: @@ -203,18 +203,18 @@ pub trait Model: 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(()); + if let Err(msg) = self.validate().await { + return Err(UpdateError::Validation(msg)); } - return Err(UpdateError::Validation); + collection + .update_one( + id_of!(self.id()), + mongodb::bson::doc! {"$set": update }, + None, + ) + .await + .map_err(UpdateError::Database)?; + return Ok(()); } Err(UpdateError::NoObject) diff --git a/src/model/reference.rs b/src/model/reference.rs index 04bdd1a..263af54 100644 --- a/src/model/reference.rs +++ b/src/model/reference.rs @@ -13,7 +13,7 @@ impl Reference { /// Create a new reference from String pub async fn new_raw(reference: &str) -> Option { let r = Self(reference.to_string()); - if r.validate().await { + if r.validate().await.is_ok() { Some(r) } else { None @@ -63,12 +63,20 @@ impl Reference { } impl Validate for Reference { - async fn validate(&self) -> bool { + async fn validate(&self) -> Result<(), String> { // cheap //self.0.split_once("::").is_some() // right - self.exists().await.unwrap_or(false) + if let Some(res) = self.exists().await { + if res { + Ok(()) + } else { + Err(format!("Reference '{}' does not exist", self.0)) + } + } else { + Err("Database error".to_string()) + } } } diff --git a/src/model/valid.rs b/src/model/valid.rs index 82f1fc4..5d3e6b8 100644 --- a/src/model/valid.rs +++ b/src/model/valid.rs @@ -1,19 +1,29 @@ /// This trait allows a `Model` to be validated. pub trait Validate { /// Validate the `Model` - fn validate(&self) -> impl std::future::Future + Send; + fn validate(&self) -> impl std::future::Future> + Send; } -/// Validate a value and return `false` if validation fails. +/// Validate a value and return an Error if validation fails. #[macro_export] macro_rules! validate { ($val:expr) => { - if !$val.validate().await { - return false; + if let Err(err) = $val.validate().await { + return Err(format!("{}: {}", stringify!($val), err)); } }; } +#[macro_export] +macro_rules! count_items { + // Base case: single item + ($single:ident) => { 1 }; + // Recursive case: count each item + ($head:ident, $($tail:ident),*) => { + 1 + mongod::count_items!($($tail),*) + }; +} + /// This macro checks for the type of a reference and is useful for validation. /// It will check all supplied types and return `false` if none are matching. /// @@ -34,7 +44,10 @@ macro_rules! assert_reference_of { } )* if !match_found { - return false; + let possible_types: [&str; mongod::count_items!($($struct_name),*)] = [ + $(stringify!($struct_name)),* + ]; + return Err(format!("{} is not of any type: {:?}", stringify!($var), possible_types)); } }; }