Ecto查询中的插值字段如何?

时间:2016-09-25 13:52:22

标签: elixir phoenix-framework ecto

Ecto documentation显示了如何进行插值。但我在查询中需要动态字段。我有几十个字段,并为每个字段编写查询似乎没有凝聚力。

defmodule Hedone.SearchController do
  use Hedone.Web, :controller

  alias Hedone.User

  def idade(conn, %{"idade+" => maior, "idade-" => menor, "campo" => campo}) do
    IO.inspect campo
  query = from u in User, where: u.campo > ^maior and u.campo < ^menor, select: u.name
  pesquisa = Repo.all query
  IO.inspect pesquisa
  text conn, "Works"
end

end

此控制器生成以下错误:

** (Ecto.QueryError) web/controllers/search.ex:8: field `Hedone.User.campo` in `where` does not exist in the schema in query:

from u in Hedone.User,
  where: u.campo > ^18 and u.campo < ^40,
  select: u.name

自动翻译。

2 个答案:

答案 0 :(得分:2)

我假设campo包含一个字符串,其中包含您要使用的字段的名称,例如"age"。您可以在查询中使用field

def idade(conn, %{"idade+" => maior, "idade-" => menor, "campo" => campo}) do
  campo = String.to_existing_atom(campo)
  query = from u in User, where: field(u, ^campo) > ^maior and field(u, ^campo) < ^menor, select: u.name
  pesquisa = Repo.all query
  IO.inspect pesquisa
  text conn, "Works"
end

field期望该字段为原子,因此我使用String.to_existing_atom将字符串安全地转换为原子。由于您已经必须在模型的模式中定义了字段,因此String.to_existing_atom对于任何有效的字段名称都不会失败。

答案 1 :(得分:1)

我发布这个作为解决问题的另一种方法的示例。由于宏在编译时被解析,因此可以使用宏来处理这种转换:

defmacro idade(conn, formula, campo: binding) do
  q = formula |> String.replace "campo", binding
  quote do
    from u in User, where: unquote(q), select: u.name
      |> Repo.all
    text conn, "Works"
  end
end

并称之为:

idade(nil, "u.campo > ^maior and u.campo < ^menor", campo: "age")