You could use fragments, for example:
from t in Transaction,
select: %{
income: sum(fragment("CASE WHEN ? = ? THEN ? ELSE 0 END", t.type, "income", t.amount)),
expense: sum(fragment("CASE WHEN ? = ? THEN ? ELSE 0 END", t.type, "income", t.amount)),
balance: sum(t.amount)
}
As you can see, I structured the fragments in a way that they both are the same for income and expense. We can enhance the query syntax using a macro:
defmacro sum_type(table, type) do
quote do
sum(fragment("CASE WHEN ? = ? THEN ? ELSE 0 END",
unquote(table).type, unquote(type), unquote(table).amount)
end
end
This allows us to change the query to:
from t in Transaction,
select: %{
income: sum_type(t, "income"),
expense: sum_type(t, "expense"),
balance: sum(t.amount)
}