1
0
Fork 0
mirror of https://github.com/maybe-finance/maybe.git synced 2025-07-25 08:09:38 +02:00

perf(income statement): cache income statement queries (#2371)

* Leftover cleanup from prior PR

* Benchmark convenience task

* Change default warm benchmark time

* Cache income statement queries

* Fix private method access
This commit is contained in:
Zach Gollwitzer 2025-06-15 10:09:46 -04:00 committed by GitHub
parent 84b2426e54
commit a5f1677f60
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 103 additions and 77 deletions

View file

@ -53,6 +53,13 @@ class IncomeStatement
family_stats(interval: interval).find { |stat| stat.classification == "income" }&.median || 0
end
def warm_caches!(interval: "month")
totals
family_stats(interval: interval)
category_stats(interval: interval)
nil
end
private
ScopeTotals = Data.define(:transactions_count, :income_money, :expense_money, :missing_exchange_rates?)
PeriodTotal = Data.define(:classification, :total, :currency, :missing_exchange_rates?, :category_totals)
@ -102,21 +109,40 @@ class IncomeStatement
def family_stats(interval: "month")
@family_stats ||= {}
@family_stats[interval] ||= FamilyStats.new(family, interval:).call
@family_stats[interval] ||= Rails.cache.fetch([
"income_statement", "family_stats", family.id, interval, entries_cache_version
]) { FamilyStats.new(family, interval:).call }
end
def category_stats(interval: "month")
@category_stats ||= {}
@category_stats[interval] ||= CategoryStats.new(family, interval:).call
@category_stats[interval] ||= Rails.cache.fetch([
"income_statement", "category_stats", family.id, interval, entries_cache_version
]) { CategoryStats.new(family, interval:).call }
end
def totals_query(transactions_scope:)
@totals_query_cache ||= {}
cache_key = Digest::MD5.hexdigest(transactions_scope.to_sql)
@totals_query_cache[cache_key] ||= Totals.new(family, transactions_scope: transactions_scope).call
sql_hash = Digest::MD5.hexdigest(transactions_scope.to_sql)
Rails.cache.fetch([
"income_statement", "totals_query", family.id, sql_hash, entries_cache_version
]) { Totals.new(family, transactions_scope: transactions_scope).call }
end
def monetizable_currency
family.currency
end
# Returns a monotonically increasing integer based on the most recent
# update to any Entry that belongs to the family. Incorporated into cache
# keys so they expire automatically on data changes.
def entries_cache_version
@entries_cache_version ||= begin
ts = Entry.joins(:account)
.where(accounts: { family_id: family.id })
.maximum(:updated_at)
ts.present? ? ts.to_i : 0
end
end
end