Reputation: 7226
I'm trying to create a function that will do some dynamic queries. There is one condition on which I want to add a join with another table, but only if a specific field is present in the 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
and I have these functions to filter down the selection:
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
However the status is stored on a different table, and I don't want to add a join to it unless I have to to avoid duplication of the results.
The query with the join would look like this:
query =
from f in Field,
left_join: d in Data, on: d.field_id = f.id
select: %{
...
How do I add this left_join
only when the :status
is present in opts
?
Upvotes: 0
Views: 742
Reputation: 120990
Use the monadic magic of 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)
The trick here is if opts[:status]
is nil
, the first clause will return without going through do
block and hence by_status
.
Upvotes: 1