Query Builder

Query Builder allows you to build and compose Ecto queries based on data.

Its primary goal is to allow Context functions to receive filters and options to avoid having to create many different functions for every combination of filters and options:

Blog.list_articles(preload: [:comments], order_by: [title: :asc])
Blog.list_articles(preload: [:category, comments: :user])

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, however the articles must be sorted based on their title, etc.

See QueryBuilder.from_list/2 below.

Examples

User
|> QueryBuilder.where(firstname: "John")
|> QueryBuilder.where([{:age, :gt, 30}, city: "Anytown"])
|> QueryBuilder.order_by(lastname: :asc)
|> QueryBuilder.preload([:role, authored_articles: :comments])
|> Repo.all()

Filtering on associations is supported:

User
|> QueryBuilder.where(:role, name@role: "admin")
|> Repo.all()
User
|> QueryBuilder.where([role: :permission], name@permission: "delete")
|> Repo.all()
Article
|> QueryBuilder.where(:author, id@author: author_id)
|> QueryBuilder.where([:author, :comments], {:logged_at@author, :lt, :inserted_at@comments})
|> QueryBuilder.preload(:comments)
|> Repo.all()

Usage

Add use QueryBuilder in your schema:

defmodule MyApp.User do
  use Ecto.Schema
  use QueryBuilder

  schema "users" do
    # code
  end

  # code
end

You may also specify the schema's associations to QueryBuilder in order to remedy some limitations when building queries:

defmodule MyApp.User do
  use Ecto.Schema
  use QueryBuilder, assoc_fields: [:role, :articles]

  schema "users" do
    # code
    belongs_to :role, MyApp.Role
    has_many :articles, MyApp.Article
  end

  # code
end

Currently supported operations are:

QueryBuilder.where/2

QueryBuilder.where(query, firstname: "John")

QueryBuilder.where/3

QueryBuilder.where(query, [role: :permissions], name@permissions: :write)

QueryBuilder.order_by/2

QueryBuilder.order_by(query, lastname: :asc, firstname: :asc)

QueryBuilder.order_by/3

QueryBuilder.order_by(query, :articles, title@articles: :asc)

QueryBuilder.preload/2

QueryBuilder.preload(query, [role: :permissions, articles: [:stars, comments: :user]])

QueryBuilder.join/3

QueryBuilder.join(query, :articles, :left)

QueryBuilder.from_list/2

QueryBuilder.from_list(query, [
  where: [name: "John", city: "Anytown"],
  preload: [articles: :comments]
])

Installation

Add query_builder for Elixir as a dependency in your mix.exs file:

def deps do
  [
    {:query_builder, "~> 0.2.0"}
  ]
end

HexDocs

HexDocs documentation can be found at https://hexdocs.pm/query_builder.