Inquisitor
Easily build composable queries for Ecto.
Usage
Adding Inquisitor to a project is simple:
defmodule MyApp.PostController do
use Inquisitor, with: MyApp.Post
def index(conn, params) do
events =
build_event_query(params)
|> Repo.all()
json(conn, events)
end
end
After use Inquisitor, with: MyApp.Post a cutom function is added to
the MyApp.PostController. In this case that function is
build_event_query. The name of the function is dynamically created
based upon the model name. So if the model was MyApp.FooBarBaz the
corresponding function would be build_foo_bar_baz_query.
This sets up a key/value queryable API for the Post model. Any
combination of fields on the model can be queried against. For example,
requesting [GET] /posts?foo=bar&baz=qux will create the query:
SELECT p0."foo", p0."baz" FROM posts as p0 WHERE (p0."foo" = $1) AND (p0."baz" = $1);
$1 and $2 will get the values of "bar" and "qux",
Adding custom query handlers
Simple key/value matching is not always what you want. In that case you
can define custom handlers for certain keys. Let's say you want to query
based upon inserted_at values, querying for all values that came on
and after that date:
defmodule MyApp.PostsController do
use Inquisitor, with: MyApp.Post
def index(conn, params) do
events =
build_event_query(params)
|> Repo.all()
json(conn, events)
end
def build_event_query(query, [{"inserted_at", date}|tail]) do
query
|> where([p], p.inserted_at >= ^date)
|> build_user_query(tail)
end
end
The query is built recursively by iterating over all the params. If there is a matching custom handler, it uses that otherwise defaults to the key/value handler.
Handing fields that don't exist on the model
The keys you query against don't need to exist on the model. Revisting the date example, let's say we want to find all posts inserted for a given month and year:
def build_event_query(query, [{attr, value}|tail]) when attr == "month" or attr == "year" do
query
|> where(fragment("date_part(?, ?) = ?", ^attr, e.inserted_at, type(^value, :integer)))
|> build_event_query(q, tail)
end
That's it!
Built in handlers
There are a few built in handlers
Booleans
Booleans that come in as text will be typecast to an actual boolean type then past on for handling. So even if the params come as:
%{ "foo" => "true" }
You will want to pattern match on the actual boolean value:
def build_event_query(query, [{"foo", true}|tail]) do
...
Authors
We are very thankful for the many contributors
Versioning
This library follows Semantic Versioning
Want to help?
Please do! We are always looking to improve this library. Please see our Contribution Guidelines on how to properly submit issues and pull requests.
Legal
DockYard, Inc. © 2016