View Source Basic Usage

Suppose you have a users schema that is defined as below:

defmodule Accounts.User do
  schema "users" do
    field :email, :string
    field :password_hash, :string

    field :name, :string
    field :is_active, :boolean

    field :signed_up_at, :naive_datetime
  end
end

Basic filtering

Suppose you wish to enable filtering by email, name, is_active, and signed_up_at. Then you can define a QueryBuilder module as below:

defmodule Accounts.User.QueryBuilder do
  use QueryElf,
    schema: Accounts.User,
    searchable_fields: [:email, :name, :is_active, :signed_up_at]
end

The schema specifies the ecto schema for which the query builder is being created. The searchable_fields specifies fields that can be filtered on. With the above definition, you can now use the query builder's capabailities as below:

User.QueryBuilder.build_query(email: "a@b.com")
|> Repo.one

User.QueryBuilder.build_query(name__in: ["Raphael Costa", "Jose Valim"])
|> Repo.all()

User.QueryBuilder.build_query(is_active: true)
|> Repo.all()

User.QueryBuilder.build_query(signed_up_at__before: ~N[2000-01-01 23:00:07])
|> Repo.all()

You can also combine multiple conditions/filters together:

# Conditions are `anded` by default
User.QueryBuilder.build_query(name__in: ["Raphael Costa", "Jose Valim"], is_active: true)
|> Repo.all()

# But you can change to using `or`
User.QueryBuilder.build_query(_or: [name: "Mr A", email: "a@b.com"])
|> Repo.all()

# Or combine them together to create a complex query
User.QueryBuilder.build_query(
  _or: [
    name: "Mr A",
    _and: [
      email__in: ["a@b.com", "a@c.com"],
      is_active: true
    ]
  ]
)
|> Repo.all()

For more information about what filters (__in, __before, etc) are defined for each field type, check the documentation for the searchable_fields option here.

Basic ordering/sorting

Assuming you have the same user schema defined above, suppose you wish to allow sorting users by name, email, and signed_up_at. QueryElf can be used to achieve this as below:

defmodule Accounts.User.QueryBuilder do
  use QueryElf,
    schema: Accounts.User,
    searchable_fields: ~w[email name is_active signed_up_at]a,
    sortable_fields: ~w[email name signed_up_at]a
end

Then sorting capabilities can be included in build_query as below:

Accounts.User.QueryBuilder.build_query([],
  order: [%{field: :name, direction: :asc}, %{field: :signed_up_at, direction: :desc}]
)
|> Repo.all()


# Shorthand expression for ordering example above
Accounts.User.QueryBuilder.build_query([],
  order: [asc: :my_int, desc: :my_bool]
)
|> Repo.all()