diff --git a/internal/cache/cache.go b/internal/cache/cache.go new file mode 100644 index 00000000..adb75772 --- /dev/null +++ b/internal/cache/cache.go @@ -0,0 +1,14 @@ +package cache + +import ( + "github.com/ananthakumaran/paisa/internal/accounting" + "github.com/ananthakumaran/paisa/internal/prediction" + "github.com/ananthakumaran/paisa/internal/service" +) + +func Clear() { + service.ClearInterestCache() + service.ClearPriceCache() + accounting.ClearCache() + prediction.ClearCache() +} diff --git a/internal/model/model.go b/internal/model/model.go index e118ce66..0af83b52 100644 --- a/internal/model/model.go +++ b/internal/model/model.go @@ -83,7 +83,7 @@ func SyncCommodities(db *gorm.DB) error { return fmt.Errorf("Failed to fetch price for %s: %w", name, err) } - price.UpsertAllByTypeAndID(db, commodity.Type, code, prices) + price.UpsertAllByTypeNameAndID(db, commodity.Type, name, code, prices) } return nil } diff --git a/internal/model/price/price.go b/internal/model/price/price.go index 97cc86ae..fe6dd056 100644 --- a/internal/model/price/price.go +++ b/internal/model/price/price.go @@ -24,12 +24,21 @@ func (p Price) Less(o btree.Item) bool { return p.Date.Before(o.(Price).Date) } -func UpsertAllByTypeAndID(db *gorm.DB, commodityType config.CommodityType, commodityID string, prices []*Price) { +func DeleteAll(db *gorm.DB) error { + err := db.Exec("DELETE FROM prices").Error + if err != nil { + return err + } + return nil +} + +func UpsertAllByTypeNameAndID(db *gorm.DB, commodityType config.CommodityType, commodityName string, commodityID string, prices []*Price) { err := db.Transaction(func(tx *gorm.DB) error { - err := tx.Delete(&Price{}, "commodity_type = ? and commodity_id = ?", commodityType, commodityID).Error + err := tx.Delete(&Price{}, "commodity_type = ? and (commodity_id = ? or commodity_name = ?)", commodityType, commodityID, commodityName).Error if err != nil { return err } + for _, price := range prices { err := tx.Create(price).Error if err != nil { diff --git a/internal/server/price.go b/internal/server/price.go index 578d37b8..db7316bc 100644 --- a/internal/server/price.go +++ b/internal/server/price.go @@ -6,7 +6,9 @@ import ( "github.com/samber/lo" log "github.com/sirupsen/logrus" + "github.com/ananthakumaran/paisa/internal/cache" "github.com/ananthakumaran/paisa/internal/config" + "github.com/ananthakumaran/paisa/internal/model" "github.com/ananthakumaran/paisa/internal/model/posting" "github.com/ananthakumaran/paisa/internal/model/price" "github.com/ananthakumaran/paisa/internal/scraper" @@ -50,6 +52,22 @@ func GetPriceProviders(db *gorm.DB) gin.H { } +func ClearPriceCache(db *gorm.DB) gin.H { + err := price.DeleteAll(db) + if err != nil { + return gin.H{"success": false, "message": err.Error()} + } + + cache.Clear() + + message, err := model.SyncJournal(db) + if err != nil { + return gin.H{"success": false, "message": message} + } + + return gin.H{"success": true} +} + func ClearPriceProviderCache(db *gorm.DB, code string) gin.H { provider := scraper.GetProviderByCode(code) provider.ClearCache(db) diff --git a/internal/server/server.go b/internal/server/server.go index 055182ec..0948c652 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -149,6 +149,14 @@ func Build(db *gorm.DB, enableCompression bool) *gin.Engine { router.GET("/api/ledger", func(c *gin.Context) { c.JSON(200, GetLedger(db)) }) + router.POST("/api/price/delete", func(c *gin.Context) { + if config.GetConfig().Readonly { + c.JSON(200, gin.H{"success": true}) + return + } + + c.JSON(200, ClearPriceCache(db)) + }) router.GET("/api/price", func(c *gin.Context) { c.JSON(200, GetPrices(db)) }) diff --git a/internal/server/sync.go b/internal/server/sync.go index ad54c600..7e07e569 100644 --- a/internal/server/sync.go +++ b/internal/server/sync.go @@ -1,10 +1,8 @@ package server import ( - "github.com/ananthakumaran/paisa/internal/accounting" + "github.com/ananthakumaran/paisa/internal/cache" "github.com/ananthakumaran/paisa/internal/model" - "github.com/ananthakumaran/paisa/internal/prediction" - "github.com/ananthakumaran/paisa/internal/service" "github.com/gin-gonic/gin" "gorm.io/gorm" ) @@ -16,10 +14,7 @@ type SyncRequest struct { } func Sync(db *gorm.DB, request SyncRequest) gin.H { - service.ClearInterestCache() - service.ClearPriceCache() - accounting.ClearCache() - prediction.ClearCache() + cache.Clear() if request.Journal { message, err := model.SyncJournal(db) diff --git a/src/lib/utils.ts b/src/lib/utils.ts index 8a5d898f..a7a98b8e 100644 --- a/src/lib/utils.ts +++ b/src/lib/utils.ts @@ -624,6 +624,11 @@ export function ajax( options?: RequestInit ): Promise<{ file: LedgerFile }>; +export function ajax( + route: "/api/price/delete", + options?: RequestInit +): Promise<{ success: boolean; message: string }>; + export function ajax( route: "/api/sync", options?: RequestInit diff --git a/src/routes/ledger/price/+page.svelte b/src/routes/ledger/price/+page.svelte index 56fcc782..f59f705b 100644 --- a/src/routes/ledger/price/+page.svelte +++ b/src/routes/ledger/price/+page.svelte @@ -2,6 +2,7 @@ import Toggleable from "$lib/components/Toggleable.svelte"; import ValueChange from "$lib/components/ValueChange.svelte"; import { ajax, formatCurrency, type Price } from "$lib/utils"; + import { toast } from "bulma-toast"; import _ from "lodash"; import { onMount } from "svelte"; import VirtualList from "svelte-tiny-virtual-list"; @@ -25,15 +26,53 @@ return null; } - onMount(async () => { + async function clearPriceCache() { + const { success, message } = await ajax("/api/price/delete", { method: "POST" }); + if (!success) { + toast({ + message: `Failed to clear price cache. reason: ${message}`, + type: "is-danger", + duration: 10000 + }); + } else { + toast({ + message: "Price cache cleared.", + type: "is-success" + }); + } + await fetchPrice(); + } + + async function fetchPrice() { ({ prices: prices } = await ajax("/api/price")); prices = _.omitBy(prices, (v) => v.length === 0); + } + + onMount(async () => { + await fetchPrice(); });
-
+
+
+
+
+

+ +

+
+
+