diff --git a/backend/migrations/20260623204123_flavors.up.sql b/backend/migrations/20260623204123_flavors.up.sql index 0d38f4b..82ddaaf 100644 --- a/backend/migrations/20260623204123_flavors.up.sql +++ b/backend/migrations/20260623204123_flavors.up.sql @@ -1,6 +1,6 @@ -- Add up migration script here CREATE TABLE flavors ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - name VARCHAR UNIQUE, - short_code VARCHAR UNIQUE + name VARCHAR UNIQUE NOT NULL, + short_code VARCHAR UNIQUE NOT NULL ); diff --git a/backend/migrations/20260623204328_ingredients.up.sql b/backend/migrations/20260623204328_ingredients.up.sql index 5c99381..cb3f6ec 100644 --- a/backend/migrations/20260623204328_ingredients.up.sql +++ b/backend/migrations/20260623204328_ingredients.up.sql @@ -1,13 +1,13 @@ -- Add up migration script here CREATE TABLE ingredients_type ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - name VARCHAR UNIQUE + name VARCHAR UNIQUE NOT NULL ); CREATE TABLE ingredients_required ( - flavor UUID REFERENCES flavors(id) NOT NULL, - ingredient UUID REFERENCES ingredients_type(id) NOT NULL, - PRIMARY KEY (flavor, ingredient) + flavor_id UUID REFERENCES flavors(id) NOT NULL, + ingredient_id UUID REFERENCES ingredients_type(id) NOT NULL, + PRIMARY KEY (flavor_id, ingredient_id) ); CREATE TABLE ingredients ( diff --git a/backend/src/models/flavor.rs b/backend/src/models/flavor.rs index 3b2ced2..943c7ff 100644 --- a/backend/src/models/flavor.rs +++ b/backend/src/models/flavor.rs @@ -1,5 +1,5 @@ use super::{ApplyOption, CrudBackend, Update}; -use crate::models::{ingredient::Ingredient, user::Permissions}; +use crate::models::{ingredient::IngredientType, user::Permissions}; use anyhow::Result; use serde::{Deserialize, Serialize}; use sqlx::{PgConnection, prelude::FromRow}; @@ -22,6 +22,7 @@ pub struct FlavorUpdate { pub struct FlavorCreate { name: String, short_code: String, + ingredient_types: Vec, } impl Update for FlavorUpdate { @@ -48,22 +49,57 @@ impl CrudBackend for Flavor { } async fn create_inner(conn: &mut PgConnection, create: Self::Create) -> Result { - todo!() + let flavor = sqlx::query_as!( + Flavor, + r#"INSERT INTO flavors (name, short_code) VALUES ($1, $2) RETURNING *"#, + create.name, + create.short_code, + ) + .fetch_one(&mut *conn) + .await?; + + for ingredient_type in create.ingredient_types { + sqlx::query!( + r#"INSERT INTO ingredients_required (flavor_id, ingredient_id) VALUES ($1, $2)"#, + flavor.id, + ingredient_type.id, + ) + .execute(&mut *conn) + .await?; + } + + Ok(flavor) } async fn read_inner<'a>( conn: impl sqlx::prelude::Executor<'a, Database = sqlx::Postgres>, id: Self::Identifier, ) -> Result { - todo!() + sqlx::query_as!(Flavor, r#"SELECT * FROM flavors WHERE id = $1"#, id) + .fetch_one(conn) + .await + .map_err(Into::into) } async fn update_inner(&mut self, conn: &mut PgConnection) -> Result<()> { - todo!() + sqlx::query!( + r#"UPDATE flavors SET name = $1, short_code = $2 WHERE id = $3"#, + self.name, + self.short_code, + self.id + ) + .execute(conn) + .await + .map_err(Into::into) + .map(|_| ()) } async fn delete_inner(&self, conn: &mut PgConnection) -> Result<()> { - todo!() + sqlx::query!(r#"DELETE FROM flavors WHERE id = $1"#, self.id) + .execute(conn) + .await + .map_err(Into::into) + .map(|_| ()) } } @@ -73,20 +109,43 @@ impl Flavor { conn: &mut PgConnection, ingredient_id: Uuid, ) -> Result<()> { - todo!() + sqlx::query!( + r#"INSERT INTO ingredients_required (flavor_id, ingredient_id) VALUES ($1, $2)"#, + self.id, + ingredient_id + ) + .execute(conn) + .await + .map_err(Into::into) + .map(|_| ()) } pub async fn remove_ingredient<'a>( &mut self, conn: &mut PgConnection, ingredient_id: Uuid, ) -> Result<()> { - todo!() + sqlx::query!( + r#"DELETE FROM ingredients_required WHERE flavor_id = $1 AND ingredient_id = $2"#, + self.id, + ingredient_id + ) + .execute(conn) + .await + .map_err(Into::into) + .map(|_| ()) } pub async fn get_ingredients( &self, conn: impl sqlx::prelude::Executor<'_, Database = sqlx::Postgres>, - ) -> Result> { - todo!() + ) -> Result> { + sqlx::query_as!( + IngredientType, + r#"SELECT ingredients_type.* FROM ingredients_type JOIN ingredients_required ON ingredients_type.id = ingredients_required.ingredient_id WHERE ingredients_required.flavor_id = $1"#, + self.id + ) + .fetch_all(conn) + .await + .map_err(Into::into) } }