Skip to content

Commit

Permalink
Merge pull request #46 from frosklis/release/0.14
Browse files Browse the repository at this point in the history
release/0.14
  • Loading branch information
frosklis authored Feb 27, 2021
2 parents 2c4e424 + 1f17a5c commit e3351de
Show file tree
Hide file tree
Showing 16 changed files with 300 additions and 140 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
# Changelog
Changelog file for dinero-rs project, a command line application for managing finances.

## [0.14.0]
### Fixed
- speed bump, from 7 seconds to 4 seconds in my personal ledger (still room to improve)
- ability to add tags from automated transactions
## [0.13.1] - 2021-02-27
### Fixed
- Fixed issue when there is no specified payee
Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,4 @@ two_timer = "2.2.0"
assert_cmd = "1.0.3"
terminal_size = "0.1.16"
pest = "2.0"
pest_derive = "2.0"
pest_derive = "2.0"
1 change: 1 addition & 0 deletions examples/automated.ledger
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,6 @@
Expenses:Rent 705.43 EUR
Assets:Checking account
2021-01-06 * Meal | My favorite restaurant
; :one_tag:
Expenses:Restaurants 58.33 EUR
Assets:Cash
2 changes: 1 addition & 1 deletion scripts/bench.sh
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#!/bin/sh
echo "This benchmark needs ledgerrc to be properly set up for it to be meaningful"

hyperfine 'dinero bal'
hyperfine 'ledger bal'

hyperfine 'dinero bal'
15 changes: 14 additions & 1 deletion src/commands/balance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use std::path::PathBuf;
use colored::Colorize;

use crate::models::{conversion, Account, Balance, Currency, HasName, Money};
use crate::parser::value_expr::build_root_node_from_expression;
use crate::parser::Tokenizer;
use crate::Error;
use crate::{filter, CommonOpts};
Expand All @@ -24,9 +25,21 @@ pub fn execute(options: &CommonOpts, flat: bool, show_total: bool) -> Result<(),

let mut balances: HashMap<Rc<Account>, Balance> = HashMap::new();

// Build a cache of abstract value trees, it takes time to parse expressions, so better do it only once
let mut regexes = HashMap::new();
let query = filter::preprocess_query(&options.query);
let node = if query.len() > 2 {
Some(build_root_node_from_expression(
query.as_str(),
&mut regexes,
))
} else {
None
};

