仅当参数存在时,如何在 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
。
我正在尝试创建一个函数来执行一些动态查询。在一个条件下,我想添加与另一个 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
。