我有这个Ecto查询:
def sum(query) do
from aggregate in query,
select: %{
ones: fragment("coalesce(sum(ones), 0)"),
twos: fragment("coalesce(sum(twos), 0)"),
threes: fragment("coalesce(sum(threes), 0)"),
fours: fragment("coalesce(sum(fours), 0)"),
fives: fragment("coalesce(sum(fives), 0)"),
unanswered: fragment("coalesce(sum(unanswered), 0)"),
n_size: fragment("coalesce(sum(n_size), 0)"),
comment_count: fragment("coalesce(sum(comment_count), 0)")
}
end
我担心此处每行fragment
,coalesce
和sum
的重复。有没有办法可以将它移到自己的函数中并像这样调用它?
def sum(query) do
from aggregate in query,
select: %{
ones: sum.("ones"),
twos: sum.("twos"),
...
答案 0 :(得分:7)
据我所知,这不能用普通函数完成,但你可以用宏来做到这一点:
defmacro sum_or_zero(column) do
quote do
fragment(unquote("coalesce(sum(#{column}), 0)"))
end
end
并称之为:
def sum(query) do
from aggregate in query,
select: %{ id: sum_or_zero("id") }
end
使用上面的函数和宏,代码如下:
MyApp.User |> A.sum |> MyApp.Repo.one |> IO.inspect
打印:
[debug] QUERY OK source="users" db=1.9ms
SELECT coalesce(sum(id), 0) FROM "users" AS u0 []
%{id: 6}
我建议将列传递给sum_or_zero
而不是字符串:
defmacro sum_or_zero(column) do
quote do
fragment("coalesce(sum(?), 0)", unquote(column))
end
end
def sum(query) do
from aggregate in query,
select: %{ id: sum_or_zero(aggregate.id) }
end
这样查询将使用查询中的表名:
[debug] QUERY OK source="users" db=1.9ms
SELECT coalesce(sum(u0."id"), 0) FROM "users" AS u0 []
%{id: 6}