Compare commits

...

7 Commits

Author SHA1 Message Date
eccbb7581b dev: Add indexeddb and a helper method for it 2024-07-11 18:29:48 -04:00
fe181fb102 cleanup: a bunch of warnings 2024-07-11 18:28:45 -04:00
61112c4e64 Merge branch 'sqlx-upgrade' 2024-07-11 18:13:39 -04:00
24fea84a0a maint: cleanup gitignore 2024-07-11 18:05:38 -04:00
113b03016f dev: Handle serving counts in the api 2024-07-11 18:04:48 -04:00
9833e22e42 upgrade: Schema version and sqlx version
It's complicated but I while debugging I upgraded sqlx. Shouldn't
have mixed up changes like that but I'm lazy and don't want to redo
it so it'll all have to just be here.
2024-07-11 18:04:41 -04:00
1f986e6372 fix: sqlx-prepare really only depends on wasm 2024-07-11 18:03:01 -04:00
58 changed files with 1553 additions and 240 deletions

5
.gitignore vendored
View File

@ -1,11 +1,10 @@
target/
.lsp/
.clj-kondo/
web/dist/
webdist/
nix/*/result
result
.vscode/
.session_store/
.gitignore/
.DS_Store/
.DS_Store/
.env

886
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -6,9 +6,6 @@ resolver = "2"
# TODO(jwall): When the fix for RcSignal Binding is released we can drop this patch.
sycamore = { git = "https://github.com/sycamore-rs/sycamore/", rev = "5d49777b4a66fb5730c40898fd2ee8cde15bcdc3" }
sycamore-router = { git = "https://github.com/sycamore-rs/sycamore/", rev = "5d49777b4a66fb5730c40898fd2ee8cde15bcdc3" }
# NOTE(jwall): We are maintaining a patch to remove the unstable async_std_feature. It breaks in our project on
# Rust v1.64
sqlx = { git = "https://github.com/zaphar/sqlx", branch = "remove_unstable_async_std_feature" }
[profile.release]
lto = true

View File

@ -55,5 +55,5 @@ sqlx-add-%:
sqlx-revert:
cd kitchen; cargo sqlx migrate revert --database-url $(sqlite_url)
sqlx-prepare: kitchen
sqlx-prepare: wasm
cd kitchen; cargo sqlx prepare --database-url $(sqlite_url)

View File

@ -51,7 +51,6 @@
# incorrect. We override those here.
"wasm-web-component-0.2.0" = "sha256-quuPgzGb2F96blHmD3BAUjsWQYbSyJGZl27PVrwL92k=";
"sycamore-0.8.2" = "sha256-D968+8C5EelGGmot9/LkAlULZOf/Cr+1WYXRCMwb1nQ=";
"sqlx-0.6.2" = "sha256-X/LFvtzRfiOIEZJiVzmFvvULPpjhqvI99pSwH7a//GM=";
};
};
kitchen = (kitchenGen {

View File

@ -0,0 +1,38 @@
{
"db_name": "SQLite",
"query": "select recipe_id, recipe_text, category, serving_count from recipes where user_id = ?",
"describe": {
"columns": [
{
"name": "recipe_id",
"ordinal": 0,
"type_info": "Text"
},
{
"name": "recipe_text",
"ordinal": 1,
"type_info": "Text"
},
{
"name": "category",
"ordinal": 2,
"type_info": "Text"
},
{
"name": "serving_count",
"ordinal": 3,
"type_info": "Int64"
}
],
"parameters": {
"Right": 1
},
"nullable": [
false,
true,
true,
true
]
},
"hash": "01018c919131848f8fa907a1356a1356b2aa6ca0912de8a296f5fef3486b5ff9"
}

View File

@ -0,0 +1,20 @@
{
"db_name": "SQLite",
"query": "select password_hashed from users where id = ?",
"describe": {
"columns": [
{
"name": "password_hashed",
"ordinal": 0,
"type_info": "Text"
}
],
"parameters": {
"Right": 1
},
"nullable": [
false
]
},
"hash": "104f07472670436d3eee1733578bbf0c92dc4f965d3d13f9bf4bfbc92958c5b6"
}

View File

@ -0,0 +1,26 @@
{
"db_name": "SQLite",
"query": "with latest_dates as (\n select user_id, max(date(plan_date)) as plan_date from plan_recipes\n where user_id = ?\n group by user_id\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.plan_date = extra_items.plan_date",
"describe": {
"columns": [
{
"name": "name",
"ordinal": 0,
"type_info": "Text"
},
{
"name": "amt",
"ordinal": 1,
"type_info": "Text"
}
],
"parameters": {
"Right": 1
},
"nullable": [
false,
false
]
},
"hash": "10de1e9950d7d3ae7f017b9175a1cee4ff7fcbc7403a39ea02930c75b4b9160a"
}

View File

@ -0,0 +1,12 @@
{
"db_name": "SQLite",
"query": "delete from modified_amts where user_id = ? and plan_date = ?",
"describe": {
"columns": [],
"parameters": {
"Right": 2
},
"nullable": []
},
"hash": "10e1c111a16d647a106a3147f4e61e34b0176860ca99cb62cb43dc72550ad990"
}

View File

@ -0,0 +1,12 @@
{
"db_name": "SQLite",
"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",
"describe": {
"columns": [],
"parameters": {
"Right": 4
},
"nullable": []
},
"hash": "160a9dfccf2e91a37d81f75eba21ec73105a7453c4f1fe76a430d04e525bc6cd"
}

View File

@ -0,0 +1,32 @@
{
"db_name": "SQLite",
"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",
"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"
}
],
"parameters": {
"Right": 2
},
"nullable": [
false,
false,
false
]
},
"hash": "19832e3582c05ed49c676fde33cde64274379a83a8dd130f6eec96c1d7250909"
}

View File

@ -0,0 +1,12 @@
{
"db_name": "SQLite",
"query": "insert into staples (user_id, content) values (?, ?)\n on conflict(user_id) do update set content = excluded.content",
"describe": {
"columns": [],
"parameters": {
"Right": 2
},
"nullable": []
},
"hash": "1b4a7250e451991ee7e642c6389656814e0dd00c94e59383c02af6313bc76213"
}

View File

@ -0,0 +1,12 @@
{
"db_name": "SQLite",
"query": "insert into modified_amts(user_id, name, form, measure_type, amt, plan_date)\n values (?, ?, ?, ?, ?, ?) on conflict (user_id, name, form, measure_type, plan_date) do update set amt=excluded.amt",
"describe": {
"columns": [],
"parameters": {
"Right": 6
},
"nullable": []
},
"hash": "1b6fd91460bef61cf02f210404a4ca57b520c969d1f9613e7101ee6aa7a9962a"
}

View File

@ -0,0 +1,12 @@
{
"db_name": "SQLite",
"query": "delete from filtered_ingredients where user_id = ? and plan_date = ?",
"describe": {
"columns": [],
"parameters": {
"Right": 2
},
"nullable": []
},
"hash": "23beb05e40cf011170182d4e98cdf1faa3d8df6e5956e471245e666f32e56962"
}

View File

@ -0,0 +1,12 @@
{
"db_name": "SQLite",
"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",
"describe": {
"columns": [],
"parameters": {
"Right": 3
},
"nullable": []
},
"hash": "2582522f8ca9f12eccc70a3b339d9030aee0f52e62d6674cfd3862de2a68a177"
}

View File

@ -0,0 +1,12 @@
{
"db_name": "SQLite",
"query": "delete from plan_table where user_id = ? and plan_date = ?",
"describe": {
"columns": [],
"parameters": {
"Right": 2
},
"nullable": []
},
"hash": "27aa0a21f534cdf580841fa111136fc26cf1a0ca4ddb308c12f3f8f5a62d6178"
}

View File

@ -0,0 +1,12 @@
{
"db_name": "SQLite",
"query": "insert into plan_table (user_id, plan_date) values (?, ?)\n on conflict (user_id, plan_date) do nothing;",
"describe": {
"columns": [],
"parameters": {
"Right": 2
},
"nullable": []
},
"hash": "288535e7b9e1f02ad1b677e3dddc85f38c0766ce16d26fc1bdd2bf90ab9a7f7c"
}

View File

@ -0,0 +1,32 @@
{
"db_name": "SQLite",
"query": "select plan_date as \"plan_date: NaiveDate\", recipe_id, count\n from plan_recipes\nwhere\n user_id = ?\n and plan_date = ?",
"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"
}
],
"parameters": {
"Right": 2
},
"nullable": [
false,
false,
false
]
},
"hash": "2e076acd2405d234daaa866e5a2ac1e10989fc8d2820f90aa722464a7b17db6b"
}

View File

@ -0,0 +1,26 @@
{
"db_name": "SQLite",
"query": "select ingredient_name, category_name from category_mappings where user_id = ?",
"describe": {
"columns": [
{
"name": "ingredient_name",
"ordinal": 0,
"type_info": "Text"
},
{
"name": "category_name",
"ordinal": 1,
"type_info": "Text"
}
],
"parameters": {
"Right": 1
},
"nullable": [
false,
false
]
},
"hash": "37f382be1b53efd2f79a0d59ae6a8717f88a86908a7a4128d5ed7339147ca59d"
}

View File

@ -0,0 +1,12 @@
{
"db_name": "SQLite",
"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",
"describe": {
"columns": [],
"parameters": {
"Right": 3
},
"nullable": []
},
"hash": "3caefb86073c47b5dd5d05f639ddef2f7ed2d1fd80f224457d1ec34243cc56c7"
}

View File

@ -0,0 +1,38 @@
{
"db_name": "SQLite",
"query": "with latest_dates as (\n select user_id, max(date(plan_date)) as plan_date from plan_recipes\n where user_id = ?\n group by 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.plan_date = modified_amts.plan_date",
"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"
}
],
"parameters": {
"Right": 1
},
"nullable": [
false,
false,
false,
false
]
},
"hash": "3e43f06f5c2e959f66587c8d74696d6db27d89fd2f7d7e1ed6fa5016b4bd1a91"
}

View File

@ -0,0 +1,26 @@
{
"db_name": "SQLite",
"query": "select\n name,\n amt\nfrom extra_items\nwhere\n user_id = ?\n and plan_date = ?",
"describe": {
"columns": [
{
"name": "name",
"ordinal": 0,
"type_info": "Text"
},
{
"name": "amt",
"ordinal": 1,
"type_info": "Text"
}
],
"parameters": {
"Right": 2
},
"nullable": [
false,
false
]
},
"hash": "4237ff804f254c122a36a14135b90434c6576f48d3a83245503d702552ea9f30"
}

View File

@ -0,0 +1,12 @@
{
"db_name": "SQLite",
"query": "insert into filtered_ingredients(user_id, name, form, measure_type, plan_date)\n values (?, ?, ?, ?, ?) on conflict(user_id, name, form, measure_type, plan_date) DO NOTHING",
"describe": {
"columns": [],
"parameters": {
"Right": 5
},
"nullable": []
},
"hash": "5883c4a57def93cca45f8f9d81c8bba849547758217cd250e7ab28cc166ab42b"
}

View File

@ -0,0 +1,12 @@
{
"db_name": "SQLite",
"query": "insert into users (id, password_hashed) values (?, ?)",
"describe": {
"columns": [],
"parameters": {
"Right": 2
},
"nullable": []
},
"hash": "5d743897fb0d8fd54c3708f1b1c6e416346201faa9e28823c1ba5a421472b1fa"
}

View File

@ -0,0 +1,20 @@
{
"db_name": "SQLite",
"query": "select content from staples where user_id = ?",
"describe": {
"columns": [
{
"name": "content",
"ordinal": 0,
"type_info": "Text"
}
],
"parameters": {
"Right": 1
},
"nullable": [
false
]
},
"hash": "64af3f713eb4c61ac02cab2dfea83d0ed197e602e99079d4d32cb38d677edf2e"
}

View File

@ -0,0 +1,38 @@
{
"db_name": "SQLite",
"query": "select\n modified_amts.name,\n modified_amts.form,\n modified_amts.measure_type,\n modified_amts.amt\nfrom modified_amts\nwhere\n user_id = ?\n and plan_date = ?",
"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"
}
],
"parameters": {
"Right": 2
},
"nullable": [
false,
false,
false,
false
]
},
"hash": "699ff0f0d4d4c6e26a21c1922a5b5249d89ed1677680a2276899a7f8b26344ee"
}

View File

@ -0,0 +1,12 @@
{
"db_name": "SQLite",
"query": "delete from recipes where user_id = ? and recipe_id = ?",
"describe": {
"columns": [],
"parameters": {
"Right": 2
},
"nullable": []
},
"hash": "6c43908d90f229b32ed8b1b076be9b452a995e1b42ba2554e947c515b031831a"
}

View File

@ -0,0 +1,12 @@
{
"db_name": "SQLite",
"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",
"describe": {
"columns": [],
"parameters": {
"Right": 5
},
"nullable": []
},
"hash": "6e28698330e42fd6c87ba1e6f1deb664c0d3995caa2b937ceac8c908e98aded6"
}

View File

@ -0,0 +1,12 @@
{
"db_name": "SQLite",
"query": "delete from extra_items where user_id = ? and plan_date = ?",
"describe": {
"columns": [],
"parameters": {
"Right": 2
},
"nullable": []
},
"hash": "6f11d90875a6230766a5f9bd1d67665dc4d00c13d7e81b0d18d60baa67987da9"
}

View File

@ -0,0 +1,12 @@
{
"db_name": "SQLite",
"query": "delete from sessions where id = ?",
"describe": {
"columns": [],
"parameters": {
"Right": 1
},
"nullable": []
},
"hash": "7578157607967a6a4c60f12408c5d9900d15b429a49681a4cae4e02d31c524ec"
}

View File

@ -0,0 +1,32 @@
{
"db_name": "SQLite",
"query": "select\n filtered_ingredients.name,\n filtered_ingredients.form,\n filtered_ingredients.measure_type\nfrom filtered_ingredients\nwhere\n user_id = ?\n and plan_date = ?",
"describe": {
"columns": [
{
"name": "name",
"ordinal": 0,
"type_info": "Text"
},
{
"name": "form",
"ordinal": 1,
"type_info": "Text"
},
{
"name": "measure_type",
"ordinal": 2,
"type_info": "Text"
}
],
"parameters": {
"Right": 2
},
"nullable": [
false,
false,
false
]
},
"hash": "7695a0602395006f9b76ecd4d0cb5ecd5dee419b71b3b0b9ea4f47a83f3df41a"
}

View File

@ -0,0 +1,12 @@
{
"db_name": "SQLite",
"query": "insert into plan_recipes (user_id, plan_date, recipe_id, count) values (?, ?, ?, ?)\n on conflict (user_id, plan_date, recipe_id) do update set count=excluded.count;",
"describe": {
"columns": [],
"parameters": {
"Right": 4
},
"nullable": []
},
"hash": "83824ea638cb64c524f5c8984ef6ef28dfe781f0abf168abc4ae9a51e6e0ae88"
}

View File

@ -0,0 +1,12 @@
{
"db_name": "SQLite",
"query": "insert into categories (user_id, category_text) values (?, ?)\n on conflict(user_id) do update set category_text=excluded.category_text",
"describe": {
"columns": [],
"parameters": {
"Right": 2
},
"nullable": []
},
"hash": "8490e1bb40879caed62ac1c38cb9af48246f3451b6f7f1e1f33850f1dbe25f58"
}

View File

@ -0,0 +1,20 @@
{
"db_name": "SQLite",
"query": "select session_value from sessions where id = ?",
"describe": {
"columns": [
{
"name": "session_value",
"ordinal": 0,
"type_info": "Blob"
}
],
"parameters": {
"Right": 1
},
"nullable": [
false
]
},
"hash": "928a479ca0f765ec7715bf8784c5490e214486edbf5b78fd501823feb328375b"
}

View File

@ -0,0 +1,12 @@
{
"db_name": "SQLite",
"query": "delete from plan_recipes where user_id = ? and plan_date = ?",
"describe": {
"columns": [],
"parameters": {
"Right": 2
},
"nullable": []
},
"hash": "93af0c367a0913d49c92aa69022fa30fc0564bd4dbab7f3ae78673a01439cd6e"
}

View File

@ -0,0 +1,12 @@
{
"db_name": "SQLite",
"query": "insert into sessions (id, session_value) values (?, ?)",
"describe": {
"columns": [],
"parameters": {
"Right": 2
},
"nullable": []
},
"hash": "9ad4acd9b9d32c9f9f441276aa71a17674fe4d65698848044778bd4aef77d42d"
}

View File

@ -0,0 +1,32 @@
{
"db_name": "SQLite",
"query": "with max_date as (\n select user_id, max(date(plan_date)) as plan_date from plan_recipes group by user_id\n)\n\nselect plan_recipes.plan_date as \"plan_date: NaiveDate\", plan_recipes.recipe_id, plan_recipes.count\n from plan_recipes\n inner join max_date on plan_recipes.user_id = max_date.user_id\nwhere\n plan_recipes.user_id = ?\n and plan_recipes.plan_date = max_date.plan_date",
"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"
}
],
"parameters": {
"Right": 1
},
"nullable": [
false,
false,
false
]
},
"hash": "ad3408cd773dd8f9308255ec2800171638a1aeda9817c57fb8360f97115f8e97"
}

View File

@ -0,0 +1,12 @@
{
"db_name": "SQLite",
"query": "insert into extra_items (user_id, name, amt, plan_date)\nvalues (?, ?, ?, ?)\non conflict (user_id, name, plan_date) do update set amt=excluded.amt",
"describe": {
"columns": [],
"parameters": {
"Right": 4
},
"nullable": []
},
"hash": "ba07658eb11f9d6cfdb5dbee4496b2573f1e51f4b4d9ae760eca3b977649b5c7"
}

View File

@ -0,0 +1,20 @@
{
"db_name": "SQLite",
"query": "select category_text from categories where user_id = ?",
"describe": {
"columns": [
{
"name": "category_text",
"ordinal": 0,
"type_info": "Text"
}
],
"parameters": {
"Right": 1
},
"nullable": [
true
]
},
"hash": "c988364f9f83f4fa8bd0e594bab432ee7c9ec47ca40f4d16e5e2a8763653f377"
}

View File

@ -0,0 +1,12 @@
{
"db_name": "SQLite",
"query": "delete from sessions",
"describe": {
"columns": [],
"parameters": {
"Right": 0
},
"nullable": []
},
"hash": "d84685a82585c5e4ae72c86ba1fe6e4a7241c4c3c9e948213e5849d956132bad"
}

View File

@ -0,0 +1,32 @@
{
"db_name": "SQLite",
"query": "with latest_dates as (\n select user_id, max(date(plan_date)) as plan_date from plan_recipes\n where user_id = ?\n group by 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.plan_date = filtered_ingredients.plan_date",
"describe": {
"columns": [
{
"name": "name",
"ordinal": 0,
"type_info": "Text"
},
{
"name": "form",
"ordinal": 1,
"type_info": "Text"
},
{
"name": "measure_type",
"ordinal": 2,
"type_info": "Text"
}
],
"parameters": {
"Right": 1
},
"nullable": [
false,
false,
false
]
},
"hash": "e38183e2e16afa308672044e5d314296d7cd84c1ffedcbfe790743547dc62de8"
}

View File

@ -0,0 +1,12 @@
{
"db_name": "SQLite",
"query": "insert into recipes (user_id, recipe_id, recipe_text, category, serving_count) values (?, ?, ?, ?, ?)\n on conflict(user_id, recipe_id) do update set recipe_text=excluded.recipe_text, category=excluded.category",
"describe": {
"columns": [],
"parameters": {
"Right": 5
},
"nullable": []
},
"hash": "eb99a37e18009e0dd46caccacea57ba0b25510d80a4e4a282a5ac2be50bba81c"
}

View File

@ -0,0 +1,38 @@
{
"db_name": "SQLite",
"query": "select recipe_id, recipe_text, category, serving_count from recipes where user_id = ? and recipe_id = ?",
"describe": {
"columns": [
{
"name": "recipe_id",
"ordinal": 0,
"type_info": "Text"
},
{
"name": "recipe_text",
"ordinal": 1,
"type_info": "Text"
},
{
"name": "category",
"ordinal": 2,
"type_info": "Text"
},
{
"name": "serving_count",
"ordinal": 3,
"type_info": "Int64"
}
],
"parameters": {
"Right": 2
},
"nullable": [
false,
true,
true,
true
]
},
"hash": "ee0491c7d1a31ef80d7abe6ea4c9a8b0618dba58a0a8bceef7bdafec98ccd543"
}

View File

@ -0,0 +1,20 @@
{
"db_name": "SQLite",
"query": "select distinct plan_date as \"plan_date: NaiveDate\" from plan_table\nwhere user_id = ?",
"describe": {
"columns": [
{
"name": "plan_date: NaiveDate",
"ordinal": 0,
"type_info": "Text"
}
],
"parameters": {
"Right": 1
},
"nullable": [
false
]
},
"hash": "fd818a6b1c800c2014b5cfe8a923ac9228832b11d7575585cf7930fbf91306d1"
}

View File

@ -62,5 +62,5 @@ version = "1.12.0"
features = ["tokio1"]
[dependencies.sqlx]
version = "0.6.2"
features = ["sqlite", "runtime-async-std-rustls", "offline", "chrono"]
version = "0.7"
features = ["sqlite", "runtime-async-std", "tls-rustls", "chrono"]

View File

@ -1,2 +1,2 @@
-- Add up migration script here
ALTER TABLE recipes ADD column serving_count number;
ALTER TABLE recipes ADD COLUMN serving_count INT;

View File

@ -22,6 +22,7 @@ use tracing::{debug, instrument};
use super::RecipeEntry;
#[allow(dead_code)]
#[derive(Debug)]
pub struct Error(String);
@ -98,7 +99,7 @@ impl AsyncFileStore {
let file_name = entry.file_name().to_string_lossy().to_string();
debug!("adding recipe file {}", file_name);
let recipe_contents = read_to_string(entry.path()).await?;
entry_vec.push(RecipeEntry(file_name, recipe_contents, None));
entry_vec.push(RecipeEntry(file_name, recipe_contents, None, None));
} else {
warn!(
file = %entry.path().to_string_lossy(),
@ -122,6 +123,7 @@ impl AsyncFileStore {
id.as_ref().to_owned(),
recipe_contents,
None,
None,
)));
} else {
return Ok(None);

View File

@ -429,20 +429,10 @@ impl APIStore for SqliteStore {
user_id: S,
id: S,
) -> Result<Option<RecipeEntry>> {
// NOTE(jwall): We allow dead code becaue Rust can't figure out that
// this code is actually constructed but it's done via the query_as
// macro.
#[allow(dead_code)]
struct RecipeRow {
pub recipe_id: String,
pub recipe_text: Option<String>,
pub category: Option<String>,
}
let id = id.as_ref();
let user_id = user_id.as_ref();
let entry = sqlx::query_as!(
RecipeRow,
"select recipe_id, recipe_text, category from recipes where user_id = ? and recipe_id = ?",
let entry = sqlx::query!(
"select recipe_id, recipe_text, category, serving_count from recipes where user_id = ? and recipe_id = ?",
user_id,
id,
)
@ -453,7 +443,8 @@ impl APIStore for SqliteStore {
RecipeEntry(
row.recipe_id.clone(),
row.recipe_text.clone().unwrap_or_else(|| String::new()),
row.category.clone()
row.category.clone(),
row.serving_count.clone(),
)
})
.nth(0);
@ -461,18 +452,8 @@ impl APIStore for SqliteStore {
}
async fn get_recipes_for_user(&self, user_id: &str) -> Result<Option<Vec<RecipeEntry>>> {
// NOTE(jwall): We allow dead code becaue Rust can't figure out that
// this code is actually constructed but it's done via the query_as
// macro.
#[allow(dead_code)]
struct RecipeRow {
pub recipe_id: String,
pub recipe_text: Option<String>,
pub category: Option<String>,
}
let rows = sqlx::query_as!(
RecipeRow,
"select recipe_id, recipe_text, category from recipes where user_id = ?",
let rows = sqlx::query!(
"select recipe_id, recipe_text, category, serving_count from recipes where user_id = ?",
user_id,
)
.fetch_all(self.pool.as_ref())
@ -483,6 +464,7 @@ impl APIStore for SqliteStore {
row.recipe_id.clone(),
row.recipe_text.clone().unwrap_or_else(|| String::new()),
row.category.clone(),
row.serving_count.clone(),
)
})
.collect();
@ -498,13 +480,15 @@ impl APIStore for SqliteStore {
let recipe_id = entry.recipe_id().to_owned();
let recipe_text = entry.recipe_text().to_owned();
let category = entry.category();
let serving_count = entry.serving_count();
sqlx::query!(
"insert into recipes (user_id, recipe_id, recipe_text, category) values (?, ?, ?, ?)
"insert into recipes (user_id, recipe_id, recipe_text, category, serving_count) values (?, ?, ?, ?, ?)
on conflict(user_id, recipe_id) do update set recipe_text=excluded.recipe_text, category=excluded.category",
user_id,
recipe_id,
recipe_text,
category,
serving_count,
)
.execute(self.pool.as_ref())
.await?;
@ -520,7 +504,7 @@ impl APIStore for SqliteStore {
user_id,
recipe_id,
)
.execute(&mut transaction)
.execute(&mut *transaction)
.await?;
}
transaction.commit().await?;
@ -552,10 +536,10 @@ impl APIStore for SqliteStore {
user_id,
date,
)
.execute(&mut transaction)
.execute(&mut *transaction)
.await?;
sqlx::query_file!("src/web/storage/init_meal_plan.sql", user_id, date)
.execute(&mut transaction)
.execute(&mut *transaction)
.await?;
for (id, count) in recipe_counts {
sqlx::query_file!(
@ -565,7 +549,7 @@ impl APIStore for SqliteStore {
id,
count
)
.execute(&mut transaction)
.execute(&mut *transaction)
.await?;
}
transaction.commit().await?;
@ -645,35 +629,35 @@ impl APIStore for SqliteStore {
user_id,
date
)
.execute(&mut transaction)
.execute(&mut *transaction)
.await?;
sqlx::query!(
"delete from plan_recipes where user_id = ? and plan_date = ?",
user_id,
date
)
.execute(&mut transaction)
.execute(&mut *transaction)
.await?;
sqlx::query!(
"delete from filtered_ingredients where user_id = ? and plan_date = ?",
user_id,
date
)
.execute(&mut transaction)
.execute(&mut *transaction)
.await?;
sqlx::query!(
"delete from modified_amts where user_id = ? and plan_date = ?",
user_id,
date
)
.execute(&mut transaction)
.execute(&mut *transaction)
.await?;
sqlx::query!(
"delete from extra_items where user_id = ? and plan_date = ?",
user_id,
date
)
.execute(&mut transaction)
.execute(&mut *transaction)
.await?;
transaction.commit().await?;
Ok(())
@ -921,7 +905,7 @@ impl APIStore for SqliteStore {
user_id,
date
)
.execute(&mut transaction)
.execute(&mut *transaction)
.await?;
for key in filtered_ingredients {
let name = key.name();
@ -935,7 +919,7 @@ impl APIStore for SqliteStore {
measure_type,
date,
)
.execute(&mut transaction)
.execute(&mut *transaction)
.await?;
}
sqlx::query!(
@ -943,7 +927,7 @@ impl APIStore for SqliteStore {
user_id,
date
)
.execute(&mut transaction)
.execute(&mut *transaction)
.await?;
// store the modified amts
for (key, amt) in modified_amts {
@ -960,7 +944,7 @@ impl APIStore for SqliteStore {
amt,
date,
)
.execute(&mut transaction)
.execute(&mut *transaction)
.await?;
}
sqlx::query!(
@ -968,7 +952,7 @@ impl APIStore for SqliteStore {
user_id,
date
)
.execute(&mut transaction)
.execute(&mut *transaction)
.await?;
// Store the extra items
for (name, amt) in extra_items {
@ -979,7 +963,7 @@ impl APIStore for SqliteStore {
amt,
date
)
.execute(&mut transaction)
.execute(&mut *transaction)
.await?;
}
transaction.commit().await?;
@ -1007,7 +991,7 @@ impl APIStore for SqliteStore {
form,
measure_type,
)
.execute(&mut transaction)
.execute(&mut *transaction)
.await?;
}
// store the modified amts
@ -1024,13 +1008,13 @@ impl APIStore for SqliteStore {
measure_type,
amt,
)
.execute(&mut transaction)
.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)
.execute(&mut *transaction)
.await?;
}
transaction.commit().await?;

View File

@ -50,11 +50,11 @@ impl Mealplan {
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct RecipeEntry(pub String, pub String, pub Option<String>);
pub struct RecipeEntry(pub String, pub String, pub Option<String>, pub Option<i64>);
impl RecipeEntry {
pub fn new<IS: Into<String>, TS: Into<String>>(recipe_id: IS, text: TS) -> Self {
Self(recipe_id.into(), text.into(), None)
Self(recipe_id.into(), text.into(), None, None)
}
pub fn set_recipe_id<S: Into<String>>(&mut self, id: S) {
@ -80,6 +80,10 @@ impl RecipeEntry {
pub fn category(&self) -> Option<&String> {
self.2.as_ref()
}
pub fn serving_count(&self) -> Option<i64> {
self.3.clone()
}
}
/// A Recipe with a title, description, and a series of steps.

View File

@ -27,6 +27,8 @@ sycamore-router = "0.8"
js-sys = "0.3.60"
wasm-web-component = { git = "https://github.com/zaphar/wasm-web-components.git", rev = "v0.3.0" }
maud = "*"
indexed-db = "0.4.1"
anyhow = "1.0.86"
[dependencies.serde]
version = "<=1.0.171"

View File

@ -30,6 +30,7 @@ use crate::{
js_lib,
};
#[allow(dead_code)]
#[derive(Debug)]
pub struct Error(String);

View File

@ -53,6 +53,7 @@ pub fn AddRecipe<'ctx, G: Html>(cx: Scope<'ctx>, sh: StateHandler<'ctx>) -> View
.replace("TITLE_PLACEHOLDER", recipe_title.get().as_str())
.replace("\r", ""),
category,
None,
)
});

View File

@ -25,16 +25,6 @@ pub mod shopping_list;
pub mod staples;
pub mod tabs;
pub use add_recipe::*;
pub use categories::*;
pub use footer::*;
pub use header::*;
pub use number_field::*;
pub use plan_list::*;
pub use recipe::*;
pub use recipe_list::*;
pub use recipe_plan::*;
pub use recipe_selection::*;
pub use shopping_list::*;
pub use staples::*;
pub use tabs::*;

View File

@ -16,9 +16,7 @@ use sycamore::prelude::*;
use tracing::{debug, error};
use wasm_bindgen::{JsCast, JsValue};
use wasm_web_component::{web_component, WebComponentBinding};
use web_sys::{window, CustomEvent, CustomEventInit, Event, HtmlElement, InputEvent, ShadowRoot};
use crate::js_lib::LogFailures;
use web_sys::{CustomEvent, CustomEventInit, Event, HtmlElement, InputEvent, ShadowRoot};
#[web_component(
observed_attrs = "['val', 'min', 'max', 'step']",
@ -135,10 +133,10 @@ impl WebComponentBinding for NumberSpinner {
return;
}
};
let mut eventDict = CustomEventInit::new();
eventDict.detail(&JsValue::from_f64(self.value as f64));
let mut event_dict = CustomEventInit::new();
event_dict.detail(&JsValue::from_f64(self.value as f64));
element
.dispatch_event(&CustomEvent::new_with_event_init_dict("updated", &eventDict).unwrap())
.dispatch_event(&CustomEvent::new_with_event_init_dict("updated", &event_dict).unwrap())
.unwrap();
debug!("Dispatched updated event");
}

View File

@ -119,6 +119,7 @@ pub fn Editor<'ctx, G: Html>(cx: Scope<'ctx>, props: RecipeComponentProps<'ctx>)
id.get_untracked().as_ref().clone(),
text.get_untracked().as_ref().clone(),
category,
None,
);
sh.dispatch(cx, Message::SaveRecipe(recipe_entry, None));
dirty.set(false);

View File

@ -14,6 +14,25 @@
use js_sys::Date;
use tracing::error;
use web_sys::{window, Storage, Window};
use indexed_db::{self, Factory, Database};
use anyhow::{Result, Context};
pub async fn get_indexed_db(name: &str, version: Option<u32>) -> Result<Database<std::io::Error>> {
let version = version.unwrap_or(0);
let factory = Factory::<std::io::Error>::get().context("opening IndexedDB")?;
let db = factory.open(name, version, |evt| async move {
// NOTE(zaphar): This is the on upgradeneeded handler. It get's called on new databases or
// database with an older version than the one we requested to build.
let db = evt.database();
// NOTE(jwall): This needs to be somewhat clever in handling version upgrades.
if db.version() == 0 {
// We use out of line keys for this object store
db.build_object_store("store").create()?;
}
Ok(())
}).await.context(format!("Openong or creating the database {}", name))?;
Ok(db)
}
pub fn get_storage() -> Storage {
get_window()

View File

@ -38,7 +38,7 @@ pub fn SelectPage<'ctx, G: Html>(cx: Scope<'ctx>, sh: StateHandler<'ctx>) -> Vie
view! {cx,
PlanningPage(
selected=Some("Select".to_owned()),
plan_date = current_plan.clone(),
plan_date = current_plan,
) {
PlanList(sh=sh, list=plan_dates)
button(on:click=move |_| {

View File

@ -12,11 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
use crate::{
app_state::StateHandler,
components::{Footer, Header},
pages::*,
};
use crate::{app_state::StateHandler, components::Header, pages::*};
use sycamore::prelude::*;
use sycamore_router::{HistoryIntegration, Route, Router};
use tracing::{debug, instrument};