Reputation: 2965
I have to filter an index that could accept in some cases comma separated values. Im working with Ecto, without phoenix (with cowboy).
my index will support some search like this
/users?ids=1,2,3&[email protected]&another=something
where email field doesn't allow more than one parameter and ids supports more than 1 id
This is what I've tried
def list_all(query_params) do
filtered_params = prepare_list_query(query_params)
User
|> where(^filtered_params)
|> Repo.all()
end
# In order to simplify queries I decided to manage all queries as IN clause
# it will returns [id: [1,2,3], email:["[email protected]"]]
defp prepare_list_query(query_params) do
query_params
|> Map.take(~w(ids email another))
# Careful: read reference #1 above
|> Enum.map(fn {name, value} ->
case name do
"ids" -> {:id, String.split(value, ",")}
single_param -> {String.to_atom(single_param), [value]}
end
end)
end
It's tricky but my idea is to return
[id: [1,2,3], email:["[email protected]"]]
and then working all filters as IN clause.
This filter has to support to send zero, one or all parameters.
I'm brand new in elixir world and I’m doing my first steps.
Thanks in advance :).
Upvotes: 0
Views: 496
Reputation: 1082
You can use Enum.reduce/3
to dynamically build an ecto query based on the params
def list_all(query_params) do
query = User # initial query
query_params
|> Map.take(~w(ids email another))
|> Enum.reduce(query, fn
{_key, value} when value in [nil, ""], q ->
q # ignore empty values
{"ids", value}, q ->
ids = String.split(values, ",")
q |> where([r], r.id in ^ids)
{key, value} ->
args = [{key, value}]
q |> where(^args)
end
end)
|> Repo.all()
end
In the reduce function you can add new clauses to handle different keys and values.
Upvotes: 2