regalade/src/routes/recipe.rs

137 lines
4 KiB
Rust
Raw Normal View History

2023-06-25 15:13:15 +02:00
use api::{
CreateRecipeRequest, CreateRecipeResponse, IngredientInfo, ListRecipesResponse, RecipeInfo,
};
use axum::{
extract::{Path, State},
Json,
};
2023-06-22 22:29:53 +02:00
use sea_orm::{prelude::*, ActiveValue, TransactionTrait};
use crate::entity::{ingredient, prelude::*, recipe, recipe_ingerdients, recipe_steps};
use super::{household::AuthorizedHousehold, AppState, JsonResult, RouteError};
pub(super) async fn create_recipe(
AuthorizedHousehold(household): AuthorizedHousehold,
State(state): State<AppState>,
Json(request): Json<CreateRecipeRequest>,
) -> JsonResult<CreateRecipeResponse> {
let id = state
.db
.transaction(|txn| {
Box::pin(async move {
let model = recipe::ActiveModel {
name: ActiveValue::Set(request.name),
ranking: ActiveValue::Set(request.rating as i32),
2023-06-22 23:03:50 +02:00
household: ActiveValue::Set(household.id),
2023-06-22 22:29:53 +02:00
..Default::default()
};
let recipe = model.insert(txn).await?;
for (num, text) in request.steps.into_iter().enumerate() {
let model = recipe_steps::ActiveModel {
num: ActiveValue::Set(num as _),
recipe_id: ActiveValue::Set(recipe.id),
text: ActiveValue::Set(text),
};
model.insert(txn).await?;
}
for (ig, amount) in request.ingredients {
if 0 == household
.find_related(Ingredient)
.filter(ingredient::Column::Id.eq(ig))
.count(txn)
.await?
{
Err(RouteError::InvalidRequest(format!(
"No such ingredient {ig}"
)))?;
}
let model = recipe_ingerdients::ActiveModel {
recipe_id: ActiveValue::Set(recipe.id),
ingredient_id: ActiveValue::Set(ig),
amount: ActiveValue::Set(amount),
};
model.insert(txn).await?;
}
Ok(recipe.id)
})
})
.await?;
Ok(CreateRecipeResponse { id }.into())
}
2023-06-22 23:04:46 +02:00
pub(super) async fn list_recipes(
AuthorizedHousehold(household): AuthorizedHousehold,
State(state): State<AppState>,
) -> JsonResult<ListRecipesResponse> {
Ok(ListRecipesResponse {
recipes: household
.find_related(Recipe)
.all(&state.db)
.await?
.into_iter()
.map(|r| (r.id, r.name))
.collect(),
}
.into())
}
2023-06-25 15:13:15 +02:00
#[derive(serde::Deserialize)]
pub(super) struct RecipeId {
recipe_id: i64,
}
pub(super) async fn fetch_recipe(
AuthorizedHousehold(household): AuthorizedHousehold,
State(state): State<AppState>,
Path(RecipeId { recipe_id }): Path<RecipeId>,
) -> JsonResult<RecipeInfo> {
let Some(recipe) = household
.find_related(Recipe)
.filter(recipe::Column::Id.eq(recipe_id))
.one(&state.db).await? else {
return Err(RouteError::RessourceNotFound);
};
let steps = recipe
.find_related(RecipeSteps)
.all(&state.db)
.await?
.into_iter()
.map(|m| m.text)
.collect();
let recipe_ingredients = recipe.find_related(Ingredient).all(&state.db).await?;
let mut ingredients = Vec::new();
for ingredient in recipe_ingredients {
ingredients.push((
ingredient.id,
IngredientInfo {
name: ingredient.name,
unit: ingredient.unit,
},
RecipeIngerdients::find_by_id((recipe.id, ingredient.id))
.one(&state.db)
.await?
.expect("Ingredient should exist as it was fetched")
.amount,
));
}
Ok(RecipeInfo {
name: recipe.name,
steps,
ingredients,
}
.into())
}