spapas
Create dynamic bindings for where clause
Hello,
the where macro (among others) gets an array of query positions as an argument ie query |> where([c0, c1, c2], c2.name = 32). How could I create the array of named bindings [c0, c1, c2] and the actual binding (c2) dynamically ? For example I lets say I have something like {name: 2} and I’d like to get both [c0, c1, c2] and c2.name=32 (or field(c2, ^“name”) in order to create a dynamic filter. Is this even possible? Do I need to use macros? Can somebody point me to the correct direction.
Thank you
Most Liked
spapas
After some clarifications on the elixir-lang IRC channel from @josevalim it seems that @peerreynders suggestion was correct. Using named bindings can solve this problem!
So, if you have a query with proper named bindings you can pass them to your filter specification in order to be used when querying. Here’s a small snippet on how you can such dynamic filters:
query = from(w in whs_query, as: :withholding,
join: b in Beneficiary, as: :beneficiary,
on: [id: w.beneficiary_id])
binding = :withholding
field = :number
value = "1"
query |> where(
[{^binding, t}],
field(t, ^field) == ^value
)
Thank you very much for helping with this !
peerreynders
While you’ve explained how you want to do it - it’s not clear why you would want to do it in this particular fashion.
I’m just mentioning this because in many use cases it makes sense to switch away from positional bindings and use named bindings instead - that is, any binding that may need to be referenced later in a composition is named so that it can be referenced by name rather than position later.
spapas
@peerreynders yes I guess I fell into the trap of asking of a way to implement the solution I had in my mind than describing the actual problem ![]()
I more or less want to create a dynamic query filtering mechanism. For example, I’ve got the following query:
whs_query =
from(w in Withholding,
join: b in Beneficiary,
on: [id: w.beneficiary_id],
join: a in Authority,
on: [id: w.authority_id],
join: ak in AuthorityKind,
on: [id: a.authority_kind_id],
preload: [beneficiary: b, authority: {a, authority_kind: ak}],
order_by: [asc: w.pay_date, asc: w.id]
)
and I want to filter on various fields from all relations (w, b, a, ak).
Now in non-dynamic case, I’ll create a schemaless changeset using something like
types = %{
status: :string,
afm: :string,
# year: :integer,
authority: :string,
authority_kind: :string
}
{%{}, types}
|> Ecto.Changeset.cast(params, Map.keys(types))
and finally retrieve the changes from the changeset and filter on the initial query:
changes = Map.fetch!(changeset, :changes) |> IO.inspect()
whs_query =
case changes[:status] do
nil -> whs_query
v -> whs_query |> where([w], w.status == ^v)
end
whs_query =
case changes[:afm] do
nil -> whs_query
v -> whs_query |> where([w, b], b.afm == ^v)
end
# etc
This works fine however it is a lot of work to do all this again and again for all my filters.
So instead I thought of modeling the filters I’d need for each query using a simple structure like:
filters= [
%{name: :status, type: :string, pos: 0},
%{name: :afm, type: :string, pos: 1}
]
– please notice that the pos defines the position in the named query i.e status is for Withholding (pos 0) while afm is for Beneficiary (pos 1) –
and then do something like:
changeset = QueryFilterEx.make_filter_changeset(filters, filter_params)
whs_query =
from(w in whs_query,
join: b in Beneficiary,
on: [id: w.beneficiary_id],
join: a in Authority,
on: [id: w.authority_id],
join: ak in AuthorityKind,
on: [id: a.authority_kind_id],
preload: [beneficiary: b, authority: {a, authority_kind: ak}],
order_by: [asc: w.pay_date, asc: w.id]
) |> QueryFilterEx.filter(filters, changeset)
So now the problem is that I have the initial query which is passed to QueryFilterEx.filter and I want to dynamically filter it using the filters struct I defined before to add where clauses to it. This leads me to the problem I described in my 1st and 2nd post ![]()
Also, concerning named bindings i really don’t think that it would solve my problem because I still wouldn’t be able to dynamically construct the aliases of the bindings in the where clauses.
BR,
Serafeim
Popular in Questions
Other popular topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #elixirconf-us
- #advent-of-code
- #distillery
- #processes
- #forms
- #api
- #metaprogramming
- #security
- #hex









