I’ll start right with an example
User
|> QueryBuilder.where(firstname: "John", city: "Anytown")
|> QueryBuilder.where({:age, :gt, 30})
|> QueryBuilder.order_by(lastname: :asc)
|> QueryBuilder.preload([:role, authored_articles: :comments])
|> Repo.all()
With associations:
User
|> QueryBuilder.where([role: :permissions], name@permissions: "delete")
|> Repo.all()
Query Builder allows to build and compose Ecto queries based on data.
Concise, no need to deal with bindings and macros.
Its primary goal is to allow Context functions to receive a set of filters and options:
# in a Controller
Blog.list_articles(preload: [:comments], order_by: [title: :asc])
Blog.list_articles(preload: [:category, comments: :user])
This avoids having to create many different functions in the Context for every combination of filters and options, or to create one general function that does too much to satisfy all the consumers.
The calling code (e.g. the Controllers), can now retrieve the list of articles with different options. In some part of the application, the category is needed; in other parts it is not; sometimes the articles must be sorted based on their title; other times it doesn’t matter, etc.
The options may be added to the query as shown below:
# in the Blog context
def get_article_by_id(id, opts \\ []) do
QueryBuilder.where(Article, id: id)
|> QueryBuilder.from_list(opts)
|> Repo.one!()
end
Inspired by the libraries token_operator and ecto_filter.
More examples are available in the doc: