Dan,
There is two ways to look at this problem...
Method 1
I think I can address both questions with one answer here (^_-), and the key is to address your fear.
You're mainly worried about the whole [].first => nil
. Second your worried about DB efficiency. Thirdly, you want to make this clean and re-factored (Good for you!).
Your answer...let PostgreSQL do this work for you, and force it to return a non-nil answer every time. Get it?
- There's no need for the
OpenStruct
because your labels in your SQL query are the same. - Use the PostgreSQL function
COALESCE()
to force the null to be a zero. - You 'could' make all of this a one-liner, but let's chop it up a bit for ease of the reader.
- This is already a summation query, you don't need the
LIMIT 1
.
Let's rewrite the code:
def initialize(args)
@loans_count = stats.loans_count
@total_fees_in_cents = stats.total_fees_in_cents
@total_amount_in_cents = stats.total_amount_in_cents
end
def stats
loans = Loan.select("count(*) as loans_count, COALESCE(sum(amount), 0) as total_amount_in_cents, COALESCE(sum(fee), 0) as total_fees_in_cents").where(account_id: @account_id)
loans = loans.where(year: @year) if single_year?
loans.first
end
Method 2
I personally think you are overly worried about the DB efficiency thing. You can always look at your development/production logs to read what is actually being outputted to the PSQL server, but I'm pretty sure it's close to the same thing your doing here.
Also, if I remember correctly, the DB query isn't actually executed UNTIL you want the data. During that time, ActiveRecord is just preparing the QUERY string.
.to_i
will convert your null to zero.
Let's rewrite the code:
def initialize(args)
stats = Loan.where(account_id: @account_id)
stats = stats.where(year: @year) if single_year?
stats.first
@loans_count = stats.count
@total_fees_in_cents = stats.sum(:fee).to_i
@total_amount_in_cents = stats.sum(:amount).to_i
end