leaf
Use dynamics as an acc in reduce
I am building a query that use dynamics and then interpolate it in the join. I build it successfully. But I want to include dynamics for multiple fields .The reduce function iterates over the map take the fields and build a dynamic query. Here is my code so far:
Enum.reduce(additional_join, true, fn {field, map}, query ->
query =
if Map.has_key?(map, "$in") do
query = dynamic([q], field(q, ^String.to_atom(field)) in ^map["$in"] and ^query)
else
query
end
if Map.has_key?(map, "$between_equal") do
query =
dynamic(
[q],
field(q, ^FatHelper.string_to_existing_atom(field)) >= ^Enum.min(map["$between_equal"]) and
field(q, ^FatHelper.string_to_existing_atom(field)) <= ^Enum.max(map["$between_equal"]) and
^query
)
else
query
end
end)
These are the params:
"$additional_on_clauses" => %{
"event_date" => %{"$between_equal" => [start_date, end_date]}
}
"$additional_on_clauses" => %{
"infection_category_id" => %{"$in" => category_ids},
"event_date" => %{"$between_equal" => [start_date, end_date]}
}
It only takes the last map in the above params and returns the query. I think reduce is a better way but i don’t have any idea how to use the dynamics inside of it.
I want dynamics to include both the above maps inside additional_on_clauses.
If I take the common part of the query outside of the reduce function and pass dynamics in the acc It won’t work because Enum not implemented for dynamics. dynamic([q, c], q.id == c.infection_id). I can’t use this as an accumulator.
Is there any other way I can build composite dynamic query with multiple dynamic conditions.?
Any help/suggestion will be much appreciated.
Thanks
Marked As Solved
peerreynders
This code strongly suggests that the problem is somewhere else in your code (something that you aren’t showing or even looking at):
defmodule Demo do
def run(additional_on_clauses) do
Enum.reduce(additional_on_clauses, true, fn {field, map}, query ->
query =
if Map.has_key?(map, "$in") do
# dynamic([q], field(q, ^String_to_atom(field)) in ^map["$in"] and ^query)
"#{field} in #{inspect(map["$in"])} and #{query}"
else
query
end
if Map.has_key?(map, "$between_equal") do
# dynamic([q],
# field(q, ^String_to_existing_atom(field)) >= ^Enum.min(map["$between_equal"]) and
# field(q, ^String_to_existing_atom(field)) <= ^Enum.max(map["$between_equal"]) and
# ^query
# )
"#{field} >= #{Enum.min(map["$between_equal"])} and " <>
"#{field} <= #{Enum.max(map["$between_equal"])} and " <>
"#{query}"
else
query
end
end)
end
end
data = %{
"$additional_on_clauses" => %{
"event_date" => %{"$between_equal" => [~N[2019-05-03 00:00:00], ~N[2019-05-04 00:00:00]]},
"infection_category_id" => %{"$in" => [2, 3, 4]}
}
}
data["$additional_on_clauses"]
|> Demo.run()
|> IO.inspect()
$ elixir demo.exs
"infection_category_id in [2, 3, 4] and event_date >= 2019-05-03 00:00:00 and event_date <= 2019-05-04 00:00:00 and true"
And to my earlier point changing to this:
data = %{
"$additional_on_clauses" => %{
"event_date" => %{"$between_equal" => [~N[2019-05-03 00:00:00], ~N[2019-05-04 00:00:00]]},
"infection_category_id" => %{"$in" => [2, 3, 4]}
},
"$additional_on_clauses" => %{
"infection_category_id" => %{"$in" => [2, 3, 4]}
}
}
data["$additional_on_clauses"]
|> Demo.run()
|> IO.inspect()
has the following result:
$ elixir demo.exs
warning: key "$additional_on_clauses" will be overridden in map
demo.exs:28
"infection_category_id in [2, 3, 4] and true"
Also Liked
al2o3cr
Note: I’m assuming that that first code block is surrounded in some kind of Enum.reduce structure. If it isn’t, please post the rest of the code.
Probably want to pass the result of the previous iteration here instead of true.







