From 4f50aee9492d3d1fb9d5aedba18fb743fa45a77c Mon Sep 17 00:00:00 2001 From: Rokas Puzonas Date: Fri, 14 Apr 2023 19:15:28 +0300 Subject: [PATCH] add updating and remove of factories/managers --- lab2/.env | 3 +- lab2/.vscode/settings.json | 5 + lab2/src-tauri/Cargo.lock | 137 +++++++++-------- lab2/src-tauri/Cargo.toml | 4 +- lab2/src-tauri/src/api.rs | 63 ++++++++ lab2/src-tauri/src/factory_repo.rs | 83 +++++++++++ lab2/src-tauri/src/main.rs | 174 +++++++--------------- lab2/src-tauri/src/manager_repo.rs | 79 ++++++++++ lab2/src-tauri/src/models.rs | 39 +++++ lab2/src/App.svelte | 2 +- lab2/src/lib/api.ts | 53 ++++++- lab2/src/routes/Factories-Managers.svelte | 23 +-- 12 files changed, 460 insertions(+), 205 deletions(-) create mode 100644 lab2/.vscode/settings.json create mode 100644 lab2/src-tauri/src/api.rs create mode 100644 lab2/src-tauri/src/factory_repo.rs create mode 100644 lab2/src-tauri/src/manager_repo.rs create mode 100644 lab2/src-tauri/src/models.rs diff --git a/lab2/.env b/lab2/.env index e006862..5fe80b9 100644 --- a/lab2/.env +++ b/lab2/.env @@ -1 +1,2 @@ -DATABASE_URL="sqlite:../database.sqlite" +RUST_BACKTRACE=1 +DATABASE_URL="mysql://root@localhost/ice_cream" \ No newline at end of file diff --git a/lab2/.vscode/settings.json b/lab2/.vscode/settings.json new file mode 100644 index 0000000..3ef0f03 --- /dev/null +++ b/lab2/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "rust-analyzer.linkedProjects": [ + ".\\src-tauri\\Cargo.toml" + ] +} \ No newline at end of file diff --git a/lab2/src-tauri/Cargo.lock b/lab2/src-tauri/Cargo.lock index c0ebba2..cc8c346 100644 --- a/lab2/src-tauri/Cargo.lock +++ b/lab2/src-tauri/Cargo.lock @@ -2,6 +2,15 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "addr2line" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a76fd60b23679b7d19bd066031410fb7e458ccc5e958eb5c325888ce4baedc97" +dependencies = [ + "gimli", +] + [[package]] name = "adler" version = "1.0.2" @@ -43,6 +52,15 @@ dependencies = [ "alloc-no-stdlib", ] +[[package]] +name = "anyhow" +version = "1.0.58" +source = "git+https://github.com/Seeker14491/anyhow-tauri.git#b77b49a539d0bc6294359f2abb99bf0097434da7" +dependencies = [ + "backtrace", + "serde", +] + [[package]] name = "anyhow" version = "1.0.70" @@ -237,6 +255,21 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[package]] +name = "backtrace" +version = "0.3.67" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "233d376d6d185f2a3093e58f283f60f880315b6c60075b01f36b3b85154564ca" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + [[package]] name = "base64" version = "0.13.1" @@ -871,18 +904,6 @@ dependencies = [ "miniz_oxide", ] -[[package]] -name = "flume" -version = "0.10.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1657b4441c3403d9f7b3409e47575237dac27b1b5726df654a6ecbf92f0f7577" -dependencies = [ - "futures-core", - "futures-sink", - "pin-project", - "spin 0.9.5", -] - [[package]] name = "fnv" version = "1.0.7" @@ -1148,6 +1169,12 @@ dependencies = [ "wasi 0.11.0+wasi-snapshot-preview1", ] +[[package]] +name = "gimli" +version = "0.27.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad0a93d233ebf96623465aad4046a8d3aa4da22d4f4beba5388838c8a434bbb4" + [[package]] name = "gio" version = "0.15.12" @@ -1204,7 +1231,7 @@ version = "0.15.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "25a68131a662b04931e71891fb14aaf65ee4b44d08e8abc10f49e77418c86c64" dependencies = [ - "anyhow", + "anyhow 1.0.70", "heck 0.4.1", "proc-macro-crate", "proc-macro-error", @@ -1312,7 +1339,7 @@ version = "0.15.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24f518afe90c23fba585b2d7697856f9e6a7bbc62f65588035e66f6afb01a2e9" dependencies = [ - "anyhow", + "anyhow 1.0.70", "proc-macro-crate", "proc-macro-error", "proc-macro2", @@ -1406,7 +1433,7 @@ checksum = "21dec9db110f5f872ed9699c3ecf50cf16f423502706ba5c72462e28d3157573" name = "ice-production" version = "0.0.0" dependencies = [ - "anyhow", + "anyhow 1.0.58", "async-std", "dotenv", "serde", @@ -1622,7 +1649,7 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" dependencies = [ - "spin 0.5.2", + "spin", ] [[package]] @@ -1637,17 +1664,6 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "348108ab3fba42ec82ff6e9564fc4ca0247bdccdc68dd8af9764bbc79c3c8ffb" -[[package]] -name = "libsqlite3-sys" -version = "0.24.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "898745e570c7d0453cc1fbc4a701eb6c662ed54e8fec8b7d14be137ebeeb9d14" -dependencies = [ - "cc", - "pkg-config", - "vcpkg", -] - [[package]] name = "line-wrap" version = "0.1.1" @@ -1979,6 +1995,15 @@ dependencies = [ "objc", ] +[[package]] +name = "object" +version = "0.30.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea86265d3d3dcb6a27fc51bd29a4bf387fae9d2986b823079d4986af253eb439" +dependencies = [ + "memchr", +] + [[package]] name = "once_cell" version = "1.17.1" @@ -2249,26 +2274,6 @@ dependencies = [ "siphasher", ] -[[package]] -name = "pin-project" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad29a609b6bcd67fee905812e544992d216af9d755757c05ed2d0e15a74c6ecc" -dependencies = [ - "pin-project-internal", -] - -[[package]] -name = "pin-project-internal" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "069bdb1e05adc7a8990dce9cc75370895fbe4e3d58b9b73bf1aee56359344a55" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "pin-project-lite" version = "0.2.9" @@ -2583,6 +2588,12 @@ dependencies = [ "zeroize", ] +[[package]] +name = "rustc-demangle" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4a36c42d1873f9a77c53bde094f9664d9891bc604a45b4798fd2c389ed12e5b" + [[package]] name = "rustc_version" version = "0.4.0" @@ -2917,15 +2928,6 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" -[[package]] -name = "spin" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dccf47db1b41fa1573ed27ccf5e08e3ca771cb994f776668c5ebda893b248fc" -dependencies = [ - "lock_api", -] - [[package]] name = "spki" version = "0.5.4" @@ -2949,9 +2951,9 @@ dependencies = [ [[package]] name = "sqlx" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9249290c05928352f71c077cc44a464d880c63f26f7534728cca008e135c0428" +checksum = "f8de3b03a925878ed54a954f621e64bf55a3c1bd29652d0d1a17830405350188" dependencies = [ "sqlx-core", "sqlx-macros", @@ -2959,9 +2961,9 @@ dependencies = [ [[package]] name = "sqlx-core" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcbc16ddba161afc99e14d1713a453747a2b07fc097d2009f4c300ec99286105" +checksum = "fa8241483a83a3f33aa5fff7e7d9def398ff9990b2752b6c6112b83c6d246029" dependencies = [ "ahash", "atoi", @@ -2974,10 +2976,8 @@ dependencies = [ "dotenvy", "either", "event-listener", - "flume", "futures-channel", "futures-core", - "futures-executor", "futures-intrusive", "futures-util", "generic-array", @@ -2986,7 +2986,6 @@ dependencies = [ "indexmap", "itoa 1.0.6", "libc", - "libsqlite3-sys", "log", "memchr", "num-bigint", @@ -3007,9 +3006,9 @@ dependencies = [ [[package]] name = "sqlx-macros" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b850fa514dc11f2ee85be9d055c512aa866746adfacd1cb42d867d68e6a5b0d9" +checksum = "9966e64ae989e7e575b19d7265cb79d7fc3cbbdf179835cb0d716f294c2049c9" dependencies = [ "dotenvy", "either", @@ -3026,9 +3025,9 @@ dependencies = [ [[package]] name = "sqlx-rt" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24c5b2d25fa654cc5f841750b8e1cdedbe21189bf9a9382ee90bfa9dd3562396" +checksum = "804d3f245f894e61b1e6263c84b23ca675d96753b5abfd5cc8597d86806e8024" dependencies = [ "async-native-tls", "async-std", @@ -3198,7 +3197,7 @@ version = "1.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fe7e0f1d535e7cbbbab43c82be4fc992b84f9156c16c160955617e0260ebc449" dependencies = [ - "anyhow", + "anyhow 1.0.70", "cocoa", "dirs-next", "embed_plist", @@ -3245,7 +3244,7 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8807c85d656b2b93927c19fe5a5f1f1f348f96c2de8b90763b3c2d561511f9b4" dependencies = [ - "anyhow", + "anyhow 1.0.70", "cargo_toml", "heck 0.4.1", "json-patch", diff --git a/lab2/src-tauri/Cargo.toml b/lab2/src-tauri/Cargo.toml index 84a6ade..224d565 100644 --- a/lab2/src-tauri/Cargo.toml +++ b/lab2/src-tauri/Cargo.toml @@ -15,11 +15,11 @@ tauri-build = { version = "1.2", features = [] } [dependencies] tauri = { version = "1.2", features = ["shell-open"] } serde = { version = "1.0", features = ["derive"] } -sqlx = { version = "0.6.2", features = ["runtime-async-std-native-tls", "mysql", "sqlite", "macros"] } +sqlx = { version = "0.6.3", features = ["runtime-async-std-native-tls", "mysql"] } async-std = {version = "1.12.0", features = ["attributes"] } serde_json = "1.0" dotenv = "0.15.0" -anyhow = "1.0.70" +anyhow = { git = "https://github.com/Seeker14491/anyhow-tauri.git", features = ["backtrace"] } [features] # this feature is used for production builds or when `devPath` points to the filesystem diff --git a/lab2/src-tauri/src/api.rs b/lab2/src-tauri/src/api.rs new file mode 100644 index 0000000..b12b3ab --- /dev/null +++ b/lab2/src-tauri/src/api.rs @@ -0,0 +1,63 @@ +use crate::{models::{Manager, Factory, ManagerData, FactoryData, Id}, manager_repo, factory_repo}; +use sqlx::{Pool, MySql}; +use tauri::State; + +use anyhow::Result; + +pub struct Database { + pub pool: Pool +} + +#[tauri::command] +pub async fn add_manager_factory( + factory: FactoryData, + manager: ManagerData, + db: State<'_, Database> + ) -> Result<(Id, Id)> { + let mut tx = db.pool.begin().await?; + let manager_id = manager_repo::add(&mut tx, &manager).await?; + let factory_id = factory_repo::add(&mut tx, manager_id, &factory).await?; + tx.commit().await?; + Ok((factory_id, manager_id)) +} + +#[tauri::command] +pub async fn delete_factory(id: Id, db: State<'_, Database>) -> Result<()> { + let mut tx = db.pool.begin().await?; + factory_repo::delete(&mut tx, id).await?; + tx.commit().await?; + Ok(()) +} + +#[tauri::command] +pub async fn update_factory(id: Id, factory: FactoryData, db: State<'_, Database>) -> Result<()> { + let mut tx = db.pool.begin().await?; + factory_repo::update(&mut tx, id, &factory).await?; + tx.commit().await?; + Ok(()) +} + +#[tauri::command] +pub async fn update_manager(id: Id, manager: ManagerData, db: State<'_, Database>) -> Result<()> { + let mut tx = db.pool.begin().await?; + manager_repo::update(&mut tx, id, &manager).await?; + tx.commit().await?; + Ok(()) +} + +#[tauri::command] +pub async fn list_managers(db: State<'_, Database>) -> Result> { + let mut tx = db.pool.begin().await?; + let managers = manager_repo::list(&mut tx).await?; + tx.commit().await?; + Ok(managers) +} + +#[tauri::command] +pub async fn list_factories(db: State<'_, Database>) -> Result> { + let mut tx = db.pool.begin().await?; + let factories = factory_repo::list(&mut tx).await?; + tx.commit().await?; + Ok(factories) +} + diff --git a/lab2/src-tauri/src/factory_repo.rs b/lab2/src-tauri/src/factory_repo.rs new file mode 100644 index 0000000..faa152d --- /dev/null +++ b/lab2/src-tauri/src/factory_repo.rs @@ -0,0 +1,83 @@ +use crate::models::{Id, FactoryData, Factory}; +use anyhow::Result; +use sqlx::{Transaction, MySql}; + +type MySqlTransaction<'a> = Transaction<'a, MySql>; + +pub async fn create_table(tx: &mut MySqlTransaction<'_>) -> Result<()> { + sqlx::query(r#" + CREATE TABLE IF NOT EXISTS `factory` ( + ID bigint unsigned NOT NULL, + NAME varchar(255) NOT NULL, + LOCATION varchar(255) NOT NULL, + FLOOR_SIZE float NOT NULL, + FK_MANAGER_ID bigint unsigned NOT NULL, + + PRIMARY KEY(ID), + UNIQUE(FK_MANAGER_ID), + FOREIGN KEY(FK_MANAGER_ID) REFERENCES MANAGER (ID) ON DELETE CASCADE + );"#).execute(tx).await?; + Ok(()) +} + +pub async fn add(tx: &mut MySqlTransaction<'_>, manager_id: Id, factory: &FactoryData) -> Result { + let id = sqlx::query(r#" + INSERT INTO `factory` + (`NAME`, `LOCATION`, `FLOOR_SIZE`, `FK_MANAGER_ID`) + VALUES + (?, ?, ?, ?) + "#) + .bind(&factory.name) + .bind(&factory.location) + .bind(factory.floor_size) + .bind(manager_id) + .execute(&mut *tx).await? + .last_insert_id(); + + Ok(id) +} + +pub async fn list(tx: &mut MySqlTransaction<'_>) -> Result> { + let factories = sqlx::query_as::<_, Factory>( + r#" + SELECT + ID as id, + NAME as name, + LOCATION as location, + FLOOR_SIZE as floor_size, + FK_MANAGER_ID as manager_id + FROM `factory` + "#).fetch_all(tx).await?; + + Ok(factories) +} + +pub async fn delete(tx: &mut MySqlTransaction<'_>, id: Id) -> Result<()> { + sqlx::query("DELETE FROM `manager` WHERE ID = (SELECT FK_MANAGER_ID FROM `factory` WHERE ID = ?)") + .bind(id) + .execute(&mut *tx).await?; + + sqlx::query("DELETE FROM `factory` WHERE ID = ?") + .bind(id) + .execute(&mut *tx).await?; + + Ok(()) +} + +pub async fn update(tx: &mut MySqlTransaction<'_>, id: Id, factory: &FactoryData) -> Result<()> { + sqlx::query( + r#" + UPDATE `factory` SET + NAME = ?, + LOCATION = ?, + FLOOR_SIZE = ? + WHERE ID = ? + "#) + .bind(&factory.name) + .bind(&factory.location) + .bind(factory.floor_size) + .bind(id) + .execute(tx).await?; + + Ok(()) +} \ No newline at end of file diff --git a/lab2/src-tauri/src/main.rs b/lab2/src-tauri/src/main.rs index e88d3f0..542f00d 100644 --- a/lab2/src-tauri/src/main.rs +++ b/lab2/src-tauri/src/main.rs @@ -1,135 +1,62 @@ // Prevents additional console window on Windows in release, DO NOT REMOVE!! #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] +mod models; +mod factory_repo; +mod manager_repo; +mod api; + use std::{env, process::exit}; use dotenv::dotenv; -use serde::{Serialize, Deserialize}; -use sqlx::{SqlitePool, sqlite::SqlitePoolOptions, Pool, Sqlite, Row}; -use tauri::State; +use models::{ManagerData, FactoryData}; +use sqlx::{Pool, MySql, mysql::MySqlPoolOptions, Row}; -// TODO: use transaction to revert changes, if failed to insert rows +use api::*; +use anyhow::Result; -type Id = i64; - -#[derive(Serialize)] -struct Manager { - id: Id, - first_name: String, - surname: String, - phone_number: Option, - title: String, - email: Option +async fn setup_tables(pool: &Pool) -> Result<()> { + let mut tx = pool.begin().await?; + manager_repo::create_table(&mut tx).await?; + factory_repo::create_table(&mut tx).await?; + tx.commit().await?; + Ok(()) } -#[derive(Deserialize)] -struct ManagerData { - first_name: String, - surname: String, - phone_number: Option, - title: String, - email: Option +async fn drop_all_tables(pool: &Pool) -> Result<()> { + let tables = sqlx::query("SHOW TABLES").fetch_all(pool).await?; + let names: Vec<_> = tables.into_iter().map(|row| row.get::(0)).collect(); + sqlx::query(&format!("DROP TABLE {}", names.join(", "))) + .execute(pool) + .await?; + + Ok(()) } -#[derive(Serialize)] -struct Factory { - id: Id, - name: String, - location: String, - floor_size: f64, - manager_id: Id -} -#[derive(Deserialize)] -struct FactoryData { - name: String, - location: String, - floor_size: f64 +async fn enable_foreign_key_checks(pool: &Pool) -> Result<()> { + sqlx::query("SET GLOBAL FOREIGN_KEY_CHECKS=1").execute(pool).await?; + Ok(()) } -struct Database { - pool: Pool -} +async fn add_test_data(pool: &Pool) -> Result<()> { + let mut tx = pool.begin().await?; + let manager = ManagerData { + first_name: "Rokas".into(), + surname: "Puzonas".into(), + phone_number: Some("+123456789".into()), + title: "Big man".into(), + email: Some("bigman@pp.com".into()) + }; + let factory = FactoryData { + name: "Big factory".into(), + location: "idk".into(), + floor_size: 10.0, + }; + let id = manager_repo::add(&mut tx, &manager).await?; + factory_repo::add(&mut tx, id, &factory).await?; -struct EntryID { - id: Id -} - -async fn add_manager(db: &Database, manager: &ManagerData) -> anyhow::Result { - let entry = sqlx::query_as!( - EntryID, - r#" - INSERT INTO manager - (`FIRST_NAME`, `SURNAME`, `PHONE_NUMBER`, `TITLE`, `EMAIL`) - VALUES - (?, ?, ?, ?, ?) - RETURNING ID as id - "#, - manager.first_name, - manager.surname, - manager.phone_number, - manager.title, - manager.email - ).fetch_one(&db.pool).await?; - Ok(entry.id) -} - -async fn add_factory(db: &Database, manager_id: Id, factory: &FactoryData) -> anyhow::Result { - let entry = sqlx::query_as!( - EntryID, - r#" - INSERT INTO factory - (`NAME`, `LOCATION`, `FLOOR_SIZE`, `FK_MANAGER_ID`) - VALUES - (?, ?, ?, ?) - RETURNING ID as id - "#, - factory.name, - factory.location, - factory.floor_size, - manager_id - ).fetch_one(&db.pool).await?; - Ok(entry.id) -} - -async fn list_factories_db(db: &Database) -> anyhow::Result> { - let factories = sqlx::query_as!( - Factory, - r#" - SELECT ID as id, NAME as name, LOCATION as location, FLOOR_SIZE as floor_size, FK_MANAGER_ID as manager_id FROM factory - "#, - ).fetch_all(&db.pool).await?; - Ok(factories) -} - -async fn list_managers_db(db: &Database) -> anyhow::Result> { - let managers = sqlx::query_as!( - Manager, - r#" - SELECT ID as id, FIRST_NAME as first_name, SURNAME as surname, TITLE as title, EMAIL as email, PHONE_NUMBER as phone_number FROM manager - "#, - ).fetch_all(&db.pool).await?; - Ok(managers) -} - -#[tauri::command] -async fn add_manager_factory( - factory: FactoryData, - manager: ManagerData, - db: State<'_, Database> - ) -> Result<(Id, Id), ()> { - let manager_id = add_manager(&db, &manager).await.unwrap(); - let factory_id = add_factory(&db, manager_id, &factory).await.unwrap(); - Ok((factory_id, manager_id)) -} - -#[tauri::command] -async fn list_managers(db: State<'_, Database>) -> Result, ()> { - Ok(list_managers_db(&db).await.unwrap()) // TODO: handle .unwrap() -} - -#[tauri::command] -async fn list_factories(db: State<'_, Database>) -> Result, ()> { - Ok(list_factories_db(&db).await.unwrap()) // TODO: handle .unwrap() + tx.commit().await?; + Ok(()) } #[async_std::main] @@ -144,18 +71,27 @@ async fn main() { Ok(url) => url, }; - let pool = SqlitePoolOptions::new() + let pool = MySqlPoolOptions::new() .max_connections(10) .connect(&database_url) .await .unwrap(); + enable_foreign_key_checks(&pool).await.expect("Enable foreign key checks"); + drop_all_tables(&pool).await.unwrap(); // For testing purposes + setup_tables(&pool).await.expect("Setup tables"); + + add_test_data(&pool).await.expect("Add test data"); + tauri::Builder::default() .manage(Database { pool }) .invoke_handler(tauri::generate_handler![ list_factories, list_managers, - add_manager_factory + add_manager_factory, + delete_factory, + update_factory, + update_manager ]) .run(tauri::generate_context!()) .expect("error while running tauri application"); diff --git a/lab2/src-tauri/src/manager_repo.rs b/lab2/src-tauri/src/manager_repo.rs new file mode 100644 index 0000000..fd2bd48 --- /dev/null +++ b/lab2/src-tauri/src/manager_repo.rs @@ -0,0 +1,79 @@ + +use anyhow::Result; +use sqlx::{Transaction, MySql}; + +use crate::models::{ManagerData, Id, Manager}; + +type MySqlTransaction<'a> = Transaction<'a, MySql>; + +pub async fn create_table(tx: &mut MySqlTransaction<'_>) -> Result<()> { + sqlx::query(r#" + CREATE TABLE IF NOT EXISTS `manager` ( + ID bigint unsigned NOT NULL, + FIRST_NAME varchar(255) NOT NULL, + SURNAME varchar(255) NOT NULL, + PHONE_NUMBER varchar(255) NULL, + TITLE varchar(255) NOT NULL, + EMAIL varchar(255) NULL, + PRIMARY KEY(ID) + );"#) + .execute(tx).await?; + Ok(()) +} + +pub async fn add(tx: &mut MySqlTransaction<'_>, manager: &ManagerData) -> Result +{ + let id = sqlx::query(r#" + INSERT INTO `manager` + (`FIRST_NAME`, `SURNAME`, `PHONE_NUMBER`, `TITLE`, `EMAIL`) + VALUES + (?, ?, ?, ?, ?) + "#) + .bind(&manager.first_name) + .bind(&manager.surname) + .bind(&manager.phone_number) + .bind(&manager.title) + .bind(&manager.email) + .execute(&mut *tx).await? + .last_insert_id(); + + Ok(id) +} + +pub async fn list(tx: &mut MySqlTransaction<'_>) -> Result> { + let managers = sqlx::query_as::<_, Manager>( + r#" + SELECT + ID as id, + FIRST_NAME as first_name, + SURNAME as surname, + TITLE as title, + EMAIL as email, + PHONE_NUMBER as phone_number + FROM `manager` + "#).fetch_all(tx).await?; + + Ok(managers) +} + +pub async fn update(tx: &mut MySqlTransaction<'_>, id: Id, manager: &ManagerData) -> Result<()> { + sqlx::query( + r#" + UPDATE `manager` SET + FIRST_NAME = ?, + SURNAME = ?, + TITLE = ?, + EMAIL = ?, + PHONE_NUMBER = ? + WHERE ID = ? + "#) + .bind(&manager.first_name) + .bind(&manager.surname) + .bind(&manager.title) + .bind(&manager.email) + .bind(&manager.phone_number) + .bind(id) + .execute(tx).await?; + + Ok(()) +} \ No newline at end of file diff --git a/lab2/src-tauri/src/models.rs b/lab2/src-tauri/src/models.rs new file mode 100644 index 0000000..ec68da1 --- /dev/null +++ b/lab2/src-tauri/src/models.rs @@ -0,0 +1,39 @@ +use serde::{Serialize, Deserialize}; +use sqlx::FromRow; + +pub type Id = u64; + +#[derive(Debug, Serialize, FromRow)] +pub struct Manager { + pub id: Id, + pub first_name: String, + pub surname: String, + pub phone_number: Option, + pub title: String, + pub email: Option +} + +#[derive(Debug, Deserialize)] +pub struct ManagerData { + pub first_name: String, + pub surname: String, + pub phone_number: Option, + pub title: String, + pub email: Option +} + +#[derive(Debug, Serialize, FromRow)] +pub struct Factory { + pub id: Id, + pub name: String, + pub location: String, + pub floor_size: f32, + pub manager_id: Id +} + +#[derive(Debug, Deserialize)] +pub struct FactoryData { + pub name: String, + pub location: String, + pub floor_size: f32 +} \ No newline at end of file diff --git a/lab2/src/App.svelte b/lab2/src/App.svelte index 641fb25..4ab6150 100644 --- a/lab2/src/App.svelte +++ b/lab2/src/App.svelte @@ -9,7 +9,7 @@ let isSideNavOpen = false; -
+
([]) export let managers = writable([]) +function remove_manager_by_id(id: number) { + managers.update(managers => { + var index = managers.findIndex(m => m.id == id) + if (index != -1) { + managers.splice(index, 1) + } + return managers + }) +} + export async function list_factories(): Promise { return invoke("list_factories") } @@ -63,10 +73,45 @@ export async function add_manager_factory(factory: FactoryData, manager: Manager return [factory_id, manager_id] } -export async function edit_manager(id: number, manager: ManagerData): Promise { - // TODO: invoke("edit_manager") +export async function update_manager(id: number, manager: ManagerData): Promise { + invoke("update_manager", { id, manager }) + + managers.update((managers) => { + var index = managers.findIndex(f => f.id == id) + if (index != -1) { + managers[index] = { + ...managers[index], + ...manager + } + } + return managers + }) } -export async function edit_factory(id: number, factory: FactoryData): Promise { - // TODO: invoke("edit_factory") +export async function update_factory(id: number, factory: FactoryData): Promise { + invoke("update_factory", { id, factory }) + + factories.update((factories) => { + var index = factories.findIndex(f => f.id == id) + if (index != -1) { + factories[index] = { + ...factories[index], + ...factory + } + } + return factories + }) +} + +export async function delete_factory(id: number): Promise { + invoke("delete_factory", { id }) + + factories.update((factories) => { + var index = factories.findIndex(f => f.id == id) + if (index != -1) { + remove_manager_by_id(factories[index].manager_id) + factories.splice(index, 1) + } + return factories + }) } \ No newline at end of file diff --git a/lab2/src/routes/Factories-Managers.svelte b/lab2/src/routes/Factories-Managers.svelte index 98938d6..5481afb 100644 --- a/lab2/src/routes/Factories-Managers.svelte +++ b/lab2/src/routes/Factories-Managers.svelte @@ -13,7 +13,7 @@ import Edit from "carbon-icons-svelte/lib/Edit.svelte" import ManagerForm from "../lib/ManagerForm.svelte" import FactoryForm from "../lib/FactoryForm.svelte" - import { add_manager_factory, edit_factory, edit_manager, factories, list_factories, list_managers, managers } from "../lib/api" + import { add_manager_factory, delete_factory, update_factory, update_manager, factories, list_factories, list_managers, managers } from "../lib/api" import { onMount } from 'svelte' var rows = [] @@ -48,6 +48,7 @@ let currentlyEditingId = undefined let showUpdateModal = factory_id => { + console.log(factory_id) currentlyEditingId = factory_id let factory = $factories.find(factory => factory.id == factory_id) @@ -75,6 +76,13 @@ let closeModal = () => { isModalShown = false } + + let deleteSelectedRows = async () => { + for (var id of selectedRowIds) { + await delete_factory(id) + } + selectedRowIds = [] + } { - rows = rows.filter((row) => !selectedRowIds.includes(row.id)); - selectedRowIds = []; - }} + on:click={deleteSelectedRows} > Delete @@ -138,7 +143,7 @@ factory.id == currentlyEditingId).manager_id - await edit_factory(currentlyEditingId, factoryData) // TODO: handle if failed - await edit_manager(manager_id, managerData) // TODO: handle if failed + await update_factory(currentlyEditingId, factoryData) // TODO: handle if failed + await update_manager(manager_id, managerData) // TODO: handle if failed } else { await add_manager_factory(factoryData, managerData) // TODO: handle error }