mirror of
https://github.com/zaphar/kitchen.git
synced 2025-07-22 19:40:14 -04:00
Store extra items in the database too
This commit is contained in:
parent
8fd940bd00
commit
d354a5db0c
@ -1,2 +1,19 @@
|
||||
-- Add up migration script here
|
||||
create unique index mealplan_lookup_index on plan_recipes (user_id, plan_date, recipe_id);
|
||||
-- First we collect a safe set of the data deduped for the unique index to handle using max to select a winning count.
|
||||
create temp table TEMP_plan_recipes_deduped as
|
||||
select user_id, plan_date, recipe_id, max(count) as count
|
||||
from plan_recipes
|
||||
group by user_id, plan_date, recipe_id;
|
||||
|
||||
-- Then we drop the plan_recipes from the table
|
||||
delete from plan_recipes;
|
||||
|
||||
-- Create the unique index
|
||||
create unique index mealplan_lookup_index
|
||||
on plan_recipes (user_id, plan_date, recipe_id);
|
||||
|
||||
-- And finally insert the dedeuped records back into the table before dropping the temp table.
|
||||
insert into plan_recipes
|
||||
select user_id, plan_date, recipe_id, count
|
||||
from TEMP_plan_recipes_deduped;
|
||||
drop table TEMP_plan_recipes_deduped;
|
@ -0,0 +1,57 @@
|
||||
-- Add down migration script here
|
||||
drop table extra_items;
|
||||
|
||||
-- make a copy of of the filtered_ingredients table with only latest plan_date rows
|
||||
create temp table TEMP_filtered_ingredients_copy as
|
||||
select
|
||||
user_id,
|
||||
name,
|
||||
max(plan_date) as plan_date,
|
||||
form,
|
||||
measure_type
|
||||
from filtered_ingredients
|
||||
group by user_id, name, form, measure_type;
|
||||
|
||||
-- Drop the filtered ingredients table and recreate without plan_date
|
||||
drop table filtered_ingredients;
|
||||
create table filtered_ingredients(
|
||||
user_id TEXT NOT NULL,
|
||||
name TEXT NOT NULL,
|
||||
form TEXT NOT NULL,
|
||||
measure_type TEXT NOT NULL,
|
||||
primary key(user_id, name, form, measure_type)
|
||||
);
|
||||
|
||||
-- Populate the new filtered ingredients table from the copied table
|
||||
insert into filtered_ingredients
|
||||
select user_id, name, form, measure_type
|
||||
from TEMP_filtered_ingredients_copy;
|
||||
|
||||
-- make a copy of of the modified_amts table with only latest plan_date rows
|
||||
create temp table TEMP_modified_amts_copy as
|
||||
select
|
||||
user_id,
|
||||
name,
|
||||
form,
|
||||
measure_type,
|
||||
max(plan_date) as plan_date,
|
||||
amt
|
||||
from modified_amts;
|
||||
|
||||
-- Drop modified_amts and recreate without plan_date.
|
||||
drop table modified_amts;
|
||||
create table modified_amts(
|
||||
user_id TEXT NOT NULL,
|
||||
name TEXT NOT NULL,
|
||||
form TEXT NOT NULL,
|
||||
measure_type TEXT NOT NULL,
|
||||
amt TEXT NOT NULL,
|
||||
primary key(user_id, name, form, measure_type)
|
||||
);
|
||||
|
||||
-- Populate the new modified amts with rows from the copy.
|
||||
insert into modified_amts
|
||||
select user_id, name, form, measure_type, amt
|
||||
from TEMP_modified_amts_copy;
|
||||
|
||||
drop table TEMP_modified_amts_copy;
|
@ -0,0 +1,68 @@
|
||||
-- Add up migration script here
|
||||
|
||||
-- Create our extra items table
|
||||
create table extra_items(
|
||||
user_id TEXT NOT NULL,
|
||||
name TEXT NOT NULL,
|
||||
plan_date DATE NOT NULL,
|
||||
amt TEXT NOT NULL,
|
||||
primary key(user_id, name, plan_date)
|
||||
);
|
||||
|
||||
-- Store a copy of filtered ingredients with current date as plan_date
|
||||
create temp table TEMP_filtered_ingredients_copy as
|
||||
select
|
||||
user_id,
|
||||
name,
|
||||
date() as plan_date,
|
||||
form,
|
||||
measure_type
|
||||
from filtered_ingredients;
|
||||
|
||||
-- Drop the filtered ingredients table and recreate with plan_date in the primary key
|
||||
drop table filtered_ingredients;
|
||||
create table filtered_ingredients(
|
||||
user_id TEXT NOT NULL,
|
||||
name TEXT NOT NULL,
|
||||
form TEXT NOT NULL,
|
||||
measure_type TEXT NOT NULL,
|
||||
plan_date DATE NOT NULL,
|
||||
primary key(user_id, name, form, measure_type, plan_date)
|
||||
);
|
||||
|
||||
-- Populate the new filtered ingredients table from the copied table
|
||||
insert into filtered_ingredients
|
||||
select user_id, name, form, measure_type, plan_date
|
||||
from TEMP_filtered_ingredients_copy;
|
||||
|
||||
drop table TEMP_filtered_ingredients_copy;
|
||||
|
||||
-- make a copy of of the modified_amts table with current date as plan_date
|
||||
create temp table TEMP_modified_amts_copy as
|
||||
select
|
||||
user_id,
|
||||
name,
|
||||
form,
|
||||
measure_type,
|
||||
date() as plan_date,
|
||||
amt
|
||||
from modified_amts;
|
||||
|
||||
-- Drop modified_amts and recreate with plan_date as part of primary key.
|
||||
drop table modified_amts;
|
||||
create table modified_amts(
|
||||
user_id TEXT NOT NULL,
|
||||
name TEXT NOT NULL,
|
||||
form TEXT NOT NULL,
|
||||
measure_type TEXT NOT NULL,
|
||||
plan_date DATE NOT NULL,
|
||||
amt TEXT NOT NULL,
|
||||
primary key(user_id, name, form, measure_type, plan_date)
|
||||
);
|
||||
|
||||
-- Populate the new modified amts with rows from the copy.
|
||||
insert into modified_amts
|
||||
select user_id, name, form, measure_type, plan_date, amt
|
||||
from TEMP_modified_amts_copy;
|
||||
|
||||
drop table TEMP_modified_amts_copy;
|
@ -1,14 +1,34 @@
|
||||
{
|
||||
"db": "SQLite",
|
||||
"07f619ff4474e9eb5f4d56497abb724e6952b4e43d681ba5ecd61490cf990ae9": {
|
||||
"04987493e4b13793a2dff75cc2710972bb28abf303275f5e6346470cdf5c2c17": {
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"nullable": [],
|
||||
"columns": [
|
||||
{
|
||||
"name": "name",
|
||||
"ordinal": 0,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "form",
|
||||
"ordinal": 1,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "measure_type",
|
||||
"ordinal": 2,
|
||||
"type_info": "Text"
|
||||
}
|
||||
],
|
||||
"nullable": [
|
||||
false,
|
||||
false,
|
||||
false
|
||||
],
|
||||
"parameters": {
|
||||
"Right": 1
|
||||
}
|
||||
},
|
||||
"query": "delete from filtered_ingredients where user_id = ?"
|
||||
"query": "with latest_dates as (\n select\n user_id,\n name,\n form,\n measure_type,\n max(plan_date) as plan_date\n from filtered_ingredients\n where user_id = ?\n)\n\nselect\n filtered_ingredients.name,\n filtered_ingredients.form,\n filtered_ingredients.measure_type\nfrom latest_dates\ninner join filtered_ingredients on\n latest_dates.user_id = filtered_ingredients.user_id\n and latest_dates.name = filtered_ingredients.name\n and latest_dates.form = filtered_ingredients.form\n and latest_dates.measure_type = filtered_ingredients.measure_type\n and latest_dates.plan_date = filtered_ingredients.plan_date"
|
||||
},
|
||||
"104f07472670436d3eee1733578bbf0c92dc4f965d3d13f9bf4bfbc92958c5b6": {
|
||||
"describe": {
|
||||
@ -28,6 +48,16 @@
|
||||
},
|
||||
"query": "select password_hashed from users where id = ?"
|
||||
},
|
||||
"160a9dfccf2e91a37d81f75eba21ec73105a7453c4f1fe76a430d04e525bc6cd": {
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"nullable": [],
|
||||
"parameters": {
|
||||
"Right": 4
|
||||
}
|
||||
},
|
||||
"query": "insert into filtered_ingredients(user_id, name, form, measure_type, plan_date)\n values (?, ?, ?, ?, date()) on conflict(user_id, name, form, measure_type, plan_date) DO NOTHING"
|
||||
},
|
||||
"196e289cbd65224293c4213552160a0cdf82f924ac597810fe05102e247b809d": {
|
||||
"describe": {
|
||||
"columns": [
|
||||
@ -82,6 +112,16 @@
|
||||
},
|
||||
"query": "select plan_date as \"plan_date: NaiveDate\", recipe_id, count\nfrom plan_recipes\nwhere\n user_id = ?\n and date(plan_date) > ?\norder by user_id, plan_date"
|
||||
},
|
||||
"3caefb86073c47b5dd5d05f639ddef2f7ed2d1fd80f224457d1ec34243cc56c7": {
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"nullable": [],
|
||||
"parameters": {
|
||||
"Right": 3
|
||||
}
|
||||
},
|
||||
"query": "insert into extra_items (user_id, name, plan_date, amt)\nvalues (?, ?, date(), ?)\non conflict (user_id, name, plan_date) do update set amt=excluded.amt"
|
||||
},
|
||||
"3fd4017569dca4fe73e97e0e2bd612027a8c1b17b0b10faabd6459f56ca1c0bb": {
|
||||
"describe": {
|
||||
"columns": [],
|
||||
@ -92,6 +132,42 @@
|
||||
},
|
||||
"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"
|
||||
},
|
||||
"406aac6ac2b0084c31c29adec6fa2fb9bb925d92121305c8afbac009caf1ecc0": {
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"name": "name",
|
||||
"ordinal": 0,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "form",
|
||||
"ordinal": 1,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "measure_type",
|
||||
"ordinal": 2,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "amt",
|
||||
"ordinal": 3,
|
||||
"type_info": "Text"
|
||||
}
|
||||
],
|
||||
"nullable": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
],
|
||||
"parameters": {
|
||||
"Right": 1
|
||||
}
|
||||
},
|
||||
"query": "with latest_dates as (\n select\n user_id,\n name,\n form,\n measure_type,\n amt,\n max(plan_date) as plan_date\n from modified_amts\n where user_id = ?\n)\n\nselect\n modified_amts.name,\n modified_amts.form,\n modified_amts.measure_type,\n modified_amts.amt\nfrom latest_dates\ninner join modified_amts on\n latest_dates.user_id = modified_amts.user_id\n and latest_dates.name = modified_amts.name\n and latest_dates.form = modified_amts.form\n and latest_dates.amt = modified_amts.amt\n and latest_dates.plan_date = modified_amts.plan_date"
|
||||
},
|
||||
"5d743897fb0d8fd54c3708f1b1c6e416346201faa9e28823c1ba5a421472b1fa": {
|
||||
"describe": {
|
||||
"columns": [],
|
||||
@ -102,6 +178,16 @@
|
||||
},
|
||||
"query": "insert into users (id, password_hashed) values (?, ?)"
|
||||
},
|
||||
"6e28698330e42fd6c87ba1e6f1deb664c0d3995caa2b937ceac8c908e98aded6": {
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"nullable": [],
|
||||
"parameters": {
|
||||
"Right": 5
|
||||
}
|
||||
},
|
||||
"query": "insert into modified_amts(user_id, name, form, measure_type, amt, plan_date)\n values (?, ?, ?, ?, ?, date()) on conflict (user_id, name, form, measure_type, plan_date) do update set amt=excluded.amt"
|
||||
},
|
||||
"7578157607967a6a4c60f12408c5d9900d15b429a49681a4cae4e02d31c524ec": {
|
||||
"describe": {
|
||||
"columns": [],
|
||||
@ -184,16 +270,6 @@
|
||||
},
|
||||
"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": [
|
||||
@ -242,36 +318,6 @@
|
||||
},
|
||||
"query": "select category_text from categories where user_id = ?"
|
||||
},
|
||||
"d7d94a87b0153d1436eac0f6db820f25594e94decc8d740037c10802aa49157f": {
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"name": "name",
|
||||
"ordinal": 0,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "form",
|
||||
"ordinal": 1,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "measure_type",
|
||||
"ordinal": 2,
|
||||
"type_info": "Text"
|
||||
}
|
||||
],
|
||||
"nullable": [
|
||||
false,
|
||||
false,
|
||||
false
|
||||
],
|
||||
"parameters": {
|
||||
"Right": 1
|
||||
}
|
||||
},
|
||||
"query": "select name, form, measure_type from filtered_ingredients where user_id = ?"
|
||||
},
|
||||
"d84685a82585c5e4ae72c86ba1fe6e4a7241c4c3c9e948213e5849d956132bad": {
|
||||
"describe": {
|
||||
"columns": [],
|
||||
@ -282,17 +328,7 @@
|
||||
},
|
||||
"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": {
|
||||
"f34ec23c5cc8f61f92464ecf68620150a8d4521b68b5099a0a7dac3328651880": {
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
@ -300,25 +336,13 @@
|
||||
"ordinal": 0,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "form",
|
||||
"ordinal": 1,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "measure_type",
|
||||
"ordinal": 2,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "amt",
|
||||
"ordinal": 3,
|
||||
"ordinal": 1,
|
||||
"type_info": "Text"
|
||||
}
|
||||
],
|
||||
"nullable": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
],
|
||||
@ -326,16 +350,6 @@
|
||||
"Right": 1
|
||||
}
|
||||
},
|
||||
"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"
|
||||
"query": "with latest_dates as (\n select\n user_id,\n name,\n max(plan_date) as plan_date\n from extra_items\n where user_id = ?\n group by user_id, name\n)\n\nselect\n extra_items.name,\n extra_items.amt\nfrom latest_dates\ninner join extra_items on\n latest_dates.user_id = extra_items.user_id\n and latest_dates.name = extra_items.name\n and latest_dates.plan_date= extra_items.plan_date"
|
||||
}
|
||||
}
|
@ -1,3 +1,4 @@
|
||||
use std::collections::BTreeMap;
|
||||
// Copyright 2022 Jeremy Wall
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -11,9 +12,9 @@
|
||||
// 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},
|
||||
@ -263,13 +264,13 @@ async fn api_save_plan(
|
||||
}
|
||||
}
|
||||
|
||||
async fn api_inventory(
|
||||
async fn api_inventory_v2(
|
||||
Extension(app_store): Extension<Arc<storage::SqliteStore>>,
|
||||
session: storage::UserIdFromSession,
|
||||
) -> impl IntoResponse {
|
||||
use storage::{UserId, UserIdFromSession::FoundUserId};
|
||||
if let FoundUserId(UserId(id)) = session {
|
||||
match app_store.fetch_inventory_data(id).await {
|
||||
match app_store.fetch_latest_inventory_data(id).await {
|
||||
Ok(tpl) => Ok(axum::Json::from(tpl)),
|
||||
Err(e) => {
|
||||
error!(err=?e);
|
||||
@ -284,6 +285,76 @@ async fn api_inventory(
|
||||
}
|
||||
}
|
||||
|
||||
async fn api_inventory(
|
||||
Extension(app_store): Extension<Arc<storage::SqliteStore>>,
|
||||
session: storage::UserIdFromSession,
|
||||
) -> impl IntoResponse {
|
||||
use storage::{UserId, UserIdFromSession::FoundUserId};
|
||||
if let FoundUserId(UserId(id)) = session {
|
||||
match app_store.fetch_latest_inventory_data(id).await {
|
||||
Ok((item1, item2, _)) => Ok(axum::Json::from((item1, item2))),
|
||||
Err(e) => {
|
||||
error!(err=?e);
|
||||
Err((StatusCode::INTERNAL_SERVER_ERROR, format!("{:?}", e)))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Err((
|
||||
StatusCode::UNAUTHORIZED,
|
||||
"You must be authorized to use this API call".to_owned(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
async fn save_inventory_data(
|
||||
app_store: Arc<storage::SqliteStore>,
|
||||
id: String,
|
||||
filtered_ingredients: BTreeSet<IngredientKey>,
|
||||
modified_amts: BTreeMap<IngredientKey, String>,
|
||||
extra_items: Vec<(String, String)>,
|
||||
) -> (StatusCode, String) {
|
||||
if let Err(e) = app_store
|
||||
.save_inventory_data(id, filtered_ingredients, modified_amts, extra_items)
|
||||
.await
|
||||
{
|
||||
error!(err=?e);
|
||||
return (StatusCode::INTERNAL_SERVER_ERROR, format!("{:?}", e));
|
||||
}
|
||||
(
|
||||
StatusCode::OK,
|
||||
"Successfully saved inventory data".to_owned(),
|
||||
)
|
||||
}
|
||||
|
||||
async fn api_save_inventory_v2(
|
||||
Extension(app_store): Extension<Arc<storage::SqliteStore>>,
|
||||
session: storage::UserIdFromSession,
|
||||
Json((filtered_ingredients, modified_amts, extra_items)): Json<(
|
||||
Vec<IngredientKey>,
|
||||
Vec<(IngredientKey, String)>,
|
||||
Vec<(String, 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();
|
||||
save_inventory_data(
|
||||
app_store,
|
||||
id,
|
||||
filtered_ingredients,
|
||||
modified_amts,
|
||||
extra_items,
|
||||
)
|
||||
.await
|
||||
} else {
|
||||
(
|
||||
StatusCode::UNAUTHORIZED,
|
||||
"You must be authorized to use this API call".to_owned(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
async fn api_save_inventory(
|
||||
Extension(app_store): Extension<Arc<storage::SqliteStore>>,
|
||||
session: storage::UserIdFromSession,
|
||||
@ -296,17 +367,14 @@ async fn api_save_inventory(
|
||||
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
|
||||
{
|
||||
error!(err=?e);
|
||||
return (StatusCode::INTERNAL_SERVER_ERROR, format!("{:?}", e));
|
||||
}
|
||||
(
|
||||
StatusCode::OK,
|
||||
"Successfully saved inventory data".to_owned(),
|
||||
save_inventory_data(
|
||||
app_store,
|
||||
id,
|
||||
filtered_ingredients,
|
||||
modified_amts,
|
||||
Vec::new(),
|
||||
)
|
||||
.await
|
||||
} else {
|
||||
(
|
||||
StatusCode::UNAUTHORIZED,
|
||||
@ -333,12 +401,13 @@ pub async fn ui_main(recipe_dir_path: PathBuf, store_path: PathBuf, listen_socke
|
||||
let router = Router::new()
|
||||
.route("/", get(|| async { Redirect::temporary("/ui/plan") }))
|
||||
.route("/ui/*path", get(ui_static_assets))
|
||||
// TODO(jwall): Cleanup the routing using nested routes
|
||||
// TODO(jwall): We should use route_layer to enforce the authorization
|
||||
// requirements here.
|
||||
// recipes api path route
|
||||
.route("/api/v1/recipes", get(api_recipes).post(api_save_recipes))
|
||||
// recipe entry api path route
|
||||
.route("/api/v1/recipe/:recipe_id", get(api_recipe_entry))
|
||||
// TODO(jwall): We should use route_layer to enforce the authorization
|
||||
// requirements here.
|
||||
// mealplan api path routes
|
||||
.route("/api/v1/plan", get(api_plan).post(api_save_plan))
|
||||
.route("/api/v1/plan/:date", get(api_plan_since))
|
||||
@ -347,6 +416,10 @@ pub async fn ui_main(recipe_dir_path: PathBuf, store_path: PathBuf, listen_socke
|
||||
"/api/v1/inventory",
|
||||
get(api_inventory).post(api_save_inventory),
|
||||
)
|
||||
.route(
|
||||
"/api/v2/inventory",
|
||||
get(api_inventory_v2).post(api_save_inventory_v2),
|
||||
)
|
||||
// categories api path route
|
||||
.route(
|
||||
"/api/v1/categories",
|
||||
|
18
kitchen/src/web/storage/fetch_extra_items.sql
Normal file
18
kitchen/src/web/storage/fetch_extra_items.sql
Normal file
@ -0,0 +1,18 @@
|
||||
with latest_dates as (
|
||||
select
|
||||
user_id,
|
||||
name,
|
||||
max(plan_date) as plan_date
|
||||
from extra_items
|
||||
where user_id = ?
|
||||
group by user_id, name
|
||||
)
|
||||
|
||||
select
|
||||
extra_items.name,
|
||||
extra_items.amt
|
||||
from latest_dates
|
||||
inner join extra_items on
|
||||
latest_dates.user_id = extra_items.user_id
|
||||
and latest_dates.name = extra_items.name
|
||||
and latest_dates.plan_date= extra_items.plan_date
|
7
kitchen/src/web/storage/fetch_extra_items_for_date.sql
Normal file
7
kitchen/src/web/storage/fetch_extra_items_for_date.sql
Normal file
@ -0,0 +1,7 @@
|
||||
select
|
||||
name,
|
||||
amt
|
||||
from extra_items
|
||||
where
|
||||
user_id = ?
|
||||
and plan_date = ?
|
@ -1 +1,22 @@
|
||||
select name, form, measure_type from filtered_ingredients where user_id = ?
|
||||
with latest_dates as (
|
||||
select
|
||||
user_id,
|
||||
name,
|
||||
form,
|
||||
measure_type,
|
||||
max(plan_date) as plan_date
|
||||
from filtered_ingredients
|
||||
where user_id = ?
|
||||
)
|
||||
|
||||
select
|
||||
filtered_ingredients.name,
|
||||
filtered_ingredients.form,
|
||||
filtered_ingredients.measure_type
|
||||
from latest_dates
|
||||
inner join filtered_ingredients on
|
||||
latest_dates.user_id = filtered_ingredients.user_id
|
||||
and latest_dates.name = filtered_ingredients.name
|
||||
and latest_dates.form = filtered_ingredients.form
|
||||
and latest_dates.measure_type = filtered_ingredients.measure_type
|
||||
and latest_dates.plan_date = filtered_ingredients.plan_date
|
@ -1 +1,24 @@
|
||||
select name, form, measure_type, amt from modified_amts where user_id = ?;
|
||||
with latest_dates as (
|
||||
select
|
||||
user_id,
|
||||
name,
|
||||
form,
|
||||
measure_type,
|
||||
amt,
|
||||
max(plan_date) as plan_date
|
||||
from modified_amts
|
||||
where user_id = ?
|
||||
)
|
||||
|
||||
select
|
||||
modified_amts.name,
|
||||
modified_amts.form,
|
||||
modified_amts.measure_type,
|
||||
modified_amts.amt
|
||||
from latest_dates
|
||||
inner join modified_amts on
|
||||
latest_dates.user_id = modified_amts.user_id
|
||||
and latest_dates.name = modified_amts.name
|
||||
and latest_dates.form = modified_amts.form
|
||||
and latest_dates.amt = modified_amts.amt
|
||||
and latest_dates.plan_date = modified_amts.plan_date
|
@ -121,16 +121,21 @@ pub trait APIStore {
|
||||
date: NaiveDate,
|
||||
) -> Result<()>;
|
||||
|
||||
async fn fetch_inventory_data<S: AsRef<str> + Send>(
|
||||
async fn fetch_latest_inventory_data<S: AsRef<str> + Send>(
|
||||
&self,
|
||||
user_id: S,
|
||||
) -> Result<(Vec<IngredientKey>, Vec<(IngredientKey, String)>)>;
|
||||
) -> Result<(
|
||||
Vec<IngredientKey>,
|
||||
Vec<(IngredientKey, String)>,
|
||||
Vec<(String, String)>,
|
||||
)>;
|
||||
|
||||
async fn save_inventory_data<S: AsRef<str> + Send>(
|
||||
&self,
|
||||
user_id: S,
|
||||
filtered_ingredients: BTreeSet<IngredientKey>,
|
||||
modified_amts: BTreeMap<IngredientKey, String>,
|
||||
extra_items: Vec<(String, String)>,
|
||||
) -> Result<()>;
|
||||
}
|
||||
|
||||
@ -504,10 +509,15 @@ impl APIStore for SqliteStore {
|
||||
Ok(Some(result))
|
||||
}
|
||||
|
||||
async fn fetch_inventory_data<S: AsRef<str> + Send>(
|
||||
// TODO(jwall): Do we need fetch for date variants of this.
|
||||
async fn fetch_latest_inventory_data<S: AsRef<str> + Send>(
|
||||
&self,
|
||||
user_id: S,
|
||||
) -> Result<(Vec<IngredientKey>, Vec<(IngredientKey, String)>)> {
|
||||
) -> Result<(
|
||||
Vec<IngredientKey>,
|
||||
Vec<(IngredientKey, String)>,
|
||||
Vec<(String, String)>,
|
||||
)> {
|
||||
let user_id = user_id.as_ref();
|
||||
struct FilteredIngredientRow {
|
||||
name: String,
|
||||
@ -561,7 +571,22 @@ impl APIStore for SqliteStore {
|
||||
row.amt,
|
||||
));
|
||||
}
|
||||
Ok((filtered_ingredients, modified_amts))
|
||||
pub struct ExtraItemRow {
|
||||
name: String,
|
||||
amt: String,
|
||||
}
|
||||
let extra_items_rows = sqlx::query_file_as!(
|
||||
ExtraItemRow,
|
||||
"src/web/storage/fetch_extra_items.sql",
|
||||
user_id,
|
||||
)
|
||||
.fetch_all(self.pool.as_ref())
|
||||
.await?;
|
||||
let mut extra_items = Vec::new();
|
||||
for row in extra_items_rows {
|
||||
extra_items.push((row.name, row.amt));
|
||||
}
|
||||
Ok((filtered_ingredients, modified_amts, extra_items))
|
||||
}
|
||||
|
||||
async fn save_inventory_data<S: AsRef<str> + Send>(
|
||||
@ -569,18 +594,11 @@ impl APIStore for SqliteStore {
|
||||
user_id: S,
|
||||
filtered_ingredients: BTreeSet<IngredientKey>,
|
||||
modified_amts: BTreeMap<IngredientKey, String>,
|
||||
extra_items: Vec<(String, String)>,
|
||||
) -> 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?;
|
||||
// store the filtered_ingredients
|
||||
for key in filtered_ingredients {
|
||||
let name = key.name();
|
||||
let form = key.form();
|
||||
@ -595,6 +613,7 @@ impl APIStore for SqliteStore {
|
||||
.execute(&mut transaction)
|
||||
.await?;
|
||||
}
|
||||
// store the modified amts
|
||||
for (key, amt) in modified_amts {
|
||||
let name = key.name();
|
||||
let form = key.form();
|
||||
@ -611,6 +630,12 @@ impl APIStore for SqliteStore {
|
||||
.execute(&mut transaction)
|
||||
.await?;
|
||||
}
|
||||
// Store the extra items
|
||||
for (name, amt) in extra_items {
|
||||
sqlx::query_file!("src/web/storage/store_extra_items.sql", user_id, name, amt)
|
||||
.execute(&mut transaction)
|
||||
.await?;
|
||||
}
|
||||
transaction.commit().await?;
|
||||
Ok(())
|
||||
}
|
||||
|
@ -1,2 +1,2 @@
|
||||
insert into filtered_ingredients(user_id, name, form, measure_type)
|
||||
values (?, ?, ?, ?) on conflict(user_id, name, form, measure_type) DO NOTHING
|
||||
insert into filtered_ingredients(user_id, name, form, measure_type, plan_date)
|
||||
values (?, ?, ?, ?, date()) on conflict(user_id, name, form, measure_type, plan_date) DO NOTHING
|
@ -1,2 +1,2 @@
|
||||
insert into modified_amts(user_id, name, form, measure_type, amt)
|
||||
values (?, ?, ?, ?, ?) on conflict (user_id, name, form, measure_type) do update set amt=excluded.amt
|
||||
insert into modified_amts(user_id, name, form, measure_type, amt, plan_date)
|
||||
values (?, ?, ?, ?, ?, date()) on conflict (user_id, name, form, measure_type, plan_date) do update set amt=excluded.amt
|
3
kitchen/src/web/storage/store_extra_items.sql
Normal file
3
kitchen/src/web/storage/store_extra_items.sql
Normal file
@ -0,0 +1,3 @@
|
||||
insert into extra_items (user_id, name, plan_date, amt)
|
||||
values (?, ?, date(), ?)
|
||||
on conflict (user_id, name, plan_date) do update set amt=excluded.amt
|
Loading…
x
Reference in New Issue
Block a user