I would like to simplify my current custom filtering function but I’m having trouble how to dynamically select a particular column in a where
clause of an Ecto.Query
.
What I have right now is this:
def query_filter(query, %{} = filters) do
query
|> first_name(filters[:first_name])
|> last_name(filters[:last_name])
# other filters truncated ...
end
defp first_name(query, first_name) do
query
|> where([a], ilike(a.first_name, ^"#{first_name}%"))
end
defp last_name(query, last_name) do
query
|> where([a], ilike(a.last_name, ^"#{last_name}%"))
end
Now, this works fine but I would like to learn how to do this behavior properly since first_name/2
and last_name/2
are really similar save the particular column being filtered.
Knowing that structs are basically special Map
, I thought I could do something like this:
def query_filter(query, %{} = filters) do
query
|> like(:first_name, filters[:first_name])
|> like(:last_name, filters[:last_name])
end
defp like(query, attr, value) do
query
|> where([a], ilike(a[attr], ^"#{value}%"))
end
But this yields this error:
** (Ecto.Query.CompileError) `a[attr]` is not a valid query expression
expanding macro: Ecto.Query.where/3
lib/ras_directory_api/recruitment/filter.ex:39: RasDirectoryApi.Recruitment.Filter.like/3
(elixir) expanding macro: Kernel.|>/2
lib/ras_directory_api/recruitment/filter.ex:39: RasDirectoryApi.Recruitment.Filter.like/3
And my bet is that the reason for this is that a
here is not really interpreted as a struct in Ecto’s Macro.
Any suggestions how can I improve my verbose code?