我有这个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
Run Code Online (Sandbox Code Playgroud)
我担心重复fragment,coalesce并sum在这里的每一行.有没有办法可以将它移动到自己的功能并像这样调用它?
def sum(query) do
from aggregate in query,
select: %{
ones: sum.("ones"),
twos: sum.("twos"),
...
Run Code Online (Sandbox Code Playgroud)
据我所知,这不能用普通函数完成,但你可以用宏来做到这一点:
defmacro sum_or_zero(column) do
quote do
fragment(unquote("coalesce(sum(#{column}), 0)"))
end
end
Run Code Online (Sandbox Code Playgroud)
并称之为:
def sum(query) do
from aggregate in query,
select: %{ id: sum_or_zero("id") }
end
Run Code Online (Sandbox Code Playgroud)
使用上面的函数和宏,代码如下:
MyApp.User |> A.sum |> MyApp.Repo.one |> IO.inspect
Run Code Online (Sandbox Code Playgroud)
打印:
[debug] QUERY OK source="users" db=1.9ms
SELECT coalesce(sum(id), 0) FROM "users" AS u0 []
%{id: 6}
Run Code Online (Sandbox Code Playgroud)
我建议将列传递给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
Run Code Online (Sandbox Code Playgroud)
这样查询将使用查询中的表名:
[debug] QUERY OK source="users" db=1.9ms
SELECT coalesce(sum(u0."id"), 0) FROM "users" AS u0 []
%{id: 6}
Run Code Online (Sandbox Code Playgroud)