Skip to content

Commit

Permalink
feat: meal deletion
Browse files Browse the repository at this point in the history
  • Loading branch information
jdevries3133 committed Dec 15, 2023
1 parent 1c79de2 commit 9b0fce8
Show file tree
Hide file tree
Showing 8 changed files with 123 additions and 46 deletions.
33 changes: 26 additions & 7 deletions sqlx-data.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,32 +17,50 @@
},
"query": "insert into meal (user_id, name, calories, fat, protein, carbohydrates)\n values ($1, $2, $3, $4, $5, $6)"
},
"4eae706064c5ddfeb72d5f5c9babc0f7ea7a4519454bc1ccc0b4e6af1f60ca4b": {
"21d97a21e8486f639820b3b00f89ba477a5443acfc3493413cef15ecf4d51f07": {
"describe": {
"columns": [],
"nullable": [],
"parameters": {
"Left": [
"Int4",
"Int4"
]
}
},
"query": "delete from meal where user_id = $1 and id = $2"
},
"62c068b9691dd48e0d6634b951ddd8d4b0d7957b7fd9f54d5d580ae9d812c052": {
"describe": {
"columns": [
{
"name": "meal_name",
"name": "id",
"ordinal": 0,
"type_info": "Int4"
},
{
"name": "meal_name",
"ordinal": 1,
"type_info": "Text"
},
{
"name": "calories",
"ordinal": 1,
"ordinal": 2,
"type_info": "Int4"
},
{
"name": "fat_grams",
"ordinal": 2,
"ordinal": 3,
"type_info": "Int4"
},
{
"name": "protein_grams",
"ordinal": 3,
"ordinal": 4,
"type_info": "Int4"
},
{
"name": "carbohydrates_grams",
"ordinal": 4,
"ordinal": 5,
"type_info": "Int4"
}
],
Expand All @@ -51,6 +69,7 @@
false,
false,
false,
false,
false
],
"parameters": {
Expand All @@ -59,7 +78,7 @@
]
}
},
"query": "select name meal_name, calories, fat fat_grams, protein protein_grams, carbohydrates carbohydrates_grams\n from meal\n where user_id = $1\n order by id desc\n "
"query": "select id, name meal_name, calories, fat fat_grams, protein protein_grams, carbohydrates carbohydrates_grams\n from meal\n where user_id = $1\n order by id desc\n "
},
"68a469121ce660fafeb842413a14b4ec275bb6fcacdb10a939f5458329cf95a1": {
"describe": {
Expand Down
2 changes: 1 addition & 1 deletion src/components.rs
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ impl Component for ExternalLink<'_> {

pub struct UserHome<'a> {
pub user: &'a models::User,
pub meals: &'a Vec<count_chat::MealInfo>,
pub meals: &'a Vec<count_chat::Meal>,
}
impl Component for UserHome<'_> {
fn render(&self) -> String {
Expand Down
20 changes: 19 additions & 1 deletion src/controllers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,13 @@ use super::{
};
use anyhow::Result;
use axum::{
extract::State,
extract::{Path, State},
http::{HeaderMap, HeaderValue},
response::IntoResponse,
Form,
};
use serde::Deserialize;
use sqlx::query;

pub async fn root() -> impl IntoResponse {
components::Page {
Expand Down Expand Up @@ -191,3 +192,20 @@ pub async fn handle_login(
))
}
}

pub async fn delete_meal(
State(AppState { db }): State<AppState>,
headers: HeaderMap,
Path(id): Path<i32>,
) -> Result<impl IntoResponse, ServerError> {
let session = Session::from_headers(&headers)
.ok_or_else(|| ServerError::forbidden("delete meal"))?;
query!(
"delete from meal where user_id = $1 and id = $2",
session.user.id,
id
)
.execute(&db)
.await?;
Ok("")
}
58 changes: 50 additions & 8 deletions src/count_chat/counter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
//! are colocated here).

use super::{
llm_parse_response::{MealCard, MealInfo, ParserResult},
llm_parse_response::{MealCard, ParserResult},
openai::OpenAI,
};
use crate::{
Expand All @@ -19,14 +19,34 @@ use axum::{
use serde::Deserialize;
use sqlx::{query, query_as, PgPool};

pub struct Meal {
id: i32,
info: MealInfo,
}

#[derive(Debug, Deserialize)]
pub struct MealInfo {
pub calories: i32,
pub protein_grams: i32,
pub carbohydrates_grams: i32,
pub fat_grams: i32,
pub meal_name: String,
}

pub struct Chat<'a> {
pub meals: &'a Vec<MealInfo>,
pub meals: &'a Vec<Meal>,
}
impl Component for Chat<'_> {
fn render(&self) -> String {
let handler = Route::HandleChat;
let meals = self.meals.iter().fold(String::new(), |mut acc, meal| {
acc.push_str(&MealCard { info: meal }.render());
acc.push_str(
&MealCard {
info: &meal.info,
meal_id: Some(meal.id),
}
.render(),
);
acc
});
format!(
Expand Down Expand Up @@ -108,16 +128,38 @@ pub async fn chat_form(
Ok(content)
}

pub async fn get_meals(db: &PgPool, user_id: i32) -> AResult<Vec<MealInfo>> {
Ok(query_as!(
MealInfo,
"select name meal_name, calories, fat fat_grams, protein protein_grams, carbohydrates carbohydrates_grams
pub async fn get_meals(db: &PgPool, user_id: i32) -> AResult<Vec<Meal>> {
struct Qres {
id: i32,
meal_name: String,
calories: i32,
fat_grams: i32,
protein_grams: i32,
carbohydrates_grams: i32,
}
let mut res = query_as!(
Qres,
"select id, name meal_name, calories, fat fat_grams, protein protein_grams, carbohydrates carbohydrates_grams
from meal
where user_id = $1
order by id desc
",
user_id
).fetch_all(db).await?)
).fetch_all(db).await?;

Ok(res
.drain(..)
.map(|r| Meal {
id: r.id,
info: MealInfo {
meal_name: r.meal_name,
calories: r.calories,
carbohydrates_grams: r.carbohydrates_grams,
fat_grams: r.fat_grams,
protein_grams: r.protein_grams,
},
})
.collect::<Vec<Meal>>())
}

pub async fn handle_save_meal(
Expand Down
24 changes: 14 additions & 10 deletions src/count_chat/llm_parse_response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
//! next time an a resonably well-structured declarative way. Inspired by
//! https://www.youtube.com/watch?v=yj-wSRJwrrc.

use super::counter::MealInfo;
use crate::{components::Component, routes::Route};
use ammonia::clean;
use regex::{Captures, Regex};
use serde::Deserialize;

#[derive(Debug)]
pub struct FollowUp {
Expand All @@ -22,14 +22,6 @@ pub enum ParserResult<T> {
FollowUp(FollowUp),
}

#[derive(Debug, Deserialize)]
pub struct MealInfo {
pub calories: i32,
pub protein_grams: i32,
pub carbohydrates_grams: i32,
pub fat_grams: i32,
pub meal_name: String,
}
impl Component for MealInfo {
fn render(&self) -> String {
let save_route = Route::SaveMeal;
Expand Down Expand Up @@ -70,9 +62,21 @@ impl Component for MealInfo {

pub struct MealCard<'a> {
pub info: &'a MealInfo,
pub meal_id: Option<i32>,
}
impl Component for MealCard<'_> {
fn render(&self) -> String {
let delete_button = match self.meal_id {
Some(id) => {
let href = Route::DeleteMeal(Some(id));
format!(
r#"<button hx-delete="{href}" hx-target="closest div"class="bg-red-100 hover:bg-red-200 rounded p-1">
Delete
</button>"#
)
}
None => "".into(),
};
let meal_name = clean(&self.info.meal_name);
let calories = self.info.calories;
let protein = self.info.protein_grams;
Expand All @@ -86,7 +90,7 @@ impl Component for MealCard<'_> {
<p><b>Protein:</b> {protein} grams</p>
<p><b>Carbs:</b> {carbs} grams</p>
<p><b>Fat:</b> {fat} grams</p>
<p class="text-sm italic">(todo: add delete button!)</p>
{delete_button}
</div>
"##
)
Expand Down
9 changes: 3 additions & 6 deletions src/count_chat/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,7 @@ mod counter;
mod llm_parse_response;
mod openai;

pub use self::{
counter::{
chat_form, get_meals, handle_chat, handle_save_meal,
Chat as ChatContainer,
},
llm_parse_response::MealInfo,
pub use self::counter::{
chat_form, get_meals, handle_chat, handle_save_meal, Chat as ChatContainer,
Meal,
};
12 changes: 0 additions & 12 deletions src/count_chat/models.rs

This file was deleted.

11 changes: 10 additions & 1 deletion src/routes.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! All possible routes with their params are defined in a big enum.

use super::{controllers, count_chat, models};
use axum::routing::{get, post, Router};
use axum::routing::{delete, get, post, Router};

/// This enum contains all of the route strings in the application. This
/// solves several problems.
Expand All @@ -23,6 +23,7 @@ pub enum Route<'a> {
HandleChat,
ChatForm,
SaveMeal,
DeleteMeal(Option<i32>),
/// The `String` slug is unnecessary here, but this is the general pattern
/// for handling routes that have slug parameters.
UserHome(Option<&'a str>),
Expand All @@ -41,6 +42,10 @@ impl Route<'_> {
Self::HandleChat => "/chat".into(),
Self::ChatForm => "/chat-form".into(),
Self::SaveMeal => "/save-meal".into(),
Self::DeleteMeal(slug) => match slug {
Some(value) => format!("/delete-meal/{value}"),
None => "/delete-meal/:id".into(),
},
Self::UserHome(slug) => match slug {
Some(value) => format!("/home/{value}"),
None => "/home/:slug".into(),
Expand Down Expand Up @@ -79,6 +84,10 @@ pub fn get_protected_routes() -> Router<models::AppState> {
&Route::SaveMeal.as_string(),
post(count_chat::handle_save_meal),
)
.route(
&Route::DeleteMeal(None).as_string(),
delete(controllers::delete_meal),
)
}

/// In [crate::main], these routes are not protected by any authentication, so
Expand Down

0 comments on commit 9b0fce8

Please sign in to comment.