From 5c88c876b370d8c24f3902b3d54e1a620c62ef68 Mon Sep 17 00:00:00 2001 From: Ida Dahl Date: Sun, 28 Dec 2025 19:54:32 +0100 Subject: [PATCH] added database --- Cargo.lock | 29 ++++++++++++++++ gui/src/main.rs | 11 ++++++- lib/src/lib.rs | 1 + srv/Cargo.toml | 1 + srv/src/db/init.sql | 6 ++++ srv/src/main.rs | 80 +++++++++++++++++++++++++-------------------- 6 files changed, 91 insertions(+), 37 deletions(-) create mode 100644 srv/src/db/init.sql diff --git a/Cargo.lock b/Cargo.lock index 796245c..b03880c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2390,6 +2390,7 @@ dependencies = [ "rocket", "serde", "serde_json", + "sqlite", ] [[package]] @@ -4913,6 +4914,34 @@ dependencies = [ "pin-utils", ] +[[package]] +name = "sqlite" +version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f66e9c01a11936154f3910dbba732c01f8b591543bc4d6672bddee79fd9c4783" +dependencies = [ + "sqlite3-sys", +] + +[[package]] +name = "sqlite3-src" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5b6d3c860886b0a33e69e421796a5f4a27f23597a182c2450f6d7ace5103120" +dependencies = [ + "cc", + "pkg-config", +] + +[[package]] +name = "sqlite3-sys" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7781d97adc13a1d5081127a9ee29afad8427f3757bd984daf814d8265267039" +dependencies = [ + "sqlite3-src", +] + [[package]] name = "stable-pattern" version = "0.1.0" diff --git a/gui/src/main.rs b/gui/src/main.rs index cf674f0..52a3a58 100644 --- a/gui/src/main.rs +++ b/gui/src/main.rs @@ -95,7 +95,15 @@ async fn main() -> Result<(), MagicAnyError> { let conf2 = conf2.clone(); tokio::spawn(async move { // TODO: add number to increment - let res = put_list(&item, &ItemData { checked: false }, &conf2).await; + let res = put_list( + &item, + &ItemData { + checked: false, + amount: 1, + }, + &conf2, + ) + .await; if let Err(err) = res { eprintln!("{err:?}"); } @@ -122,6 +130,7 @@ async fn main() -> Result<(), MagicAnyError> { &item.name, &ItemData { checked: item.checked, + amount: 1, }, &conf2, ) diff --git a/lib/src/lib.rs b/lib/src/lib.rs index d4bfc09..5724275 100644 --- a/lib/src/lib.rs +++ b/lib/src/lib.rs @@ -10,5 +10,6 @@ pub struct Item { pub struct ItemData { pub checked: bool, + pub amount: i64, // TODO: add number } diff --git a/srv/Cargo.toml b/srv/Cargo.toml index 5a5adac..e2fe252 100644 --- a/srv/Cargo.toml +++ b/srv/Cargo.toml @@ -8,3 +8,4 @@ rocket = { version = "0.5.1", features = ["json"] } serde = { version = "1.0.228", features = ["derive"] } serde_json = "1.0.145" inkopslista-lib = { path = "../lib" } +sqlite = "0.37.0" diff --git a/srv/src/db/init.sql b/srv/src/db/init.sql new file mode 100644 index 0000000..3111164 --- /dev/null +++ b/srv/src/db/init.sql @@ -0,0 +1,6 @@ +CREATE TABLE + IF NOT EXISTS list ( + itemname TEXT NOT NULL PRIMARY KEY, + checked INT NOT NULL, -- actually a boolean + amount INT NOT NULL + ) STRICT; \ No newline at end of file diff --git a/srv/src/main.rs b/srv/src/main.rs index 0da8699..4a0d74b 100644 --- a/srv/src/main.rs +++ b/srv/src/main.rs @@ -1,62 +1,70 @@ #[macro_use] extern crate rocket; -use std::sync::Mutex; +use std::env; use inkopslista_lib::{Item, ItemData}; use rocket::{serde::json::Json, State}; -use serde::{Deserialize, Serialize}; +use sqlite::ConnectionThreadSafe; #[get("/")] fn index() -> &'static str { "hello world" } -// http GET hemma.nubo.sh/api/list/ -// response: [ -// Item { name: "Mjölk", ItemData { checked: true } } -// ] #[get("/api/list")] -fn get_list(mock_db: &State>) -> Json> { - let mock_db = mock_db.lock().unwrap(); - Json(mock_db.list.clone()) +fn get_list(db: &State) -> Json> { + // TODO errorhandling + let query = "SELECT * FROM list;"; + let list = db + .prepare(query) + .unwrap() + .into_iter() + .map(|row| { + let row = row.unwrap(); + Item { + name: row.read::<&str, _>("itemname").to_string(), + data: ItemData { + checked: row.read::("checked") > 0, + amount: row.read::("amount"), + }, + } + }) + .collect(); + Json(list) } -// http PUT hemma.nubo.sh/api/list/mjölk -// body: ItemData { -// checked: true, -// } #[put("/api/list/", data = "")] -fn put_list(item: &str, data: Json, mock_db: &State>) { - println!("{} {:?}", item, data); - - let mut mock_db = mock_db.lock().unwrap(); - if let Some(item) = mock_db.list.iter_mut().find(|x| x.name == item) { - item.data = data.into_inner() - } else { - mock_db.list.push(Item { - name: item.to_string(), - data: data.into_inner(), - }); - } +fn put_list(item: &str, data: Json, db: &State) { + // TODO: errorhandling + let query = + "INSERT INTO list VALUES(?, ?, ?) ON CONFLICT DO UPDATE SET checked = ?, amount = ?;"; + let mut statement = db.prepare(query).unwrap(); + let data = data.into_inner(); + statement.bind((1, item)).unwrap(); + statement.bind((2, data.checked as i64)).unwrap(); + statement.bind((3, data.amount)).unwrap(); + statement.bind((4, data.checked as i64)).unwrap(); + statement.bind((5, data.amount)).unwrap(); + while let Ok(sqlite::State::Row) = statement.next() {} } #[delete("/api/list/")] -fn delete_item(item: &str, mock_db: &State>) { - let mut mock_db = mock_db.lock().unwrap(); - if let Some(index) = mock_db.list.iter().position(|x| x.name == item) { - mock_db.list.remove(index); - } +fn delete_item(item: &str, db: &State) { + // TODO: Eror handling + let query = "DELETE FROM list WHERE itemname = ?"; + let mut statement = db.prepare(query).unwrap(); + statement.bind((1, item)).unwrap(); + while let Ok(sqlite::State::Row) = statement.next() {} } #[launch] fn rocket() -> _ { + let db_path = env::var("DB_PATH").unwrap(); + let db = sqlite::Connection::open_thread_safe(db_path).unwrap(); + db.execute(include_str!("db/init.sql")) + .expect("unable to initialize database"); rocket::build() - .manage(Mutex::new(MockDb::default())) + .manage(db) .mount("/", routes![index, get_list, put_list, delete_item]) } - -#[derive(Serialize, Deserialize, Default, Debug)] -struct MockDb { - pub list: Vec, -}