Skip to content

Commit

Permalink
fix: balance in range query (#189)
Browse files Browse the repository at this point in the history
  • Loading branch information
bodymindarts authored Aug 15, 2024
1 parent 05fd2ee commit 9c9349d
Show file tree
Hide file tree
Showing 6 changed files with 144 additions and 14 deletions.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

40 changes: 35 additions & 5 deletions cala-ledger/src/balance/account_balance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,11 +70,41 @@ pub struct BalanceRange {
}

impl BalanceRange {
pub fn new(start: AccountBalance, end: AccountBalance) -> Self {
Self {
start: start.clone(),
diff: start.derive_diff(&end),
end,
pub fn new(start: Option<AccountBalance>, end: AccountBalance) -> Self {
match start {
Some(start) => Self {
end: end.clone(),
diff: end.derive_diff(&start),
start,
},
None => {
use chrono::{TimeZone, Utc};
let zero_time = Utc.timestamp_opt(0, 0).single().expect("0 timestamp");
let zero_entry = EntryId::from(super::UNASSIGNED_ENTRY_ID);
let zero_amount = BalanceAmount {
dr_balance: Decimal::ZERO,
cr_balance: Decimal::ZERO,
entry_id: zero_entry,
modified_at: zero_time,
};
Self {
diff: end.clone(),
end: end.clone(),
start: AccountBalance {
balance_type: end.balance_type,
details: BalanceSnapshot {
version: 0,
created_at: zero_time,
modified_at: zero_time,
entry_id: zero_entry,
settled: zero_amount.clone(),
pending: zero_amount.clone(),
encumbrance: zero_amount,
..end.details
},
},
}
}
}
}
}
3 changes: 1 addition & 2 deletions cala-ledger/src/balance/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,7 @@ impl Balances {
.find_range(journal_id, account_id, currency, from, until)
.await?
{
(Some(start), Some(end)) => Ok(BalanceRange::new(start, end)),
(None, Some(end)) => Ok(BalanceRange::new(end.clone(), end)),
(start, Some(end)) => Ok(BalanceRange::new(start, end)),
_ => Err(BalanceError::NotFound(journal_id, account_id, currency)),
}
}
Expand Down
6 changes: 3 additions & 3 deletions cala-ledger/src/balance/repo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,8 @@ impl BalanceRepo {
AND h.journal_id = $1
AND h.account_id = $2
AND h.currency = $3
AND h.recorded_at >= $4
ORDER BY h.recorded_at
AND h.recorded_at < $4
ORDER BY h.recorded_at DESC, h.version DESC
LIMIT 1
),
last AS (
Expand All @@ -126,7 +126,7 @@ impl BalanceRepo {
AND h.account_id = $2
AND h.currency = $3
AND h.recorded_at <= COALESCE($5, NOW())
ORDER BY h.recorded_at DESC
ORDER BY h.recorded_at DESC, h.version DESC
LIMIT 1
)
SELECT * FROM first
Expand Down
101 changes: 101 additions & 0 deletions cala-ledger/tests/balance.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
mod helpers;

use chrono::{TimeZone, Utc};
use rust_decimal::Decimal;

use cala_ledger::{tx_template::*, *};
use rand::distributions::{Alphanumeric, DistString};

#[tokio::test]
async fn balance_in_range() -> anyhow::Result<()> {
let btc: Currency = "BTC".parse().unwrap();

let pool = helpers::init_pool().await?;
let cala_config = CalaLedgerConfig::builder()
.pool(pool)
.exec_migrations(false)
.build()?;

let cala = CalaLedger::init(cala_config).await?;

let new_journal = helpers::test_journal();
let journal = cala.journals().create(new_journal).await.unwrap();
let (sender, receiver) = helpers::test_accounts();
let sender_account = cala.accounts().create(sender).await.unwrap();
let recipient_account = cala.accounts().create(receiver).await.unwrap();

let tx_code = Alphanumeric.sample_string(&mut rand::thread_rng(), 32);
let new_template = helpers::test_template(&tx_code);

cala.tx_templates().create(new_template).await.unwrap();
let mut params = Params::new();
params.insert("journal_id", journal.id().to_string());
params.insert("sender", sender_account.id());
params.insert("recipient", recipient_account.id());

cala.post_transaction(TransactionId::new(), &tx_code, params)
.await
.unwrap();

let range = cala
.balances()
.find_in_range(
journal.id(),
recipient_account.id(),
btc,
Utc.timestamp_opt(0, 0).single().unwrap(),
None,
)
.await?;

assert_eq!(range.start.settled(), Decimal::ZERO);
assert_eq!(range.end.settled(), Decimal::from(1290));
assert_eq!(range.diff.settled(), Decimal::from(1290));
assert_eq!(range.end.details.version, 1);

let after_first_before_second_tx = Utc::now();
tokio::time::sleep(std::time::Duration::from_millis(500)).await;

let mut params = Params::new();
params.insert("journal_id", journal.id().to_string());
params.insert("sender", sender_account.id());
params.insert("recipient", recipient_account.id());

cala.post_transaction(TransactionId::new(), &tx_code, params)
.await
.unwrap();

let range = cala
.balances()
.find_in_range(
journal.id(),
recipient_account.id(),
btc,
Utc.timestamp_opt(0, 0).single().unwrap(),
Some(after_first_before_second_tx),
)
.await?;

assert_eq!(range.start.settled(), Decimal::ZERO);
assert_eq!(range.end.settled(), Decimal::from(1290));
assert_eq!(range.diff.settled(), Decimal::from(1290));
assert_eq!(range.end.details.version, 1);

let range = cala
.balances()
.find_in_range(
journal.id(),
recipient_account.id(),
btc,
after_first_before_second_tx,
None,
)
.await?;

assert_eq!(range.start.settled(), Decimal::from(1290));
assert_eq!(range.end.settled(), Decimal::from(2580));
assert_eq!(range.diff.settled(), Decimal::from(1290));
assert_eq!(range.end.details.version, 2);

Ok(())
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 9c9349d

Please sign in to comment.