use actix_web::web::Data; use chrono::{Datelike, DateTime, Utc}; use futures::executor::block_on; use sqlx::{Arguments, Pool, Row, Sqlite}; use sqlx::sqlite::{SqliteArguments, SqliteRow}; use common::models::entry::Entry; use common::models::production::Production; use crate::traits::database::{Database, DatabaseSub}; use crate::traits::query::QuerySub; use crate::traits::standard::{Standard, StandardSub}; impl Standard for Entry { fn table_name() -> String { "entry".to_string() } } impl StandardSub for Entry { fn parent_table() -> String { "variant".to_string() } } impl QuerySub for Entry { fn from_sqlite_row(row: SqliteRow, _parent_id: i64, pool: &Data>) -> Entry { let production: Option = match Production::get_by_id(row.get(7), pool).first() { Some(prod) => { Some(prod.clone()) } None => { None } }; Entry { id: row.get(0), charge: row.get(1), amount_created: row.get(2), amount_left: row.get(3), date: row.get(4), variant_id: row.get(5), origin: row.get(6), production, } } fn from_sqlite_row_small(row: SqliteRow, _parent_id: i64, pool: &Data>) -> Entry { Entry { id: row.get(0), charge: row.get(1), amount_created: row.get(2), amount_left: row.get(3), date: row.get(4), variant_id: row.get(5), origin: row.get(6), production: None, } } } impl DatabaseSub for Entry { } impl Database for Entry { fn insert(&self, pool: &Data>) -> i64 { let production_id = match &self.production { Some(production) => { Some(production.insert(pool)) } None => { None } }; let statement = format!( "INSERT INTO {} (charge, amount_created, amount_left, date, variant, origin_id, production_id) VALUES ($1, $2, $2, $3, $4, $5, $6)", Entry::table_name(), ); let charge = self.charge.as_str(); let charge = if charge.eq("000_TO_GENERATE") { let new_charge = next_charge(pool); insert_charge(new_charge.clone(), pool); new_charge } else { self.charge.clone() }; let mut date_time: DateTime = Utc::now(); date_time = date_time.with_day(21).unwrap(); date_time = date_time.with_month(09).unwrap(); //date_time = date_time.with_hour(10).unwrap(); let mut args = SqliteArguments::default(); args.add(charge); args.add(&self.amount_created); args.add(date_time); args.add(&self.variant_id); args.add(&self.origin); args.add(production_id); let mut conn = block_on(pool.acquire()).unwrap(); let temp = block_on( sqlx::query_with( statement.as_str(), args) .execute(&mut *conn) ); println!("Entry result:\n {:#?}", temp); temp.unwrap().last_insert_rowid() } fn update(&self, pool: &Data>) { let statement = format!( "UPDATE {} SET amount_left = $2 WHERE id = $1", Entry::table_name(), ); let mut args = SqliteArguments::default(); args.add(&self.id); args.add(&self.amount_left); println!("Updating"); let mut conn = block_on(pool.acquire()).unwrap(); let temp = block_on( sqlx::query_with( statement.as_str(), args) .execute(&mut *conn) ); println!("Result:\n {:#?}", temp); } fn delete(&self, pool: &Data>) { let mut conn = block_on(pool.acquire()).unwrap(); let temp = block_on( sqlx::query( format!("DELETE FROM {} WHERE id = {}", Entry::table_name(), self.id ).as_str() ).execute(&mut *conn) ); println!("Result:\n {:#?}", temp); } fn get_all(pool: &Data>) -> Vec { let mut conn = block_on(pool.acquire()).unwrap(); let res = block_on( sqlx::query(format!("SELECT * FROM {}", Entry::table_name()).as_str()) .fetch_all(&mut *conn) ); let mut entry: Vec = Vec::new(); match res { Ok(records) => { for record in records { entry.push( // TODO: Parent_id Entry::from_sqlite_row_small(record, -1, pool) ); } } Err(err) => { println!("Error while loading all entry entries:"); println!("{:#?}", err); } } entry } fn get_by_id(id: i64, pool: &Data>) -> Vec { let statement = format!( "SELECT * FROM {} WHERE id = $1", Entry::table_name(), ); let mut args = SqliteArguments::default(); args.add(id); let mut conn = block_on(pool.acquire()).unwrap(); let res = block_on( sqlx::query_with( statement.as_str(), args) .fetch_all(&mut *conn) ); let mut entry: Vec = Vec::new(); match res { Ok(records) => { for record in records { entry.push( // TODO: Parent_id Entry::from_sqlite_row(record, -1, pool) ); } } Err(err) => { println!("Error while loading all entry entries:"); println!("{:#?}", err); } } entry } fn get_by_search(search_term: String, pool: &Data>) -> Vec { let statement = format!( "SELECT * FROM {} WHERE variant = {}", Entry::table_name(), search_term, ); let mut conn = block_on(pool.acquire()).unwrap(); let res = block_on( sqlx::query( statement.as_str()) .fetch_all(&mut *conn) ); let mut entry: Vec = Vec::new(); match res { Ok(records) => { for record in records { entry.push( // TODO: Parent_id Entry::from_sqlite_row(record, -1, pool) ); } } Err(err) => { println!("Error while loading all entry entries:"); println!("{:#?}", err); } } entry } } pub fn get_entry_by_variant_and_date(variant_id: i64, date_start: String, date_end: String, pool: &Data>) -> Vec { let statement = format!( "SELECT entry.* FROM entry WHERE entry.variant = $1 AND entry.date > date($2) AND entry.date < date($3)", ); let mut args = SqliteArguments::default(); args.add(variant_id); args.add(date_start); args.add(date_end); let mut conn = block_on(pool.acquire()).unwrap(); let res = block_on( sqlx::query_with( statement.as_str(), args) .fetch_all(&mut *conn) ); conn.detach(); let mut entries: Vec = Vec::new(); match res { Ok(records) => { for record in records { entries.push( // TODO: Parent_id Entry::from_sqlite_row_small(record, -1, pool) ); } } Err(err) => { println!("Error while loading entries by variant and dates:"); println!("{:#?}", err); } } entries } pub fn get_entry_with_used_via_production(production_id: i64, pool: &Data>) -> Option { let statement = format!( "SELECT entry.* FROM entry WHERE entry.production_id = $1", ); let mut args = SqliteArguments::default(); args.add(production_id); let mut conn = block_on(pool.acquire()).unwrap(); let res = block_on( sqlx::query_with( statement.as_str(), args) .fetch_one(&mut *conn) ); conn.detach(); let entry: Option; match res { Ok(record) => { entry = Some(Entry::from_sqlite_row_small(record, -1, pool)); } Err(err) => { entry = None; println!("Error while loading parent entry by used:"); println!("{:#?}", err); } } entry } const CHARGE_TABLE: &str = "used_charge"; fn insert_charge(charge: String, pool: &Data>) { let statement = format!( "INSERT INTO {} (charge) VALUES ($1)", CHARGE_TABLE, ); let mut args = SqliteArguments::default(); args.add(charge); let mut conn = block_on(pool.acquire()).unwrap(); let temp = block_on( sqlx::query_with( statement.as_str(), args) .execute(&mut *conn) ); conn.detach(); println!("Charge result:\n {:#?}", temp); } fn next_charge(pool: &Data>) -> String { let statement = format!( "SELECT charge FROM {}", CHARGE_TABLE, ); let mut conn = block_on(pool.acquire()).unwrap(); let temp = block_on( sqlx::query( statement.as_str()) .fetch_all(&mut *conn) ); conn.detach(); match temp { Ok(charges) => { if charges.last().is_some() { increment_charge(charges.last().unwrap().get(0)) } else { "A".to_string() } }, Err(_) => { "A".to_string() } } } fn increment_charge(charge: String) -> String { let mut charge: Vec = charge.chars().collect(); charge.reverse(); let mut over = false; for ch in charge.iter_mut() { if *ch == 'Z' { over = true; *ch = 'A'; } else if over { *ch = std::char::from_u32(*ch as u32 + 1).unwrap_or(*ch); over = false; } else { *ch = std::char::from_u32(*ch as u32 + 1).unwrap_or(*ch); break; } } charge.reverse(); if over { charge.push('A'); } charge.iter().collect() }