Skip to content

Instantly share code, notes, and snippets.

@paulcsmith
Last active February 4, 2016 16:55
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save paulcsmith/b7ad3f40b20e1fd15cc1 to your computer and use it in GitHub Desktop.
Save paulcsmith/b7ad3f40b20e1fd15cc1 to your computer and use it in GitHub Desktop.
Building queries using plain functions
def index(conn, params) do
Post
|> filter_upcoming(params)
|> filter_attributes(params, whitelist: ~w(title body)
|> filter_timespan(params)
# Or simplify it if it's used in multiple controllers
Post |> filter_post_params(params)
end
def filter_post_params(query, params) do
query
|> filter_upcoming(params)
|> filter_attributes(params, whitelist: ~w(title body)
|> filter_timespan(params)
end
def filter_upcoming(query, %{"upcoming" => "true") do
from row in query, where: row.publish_at > Ecto.DateTime.utc
end
def filter_upcoming(query, _params), do: query
def filter_timespan(query, %{"start_time" => start_time, "end_time" => end_time}) do
# You'll need to cast the times somehow. Probably with Ecto.DateTime.cast!
from row in query,
where: row.published_at > cast(start_time),
where: row.published_at < cast(end_time)
end
def filter_dates(query, _params), do: query
def filter_attributes(query, params, whitelist: whitelist) do
params = Map.take(params, whitelist)
Enum.reduce params, query, fn({attr, value}, query) ->
from row in query, where: field(row, ^String.to_atom(attr)) == ^value
end
end
@paulcsmith
Copy link
Author

The good thing about using regular function is that you can easily use just some of these if you want to use them in different controllers. You can also use the same function for different models if they have similar functionality (like a Post and a Tweet that both have a published_at field)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment