首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >多个关键字的Ecto ILIKE?

多个关键字的Ecto ILIKE?
EN

Stack Overflow用户
提问于 2019-11-16 11:06:06
回答 2查看 347关注 0票数 1

所以现在我使用的是:

代码语言:javascript
代码运行次数:0
运行
复制
dynamic(
  [u],
  ilike(
    u.name, ^"%#{String.replace(term, "%", "\\%")}%"
  ) 
)

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

EN

回答 2

Stack Overflow用户

发布于 2019-11-16 15:21:07

嗯,通过一些元编程,这在某种程度上是可能的。幸运的是,ecto允许在查询中使用自己的宏,所以我们所需要的就是构建自己的宏,将几个ILIKEor粘合在一起。

这里有几个陷阱。首先,我们应该让编译器忘记Kernel.or/2,否则,它将试图在适当的位置进行逻辑析取。然后,我们应该显式导入Ecto.Query.API.or/2。最后,我们应该递归地构建要传递给查询的结果AST。

总结一下。

代码语言:javascript
代码运行次数:0
运行
复制
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。它们不能是宏(这可能会简化所有事情),因为不能递归地调用宏(应该在第一次调用之前预先定义)。

让我们看看。

代码语言:javascript
代码运行次数:0
运行
复制
MultiOr.test
#⇒ #Ecto.Query<from u0 in User,
#   where: ilike(u0.name, "charlie") or (ilike(u0.name, "dennis") or ilike(u0.name, "frank"))>
票数 4
EN

Stack Overflow用户

发布于 2019-11-18 18:40:48

您可以使用来自标准Ecto的or_where

代码语言:javascript
代码运行次数:0
运行
复制
def multi_ilike(queryable, words) do
  for term <- words, reduce: queryable do
    acc -> 
      str = "%#{String.replace(term, "%", "\\%")}%"
      cond = dynamic([u], ilike(u.name, ^str))
      or_where(acc, ^cond)
  end
end

或者如果你不喜欢for

代码语言:javascript
代码运行次数:0
运行
复制
def multi_ilike(queryable, words) do
  words
  |> Enum.map(&"%#{String.replace(&1, "%", "\\%")}%")
  |> Enum.map(&dynamic([u], ilike(u.name, ^&1))
  |> Enum.reduce(queryable, &or_where(&2, ^&1))
end
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/58887180

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档