I am suggesting a technique I learned from the book Absinthe/GraphQL…
For example…
def list_requests_query(criteria \\ []) do
query = from(p in Request)
Enum.reduce(criteria, query, fn
{:limit, limit}, query ->
from p in query, limit: ^limit
{:offset, offset}, query ->
from p in query, offset: ^offset
{:filter, filters}, query ->
filter_with(filters, query)
{:order, order}, query ->
from p in query, order_by: [{^order, ^@order_field}]
{:preload, preloads}, query ->
from p in query, preload: ^preloads
arg, query ->
Logger.info("args is not matched in query #{inspect(arg)}")
query
end)
end
defp filter_with(filters, query) do
Enum.reduce(filters, query, fn
{:user_id, user_id}, query ->
from q in query, where: q.user_id == ^user_id
{:is_fetched, is_fetched}, query ->
from q in query, where: q.is_fetched == ^is_fetched
{:is_post_processed, is_post_processed}, query ->
from q in query, where: q.is_post_processed == ^is_post_processed
{:with_medium_path, true}, query ->
from q in query, where: not is_nil(q.medium_path)
{:with_medium_path, false}, query ->
from q in query, where: is_nil(q.medium_path)
arg, query ->
Logger.info("args is not matched in query #{inspect(arg)}")
query
end)
end
def list_requests(criteria \\ []) do
criteria
|> list_requests_query()
|> Repo.all()
end
Using this, I could probably do something like…
filter by location
filter by category
move to the next month
move to the previous month
show/hide the events that already have occured this month
filter by the person who created the event
… and this would translate to
[filter: [by_location: location, by_category: category, by_month: month ...]]
|> App.list_requests()