468 lines
16 KiB
Rust
468 lines
16 KiB
Rust
use bigdecimal::BigDecimal;
|
||
use chrono::DateTime;
|
||
use sqlx::Row;
|
||
use sqlx::mysql::MySqlPool;
|
||
use sqlx::mysql::MySqlPoolOptions;
|
||
|
||
use dotenvy::dotenv_override;
|
||
use std::collections::HashMap;
|
||
use std::env;
|
||
// use crate::schema::equipment::dsl::*;
|
||
// use crate::schema::worker::dsl::*;
|
||
use crate::models::*;
|
||
use anyhow::anyhow;
|
||
|
||
pub struct DBOperator {
|
||
pool: MySqlPool,
|
||
}
|
||
impl DBOperator {
|
||
pub async fn new() -> Self {
|
||
dotenv_override().ok();
|
||
let db_url = env::var("DATABASE_URL").expect("DATABASE_URL установи!");
|
||
Self {
|
||
pool: MySqlPool::connect(&db_url).await.unwrap(),
|
||
}
|
||
}
|
||
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?;
|
||
Ok(rets)
|
||
}
|
||
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 mut rets: Vec<Worker> = Vec::new();
|
||
let pos = self.get_position().await.unwrap();
|
||
for worker in pre_rets {
|
||
let mut ppos = Position::default();
|
||
for position in pos.clone() {
|
||
if position.id == worker.position_id {
|
||
ppos = position.clone();
|
||
break;
|
||
}
|
||
}
|
||
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)
|
||
}
|
||
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 mut rets: Vec<Equipment> = Vec::new();
|
||
let workers = self.get_workers().await?;
|
||
for eq in pre_rets {
|
||
let mut pworker = Worker::default();
|
||
for worker in workers.clone() {
|
||
if worker.id == eq.worker_id {
|
||
pworker = worker.clone();
|
||
break;
|
||
}
|
||
}
|
||
rets.push(Equipment {
|
||
id: eq.id,
|
||
name: eq.name,
|
||
inv_number: eq.inv_number,
|
||
maintenance_date: eq.maintenance_date,
|
||
worker: pworker,
|
||
is_written_off: eq.is_written_off,
|
||
});
|
||
}
|
||
Ok(rets)
|
||
}
|
||
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?;
|
||
Ok(rets)
|
||
}
|
||
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 cats = self.get_mcat().await?;
|
||
let cat_map: HashMap<_, MaterialCategory> =
|
||
cats.into_iter().map(|cat| (cat.id, cat)).collect();
|
||
let mut rets = Vec::with_capacity(mats.len());
|
||
for mat in mats {
|
||
let cat = cat_map
|
||
.get(&mat.category_id)
|
||
.expect("Никто не знает как, но БД не смогла связать материал с его категорией. Заставьте разраба это починить.")
|
||
.clone();
|
||
rets.push(Material {
|
||
id: mat.id,
|
||
name: mat.name,
|
||
quantity: mat.quantity,
|
||
category: cat,
|
||
});
|
||
}
|
||
Ok(rets)
|
||
}
|
||
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?;
|
||
if ret.len() > 0 {
|
||
return Ok(true);
|
||
}
|
||
Ok(false)
|
||
}
|
||
pub async fn add_worker(&self, worker: WorkerRow) -> 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)
|
||
match sqlx::query("INSERT INTO Brewery.worker (id, position_id, hire_date, is_fired, full_name) VALUES(0, ?, ?, ?, ?);")
|
||
.bind(worker.position_id)
|
||
.bind(worker.hire_date)
|
||
.bind(worker.is_fired)
|
||
.bind(worker.full_name)
|
||
.execute(&self.pool)
|
||
.await {
|
||
Ok(_) =>{
|
||
return Ok(true)
|
||
},
|
||
Err(_) =>{
|
||
Ok(false)
|
||
}
|
||
}
|
||
}
|
||
pub async fn add_position(&self, position: Position) -> Result<bool, sqlx::Error> {
|
||
match sqlx::query("INSERT INTO Brewery.`position` (id, name, wage) VALUES(0, ?, ?);")
|
||
.bind(position.name)
|
||
.bind(position.wage)
|
||
.execute(&self.pool)
|
||
.await
|
||
{
|
||
Ok(_) => Ok(true),
|
||
Err(_) => Ok(false),
|
||
}
|
||
}
|
||
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, ?)")
|
||
.bind(mat_cat.name)
|
||
.execute(&self.pool)
|
||
.await
|
||
{
|
||
Ok(_) => Ok(true),
|
||
Err(_) => Ok(false),
|
||
}
|
||
}
|
||
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, ?, ?, ?);",
|
||
)
|
||
.bind(mat.name)
|
||
.bind(mat.quantity)
|
||
.bind(mat.category_id)
|
||
.execute(&self.pool)
|
||
.await
|
||
{
|
||
Ok(_) => Ok(true),
|
||
Err(_) => Ok(false),
|
||
}
|
||
}
|
||
pub async fn delete_position(&self, position: Position) -> Result<bool, sqlx::Error> {
|
||
match sqlx::query("DELETE FROM Brewery.`position` WHERE id = ?;")
|
||
.bind(position.id)
|
||
.execute(&self.pool)
|
||
.await
|
||
{
|
||
Ok(_) => Ok(true),
|
||
Err(_) => Ok(false),
|
||
}
|
||
}
|
||
pub async fn delete_material_category(
|
||
&self,
|
||
mat_cat: MaterialCategory,
|
||
) -> Result<bool, sqlx::Error> {
|
||
match sqlx::query("DELETE FROM Brewery.`material_category` WHERE id = ?;")
|
||
.bind(mat_cat.id)
|
||
.execute(&self.pool)
|
||
.await
|
||
{
|
||
Ok(_) => Ok(true),
|
||
Err(_) => Ok(false),
|
||
}
|
||
}
|
||
pub async fn delete_material(&self, mat: MaterialRow) -> Result<bool, sqlx::Error> {
|
||
match sqlx::query("DELETE FROM Brewery.`material` WHERE id = ?;")
|
||
.bind(mat.id)
|
||
.execute(&self.pool)
|
||
.await
|
||
{
|
||
Ok(_) => Ok(true),
|
||
Err(_) => Ok(false),
|
||
}
|
||
}
|
||
|
||
pub async fn update_worker(&self, worker: WorkerRow) -> Result<bool, sqlx::Error> {
|
||
match sqlx::query("UPDATE Brewery.worker SET position_id=?, hire_date=?, is_fired=?, full_name=? WHERE id=?;")
|
||
.bind(worker.position_id)
|
||
.bind(worker.hire_date)
|
||
.bind(worker.is_fired)
|
||
.bind(worker.full_name)
|
||
.bind(worker.id)
|
||
.execute(&self.pool)
|
||
.await{
|
||
Ok(_) =>{
|
||
Ok(true)
|
||
},
|
||
Err(_)=>{
|
||
Ok(false)
|
||
}
|
||
}
|
||
}
|
||
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=?;")
|
||
.bind(mat_cat.name)
|
||
.bind(mat_cat.id)
|
||
.execute(&self.pool)
|
||
.await
|
||
{
|
||
Ok(_) => Ok(true),
|
||
Err(_) => Ok(false),
|
||
}
|
||
}
|
||
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=?;",
|
||
)
|
||
.bind(mat.name)
|
||
.bind(mat.quantity)
|
||
.bind(mat.category_id)
|
||
.bind(mat.id)
|
||
.execute(&self.pool)
|
||
.await
|
||
{
|
||
Ok(_) => Ok(true),
|
||
Err(_) => Ok(false),
|
||
}
|
||
}
|
||
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 poses = self.get_position().await?;
|
||
let ret = Ok(Worker {
|
||
id: preret[0].id,
|
||
full_name: preret[0].full_name.clone(),
|
||
hire_date: preret[0].hire_date,
|
||
is_fired: preret[0].is_fired,
|
||
position: poses
|
||
.iter()
|
||
.find(|&pos| &pos.id == &preret[0].position_id)
|
||
.unwrap()
|
||
.clone(),
|
||
});
|
||
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),
|
||
}
|
||
}
|
||
pub async fn check_password(
|
||
&self,
|
||
username: String,
|
||
password_hash: String,
|
||
) -> Result<bool, sqlx::Error> {
|
||
let ans = sqlx::query("SELECT * FROM Brewery.profile WHERE login=? AND password=?")
|
||
.bind(username)
|
||
.bind(password_hash)
|
||
.fetch_all(&self.pool)
|
||
.await;
|
||
match ans {
|
||
Ok(n) => {
|
||
if n.len() > 0 {
|
||
return Ok(true);
|
||
} else {
|
||
return Ok(false);
|
||
}
|
||
}
|
||
Err(_) => Ok(false),
|
||
}
|
||
}
|
||
pub async fn check_admin(&self, username: String) -> Result<bool, sqlx::Error> {
|
||
let ans: bool = sqlx::query_scalar(
|
||
r#"SELECT
|
||
position.is_admin,
|
||
profile.worker_id,
|
||
worker.id,
|
||
profile.login,
|
||
position.id
|
||
FROM
|
||
Brewery.profile
|
||
JOIN
|
||
Brewery.worker
|
||
JOIN
|
||
Brewery.position
|
||
ON profile.worker_id = worker.id
|
||
AND profile.login=?
|
||
AND worker.position_id =position.id"#,
|
||
)
|
||
.bind(username)
|
||
.fetch_one(&self.pool)
|
||
.await
|
||
.unwrap();
|
||
Ok(ans)
|
||
}
|
||
pub async fn write_off_equipment(&self, equipment_id: i32) -> Result<bool, sqlx::Error> {
|
||
match sqlx::query("UPDATE `equipment` SET is_written_off=1 WHERE id=?")
|
||
.bind(equipment_id)
|
||
.execute(&self.pool)
|
||
.await
|
||
{
|
||
Ok(_) => Ok(true),
|
||
Err(_) => Ok(false),
|
||
}
|
||
}
|
||
pub async fn get_salaries(&self) -> Result<Vec<Salary>, sqlx::Error> {
|
||
let sals = sqlx::query_as::<_, SalaryRow>("SELECT * FROM `salary`")
|
||
.fetch_all(&self.pool)
|
||
.await?;
|
||
let mut rets: Vec<Salary> = Vec::new();
|
||
let workers = self.get_workers().await.unwrap();
|
||
for sal in sals {
|
||
match workers.iter().find(|w| w.id == sal.worker_id) {
|
||
Some(w) => rets.push(Salary {
|
||
id: sal.id,
|
||
worker: w.clone(),
|
||
salary_date: sal.salary_date,
|
||
salary_size: sal.salary_size,
|
||
comment: sal.comment,
|
||
}),
|
||
None => {}
|
||
}
|
||
}
|
||
|
||
Ok(rets)
|
||
}
|
||
pub async fn add_salary(
|
||
&self,
|
||
worker_id: i32,
|
||
salary_date: DateTime<chrono::Local>,
|
||
salary_size: BigDecimal,
|
||
comment: Option<String>,
|
||
) -> Result<bool, sqlx::Error> {
|
||
match sqlx::query("INSERT INTO Brewery.salary (id, worker_id, salary_size, salary_date, comment) VALUES(0, ?, ?, ?, ?);")
|
||
.bind(worker_id)
|
||
.bind(salary_size)
|
||
.bind(salary_date)
|
||
.bind(comment.unwrap_or(String::new()))
|
||
.execute(&self.pool)
|
||
.await{
|
||
Ok(_) => Ok(true),
|
||
Err(_) => Ok(false)
|
||
}
|
||
}
|
||
pub async fn update_salary(&self, salary: Salary) -> Result<bool, sqlx::Error> {
|
||
match sqlx::query("UPDATE Brewery.salary SET worker_id=?, salary_size=?, salary_date=?, comment=? WHERE id=?;")
|
||
.bind(salary.worker.id)
|
||
.bind(salary.salary_size)
|
||
.bind(salary.salary_date)
|
||
.bind(salary.comment)
|
||
.bind(salary.id)
|
||
.execute(&self.pool)
|
||
.await{
|
||
Ok(_) => Ok(true),
|
||
Err(_) => Ok(false)
|
||
}
|
||
}
|
||
pub async fn remove_salary(&self, id: i32) -> Result<bool, sqlx::Error> {
|
||
match sqlx::query("DELETE FROM Brewery.salary WHERE id=?;")
|
||
.bind(id)
|
||
.execute(&self.pool)
|
||
.await
|
||
{
|
||
Ok(_) => Ok(true),
|
||
Err(_) => Ok(false),
|
||
}
|
||
}
|
||
pub async fn get_recipes(&self) -> Result<Vec<Recipe>, sqlx::Error> {
|
||
let pre_ret = sqlx::query_as::<_, RecipeRow>("SELECT * FROM recipe")
|
||
.fetch_all(&self.pool)
|
||
.await
|
||
.unwrap_or(Vec::new());
|
||
|
||
let ret: Vec<Recipe> = Vec::new();
|
||
let elements = self.get_recipe_elements().await.unwrap_or(Vec::new());
|
||
for pr in pre_ret.iter() {}
|
||
Ok(ret)
|
||
}
|
||
pub async fn get_recipe_elements(&self) -> Result<Vec<RecipeElement>, sqlx::Error> {
|
||
let pre_ret = sqlx::query_as::<_, RecipeElementRow>("SELECT id, recipe_id, material_id, equipment_id, quantity FROM Brewery.recipe_element;").fetch_all(&self.pool).await;
|
||
|
||
let mats = self.get_materials().await.unwrap();
|
||
let eqs = self.get_equipment().await.unwrap();
|
||
let ret: Vec<RecipeElement> = Vec::new();
|
||
for re in pre_ret.unwrap().iter() {
|
||
let mat = mats.iter().find(|m| m.id == re.material_id);
|
||
let eq = eqs.iter().find(|e| e.id == re.equipment_id);
|
||
match (mat, eq) {
|
||
(Some(m), Some(e)) => {
|
||
ret.push(RecipeElement {
|
||
id: re.id,
|
||
material: m.clone(),
|
||
equipment: e.clone(),
|
||
quantity: re.quantity,
|
||
});
|
||
}
|
||
(_, _) => {}
|
||
}
|
||
}
|
||
Ok(ret)
|
||
}
|
||
}
|
||
|
||
pub async fn estabilish_connection() -> Result<(), sqlx::Error> {
|
||
dotenv_override().ok();
|
||
let db_url = env::var("DATABASE_URL").expect("DATABASE_URL установи!");
|
||
let _pool = MySqlPoolOptions::new()
|
||
.max_connections(5)
|
||
.connect(&db_url)
|
||
.await?;
|
||
|
||
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),
|
||
}
|
||
}
|
||
};
|
||
}
|