put sql statements in separate files

This commit is contained in:
Khaïs COLIN 2025-10-19 17:58:02 +02:00
parent 1bb63b1fa4
commit 080bb80956
Signed by: logistic-bot
SSH key fingerprint: SHA256:RlpiqKeXpcPFZZ4y9Ou4xi2M8OhRJovIwDlbCaMsuAo
6 changed files with 107 additions and 17 deletions

14
src/decrease.sql Normal file
View file

@ -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

12
src/get_food.sql Normal file
View file

@ -0,0 +1,12 @@
SELECT
id,
portion,
name,
kc_per_serving,
target_servings,
actual_servings,
color
FROM
food
WHERE
id = ?1

10
src/get_foods.sql Normal file
View file

@ -0,0 +1,10 @@
SELECT
id,
portion,
name,
kc_per_serving,
target_servings,
actual_servings,
color
FROM
food

4
src/get_sum.sql Normal file
View file

@ -0,0 +1,4 @@
SELECT
SUM(kc_per_serving * actual_servings) AS kc
FROM
food

9
src/increase.sql Normal file
View file

@ -0,0 +1,9 @@
UPDATE
food
SET actual_servings = (
SELECT actual_servings
FROM food
WHERE id = ?1
) + 1
WHERE id = ?1
RETURNING actual_servings

View file

@ -9,7 +9,7 @@ use axum::{
routing::{get, post}, routing::{get, post},
}; };
use parking_lot::Mutex; use parking_lot::Mutex;
use rusqlite::Connection; use rusqlite::{CachedStatement, Connection};
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};
@ -40,6 +40,53 @@ struct Food {
color: String, color: String,
} }
#[derive(Clone)]
struct PreparedStatements {}
impl<'conn> PreparedStatements {
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!("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<Mutex<Connection>>;
#[tokio::main] #[tokio::main]
async fn main() -> Result<(), std::io::Error> { async fn main() -> Result<(), std::io::Error> {
tracing_subscriber::registry() tracing_subscriber::registry()
@ -60,11 +107,11 @@ async fn main() -> Result<(), std::io::Error> {
let db_connecion_str = "./foods.db".to_string(); let db_connecion_str = "./foods.db".to_string();
debug!(db_connecion_str, "opening database"); debug!(db_connecion_str, "opening database");
let conn = Connection::open(db_connecion_str).expect("failed to open 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"); error!(?e, "failed to create tables");
panic!("failed to create tables: {:#?}", e); panic!("failed to create tables: {:#?}", e);
} }
let conn = Arc::new(Mutex::new(conn));
let app = Router::new() let app = Router::new()
.route("/", get(root)) .route("/", get(root))
@ -91,7 +138,7 @@ async fn main() -> Result<(), std::io::Error> {
}), }),
) )
.layer(RequestIdLayer) .layer(RequestIdLayer)
.with_state(conn); .with_state(Arc::new(Mutex::new(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)
@ -106,13 +153,9 @@ async fn main() -> Result<(), std::io::Error> {
axum::serve(listener, app).await axum::serve(listener, app).await
} }
fn get_foods(conn: &Arc<Mutex<Connection>>) -> Vec<Food> { fn get_foods(conn: &ConnState) -> Vec<Food> {
let conn = conn.lock(); let conn = conn.lock();
let mut stmt = conn let mut stmt = PreparedStatements::get_foods(&conn);
.prepare(
"SELECT id, portion, name, kc_per_serving, target_servings, actual_servings, color FROM food",
)
.unwrap();
let foods: Vec<_> = stmt let foods: Vec<_> = stmt
.query_map((), |row| { .query_map((), |row| {
Ok(Food { Ok(Food {
@ -134,15 +177,13 @@ fn get_foods(conn: &Arc<Mutex<Connection>>) -> Vec<Food> {
fn get_sum(conn: &Arc<Mutex<Connection>>) -> i32 { fn get_sum(conn: &Arc<Mutex<Connection>>) -> i32 {
let conn = conn.lock(); let conn = conn.lock();
let mut stmt = conn let mut stmt = PreparedStatements::get_sum(&conn);
.prepare("SELECT SUM(kc_per_serving * actual_servings) as kc FROM food")
.unwrap();
let sum = stmt.query_one((), |row| row.get(0)).unwrap(); let sum = stmt.query_one((), |row| row.get(0)).unwrap();
debug!(sum); debug!(sum);
sum sum
} }
async fn root(State(conn): State<Arc<Mutex<Connection>>>) -> Html<String> { async fn root(State(conn): State<ConnState>) -> Html<String> {
let foods = get_foods(&conn); let foods = get_foods(&conn);
let sum = get_sum(&conn); let sum = get_sum(&conn);
let index = IndexTemplate { foods, sum }; let index = IndexTemplate { foods, sum };
@ -151,14 +192,14 @@ async fn root(State(conn): State<Arc<Mutex<Connection>>>) -> Html<String> {
fn do_increase(conn: &Arc<Mutex<Connection>>, id: i32) { fn do_increase(conn: &Arc<Mutex<Connection>>, id: i32) {
let conn = conn.lock(); 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(); let new: i32 = stmt.query_one((id,), |row| row.get(0)).unwrap();
debug!(id, new_serving_count = new, "increase"); debug!(id, new_serving_count = new, "increase");
} }
fn get_food(conn: &Arc<Mutex<Connection>>, id: i32) -> Food { fn get_food(conn: &Arc<Mutex<Connection>>, id: i32) -> Food {
let conn = conn.lock(); 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 let food = stmt
.query_one((id,), |row| { .query_one((id,), |row| {
Ok(Food { Ok(Food {
@ -186,7 +227,7 @@ async fn increase(State(conn): State<Arc<Mutex<Connection>>>, Path(id): Path<i32
fn do_decrease(conn: &Arc<Mutex<Connection>>, id: i32) { fn do_decrease(conn: &Arc<Mutex<Connection>>, id: i32) {
let conn = conn.lock(); 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(); let new: i32 = stmt.query_one((id,), |row| row.get(0)).unwrap();
debug!(id, new_serving_count = new, "decrease"); debug!(id, new_serving_count = new, "decrease");
} }