На маленьком плоту сквозь бури, дождь и грозы

Взяв только сны и грёзы, и детскую мечту
Я тихо уплыву, лишь в дом проникнет полночь
Чтоб рифмами наполнить мир, в котором я живу
master
Алексей Алексей 2026-06-03 19:23:50 +10:00
parent 748b06b421
commit 14c9038df2
4 changed files with 419 additions and 273 deletions

1
code/Cargo.lock generated
View File

@ -742,6 +742,7 @@ name = "code"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"bigdecimal",
"chrono", "chrono",
"dotenvy", "dotenvy",
"eframe", "eframe",

View File

@ -5,6 +5,7 @@ edition = "2024"
[dependencies] [dependencies]
anyhow = "1.0.102" anyhow = "1.0.102"
bigdecimal = "0.4.10"
chrono = { version = "0.4.44", features = ["serde"] } chrono = { version = "0.4.44", features = ["serde"] }
dotenvy = "0.15.7" dotenvy = "0.15.7"
eframe = "0.34.2" eframe = "0.34.2"

View File

@ -1,4 +1,4 @@
use std::{collections::HashMap, ops::Deref, sync::Arc}; use std::{collections::HashMap, ops::Deref, str::FromStr, sync::Arc};
use crate::{ use crate::{
database::DBOperator, database::DBOperator,
@ -153,11 +153,28 @@ impl Default for MainTabViewer {
rt, rt,
is_dark_theme: true, is_dark_theme: true,
interface_scale_ratio: 1.2, interface_scale_ratio: 1.2,
equipment_modal_state: ModalWinState {
is_open: false,
can_finish: false,
data: HashMap::from([
("id".to_owned(), String::new()),
("inv_number".to_owned(), String::new()),
("maintenance_date".to_owned(), String::new()),
("worker_id".to_owned(), String::new()),
]),
status: ModalStatus::Add,
},
} }
} }
} }
impl MainTabViewer { impl MainTabViewer {
fn show_equipment(&mut self, ui: &mut egui::Ui) { fn show_equipment(&mut self, ui: &mut egui::Ui) {
ui.horizontal(|ui| {
if ui.button("Добавить").clicked() {}
if ui.button("Редактировать").clicked() {}
if ui.button("Удалить").clicked() {}
});
let mut table = TableBuilder::new(ui) let mut table = TableBuilder::new(ui)
.striped(true) .striped(true)
.resizable(false) .resizable(false)
@ -167,6 +184,7 @@ impl MainTabViewer {
.column(Column::auto()) .column(Column::auto())
.column(Column::auto()) .column(Column::auto())
.column(Column::auto()) .column(Column::auto())
.sense(egui::Sense::click())
.header(30.0, |mut header| { .header(30.0, |mut header| {
header.col(|ui| { header.col(|ui| {
ui.heading("ID"); ui.heading("ID");
@ -202,6 +220,9 @@ impl MainTabViewer {
row.col(|ui| { row.col(|ui| {
ui.label(eq.maintenance_date.date_naive().to_string()); ui.label(eq.maintenance_date.date_naive().to_string());
}); });
if row.response().double_clicked() {
println!("I love Paris!");
}
}); });
} }
}); });
@ -278,7 +299,7 @@ impl egui_dock::TabViewer for MainTabViewer {
struct WorkerTabViewer { struct WorkerTabViewer {
db_oper: DBOperator, db_oper: DBOperator,
workers: Arc<RwLock<Option<Vec<Worker>>>>, workers: Arc<RwLock<Option<Vec<Worker>>>>,
positions: Arc<RwLock<Option<Vec<Position>>>>, positions: Arc<RwLock<Vec<Position>>>,
show_worker_add_modal: bool, show_worker_add_modal: bool,
show_worker_edit_modal: bool, show_worker_edit_modal: bool,
show_position_add_modal: bool, show_position_add_modal: bool,
@ -297,21 +318,10 @@ struct WorkerTabViewer {
edit_worker_is_fired: bool, edit_worker_is_fired: bool,
edit_worker_position: Position, edit_worker_position: Position,
equipment_modal_state: ModalWinState {
is_open: false,
can_finish: false,
data: HashMap::from([
("id".to_owned(), String::new()),
("inv_number".to_owned(), String::new()),
("maintenance_date".to_owned(), String::new()),
("worker_id".to_owned(), String::new()),
]),
status: ModalStatus::Add
},
rt: tokio::runtime::Runtime, rt: tokio::runtime::Runtime,
show_position_delete_modal: bool, show_position_delete_modal: bool,
delete_position: Position, delete_position: Position,
process_position_state: ModalWinState,
} }
impl WorkerTabViewer { impl WorkerTabViewer {
@ -322,10 +332,10 @@ impl WorkerTabViewer {
))); )));
} }
fn update_positions(&mut self) { fn update_positions(&mut self) {
self.positions = Arc::new(RwLock::new(Option::Some( self.positions = Arc::new(RwLock::new(
self.rt self.rt
.block_on(async { self.db_oper.get_position().await.unwrap() }), .block_on(async { self.db_oper.get_position().await.unwrap() }),
))); ));
} }
fn show_worker(&mut self, ui: &mut egui::Ui) { fn show_worker(&mut self, ui: &mut egui::Ui) {
@ -559,113 +569,181 @@ impl WorkerTabViewer {
fn show_position(&mut self, ui: &mut egui::Ui) { fn show_position(&mut self, ui: &mut egui::Ui) {
ui.horizontal(|ui| { ui.horizontal(|ui| {
if ui.button("Добавить").clicked() { if ui.button("Добавить").clicked() {
self.show_position_add_modal = true; // self.show_position_add_modal = true;
} self.process_position_state.is_open = true;
if ui.button("Удалить").clicked() { self.process_position_state.status = ModalStatus::Add;
self.show_position_delete_modal = true; self.process_position_state
self.delete_position = self.positions.read().clone().unwrap()[0].clone(); .data
self.update_positions(); .insert("id".into(), "0".to_string());
self.update_workers(); self.process_position_state
.data
.insert("name".into(), String::new());
self.process_position_state
.data
.insert("wage".into(), String::from("0"));
} }
if ui.button("Обновить").clicked() { if ui.button("Обновить").clicked() {
self.update_positions(); self.update_positions();
} }
}); });
for eq in self.positions.read().clone().unwrap().iter() { TableBuilder::new(ui)
ui.push_id(&eq.name, |ui| { .column(Column::auto())
egui::CollapsingHeader::new(&eq.name) .column(Column::auto())
.default_open(false) .column(Column::auto())
.show(ui, |ui| { .sense(egui::Sense::click())
ui.horizontal(|ui| { .header(30.0, |mut header| {
ui.monospace("Оклад:"); header.col(|ui| {
ui.label(format!("${}", eq.wage)); ui.heading("Название");
});
})
});
}
if self.show_position_add_modal {
egui::Modal::new("add_position".into()).show(ui.ctx(), |ui| {
if ui.button("Закрыть").clicked() {
self.show_position_add_modal = false;
}
let mut size = ui.spacing().interact_size;
size.x = 200.0;
egui::Grid::new("add_pos_grid").show(ui, |ui| {
ui.label("Название");
ui.add_sized(size, |ui: &mut egui::Ui| {
ui.text_edit_singleline(&mut self.add_position_name)
});
ui.end_row();
ui.label("Оклад");
ui.text_edit_singleline(&mut self.add_position_wage);
ui.end_row();
}); });
let resp = ui.add_enabled( header.col(|ui| {
self.add_position_name.len() > 0 && self.add_position_wage.len() > 0, ui.heading("Оклад");
egui::Button::new("Добавить"), });
); })
if resp.clicked() { .body(|mut body| {
self.rt.block_on(async { body.ui_mut().style_mut().interaction.selectable_labels = false;
self.db_oper for pos in self.positions.read().clone().iter() {
.add_position(Position { body.row(20.0, |mut row| {
id: 0, row.col(|ui| {
name: self.add_position_name.clone(), ui.label(pos.name.clone());
wage: BigDecimal::from( });
self.add_position_wage.trim().parse::<i32>().unwrap(), row.col(|ui| {
), ui.label(format!("${}", pos.wage));
}) });
.await row.col(|ui| {
.ok(); let resp = ui.add(egui::Button::new("Удалить"));
}); if resp.clicked() {
self.update_positions(); self.process_position_state.is_open = true;
self.show_position_add_modal = false; self.process_position_state.status = ModalStatus::Remove;
} self.process_position_state
}); .data
} .insert("id".into(), pos.id.to_string());
if self.show_position_delete_modal { self.process_position_state
egui::Modal::new("delete_position".into()).show(ui.ctx(), |ui| { .data
if ui.button("Закрыть").clicked() { .insert("name".into(), pos.name.clone());
self.show_position_delete_modal = false; self.process_position_state
} .data
egui::ComboBox::from_label("Должность") .insert("wage".into(), pos.wage.to_string());
.selected_text(&self.delete_position.name)
.show_ui(ui, |ui| {
self.rt.block_on(async {
for pos in self.positions.read().clone().unwrap().iter() {
ui.selectable_value(
&mut self.delete_position,
pos.clone(),
&pos.name,
);
} }
}); });
if row.response().double_clicked() {
self.process_position_state.is_open = true;
self.process_position_state.status = ModalStatus::Edit;
self.process_position_state
.data
.insert("id".into(), pos.id.to_string());
self.process_position_state
.data
.insert("name".into(), pos.name.clone());
self.process_position_state
.data
.insert("wage".into(), pos.wage.to_string());
}
}); });
let can_delete = self
.workers
.read()
.clone()
.unwrap()
.iter()
.find(|wrkr| wrkr.position.id == self.delete_position.id)
.iter()
.len()
== 0;
if !can_delete {
ui.label(
egui::RichText::new("Есть сотрудники с этой должностью")
.color(egui::Color32::YELLOW),
);
} }
let resp = ui.add_enabled(can_delete, egui::Button::new("Удалить")); });
if resp.clicked() {
self.rt.block_on(async { if self.process_position_state.is_open {
self.db_oper egui::Modal::new(egui::Id::new("process_worker_pos_modal")).show(ui.ctx(), |ui| {
.delete_position(self.delete_position.clone()) if ui.button("Закрыть").clicked() {
.await self.process_position_state.is_open = false;
.unwrap(); }
if self.process_position_state.status != ModalStatus::Remove {
egui::Grid::new("process_worker_pos_grid").show(ui, |ui| {
ui.label("Название");
let mut name = self.process_position_state.data.get_mut("name").unwrap();
let mut spacing = ui.spacing().interact_size;
spacing.x = 150.0;
ui.add_sized(spacing, |ui: &mut egui::Ui| ui.text_edit_singleline(name));
ui.end_row();
ui.label("Оклад");
let mut wage = self.process_position_state.data.get_mut("wage").unwrap();
ui.text_edit_singleline(wage);
}); });
} else {
ui.label("Вы уверены, что хотите удалить:");
ui.label(format!(
"{}?",
self.process_position_state.data["name"].clone()
));
}
let btext: String;
match self.process_position_state.status {
ModalStatus::Add => {
btext = String::from("Добавить");
self.process_position_state.can_finish = true;
}
ModalStatus::Edit => {
btext = String::from("Сохранить");
self.process_position_state.can_finish = true;
}
ModalStatus::Remove => {
self.process_position_state.can_finish = self
.workers
.read()
.clone()
.unwrap()
.iter()
.find(|wrkr| wrkr.position.id == self.delete_position.id)
.iter()
.len()
== 0;
btext = String::from("Удалить");
}
}
let button = ui.add_enabled(
self.process_position_state.can_finish,
egui::Button::new(btext),
);
if button.clicked() {
match self.process_position_state.status {
ModalStatus::Add => {
let pos = self.process_position_state.data.clone();
self.rt.block_on(async {
self.db_oper
.add_position(Position {
id: pos["id"].parse::<i32>().unwrap(),
name: pos["name"].clone(),
wage: bigdecimal::BigDecimal::from_str(
pos["wage"].as_str(),
)
.unwrap(),
})
.await;
})
}
ModalStatus::Edit => {
let pos = self.process_position_state.data.clone();
self.rt.block_on(async {
self.db_oper
.update_position(Position {
id: pos["id"].parse::<i32>().unwrap(),
name: pos["name"].clone(),
wage: bigdecimal::BigDecimal::from_str(
pos["wage"].as_str(),
)
.unwrap(),
})
.await;
})
}
ModalStatus::Remove => {
let pos = self.process_position_state.data.clone();
self.rt.block_on(async {
self.db_oper
.delete_position(Position {
id: pos["id"].parse::<i32>().unwrap(),
name: String::new(),
wage: BigDecimal::from(0),
})
.await;
});
}
}
self.update_positions();
self.process_position_state.is_open = false;
} }
}); });
} }
@ -700,13 +778,29 @@ impl Default for WorkerTabViewer {
fn default() -> Self { fn default() -> Self {
let rt = tokio::runtime::Runtime::new().unwrap(); let rt = tokio::runtime::Runtime::new().unwrap();
let db_oper = rt.block_on(async { DBOperator::new().await }); let db_oper = rt.block_on(async { DBOperator::new().await });
let positions = Arc::new(RwLock::new(
rt.block_on(async { db_oper.get_position().await.unwrap() }),
));
let mut pos_map: HashMap<String, String> = HashMap::new();
pos_map.extend(|| -> Vec<(String, String)> {
let pos = positions.read()[0].clone();
vec![
("id".to_string(), pos.id.to_string()),
("name".to_string(), pos.name.clone()),
("wage".to_string(), pos.wage.to_string()),
]
}());
Self { Self {
process_position_state: ModalWinState {
is_open: false,
can_finish: false,
data: pos_map,
status: ModalStatus::Add,
},
workers: Arc::new(RwLock::new(Option::Some( workers: Arc::new(RwLock::new(Option::Some(
rt.block_on(async { db_oper.get_workers().await.unwrap() }), rt.block_on(async { db_oper.get_workers().await.unwrap() }),
))), ))),
positions: Arc::new(RwLock::new(Option::Some( positions: positions,
rt.block_on(async { db_oper.get_position().await.unwrap() }),
))),
show_worker_add_modal: false, show_worker_add_modal: false,
show_worker_edit_modal: false, show_worker_edit_modal: false,
show_position_add_modal: false, show_position_add_modal: false,
@ -762,10 +856,6 @@ impl MaterialTabViewer {
self.process_material_state.is_open = true; self.process_material_state.is_open = true;
self.process_material_state.status = ModalStatus::Add; self.process_material_state.status = ModalStatus::Add;
} }
if ui.button("Редактировать").clicked() {
self.process_material_state.is_open = true;
self.process_material_state.status = ModalStatus::Edit;
}
if ui.button("Удалить").clicked() { if ui.button("Удалить").clicked() {
self.process_material_state.is_open = true; self.process_material_state.is_open = true;
self.process_material_state.status = ModalStatus::Remove; self.process_material_state.status = ModalStatus::Remove;
@ -784,11 +874,8 @@ impl MaterialTabViewer {
.column(Column::auto()) .column(Column::auto())
.column(Column::auto()) .column(Column::auto())
.column(Column::auto()) .column(Column::auto())
.column(Column::auto()) .sense(egui::Sense::click())
.header(20.0, |mut header| { .header(20.0, |mut header| {
header.col(|ui| {
ui.heading("ID");
});
header.col(|ui| { header.col(|ui| {
ui.heading("Название"); ui.heading("Название");
}); });
@ -800,12 +887,10 @@ impl MaterialTabViewer {
}); });
}) })
.body(|mut body| { .body(|mut body| {
body.ui_mut().style_mut().interaction.selectable_labels = false;
self.rt.block_on(async { self.rt.block_on(async {
for mat in self.mats.read().clone().iter() { for mat in self.mats.read().clone().iter() {
body.row(30.0, |mut row| { body.row(30.0, |mut row| {
row.col(|ui| {
ui.label(mat.id.to_string());
});
row.col(|ui| { row.col(|ui| {
ui.label(&mat.name); ui.label(&mat.name);
}); });
@ -815,6 +900,22 @@ impl MaterialTabViewer {
row.col(|ui| { row.col(|ui| {
ui.label(mat.quantity.to_string()); ui.label(mat.quantity.to_string());
}); });
if row.response().double_clicked() {
self.process_material_state.is_open = true;
self.process_material_state.status = ModalStatus::Edit;
self.process_material_state
.data
.insert("id".into(), mat.id.to_string());
self.process_material_state
.data
.insert("name".into(), mat.name.to_string());
self.process_material_state
.data
.insert("category_id".into(), mat.category.id.to_string());
self.process_material_state
.data
.insert("quantity".into(), mat.quantity.to_string());
}
}); });
} }
}) })
@ -1068,10 +1169,6 @@ impl MaterialTabViewer {
self.process_mcat_state.is_open = true; self.process_mcat_state.is_open = true;
self.process_mcat_state.status = ModalStatus::Add; self.process_mcat_state.status = ModalStatus::Add;
} }
if ui.button("Редактировать").clicked() {
self.process_mcat_state.is_open = true;
self.process_mcat_state.status = ModalStatus::Edit;
}
if ui.button("Удалить").clicked() { if ui.button("Удалить").clicked() {
self.process_mcat_state.is_open = true; self.process_mcat_state.is_open = true;
self.process_mcat_state.status = ModalStatus::Remove; self.process_mcat_state.status = ModalStatus::Remove;
@ -1197,6 +1294,7 @@ impl MaterialTabViewer {
.striped(true) .striped(true)
.column(Column::auto()) .column(Column::auto())
.column(Column::auto()) .column(Column::auto())
.sense(egui::Sense::click())
.header(20.0, |mut header| { .header(20.0, |mut header| {
header.col(|ui| { header.col(|ui| {
ui.heading("ID"); ui.heading("ID");
@ -1215,6 +1313,16 @@ impl MaterialTabViewer {
row.col(|ui| { row.col(|ui| {
ui.label(&mcat.name); ui.label(&mcat.name);
}); });
if row.response().double_clicked() {
self.process_mcat_state.is_open = true;
self.process_mcat_state.status = ModalStatus::Edit;
self.process_mcat_state
.data
.insert("id".into(), mcat.id.to_string());
self.process_mcat_state
.data
.insert("name".into(), mcat.name.clone());
}
}); });
} }
}); });
@ -1316,7 +1424,7 @@ impl egui_dock::TabViewer for RecipeTabViewer {
self.show_recipe_detail(ui); self.show_recipe_detail(ui);
} }
_ => { _ => {
ui.label("Hello!"); ui.label("Помогите!!");
} }
} }
} }

View File

@ -1,6 +1,5 @@
use sqlx::mysql::MySqlPoolOptions;
use sqlx::mysql::MySqlPool; use sqlx::mysql::MySqlPool;
use sqlx::mysql::MySqlPoolOptions;
use dotenvy::dotenv_override; use dotenvy::dotenv_override;
use std::collections::HashMap; use std::collections::HashMap;
@ -10,70 +9,91 @@ use std::env;
use crate::models::*; use crate::models::*;
use anyhow::anyhow; use anyhow::anyhow;
pub struct DBOperator{ pub struct DBOperator {
pool: MySqlPool, pool: MySqlPool,
} }
impl DBOperator{ impl DBOperator {
pub async fn new() -> Self{ pub async fn new() -> Self {
dotenv_override().ok(); dotenv_override().ok();
let db_url = env::var("DATABASE_URL").expect("DATABASE_URL установи!"); let db_url = env::var("DATABASE_URL").expect("DATABASE_URL установи!");
Self{pool: MySqlPool::connect(&db_url).await.unwrap()} Self {
pool: MySqlPool::connect(&db_url).await.unwrap(),
}
} }
pub async fn get_position(&self) -> Result<Vec<Position>, sqlx::Error>{ pub async fn get_position(&self) -> Result<Vec<Position>, sqlx::Error> {
let rets: Vec<Position> = sqlx::query_as:: <_, Position>("SELECT * FROM `position`").fetch_all(&self.pool).await?; let rets: Vec<Position> = sqlx::query_as::<_, Position>("SELECT * FROM `position`")
.fetch_all(&self.pool)
.await?;
Ok(rets) Ok(rets)
} }
pub async fn get_workers(&self) -> Result<Vec<Worker>, sqlx::Error>{ pub async fn get_workers(&self) -> Result<Vec<Worker>, sqlx::Error> {
let pre_rets: Vec<WorkerRow> = sqlx::query_as::<_, WorkerRow>("SELECT * FROM `worker`").fetch_all(&self.pool).await?; let pre_rets: Vec<WorkerRow> = sqlx::query_as::<_, WorkerRow>("SELECT * FROM `worker`")
let mut rets:Vec<Worker> = Vec::new(); .fetch_all(&self.pool)
.await?;
let mut rets: Vec<Worker> = Vec::new();
let pos = self.get_position().await.unwrap(); let pos = self.get_position().await.unwrap();
for worker in pre_rets{ for worker in pre_rets {
let mut ppos = Position::default(); let mut ppos = Position::default();
for position in pos.clone(){ for position in pos.clone() {
if position.id == worker.position_id{ if position.id == worker.position_id {
ppos = position.clone(); ppos = position.clone();
break; break;
} }
} }
rets.push(Worker{ id: worker.id, full_name: worker.full_name, hire_date: worker.hire_date, position: ppos, is_fired: worker.is_fired }); rets.push(Worker {
id: worker.id,
full_name: worker.full_name,
hire_date: worker.hire_date,
position: ppos,
is_fired: worker.is_fired,
});
} }
Ok(rets) Ok(rets)
} }
pub async fn get_equipment(&self) -> Result<Vec<Equipment>,sqlx::Error>{ pub async fn get_equipment(&self) -> Result<Vec<Equipment>, sqlx::Error> {
let pre_rets = sqlx::query_as::<_, EquipmentRow>("SELECT * FROM `equipment`").fetch_all(&self.pool).await?; let pre_rets = sqlx::query_as::<_, EquipmentRow>("SELECT * FROM `equipment`")
.fetch_all(&self.pool)
.await?;
let mut rets: Vec<Equipment> = Vec::new(); let mut rets: Vec<Equipment> = Vec::new();
let workers = self.get_workers().await?; let workers = self.get_workers().await?;
for eq in pre_rets{ for eq in pre_rets {
let mut pworker = Worker::default(); let mut pworker = Worker::default();
for worker in workers.clone(){ for worker in workers.clone() {
if worker.id == eq.worker_id{ if worker.id == eq.worker_id {
pworker = worker.clone(); pworker = worker.clone();
break; break;
} }
} }
rets.push(Equipment { id: eq.id, name: eq.name, inv_number: eq.inv_number, maintenance_date: eq.maintenance_date, worker: pworker }); rets.push(Equipment {
id: eq.id,
name: eq.name,
inv_number: eq.inv_number,
maintenance_date: eq.maintenance_date,
worker: pworker,
});
} }
Ok(rets) Ok(rets)
} }
pub async fn get_mcat(&self) -> Result<Vec<MaterialCategory>,sqlx::Error>{ pub async fn get_mcat(&self) -> Result<Vec<MaterialCategory>, sqlx::Error> {
let rets = sqlx::query_as::<_, MaterialCategory>("SELECT * FROM `material_category`").fetch_all(&self.pool).await?; let rets = sqlx::query_as::<_, MaterialCategory>("SELECT * FROM `material_category`")
.fetch_all(&self.pool)
.await?;
Ok(rets) Ok(rets)
} }
pub async fn get_materials(&self) -> Result<Vec<Material>, sqlx::Error>{ pub async fn get_materials(&self) -> Result<Vec<Material>, sqlx::Error> {
let mats = sqlx::query_as::<_,MaterialRow>("SELECT * FROM `material`").fetch_all(&self.pool).await?; let mats = sqlx::query_as::<_, MaterialRow>("SELECT * FROM `material`")
.fetch_all(&self.pool)
.await?;
let cats = self.get_mcat().await?; let cats = self.get_mcat().await?;
let cat_map : HashMap<_, MaterialCategory> = cats let cat_map: HashMap<_, MaterialCategory> =
.into_iter() cats.into_iter().map(|cat| (cat.id, cat)).collect();
.map(|cat| (cat.id, cat))
.collect();
let mut rets = Vec::with_capacity(mats.len()); let mut rets = Vec::with_capacity(mats.len());
for mat in mats{ for mat in mats {
let cat = cat_map let cat = cat_map
.get(&mat.category_id) .get(&mat.category_id)
.expect("Никто не знает как, но БД не смогла связать материал с его категорией. Заставьте разраба это починить.") .expect("Никто не знает как, но БД не смогла связать материал с его категорией. Заставьте разраба это починить.")
.clone(); .clone();
rets.push(Material{ rets.push(Material {
id: mat.id, id: mat.id,
name: mat.name, name: mat.name,
quantity: mat.quantity, quantity: mat.quantity,
@ -81,16 +101,22 @@ impl DBOperator{
}); });
} }
Ok(rets) Ok(rets)
} }
pub async fn check_worker(&self, worker: Worker) -> Result<bool, sqlx::Error>{ pub async fn check_worker(&self, worker: Worker) -> Result<bool, sqlx::Error> {
let ret = sqlx::query(&format!("SELECT * FROM `worker` WHERE full_name = {}, position_id = {}, hire_date = {}", worker.full_name, worker.position.id, worker.hire_date.to_string())).fetch_all(&self.pool).await?; let ret = sqlx::query(&format!(
if ret.len() > 0{ "SELECT * FROM `worker` WHERE full_name = {}, position_id = {}, hire_date = {}",
return Ok(true) worker.full_name,
worker.position.id,
worker.hire_date.to_string()
))
.fetch_all(&self.pool)
.await?;
if ret.len() > 0 {
return Ok(true);
} }
Ok(false) Ok(false)
} }
pub async fn add_worker(&self, worker: Worker) -> Result<bool,sqlx::Error>{ pub async fn add_worker(&self, worker: Worker) -> Result<bool, sqlx::Error> {
// sqlx::query!("INSERT INTO Brewery.worker (id, position_id, hire_date, is_fired, full_name) VALUES(0, ?, ?, ?, ?);",worker.position.id, worker.hire_date ,worker.is_fired,worker.full_name) // sqlx::query!("INSERT INTO Brewery.worker (id, position_id, hire_date, is_fired, full_name) VALUES(0, ?, ?, ?, ?);",worker.position.id, worker.hire_date ,worker.is_fired,worker.full_name)
match sqlx::query("INSERT INTO Brewery.worker (id, position_id, hire_date, is_fired, full_name) VALUES(0, ?, ?, ?, ?);") match sqlx::query("INSERT INTO Brewery.worker (id, position_id, hire_date, is_fired, full_name) VALUES(0, ?, ?, ?, ?);")
.bind(worker.position.id) .bind(worker.position.id)
@ -107,89 +133,79 @@ impl DBOperator{
} }
} }
} }
pub async fn add_position(&self, position: Position) -> Result<bool,sqlx::Error>{ pub async fn add_position(&self, position: Position) -> Result<bool, sqlx::Error> {
match sqlx::query("INSERT INTO Brewery.`position` (id, name, wage) VALUES(0, ?, ?);") match sqlx::query("INSERT INTO Brewery.`position` (id, name, wage) VALUES(0, ?, ?);")
.bind(position.name) .bind(position.name)
.bind(position.wage) .bind(position.wage)
.execute(&self.pool) .execute(&self.pool)
.await{ .await
Ok(_)=>{ {
Ok(true) Ok(_) => Ok(true),
}, Err(_) => Ok(false),
Err(_)=>{
Ok(false)
}
} }
} }
pub async fn add_material_category(&self, mat_cat: MaterialCategory) -> Result<bool, sqlx::Error>{ pub async fn add_material_category(
&self,
mat_cat: MaterialCategory,
) -> Result<bool, sqlx::Error> {
match sqlx::query("INSERT INTO Brewery.`material_category` (id, name) VALUES (0, ?)") match sqlx::query("INSERT INTO Brewery.`material_category` (id, name) VALUES (0, ?)")
.bind(mat_cat.name) .bind(mat_cat.name)
.execute(&self.pool) .execute(&self.pool)
.await{ .await
Ok(_)=>{ {
Ok(true) Ok(_) => Ok(true),
}, Err(_) => Ok(false),
Err(_)=>{
Ok(false)
}
} }
} }
pub async fn add_material(&self, mat: MaterialRow) -> Result<bool, sqlx::Error>{ pub async fn add_material(&self, mat: MaterialRow) -> Result<bool, sqlx::Error> {
match sqlx::query("INSERT INTO Brewery.material (id, name, quantity, category_id) VALUES(0, ?, ?, ?);") match sqlx::query(
"INSERT INTO Brewery.material (id, name, quantity, category_id) VALUES(0, ?, ?, ?);",
)
.bind(mat.name) .bind(mat.name)
.bind(mat.quantity) .bind(mat.quantity)
.bind(mat.category_id) .bind(mat.category_id)
.execute(&self.pool) .execute(&self.pool)
.await{ .await
Ok(_)=>{ {
Ok(true) Ok(_) => Ok(true),
}, Err(_) => Ok(false),
Err(_)=>{
Ok(false)
}
} }
} }
pub async fn delete_position(&self, position: Position) -> Result<bool,sqlx::Error>{ pub async fn delete_position(&self, position: Position) -> Result<bool, sqlx::Error> {
match sqlx::query("DELETE FROM Brewery.`position` WHERE id = ?;") match sqlx::query("DELETE FROM Brewery.`position` WHERE id = ?;")
.bind(position.id) .bind(position.id)
.execute(&self.pool) .execute(&self.pool)
.await{ .await
Ok(_)=>{ {
Ok(true) Ok(_) => Ok(true),
}, Err(_) => Ok(false),
Err(_)=>{
Ok(false)
}
} }
} }
pub async fn delete_material_category(&self, mat_cat: MaterialCategory) -> Result<bool,sqlx::Error>{ pub async fn delete_material_category(
&self,
mat_cat: MaterialCategory,
) -> Result<bool, sqlx::Error> {
match sqlx::query("DELETE FROM Brewery.`material_category` WHERE id = ?;") match sqlx::query("DELETE FROM Brewery.`material_category` WHERE id = ?;")
.bind(mat_cat.id) .bind(mat_cat.id)
.execute(&self.pool) .execute(&self.pool)
.await{ .await
Ok(_) =>{ {
Ok(true) Ok(_) => Ok(true),
}, Err(_) => Ok(false),
Err(_)=>{
Ok(false)
}
} }
} }
pub async fn delete_material(&self, mat: MaterialRow) -> Result<bool, sqlx::Error>{ pub async fn delete_material(&self, mat: MaterialRow) -> Result<bool, sqlx::Error> {
match sqlx::query("DELETE FROM Brewery.`material` WHERE id = ?;") match sqlx::query("DELETE FROM Brewery.`material` WHERE id = ?;")
.bind(mat.id) .bind(mat.id)
.execute(&self.pool) .execute(&self.pool)
.await{ .await
Ok(_) =>{ {
Ok(true) Ok(_) => Ok(true),
}, Err(_) => Ok(false),
Err(_)=>{
Ok(false)
}
} }
} }
pub async fn update_worker(&self, worker: Worker) -> Result<bool, sqlx::Error>{ pub async fn update_worker(&self, worker: Worker) -> Result<bool, sqlx::Error> {
match sqlx::query("UPDATE Brewery.worker SET position_id=?, hire_date=?, is_fired=?, full_name=? WHERE id=?;") match sqlx::query("UPDATE Brewery.worker SET position_id=?, hire_date=?, is_fired=?, full_name=? WHERE id=?;")
.bind(worker.position.id) .bind(worker.position.id)
.bind(worker.hire_date) .bind(worker.hire_date)
@ -206,71 +222,91 @@ impl DBOperator{
} }
} }
} }
pub async fn update_material_category(&self, mat_cat: MaterialCategory) -> Result<bool, sqlx::Error>{ pub async fn update_material_category(
&self,
mat_cat: MaterialCategory,
) -> Result<bool, sqlx::Error> {
match sqlx::query("UPDATE Brewery.`material_category` SET name=? WHERE id=?;") match sqlx::query("UPDATE Brewery.`material_category` SET name=? WHERE id=?;")
.bind(mat_cat.name) .bind(mat_cat.name)
.bind(mat_cat.id) .bind(mat_cat.id)
.execute(&self.pool) .execute(&self.pool)
.await{ .await
Ok(_) =>{ {
Ok(true) Ok(_) => Ok(true),
}, Err(_) => Ok(false),
Err(_)=>{
Ok(false)
}
} }
} }
pub async fn update_material(&self, mat: MaterialRow) -> Result<bool, sqlx::Error>{ pub async fn update_material(&self, mat: MaterialRow) -> Result<bool, sqlx::Error> {
match sqlx::query("UPDATE Brewery.material SET name=?, quantity=?, category_id=? WHERE id=?;") match sqlx::query(
"UPDATE Brewery.material SET name=?, quantity=?, category_id=? WHERE id=?;",
)
.bind(mat.name) .bind(mat.name)
.bind(mat.quantity) .bind(mat.quantity)
.bind(mat.category_id) .bind(mat.category_id)
.bind(mat.id) .bind(mat.id)
.execute(&self.pool) .execute(&self.pool)
.await{ .await
Ok(_) =>{ {
Ok(true) Ok(_) => Ok(true),
}, Err(_) => Ok(false),
Err(_)=>{
Ok(false)
}
} }
} }
pub async fn get_worker_by_id(&self, worker_id:i32) -> Result<Worker, sqlx::Error>{ pub async fn get_worker_by_id(&self, worker_id: i32) -> Result<Worker, sqlx::Error> {
let preret = sqlx::query_as::<_, WorkerRow>("SELECT * FROM `worker` WHERE id = ?;").bind(worker_id).fetch_all(&self.pool).await?; let preret = sqlx::query_as::<_, WorkerRow>("SELECT * FROM `worker` WHERE id = ?;")
.bind(worker_id)
.fetch_all(&self.pool)
.await?;
let poses = self.get_position().await?; let poses = self.get_position().await?;
let ret = Ok(Worker{ let ret = Ok(Worker {
id: preret[0].id, id: preret[0].id,
full_name: preret[0].full_name.clone(), full_name: preret[0].full_name.clone(),
hire_date: preret[0].hire_date, hire_date: preret[0].hire_date,
is_fired: preret[0].is_fired, is_fired: preret[0].is_fired,
position: poses.iter().find(|&pos| &pos.id == &preret[0].position_id).unwrap().clone(), position: poses
.iter()
.find(|&pos| &pos.id == &preret[0].position_id)
.unwrap()
.clone(),
}); });
ret ret
} }
pub async fn update_position(&self, pos: Position) -> Result<bool, sqlx::Error> {
match sqlx::query("UPDATE Brewery.position SET name=?, wage=? WHERE id=?")
.bind(pos.name)
.bind(pos.wage)
.bind(pos.id)
.execute(&self.pool)
.await
{
Ok(_) => Ok(true),
Err(_) => Ok(false),
}
}
} }
macro_rules! insert_fn { pub async fn estabilish_connection() -> Result<(), sqlx::Error> {
($expr:expr, $datatype:ty, $fn_name:ident) => {
pub async fn $fn_name{
match sqlx::query(stringify!($expr))
}
};
}
pub async fn estabilish_connection() -> Result<(), sqlx::Error>{
dotenv_override().ok(); dotenv_override().ok();
let db_url = env::var("DATABASE_URL").expect("DATABASE_URL установи!"); let db_url = env::var("DATABASE_URL").expect("DATABASE_URL установи!");
let _pool = MySqlPoolOptions::new() let _pool = MySqlPoolOptions::new()
.max_connections(5) .max_connections(5)
.connect(&db_url).await?; .connect(&db_url)
.await?;
Ok(()) Ok(())
} }
macro_rules! add_get {
($fn_name:ident, $table:ident) => {
pub async fn $fn_name(&self, $id: i32) -> Result<bool, sqlx::Error> {
match sqlx::query("UPDATE `$table` SET WHERE id = ?")
.bind($id)
.execute(&self.pool)
.await
{
Ok(_) => Ok(true),
Err(e) => Err(e),
}
}
};
}