mirror of
https://github.com/maybe-finance/maybe.git
synced 2025-08-04 21:15:19 +02:00
perf(transactions): add kind
to Transaction
model and remove expensive Transfer joins in aggregations (#2388)
* add kind to transaction model * Basic transfer creator * Fix method naming conflict * Creator form pattern * Remove stale methods * Tweak migration * Remove BaseQuery, write entire query in each class for clarity * Query optimizations * Remove unused exchange rate query lines * Remove temporary cache-warming strategy * Fix test * Update transaction search * Decouple transactions endpoint from IncomeStatement * Clean up transactions controller * Update cursor rules * Cleanup comments, logic in search * Fix totals logic on transactions view * Fix pagination * Optimize search totals query * Default to last 30 days on transactions page if no filters * Decouple transactions list from transfer details * Revert transfer route * Migration reset * Bundle update * Fix matching logic, tests * Remove unused code
This commit is contained in:
parent
7aca5a2277
commit
1aae00f586
49 changed files with 1749 additions and 705 deletions
|
@ -20,8 +20,7 @@ class IncomeStatement
|
|||
ScopeTotals.new(
|
||||
transactions_count: result.sum(&:transactions_count),
|
||||
income_money: Money.new(total_income, family.currency),
|
||||
expense_money: Money.new(total_expense, family.currency),
|
||||
missing_exchange_rates?: result.any?(&:missing_exchange_rates?)
|
||||
expense_money: Money.new(total_expense, family.currency)
|
||||
)
|
||||
end
|
||||
|
||||
|
@ -53,16 +52,9 @@ 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)
|
||||
ScopeTotals = Data.define(:transactions_count, :income_money, :expense_money)
|
||||
PeriodTotal = Data.define(:classification, :total, :currency, :category_totals)
|
||||
CategoryTotal = Data.define(:category, :total, :currency, :weight)
|
||||
|
||||
def categories
|
||||
|
@ -102,7 +94,6 @@ class IncomeStatement
|
|||
classification: classification,
|
||||
total: category_totals.reject { |ct| ct.category.subcategory? }.sum(&:total),
|
||||
currency: family.currency,
|
||||
missing_exchange_rates?: totals.any?(&:missing_exchange_rates?),
|
||||
category_totals: category_totals
|
||||
)
|
||||
end
|
||||
|
@ -110,14 +101,14 @@ class IncomeStatement
|
|||
def family_stats(interval: "month")
|
||||
@family_stats ||= {}
|
||||
@family_stats[interval] ||= Rails.cache.fetch([
|
||||
"income_statement", "family_stats", family.id, interval, entries_cache_version
|
||||
"income_statement", "family_stats", family.id, interval, family.entries_cache_version
|
||||
]) { FamilyStats.new(family, interval:).call }
|
||||
end
|
||||
|
||||
def category_stats(interval: "month")
|
||||
@category_stats ||= {}
|
||||
@category_stats[interval] ||= Rails.cache.fetch([
|
||||
"income_statement", "category_stats", family.id, interval, entries_cache_version
|
||||
"income_statement", "category_stats", family.id, interval, family.entries_cache_version
|
||||
]) { CategoryStats.new(family, interval:).call }
|
||||
end
|
||||
|
||||
|
@ -125,24 +116,11 @@ class IncomeStatement
|
|||
sql_hash = Digest::MD5.hexdigest(transactions_scope.to_sql)
|
||||
|
||||
Rails.cache.fetch([
|
||||
"income_statement", "totals_query", family.id, sql_hash, entries_cache_version
|
||||
"income_statement", "totals_query", family.id, sql_hash, family.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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue