début gestion des erreurs

This commit is contained in:
thatscringebro
2026-03-27 16:01:03 -04:00
parent 366283f87e
commit 69686460b2
5 changed files with 79 additions and 28 deletions

View File

@@ -16,6 +16,8 @@ pub struct App {
pub tr_types: Vec<TransactionType>, pub tr_types: Vec<TransactionType>,
pub selected_tab: usize, pub selected_tab: usize,
pub tabs: Vec<String>, pub tabs: Vec<String>,
pub error: String,
pub error_showing: bool,
pub connection: Connection, pub connection: Connection,
} }
@@ -50,12 +52,20 @@ impl App {
"Chart 3".to_string(), "Chart 3".to_string(),
] ]
.to_vec(), .to_vec(),
error: String::new(),
error_showing: false,
connection: con, connection: con,
}; };
} }
pub fn get_list_accounts(&mut self) -> Vec<Account> { pub fn get_list_accounts(&mut self) -> Vec<Account> {
return self.acc_list.get_accounts(&self.connection); return match self.acc_list.get_accounts(&self.connection) {
Ok(a) => a,
Err(e) => {
self.error = e.to_string();
return Vec::new();
}
};
} }
pub fn next_ac(&mut self) { pub fn next_ac(&mut self) {
@@ -82,7 +92,13 @@ impl App {
pub fn save_new_account(&mut self) { pub fn save_new_account(&mut self) {
let new = self.new_account.get_id() == 0; let new = self.new_account.get_id() == 0;
self.next_ac_input(); self.next_ac_input();
let ac = data_layer::upsert_account(&self.connection, self.new_account.clone()); let ac = match data_layer::upsert_account(&self.connection, self.new_account.clone()) {
Ok(a) => a,
Err(e) => {
self.error = e.to_string();
return;
}
};
if new { if new {
self.acc_list.add_account(ac); self.acc_list.add_account(ac);
} }

View File

@@ -41,7 +41,10 @@ pub fn setup(con: &Connection) {
} }
} }
pub fn upsert_account(con: &Connection, ac: Account) -> Account { pub fn upsert_account(
con: &Connection,
ac: Account,
) -> Result<Account, Box<dyn std::error::Error>> {
let query; let query;
let ac_type = ac.get_ac_type() as i64; let ac_type = ac.get_ac_type() as i64;
if ac.get_id() == 0 { if ac.get_id() == 0 {
@@ -50,30 +53,33 @@ pub fn upsert_account(con: &Connection, ac: Account) -> Account {
query = "UPDATE Accounts SET name = :name, type = :type, asset_price = :asset_price WHERE id = :id RETURNING id;"; query = "UPDATE Accounts SET name = :name, type = :type, asset_price = :asset_price WHERE id = :id RETURNING id;";
} }
let mut statement = con.prepare(query).unwrap(); let mut statement = con
statement.bind((":name", &ac.get_name() as &str)).unwrap(); .prepare(query)
statement.bind((":type", ac_type)).unwrap(); .map_err(|e| format!("Could not prepare query: {}", e))?;
statement statement.bind((":name", &ac.get_name() as &str))?;
.bind((":asset_price", ac.get_asset_price())) statement.bind((":type", ac_type))?;
.unwrap(); statement.bind((":asset_price", ac.get_asset_price()))?;
if ac.get_id() != 0 { if ac.get_id() != 0 {
statement.bind((":id", ac.get_id())).unwrap(); statement.bind((":id", ac.get_id()))?;
} }
let id; let id;
if let Ok(State::Row) = statement.next() { if let Ok(State::Row) = statement.next() {
id = statement.read::<i64, _>("id").unwrap(); id = statement.read::<i64, _>("id")?;
} else { } else {
id = 0; id = 0;
} }
return Account::new( let ac_type_enum =
AccountType::try_from(ac_type).map_err(|_| "Could not parse account type")?;
return Ok(Account::new(
id, id,
ac.get_name(), ac.get_name(),
ac.get_asset_price(), ac.get_asset_price(),
ac_type.try_into().unwrap(), ac_type_enum,
); ));
} }
// pub fn get_account(con: &Connection, id: i64) -> Account { // pub fn get_account(con: &Connection, id: i64) -> Account {
@@ -126,27 +132,28 @@ JOIN Accounts a ON t.account_id = a.id"
} }
} }
pub fn get_accounts(con: &Connection) -> Vec<Account> { pub fn get_accounts(con: &Connection) -> Result<Vec<Account>, Box<dyn std::error::Error>> {
let query = "SELECT * FROM Accounts"; let query = "SELECT * FROM Accounts";
let mut statement = con.prepare(query).unwrap(); let mut statement = con
.prepare(query)
.map_err(|e| format!("Could not prepare query: {}", e))?;
let mut vec = Vec::<Account>::new(); let mut vec = Vec::<Account>::new();
vec.push(Account::new(0, "All".to_string(), 0.0, AccountType::Cash)); vec.push(Account::new(0, "All".to_string(), 0.0, AccountType::Cash));
while let Ok(State::Row) = statement.next() { while let Ok(State::Row) = statement.next() {
let type_i = statement.read::<i64, _>("type")?;
let ac_type_enum =
AccountType::try_from(type_i).map_err(|_| "Could not parse account type")?;
vec.push(Account::new( vec.push(Account::new(
statement.read::<i64, _>("id").unwrap(), statement.read::<i64, _>("id")?,
statement.read::<String, _>("name").unwrap(), statement.read::<String, _>("name")?,
statement.read::<f64, _>("asset_price").unwrap(), statement.read::<f64, _>("asset_price")?,
statement ac_type_enum,
.read::<i64, _>("type")
.unwrap()
.try_into()
.unwrap(),
)); ));
} }
return vec; return Ok(vec);
} }
// pub fn upsert_transaction_type(con: &Connection, tt: TransactionType) -> TransactionType { // pub fn upsert_transaction_type(con: &Connection, tt: TransactionType) -> TransactionType {

