code restructure

This commit is contained in:
djkato 2023-04-16 20:51:50 +02:00
parent f028064630
commit eb68d42748
9 changed files with 205 additions and 169 deletions

7
Cargo.lock generated
View file

@ -719,6 +719,7 @@ dependencies = [
"egui", "egui",
"egui_extras", "egui_extras",
"grid", "grid",
"if_chain",
"regex", "regex",
"rfd", "rfd",
"sqlx", "sqlx",
@ -1459,6 +1460,12 @@ dependencies = [
"unicode-normalization", "unicode-normalization",
] ]
[[package]]
name = "if_chain"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb56e1aa765b4b4f3aadfab769793b7087bb03a4ea4920644a6d238e2df5b9ed"
[[package]] [[package]]
name = "indexmap" name = "indexmap"
version = "1.9.2" version = "1.9.2"

View file

@ -21,3 +21,4 @@ rfd = "0.11.1"
grid = "0.9.0" grid = "0.9.0"
regex = "1.7.1" regex = "1.7.1"
chrono = "0.4.24" chrono = "0.4.24"
if_chain = "1.0.2"

View file

@ -19,7 +19,7 @@ volumes:
# To connect to mysql, do: # To connect to mysql, do:
# sudo docker exec -it csql-Opencart_dummy_DB-1 /bin/bash # sudo docker exec -it csql-Opencart_dummy_DB-1 /bin/bash
# mysql -p # mysql -pmauFJcuf5dhRMQrjj
# [password] # [password]
# use quotes; # use quotes;
# select * from oc_product; # select * from oc_product;

View file

