Remember that everything in Elixir is an assignment. That means that you have to divorce yourself of many patterns which are quite common in other languages because an Elixir variable does not share any scope beyond its block. For example, in many OO languages, you might do a conditional count of list items doing something like this:
# pseudo code... This pattern will not work in Elixir!
cnt = 0
for i = 0; i < length(list); i++ {
if list[i] == 'something'
cnt++
}
}
In Elixir, you would need to do an "assignment", which in this case means you'd have to fall back to the tried and true Enum module, e.g. using Enum.reduce/3:
cnt = Enum.reduce(list, 0, fn
"something", acc -> acc + 1 # function clause 1 (match)
_, acc -> acc # function clause 2 (no match)
end)
Above we have employed 2 function clauses to match on a specific conditional value ("something") instead of using an if-statement -- if-statements end up being somewhat rare in Elixir because it turns out you don't often need them.
In your example, you can leverage assignment via a simple case statement:
def user_balance(user) do
query = from t in Transactions, where: (t.user_id == ^user), select: sum(t.amount)
case Repo.one(query) do
nil -> 0
balance -> Decimal.to_float(balance)
end
end
If you follow the execution flow, you see that the result of the Repo.one(query) is evaluated immediately inside the case statement. Again, we use pattern-matching instead of an if statement (remember, the most specific matches must appear first). So if the result is nil, 0 gets returned; if it is anything else, it is handed off to the Decimal.to_float/1. Because Elixir functions rely on implicit returns, the output of this case statement is the return value of the user_balance/1 function.
Breaking things down into separate functions not only makes your code more readable, it helps you achieve an assignment so your code actually works.