View File

@@ -17,11 +17,14 @@ impl AccountList {
}; };
} }
pub fn get_accounts(&mut self, con: &Connection) -> Vec<Account> { pub fn get_accounts(
&mut self,
con: &Connection,
) -> Result<Vec<Account>, Box<dyn std::error::Error>> {
if self.accounts.iter().count() == 0 { if self.accounts.iter().count() == 0 {
self.accounts = data_layer::get_accounts(con); self.accounts = data_layer::get_accounts(con)?;
} }
return self.accounts.clone(); return Ok(self.accounts.clone());
} }
pub fn get_selected_id(&self) -> i64 { pub fn get_selected_id(&self) -> i64 {

View File

@@ -63,6 +63,13 @@ where
continue; continue;
} }
if let KeyCode::Enter = key.code
&& app.error_showing
{
app.error = String::new();
app.error_showing = false;
}
match app.current_screen { match app.current_screen {
CurrentScreen::Main => match key.code { CurrentScreen::Main => match key.code {
KeyCode::Char('q') => { KeyCode::Char('q') => {

View File

@@ -299,6 +299,24 @@ pub fn ui(frame: &mut Frame, app: &mut App) {
frame.render_widget(Clear, area); frame.render_widget(Clear, area);
frame.render_widget(exit_paragraph, area); frame.render_widget(exit_paragraph, area);
} }
if !app.error.is_empty() {
app.error_showing = true;
let popup = Block::default()
.title("Error")
.borders(Borders::all())
.style(Style::default());
let error_text = Text::styled(&app.error, Style::default().fg(Color::Red));
let error_paragraph = Paragraph::new(error_text)
.block(popup)
.wrap(Wrap { trim: false });
let area = centered_rect(50, 20, frame.area());
frame.render_widget(Clear, area);
frame.render_widget(error_paragraph, area);
}
} }
fn centered_rect(percent_x: u16, percent_y: u16, r: Rect) -> Rect { fn centered_rect(percent_x: u16, percent_y: u16, r: Rect) -> Rect {