@ -1,6 +1,7 @@
use super::csv_handler::{DataEntry, ImportedData}; use super::csv_handler::{DataEntry, ImportedData};
use super::database_handler::{DBLoginData, QueryResult, Table, Tables}; use super::database_handler::{DBLoginData, QueryResult, Table, Tables};
use super::parser::parse; use super::parser::parse;
use if_chain::if_chain;
use sqlx::MySqlConnection; use sqlx::MySqlConnection;
use std::sync::Arc; use std::sync::Arc;
use tokio::sync::mpsc::{Receiver, Sender}; use tokio::sync::mpsc::{Receiver, Sender};
@ -183,62 +184,52 @@ pub fn try_match_headers_to_fields(
if !csv_data.are_headers || csv_data.data.is_empty() { if !csv_data.are_headers || csv_data.data.is_empty() {
return; return;
} }
let final_table_index: usize; let new_i: usize;
if let Some(i) = table_index { if let Some(table_index) = table_index.or(tables.current_working_table) {
final_table_index = i; new_i = table_index;
} else if let Some(cw_table_i) = tables.current_working_table {
final_table_index = cw_table_i;
} else { } else {
return; return;
} }
let table_index = final_table_index; let table_index = new_i;
println!("Trying to automatch table \"{}\"...", table_index);
let db_fields = tables
.tables
.get_mut(table_index)
.unwrap()
.fields
.as_mut()
.unwrap();
let mut has_matched_some = false; let mut has_matched_some = false;
for field in db_fields { if let Some(db_fields) = tables.tables.get_mut(table_index).unwrap().fields.as_mut() {
for (i, header) in csv_data.data.iter_row(0).into_iter().enumerate() { for field in db_fields {
if &field.description.field == &header.data { for (i, header) in csv_data.data.iter_row(0).into_iter().enumerate() {
field.mapped_to_col = Some(i); if &field.description.field == &header.data {
has_matched_some = true; field.mapped_to_col = Some(i);
has_matched_some = true;
}
} }
} }
} }
if !has_matched_some {
if has_matched_some == false
|| tables.current_working_table.is_none()
|| tables.tables.is_empty()
{
return; return;
} }
println!("Autommapped some!");
/* If some got automapped, try to parse them all */ /* If some got automapped, try to parse them all */
if let Some(table_i) = tables.current_working_table { if_chain! {
if let Some(table) = tables.tables.get_mut(table_i) { if let Some(table) = tables.tables.get_mut(table_index);
if let Some(fields) = table.fields.as_mut() { if let Some(fields) = table.fields.as_mut();
for (col_index, field) in fields.iter().enumerate() { then {
for (field_index, field) in fields.iter().enumerate() {
if let Some(col_index) = field.mapped_to_col {
println!( println!(
" > automapping field \"{}\" to col \"{:?}\"", " > automapping field \"{}\" to col \"{:?}\"",
&field.description.field, field.mapped_to_col &field.description.field, field.mapped_to_col
); );
if let Some(col_index) = field.mapped_to_col { for cell in csv_data.data.iter_col_mut(col_index) {
for cell in csv_data.data.iter_mut() { cell.curr_field_description = Some(field.description.clone());
cell.curr_field_description = Some(field.description.clone()); parse(cell);
parse(cell);
}
}
if is_whole_col_parsed(csv_data, col_index) {
println!("col \"{}\" is parsed whole!", &col_index);
csv_data.parsed_cols.push(col_index);
}
if is_whole_table_parsed(&csv_data) {
csv_data.is_parsed = true;
} }
} }
if is_whole_col_parsed(csv_data, field_index) {
println!("col \"{}\" is parsed whole!", &field_index);
csv_data.parsed_cols.push(field_index);
}
if is_whole_table_parsed(&csv_data) {
csv_data.is_parsed = true;
}
} }
} }
} }

View file

@ -158,16 +158,19 @@ fn parse_decimal(cell: &mut DataEntry, args: Option<String>) {
if let Some(num_args) = process_args(args) { if let Some(num_args) = process_args(args) {
let num_parse_res: Result<f32, ParseFloatError> = cell.data.parse(); let num_parse_res: Result<f32, ParseFloatError> = cell.data.parse();
if let Ok(_) = num_parse_res { if let Ok(_) = num_parse_res {
let dot_i = cell.data.find(".").unwrap(); if let Some(dot_i) = cell.data.find(".") {
// -1 cuz the dot is there // -1 cuz the dot is there
let count_to_dot = cell.data.chars().count() as u32; let count_to_dot = cell.data.chars().count() as u32;
let count_from_dot = cell.data.chars().skip(dot_i + 1).count() as u32; let count_from_dot = cell.data.chars().skip(dot_i + 1).count() as u32;
if count_to_dot - 1 <= num_args[0] && count_from_dot >= num_args[1] { if count_to_dot - 1 <= num_args[0] && count_from_dot >= num_args[1] {
cell.is_parsed = Some(Ok(())); cell.is_parsed = Some(Ok(()));
} else { } else {
cell.is_parsed = Some(Err(Arc::from(<&str as Into< cell.is_parsed = Some(Err(Arc::from(<&str as Into<
Box<dyn Error + Send + Sync>, Box<dyn Error + Send + Sync>,
>>::into("too many numbers")))) >>::into(
"too many numbers"
))))
}
} }
} else { } else {
cell.is_parsed = Some(Err(Arc::from(<&str as Into< cell.is_parsed = Some(Err(Arc::from(<&str as Into<

View file

@ -1,5 +1,5 @@
#![cfg_attr(not(debug_assertions), deny(dead_code), deny(unused_variables))] //#![cfg_attr(not(debug_assertions), deny(dead_code), deny(unused_variables))]
#![cfg_attr(debug_assertions, allow(dead_code), allow(unused_variables))] //#![cfg_attr(debug_assertions, allow(dead_code), allow(unused_variables))]
mod backend; mod backend;
mod ui; mod ui;
use backend::backend_manager::BackendManger; use backend::backend_manager::BackendManger;

View file

@ -41,6 +41,7 @@ impl CSQLWindow for DBTransactionWindow {
ui: &mut Ui, ui: &mut Ui,
frame: &mut eframe::Frame, frame: &mut eframe::Frame,
) -> Option<Result<ExitStatus, Box<dyn std::error::Error>>> { ) -> Option<Result<ExitStatus, Box<dyn std::error::Error>>> {
println!("Opening Transaction window...");
egui::Window::new("Database Transactions") egui::Window::new("Database Transactions")
.id(egui::Id::new("Database Transactions")) .id(egui::Id::new("Database Transactions"))
.resizable(false) .resizable(false)

View file

@ -4,6 +4,7 @@ use crate::backend::csv_handler::ImportedData;
use crate::backend::database_handler::{TableField, Tables}; use crate::backend::database_handler::{TableField, Tables};
use egui::{ComboBox, Context, Ui}; use egui::{ComboBox, Context, Ui};
use egui_extras::{Column, TableBuilder}; use egui_extras::{Column, TableBuilder};
use if_chain::if_chain;
use std::error::Error; use std::error::Error;
use std::sync::Arc; use std::sync::Arc;
use tokio::sync::mpsc::Sender; use tokio::sync::mpsc::Sender;
@ -43,7 +44,7 @@ impl CSQLWindow for SpreadSheetWindow {
frame: &mut eframe::Frame, frame: &mut eframe::Frame,
) -> Option<Result<ExitStatus, Box<dyn std::error::Error>>> { ) -> Option<Result<ExitStatus, Box<dyn std::error::Error>>> {
self.ui(ui, ctx); self.ui(ui, ctx);
if let Some(return_status) = self.return_status { if let Some(return_status) = self.return_status.clone() {
self.return_status = None; self.return_status = None;
return Some(Ok(return_status)); return Some(Ok(return_status));
} }
@ -109,16 +110,119 @@ impl SpreadSheetWindow {
} }
}); });
SpreadSheetWindow::preview_files_being_dropped(ctx); SpreadSheetWindow::preview_files_being_dropped(ctx);
/*All the dzum checks before making the window... */
if self.current_table.is_some() { if_chain! {
ui.group(|ui| { if let Some(current_table) = self.current_table;
egui::ScrollArea::horizontal().show(ui, |ui| { if let Ok(csv_data) = &mut self.csv_data_handle.try_lock();
self.table_builder(ui) if let Ok(db_table_data) = &mut self.db_table_data_handle.try_lock();
.unwrap_or_else(|e| println!("Table un-intd, {:?}", e)); if !csv_data.data.is_empty();
}); if let Some(curr_db_table) = db_table_data.tables.get_mut(current_table);
}); then {
if let Some(curr_db_table_fields) = curr_db_table.fields.as_mut() {
ui.group(|ui| {
egui::ScrollArea::horizontal().show(ui, |ui| {
SpreadSheetWindow::table_builder(
&mut self.sender,
ui,
csv_data,
curr_db_table_fields,
)
});
});
} else {
if !self.is_table_description_request_sent {
if let Ok(mesg) = self.sender.try_send(
Communication::GetTableDescription(self.current_table.unwrap()),
) {}
}
}
} else {
ui.centered_and_justified(|ui| ui.heading("Import or Drag and Drop a file..."));
}
} }
} }
fn table_builder(
sender: &mut Sender<Communication>,
ui: &mut Ui,
csv_data: &mut MutexGuard<ImportedData>,
curr_db_table_fields: &mut Vec<TableField>,
) {
let table = TableBuilder::new(ui)
.striped(true)
.cell_layout(egui::Layout::left_to_right(egui::Align::Center))
/*First collumn for row actions */
.column(Column::auto().at_most(30.0).resizable(false).clip(false));
table
.columns(
Column::auto().resizable(true).clip(false),
csv_data.data.cols(),
)
.min_scrolled_height(0.0)
.header(20., |mut header| {
/* First Col for row mutators */
header.col(|ui| {});
SpreadSheetWindow::add_header_cols(
&mut header,
csv_data,
curr_db_table_fields,
sender,
);
})
.body(|body| {
body.rows(
15.,
csv_data.data.rows() - csv_data.are_headers as usize,
|row_index, mut row| {
let headers_i_offset = csv_data.are_headers as usize;
row.col(|ui| {
if ui.button("x").clicked() {
if let Ok(_) = sender.try_send(Communication::RemoveRow(row_index))
{
};
}
});
for curr_cell in csv_data.data.iter_row_mut(row_index + headers_i_offset) {
/* If cell is bound to a field, color it's bg according to is_parsed */
row.col(|ui| {
let mut err: Option<Arc<dyn Error>> = None;
if curr_cell.curr_field_description.is_some() {
match &curr_cell.is_parsed {
Some(parse) => match parse {
Ok(_) => {
ui.style_mut().visuals.extreme_bg_color =
egui::Color32::DARK_GREEN
}
Err(arc) => {
err = Some(arc.clone());
ui.style_mut().visuals.extreme_bg_color =
egui::Color32::DARK_RED;
}
},
None => {
ui.style_mut().visuals.extreme_bg_color =
egui::Color32::DARK_GRAY
}
}
}
if let Some(err) = err {
ui.text_edit_singleline(&mut curr_cell.data)
.on_hover_text(format!("{}", err));
} else {
ui.text_edit_singleline(&mut curr_cell.data);
}
if curr_cell.curr_field_description.is_some() {
ui.reset_style();
}
});
}
},
);
});
}
fn table_options(&mut self, ui: &mut Ui) { fn table_options(&mut self, ui: &mut Ui) {
/* Create table select option, only enable if the tables are discovered yet*/ /* Create table select option, only enable if the tables are discovered yet*/
if let Ok(db_table_data) = &mut self.db_table_data_handle.try_lock() { if let Ok(db_table_data) = &mut self.db_table_data_handle.try_lock() {
@ -132,115 +236,34 @@ impl SpreadSheetWindow {
/* autoselect oc_product in debug mode */ /* autoselect oc_product in debug mode */
if cfg!(debug_assertions) && self.current_table.is_none() { if cfg!(debug_assertions) && self.current_table.is_none() {
self.current_table = Some(88); self.current_table = Some(88);
db_table_data.current_working_table = Some(88);
if let Some(table_88) = &db_table_data.tables.get(88) { if let Some(table_88) = &db_table_data.tables.get(88) {
select_table = select_table.selected_text(table_88.name.clone()); select_table = select_table.selected_text(table_88.name.clone());
} }
} }
ui.vertical(|ui| { ui.vertical(|ui| {
select_table.show_ui(ui, |ui| { select_table.show_ui(ui, |ui| {
for (table_i, table) in db_table_data.tables.iter().enumerate() { let mut current_working_table_i = None;
ui.selectable_value( for (table_i, table) in db_table_data.tables.iter_mut().enumerate() {
&mut self.current_table, if ui
Some(table_i.clone()), .selectable_value(
&table.name, &mut self.current_table,
); Some(table_i.clone()),
&table.name,
)
.clicked()
{
current_working_table_i = Some(table_i);
};
}
if let Some(current_working_table_i) = current_working_table_i {
db_table_data.current_working_table = Some(current_working_table_i);
} }
}); });
}); });
}); });
} }
} }
fn table_builder(&mut self, ui: &mut Ui) -> Result<(), Box<dyn std::error::Error>> {
if let Ok(csv_data) = &mut self.csv_data_handle.try_lock() {
if let Ok(db_table_data) = &mut self.db_table_data_handle.try_lock() {
//ref to all fields in curr db table
let mut curr_db_table_fields: &mut Vec<TableField> = match db_table_data
.tables
.get_mut(self.current_table.unwrap())
.ok_or("no current table")?
.fields
.as_mut()
.ok_or("no fields yet")
{
Ok(val) => val,
Err(e) => {
if !self.is_table_description_request_sent {
self.sender.try_send(Communication::GetTableDescription(
self.current_table.unwrap(),
))?;
self.is_table_description_request_sent = true;
}
return Err(Box::from(
<String as Into<Box<dyn std::error::Error>>>::into(e.to_string()),
));
}
};
if csv_data.data.is_empty() {
return Err(<String as Into<Box<dyn std::error::Error>>>::into(
"no rows yet".to_string(),
));
}
let table = TableBuilder::new(ui)
.striped(true)
.cell_layout(egui::Layout::left_to_right(egui::Align::Center))
/*First collumn for row actions */
.column(Column::auto().at_most(30.0).resizable(false).clip(false));
table
.columns(
Column::auto().resizable(true).clip(false),
csv_data.data.cols(),
)
.min_scrolled_height(0.0)
.header(20., |mut header| {
/* First Col for row mutators */
header.col(|ui|{
});
SpreadSheetWindow::add_header_cols(&mut header, csv_data,&mut curr_db_table_fields, &mut self.sender);
})
.body(|body| {
body.rows(15., csv_data.data.rows() - csv_data.are_headers as usize, |row_index, mut row| {
let headers_i_offset = csv_data.are_headers as usize;
row.col(|ui|{
if ui.button("x").clicked(){}
});
for curr_cell in
csv_data.data.iter_row_mut(row_index + headers_i_offset)
{
/* If cell is bound to a field, color it's bg according to is_parsed */
row.col(|ui| {
let mut err: Option<Arc<dyn Error>> = None;
if curr_cell.curr_field_description.is_some() {
match &curr_cell.is_parsed{
Some(parse) => match parse{
Ok(_) => ui.style_mut().visuals.extreme_bg_color = egui::Color32::DARK_GREEN,
Err(arc) => {
err = Some(arc.clone());
ui.style_mut().visuals.extreme_bg_color = egui::Color32::DARK_RED;
}
}
None => ui.style_mut().visuals.extreme_bg_color = egui::Color32::DARK_GRAY,
}
}
if err.is_some(){
ui.text_edit_singleline(&mut curr_cell.data).on_hover_text(format!("{}", &err.unwrap()));
} else{
ui.text_edit_singleline(&mut curr_cell.data);
}
if curr_cell.curr_field_description.is_some() {
ui.reset_style();
}
});
}
});
});
}
} else {
ui.centered_and_justified(|ui| ui.heading("Drag and drop or Open a file..."));
}
Ok(())
}
} }
impl SpreadSheetWindow { impl SpreadSheetWindow {
@ -253,7 +276,9 @@ impl SpreadSheetWindow {
for i in 0..csv_data.data.cols() { for i in 0..csv_data.data.cols() {
header.col(|ui| { header.col(|ui| {
ui.vertical_centered_justified(|ui| { ui.vertical_centered_justified(|ui| {
if ui.button("x").clicked() {} if ui.button("x").clicked() {
if let Ok(_) = sender.try_send(Communication::RemoveCol(i)) {}
}
if csv_data.parsed_cols.contains(&i) { if csv_data.parsed_cols.contains(&i) {
/* If the whole col is parsed, change header bg to green, else normal */ /* If the whole col is parsed, change header bg to green, else normal */
ui.style_mut().visuals.override_text_color = Some(egui::Color32::GREEN); ui.style_mut().visuals.override_text_color = Some(egui::Color32::GREEN);
@ -340,12 +365,12 @@ impl SpreadSheetWindow {
} else { } else {
return; return;
} }
self.sender
.try_send(Communication::LoadImportFilePath(
final_path.display().to_string(),
))
.unwrap_or_else(|err| println!("failed to send loadimportpath, {}", err));
} }
self.sender
.try_send(Communication::LoadImportFilePath(
final_path.display().to_string(),
))
.unwrap_or_else(|err| println!("failed to send loadimportpath, {}", err));
} }
pub fn open_dropped_file(&mut self, path: &egui::InputState) { pub fn open_dropped_file(&mut self, path: &egui::InputState) {

View file

@ -1,15 +1,15 @@
use super::db_transaction_window::DBTransactionWindow;
use crate::backend::backend_manager::Communication; use crate::backend::backend_manager::Communication;
use crate::backend::csv_handler::ImportedData; use crate::backend::csv_handler::ImportedData;
use crate::backend::database_handler::Tables; use crate::backend::database_handler::Tables;
use crate::ui::db_login_window::DBLoginWindow; use crate::ui::db_login_window::DBLoginWindow;
use crate::ui::table_window::SpreadSheetWindow; use crate::ui::table_window::SpreadSheetWindow;
use eframe::{run_native, App, NativeOptions}; use eframe::{run_native, App, NativeOptions};
use if_chain::*;
use std::sync::Arc; use std::sync::Arc;
use tokio::sync::mpsc::{channel, Sender}; use tokio::sync::mpsc::{channel, Sender};
use tokio::sync::Mutex; use tokio::sync::Mutex;
use super::db_transaction_window::DBTransactionWindow;
pub fn create_ui( pub fn create_ui(
sender: Sender<Communication>, sender: Sender<Communication>,
csv_data_handle: Arc<Mutex<ImportedData>>, csv_data_handle: Arc<Mutex<ImportedData>>,
@ -60,8 +60,11 @@ impl App for CSQL {
if let Some(result) = self.spreadsheet_window.refresh(ctx, ui, frame) { if let Some(result) = self.spreadsheet_window.refresh(ctx, ui, frame) {
match result { match result {
Ok(status) => match status { Ok(status) => match status {
ExitStatus::StartLoginWindow => self.should_open_transaction_window = true, ExitStatus::StartLoginWindow => self.should_open_login_window = true,
ExitStatus::StartTransactionWindow => self.should_open_login_window = true, ExitStatus::StartTransactionWindow => {
self.should_open_transaction_window = true;
println!("should_open_transaction_window");
}
_ => {} _ => {}
}, },
_ => (), _ => (),
@ -83,7 +86,9 @@ impl App for CSQL {
self.db_login_window = Some(DBLoginWindow::default(self.sender.clone())); self.db_login_window = Some(DBLoginWindow::default(self.sender.clone()));
} }
} }
if self.should_open_transaction_window { if self.should_open_transaction_window {
println!("inside if.shoud...");
if let Some(db_transaction_window) = self.db_transaction_window.as_mut() { if let Some(db_transaction_window) = self.db_transaction_window.as_mut() {
if let Some(result) = db_transaction_window.refresh(ctx, ui, frame) { if let Some(result) = db_transaction_window.refresh(ctx, ui, frame) {
match result { match result {
@ -95,14 +100,17 @@ impl App for CSQL {
} }
} }
} else { } else {
println!("No transaction window, creating...");
if let Ok(db_table_data) = self.db_table_data_handle.try_lock() { if let Ok(db_table_data) = self.db_table_data_handle.try_lock() {
println!("got a db_lock");
if let Some(cw_table_i) = db_table_data.current_working_table { if let Some(cw_table_i) = db_table_data.current_working_table {
println!("Found a current_working _table");
self.db_transaction_window = Some(DBTransactionWindow::default( self.db_transaction_window = Some(DBTransactionWindow::default(
self.sender.clone(), self.sender.clone(),
cw_table_i, cw_table_i,
)) ))
} }
} };
} }
} }
}); });