From b2969b988d15240ea10aacc2c5dd78de3bfcf7b1 Mon Sep 17 00:00:00 2001 From: Max Hohlfeld Date: Sun, 22 Jun 2025 21:33:01 +0200 Subject: [PATCH] refactor: custom context for validation --- web/src/endpoints/user/post_edit.rs | 5 +++-- web/src/endpoints/user/post_new.rs | 5 +++-- web/src/models/user_changeset.rs | 10 ++++++---- web/src/utils/validation/mod.rs | 11 +++++++++++ web/src/utils/validation/trait.rs | 9 +++++---- 5 files changed, 28 insertions(+), 12 deletions(-) diff --git a/web/src/endpoints/user/post_edit.rs b/web/src/endpoints/user/post_edit.rs index 1c786cd2..bef44e77 100644 --- a/web/src/endpoints/user/post_edit.rs +++ b/web/src/endpoints/user/post_edit.rs @@ -4,7 +4,7 @@ use sqlx::PgPool; use crate::{ endpoints::{user::NewOrEditUserForm, IdPath}, models::{Function, Role, User, UserChangeset}, - utils::{validation::AsyncValidate, ApplicationError}, + utils::{validation::{AsyncValidate, DbContext}, ApplicationError}, }; #[actix_web::post("/users/edit/{id}")] @@ -63,7 +63,8 @@ pub async fn post_edit( } } - if let Err(e) = changeset.validate_with_pool(pool.get_ref()).await { + let context = DbContext::new(pool.get_ref()); + if let Err(e) = changeset.validate_with_context(&context).await { return Ok(HttpResponse::UnprocessableEntity().body(e.to_string())); }; diff --git a/web/src/endpoints/user/post_new.rs b/web/src/endpoints/user/post_new.rs index 726f50d8..f111681a 100644 --- a/web/src/endpoints/user/post_new.rs +++ b/web/src/endpoints/user/post_new.rs @@ -5,7 +5,7 @@ use crate::{ endpoints::user::NewOrEditUserForm, mail::Mailer, models::{Function, Registration, Role, User, UserChangeset}, - utils::{validation::AsyncValidate, ApplicationError}, + utils::{validation::{AsyncValidate, DbContext}, ApplicationError}, }; #[actix_web::post("/users/new")] @@ -57,7 +57,8 @@ pub async fn post_new( .body("email: an user already exists with the same email")); } - if let Err(e) = changeset.validate_with_pool(pool.get_ref()).await { + let context = DbContext::new(pool.get_ref()); + if let Err(e) = changeset.validate_with_context(&context).await { return Ok(HttpResponse::UnprocessableEntity().body(e.to_string())); }; diff --git a/web/src/models/user_changeset.rs b/web/src/models/user_changeset.rs index fdcf3731..5ca14d3e 100644 --- a/web/src/models/user_changeset.rs +++ b/web/src/models/user_changeset.rs @@ -3,7 +3,7 @@ use fake::{faker::internet::en::SafeEmail, faker::name::en::Name, Dummy}; use sqlx::PgPool; -use crate::utils::validation::{email_is_valid, AsyncValidate, AsyncValidateError}; +use crate::utils::validation::{email_is_valid, AsyncValidate, AsyncValidateError, DbContext}; use super::{Area, Function, Role}; @@ -22,13 +22,15 @@ pub struct UserChangeset { pub area_id: i32, } -impl AsyncValidate for UserChangeset { - async fn validate_with_pool(&self, pool: &sqlx::PgPool) -> Result<(), AsyncValidateError> { +impl <'a>AsyncValidate<'a> for UserChangeset { + async fn validate_with_context(&self, context: &'a Self::Context) -> Result<(), AsyncValidateError> { email_is_valid(&self.email)?; - area_exists(pool, self.area_id).await?; + area_exists(context.pool, self.area_id).await?; Ok(()) } + + type Context = DbContext<'a>; } async fn area_exists(pool: &PgPool, id: i32) -> Result<(), AsyncValidateError> { diff --git a/web/src/utils/validation/mod.rs b/web/src/utils/validation/mod.rs index a688580e..f659f62a 100644 --- a/web/src/utils/validation/mod.rs +++ b/web/src/utils/validation/mod.rs @@ -5,3 +5,14 @@ mod r#trait; pub use email::email_is_valid; pub use error::AsyncValidateError; pub use r#trait::AsyncValidate; +use sqlx::PgPool; + +pub struct DbContext<'a> { + pub pool: &'a PgPool, +} + +impl<'a> DbContext<'a> { + pub fn new(pool: &'a PgPool) -> Self { + Self { pool } + } +} diff --git a/web/src/utils/validation/trait.rs b/web/src/utils/validation/trait.rs index f7bc555b..85c92b0a 100644 --- a/web/src/utils/validation/trait.rs +++ b/web/src/utils/validation/trait.rs @@ -1,7 +1,8 @@ -use sqlx::PgPool; - use super::AsyncValidateError; -pub trait AsyncValidate { - async fn validate_with_pool(&self, pool: &PgPool) -> Result<(), AsyncValidateError>; +pub trait AsyncValidate<'a> { + type Context: 'a; + + async fn validate_with_context(&self, context: &'a Self::Context) -> Result<(), AsyncValidateError>; } +