inquisitor v0.3.0 Inquisitor

Composable query builder for Ecto.

Inquisitor provides functionality to build a powerful query builder from a very simple pattern.

defmodule App.PostController do
  use Inquisitor
end

This will inject the necessary code into the App.PostController module. The function name depends upon the schema name. In this case the function injected will be called build_query/1.

The builder function expects a flat map of key/value pairs to be passed in. Typically this might be captured from an incoming request.

[GET] /posts?foo=hello&bar=world may result in a params map of %{"foo" => "hello", "bar" => "world"}

def index(conn, params) do
  posts =
    build_query(params)
    |> Repo.all()

  json(conn, posts)
end

Writing custom query handlers

Custom query handlers are written using defquery/2. This macro has the query variable injected at compile-time so you can use it to build up a new query. The result of the this macro should always be the query. The first argument will be the param key to match on, the second is the value matcher:

defquery "title", title do
  query
  |> Ecto.Query.where([r], r.title == ^title)
end

This macro will inject a new function at compile time. The above example will produce:

def build_query(query, [{"title", title} | tail]) do
  query
  |> Ecto.Qiery.where([r], r.title == ^title)
  |> build_query(tail)
end

The macro is there for convenience. If you’d like to just write the function and avoid the macro you are free to do so.

Summary

Macros

Define new query matcher

Macros

defquery(field, value)

Define new query matcher

Query matcher macro, the query is automatically injected at compile-time for use in the block

Usage

defquery "name", name do
  query
  |> Ecto.Query.where([r], r.name == ^name)
end

You can also use guards with the macro:

defquery attr, value when attr == "month" or attr == "year" do
  query
  |> Ecto.Query.where([e], fragment("date_part(?, ?) = ?", ^attr, e.inserted_at, type(^value, :integer)))
end