Skip to content

Commit

Permalink
[cache] cache XIRR computation
Browse files Browse the repository at this point in the history
refer #127
  • Loading branch information
ananthakumaran committed Feb 2, 2024
1 parent 4551a85 commit 798154b
Show file tree
Hide file tree
Showing 6 changed files with 91 additions and 10 deletions.
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ require (
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/kelindar/binary v1.0.18 // indirect
github.com/klauspost/cpuid/v2 v2.2.6 // indirect
github.com/labstack/echo/v4 v4.11.1 // indirect
github.com/labstack/gommon v0.4.0 // indirect
Expand All @@ -57,6 +58,7 @@ require (
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-sqlite3 v1.14.19 // indirect
github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/pelletier/go-toml/v2 v2.1.1 // indirect
Expand Down
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,8 @@ github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/kelindar/binary v1.0.18 h1:xGKmvb6Q3bpvvhKULfB0rG5vLOjtpoZn/FgPpnTl+aI=
github.com/kelindar/binary v1.0.18/go.mod h1:/twdz8gRLNMffx0U4UOgqm1LywPs6nd9YK2TX52MDh8=
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.2.6 h1:ndNyv040zDGIDh8thGkXYjnFtiN02M1PVVF+JE/48xc=
github.com/klauspost/cpuid/v2 v2.2.6/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
Expand Down Expand Up @@ -136,6 +138,8 @@ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWE
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-sqlite3 v1.14.19 h1:fhGleo2h1p8tVChob4I9HpmVFIAkKGpiukdrgQbWfGI=
github.com/mattn/go-sqlite3 v1.14.19/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4=
github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
Expand Down
58 changes: 58 additions & 0 deletions internal/model/cache/cache.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package cache

import (
"fmt"
"time"

"github.com/kelindar/binary"
"github.com/mitchellh/hashstructure/v2"
"gorm.io/gorm"
)

type Cache struct {
ID uint `gorm:"primaryKey" json:"id"`
ExpiresAt time.Time `json:"expires_at"`
HashKey string `json:"hash_key"`
Value []byte `gorm:"type:BLOB" json:"item"`
}

func DeleteExpired(db *gorm.DB) error {
err := db.Exec("DELETE FROM caches WHERE expires_at < ?", time.Now()).Error
if err != nil {
return err
}
return nil
}

func Lookup[I any, K any](db *gorm.DB, key K, fallback func() I) I {
var item I
var cache Cache

hash, err := hashstructure.Hash(key, hashstructure.FormatV2, nil)
hashKey := fmt.Sprintf("%d", hash)
if err == nil {
err := db.Where("hash_key = ?", hashKey).First(&cache).Error
if err == nil {
if time.Now().Before(cache.ExpiresAt) {
err := binary.Unmarshal(cache.Value, &item)
if err == nil {
return item
}
} else {
DeleteExpired(db)
}
}
}

item = fallback()
bytes, err := binary.Marshal(item)
if err == nil {
cache = Cache{
ExpiresAt: time.Now().Add(24 * time.Hour),
HashKey: hashKey,
Value: bytes,
}
db.Save(&cache)
}
return item
}
2 changes: 2 additions & 0 deletions internal/model/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (

"github.com/ananthakumaran/paisa/internal/config"
"github.com/ananthakumaran/paisa/internal/ledger"
"github.com/ananthakumaran/paisa/internal/model/cache"
"github.com/ananthakumaran/paisa/internal/model/cii"
"github.com/ananthakumaran/paisa/internal/model/commodity"
mutualfundModel "github.com/ananthakumaran/paisa/internal/model/mutualfund/scheme"
Expand All @@ -29,6 +30,7 @@ func AutoMigrate(db *gorm.DB) {
db.AutoMigrate(&portfolio.Portfolio{})
db.AutoMigrate(&price.Price{})
db.AutoMigrate(&cii.CII{})
db.AutoMigrate(&cache.Cache{})
}

func SyncJournal(db *gorm.DB) (string, error) {
Expand Down
10 changes: 8 additions & 2 deletions internal/service/xirr.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package service

import (
"github.com/ananthakumaran/paisa/internal/model/cache"
"github.com/ananthakumaran/paisa/internal/model/posting"
"github.com/ananthakumaran/paisa/internal/utils"
"github.com/ananthakumaran/paisa/internal/xirr"
Expand All @@ -26,7 +27,9 @@ func XIRR(db *gorm.DB, ps []posting.Posting) decimal.Decimal {
}))

cashflows = append(cashflows, xirr.Cashflow{Date: today, Amount: marketAmount.Round(4).InexactFloat64()})
return xirr.XIRR(cashflows)
return cache.Lookup(db, cashflows, func() decimal.Decimal {
return xirr.XIRR(cashflows)
})
}

func APR(db *gorm.DB, ps []posting.Posting) decimal.Decimal {
Expand All @@ -38,5 +41,8 @@ func APR(db *gorm.DB, ps []posting.Posting) decimal.Decimal {
return xirr.Cashflow{Date: p.Date, Amount: p.Amount.Round(4).InexactFloat64()}
})
cashflows = append(cashflows, xirr.Cashflow{Date: today, Amount: marketAmount.Neg().Round(4).InexactFloat64()})
return xirr.XIRR(cashflows)

return cache.Lookup(db, cashflows, func() decimal.Decimal {
return xirr.XIRR(cashflows)
})
}
25 changes: 17 additions & 8 deletions src/routes/(app)/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@
<div class="tile is-child">
<div class="content">
<p class="subtitle">
<a class="secondary-link" href="/assets/networth">Assets</a>
<a class="secondary-link has-text-grey" href="/assets/networth">Assets</a>
</p>
<div class="content">
<div>
Expand Down Expand Up @@ -201,7 +201,8 @@
<article class="tile is-child">
<div class="content">
<p class="subtitle">
<a class="secondary-link" href="/assets/balance">Checking Balance</a>
<a class="secondary-link has-text-grey" href="/assets/balance">Checking Balance</a
>
</p>
<div class="content">
<UntypedMasonryGrid gap={10} maxStretchColumnSize={400} align="stretch">
Expand All @@ -220,7 +221,7 @@
<div class="tile is-parent">
<article class="tile is-child min-w-0">
<p class="subtitle">
<a class="secondary-link" href="/cash_flow/monthly">Cash Flow</a>
<a class="secondary-link has-text-grey" href="/cash_flow/monthly">Cash Flow</a>
</p>
<div class="content box px-2 pb-0">
<ZeroState item={cashFlows}>
Expand All @@ -243,7 +244,7 @@
<div class="tile is-child">
<div class="content">
<p class="subtitle">
<a class="secondary-link" href="/expense/budget">Budget</a>
<a class="secondary-link has-text-grey" href="/expense/budget">Budget</a>
</p>
<div class="content">
<div>
Expand All @@ -262,7 +263,7 @@
<article class="tile is-child">
<div class="content">
<p class="subtitle">
<a class="secondary-link" href="/more/goals">Goals</a>
<a class="secondary-link has-text-grey" href="/more/goals">Goals</a>
</p>
<div class="content">
{#each goalSummaries as goal}
Expand All @@ -280,7 +281,7 @@
<article class="tile is-child">
<p class="subtitle is-flex is-justify-content-space-between is-align-items-end">
<span
><a class="secondary-link" href="/expense/monthly">Expenses</a>
><a class="secondary-link has-text-grey" href="/expense/monthly">Expenses</a>
<span class="is-size-5 has-text-weight-bold px-2" style="color: {COLORS.expenses}"
>{formatCurrency(totalExpense)}</span
></span
Expand All @@ -301,7 +302,8 @@
<article class="tile is-child">
<div class="content">
<p class="subtitle">
<a class="secondary-link" href="/cash_flow/recurring">Recurring</a>
<a class="secondary-link has-text-grey" href="/cash_flow/recurring">Recurring</a
>
</p>
<div class="content box">
<div
Expand All @@ -324,7 +326,9 @@
<article class="tile is-child">
<div class="content">
<p class="subtitle">
<a class="secondary-link" href="/ledger/transaction">Recent Transactions</a>
<a class="secondary-link has-text-grey" href="/ledger/transaction"
>Recent Transactions</a
>
</p>
<div>
<UntypedMasonryGrid gap={10} maxStretchColumnSize={500} align="stretch">
Expand All @@ -349,4 +353,9 @@
p.subtitle {
margin-bottom: 0.5rem !important;
}
p.subtitle a.secondary-link {
text-transform: uppercase;
font-size: 1rem;
}
</style>

0 comments on commit 798154b

Please sign in to comment.