Skip to content
58 changes: 27 additions & 31 deletions app/src/conn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use crate::modifier::{
activity_swap_position, add_new_tx, add_new_tx_methods, delete_tx,
};
use crate::ui_helper::{Autofiller, Stepper, Verifier};
use crate::utils::month_name_to_num;
use crate::utils::parse_month_year;
use crate::views::{
ActivityView, ChartView, SearchView, SummaryView, TxViewGroup, get_activity_view,
get_chart_view, get_search_txs, get_summary, get_txs,
Expand Down Expand Up @@ -78,7 +78,6 @@ impl DbConn {
cache: Cache {
tags: HashMap::new(),
tx_methods: HashMap::new(),
txs: None,
details: HashSet::new(),
},
};
Expand All @@ -98,7 +97,6 @@ impl DbConn {
cache: Cache {
tags: HashMap::new(),
tx_methods: HashMap::new(),
txs: None,
details: HashSet::new(),
},
}
Expand Down Expand Up @@ -212,10 +210,7 @@ impl DbConn {
let result = self.conn.transaction::<TxViewGroup, Error, _>(|conn| {
let mut db_conn = MutDbConn::new(conn, &self.cache);

let year_num = year.parse::<i32>().unwrap();
let month_num = month_name_to_num(month);

let date = NaiveDate::from_ymd_opt(year_num, month_num, 1).unwrap();
let date = parse_month_year(month, year)?;

get_txs(date, nature, &mut db_conn)
})?;
Expand Down Expand Up @@ -257,24 +252,13 @@ impl DbConn {
year: &'a str,
nature: FetchNature,
) -> Result<SummaryView> {
let (summary, txs) = self
.conn
.transaction::<(SummaryView, Option<HashMap<i32, Vec<FullTx>>>), Error, _>(|conn| {
let mut db_conn = MutDbConn::new(conn, &self.cache);

let year_num = year.parse::<i32>().unwrap();
let month_num = month_name_to_num(month);

let date = NaiveDate::from_ymd_opt(year_num, month_num, 1).unwrap();

get_summary(date, nature, &mut db_conn)
})?;
self.conn.transaction::<SummaryView, Error, _>(|conn| {
let mut db_conn = MutDbConn::new(conn, &self.cache);

if let Some(txs) = txs {
self.cache.set_txs(txs);
}
let date = parse_month_year(month, year)?;

Ok(summary)
get_summary(date, nature, &mut db_conn)
})
}

pub fn get_chart_view_with_str<'a>(
Expand All @@ -286,10 +270,7 @@ impl DbConn {
let result = self.conn.transaction::<ChartView, Error, _>(|conn| {
let mut db_conn = MutDbConn::new(conn, &self.cache);

let year_num = year.parse::<i32>().unwrap();
let month_num = month_name_to_num(month);

let date = NaiveDate::from_ymd_opt(year_num, month_num, 1).unwrap();
let date = parse_month_year(month, year)?;

let tx_view = get_txs(date, nature, &mut db_conn)?;

Expand All @@ -309,10 +290,7 @@ impl DbConn {
let result = self.conn.transaction::<ActivityView, Error, _>(|conn| {
let mut db_conn = MutDbConn::new(conn, &self.cache);

let year_num = year.parse::<i32>().unwrap();
let month_num = month_name_to_num(month);

let date = NaiveDate::from_ymd_opt(year_num, month_num, 1).unwrap();
let date = parse_month_year(month, year)?;

let activity_view = get_activity_view(date, &mut db_conn)?;

Expand Down Expand Up @@ -361,6 +339,19 @@ impl DbConn {
Ok(())
}

pub fn rename_tag(&mut self, old_name: &str, new_name: &str) -> Result<()> {
let new_tag = self.conn.transaction::<Tag, Error, _>(|conn| {
let mut db_conn = MutDbConn::new(conn, &self.cache);

Ok(Tag::update_name(old_name, new_name, &mut db_conn)?)
})?;

let tag = self.cache.tags.get_mut(&new_tag.id).unwrap();
tag.name = new_name.to_string();

Ok(())
}

pub fn set_new_tx_method_positions(&mut self, new_format: &[String]) -> Result<()> {
let mut new_method_positions = Vec::new();

Expand Down Expand Up @@ -397,6 +388,11 @@ impl DbConn {
self.cache.get_methods()
}

#[must_use]
pub fn get_tags_sorted(&self) -> Vec<&Tag> {
self.cache.get_tags_sorted()
}

#[must_use]
pub fn get_tx_methods_cumulative(&self) -> Vec<String> {
let mut methods: Vec<String> = self
Expand Down
14 changes: 3 additions & 11 deletions app/src/migration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use std::io::Write;
use crate::conn::{DbConn, MutDbConn};
use crate::modifier::add_new_tx_methods;
use crate::utils::parse_amount_nature_cent;
use crate::utils::split_tags;

#[derive(QueryableByName)]
struct ColumnInfo {
Expand Down Expand Up @@ -283,19 +284,10 @@ fn migrate_tx(
Some(db_conn.cache().get_method_id(to_method).unwrap())
};

let mut tag_list = Vec::new();
let mut tag_list = split_tags(tags);

if tags.is_empty() {
if tag_list.is_empty() {
tag_list.push("Unknown".to_string());
} else {
let split_tags = tags.split(',').collect::<Vec<&str>>();

for tag in split_tags {
let trimmed_tag = tag.trim();
if !trimmed_tag.is_empty() {
tag_list.push(trimmed_tag.to_string());
}
}
}

let new_tx = NewTx::new(
Expand Down
29 changes: 7 additions & 22 deletions app/src/modifier/new_activity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,18 @@ use rex_db::models::{
ActivityNature, ActivityTxTag, FullTx, NewActivity, NewActivityTx, NewSearch, NewTx, Tag,
};

use crate::utils::split_tags;

pub(crate) fn activity_new_tx(tx: &NewTx, tags: &str, conn: &mut impl ConnCache) -> Result<()> {
let activity_type = ActivityNature::AddTx;

let new_activity = NewActivity::new(activity_type).insert(conn)?;
let added_tx = NewActivityTx::new_from_new_tx(tx, new_activity.id).insert(conn)?;

let mut tag_list = Vec::new();
let mut tag_list = split_tags(tags);

if tags.is_empty() {
if tag_list.is_empty() {
tag_list.push("Unknown".to_string());
} else {
let split_tags = tags.split(',').collect::<Vec<&str>>();

for tag in split_tags {
let trimmed_tag = tag.trim();
if !trimmed_tag.is_empty() {
tag_list.push(trimmed_tag.to_string());
}
}
}

let mut tx_tags = Vec::new();
Expand Down Expand Up @@ -80,24 +73,16 @@ pub(crate) fn activity_edit_tx(
NewActivityTx::new_from_full_tx(old_tx, false, new_activity.id).insert(conn)?;

let mut old_tag_list = Vec::new();
let mut new_tag_list = Vec::new();

for tag in &old_tx.tags {
let tag = ActivityTxTag::new(old_tx_activity.id, tag.id);
old_tag_list.push(tag);
}

if tags.is_empty() {
let mut new_tag_list = split_tags(tags);

if new_tag_list.is_empty() {
new_tag_list.push("Unknown".to_string());
} else {
let split_tags = tags.split(',').collect::<Vec<&str>>();

for tag in split_tags {
let trimmed_tag = tag.trim();
if !trimmed_tag.is_empty() {
new_tag_list.push(trimmed_tag.to_string());
}
}
}

let mut new_tags = Vec::new();
Expand Down
14 changes: 3 additions & 11 deletions app/src/modifier/new_tx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use rex_db::ConnCache;
use rex_db::models::{Balance, NewTag, NewTx, Tag, Tx, TxTag, TxType};

use crate::modifier::tidy_balances;
use crate::utils::split_tags;

pub(crate) fn add_new_tx(
tx: NewTx,
Expand All @@ -15,19 +16,10 @@ pub(crate) fn add_new_tx(
let to_method = tx.to_method;
let amount = tx.amount;
let tx_type = tx.tx_type;
let mut tag_list = Vec::new();
let mut tag_list = split_tags(tags);

if tags.is_empty() {
if tag_list.is_empty() {
tag_list.push("Unknown".to_string());
} else {
let split_tags = tags.split(',').collect::<Vec<&str>>();

for tag in split_tags {
let trimmed_tag = tag.trim();
if !trimmed_tag.is_empty() {
tag_list.push(trimmed_tag.to_string());
}
}
}

let mut current_balance = Balance::get_balance_map(date.date(), db_conn)?;
Expand Down
17 changes: 9 additions & 8 deletions app/src/modifier/shared.rs
Original file line number Diff line number Diff line change
Expand Up @@ -217,14 +217,15 @@ pub fn parse_search_fields<'a>(
let tags = if tags.is_empty() {
None
} else {
let tags = tags.split(',').map(str::trim).collect::<Vec<&str>>();
let tags = tags
.iter()
.map(|t| db_conn.cache().get_tag_id(t))
.filter_map(Result::ok)
.collect::<Vec<i32>>();

Some(tags)
let tag_names = tags.split(',').map(str::trim).filter(|s| !s.is_empty());

let mut tag_ids = Vec::new();

for t in tag_names {
tag_ids.push(db_conn.cache().get_tag_id(t)?);
}

Some(tag_ids)
};

let search_tx = NewSearch::new(
Expand Down
83 changes: 50 additions & 33 deletions app/src/utils.rs
Original file line number Diff line number Diff line change
@@ -1,22 +1,40 @@
use anyhow::Result;
use anyhow::{Result, anyhow};
use chrono::NaiveDate;
use rex_db::models::AmountNature;
use rex_shared::models::{Cent, Dollar};

pub fn month_name_to_num(name: &str) -> u32 {
pub fn split_tags(input: &str) -> Vec<String> {
input
.split(',')
.map(str::trim)
.filter(|s| !s.is_empty())
.map(|s| s.to_string())
.collect()
}

pub fn parse_month_year(month: &str, year: &str) -> Result<NaiveDate> {
let year_num = year.parse::<i32>()?;
let month_num = month_name_to_num(month)?;

NaiveDate::from_ymd_opt(year_num, month_num, 1)
.ok_or_else(|| anyhow!("Invalid date: {year}-{month}-01"))
}

pub fn month_name_to_num(name: &str) -> Result<u32> {
match name {
"January" => 1,
"February" => 2,
"March" => 3,
"April" => 4,
"May" => 5,
"June" => 6,
"July" => 7,
"August" => 8,
"September" => 9,
"October" => 10,
"November" => 11,
"December" => 12,
_ => panic!("Invalid month name {name}"),
"January" => Ok(1),
"February" => Ok(2),
"March" => Ok(3),
"April" => Ok(4),
"May" => Ok(5),
"June" => Ok(6),
"July" => Ok(7),
"August" => Ok(8),
"September" => Ok(9),
"October" => Ok(10),
"November" => Ok(11),
"December" => Ok(12),
_ => Err(anyhow!("Invalid month name {name}")),
}
}

Expand Down Expand Up @@ -84,24 +102,23 @@ mod tests {

#[test]
fn test_month_name_to_num_all_months() {
assert_eq!(month_name_to_num("January"), 1);
assert_eq!(month_name_to_num("February"), 2);
assert_eq!(month_name_to_num("March"), 3);
assert_eq!(month_name_to_num("April"), 4);
assert_eq!(month_name_to_num("May"), 5);
assert_eq!(month_name_to_num("June"), 6);
assert_eq!(month_name_to_num("July"), 7);
assert_eq!(month_name_to_num("August"), 8);
assert_eq!(month_name_to_num("September"), 9);
assert_eq!(month_name_to_num("October"), 10);
assert_eq!(month_name_to_num("November"), 11);
assert_eq!(month_name_to_num("December"), 12);
}

#[test]
#[should_panic(expected = "Invalid month name")]
fn test_month_name_to_num_invalid_panics() {
month_name_to_num("NotAMonth");
assert_eq!(month_name_to_num("January").unwrap(), 1);
assert_eq!(month_name_to_num("February").unwrap(), 2);
assert_eq!(month_name_to_num("March").unwrap(), 3);
assert_eq!(month_name_to_num("April").unwrap(), 4);
assert_eq!(month_name_to_num("May").unwrap(), 5);
assert_eq!(month_name_to_num("June").unwrap(), 6);
assert_eq!(month_name_to_num("July").unwrap(), 7);
assert_eq!(month_name_to_num("August").unwrap(), 8);
assert_eq!(month_name_to_num("September").unwrap(), 9);
assert_eq!(month_name_to_num("October").unwrap(), 10);
assert_eq!(month_name_to_num("November").unwrap(), 11);
assert_eq!(month_name_to_num("December").unwrap(), 12);
}

#[test]
fn test_month_name_to_num_invalid_errors() {
assert!(month_name_to_num("NotAMonth").is_err());
}

#[test]
Expand Down
Loading
Loading