for t in ledger.transactions.iter() {
for p in t.postings_iter() {
if !filter::filter(&options, t, p, &mut ledger.commodities)? {
if !filter::filter(&options, &node, t, p, &mut ledger.commodities)? {
continue;
}
let mut cur_bal = balances
Expand Down
17 changes: 16 additions & 1 deletion src/commands/register.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
use crate::models::{Balance, Money};
use crate::parser::value_expr::build_root_node_from_expression;
use crate::parser::Tokenizer;
use crate::Error;
use crate::{filter, CommonOpts};
use colored::Colorize;
use std::collections::HashMap;
use terminal_size::{terminal_size, Width};

/// Register report
Expand Down Expand Up @@ -33,10 +35,23 @@ pub fn execute(options: &CommonOpts) -> Result<(), Error> {
} else {
width - w_date - w_description - w_amount - w_balance
};

// Build a cache of abstract value trees, it takes time to parse expressions, so better do it only once
let mut regexes = HashMap::new();
let query = filter::preprocess_query(&options.query);
let node = if query.len() > 2 {
Some(build_root_node_from_expression(
query.as_str(),
&mut regexes,
))
} else {
None
};

for t in ledger.transactions.iter() {
let mut counter = 0;
for p in t.postings_iter() {
if !filter::filter(&options, t, p, &mut ledger.commodities)? {
if !filter::filter(&options, &node, t, p, &mut ledger.commodities)? {
continue;
}
counter += 1;
Expand Down
30 changes: 13 additions & 17 deletions src/filter.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
use crate::models::{Currency, Posting, PostingType, Transaction};
use crate::parser::value_expr::{eval_expression, EvalResult};
use crate::parser::value_expr::{eval, eval_expression, EvalResult, Node};
use crate::{CommonOpts, Error, List};
use colored::Colorize;
use regex::Regex;
use std::collections::HashMap;

pub fn filter(
options: &CommonOpts,
node: &Option<Node>,
transaction: &Transaction<Posting>,
posting: &Posting,
commodities: &mut List<Currency>,
) -> Result<bool, Error> {
// Get what's needed
let predicate = preprocess_query(&options.query);
let real = options.real;

// Check for real postings
Expand All @@ -35,31 +35,27 @@ pub fn filter(
return Ok(false);
}
}

filter_predicate(
predicate.as_str(),
posting,
transaction,
commodities,
&mut HashMap::new(),
)
match node {
Some(x) => filter_expression(x, posting, transaction, commodities, &mut HashMap::new()),
None => Ok(true),
}
}

pub fn filter_predicate(
predicate: &str,
pub fn filter_expression(
predicate: &Node,
posting: &Posting,
transaction: &Transaction<Posting>,
commodities: &mut List<Currency>,
regexes: &mut HashMap<String, Regex>,
) -> Result<bool, Error> {
if (predicate.len() == 0) | (predicate == "()") {
return Ok(true);
}
let result = eval_expression(predicate, posting, transaction, commodities, regexes);
let result = eval(predicate, posting, transaction, commodities, regexes);
match result {
EvalResult::Boolean(b) => Ok(b),
_ => Err(Error {
message: vec![predicate.red().bold(), "should return a boolean".normal()],
message: vec![
format!("{:?}", predicate).red().bold(),
"should return a boolean".normal(),
],
}),
}
}
Expand Down
46 changes: 34 additions & 12 deletions src/list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,19 @@ use crate::LedgerError;
pub struct List<T> {
aliases: HashMap<String, String>,
list: HashMap<String, Rc<T>>,
matches: HashMap<String, Option<String>>,
}

impl<'a, T: Eq + Hash + HasName + Clone + FromDirective + HasAliases + Debug> List<T> {
pub fn new() -> Self {
let aliases: HashMap<String, String> = HashMap::new();
let list: HashMap<String, Rc<T>> = HashMap::new();
List { aliases, list }
let matches: HashMap<String, Option<String>> = HashMap::new();
List {
aliases,
list,
matches,
}
}

/// Inserts an ```element``` in the list
Expand Down Expand Up @@ -77,20 +83,36 @@ impl<'a, T: Eq + Hash + HasName + Clone + FromDirective + HasAliases + Debug> Li
}
}
/// Gets an element from the regex
pub fn get_regex(&self, regex: Regex) -> Option<&Rc<T>> {
// Try the list
for (_alias, value) in self.list.iter() {
if regex.is_match(value.get_name()) {
return Some(value);
}
}
for (alias, value) in self.aliases.iter() {
if regex.is_match(alias) {
return self.list.get(value);
pub fn get_regex(&mut self, regex: Regex) -> Option<&Rc<T>> {
let alias = self.matches.get(regex.as_str());
match alias {
Some(x) => match x {
Some(alias) => Some(self.get(alias).unwrap()),
None => None,
},
None => {
// cache miss
for (_alias, value) in self.list.iter() {
if regex.is_match(value.get_name()) {
self.matches
.insert(regex.as_str().to_string(), Some(_alias.clone()));
return Some(value);
}
}
for (alias, value) in self.aliases.iter() {
if regex.is_match(alias) {
self.matches
.insert(regex.as_str().to_string(), Some(value.clone()));
return self.list.get(value);
}
}
self.matches.insert(regex.as_str().to_string(), None);
None
}
}
// // Try the list

None
// None
}

pub fn iter(&self) -> Iter<'_, String, Rc<T>> {
Expand Down
Loading

0 comments on commit e3351de

Please sign in to comment.