From 080bb80956f9adebaea074bed04a4ff52abf5dcf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kha=C3=AFs=20COLIN?= Date: Sun, 19 Oct 2025 17:58:02 +0200 Subject: [PATCH] put sql statements in separate files --- src/decrease.sql | 14 +++++++++ src/get_food.sql | 12 ++++++++ src/get_foods.sql | 10 +++++++ src/get_sum.sql | 4 +++ src/increase.sql | 9 ++++++ src/main.rs | 75 ++++++++++++++++++++++++++++++++++++----------- 6 files changed, 107 insertions(+), 17 deletions(-) create mode 100644 src/decrease.sql create mode 100644 src/get_food.sql create mode 100644 src/get_foods.sql create mode 100644 src/get_sum.sql create mode 100644 src/increase.sql diff --git a/src/decrease.sql b/src/decrease.sql new file mode 100644 index 0000000..5723d8b --- /dev/null +++ b/src/decrease.sql @@ -0,0 +1,14 @@ +UPDATE + food +SET + actual_servings = MAX( + (SELECT + actual_servings + FROM + food + WHERE id = ?1) - 1, + 0) +WHERE + id = ?1 +RETURNING + actual_servings diff --git a/src/get_food.sql b/src/get_food.sql new file mode 100644 index 0000000..a7c517f --- /dev/null +++ b/src/get_food.sql @@ -0,0 +1,12 @@ +SELECT + id, + portion, + name, + kc_per_serving, + target_servings, + actual_servings, + color +FROM + food +WHERE + id = ?1 diff --git a/src/get_foods.sql b/src/get_foods.sql new file mode 100644 index 0000000..dbd3e94 --- /dev/null +++ b/src/get_foods.sql @@ -0,0 +1,10 @@ +SELECT + id, + portion, + name, + kc_per_serving, + target_servings, + actual_servings, + color +FROM + food diff --git a/src/get_sum.sql b/src/get_sum.sql new file mode 100644 index 0000000..7e72bb7 --- /dev/null +++ b/src/get_sum.sql @@ -0,0 +1,4 @@ +SELECT + SUM(kc_per_serving * actual_servings) AS kc +FROM + food diff --git a/src/increase.sql b/src/increase.sql new file mode 100644 index 0000000..fd2c00e --- /dev/null +++ b/src/increase.sql @@ -0,0 +1,9 @@ +UPDATE + food +SET actual_servings = ( + SELECT actual_servings + FROM food + WHERE id = ?1 +) + 1 +WHERE id = ?1 +RETURNING actual_servings diff --git a/src/main.rs b/src/main.rs index 28fdf90..a6363c1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,7 +9,7 @@ use axum::{ routing::{get, post}, }; use parking_lot::Mutex; -use rusqlite::Connection; +use rusqlite::{CachedStatement, Connection}; use tower_http::trace::TraceLayer; use tower_request_id::{RequestId, RequestIdLayer}; use tracing::{debug, error, info, info_span}; @@ -40,6 +40,53 @@ struct Food { color: String, } +#[derive(Clone)] +struct PreparedStatements {} + +impl<'conn> PreparedStatements { + fn check(conn: &Connection) -> rusqlite::Result { + conn.prepare_cached(include_str!("create_tables.sql"))?; + conn.prepare_cached(include_str!("increase.sql"))?; + conn.prepare_cached(include_str!("decrease.sql"))?; + conn.prepare_cached(include_str!("get_food.sql"))?; + conn.prepare_cached(include_str!("get_foods.sql"))?; + conn.prepare_cached(include_str!("get_sum.sql"))?; + 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> { + conn.prepare_cached(include_str!("increase.sql")) + .expect("cached statement is invalid") + } + + fn decrease(conn: &'conn Connection) -> CachedStatement<'conn> { + conn.prepare_cached(include_str!("decrease.sql")) + .expect("cached statement is invalid") + } + + fn get_food(conn: &'conn Connection) -> CachedStatement<'conn> { + conn.prepare_cached(include_str!("get_food.sql")) + .expect("cached statement is invalid") + } + + fn get_foods(conn: &'conn Connection) -> CachedStatement<'conn> { + conn.prepare_cached(include_str!("get_foods.sql")) + .expect("cached statement is invalid") + } + + fn get_sum(conn: &'conn Connection) -> CachedStatement<'conn> { + conn.prepare_cached(include_str!("get_sum.sql")) + .expect("cached statement is invalid") + } +} + +type ConnState = Arc>; + #[tokio::main] async fn main() -> Result<(), std::io::Error> { tracing_subscriber::registry() @@ -60,11 +107,11 @@ async fn main() -> Result<(), std::io::Error> { let db_connecion_str = "./foods.db".to_string(); debug!(db_connecion_str, "opening database"); let conn = Connection::open(db_connecion_str).expect("failed to open database"); - if let Err(e) = conn.execute(include_str!("create_tables.sql"), ()) { + PreparedStatements::check(&conn).expect("failed to prepare sql statements"); + if let Err(e) = PreparedStatements::create_tables(&conn).execute(()) { error!(?e, "failed to create tables"); panic!("failed to create tables: {:#?}", e); } - let conn = Arc::new(Mutex::new(conn)); let app = Router::new() .route("/", get(root)) @@ -91,7 +138,7 @@ async fn main() -> Result<(), std::io::Error> { }), ) .layer(RequestIdLayer) - .with_state(conn); + .with_state(Arc::new(Mutex::new(conn))); let address = "0.0.0.0:3001"; let listener = tokio::net::TcpListener::bind(address) @@ -106,13 +153,9 @@ async fn main() -> Result<(), std::io::Error> { axum::serve(listener, app).await } -fn get_foods(conn: &Arc>) -> Vec { +fn get_foods(conn: &ConnState) -> Vec { let conn = conn.lock(); - let mut stmt = conn - .prepare( - "SELECT id, portion, name, kc_per_serving, target_servings, actual_servings, color FROM food", - ) - .unwrap(); + let mut stmt = PreparedStatements::get_foods(&conn); let foods: Vec<_> = stmt .query_map((), |row| { Ok(Food { @@ -134,15 +177,13 @@ fn get_foods(conn: &Arc>) -> Vec { fn get_sum(conn: &Arc>) -> i32 { let conn = conn.lock(); - let mut stmt = conn - .prepare("SELECT SUM(kc_per_serving * actual_servings) as kc FROM food") - .unwrap(); + let mut stmt = PreparedStatements::get_sum(&conn); let sum = stmt.query_one((), |row| row.get(0)).unwrap(); debug!(sum); sum } -async fn root(State(conn): State>>) -> Html { +async fn root(State(conn): State) -> Html { let foods = get_foods(&conn); let sum = get_sum(&conn); let index = IndexTemplate { foods, sum }; @@ -151,14 +192,14 @@ async fn root(State(conn): State>>) -> Html { fn do_increase(conn: &Arc>, id: i32) { let conn = conn.lock(); - let mut stmt = conn.prepare("UPDATE food SET actual_servings = (SELECT actual_servings FROM food WHERE id = ?1) + 1 WHERE id = ?1 RETURNING actual_servings").unwrap(); + let mut stmt = PreparedStatements::increase(&conn); let new: i32 = stmt.query_one((id,), |row| row.get(0)).unwrap(); debug!(id, new_serving_count = new, "increase"); } fn get_food(conn: &Arc>, id: i32) -> Food { let conn = conn.lock(); - let mut stmt = conn.prepare("SELECT id, portion, name, kc_per_serving, target_servings, actual_servings, color FROM food WHERE id = ?1").unwrap(); + let mut stmt = PreparedStatements::get_food(&conn); let food = stmt .query_one((id,), |row| { Ok(Food { @@ -186,7 +227,7 @@ async fn increase(State(conn): State>>, Path(id): Path>, id: i32) { let conn = conn.lock(); - let mut stmt = conn.prepare("UPDATE food SET actual_servings = MAX((SELECT actual_servings FROM food WHERE id = ?1) - 1, 0) WHERE id = ?1 RETURNING actual_servings").unwrap(); + let mut stmt = PreparedStatements::decrease(&conn); let new: i32 = stmt.query_one((id,), |row| row.get(0)).unwrap(); debug!(id, new_serving_count = new, "decrease"); }