Ecto ILIKE 多个关键字?

Nem*_* Ga 2 elixir ecto

所以现在我正在使用这个:

dynamic(
  [u],
  ilike(
    u.name, ^"%#{String.replace(term, "%", "\\%")}%"
  ) 
)
Run Code Online (Sandbox Code Playgroud)

该术语是一个简单的字符串,例如"charlie"。我如何将其与术语列表一起使用,例如:["charlie", "dennis", "frank"]- 没有片段是否可能?

Ale*_*kin 5

嗯,通过一些元编程,这在某种程度上是可能的。幸运的是,允许在查询中使用您自己的宏,因此我们需要的只是构建我们自己的宏,将几个ILIKEs 与ors 粘合在一起。

\n\n

这里有几个陷阱。首先,我们应该让编译器忘记Kernel.or/2,否则,它会尝试就地进行逻辑析取。然后,我们应该显式导入Ecto.Query.API.or/2. 最后,我们应该递归地构建生成的 AST 以传递给查询。

\n\n

加起来。

\n\n
defmodule MultiOr do\n  import Ecto.Query\n  import Kernel, except: [or: 2]\n  import Ecto.Query.API, only: [or: 2]\n\n  # terminating call, we are done\n  defp or_ilike(var, [term1, term2] = terms) do\n    quote do\n      ilike(unquote(var), unquote(term1)) or ilike(unquote(var), unquote(term2))\n    end\n  end\n\n  # recursive call\n  defp or_ilike(var, [term | terms]) do\n    quote do\n      ilike(unquote(var), unquote(term)) or unquote(or_ilike(var, terms))\n    end\n  end\n\n  # the macro wrapper to inject AST\n  defmacrop multi_ilike(var, terms) do\n    Macro.expand(or_ilike(var, terms), __CALLER__)\n  end\n\n  # test\n  def test do\n    Ecto.Query.where(User, [u],\n      multi_ilike(u.name, ["charlie", "dennis", "frank"]))\n  end\nend\n\n
Run Code Online (Sandbox Code Playgroud)\n\n

请注意,这or_ilike/2是返回 AST 的函数。它们不能是宏(这可能会简化一切),因为不能递归调用宏(应该在第一次调用之前预先定义)。

\n\n

让\xe2\x80\x99s看看。

\n\n
MultiOr.test\n#\xe2\x87\x92 #Ecto.Query<from u0 in User,\n#   where: ilike(u0.name, "charlie") or (ilike(u0.name, "dennis") or ilike(u0.name, "frank"))>\n
Run Code Online (Sandbox Code Playgroud)\n