在 Ecto 中构建动态片段
Building Dynamic fragments in Ecto
我有这个 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"),
...
据我所知,这不能用普通函数来完成,但你可以用宏来完成:
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
这样查询将在查询中使用 table 名称:
[debug] QUERY OK source="users" db=1.9ms
SELECT coalesce(sum(u0."id"), 0) FROM "users" AS u0 []
%{id: 6}
我有这个 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"),
...
据我所知,这不能用普通函数来完成,但你可以用宏来完成:
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
这样查询将在查询中使用 table 名称:
[debug] QUERY OK source="users" db=1.9ms
SELECT coalesce(sum(u0."id"), 0) FROM "users" AS u0 []
%{id: 6}