Although I agree with @sheharyar that composable queries is the best approach, sometimes we need need solutions that go beyond best practices. So, I'll provide an answer to your question as stated.
Don't let my example's schema distract you. It's just a project I had loaded to test the solution...
To examine a query structure, you might try this:
iex(128)> Map.from_struct(from(q in OneIosThemeGen.Themes.Entry, where: q.base_hex == ^base_hex))
%{
assocs: [],
distinct: nil,
from: {"entries", OneIosThemeGen.Themes.Entry},
group_bys: [],
havings: [],
joins: [],
limit: nil,
lock: nil,
offset: nil,
order_bys: [],
prefix: nil,
preloads: [],
select: nil,
sources: nil,
updates: [],
wheres: [
%Ecto.Query.BooleanExpr{
expr: {:==, [],
[{{:., [], [{:&, [], [0]}, :base_hex]}, [], []}, {:^, [], [0]}]},
file: "iex",
line: 128,
op: :and,
params: [{"#E8EBED", {0, :base_hex}}]
}
]
}
As you can see, the where clause is held in the wheres
field. It contains a list.
So, we could extract the wheres
field from each of the queries and concatenate the lists. That is what I demonstrate below.
Here is an example of composing the where clauses of multiple queries. It only handles the where clauses by 'and'ing them together.
base_hex = "#E8EBED"
name = "bodyText"
queries = [
from(q in OneIosThemeGen.Themes.Entry, where: q.base_hex == ^base_hex),
from(q in OneIosThemeGen.Themes.Entry, where: q.name == ^name)
]
build = fn queries ->
wheres = Enum.reduce(queries, [], fn %{wheres: wheres}, acc -> wheres ++ acc end)
from(q in OneIosThemeGen.Themes.Entry)
|> Map.put(:wheres, wheres)
end
query = build.(queries)
rows = Repo.all(query)
# sort function for result equality assertion
sort = fn list -> Enum.sort(list, & &1.id <= &2.id) end
# Single query for results equality test
combined_query = from(q in OneIosThemeGen.Themes.Entry, where: q.base_hex == ^base_hex and q.name == ^name)
rows_combined = Repo.all(combined_query)
# Test that the results are the same
sort.(rows) == sort.(rows_combined)
# true
# Now test that running the queries individually does not return the same results
rows3 = Enum.map(queries, &Repo.all/1) |> List.flatten()
sort.(rows3) != sort.(rows)
# true
IO.puts("length {rows, rows3}: " <> inspect({length(rows), length(rows3)}))
# length {rows, rows3}: {2, 5}
Note that this solution relays on the internal structure of the Ecto query which is generally a bad practice. It could break in a future Ecto update. However, it is one potential solution to the specific question asked.
https://hexdocs.pm/ecto/Ecto.Query.API.html#field/2
. I twill build the query dynamically with any field ad value. You just have to iterate over it with you key value pairs from params . – script