在Ecto中构建动态片段

时间:2017-01-24 00:49:00

标签: elixir 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

我担心此处每行fragmentcoalescesum的重复。有没有办法可以将它移到自己的函数中并像这样调用它?

def sum(query) do
  from aggregate in query,
  select: %{
    ones: sum.("ones"),
    twos: sum.("twos"),
  ...

1 个答案:

答案 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}