elixir - Ecto ILIKE 用于多个关键字?
问题描述
所以现在我正在使用这个:
dynamic(
[u],
ilike(
u.name, ^"%#{String.replace(term, "%", "\\%")}%"
)
)
该术语是一个简单的字符串,例如"charlie"
. 我将如何将其与术语列表一起使用,例如:["charlie", "dennis", "frank"]
- 没有片段甚至可能吗?
解决方案
嗯,这在某种程度上可以通过一些元编程来实现。幸运的是,ecto允许在查询中使用您自己的宏,所以我们只需要构建自己的宏,将几个ILIKE
s 与or
s 粘合起来。
这里有几个陷阱。首先,我们应该让编译器忘记Kernel.or/2
,否则,它将尝试在适当的位置进行逻辑析取。然后,我们应该显式地导入Ecto.Query.API.or/2
. 最后,我们应该递归地构建生成的 AST 以传递给查询。
加起来。
defmodule MultiOr do
import Ecto.Query
import Kernel, except: [or: 2]
import Ecto.Query.API, only: [or: 2]
# terminating call, we are done
defp or_ilike(var, [term1, term2] = terms) do
quote do
ilike(unquote(var), unquote(term1)) or ilike(unquote(var), unquote(term2))
end
end
# recursive call
defp or_ilike(var, [term | terms]) do
quote do
ilike(unquote(var), unquote(term)) or unquote(or_ilike(var, terms))
end
end
# the macro wrapper to inject AST
defmacrop multi_ilike(var, terms) do
Macro.expand(or_ilike(var, terms), __CALLER__)
end
# test
def test do
Ecto.Query.where(User, [u],
multi_ilike(u.name, ["charlie", "dennis", "frank"]))
end
end
请注意,这or_ilike/2
是函数,返回 AST。它们不能是宏(这可能会简化一切),因为不能递归调用宏(应该在第一次调用之前预先定义。)
让我们来看看。
MultiOr.test
#⇒ #Ecto.Query<from u0 in User,
# where: ilike(u0.name, "charlie") or (ilike(u0.name, "dennis") or ilike(u0.name, "frank"))>
推荐阅读
- php - 如何从 Symfony 中的复选框类型中删除特定实体?
- javascript - 处理多个文件上传:当您将某些内容推送到数组时,数组何时更新?
- python - 将字典项目映射到熊猫系列时忽略大小写
- node.js - 无法使用 xpath 单击元素 - TypeError:无法读取未定义的属性“单击”
- javascript - 如何将 JS 日期(以编程方式)转换为 Google 表格序列号,反之亦然?
- reactjs - 在功能组件中调用 MapDispatchToProps 方法
- java - 如何使用 JNA 将带有数组 [1+1] 的结构和带有 FAR PASCAL 的方法从 C 映射到 Java?
- java - 收到错误消息“代码推荐者无法下载其模型存储库索引”
- javascript - 当文本省略号应用于元素时,如何使用工具提示?
- python - IOError:[Errno 13] 运行脚本后权限被拒绝错误