From 0372f0488fbaf772147b668a9875c2eb936ed263 Mon Sep 17 00:00:00 2001 From: Aaron Lindsay Date: Tue, 12 Dec 2017 20:17:39 -0500 Subject: [PATCH] Move balance calculations into DBs --- internal/reports/accounts.go | 22 ++++-------- internal/store/db/transactions.go | 60 +++++++++++++------------------ internal/store/store.go | 6 ++-- 3 files changed, 33 insertions(+), 55 deletions(-) diff --git a/internal/reports/accounts.go b/internal/reports/accounts.go index faa7778..a180021 100644 --- a/internal/reports/accounts.go +++ b/internal/reports/accounts.go @@ -6,7 +6,6 @@ import ( "github.com/aclindsa/moneygo/internal/models" "github.com/aclindsa/moneygo/internal/store" "github.com/yuin/gopher-lua" - "math/big" "strings" ) @@ -147,14 +146,6 @@ func luaAccount__index(L *lua.LState) int { return 1 } -func balanceFromSplits(splits *[]*models.Split) *big.Rat { - var balance big.Rat - for _, s := range *splits { - balance.Add(&balance, &s.Amount.Rat) - } - return &balance -} - func luaAccountBalance(L *lua.LState) int { a := luaCheckAccount(L, 1) @@ -176,23 +167,22 @@ func luaAccountBalance(L *lua.LState) int { panic("SecurityId not in lua security_map") } date := luaWeakCheckTime(L, 2) - var splits *[]*models.Split + var balance *models.Amount if date != nil { end := luaWeakCheckTime(L, 3) if end != nil { - splits, err = tx.GetAccountSplitsDateRange(user, a.AccountId, date, end) + balance, err = tx.GetAccountBalanceDateRange(user, a.AccountId, date, end) } else { - splits, err = tx.GetAccountSplitsDate(user, a.AccountId, date) + balance, err = tx.GetAccountBalanceDate(user, a.AccountId, date) } } else { - splits, err = tx.GetAccountSplits(user, a.AccountId) + balance, err = tx.GetAccountBalance(user, a.AccountId) } if err != nil { - panic("Failed to fetch splits for account:" + err.Error()) + panic("Failed to fetch balance for account:" + err.Error()) } - rat := balanceFromSplits(splits) b := &Balance{ - Amount: models.Amount{*rat}, + Amount: *balance, Security: security, } diff --git a/internal/store/db/transactions.go b/internal/store/db/transactions.go index 1bcf989..55aa1d4 100644 --- a/internal/store/db/transactions.go +++ b/internal/store/db/transactions.go @@ -305,53 +305,41 @@ func (tx *Tx) DeleteTransaction(t *models.Transaction, user *models.User) error return nil } -func (tx *Tx) GetAccountSplits(user *models.User, accountid int64) (*[]*models.Split, error) { - var modelsplits []*models.Split - var splits []*Split - - sql := "SELECT DISTINCT splits.* FROM splits INNER JOIN transactions ON transactions.TransactionId = splits.TransactionId WHERE splits.AccountId=? AND transactions.UserId=?" - _, err := tx.Select(&splits, sql, accountid, user.UserId) - if err != nil { - return nil, err - } - - for _, s := range splits { - modelsplits = append(modelsplits, s.Split()) - } - return &modelsplits, nil -} - // Assumes accountid is valid and is owned by the current user -func (tx *Tx) GetAccountSplitsDate(user *models.User, accountid int64, date *time.Time) (*[]*models.Split, error) { - var modelsplits []*models.Split - var splits []*Split +func (tx *Tx) getAccountBalance(xtrasql string, args ...interface{}) (*models.Amount, error) { + var balance models.Amount - sql := "SELECT DISTINCT splits.* FROM splits INNER JOIN transactions ON transactions.TransactionId = splits.TransactionId WHERE splits.AccountId=? AND transactions.UserId=? AND transactions.Date < ?" - _, err := tx.Select(&splits, sql, accountid, user.UserId, date) + sql := "FROM splits INNER JOIN transactions ON transactions.TransactionId = splits.TransactionId WHERE splits.AccountId=? AND transactions.UserId=?" + xtrasql + count, err := tx.SelectInt("SELECT splits.SplitId "+sql+" LIMIT 1", args...) if err != nil { return nil, err } + if count > 0 { + type bal struct { + Whole, Fractional int64 + } + var b bal + err := tx.SelectOne(&b, "SELECT sum(splits.WholeAmount) AS Whole, sum(splits.FractionalAmount) AS Fractional "+sql, args...) + if err != nil { + return nil, err + } - for _, s := range splits { - modelsplits = append(modelsplits, s.Split()) + balance.FromParts(b.Whole, b.Fractional, MaxPrecision) } - return &modelsplits, nil + + return &balance, nil } -func (tx *Tx) GetAccountSplitsDateRange(user *models.User, accountid int64, begin, end *time.Time) (*[]*models.Split, error) { - var modelsplits []*models.Split - var splits []*Split +func (tx *Tx) GetAccountBalance(user *models.User, accountid int64) (*models.Amount, error) { + return tx.getAccountBalance("", accountid, user.UserId) +} - sql := "SELECT DISTINCT splits.* FROM splits INNER JOIN transactions ON transactions.TransactionId = splits.TransactionId WHERE splits.AccountId=? AND transactions.UserId=? AND transactions.Date >= ? AND transactions.Date < ?" - _, err := tx.Select(&splits, sql, accountid, user.UserId, begin, end) - if err != nil { - return nil, err - } +func (tx *Tx) GetAccountBalanceDate(user *models.User, accountid int64, date *time.Time) (*models.Amount, error) { + return tx.getAccountBalance(" AND transactions.date < ?", accountid, user.UserId, date) +} - for _, s := range splits { - modelsplits = append(modelsplits, s.Split()) - } - return &modelsplits, nil +func (tx *Tx) GetAccountBalanceDateRange(user *models.User, accountid int64, begin, end *time.Time) (*models.Amount, error) { + return tx.getAccountBalance(" AND transactions.date >= ? AND transactions.Date < ?", accountid, user.UserId, begin, end) } func (tx *Tx) transactionsBalanceDifference(accountid int64, transactions []*models.Transaction) (*big.Rat, error) { diff --git a/internal/store/store.go b/internal/store/store.go index 412b7c6..4458c2a 100644 --- a/internal/store/store.go +++ b/internal/store/store.go @@ -89,9 +89,9 @@ type TransactionStore interface { GetTransactions(userid int64) (*[]*models.Transaction, error) UpdateTransaction(t *models.Transaction, user *models.User) error DeleteTransaction(t *models.Transaction, user *models.User) error - GetAccountSplits(user *models.User, accountid int64) (*[]*models.Split, error) - GetAccountSplitsDate(user *models.User, accountid int64, date *time.Time) (*[]*models.Split, error) - GetAccountSplitsDateRange(user *models.User, accountid int64, begin, end *time.Time) (*[]*models.Split, error) + GetAccountBalance(user *models.User, accountid int64) (*models.Amount, error) + GetAccountBalanceDate(user *models.User, accountid int64, date *time.Time) (*models.Amount, error) + GetAccountBalanceDateRange(user *models.User, accountid int64, begin, end *time.Time) (*models.Amount, error) GetAccountTransactions(user *models.User, accountid int64, sort string, page uint64, limit uint64) (*models.AccountTransactionsList, error) }