diff --git a/backend/src/models/batch.rs b/backend/src/models/batch.rs index 46915a4..305acc9 100644 --- a/backend/src/models/batch.rs +++ b/backend/src/models/batch.rs @@ -4,7 +4,7 @@ use super::{ApplyOption, CrudBackend, Update}; use anyhow::Result; use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; -use sqlx::prelude::FromRow; +use sqlx::{PgConnection, prelude::FromRow}; use uuid::Uuid; #[derive(Debug, Deserialize, Serialize, Clone, FromRow)] @@ -57,10 +57,7 @@ impl CrudBackend for Batch { self.id } - async fn create_inner<'a>( - conn: impl sqlx::prelude::Executor<'a, Database = sqlx::Postgres>, - create: Self::Create, - ) -> Result { + async fn create_inner(conn: &mut PgConnection, create: Self::Create) -> Result { todo!() } @@ -71,33 +68,27 @@ impl CrudBackend for Batch { todo!() } - async fn update_inner<'a>( - &mut self, - conn: impl sqlx::prelude::Executor<'a, Database = sqlx::Postgres>, - ) -> Result<()> { + async fn update_inner(&mut self, conn: &mut PgConnection) -> Result<()> { todo!() } - async fn delete_inner<'a>( - &self, - conn: impl sqlx::prelude::Executor<'a, Database = sqlx::Postgres>, - ) -> Result<()> { + async fn delete_inner(&self, conn: &mut PgConnection) -> Result<()> { todo!() } } impl Batch { - pub async fn remove_ingredient<'a>( + pub async fn remove_ingredient( &mut self, - conn: impl sqlx::prelude::Executor<'a, Database = sqlx::Postgres>, + conn: &mut PgConnection, ingredient_id: Uuid, ) -> Result<()> { todo!() } - pub async fn add_ingredient<'a>( + pub async fn add_ingredient( &mut self, - conn: impl sqlx::prelude::Executor<'a, Database = sqlx::Postgres>, + conn: &mut PgConnection, ingredient_id: Uuid, ) -> Result<()> { todo!() diff --git a/backend/src/models/customer.rs b/backend/src/models/customer.rs index f89e6c9..cf9a648 100644 --- a/backend/src/models/customer.rs +++ b/backend/src/models/customer.rs @@ -2,7 +2,7 @@ use super::{ApplyOption, CrudBackend, Update}; use crate::models::user::Permissions; use anyhow::Result; use serde::{Deserialize, Serialize}; -use sqlx::prelude::FromRow; +use sqlx::{PgConnection, prelude::FromRow}; use uuid::Uuid; #[derive(Debug, Deserialize, Serialize, Clone, FromRow)] @@ -47,10 +47,7 @@ impl CrudBackend for Customer { self.id } - async fn create_inner<'a>( - conn: impl sqlx::prelude::Executor<'a, Database = sqlx::Postgres>, - create: Self::Create, - ) -> Result { + async fn create_inner(conn: &mut PgConnection, create: Self::Create) -> Result { todo!() } @@ -61,17 +58,11 @@ impl CrudBackend for Customer { todo!() } - async fn update_inner<'a>( - &mut self, - conn: impl sqlx::prelude::Executor<'a, Database = sqlx::Postgres>, - ) -> Result<()> { + async fn update_inner(&mut self, conn: &mut PgConnection) -> Result<()> { todo!() } - async fn delete_inner<'a>( - &self, - conn: impl sqlx::prelude::Executor<'a, Database = sqlx::Postgres>, - ) -> Result<()> { + async fn delete_inner(&self, conn: &mut PgConnection) -> Result<()> { todo!() } } diff --git a/backend/src/models/flavor.rs b/backend/src/models/flavor.rs index 7d6590c..3b2ced2 100644 --- a/backend/src/models/flavor.rs +++ b/backend/src/models/flavor.rs @@ -2,7 +2,7 @@ use super::{ApplyOption, CrudBackend, Update}; use crate::models::{ingredient::Ingredient, user::Permissions}; use anyhow::Result; use serde::{Deserialize, Serialize}; -use sqlx::prelude::FromRow; +use sqlx::{PgConnection, prelude::FromRow}; use uuid::Uuid; #[derive(Debug, Deserialize, Serialize, Clone, FromRow)] @@ -47,10 +47,7 @@ impl CrudBackend for Flavor { self.id } - async fn create_inner<'a>( - conn: impl sqlx::prelude::Executor<'a, Database = sqlx::Postgres>, - create: Self::Create, - ) -> Result { + async fn create_inner(conn: &mut PgConnection, create: Self::Create) -> Result { todo!() } @@ -61,17 +58,11 @@ impl CrudBackend for Flavor { todo!() } - async fn update_inner<'a>( - &mut self, - conn: impl sqlx::prelude::Executor<'a, Database = sqlx::Postgres>, - ) -> Result<()> { + async fn update_inner(&mut self, conn: &mut PgConnection) -> Result<()> { todo!() } - async fn delete_inner<'a>( - &self, - conn: impl sqlx::prelude::Executor<'a, Database = sqlx::Postgres>, - ) -> Result<()> { + async fn delete_inner(&self, conn: &mut PgConnection) -> Result<()> { todo!() } } @@ -79,14 +70,14 @@ impl CrudBackend for Flavor { impl Flavor { pub async fn add_ingredient( &mut self, - conn: impl sqlx::prelude::Executor<'_, Database = sqlx::Postgres>, + conn: &mut PgConnection, ingredient_id: Uuid, ) -> Result<()> { todo!() } pub async fn remove_ingredient<'a>( &mut self, - conn: impl sqlx::prelude::Executor<'_, Database = sqlx::Postgres>, + conn: &mut PgConnection, ingredient_id: Uuid, ) -> Result<()> { todo!() diff --git a/backend/src/models/ingredient.rs b/backend/src/models/ingredient.rs index 575c7c6..c84f00d 100644 --- a/backend/src/models/ingredient.rs +++ b/backend/src/models/ingredient.rs @@ -3,7 +3,7 @@ use crate::models::user::Permissions; use anyhow::Result; use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; -use sqlx::prelude::FromRow; +use sqlx::{PgConnection, prelude::FromRow}; use uuid::Uuid; // MARK - Ingredient Type @@ -47,10 +47,7 @@ impl CrudBackend for IngredientType { self.id } - async fn create_inner<'a>( - conn: impl sqlx::prelude::Executor<'a, Database = sqlx::Postgres>, - create: Self::Create, - ) -> Result { + async fn create_inner(conn: &mut PgConnection, create: Self::Create) -> Result { todo!() } @@ -61,17 +58,11 @@ impl CrudBackend for IngredientType { todo!() } - async fn update_inner<'a>( - &mut self, - conn: impl sqlx::prelude::Executor<'a, Database = sqlx::Postgres>, - ) -> Result<()> { + async fn update_inner(&mut self, conn: &mut PgConnection) -> Result<()> { todo!() } - async fn delete_inner<'a>( - &self, - conn: impl sqlx::prelude::Executor<'a, Database = sqlx::Postgres>, - ) -> Result<()> { + async fn delete_inner(&self, conn: &mut PgConnection) -> Result<()> { todo!() } } @@ -128,10 +119,7 @@ impl CrudBackend for Ingredient { self.id } - async fn create_inner<'a>( - conn: impl sqlx::prelude::Executor<'a, Database = sqlx::Postgres>, - create: Self::Create, - ) -> Result { + async fn create_inner(conn: &mut PgConnection, create: Self::Create) -> Result { todo!() } @@ -142,17 +130,11 @@ impl CrudBackend for Ingredient { todo!() } - async fn update_inner<'a>( - &mut self, - conn: impl sqlx::prelude::Executor<'a, Database = sqlx::Postgres>, - ) -> Result<()> { + async fn update_inner(&mut self, conn: &mut PgConnection) -> Result<()> { todo!() } - async fn delete_inner<'a>( - &self, - conn: impl sqlx::prelude::Executor<'a, Database = sqlx::Postgres>, - ) -> Result<()> { + async fn delete_inner(&self, conn: &mut PgConnection) -> Result<()> { todo!() } } diff --git a/backend/src/models/mod.rs b/backend/src/models/mod.rs index 4265f08..c4072c6 100644 --- a/backend/src/models/mod.rs +++ b/backend/src/models/mod.rs @@ -1,5 +1,5 @@ use anyhow::Result; -use sqlx::{Executor, Postgres}; +use sqlx::{Acquire, Executor, PgConnection, PgPool, Postgres}; use std::fmt::Display; use tracing::Instrument; use uuid::Uuid; @@ -45,75 +45,61 @@ pub trait CrudBackend: Sized { fn id(&self) -> Self::Identifier; - async fn create_inner<'a>( - conn: impl Executor<'a, Database = Postgres>, - create: Self::Create, - ) -> Result; + async fn create_inner(conn: &mut PgConnection, create: Self::Create) -> Result; async fn read_inner<'a>( conn: impl Executor<'a, Database = Postgres>, id: Self::Identifier, ) -> Result; - async fn update_inner<'a>( - &mut self, - conn: impl Executor<'a, Database = Postgres>, - ) -> Result<()>; + async fn update_inner(&mut self, conn: &mut PgConnection) -> Result<()>; - async fn delete_inner<'a>(&self, conn: impl Executor<'a, Database = Postgres>) -> Result<()>; + async fn delete_inner(&self, conn: &mut PgConnection) -> Result<()>; } pub trait Crud: CrudBackend { - async fn create<'a>( - conn: impl Executor<'a, Database = Postgres>, - create: Self::Create, - ) -> Result; + async fn create(conn: &PgPool, create: Self::Create) -> Result; - async fn read<'a>( - conn: impl Executor<'a, Database = Postgres>, - id: Self::Identifier, - ) -> Result; + async fn read(conn: &PgPool, id: Self::Identifier) -> Result; - async fn update<'a>( - &mut self, - conn: impl Executor<'a, Database = Postgres>, - updates: Self::Update, - ) -> Result<()>; + async fn update(&mut self, conn: &PgPool, updates: Self::Update) -> Result<()>; - async fn delete<'a>(&self, conn: impl Executor<'a, Database = Postgres>) -> Result<()>; + async fn delete(&self, conn: &PgPool) -> Result<()>; } impl Crud for T { - async fn create<'a>( - conn: impl Executor<'a, Database = Postgres>, - create: Self::Create, - ) -> Result { + async fn create(conn: &PgPool, create: Self::Create) -> Result { let span = tracing::info_span!("create", model = std::any::type_name::()); - T::create_inner(conn, create).instrument(span).await + let mut tx = conn.begin().await?; + let item = T::create_inner(&mut *tx, create).instrument(span).await?; + tx.commit().await?; + Ok(item) } - async fn read<'a>( - conn: impl Executor<'a, Database = Postgres>, - id: T::Identifier, - ) -> Result { + async fn read(conn: &PgPool, id: T::Identifier) -> Result { let span = tracing::info_span!("read", id = %id, model = std::any::type_name::()); - T::read_inner(conn, id).instrument(span).await + let mut tx = conn.begin().await?; + let item = T::read_inner(&mut *tx, id).instrument(span).await?; + tx.commit().await?; + Ok(item) } - async fn update<'a>( - &mut self, - conn: impl Executor<'a, Database = Postgres>, - updates: Self::Update, - ) -> Result<()> { + async fn update(&mut self, conn: &PgPool, updates: Self::Update) -> Result<()> { let id = self.id(); let span = tracing::info_span!("update", id = %id, model = std::any::type_name::()); + let mut tx = conn.begin().await?; updates.apply(self); - self.update_inner(conn).instrument(span).await + self.update_inner(&mut *tx).instrument(span).await?; + tx.commit().await?; + Ok(()) } - async fn delete<'a>(&self, conn: impl Executor<'a, Database = Postgres>) -> Result<()> { + async fn delete(&self, conn: &PgPool) -> Result<()> { let id = self.id(); let span = tracing::info_span!("update", id = %id, model = std::any::type_name::()); - self.delete_inner(conn).instrument(span).await + let mut tx = conn.begin().await?; + self.delete_inner(&mut *tx).instrument(span).await?; + tx.commit().await?; + Ok(()) } } diff --git a/backend/src/models/order.rs b/backend/src/models/order.rs index 1d57859..0928325 100644 --- a/backend/src/models/order.rs +++ b/backend/src/models/order.rs @@ -2,7 +2,7 @@ use super::{ApplyOption, CrudBackend, Update}; use crate::models::{batch::Batch, user::Permissions}; use anyhow::Result; use serde::{Deserialize, Serialize}; -use sqlx::prelude::FromRow; +use sqlx::{PgConnection, prelude::FromRow}; use uuid::Uuid; #[derive(Debug, Deserialize, Serialize, Clone, FromRow)] @@ -51,10 +51,7 @@ impl CrudBackend for Order { self.id } - async fn create_inner<'a>( - conn: impl sqlx::prelude::Executor<'a, Database = sqlx::Postgres>, - create: Self::Create, - ) -> Result { + async fn create_inner(conn: &mut PgConnection, create: Self::Create) -> Result { todo!() } @@ -65,35 +62,21 @@ impl CrudBackend for Order { todo!() } - async fn update_inner<'a>( - &mut self, - conn: impl sqlx::prelude::Executor<'a, Database = sqlx::Postgres>, - ) -> Result<()> { + async fn update_inner(&mut self, conn: &mut PgConnection) -> Result<()> { todo!() } - async fn delete_inner<'a>( - &self, - conn: impl sqlx::prelude::Executor<'a, Database = sqlx::Postgres>, - ) -> Result<()> { + async fn delete_inner(&self, conn: &mut PgConnection) -> Result<()> { todo!() } } impl Order { - pub async fn add_batch<'a>( - &mut self, - conn: impl sqlx::prelude::Executor<'a, Database = sqlx::Postgres>, - batch_id: Uuid, - ) -> Result<()> { + pub async fn add_batch(&mut self, conn: &mut PgConnection, batch_id: Uuid) -> Result<()> { todo!() } - pub async fn remove_batch<'a>( - &mut self, - conn: impl sqlx::prelude::Executor<'a, Database = sqlx::Postgres>, - batch_id: Uuid, - ) -> Result<()> { + pub async fn remove_batch(&mut self, conn: &mut PgConnection, batch_id: Uuid) -> Result<()> { todo!() } diff --git a/backend/src/models/supplier.rs b/backend/src/models/supplier.rs index a889e03..d13fd81 100644 --- a/backend/src/models/supplier.rs +++ b/backend/src/models/supplier.rs @@ -2,7 +2,7 @@ use super::{ApplyOption, CrudBackend, Update}; use crate::models::user::Permissions; use anyhow::Result; use serde::{Deserialize, Serialize}; -use sqlx::prelude::FromRow; +use sqlx::{PgConnection, prelude::FromRow}; use uuid::Uuid; #[derive(Debug, Deserialize, Serialize, Clone, FromRow)] @@ -56,10 +56,7 @@ impl CrudBackend for Supplier { self.id } - async fn create_inner<'a>( - conn: impl sqlx::prelude::Executor<'a, Database = sqlx::Postgres>, - create: Self::Create, - ) -> Result { + async fn create_inner(conn: &mut PgConnection, create: Self::Create) -> Result { todo!() } @@ -70,17 +67,11 @@ impl CrudBackend for Supplier { todo!() } - async fn update_inner<'a>( - &mut self, - conn: impl sqlx::prelude::Executor<'a, Database = sqlx::Postgres>, - ) -> Result<()> { + async fn update_inner(&mut self, conn: &mut PgConnection) -> Result<()> { todo!() } - async fn delete_inner<'a>( - &self, - conn: impl sqlx::prelude::Executor<'a, Database = sqlx::Postgres>, - ) -> Result<()> { + async fn delete_inner(&self, conn: &mut PgConnection) -> Result<()> { todo!() } } diff --git a/backend/src/models/user.rs b/backend/src/models/user.rs index e682702..5e445ec 100644 --- a/backend/src/models/user.rs +++ b/backend/src/models/user.rs @@ -5,6 +5,7 @@ use argon2::{ password_hash::{SaltString, rand_core::OsRng}, }; use serde::{Deserialize, Serialize}; +use sqlx::PgConnection; use uuid::Uuid; #[derive(Debug, Deserialize, Serialize, Clone)] @@ -82,10 +83,7 @@ impl CrudBackend for User { UserIdentifier::UserId(self.id) } - async fn create_inner<'a>( - pool: impl sqlx::Executor<'a, Database = sqlx::Postgres>, - create: UserCreate, - ) -> Result { + async fn create_inner(pool: &mut PgConnection, create: UserCreate) -> Result { let hashed_password = Self::hash_password(&create.password)?; let user = sqlx::query_as!( User, @@ -124,10 +122,7 @@ impl CrudBackend for User { .map_err(Into::into) } - async fn update_inner<'a>( - &mut self, - pool: impl sqlx::Executor<'a, Database = sqlx::Postgres>, - ) -> Result<()> { + async fn update_inner(&mut self, pool: &mut PgConnection) -> Result<()> { sqlx::query_as!( User, r#"UPDATE users SET full_name = $1, username = $2, password = $3, permissions = $4 WHERE id = $5 RETURNING *"#, @@ -143,10 +138,7 @@ impl CrudBackend for User { .map(|_| ()) } - async fn delete_inner<'a>( - &self, - pool: impl sqlx::Executor<'a, Database = sqlx::Postgres>, - ) -> Result<()> { + async fn delete_inner(&self, pool: &mut PgConnection) -> Result<()> { sqlx::query!(r#"DELETE FROM users WHERE id = $1"#, self.id) .execute(pool) .await diff --git a/backend/src/routes/batch.rs b/backend/src/routes/batch.rs index 8cb4275..e093e40 100644 --- a/backend/src/routes/batch.rs +++ b/backend/src/routes/batch.rs @@ -219,10 +219,15 @@ async fn add_ingredient( } }; - match batch - .add_ingredient(pool.get_ref(), body.ingredient_id) - .await - { + let mut pg = match pool.get_ref().acquire().await { + Ok(pg) => pg, + Err(err) => { + tracing::error!("{err:?}"); + return HttpResponse::InternalServerError().finish(); + } + }; + + match batch.add_ingredient(&mut pg, body.ingredient_id).await { Ok(batch) => HttpResponse::Created().json(batch), Err(err) => { if let Some(sqlx_err) = err.downcast_ref::() { @@ -308,8 +313,16 @@ async fn remove_ingredient( } }; + let mut pg = match pool.get_ref().acquire().await { + Ok(pg) => pg, + Err(err) => { + tracing::error!("{err:?}"); + return HttpResponse::InternalServerError().finish(); + } + }; + match resource - .remove_ingredient(pool.get_ref(), ingredient_id.into_inner()) + .remove_ingredient(&mut pg, ingredient_id.into_inner()) .await { Ok(()) => HttpResponse::NoContent().finish(), diff --git a/backend/src/routes/flavor.rs b/backend/src/routes/flavor.rs index 9513817..7a5a489 100644 --- a/backend/src/routes/flavor.rs +++ b/backend/src/routes/flavor.rs @@ -229,7 +229,15 @@ async fn add_ingredient( } }; - match flavor.add_ingredient(pool.get_ref(), ingredient.id).await { + let mut pg = match pool.get_ref().acquire().await { + Ok(pg) => pg, + Err(err) => { + tracing::error!("{err:?}"); + return HttpResponse::InternalServerError().finish(); + } + }; + + match flavor.add_ingredient(&mut pg, ingredient.id).await { Ok(()) => HttpResponse::Created().finish(), Err(err) => { if let Some(sqlx_err) = err.downcast_ref::() { @@ -315,8 +323,16 @@ async fn remove_ingredient( } }; + let mut pg = match pool.get_ref().acquire().await { + Ok(pg) => pg, + Err(err) => { + tracing::error!("{err:?}"); + return HttpResponse::InternalServerError().finish(); + } + }; + match flavor - .remove_ingredient(pool.get_ref(), ingredient_id.into_inner()) + .remove_ingredient(&mut pg, ingredient_id.into_inner()) .await { Ok(_) => HttpResponse::NoContent().finish(), diff --git a/backend/src/routes/order.rs b/backend/src/routes/order.rs index b797856..2d6d634 100644 --- a/backend/src/routes/order.rs +++ b/backend/src/routes/order.rs @@ -209,7 +209,15 @@ async fn add_item( } }; - match order.add_batch(pool.get_ref(), body.batch_id).await { + let mut pg = match pool.get_ref().acquire().await { + Ok(pg) => pg, + Err(err) => { + tracing::error!("{err:?}"); + return HttpResponse::InternalServerError().finish(); + } + }; + + match order.add_batch(&mut pg, body.batch_id).await { Ok(order) => HttpResponse::Created().json(order), Err(err) => { if let Some(sqlx_err) = err.downcast_ref::() { @@ -295,10 +303,15 @@ async fn remove_item( } }; - match resource - .remove_batch(pool.get_ref(), batch_id.into_inner()) - .await - { + let mut pg = match pool.get_ref().acquire().await { + Ok(pg) => pg, + Err(err) => { + tracing::error!("{err:?}"); + return HttpResponse::InternalServerError().finish(); + } + }; + + match resource.remove_batch(&mut pg, batch_id.into_inner()).await { Ok(()) => HttpResponse::NoContent().finish(), Err(err) => { tracing::error!("{err:?}");