From 38582f66ab36df90e6b43c1d1b4a889b9fc3431d Mon Sep 17 00:00:00 2001 From: Jeremy Wall Date: Tue, 17 Jan 2023 13:07:14 -0500 Subject: [PATCH] Add api for getting a plan for a specific date --- kitchen/sqlx-data.json | 30 ++++++++++++++ kitchen/src/web/mod.rs | 14 +++++++ .../src/web/storage/fetch_plan_for_date.sql | 5 +++ kitchen/src/web/storage/mod.rs | 40 +++++++++++++++++++ 4 files changed, 89 insertions(+) create mode 100644 kitchen/src/web/storage/fetch_plan_for_date.sql diff --git a/kitchen/sqlx-data.json b/kitchen/sqlx-data.json index e6cecb4..4b81565 100644 --- a/kitchen/sqlx-data.json +++ b/kitchen/sqlx-data.json @@ -126,6 +126,36 @@ }, "query": "insert into category_mappings\n (user_id, ingredient_name, category_name)\n values (?, ?, ?)\n on conflict (user_id, ingredient_name)\n do update set category_name=excluded.category_name\n" }, + "2e076acd2405d234daaa866e5a2ac1e10989fc8d2820f90aa722464a7b17db6b": { + "describe": { + "columns": [ + { + "name": "plan_date: NaiveDate", + "ordinal": 0, + "type_info": "Date" + }, + { + "name": "recipe_id", + "ordinal": 1, + "type_info": "Text" + }, + { + "name": "count", + "ordinal": 2, + "type_info": "Int64" + } + ], + "nullable": [ + false, + false, + false + ], + "parameters": { + "Right": 2 + } + }, + "query": "select plan_date as \"plan_date: NaiveDate\", recipe_id, count\n from plan_recipes\nwhere\n user_id = ?\n and plan_date = ?" + }, "37f382be1b53efd2f79a0d59ae6a8717f88a86908a7a4128d5ed7339147ca59d": { "describe": { "columns": [ diff --git a/kitchen/src/web/mod.rs b/kitchen/src/web/mod.rs index ab4a4ec..a79aca7 100644 --- a/kitchen/src/web/mod.rs +++ b/kitchen/src/web/mod.rs @@ -208,6 +208,19 @@ async fn api_save_recipes( } } +async fn api_plan_for_date( + Extension(app_store): Extension>, + session: storage::UserIdFromSession, + Path(date): Path, +) -> api::PlanDataResponse { + use storage::{UserId, UserIdFromSession::FoundUserId}; + if let FoundUserId(UserId(id)) = session { + app_store.fetch_meal_plan_for_date(&id, date).await.into() + } else { + api::Response::Unauthorized + } +} + async fn api_plan( Extension(app_store): Extension>, session: storage::UserIdFromSession, @@ -422,6 +435,7 @@ fn mk_v2_routes() -> Router { // mealplan api path routes .route("/plan", get(api_plan).post(api_save_plan)) .route("/plan/since/:date", get(api_plan_since)) + .route("/plan/at/:date", get(api_plan_for_date)) .route("/plan/all", get(api_all_plans)) .route( "/inventory", diff --git a/kitchen/src/web/storage/fetch_plan_for_date.sql b/kitchen/src/web/storage/fetch_plan_for_date.sql new file mode 100644 index 0000000..44ef12d --- /dev/null +++ b/kitchen/src/web/storage/fetch_plan_for_date.sql @@ -0,0 +1,5 @@ +select plan_date as "plan_date: NaiveDate", recipe_id, count + from plan_recipes +where + user_id = ? + and plan_date = ? \ No newline at end of file diff --git a/kitchen/src/web/storage/mod.rs b/kitchen/src/web/storage/mod.rs index 7a2218b..4be6c47 100644 --- a/kitchen/src/web/storage/mod.rs +++ b/kitchen/src/web/storage/mod.rs @@ -121,6 +121,12 @@ pub trait APIStore { user_id: S, ) -> Result>>; + async fn fetch_meal_plan_for_date + Send>( + &self, + user_id: S, + date: NaiveDate, + ) -> Result>>; + async fn fetch_meal_plans_since + Send>( &self, user_id: S, @@ -583,6 +589,40 @@ impl APIStore for SqliteStore { Ok(Some(result)) } + async fn fetch_meal_plan_for_date + Send>( + &self, + user_id: S, + date: NaiveDate, + ) -> Result>> { + let user_id = user_id.as_ref(); + struct Row { + pub plan_date: NaiveDate, + pub recipe_id: String, + pub count: i64, + } + // NOTE(jwall): It feels like I shouldn't have to use an override here + // but I do because of the way sqlite does types and how that interacts + // with sqlx's type inference machinery. + let rows = sqlx::query_file_as!( + Row, + "src/web/storage/fetch_plan_for_date.sql", + user_id, + date + ) + .fetch_all(self.pool.as_ref()) + .await?; + if rows.is_empty() { + return Ok(None); + } + let mut result = Vec::new(); + for row in rows { + let (_, recipe_id, count): (NaiveDate, String, i64) = + (row.plan_date, row.recipe_id, row.count); + result.push((recipe_id, count as i32)); + } + Ok(Some(result)) + } + async fn fetch_latest_meal_plan + Send>( &self, user_id: S,