add updating and remove of factories/managers
This commit is contained in:
parent
e3dd339ffe
commit
4f50aee949
@ -1 +1,2 @@
|
||||
DATABASE_URL="sqlite:../database.sqlite"
|
||||
RUST_BACKTRACE=1
|
||||
DATABASE_URL="mysql://root@localhost/ice_cream"
|
5
lab2/.vscode/settings.json
vendored
Normal file
5
lab2/.vscode/settings.json
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"rust-analyzer.linkedProjects": [
|
||||
".\\src-tauri\\Cargo.toml"
|
||||
]
|
||||
}
|
137
lab2/src-tauri/Cargo.lock
generated
137
lab2/src-tauri/Cargo.lock
generated
@ -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",
|
||||
|
@ -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
|
||||
|
63
lab2/src-tauri/src/api.rs
Normal file
63
lab2/src-tauri/src/api.rs
Normal file
@ -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<MySql>
|
||||
}
|
||||
|
||||
#[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<Vec<Manager>> {
|
||||
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<Vec<Factory>> {
|
||||
let mut tx = db.pool.begin().await?;
|
||||
let factories = factory_repo::list(&mut tx).await?;
|
||||
tx.commit().await?;
|
||||
Ok(factories)
|
||||
}
|
||||
|
83
lab2/src-tauri/src/factory_repo.rs
Normal file
83
lab2/src-tauri/src/factory_repo.rs
Normal file
@ -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<Id> {
|
||||
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<Vec<Factory>> {
|
||||
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(())
|
||||
}
|
@ -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<String>,
|
||||
title: String,
|
||||
email: Option<String>
|
||||
async fn setup_tables(pool: &Pool<MySql>) -> 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<String>,
|
||||
title: String,
|
||||
email: Option<String>
|
||||
async fn drop_all_tables(pool: &Pool<MySql>) -> Result<()> {
|
||||
let tables = sqlx::query("SHOW TABLES").fetch_all(pool).await?;
|
||||
let names: Vec<_> = tables.into_iter().map(|row| row.get::<String, usize>(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<MySql>) -> Result<()> {
|
||||
sqlx::query("SET GLOBAL FOREIGN_KEY_CHECKS=1").execute(pool).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
struct Database {
|
||||
pool: Pool<Sqlite>
|
||||
}
|
||||
async fn add_test_data(pool: &Pool<MySql>) -> 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<Id> {
|
||||
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<Id> {
|
||||
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<Vec<Factory>> {
|
||||
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<Vec<Manager>> {
|
||||
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<Vec<Manager>, ()> {
|
||||
Ok(list_managers_db(&db).await.unwrap()) // TODO: handle .unwrap()
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
async fn list_factories(db: State<'_, Database>) -> Result<Vec<Factory>, ()> {
|
||||
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");
|
||||
|
79
lab2/src-tauri/src/manager_repo.rs
Normal file
79
lab2/src-tauri/src/manager_repo.rs
Normal file
@ -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<Id>
|
||||
{
|
||||
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<Vec<Manager>> {
|
||||
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(())
|
||||
}
|
39
lab2/src-tauri/src/models.rs
Normal file
39
lab2/src-tauri/src/models.rs
Normal file
@ -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<String>,
|
||||
pub title: String,
|
||||
pub email: Option<String>
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct ManagerData {
|
||||
pub first_name: String,
|
||||
pub surname: String,
|
||||
pub phone_number: Option<String>,
|
||||
pub title: String,
|
||||
pub email: Option<String>
|
||||
}
|
||||
|
||||
#[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
|
||||
}
|
@ -9,7 +9,7 @@
|
||||
let isSideNavOpen = false;
|
||||
</script>
|
||||
|
||||
<Header href="/#/" company="ICE" platformName="Production" />
|
||||
<Header href="/#/" company="ICE" platformName="Production" bind:isSideNavOpen />
|
||||
<SideNav bind:isOpen={isSideNavOpen} rail>
|
||||
<SideNavItems>
|
||||
<SideNavLink
|
||||
|
@ -33,6 +33,16 @@ export interface FactoryData {
|
||||
export let factories = writable<Factory[]>([])
|
||||
export let managers = writable<Manager[]>([])
|
||||
|
||||
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<Factory[]> {
|
||||
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<void> {
|
||||
// TODO: invoke("edit_manager")
|
||||
export async function update_manager(id: number, manager: ManagerData): Promise<void> {
|
||||
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<void> {
|
||||
// TODO: invoke("edit_factory")
|
||||
export async function update_factory(id: number, factory: FactoryData): Promise<void> {
|
||||
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<void> {
|
||||
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
|
||||
})
|
||||
}
|
@ -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 = []
|
||||
}
|
||||
</script>
|
||||
|
||||
<DataTable
|
||||
@ -103,10 +111,7 @@
|
||||
<Button
|
||||
icon={TrashCan}
|
||||
disabled={selectedRowIds.length === 0}
|
||||
on:click={() => {
|
||||
rows = rows.filter((row) => !selectedRowIds.includes(row.id));
|
||||
selectedRowIds = [];
|
||||
}}
|
||||
on:click={deleteSelectedRows}
|
||||
>
|
||||
Delete
|
||||
</Button>
|
||||
@ -138,7 +143,7 @@
|
||||
|
||||
<Modal
|
||||
bind:open={isModalShown}
|
||||
modalHeading={currentlyEditingId ? "Edit factory & manager" : "Create factory & manager"}
|
||||
modalHeading={currentlyEditingId != undefined ? "Edit factory & manager" : "Create factory & manager"}
|
||||
primaryButtonText="Confirm"
|
||||
secondaryButtonText="Cancel"
|
||||
on:open
|
||||
@ -150,12 +155,12 @@
|
||||
return false
|
||||
}
|
||||
|
||||
if (currentlyEditingId) {
|
||||
if (currentlyEditingId != undefined) {
|
||||
// TODO: Handle if factory is not found
|
||||
let manager_id = $factories.find(factory => 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
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user