query v0.3.0 Query

Query adds simple tools to aid the use of Ecto in web settings. With it, we can add paging, scopes, and sorting with ease. At its heart, Query lets us build complex queries from our controller params.

Before starting, we should configure Query. At a minimum, we need to add an Ecto Repo from which to work with.

config :query, [
  repo: App.Repo
]

Query is split into two main components:

  • Query.Builder - the builder readies our query paging, sorting, and scopes based on the provided params. The builder does not touch the database.

  • Query.Result - the result takes our builder, composes the final query, and fetches the data from our repo. It will also provide additional meta details that we can provide back to the user.

We can now compose complex queries from our controller.

defmodule App.PostController do
  use App, :controller

  @options [
    sorting: [permitted: ["id", "title", "created_at"]],
    scopes: [{App.Context, "by_title"}]
  ]

  def index(conn, params) do
    result = App.Post
    |> Query.builder(params, @options)
    |> Query.result()
    render(conn, "index.json", result: result)
  end
end

Given the controller above, we can now pass the following query options.

/posts?sort_by=created_at&direction=desc&by_title=test

We are able to sort by created_at, as we permitted it in our sorting options. By default, we are not allowed to sort by any attribute. They must be whitelisted first.

We are also able to pass the by_title query param. Once again, this is only possible as we whitelisted it in our list of scopes. Scopes are passed in the following format: {App.Context, "by_title"}. The first item in the tuple is the module that contains the function from which we will use to query against. The second item is the query param as well as function name.

So given the above, we must have an App.Context module that contains a by_title function. This function must have an arity of 2 - with the first argument being an Ecto.Queryable and the second argument being the value that we are querying with. In the above case, it would be “test”.

Link to this section Summary

Functions

Creates a new Query.Builder struct

Creates a new Query.Result struct from a Query.Builder

Creates a new Query.Builder struct, runs it, and returns a Query.Result struct

Link to this section Functions

Link to this function builder(queryable, params \\ %{}, options \\ [])

Creates a new Query.Builder struct.

Parameters

  • queryable: Any Ecto queryable.
  • params: A param map - most likely from a controller.
  • options: A keyword list of options.

Options

  • :repo - the Ecto repo from which to work with.
  • :paging - a list of paging options. For more info, see __.
  • :sorting - a list of sorting options. For more info, see __.
  • :scopes - a list of scope options. For more info, see __.

Examples

iex> Query.builder(App.Post)
%Query.Builder{limit: 20, offset: 0, page: 1,
queryable: #Ecto.Query<from p in App.Post>, repo: App.Repo,
scopes: [], sorting: [asc: :id]}
Link to this function result(builder)
result(builder :: Query.Builder.t()) :: Query.Result.t()

Creates a new Query.Result struct from a Query.Builder.

Parameters

  • builder: A Query.Builder struct.

Examples

iex> Query.result(builder)
%Query.Result{data: [
%App.Post{body: "Body 1", title: "Title 1"},
%App.Post{body: "Body 2", id: 840, title: "Title 2"}],
meta: %{page: 1, page_total: 2, total: 2, total_pages: 1}}
Link to this function run(queryable, params \\ %{}, options \\ [])
run(queryable :: Ecto.Queryable.t(), params :: Query.Builder.param(), list()) ::
  result :: Query.Result.t() | no_return()

Creates a new Query.Builder struct, runs it, and returns a Query.Result struct.

This is a shortend version of App.Post |> Query.builder() |> Query.result()

Parameters

  • queryable: Any Ecto queryable.
  • params: A param map - most likely from a controller.
  • options: A keyword list of options.

Options

  • :repo - the Ecto repo from which to work with.
  • :paging - a list of paging options. For more info, see __.
  • :sorting - a list of sorting options. For more info, see __.
  • :scopes - a list of scope options. For more info, see __.

Examples

iex> Query.run(App.Post)
%Query.Result{data: [
%App.Post{body: "Body 1", title: "Title 1"},
%App.Post{body: "Body 2", id: 840, title: "Title 2"}],
meta: %{page: 1, page_total: 2, total: 2, total_pages: 1}}