所以现在我正在使用这个:
dynamic(
[u],
ilike(
u.name, ^"%#{String.replace(term, "%", "\\%")}%"
)
)
Run Code Online (Sandbox Code Playgroud)
该术语是一个简单的字符串,例如"charlie"。我如何将其与术语列表一起使用,例如:["charlie", "dennis", "frank"]- 没有片段是否可能?
嗯,通过一些元编程,这在某种程度上是可能的。幸运的是,ecto允许在查询中使用您自己的宏,因此我们需要的只是构建我们自己的宏,将几个ILIKEs 与ors 粘合在一起。
这里有几个陷阱。首先,我们应该让编译器忘记Kernel.or/2,否则,它会尝试就地进行逻辑析取。然后,我们应该显式导入Ecto.Query.API.or/2. 最后,我们应该递归地构建生成的 AST 以传递给查询。
加起来。
\n\ndefmodule 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\nRun Code Online (Sandbox Code Playgroud)\n\n请注意,这or_ilike/2是返回 AST 的函数。它们不能是宏(这可能会简化一切),因为不能递归调用宏(应该在第一次调用之前预先定义)。
让\xe2\x80\x99s看看。
\n\nMultiOr.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"))>\nRun Code Online (Sandbox Code Playgroud)\n
| 归档时间: |
|
| 查看次数: |
747 次 |
| 最近记录: |