仅当参数存在时,如何在 ecto 中定义连接?

How do I define a join in ecto only if a parameter exists?

我正在尝试创建一个函数来执行一些动态查询。在一个条件下,我想添加与另一个 table 的连接,但前提是 opts

中存在特定字段
def list_fields(opts) do
  query =
    from f in Field,
      select: %{
        id: f.id,
        type: f.type,
        value: f.value
      }

  with query <- by_type(opts[:type], query),
       query <- by_status(opts[:status], query) do
    Repo.all(query)
  end
end

我有这些功能来过滤选择:

defp by_type(nil, query), do: query

defp by_type(type, query) do
  from [f] in query, where: f.type == ^type
end

defp by_status(nil, query), do: query

defp by_status(status, query) do
  from [f, d] in query, where: d.status == ^status
end

但是状态存储在不同的 table 上,我不想向它添加连接,除非我必须避免结果重复。

带有联接的查询如下所示:

query =
  from f in Field,
  left_join: d in Data, on: d.field_id = f.id
  select: %{
    ...

如何仅在 opts 中存在 :status 时才添加此 left_join

使用 Kernel.SpecialForms.with/1 的单子魔法。

{_, query} =
  with {status, query} when not is_nil(status) <-
          {opts[:status], by_type(opts[:type], query)},
    do: {:ok, by_status(opts[:status], query)}
Repo.all(query)

这里的技巧是,如果 opts[:status]nil,第一个子句将 return 而不会经过 do 块,因此 by_status