Shopping list (WIP)

This commit is contained in:
Greg Burri 2025-02-11 19:39:13 +01:00
parent ce3821b94e
commit 084be9fb00
16 changed files with 296 additions and 90 deletions

View file

@ -17,6 +17,7 @@ use crate::consts;
pub mod recipe;
pub mod settings;
pub mod shopping_list;
pub mod user;
const CURRENT_DB_VERSION: u32 = 1;

View file

@ -0,0 +1,38 @@
use sqlx;
use super::{Connection, DBError, Result};
use crate::data::model;
impl Connection {
pub async fn get_shopping_list(&self, user_id: i64) -> Result<Vec<model::ShoppingListItem>> {
sqlx::query_as(
r#"
SELECT [ShoppingEntry].[id],
CASE [ShoppingEntry].[name]
WHEN '' THEN [Ingredient].[name]
ELSE [ShoppingEntry].[name]
END AS [name],
CASE WHEN [ShoppingEntry].[quantity_value] IS NOT NULL THEN [ShoppingEntry].[quantity_value]
ELSE [Ingredient].[quantity_value]
END AS [quantity_value],
CASE [ShoppingEntry].[quantity_unit] WHEN '' THEN [Ingredient].[quantity_unit]
ELSE [ShoppingEntry].[quantity_unit]
END AS [quantity_unit],
[Recipe].[id] AS [recipe_id],
[Recipe].[title] AS [recipe_title],
[RecipeScheduled].[date],
[is_checked]
FROM [ShoppingEntry]
LEFT JOIN [Ingredient] ON [Ingredient].[id] = [ShoppingEntry].[ingredient_id]
LEFT JOIN [RecipeScheduled] ON [RecipeScheduled].[id] = [ShoppingEntry].[recipe_scheduled_id]
LEFT JOIN [Recipe] ON [Recipe].[id] = [RecipeScheduled].[recipe_id]
WHERE [ShoppingEntry].[user_id] = $1
ORDER BY [is_checked], [recipe_id], [name]
"#,
)
.bind(user_id)
.fetch_all(&self.pool)
.await
.map_err(DBError::from)
}
}

View file

@ -72,3 +72,15 @@ pub struct Ingredient {
pub quantity_value: Option<f64>,
pub quantity_unit: String,
}
#[derive(Debug, FromRow)]
pub struct ShoppingListItem {
pub id: i64,
pub name: String,
pub quantity_value: Option<f64>,
pub quantity_unit: String,
pub recipe_id: Option<i64>,
pub recipe_title: Option<String>,
pub date: Option<NaiveDate>,
pub is_checked: bool,
}

View file

@ -190,6 +190,10 @@ async fn main() {
"/calendar/remove_scheduled_recipe",
delete(services::ron::rm_scheduled_recipe),
)
.route(
"/shopping_list/get_list",
get(services::ron::get_shopping_list),
)
.fallback(services::ron::not_found);
let fragments_routes = Router::new().route(

View file

@ -618,7 +618,7 @@ pub async fn set_ingredients_order(
Ok(StatusCode::OK)
}
/// Calendar ///
/*** Calendar ***/
#[debug_handler]
pub async fn get_scheduled_recipes(
@ -692,7 +692,46 @@ pub async fn rm_scheduled_recipe(
Ok(StatusCode::OK)
}
/// 404 ///
/*** Shopping list ***/
impl From<model::ShoppingListItem> for common::ron_api::ShoppingListItem {
fn from(item: model::ShoppingListItem) -> Self {
Self {
id: item.id,
name: item.name,
quantity_value: item.quantity_value,
quantity_unit: item.quantity_unit,
recipe_id: item.recipe_id,
recipe_title: item.recipe_title,
date: item.date,
is_checked: item.is_checked,
}
}
}
#[debug_handler]
pub async fn get_shopping_list(
State(connection): State<db::Connection>,
Extension(user): Extension<Option<model::User>>,
) -> Result<impl IntoResponse> {
if let Some(user) = user {
Ok(ron_response_ok(
connection
.get_shopping_list(user.id)
.await?
.into_iter()
.map(common::ron_api::ShoppingListItem::from)
.collect::<Vec<_>>(),
))
} else {
Err(ErrorResponse::from(ron_error(
StatusCode::UNAUTHORIZED,
NOT_AUTHORIZED_MESSAGE,
)))
}
}
/*** 404 ***/
#[debug_handler]
pub async fn not_found(Extension(_user): Extension<Option<model::User>>) -> impl IntoResponse {