From 838830d2e6f8120fe233d23a42ceb99a2c44e468 Mon Sep 17 00:00:00 2001 From: Rokas Puzonas Date: Sun, 16 Apr 2023 02:23:59 +0300 Subject: [PATCH] add ability to assign process to factory --- lab2/.vscode/settings.json | 1 - lab2/src-tauri/Cargo.lock | 8 +- lab2/src-tauri/src/api.rs | 25 ++- lab2/src-tauri/src/factory_repo.rs | 70 ++++++- lab2/src-tauri/src/main.rs | 38 +++- lab2/src-tauri/src/process_repo.rs | 14 +- lab2/src/App.svelte | 5 +- lab2/src/lib/FactoryForm.svelte | 2 +- lab2/src/lib/MyDataTable.svelte | 46 ++--- lab2/src/lib/ProcessList.svelte | 86 +++++++++ lab2/src/lib/api.ts | 219 ++++++++++++---------- lab2/src/routes/Factories-Managers.svelte | 169 ++++++----------- lab2/src/routes/Processess.svelte | 2 +- 13 files changed, 416 insertions(+), 269 deletions(-) create mode 100644 lab2/src/lib/ProcessList.svelte diff --git a/lab2/.vscode/settings.json b/lab2/.vscode/settings.json index 05bd5e5..3ef0f03 100644 --- a/lab2/.vscode/settings.json +++ b/lab2/.vscode/settings.json @@ -1,6 +1,5 @@ { "rust-analyzer.linkedProjects": [ - ".\\src-tauri\\Cargo.toml", ".\\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 cc8c346..926e9ec 100644 --- a/lab2/src-tauri/Cargo.lock +++ b/lab2/src-tauri/Cargo.lock @@ -2410,9 +2410,9 @@ checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" [[package]] name = "proc-macro2" -version = "1.0.51" +version = "1.0.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d727cae5b39d21da60fa540906919ad737832fe0b1c165da3a34d6548c849d6" +checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435" dependencies = [ "unicode-ident", ] @@ -2428,9 +2428,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.23" +version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" +checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc" dependencies = [ "proc-macro2", ] diff --git a/lab2/src-tauri/src/api.rs b/lab2/src-tauri/src/api.rs index cbac816..fb4c407 100644 --- a/lab2/src-tauri/src/api.rs +++ b/lab2/src-tauri/src/api.rs @@ -1,7 +1,6 @@ use crate::{models::{Manager, Factory, ManagerData, FactoryData, Id, Process, ProcessData}, manager_repo, factory_repo, process_repo}; use sqlx::{Pool, MySql}; use tauri::State; - use anyhow::Result; pub struct Database { @@ -47,6 +46,30 @@ pub async fn delete_factory(id: Id, db: State<'_, Database>) -> Result<()> { Ok(()) } +#[tauri::command] +pub async fn list_factory_processess(id: Id, db: State<'_, Database>) -> Result> { + let mut tx = db.pool.begin().await?; + let processess = factory_repo::list_processess(&mut tx, id).await?; + tx.commit().await?; + Ok(processess) +} + +#[tauri::command] +pub async fn add_factory_process(factory_id: Id, process_id: Id, db: State<'_, Database>) -> Result<()> { + let mut tx = db.pool.begin().await?; + factory_repo::add_process(&mut tx, factory_id, process_id).await?; + tx.commit().await?; + Ok(()) +} + +#[tauri::command] +pub async fn delete_factory_process(factory_id: Id, process_id: Id, db: State<'_, Database>) -> Result<()> { + let mut tx = db.pool.begin().await?; + factory_repo::delete_process(&mut tx, factory_id, process_id).await?; + tx.commit().await?; + Ok(()) +} + // --------------------- Manager --------------------------- #[tauri::command] diff --git a/lab2/src-tauri/src/factory_repo.rs b/lab2/src-tauri/src/factory_repo.rs index 39e3dec..c4bec58 100644 --- a/lab2/src-tauri/src/factory_repo.rs +++ b/lab2/src-tauri/src/factory_repo.rs @@ -1,6 +1,6 @@ use crate::models::{Id, FactoryData, Factory}; use anyhow::Result; -use sqlx::{Transaction, MySql}; +use sqlx::{Transaction, MySql, Row}; type MySqlTransaction<'a> = Transaction<'a, MySql>; @@ -15,8 +15,18 @@ pub async fn create_table(tx: &mut MySqlTransaction<'_>) -> Result<()> { PRIMARY KEY(ID), UNIQUE(FK_MANAGER_ID), - FOREIGN KEY(FK_MANAGER_ID) REFERENCES MANAGER (ID) ON DELETE CASCADE - );"#).execute(tx).await?; + FOREIGN KEY(FK_MANAGER_ID) REFERENCES MANAGER (ID) + );"#).execute(&mut *tx).await?; + sqlx::query(r#" + CREATE TABLE `factory_supports_processes` ( + FK_PROCESS_ID bigint unsigned NOT NULL, + FK_FACTORY_ID bigint unsigned NOT NULL, + + PRIMARY KEY(FK_PROCESS_ID, FK_FACTORY_ID), + FOREIGN KEY(FK_PROCESS_ID) REFERENCES PROCESS (ID), + FOREIGN KEY(FK_FACTORY_ID) REFERENCES FACTORY (ID) + );"#) + .execute(&mut *tx).await?; Ok(()) } @@ -38,8 +48,7 @@ pub async fn add(tx: &mut MySqlTransaction<'_>, manager_id: Id, factory: &Factor } pub async fn list(tx: &mut MySqlTransaction<'_>) -> Result> { - let factories = sqlx::query_as::<_, Factory>( - r#" + let factories = sqlx::query_as::<_, Factory>(r#" SELECT ID as id, NAME as name, @@ -57,6 +66,10 @@ pub async fn delete(tx: &mut MySqlTransaction<'_>, id: Id) -> Result<()> { .bind(id) .execute(&mut *tx).await?; + sqlx::query("DELETE FROM `factory_supports_processes` WHERE FK_FACTORY_ID = ?") + .bind(id) + .execute(&mut *tx).await?; + sqlx::query("DELETE FROM `factory` WHERE ID = ?") .bind(id) .execute(&mut *tx).await?; @@ -65,8 +78,7 @@ pub async fn delete(tx: &mut MySqlTransaction<'_>, id: Id) -> Result<()> { } pub async fn update(tx: &mut MySqlTransaction<'_>, id: Id, factory: &FactoryData) -> Result<()> { - sqlx::query( - r#" + sqlx::query(r#" UPDATE `factory` SET NAME = ?, LOCATION = ?, @@ -80,4 +92,48 @@ pub async fn update(tx: &mut MySqlTransaction<'_>, id: Id, factory: &FactoryData .execute(tx).await?; Ok(()) +} + +pub async fn add_process(tx: &mut MySqlTransaction<'_>, factory_id: Id, process_id: Id) -> Result<()> { + sqlx::query(r#" + INSERT INTO `factory_supports_processes` + (`FK_FACTORY_ID`, `FK_PROCESS_ID`) + VALUES + (?, ?) + "#) + .bind(factory_id) + .bind(process_id) + .execute(&mut *tx).await?; + + Ok(()) +} + +pub async fn list_processess(tx: &mut MySqlTransaction<'_>, id: Id) -> Result> { + let processess = sqlx::query(r#" + SELECT + FK_PROCESS_ID + FROM `factory_supports_processes` + WHERE FK_FACTORY_ID = ? + "#) + .bind(id) + .fetch_all(tx).await?; + + let processess = processess.into_iter() + .map(|r| r.get(0)) + .collect(); + Ok(processess) +} + +pub async fn delete_process(tx: &mut MySqlTransaction<'_>, factory_id: Id, process_id: Id) -> Result<()> { + sqlx::query(r#" + DELETE FROM `factory_supports_processes` + WHERE + FK_FACTORY_ID = ? AND + FK_PROCESS_ID = ? + "#) + .bind(factory_id) + .bind(process_id) + .execute(&mut *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 3721b58..52f97df 100644 --- a/lab2/src-tauri/src/main.rs +++ b/lab2/src-tauri/src/main.rs @@ -11,16 +11,18 @@ use std::{env, process::exit}; use dotenv::dotenv; use models::{ManagerData, FactoryData, ProcessData}; -use sqlx::{Pool, MySql, mysql::MySqlPoolOptions, Row}; +use sqlx::{Pool, MySql, mysql::MySqlPoolOptions, Row, Transaction}; use api::*; use anyhow::Result; +type MySqlTransaction<'a> = Transaction<'a, MySql>; + 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?; process_repo::create_table(&mut tx).await?; + factory_repo::create_table(&mut tx).await?; tx.commit().await?; Ok(()) } @@ -37,13 +39,18 @@ async fn drop_all_tables(pool: &Pool) -> Result<()> { async fn set_foreign_key_checks(pool: &Pool, enable: bool) -> Result<()> { let query = match enable { - true => "SET GLOBAL FOREIGN_KEY_CHECKS=1", - false => "SET GLOBAL FOREIGN_KEY_CHECKS=0", + true => "SET FOREIGN_KEY_CHECKS=1", + false => "SET FOREIGN_KEY_CHECKS=0", }; sqlx::query(query).execute(pool).await?; Ok(()) } +async fn add_test_process(tx: &mut MySqlTransaction<'_>, process: ProcessData) -> Result<()> { + process_repo::add(tx, &process).await?; + Ok(()) +} + async fn add_test_data(pool: &Pool) -> Result<()> { let mut tx = pool.begin().await?; let manager = ManagerData { @@ -58,13 +65,23 @@ async fn add_test_data(pool: &Pool) -> Result<()> { location: "idk".into(), floor_size: 10.0, }; - let process = ProcessData { - name: "Certifuge 9000".into(), - size: 10.0 - }; let id = manager_repo::add(&mut tx, &manager).await?; factory_repo::add(&mut tx, id, &factory).await?; - process_repo::add(&mut tx, &process).await?; + + add_test_process(&mut tx, ProcessData { + name: "Certifuge 9000".into(), + size: 10.0 + }).await?; + + add_test_process(&mut tx, ProcessData { + name: "Certifuge 9001".into(), + size: 20.0 + }).await?; + + add_test_process(&mut tx, ProcessData { + name: "Certifuge 9002".into(), + size: 30.0 + }).await?; tx.commit().await?; Ok(()) @@ -103,6 +120,9 @@ async fn main() { list_factories, delete_factory, update_factory, + list_factory_processess, + add_factory_process, + delete_factory_process, list_managers, update_manager, diff --git a/lab2/src-tauri/src/process_repo.rs b/lab2/src-tauri/src/process_repo.rs index 101019d..f071d8a 100644 --- a/lab2/src-tauri/src/process_repo.rs +++ b/lab2/src-tauri/src/process_repo.rs @@ -15,16 +15,6 @@ pub async fn create_table(tx: &mut MySqlTransaction<'_>) -> Result<()> { PRIMARY KEY(ID) );"#) .execute(&mut *tx).await?; - sqlx::query(r#" - CREATE TABLE `factory_supports_processes` ( - FK_PROCESS_ID bigint unsigned NOT NULL, - FK_FACTORY_ID bigint unsigned NOT NULL, - - PRIMARY KEY(FK_PROCESS_ID, FK_FACTORY_ID), - FOREIGN KEY(FK_PROCESS_ID) REFERENCES PROCESS (ID), - FOREIGN KEY(FK_FACTORY_ID) REFERENCES FACTORY (ID) - );"#) - .execute(&mut *tx).await?; Ok(()) } @@ -63,6 +53,10 @@ pub async fn delete(tx: &mut MySqlTransaction<'_>, id: Id) -> Result<()> { .bind(id) .execute(&mut *tx).await?; + sqlx::query("DELETE FROM `factory_supports_processes` WHERE FK_PROCESS_ID = ?") + .bind(id) + .execute(&mut *tx).await?; + Ok(()) } diff --git a/lab2/src/App.svelte b/lab2/src/App.svelte index b71deb9..725236e 100644 --- a/lab2/src/App.svelte +++ b/lab2/src/App.svelte @@ -3,7 +3,7 @@ import { Header, Content, SideNav, SideNavItems, SideNavLink } from "carbon-components-svelte"; import Home from './routes/Home.svelte' import FactoriesManagers from './routes/Factories-Managers.svelte' - import { factories, list_factories, list_managers, list_processess, managers, processess } from "./lib/api"; + import { factories, factory_processess, list_factories, list_factory_processess, list_managers, list_processess, managers, processess } from "./lib/api"; import { onMount } from "svelte"; import Processess from "./routes/Processess.svelte"; import { Building, Calibrate } from "carbon-icons-svelte"; @@ -12,6 +12,9 @@ $managers = await list_managers() $factories = await list_factories() $processess = await list_processess() + for (var factory of $factories) { + $factory_processess[factory.id] = await list_factory_processess(factory.id) + } }) let isSideNavOpen = false; diff --git a/lab2/src/lib/FactoryForm.svelte b/lab2/src/lib/FactoryForm.svelte index 900dd74..2a708cd 100644 --- a/lab2/src/lib/FactoryForm.svelte +++ b/lab2/src/lib/FactoryForm.svelte @@ -1,6 +1,6 @@ + +
+
+ {#each processess as id} +
+ item.id == id || !processess.includes(item.id))} + /> +
+ {/each} + + +
+ {#if allProcessItems.length === processess.length} + +
+
+
\ No newline at end of file diff --git a/lab2/src/lib/api.ts b/lab2/src/lib/api.ts index 3f34117..f9e95ab 100644 --- a/lab2/src/lib/api.ts +++ b/lab2/src/lib/api.ts @@ -1,14 +1,8 @@ import { invoke } from '@tauri-apps/api/tauri' -import { writable } from 'svelte/store' +import { get, writable, type Writable } from 'svelte/store' + +export type Id = number -export interface Manager { - id: number, - first_name: string, - surname: string, - phone_number?: string, - title: string, - email?: string -} export interface ManagerData { first_name: string, surname: string, @@ -16,42 +10,63 @@ export interface ManagerData { title: string, email?: string } - -export interface Factory { - id: number, - name: string, - location: string, - floor_size: number, - manager_id: number +export interface Manager extends ManagerData { + id: Id } + export interface FactoryData { name: string, location: string, floor_size: number } - -export interface Process { - id: number, - name: string, - size: number +export interface Factory extends FactoryData { + id: Id, + manager_id: Id } + export interface ProcessData { name: string, size: number } +export interface Process extends ProcessData { + id: Id +} -export let factories = writable([]) -export let managers = writable([]) -export let processess = writable([]) +export let factory_processess = writable>([]) +export let factories = writable([]) +export let managers = writable([]) +export let processess = writable([]) + +function add_object(objects: Writable, object: T) { + objects.update((objects) => { + objects.push(object) + return objects + }) +} + +function update_object(objects: Writable, index: number, updates: Partial) { + if (index == -1) return + + objects.update((objects) => { + const obj = objects[index] + for (var key in updates) { + obj[key] = updates[key] + } + return objects + }) +} + +function remove_object(objects: Writable, index: number) { + if (index == -1) return + + objects.update((objects) => { + objects.splice(index, 1) + return objects + }) +} 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 - }) + remove_object(managers, get(managers).findIndex(m => m.id == id)) } export async function list_factories(): Promise { @@ -66,82 +81,59 @@ export async function list_processess(): Promise { return invoke("list_processess") } +export async function list_factory_processess(id: number): Promise { + return invoke("list_factory_processess", { id }) +} + // Result -> Promise<[factory_id, manager_id]> export async function add_manager_factory(factory: FactoryData, manager: ManagerData): Promise<[number, number]> { // TODO: For now always assume success // TODO: handle error let [factory_id, manager_id] = await invoke<[number, number]>("add_manager_factory", { factory, manager }) - factories.update((factories) => { - factories.push({ - id: factory_id, - manager_id, - ...factory - }) - return factories + add_object(factories, { + id: factory_id, + manager_id, + ...factory }) - managers.update((managers) => { - managers.push({ id: manager_id, ...manager }) - return managers + add_object(managers, { + id: manager_id, + ...manager }) return [factory_id, manager_id] } export async function update_manager(id: number, manager: ManagerData): Promise { - invoke("update_manager", { id, manager }) + await 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 - }) + const index = get(managers).findIndex(f => f.id == id) + update_object(managers, index, manager) } export async function update_factory(id: number, factory: FactoryData): Promise { - invoke("update_factory", { id, factory }) + await 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 - }) + const index = get(factories).findIndex(f => f.id == id) + update_object(factories, index, factory) } export async function delete_factory(id: number): Promise { - invoke("delete_factory", { id }) + await 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 - }) + const index = get(factories).findIndex(f => f.id == id) + if (index != -1) { + var manager_id = factories[index] + remove_object(factories, index) + remove_manager_by_id(manager_id) + } } export async function delete_process(id: number): Promise { - invoke("delete_process", { id }) + await invoke("delete_process", { id }) - processess.update((processess) => { - var index = processess.findIndex(f => f.id == id) - if (index != -1) { - // TODO: Remove from associated factories - processess.splice(index, 1) - } - return processess - }) + const index = get(processess).findIndex(f => f.id == id) + remove_object(processess, index) } export async function add_process(process: ProcessData): Promise { @@ -149,28 +141,63 @@ export async function add_process(process: ProcessData): Promise { // TODO: handle error let id = await invoke("add_process", { process }) - processess.update((processess) => { - processess.push({ - id, - ...process - }) - return processess + add_object(processess, { + id, + ...process }) return id } export async function update_process(id: number, process: ProcessData): Promise { - invoke("update_process", { id, process }) + await invoke("update_process", { id, process }) - processess.update((processess) => { - var index = processess.findIndex(f => f.id == id) - if (index != -1) { - processess[index] = { - ...processess[index], - ...process - } + var index = get(processess).findIndex(f => f.id == id) + update_object(processess, index, process) +} + +export async function add_factory_processess(factory_id: Id, process_ids: Id[]): Promise { + for (var processId of process_ids) { + await invoke("add_factory_process", { factoryId: factory_id, processId }) + } + + factory_processess.update((factory_processess) => { + if (factory_processess[factory_id] == undefined) { + factory_processess[factory_id] = [] } - return processess + for (var process_id of process_ids) { + factory_processess[factory_id].push(process_id) + } + return factory_processess + }) +} + +export async function update_factory_processess(factory_id: Id, process_ids: Id[]): Promise { + let current = get(factory_processess)[factory_id] + + let added = process_ids.filter(id => !current.includes(id)) + let removed = current.filter(id => !process_ids.includes(id)) + + for (var processId of added) { + await invoke("add_factory_process", { factoryId: factory_id, processId }) + } + + for (var processId of removed) { + await invoke("delete_factory_process", { factoryId: factory_id, processId }) + } + + factory_processess.update((factory_processess) => { + if (factory_processess[factory_id] == undefined) { + factory_processess[factory_id] = [] + } + + var processess = factory_processess[factory_id] + for (var process_id of added) { + processess.push(process_id) + } + for (var process_id of removed) { + processess.splice(processess.findIndex(id => id === process_id), 1) + } + return factory_processess }) } \ No newline at end of file diff --git a/lab2/src/routes/Factories-Managers.svelte b/lab2/src/routes/Factories-Managers.svelte index b695a1c..9d8d964 100644 --- a/lab2/src/routes/Factories-Managers.svelte +++ b/lab2/src/routes/Factories-Managers.svelte @@ -1,18 +1,9 @@ - { + let [factory_id, _] = await add_manager_factory(factoryData, managerData) + await add_factory_processess(factory_id, processess) + }} + on:update={async (event) => { + let factory_id = event.detail + let manager_id = $factories.find(factory => factory.id == factory_id).manager_id + await update_factory(factory_id, factoryData) + await update_manager(manager_id, managerData) + await update_factory_processess(factory_id, processess) + }} + on:delete={async (event) => { + let ids = event.detail + for (var id of ids) { + await delete_factory(id) + } + }} headers={[ { key: "factory_name", value: "Factory" }, { key: "factory_location", value: "Location" }, { key: "factory_floor_size", value: "Floor size" }, - { key: "manager_fullname", value: "Manager" }, - { key: "update_btn", empty: true, width: "5rem" }, + { key: "manager_fullname", value: "Manager" } ]} - {rows} > - - { - e.preventDefault(); - activeDelete = false; - }} - > - - - - - - - - - - {#if cell.key === "update_btn"} -