Compare commits
No commits in common. "713dff67cef5d35eab8c947745269fb8a7103612" and "a182e4e0cb4e8e488b0904769e1626bd3b94e5a5" have entirely different histories.
713dff67ce
...
a182e4e0cb
23 changed files with 202 additions and 2410 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -1,5 +1,4 @@
|
||||||
result
|
result
|
||||||
result-bin
|
|
||||||
.direnv
|
.direnv
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
117
Cargo.lock
generated
117
Cargo.lock
generated
|
|
@ -4,9 +4,9 @@ version = 4
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "aho-corasick"
|
name = "aho-corasick"
|
||||||
version = "1.1.4"
|
version = "1.1.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301"
|
checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
|
|
@ -20,12 +20,6 @@ dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "anyhow"
|
|
||||||
version = "1.0.100"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "askama"
|
name = "askama"
|
||||||
version = "0.14.0"
|
version = "0.14.0"
|
||||||
|
|
@ -143,9 +137,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bitflags"
|
name = "bitflags"
|
||||||
version = "2.10.0"
|
version = "2.9.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3"
|
checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bumpalo"
|
name = "bumpalo"
|
||||||
|
|
@ -161,9 +155,9 @@ checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cc"
|
name = "cc"
|
||||||
version = "1.2.44"
|
version = "1.2.41"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "37521ac7aabe3d13122dc382493e20c9416f299d2ccd5b3a5340a2570cdeb0f3"
|
checksum = "ac9fe6cdbb24b6ade63616c0a0688e45bb56732262c158df3c0c4bea4ca47cb7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"find-msvc-tools",
|
"find-msvc-tools",
|
||||||
"shlex",
|
"shlex",
|
||||||
|
|
@ -224,23 +218,6 @@ version = "0.1.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
|
checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "food-tracker"
|
|
||||||
version = "0.1.0"
|
|
||||||
dependencies = [
|
|
||||||
"anyhow",
|
|
||||||
"askama",
|
|
||||||
"axum",
|
|
||||||
"chrono",
|
|
||||||
"parking_lot",
|
|
||||||
"rusqlite",
|
|
||||||
"tokio",
|
|
||||||
"tower-http",
|
|
||||||
"tower-request-id",
|
|
||||||
"tracing",
|
|
||||||
"tracing-subscriber",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "form_urlencoded"
|
name = "form_urlencoded"
|
||||||
version = "1.2.2"
|
version = "1.2.2"
|
||||||
|
|
@ -428,9 +405,9 @@ checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "js-sys"
|
name = "js-sys"
|
||||||
version = "0.3.82"
|
version = "0.3.81"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b011eec8cc36da2aab2d5cff675ec18454fad408585853910a202391cf9f8e65"
|
checksum = "ec48937a97411dcb524a265206ccd4c90bb711fca92b2792c407f268825b9305"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
|
|
@ -594,9 +571,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.103"
|
version = "1.0.101"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8"
|
checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
@ -816,9 +793,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "2.0.108"
|
version = "2.0.107"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "da58917d35242480a05c2897064da0a80589a2a0476c9a3f2fdc83b53502e917"
|
checksum = "2a26dbd934e5451d21ef060c018dae56fc073894c5a7896f882928a76e6d081b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
|
@ -831,6 +808,22 @@ version = "1.0.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263"
|
checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "task_counter"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"askama",
|
||||||
|
"axum",
|
||||||
|
"chrono",
|
||||||
|
"parking_lot",
|
||||||
|
"rusqlite",
|
||||||
|
"tokio",
|
||||||
|
"tower-http",
|
||||||
|
"tower-request-id",
|
||||||
|
"tracing",
|
||||||
|
"tracing-subscriber",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thread_local"
|
name = "thread_local"
|
||||||
version = "1.1.9"
|
version = "1.1.9"
|
||||||
|
|
@ -998,9 +991,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-ident"
|
name = "unicode-ident"
|
||||||
version = "1.0.22"
|
version = "1.0.19"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5"
|
checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "valuable"
|
name = "valuable"
|
||||||
|
|
@ -1031,9 +1024,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen"
|
name = "wasm-bindgen"
|
||||||
version = "0.2.105"
|
version = "0.2.104"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "da95793dfc411fbbd93f5be7715b0578ec61fe87cb1a42b12eb625caa5c5ea60"
|
checksum = "c1da10c01ae9f1ae40cbfac0bac3b1e724b320abfcf52229f80b547c0d250e2d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
|
|
@ -1043,22 +1036,13 @@ dependencies = [
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-macro"
|
name = "wasm-bindgen-backend"
|
||||||
version = "0.2.105"
|
version = "0.2.104"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "04264334509e04a7bf8690f2384ef5265f05143a4bff3889ab7a3269adab59c2"
|
checksum = "671c9a5a66f49d8a47345ab942e2cb93c7d1d0339065d4f8139c486121b43b19"
|
||||||
dependencies = [
|
|
||||||
"quote",
|
|
||||||
"wasm-bindgen-macro-support",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "wasm-bindgen-macro-support"
|
|
||||||
version = "0.2.105"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "420bc339d9f322e562942d52e115d57e950d12d88983a14c79b86859ee6c7ebc"
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bumpalo",
|
"bumpalo",
|
||||||
|
"log",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn",
|
||||||
|
|
@ -1066,10 +1050,33 @@ dependencies = [
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-shared"
|
name = "wasm-bindgen-macro"
|
||||||
version = "0.2.105"
|
version = "0.2.104"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "76f218a38c84bcb33c25ec7059b07847d465ce0e0a76b995e134a45adcb6af76"
|
checksum = "7ca60477e4c59f5f2986c50191cd972e3a50d8a95603bc9434501cf156a9a119"
|
||||||
|
dependencies = [
|
||||||
|
"quote",
|
||||||
|
"wasm-bindgen-macro-support",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasm-bindgen-macro-support"
|
||||||
|
version = "0.2.104"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9f07d2f20d4da7b26400c9f4a0511e6e0345b040694e8a75bd41d578fa4421d7"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
"wasm-bindgen-backend",
|
||||||
|
"wasm-bindgen-shared",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasm-bindgen-shared"
|
||||||
|
version = "0.2.104"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bad67dc8b2a1a6e5448428adec4c3e84c43e561d8c9ee8a9e5aabeb193ec41d1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,9 @@
|
||||||
[package]
|
[package]
|
||||||
name = "food-tracker"
|
name = "task_counter"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0.100"
|
|
||||||
askama = "0.14.0"
|
askama = "0.14.0"
|
||||||
axum = "0.8.6"
|
axum = "0.8.6"
|
||||||
chrono = "0.4.42"
|
chrono = "0.4.42"
|
||||||
|
|
|
||||||
130
flake.lock
generated
130
flake.lock
generated
|
|
@ -1,80 +1,6 @@
|
||||||
{
|
{
|
||||||
"nodes": {
|
"nodes": {
|
||||||
"cargo2nix": {
|
|
||||||
"inputs": {
|
|
||||||
"flake-compat": "flake-compat",
|
|
||||||
"flake-utils": "flake-utils",
|
|
||||||
"nixpkgs": "nixpkgs",
|
|
||||||
"rust-overlay": [
|
|
||||||
"rust-overlay"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1750364353,
|
|
||||||
"narHash": "sha256-l06DIwnB4JHwP1isUUXk85F+AHQkUSUyAWnAmRxXICg=",
|
|
||||||
"owner": "cargo2nix",
|
|
||||||
"repo": "cargo2nix",
|
|
||||||
"rev": "a709c74619e1a2b68ed12bb398e12fbe29d69657",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "cargo2nix",
|
|
||||||
"ref": "release-0.12",
|
|
||||||
"repo": "cargo2nix",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"flake-compat": {
|
|
||||||
"flake": false,
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1696426674,
|
|
||||||
"narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=",
|
|
||||||
"owner": "edolstra",
|
|
||||||
"repo": "flake-compat",
|
|
||||||
"rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "edolstra",
|
|
||||||
"repo": "flake-compat",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"flake-utils": {
|
|
||||||
"inputs": {
|
|
||||||
"systems": "systems"
|
|
||||||
},
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1694529238,
|
|
||||||
"narHash": "sha256-zsNZZGTGnMOf9YpHKJqMSsa0dXbfmxeoJ7xHlrt+xmY=",
|
|
||||||
"owner": "numtide",
|
|
||||||
"repo": "flake-utils",
|
|
||||||
"rev": "ff7b65b44d01cf9ba6a71320833626af21126384",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "numtide",
|
|
||||||
"repo": "flake-utils",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
|
||||||
"lastModified": 1705099185,
|
|
||||||
"narHash": "sha256-SxJenKtvcrKJd0TyJQMO3p6VA7PEp+vmMnmlKFzWMNs=",
|
|
||||||
"owner": "nixos",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"rev": "2bce5ccff0ad7abda23e8bb56434b6877a446694",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "nixos",
|
|
||||||
"ref": "release-23.11",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nixpkgs_2": {
|
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1760580664,
|
"lastModified": 1760580664,
|
||||||
"narHash": "sha256-/YdfibIrnqXAL8p5kqCU345mzpHoOtuVIkMiI2pF4Dc=",
|
"narHash": "sha256-/YdfibIrnqXAL8p5kqCU345mzpHoOtuVIkMiI2pF4Dc=",
|
||||||
|
|
@ -90,49 +16,12 @@
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"nixpkgs_3": {
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1744536153,
|
|
||||||
"narHash": "sha256-awS2zRgF4uTwrOKwwiJcByDzDOdo3Q1rPZbiHQg/N38=",
|
|
||||||
"owner": "NixOS",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"rev": "18dd725c29603f582cf1900e0d25f9f1063dbf11",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "NixOS",
|
|
||||||
"ref": "nixpkgs-unstable",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"root": {
|
"root": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"cargo2nix": "cargo2nix",
|
"nixpkgs": "nixpkgs",
|
||||||
"nixpkgs": "nixpkgs_2",
|
|
||||||
"rust-overlay": "rust-overlay",
|
|
||||||
"utils": "utils"
|
"utils": "utils"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"rust-overlay": {
|
|
||||||
"inputs": {
|
|
||||||
"nixpkgs": "nixpkgs_3"
|
|
||||||
},
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1761851069,
|
|
||||||
"narHash": "sha256-VHqBFyQdXE10lvBaNCaJSD5xw1WH6Thqq92OIB6MqZo=",
|
|
||||||
"owner": "oxalica",
|
|
||||||
"repo": "rust-overlay",
|
|
||||||
"rev": "0881bcdf6c34cd3ba558b19d7a74d8ffc9e1fff0",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "oxalica",
|
|
||||||
"ref": "stable",
|
|
||||||
"repo": "rust-overlay",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"systems": {
|
"systems": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1681028828,
|
"lastModified": 1681028828,
|
||||||
|
|
@ -148,24 +37,9 @@
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"systems_2": {
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1681028828,
|
|
||||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
|
||||||
"owner": "nix-systems",
|
|
||||||
"repo": "default",
|
|
||||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "nix-systems",
|
|
||||||
"repo": "default",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"utils": {
|
"utils": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"systems": "systems_2"
|
"systems": "systems"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1731533236,
|
"lastModified": 1731533236,
|
||||||
|
|
|
||||||
23
flake.nix
23
flake.nix
|
|
@ -2,35 +2,16 @@
|
||||||
inputs = {
|
inputs = {
|
||||||
utils.url = "github:numtide/flake-utils";
|
utils.url = "github:numtide/flake-utils";
|
||||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.05";
|
nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.05";
|
||||||
cargo2nix = {
|
|
||||||
url = "github:cargo2nix/cargo2nix/release-0.12";
|
|
||||||
inputs.rust-overlay.follows = "rust-overlay";
|
|
||||||
};
|
|
||||||
rust-overlay.url = "github:oxalica/rust-overlay/stable";
|
|
||||||
};
|
};
|
||||||
outputs = {
|
outputs = {
|
||||||
self,
|
self,
|
||||||
nixpkgs,
|
nixpkgs,
|
||||||
utils,
|
utils,
|
||||||
cargo2nix,
|
|
||||||
rust-overlay,
|
|
||||||
}:
|
}:
|
||||||
utils.lib.eachDefaultSystem (
|
utils.lib.eachDefaultSystem (
|
||||||
system: let
|
system: let
|
||||||
pkgs = import nixpkgs {
|
pkgs = nixpkgs.legacyPackages.${system};
|
||||||
inherit system;
|
in {
|
||||||
overlays = [cargo2nix.overlays.default];
|
|
||||||
};
|
|
||||||
|
|
||||||
rustPkgs = pkgs.rustBuilder.makePackageSet {
|
|
||||||
rustVersion = "1.86.0";
|
|
||||||
packageFun = import ./Cargo.nix;
|
|
||||||
};
|
|
||||||
in rec {
|
|
||||||
packages = {
|
|
||||||
food-tracker = rustPkgs.workspace.food-tracker {};
|
|
||||||
default = packages.food-tracker;
|
|
||||||
};
|
|
||||||
devShell = pkgs.mkShell {
|
devShell = pkgs.mkShell {
|
||||||
buildInputs = [
|
buildInputs = [
|
||||||
pkgs.cargo
|
pkgs.cargo
|
||||||
|
|
|
||||||
BIN
foods.db
BIN
foods.db
Binary file not shown.
|
|
@ -6,4 +6,4 @@ CREATE TABLE IF NOT EXISTS food (
|
||||||
target_servings INTEGER NOT NULL DEFAULT 1,
|
target_servings INTEGER NOT NULL DEFAULT 1,
|
||||||
actual_servings INTEGER NOT NULL DEFAULT 0,
|
actual_servings INTEGER NOT NULL DEFAULT 0,
|
||||||
color TEXT NOT NULL DEFAULT 'white'
|
color TEXT NOT NULL DEFAULT 'white'
|
||||||
) STRICT;
|
);
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,14 @@
|
||||||
INSERT OR REPLACE INTO
|
UPDATE
|
||||||
day_serving (day, food_id, servings_eaten)
|
food
|
||||||
VALUES (
|
SET
|
||||||
CURRENT_DATE,
|
actual_servings = MAX(
|
||||||
?1,
|
(SELECT
|
||||||
MAX(coalesce((
|
actual_servings
|
||||||
SELECT
|
FROM
|
||||||
servings_eaten
|
food
|
||||||
FROM
|
WHERE id = ?1) - 1,
|
||||||
day_serving
|
0)
|
||||||
WHERE
|
WHERE
|
||||||
food_id = ?1
|
id = ?1
|
||||||
AND day = CURRENT_DATE
|
RETURNING
|
||||||
) - 1,
|
actual_servings
|
||||||
0
|
|
||||||
), 0)
|
|
||||||
) RETURNING servings_eaten;
|
|
||||||
|
|
|
||||||
|
|
@ -4,14 +4,9 @@ SELECT
|
||||||
name,
|
name,
|
||||||
kc_per_serving,
|
kc_per_serving,
|
||||||
target_servings,
|
target_servings,
|
||||||
coalesce(day_serving.servings_eaten, 0),
|
actual_servings,
|
||||||
color
|
color
|
||||||
FROM
|
FROM
|
||||||
food
|
food
|
||||||
LEFT JOIN
|
|
||||||
day_serving
|
|
||||||
ON
|
|
||||||
day_serving.food_id = food.id
|
|
||||||
AND day_serving.day = CURRENT_DATE
|
|
||||||
WHERE
|
WHERE
|
||||||
food.id = ?1;
|
id = ?1
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,10 @@
|
||||||
SELECT
|
SELECT
|
||||||
food.id,
|
id,
|
||||||
food.portion,
|
portion,
|
||||||
food.name,
|
name,
|
||||||
food.kc_per_serving,
|
kc_per_serving,
|
||||||
food.target_servings,
|
target_servings,
|
||||||
coalesce(day_serving.servings_eaten, 0) as servings_eaten,
|
actual_servings,
|
||||||
food.color
|
color
|
||||||
FROM
|
FROM
|
||||||
food
|
food
|
||||||
LEFT JOIN
|
|
||||||
day_serving
|
|
||||||
ON
|
|
||||||
day_serving.food_id = food.id
|
|
||||||
AND coalesce(day_serving.day, CURRENT_DATE) = CURRENT_DATE
|
|
||||||
ORDER BY
|
|
||||||
sort_order, name;
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,4 @@
|
||||||
SELECT
|
SELECT
|
||||||
SUM(kc_per_serving * coalesce(servings_eaten, 0)) AS kc,
|
SUM(kc_per_serving * actual_servings) AS kc
|
||||||
SUM(protein_per_portion * coalesce(servings_eaten, 0)) AS protein,
|
|
||||||
SUM(fiber_per_portion * coalesce(servings_eaten, 0)) AS bs
|
|
||||||
FROM
|
FROM
|
||||||
food
|
food
|
||||||
LEFT JOIN
|
|
||||||
day_serving
|
|
||||||
ON
|
|
||||||
day_serving.food_id = food.id
|
|
||||||
AND coalesce(day_serving.day, CURRENT_DATE) = CURRENT_DATE;
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
PRAGMA user_version;
|
|
||||||
|
|
@ -1,17 +1,9 @@
|
||||||
INSERT OR REPLACE INTO
|
UPDATE
|
||||||
day_serving (day, food_id, servings_eaten)
|
food
|
||||||
VALUES (
|
SET actual_servings = (
|
||||||
CURRENT_DATE,
|
SELECT actual_servings
|
||||||
?1,
|
FROM food
|
||||||
coalesce((
|
WHERE id = ?1
|
||||||
SELECT
|
) + 1
|
||||||
servings_eaten
|
WHERE id = ?1
|
||||||
FROM
|
RETURNING actual_servings
|
||||||
day_serving
|
|
||||||
WHERE
|
|
||||||
food_id = ?1
|
|
||||||
AND day = CURRENT_DATE
|
|
||||||
) + 1,
|
|
||||||
1
|
|
||||||
)
|
|
||||||
) RETURNING servings_eaten;
|
|
||||||
|
|
|
||||||
232
src/main.rs
232
src/main.rs
|
|
@ -5,11 +5,11 @@ use axum::{
|
||||||
Router,
|
Router,
|
||||||
extract::{MatchedPath, Path, State},
|
extract::{MatchedPath, Path, State},
|
||||||
http::{Request, StatusCode},
|
http::{Request, StatusCode},
|
||||||
response::{Html, IntoResponse, Response},
|
response::Html,
|
||||||
routing::{get, post},
|
routing::{get, post},
|
||||||
};
|
};
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use rusqlite::{CachedStatement, Connection, Row, Transaction};
|
use rusqlite::{CachedStatement, Connection, Row};
|
||||||
use tower_http::trace::TraceLayer;
|
use tower_http::trace::TraceLayer;
|
||||||
use tower_request_id::{RequestId, RequestIdLayer};
|
use tower_request_id::{RequestId, RequestIdLayer};
|
||||||
use tracing::{debug, error, info, info_span};
|
use tracing::{debug, error, info, info_span};
|
||||||
|
|
@ -18,8 +18,8 @@ use tracing_subscriber::{layer::SubscriberExt as _, util::SubscriberInitExt as _
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct Sum {
|
struct Sum {
|
||||||
kc: i32,
|
kc: i32,
|
||||||
bs: f32,
|
bs: i32,
|
||||||
protein: f32,
|
protein: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Display for Sum {
|
impl std::fmt::Display for Sum {
|
||||||
|
|
@ -56,7 +56,7 @@ struct Food {
|
||||||
name: String,
|
name: String,
|
||||||
kc_per_serving: i32,
|
kc_per_serving: i32,
|
||||||
target_servings: i32,
|
target_servings: i32,
|
||||||
servings_eaten: i32,
|
actual_servings: i32,
|
||||||
color: String,
|
color: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -69,7 +69,7 @@ impl Food {
|
||||||
name: row.get(2)?,
|
name: row.get(2)?,
|
||||||
kc_per_serving: row.get(3)?,
|
kc_per_serving: row.get(3)?,
|
||||||
target_servings: row.get(4)?,
|
target_servings: row.get(4)?,
|
||||||
servings_eaten: row.get(5)?,
|
actual_servings: row.get(5)?,
|
||||||
color: row.get(6)?,
|
color: row.get(6)?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -80,7 +80,8 @@ impl Food {
|
||||||
struct PreparedStatements {}
|
struct PreparedStatements {}
|
||||||
|
|
||||||
impl<'conn> PreparedStatements {
|
impl<'conn> PreparedStatements {
|
||||||
fn check(conn: &Connection) -> anyhow::Result<Self> {
|
fn check(conn: &Connection) -> rusqlite::Result<Self> {
|
||||||
|
conn.prepare_cached(include_str!("create_tables.sql"))?;
|
||||||
conn.prepare_cached(include_str!("increase.sql"))?;
|
conn.prepare_cached(include_str!("increase.sql"))?;
|
||||||
conn.prepare_cached(include_str!("decrease.sql"))?;
|
conn.prepare_cached(include_str!("decrease.sql"))?;
|
||||||
conn.prepare_cached(include_str!("get_food.sql"))?;
|
conn.prepare_cached(include_str!("get_food.sql"))?;
|
||||||
|
|
@ -90,6 +91,11 @@ impl<'conn> PreparedStatements {
|
||||||
Ok(PreparedStatements {})
|
Ok(PreparedStatements {})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn create_tables(conn: &'conn Connection) -> CachedStatement<'conn> {
|
||||||
|
conn.prepare_cached(include_str!("create_tables.sql"))
|
||||||
|
.expect("cached statement is invalid")
|
||||||
|
}
|
||||||
|
|
||||||
fn increase(conn: &'conn Connection) -> CachedStatement<'conn> {
|
fn increase(conn: &'conn Connection) -> CachedStatement<'conn> {
|
||||||
conn.prepare_cached(include_str!("increase.sql"))
|
conn.prepare_cached(include_str!("increase.sql"))
|
||||||
.expect("cached statement is invalid")
|
.expect("cached statement is invalid")
|
||||||
|
|
@ -121,82 +127,35 @@ impl<'conn> PreparedStatements {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make our own error that wraps `anyhow::Error`.
|
|
||||||
struct AppError(anyhow::Error);
|
|
||||||
|
|
||||||
// Tell axum how to convert `AppError` into a response.
|
|
||||||
impl IntoResponse for AppError {
|
|
||||||
fn into_response(self) -> Response {
|
|
||||||
let error = &self.0;
|
|
||||||
error!(?error, "error returned to client");
|
|
||||||
(
|
|
||||||
StatusCode::INTERNAL_SERVER_ERROR,
|
|
||||||
format!("Something went wrong: {}", self.0),
|
|
||||||
)
|
|
||||||
.into_response()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// This enables using `?` on functions that return `Result<_, anyhow::Error>` to turn them into
|
|
||||||
// `Result<_, AppError>`. That way you don't need to do that manually.
|
|
||||||
impl<E> From<E> for AppError
|
|
||||||
where
|
|
||||||
E: Into<anyhow::Error>,
|
|
||||||
{
|
|
||||||
fn from(err: E) -> Self {
|
|
||||||
Self(err.into())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type ConnState = Arc<Mutex<Connection>>;
|
type ConnState = Arc<Mutex<Connection>>;
|
||||||
|
|
||||||
fn get_version(tx: &Transaction) -> anyhow::Result<usize> {
|
#[tokio::main]
|
||||||
Ok(tx.query_one(include_str!("get_version.sql"), (), |row| row.get(0))?)
|
async fn main() -> Result<(), std::io::Error> {
|
||||||
}
|
tracing_subscriber::registry()
|
||||||
|
.with(
|
||||||
|
tracing_subscriber::EnvFilter::try_from_default_env().unwrap_or_else(|_| {
|
||||||
|
// axum logs rejections from built-in extractors with the `axum::rejection`
|
||||||
|
// target, at `TRACE` level. `axum::rejection=trace` enables showing those events
|
||||||
|
format!(
|
||||||
|
"{}=debug,tower_http=debug,axum::rejection=trace",
|
||||||
|
env!("CARGO_CRATE_NAME")
|
||||||
|
)
|
||||||
|
.into()
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.with(tracing_subscriber::fmt::layer())
|
||||||
|
.init();
|
||||||
|
|
||||||
fn get_migrations() -> [&'static str; 5] {
|
let db_connecion_str = "./foods.db".to_string();
|
||||||
[
|
debug!(db_connecion_str, "opening database");
|
||||||
include_str!("migrations/1.sql"),
|
let conn = Connection::open(db_connecion_str).expect("failed to open database");
|
||||||
include_str!("migrations/2.sql"),
|
PreparedStatements::check(&conn).expect("failed to prepare sql statements");
|
||||||
include_str!("migrations/3.sql"),
|
if let Err(e) = PreparedStatements::create_tables(&conn).execute(()) {
|
||||||
include_str!("migrations/4.sql"),
|
error!(?e, "failed to create tables");
|
||||||
include_str!("migrations/5.sql"),
|
panic!("failed to create tables: {:#?}", e);
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
fn do_migrations(conn: &mut Connection) -> anyhow::Result<()> {
|
|
||||||
let migrations = get_migrations();
|
|
||||||
let num_migrations = migrations.len();
|
|
||||||
let tx = conn.transaction()?;
|
|
||||||
let version = get_version(&tx)?;
|
|
||||||
if version < migrations.len() {
|
|
||||||
info!(
|
|
||||||
migrations_to_apply = num_migrations - version,
|
|
||||||
"need to apply some migrations"
|
|
||||||
);
|
|
||||||
let mut mig_number = version;
|
|
||||||
for migration in migrations.iter().skip(version) {
|
|
||||||
mig_number += 1;
|
|
||||||
info!(mig_number, "applying migration");
|
|
||||||
debug!(migration = migration);
|
|
||||||
tx.execute_batch(migration)?;
|
|
||||||
if get_version(&tx)? != mig_number {
|
|
||||||
panic!(
|
|
||||||
"expected user_version to eq {} after applying migration {}. maybe a missing 'PRAGMA user_version =' ?",
|
|
||||||
mig_number, mig_number
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
tx.commit()?;
|
|
||||||
info!("applied all migrations");
|
|
||||||
} else {
|
|
||||||
info!("no migrations to apply");
|
|
||||||
}
|
}
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn app(conn: Connection) -> axum::Router {
|
let app = Router::new()
|
||||||
Router::new()
|
|
||||||
.route("/", get(root))
|
.route("/", get(root))
|
||||||
.route("/increase/{id}", post(increase))
|
.route("/increase/{id}", post(increase))
|
||||||
.route("/decrease/{id}", post(decrease))
|
.route("/decrease/{id}", post(decrease))
|
||||||
|
|
@ -222,40 +181,7 @@ fn app(conn: Connection) -> axum::Router {
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
.layer(RequestIdLayer)
|
.layer(RequestIdLayer)
|
||||||
.with_state(Arc::new(Mutex::new(conn)))
|
.with_state(Arc::new(Mutex::new(conn)));
|
||||||
}
|
|
||||||
|
|
||||||
#[tokio::main]
|
|
||||||
async fn main() -> anyhow::Result<()> {
|
|
||||||
tracing_subscriber::registry()
|
|
||||||
.with(
|
|
||||||
tracing_subscriber::EnvFilter::try_from_default_env().unwrap_or_else(|_| {
|
|
||||||
// axum logs rejections from built-in extractors with the `axum::rejection`
|
|
||||||
// target, at `TRACE` level. `axum::rejection=trace` enables showing those events
|
|
||||||
format!(
|
|
||||||
"{}=debug,tower_http=debug,axum::rejection=trace",
|
|
||||||
env!("CARGO_CRATE_NAME")
|
|
||||||
)
|
|
||||||
.into()
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
.with(tracing_subscriber::fmt::layer())
|
|
||||||
.init();
|
|
||||||
|
|
||||||
let db_connecion_str = "./foods.db".to_string();
|
|
||||||
debug!(db_connecion_str, "opening database");
|
|
||||||
let mut conn = Connection::open(db_connecion_str).expect("failed to open database");
|
|
||||||
|
|
||||||
if let Err(e) = conn.execute(include_str!("create_tables.sql"), ()) {
|
|
||||||
error!(?e, "failed to create tables");
|
|
||||||
panic!("failed to create tables: {:#?}", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
do_migrations(&mut conn).expect("failed to do database migrations");
|
|
||||||
|
|
||||||
PreparedStatements::check(&conn).expect("failed to prepare sql statements");
|
|
||||||
|
|
||||||
let app = app(conn);
|
|
||||||
|
|
||||||
let address = "0.0.0.0:3001";
|
let address = "0.0.0.0:3001";
|
||||||
let listener = tokio::net::TcpListener::bind(address)
|
let listener = tokio::net::TcpListener::bind(address)
|
||||||
|
|
@ -267,11 +193,10 @@ async fn main() -> anyhow::Result<()> {
|
||||||
.local_addr()
|
.local_addr()
|
||||||
.expect("failed to get local listening address")
|
.expect("failed to get local listening address")
|
||||||
);
|
);
|
||||||
axum::serve(listener, app).await?;
|
axum::serve(listener, app).await
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_foods(conn: &ConnState) -> anyhow::Result<Vec<Food>> {
|
fn get_foods(conn: &ConnState) -> rusqlite::Result<Vec<Food>> {
|
||||||
let conn = conn.lock();
|
let conn = conn.lock();
|
||||||
let mut stmt = PreparedStatements::get_foods(&conn);
|
let mut stmt = PreparedStatements::get_foods(&conn);
|
||||||
let foods: Vec<_> = stmt
|
let foods: Vec<_> = stmt
|
||||||
|
|
@ -281,16 +206,15 @@ fn get_foods(conn: &ConnState) -> anyhow::Result<Vec<Food>> {
|
||||||
Ok(foods)
|
Ok(foods)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_sum(conn: &Arc<Mutex<Connection>>) -> anyhow::Result<Sum> {
|
fn get_sum(conn: &Arc<Mutex<Connection>>) -> rusqlite::Result<Sum> {
|
||||||
let conn = conn.lock();
|
let conn = conn.lock();
|
||||||
let mut stmt = PreparedStatements::get_sum(&conn);
|
let mut stmt = PreparedStatements::get_sum(&conn);
|
||||||
let sum = stmt.query_one((), |row| {
|
let kc = stmt.query_one((), |row| row.get(0))?;
|
||||||
Ok(Sum {
|
let sum = Sum {
|
||||||
kc: row.get(0)?,
|
kc,
|
||||||
bs: row.get(1)?,
|
bs: 99,
|
||||||
protein: row.get(2)?,
|
protein: 99,
|
||||||
})
|
};
|
||||||
})?;
|
|
||||||
debug!(?sum);
|
debug!(?sum);
|
||||||
Ok(sum)
|
Ok(sum)
|
||||||
}
|
}
|
||||||
|
|
@ -301,15 +225,19 @@ fn get_date() -> String {
|
||||||
date
|
date
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn root(State(conn): State<ConnState>) -> Result<Html<String>, AppError> {
|
async fn root(State(conn): State<ConnState>) -> Result<Html<String>, StatusCode> {
|
||||||
let foods = get_foods(&conn)?;
|
let foods = get_foods(&conn).map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
||||||
let sum = get_sum(&conn)?;
|
let sum = get_sum(&conn).map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
||||||
let date = get_date();
|
let date = get_date();
|
||||||
let index = IndexTemplate { foods, sum, date };
|
let index = IndexTemplate { foods, sum, date };
|
||||||
Ok(Html(index.render()?))
|
Ok(Html(
|
||||||
|
index
|
||||||
|
.render()
|
||||||
|
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn do_increase(conn: &Arc<Mutex<Connection>>, id: i32) -> anyhow::Result<()> {
|
fn do_increase(conn: &Arc<Mutex<Connection>>, id: i32) -> rusqlite::Result<()> {
|
||||||
let conn = conn.lock();
|
let conn = conn.lock();
|
||||||
let mut stmt = PreparedStatements::increase(&conn);
|
let mut stmt = PreparedStatements::increase(&conn);
|
||||||
let new: i32 = stmt.query_one((id,), |row| row.get(0))?;
|
let new: i32 = stmt.query_one((id,), |row| row.get(0))?;
|
||||||
|
|
@ -317,7 +245,7 @@ fn do_increase(conn: &Arc<Mutex<Connection>>, id: i32) -> anyhow::Result<()> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_food(conn: &Arc<Mutex<Connection>>, id: i32) -> anyhow::Result<Food> {
|
fn get_food(conn: &Arc<Mutex<Connection>>, id: i32) -> rusqlite::Result<Food> {
|
||||||
let conn = conn.lock();
|
let conn = conn.lock();
|
||||||
let mut stmt = PreparedStatements::get_food(&conn);
|
let mut stmt = PreparedStatements::get_food(&conn);
|
||||||
let food = stmt.query_one((id,), Food::from_row)?;
|
let food = stmt.query_one((id,), Food::from_row)?;
|
||||||
|
|
@ -328,16 +256,20 @@ fn get_food(conn: &Arc<Mutex<Connection>>, id: i32) -> anyhow::Result<Food> {
|
||||||
async fn increase(
|
async fn increase(
|
||||||
State(conn): State<Arc<Mutex<Connection>>>,
|
State(conn): State<Arc<Mutex<Connection>>>,
|
||||||
Path(id): Path<i32>,
|
Path(id): Path<i32>,
|
||||||
) -> Result<Html<String>, AppError> {
|
) -> Result<Html<String>, StatusCode> {
|
||||||
do_increase(&conn, id)?;
|
do_increase(&conn, id).map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
||||||
let food = get_food(&conn, id)?;
|
let food = get_food(&conn, id).map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
||||||
let sum = get_sum(&conn)?;
|
let sum = get_sum(&conn).map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
||||||
let date = get_date();
|
let date = get_date();
|
||||||
let update = FoodUpdateTemplate { food, sum, date };
|
let update = FoodUpdateTemplate { food, sum, date };
|
||||||
Ok(Html(update.render()?))
|
Ok(Html(
|
||||||
|
update
|
||||||
|
.render()
|
||||||
|
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn do_decrease(conn: &Arc<Mutex<Connection>>, id: i32) -> anyhow::Result<()> {
|
fn do_decrease(conn: &Arc<Mutex<Connection>>, id: i32) -> rusqlite::Result<()> {
|
||||||
let conn = conn.lock();
|
let conn = conn.lock();
|
||||||
let mut stmt = PreparedStatements::decrease(&conn);
|
let mut stmt = PreparedStatements::decrease(&conn);
|
||||||
let new: i32 = stmt.query_one((id,), |row| row.get(0))?;
|
let new: i32 = stmt.query_one((id,), |row| row.get(0))?;
|
||||||
|
|
@ -348,16 +280,20 @@ fn do_decrease(conn: &Arc<Mutex<Connection>>, id: i32) -> anyhow::Result<()> {
|
||||||
async fn decrease(
|
async fn decrease(
|
||||||
State(conn): State<Arc<Mutex<Connection>>>,
|
State(conn): State<Arc<Mutex<Connection>>>,
|
||||||
Path(id): Path<i32>,
|
Path(id): Path<i32>,
|
||||||
) -> Result<Html<String>, AppError> {
|
) -> Result<Html<String>, StatusCode> {
|
||||||
do_decrease(&conn, id)?;
|
do_decrease(&conn, id).map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
||||||
let food = get_food(&conn, id)?;
|
let food = get_food(&conn, id).map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
||||||
let sum = get_sum(&conn)?;
|
let sum = get_sum(&conn).map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
||||||
let date = get_date();
|
let date = get_date();
|
||||||
let update = FoodUpdateTemplate { food, sum, date };
|
let update = FoodUpdateTemplate { food, sum, date };
|
||||||
Ok(Html(update.render()?))
|
Ok(Html(
|
||||||
|
update
|
||||||
|
.render()
|
||||||
|
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn do_set(conn: &Arc<Mutex<Connection>>, id: i32, amount: i32) -> anyhow::Result<()> {
|
fn do_set(conn: &Arc<Mutex<Connection>>, id: i32, amount: i32) -> rusqlite::Result<()> {
|
||||||
let conn = conn.lock();
|
let conn = conn.lock();
|
||||||
let mut stmt = PreparedStatements::set(&conn);
|
let mut stmt = PreparedStatements::set(&conn);
|
||||||
let new: i32 = stmt.query_one((id, amount), |row| row.get(0))?;
|
let new: i32 = stmt.query_one((id, amount), |row| row.get(0))?;
|
||||||
|
|
@ -368,11 +304,15 @@ fn do_set(conn: &Arc<Mutex<Connection>>, id: i32, amount: i32) -> anyhow::Result
|
||||||
async fn set(
|
async fn set(
|
||||||
State(conn): State<Arc<Mutex<Connection>>>,
|
State(conn): State<Arc<Mutex<Connection>>>,
|
||||||
Path((id, amount)): Path<(i32, i32)>,
|
Path((id, amount)): Path<(i32, i32)>,
|
||||||
) -> Result<Html<String>, AppError> {
|
) -> Result<Html<String>, StatusCode> {
|
||||||
do_set(&conn, id, amount)?;
|
do_set(&conn, id, amount).map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
||||||
let food = get_food(&conn, id)?;
|
let food = get_food(&conn, id).map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
||||||
let sum = get_sum(&conn)?;
|
let sum = get_sum(&conn).map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
||||||
let date = get_date();
|
let date = get_date();
|
||||||
let update = FoodUpdateTemplate { food, sum, date };
|
let update = FoodUpdateTemplate { food, sum, date };
|
||||||
Ok(Html(update.render()?))
|
Ok(Html(
|
||||||
|
update
|
||||||
|
.render()
|
||||||
|
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +0,0 @@
|
||||||
ALTER TABLE
|
|
||||||
food
|
|
||||||
ADD COLUMN
|
|
||||||
portion_weight INTEGER NOT NULL DEFAULT 100 CHECK (portion_weight > 0);
|
|
||||||
|
|
||||||
PRAGMA user_version = 1;
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
||||||
ALTER TABLE
|
|
||||||
food
|
|
||||||
ADD COLUMN
|
|
||||||
-- per 100g
|
|
||||||
protein REAL NOT NULL DEFAULT 5.0 CHECK (protein > 0);
|
|
||||||
|
|
||||||
ALTER TABLE
|
|
||||||
food
|
|
||||||
ADD COLUMN
|
|
||||||
-- per 100g
|
|
||||||
fiber REAL NOT NULL DEFAULT 5.0 CHECK (fiber > 0);
|
|
||||||
|
|
||||||
ALTER TABLE
|
|
||||||
food
|
|
||||||
ADD COLUMN
|
|
||||||
protein_per_portion REAL NOT NULL GENERATED ALWAYS AS ((protein / 100) * portion_weight) VIRTUAL;
|
|
||||||
|
|
||||||
ALTER TABLE
|
|
||||||
food
|
|
||||||
ADD COLUMN
|
|
||||||
fiber_per_portion REAL NOT NULL GENERATED ALWAYS AS ((fiber / 100) * portion_weight) VIRTUAL;
|
|
||||||
|
|
||||||
PRAGMA user_version = 2;
|
|
||||||
|
|
@ -1,6 +0,0 @@
|
||||||
ALTER TABLE
|
|
||||||
food
|
|
||||||
ADD COLUMN
|
|
||||||
sort_order INTEGER NOT NULL DEFAULT 0;
|
|
||||||
|
|
||||||
PRAGMA user_version = 3;
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
||||||
CREATE TABLE "sqlb_temp_table_1" (
|
|
||||||
"id" INTEGER,
|
|
||||||
"portion" TEXT NOT NULL,
|
|
||||||
"name" TEXT NOT NULL,
|
|
||||||
"kc_per_serving" INTEGER NOT NULL DEFAULT 0,
|
|
||||||
"target_servings" INTEGER NOT NULL DEFAULT 1,
|
|
||||||
"actual_servings" INTEGER NOT NULL DEFAULT 0,
|
|
||||||
"color" TEXT NOT NULL DEFAULT 'white',
|
|
||||||
"portion_weight" INTEGER NOT NULL DEFAULT 100 CHECK("portion_weight" > 0),
|
|
||||||
"protein" REAL NOT NULL DEFAULT 5.0 CHECK("protein" >= 0),
|
|
||||||
"fiber" REAL NOT NULL DEFAULT 5.0 CHECK("fiber" >= 0),
|
|
||||||
"protein_per_portion" REAL NOT NULL GENERATED ALWAYS AS (("protein" / 100) * "portion_weight") VIRTUAL,
|
|
||||||
"fiber_per_portion" REAL NOT NULL GENERATED ALWAYS AS (("fiber" / 100) * "portion_weight") VIRTUAL,
|
|
||||||
"sort_order" INTEGER NOT NULL DEFAULT 0,
|
|
||||||
PRIMARY KEY("id")
|
|
||||||
) STRICT;
|
|
||||||
INSERT INTO "main"."sqlb_temp_table_1" ("actual_servings","color","fiber","id","kc_per_serving","name","portion","portion_weight","protein","sort_order","target_servings") SELECT "actual_servings","color","fiber","id","kc_per_serving","name","portion","portion_weight","protein","sort_order","target_servings" FROM "main"."food";
|
|
||||||
PRAGMA defer_foreign_keys = '1';
|
|
||||||
DROP TABLE "main"."food";
|
|
||||||
ALTER TABLE "main"."sqlb_temp_table_1" RENAME TO "food";
|
|
||||||
PRAGMA defer_foreign_keys = '0';
|
|
||||||
|
|
||||||
PRAGMA user_version = 4;
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
||||||
CREATE TABLE day_serving (
|
|
||||||
-- ISO-8601
|
|
||||||
day TEXT NOT NULL DEFAULT CURRENT_DATE,
|
|
||||||
food_id INTEGER NOT NULL,
|
|
||||||
servings_eaten INTEGER NOT NULL DEFAULT 0,
|
|
||||||
PRIMARY KEY(day, food_id),
|
|
||||||
FOREIGN KEY(food_id) REFERENCES food(id)
|
|
||||||
) STRICT;
|
|
||||||
|
|
||||||
INSERT INTO
|
|
||||||
day_serving (food_id, servings_eaten)
|
|
||||||
SELECT
|
|
||||||
id,
|
|
||||||
actual_servings
|
|
||||||
FROM
|
|
||||||
food;
|
|
||||||
|
|
||||||
ALTER TABLE
|
|
||||||
food
|
|
||||||
DROP COLUMN
|
|
||||||
actual_servings;
|
|
||||||
|
|
||||||
PRAGMA user_version = 5;
|
|
||||||
17
src/set.sql
17
src/set.sql
|
|
@ -1,9 +1,8 @@
|
||||||
INSERT OR REPLACE INTO
|
UPDATE
|
||||||
day_serving (day, food_id, servings_eaten)
|
food
|
||||||
VALUES (
|
SET
|
||||||
CURRENT_DATE,
|
actual_servings = MAX(?2, 0)
|
||||||
?1,
|
WHERE
|
||||||
MAX(?2, 0)
|
id = ?1
|
||||||
)
|
RETURNING
|
||||||
RETURNING servings_eaten;
|
actual_servings
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,18 +20,18 @@
|
||||||
{% for counter in self::range(10) %}
|
{% for counter in self::range(10) %}
|
||||||
{% if loop.index as i32 <= food.target_servings %}
|
{% if loop.index as i32 <= food.target_servings %}
|
||||||
<label class="ok">
|
<label class="ok">
|
||||||
{% if loop.index as i32 <= food.servings_eaten %}
|
{% if loop.index as i32 <= food.actual_servings %}
|
||||||
<input type="button" hx-post="/set/{{ food.id }}/to/{{ loop.index as i32 - 1}}" hx-target="#card-{{ food.id }}" value="●" class="checked">
|
<input type="checkbox" checked hx-post="/set/{{ food.id }}/to/{{ loop.index as i32 - 1}}" hx-target="#card-{{ food.id }}">
|
||||||
{% else %}
|
{% else %}
|
||||||
<input type="button" hx-post="/set/{{ food.id }}/to/{{ loop.index as i32 }}" hx-target="#card-{{ food.id }}" value="●" class="unchecked">
|
<input type="checkbox" hx-post="/set/{{ food.id }}/to/{{ loop.index as i32 }}" hx-target="#card-{{ food.id }}">
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</label>
|
</label>
|
||||||
{% else %}
|
{% else %}
|
||||||
<label class="bad">
|
<label class="bad">
|
||||||
{% if loop.index as i32 <= food.servings_eaten %}
|
{% if loop.index as i32 <= food.actual_servings %}
|
||||||
<input type="button" hx-post="/set/{{ food.id }}/to/{{ loop.index as i32 - 1}}" hx-target="#card-{{ food.id }}" value="●" class="checked">
|
<input type="checkbox" checked hx-post="/set/{{ food.id }}/to/{{ loop.index as i32 - 1}}" hx-target="#card-{{ food.id }}">
|
||||||
{% else %}
|
{% else %}
|
||||||
<input type="button" hx-post="/set/{{ food.id }}/to/{{ loop.index as i32 }}" hx-target="#card-{{ food.id }}" value="●" class="unchecked">
|
<input type="checkbox" hx-post="/set/{{ food.id }}/to/{{ loop.index as i32 }}" hx-target="#card-{{ food.id }}">
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</label>
|
</label>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.card {
|
.card {
|
||||||
background-color: #f6edcd;
|
background-color: hsl(from #a8c8a6 h 30% l);
|
||||||
}
|
}
|
||||||
|
|
||||||
hr {
|
hr {
|
||||||
|
|
@ -132,22 +132,5 @@
|
||||||
accent-color: hsl(from #cb8175 h 90% l);
|
accent-color: hsl(from #cb8175 h 90% l);
|
||||||
background-color: hsl(from #cb8175 h 60% l);
|
background-color: hsl(from #cb8175 h 60% l);
|
||||||
}
|
}
|
||||||
|
|
||||||
input[type="button"] {
|
|
||||||
display: inline-block;
|
|
||||||
border: none;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
background-color: inherit;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.unchecked {
|
|
||||||
color: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
input[type="button"]:hover {
|
|
||||||
background-color: beige;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
</html>
|
</html>
|
||||||
Loading…
Add table
Add a link
Reference in a new issue