optimize net_category_totals() by using memoized cache (#1881)

* optimize net_category_totals() by using memoized cache

* fix issue - net_category_totals cache is never populated - suggested by coderabbitAI
This commit is contained in:
William Wei Ming
2026-05-21 02:28:26 +08:00
committed by GitHub
parent ba87a4f0f3
commit 444f5e6a2d

View File

@@ -30,14 +30,23 @@ class IncomeStatement
end
def expense_totals(period: Period.current_month)
build_period_total(classification: "expense", period: period)
# Memoized per instance so callers that also invoke `net_category_totals`
@expense_totals_by_period ||= {}
@expense_totals_by_period[period_cache_key(period)] ||=
build_period_total(classification: "expense", period: period)
end
def income_totals(period: Period.current_month)
build_period_total(classification: "income", period: period)
@income_totals_by_period ||= {}
@income_totals_by_period[period_cache_key(period)] ||=
build_period_total(classification: "income", period: period)
end
def net_category_totals(period: Period.current_month)
@net_category_totals_by_period ||= {}
cached = @net_category_totals_by_period[period_cache_key(period)]
return cached if cached
expense = expense_totals(period: period)
income = income_totals(period: period)
@@ -87,7 +96,7 @@ class IncomeStatement
CategoryTotal.new(category: r[:category], total: r[:total], currency: family.currency, weight: weight)
end
NetCategoryTotals.new(
@net_category_totals_by_period[period_cache_key(period)] = NetCategoryTotals.new(
net_expense_categories: net_expense_categories,
net_income_categories: net_income_categories,
total_net_expense: total_net_expense,
@@ -126,6 +135,10 @@ class IncomeStatement
@categories ||= family.categories.all.to_a
end
def period_cache_key(period)
[ period.start_date, period.end_date ]
end
def build_period_total(classification:, period:)
# Exclude pending transactions from budget calculations
totals = totals_query(transactions_scope: family.transactions.visible.excluding_pending.in_period(period), date_range: period.date_range).select { |t| t.classification == classification }