diff --git a/kitchen/sqlx-data.json b/kitchen/sqlx-data.json index 0e8c5f8..15e2ca0 100644 --- a/kitchen/sqlx-data.json +++ b/kitchen/sqlx-data.json @@ -1,14 +1,14 @@ { "db": "SQLite", - "0e06f6e072e2c55769feda0d5f998509139097fee640caf8fb38c7087669bee4": { + "07f619ff4474e9eb5f4d56497abb724e6952b4e43d681ba5ecd61490cf990ae9": { "describe": { "columns": [], "nullable": [], "parameters": { - "Right": 4 + "Right": 1 } }, - "query": "insert into filtered_ingredients(user_id, name, form, measure_type)\n values (?, ?, ?, ?)" + "query": "delete from filtered_ingredients where user_id = ?" }, "104f07472670436d3eee1733578bbf0c92dc4f965d3d13f9bf4bfbc92958c5b6": { "describe": { @@ -92,16 +92,6 @@ }, "query": "insert into recipes (user_id, recipe_id, recipe_text) values (?, ?, ?)\n on conflict(user_id, recipe_id) do update set recipe_text=excluded.recipe_text" }, - "512003bd6ef47567b243bbcaefcbd220acf36efab4cbd43b1a8debe59593577c": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Right": 5 - } - }, - "query": "insert into modified_amts(user_id, name, form, measure_type, amt)\n values (?, ?, ?, ?, ?)" - }, "5d743897fb0d8fd54c3708f1b1c6e416346201faa9e28823c1ba5a421472b1fa": { "describe": { "columns": [], @@ -184,6 +174,16 @@ }, "query": "insert into sessions (id, session_value) values (?, ?)" }, + "9e24ed2ea4d235e3a036025a0a0b5ea685546a81d7f2469a59a2fc1fc88798dc": { + "describe": { + "columns": [], + "nullable": [], + "parameters": { + "Right": 1 + } + }, + "query": "delete from modified_amts where user_id = ?" + }, "ad3408cd773dd8f9308255ec2800171638a1aeda9817c57fb8360f97115f8e97": { "describe": { "columns": [ @@ -282,6 +282,16 @@ }, "query": "delete from sessions" }, + "f510d7f8dcb79907abd8b17bd52127af1699b3b79d2737c7729972d6bd5a0693": { + "describe": { + "columns": [], + "nullable": [], + "parameters": { + "Right": 4 + } + }, + "query": "insert into filtered_ingredients(user_id, name, form, measure_type)\n values (?, ?, ?, ?) on conflict(user_id, name, form, measure_type) DO NOTHING" + }, "fc294739374d2a791214f747095e0bf9378989d1ff07d96a5431dbb208f21951": { "describe": { "columns": [ @@ -317,5 +327,15 @@ } }, "query": "select name, form, measure_type, amt from modified_amts where user_id = ?;" + }, + "fc9d3f8ce9d0b42f34307aeb31c128cc3267e77613d6f2e170c95e83d6e361df": { + "describe": { + "columns": [], + "nullable": [], + "parameters": { + "Right": 5 + } + }, + "query": "insert into modified_amts(user_id, name, form, measure_type, amt)\n values (?, ?, ?, ?, ?) on conflict (user_id, name, form, measure_type) do update set amt=excluded.amt" } } \ No newline at end of file diff --git a/kitchen/src/web/mod.rs b/kitchen/src/web/mod.rs index 136b374..67bebba 100644 --- a/kitchen/src/web/mod.rs +++ b/kitchen/src/web/mod.rs @@ -1,4 +1,3 @@ -use std::collections::BTreeMap; // Copyright 2022 Jeremy Wall // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -12,9 +11,9 @@ use std::collections::BTreeMap; // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +use std::net::SocketAddr; use std::path::PathBuf; use std::sync::Arc; -use std::{collections::BTreeSet, net::SocketAddr}; use axum::{ body::{boxed, Full}, @@ -289,12 +288,14 @@ async fn api_save_inventory( Extension(app_store): Extension>, session: storage::UserIdFromSession, Json((filtered_ingredients, modified_amts)): Json<( - BTreeSet, - BTreeMap, + Vec, + Vec<(IngredientKey, String)>, )>, ) -> impl IntoResponse { use storage::{UserId, UserIdFromSession::FoundUserId}; if let FoundUserId(UserId(id)) = session { + let filtered_ingredients = filtered_ingredients.into_iter().collect(); + let modified_amts = modified_amts.into_iter().collect(); if let Err(e) = app_store .save_inventory_data(id, filtered_ingredients, modified_amts) .await diff --git a/kitchen/src/web/storage/mod.rs b/kitchen/src/web/storage/mod.rs index 51dd5e5..70422ee 100644 --- a/kitchen/src/web/storage/mod.rs +++ b/kitchen/src/web/storage/mod.rs @@ -124,7 +124,7 @@ pub trait APIStore { async fn fetch_inventory_data + Send>( &self, user_id: S, - ) -> Result<(BTreeSet, BTreeMap)>; + ) -> Result<(Vec, Vec<(IngredientKey, String)>)>; async fn save_inventory_data + Send>( &self, @@ -496,7 +496,7 @@ impl APIStore for SqliteStore { async fn fetch_inventory_data + Send>( &self, user_id: S, - ) -> Result<(BTreeSet, BTreeMap)> { + ) -> Result<(Vec, Vec<(IngredientKey, String)>)> { let user_id = user_id.as_ref(); struct FilteredIngredientRow { name: String, @@ -510,9 +510,9 @@ impl APIStore for SqliteStore { ) .fetch_all(self.pool.as_ref()) .await?; - let mut filtered_ingredients = BTreeSet::new(); + let mut filtered_ingredients = Vec::new(); for row in filtered_ingredient_rows { - filtered_ingredients.insert(IngredientKey::new( + filtered_ingredients.push(IngredientKey::new( row.name, if row.form.is_empty() { None @@ -535,9 +535,9 @@ impl APIStore for SqliteStore { ) .fetch_all(self.pool.as_ref()) .await?; - let mut modified_amts = BTreeMap::new(); + let mut modified_amts = Vec::new(); for row in modified_amt_rows { - modified_amts.insert( + modified_amts.push(( IngredientKey::new( row.name, if row.form.is_empty() { @@ -548,7 +548,7 @@ impl APIStore for SqliteStore { row.measure_type, ), row.amt, - ); + )); } Ok((filtered_ingredients, modified_amts)) } @@ -561,6 +561,15 @@ impl APIStore for SqliteStore { ) -> Result<()> { let user_id = user_id.as_ref(); let mut transaction = self.pool.as_ref().begin().await?; + sqlx::query!( + "delete from filtered_ingredients where user_id = ?", + user_id + ) + .execute(&mut transaction) + .await?; + sqlx::query!("delete from modified_amts where user_id = ?", user_id) + .execute(&mut transaction) + .await?; for key in filtered_ingredients { let name = key.name(); let form = key.form(); diff --git a/kitchen/src/web/storage/save_inventory_filtered_ingredients.sql b/kitchen/src/web/storage/save_inventory_filtered_ingredients.sql index fabce9f..3472aa0 100644 --- a/kitchen/src/web/storage/save_inventory_filtered_ingredients.sql +++ b/kitchen/src/web/storage/save_inventory_filtered_ingredients.sql @@ -1,2 +1,2 @@ insert into filtered_ingredients(user_id, name, form, measure_type) - values (?, ?, ?, ?) \ No newline at end of file + values (?, ?, ?, ?) on conflict(user_id, name, form, measure_type) DO NOTHING \ No newline at end of file diff --git a/kitchen/src/web/storage/save_inventory_modified_amts.sql b/kitchen/src/web/storage/save_inventory_modified_amts.sql index 57a77b3..88ec9f0 100644 --- a/kitchen/src/web/storage/save_inventory_modified_amts.sql +++ b/kitchen/src/web/storage/save_inventory_modified_amts.sql @@ -1,2 +1,2 @@ insert into modified_amts(user_id, name, form, measure_type, amt) - values (?, ?, ?, ?, ?) \ No newline at end of file + values (?, ?, ?, ?, ?) on conflict (user_id, name, form, measure_type) do update set amt=excluded.amt \ No newline at end of file diff --git a/web/src/api.rs b/web/src/api.rs index ef1caf0..8e17ef7 100644 --- a/web/src/api.rs +++ b/web/src/api.rs @@ -392,8 +392,14 @@ impl HttpStore { Err(format!("Status: {}", resp.status()).into()) } else { debug!("We got a valid response back"); - let inventory = resp.json().await.map_err(|e| format!("{}", e))?; - Ok(inventory) + let (filtered_ingredients, modified_amts): ( + Vec, + Vec<(IngredientKey, String)>, + ) = resp.json().await.map_err(|e| format!("{}", e))?; + Ok(( + filtered_ingredients.into_iter().collect(), + modified_amts.into_iter().collect(), + )) } } @@ -403,6 +409,8 @@ impl HttpStore { modified_amts: BTreeMap, ) -> Result<(), Error> { let mut path = self.root.clone(); + let filtered_ingredients: Vec = filtered_ingredients.into_iter().collect(); + let modified_amts: Vec<(IngredientKey, String)> = modified_amts.into_iter().collect(); let serialized_inventory = to_string(&(filtered_ingredients, modified_amts)) .expect("Unable to encode plan as json"); path.push_str("/inventory"); diff --git a/web/src/components/shopping_list.rs b/web/src/components/shopping_list.rs index 8eef375..5c196b8 100644 --- a/web/src/components/shopping_list.rs +++ b/web/src/components/shopping_list.rs @@ -15,7 +15,7 @@ use std::collections::{BTreeMap, BTreeSet}; use recipes::{Ingredient, IngredientKey}; use sycamore::{futures::spawn_local_scoped, prelude::*}; -use tracing::{debug, instrument}; +use tracing::{debug, info, instrument}; fn make_ingredients_rows<'ctx, G: Html>( cx: Scope<'ctx>, @@ -187,15 +187,20 @@ pub fn ShoppingList(cx: Scope) -> View { }); create_effect(cx, move || { save_click.track(); + info!("Registering save request for inventory"); spawn_local_scoped(cx, { let state = crate::app_state::State::get_from_context(cx); let store = crate::api::HttpStore::get_from_context(cx); + let filtered_ingredients = state.filtered_ingredients.get_untracked().as_ref().clone(); + let modified_amts = state.get_current_modified_amts(); async move { + debug!( + ?filtered_ingredients, + ?modified_amts, + "Attempting save for inventory" + ); store - .save_inventory_data( - state.filtered_ingredients.get_untracked().as_ref().clone(), - state.get_current_modified_amts(), - ) + .save_inventory_data(filtered_ingredients, modified_amts) .await .expect("Unable to save inventory data"); }