Query (query v0.6.0)

Query aids the use of Ecto in web settings.

With it, we can add paging, sorting, and scoping with ease. At its heart, Query lets us build complex queries from our controller params.

Example

Functionality is conducted through one main function Query.run/4:

defmodule App.PostController do
  use App, :controller

  @options [
    sort_permitted: ["id", "title", "inserted_at"],
    scope_permitted: ["by_title"],
    scope: {App.Context, :query}
  ]

  def index(conn, params) do
    result = Query.run(Post, Repo, params, @options)
    render(conn, "index.json", posts: result)
  end
end

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

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

Further documentation to come...

Summary

Functions

Fetches data from the given repository based on the params and options given.

Types

option()

@type option() ::
  {:page_default, non_neg_integer()}
  | {:page_param, binary()}
  | {:limit_default, non_neg_integer()}
  | {:limit_max, non_neg_integer()}
  | {:limit_param, binary()}
  | {:sort_default, binary()}
  | {:sort_param, binary()}
  | {:sort_permitted, [binary()]}
  | {:dir_default, binary()}
  | {:dir_param, binary()}
  | {:count, boolean()}
  | {:count_limit, :infinite | non_neg_integer()}
  | {:scoping, {module(), atom()}}
  | {:scopes, [{module(), binary()}]}
  | {:preloads, [atom()]}

options()

@type options() :: [option()]

params()

@type params() :: %{required(binary()) => binary()}

t()

@type t() :: %Query{
  count: term(),
  count_column: term(),
  count_limit: term(),
  limit: term(),
  offset: term(),
  page: term(),
  preloads: term(),
  queryable: term(),
  repo: term(),
  scoping: term(),
  sorting: term()
}

Functions

run(queryable, repo, params \\ %{}, opts \\ [])

@spec run(Ecto.Queryable.t(), Ecto.Repo.t(), params(), options()) :: Query.Result.t()

Fetches data from the given repository based on the params and options given.

This provides an easy way to performing paging, sorting, and scoping all from binary maps - typically given from controller params.

Options

  • :page_default - the default page if none is provided - defaults to 1
  • :page_param - the param key to use for the page - defaults to "page"
  • :limit_default - the default limit if none is provided - defaults to 20
  • :limit_param - the param key to use for the limit - defaults to "limit"
  • :limit_max - the maximum allowed limit - defaults to 50
  • :sort_default - the default sort attribute if none is provided - defaults to "id"
  • :sort_param - the param key to use for the sort - defaults to "sort_by"
  • :sort_permitted - a list of permitted attributes that we can sort on
  • :dir_default - the default direction - defaults to "asc"
  • :dir_param - the param key to use for the direction - defaults to "dir"
  • :count - whether or not to fetch the total number of records - defaults to true
  • :count_limit - the maximum number of records to count - defaults to :infinite
  • :count_column - the column used to perform the count on
  • :scope_permitted - a list of permitted params that we can scope on
  • :scope - a {module, function} with an arity of 2, that will be passed an Ecto.Query as well as a map of the permitted scopes. You can then perform custom queries with these params
  • :preloads - a list of preloads that will be applied to the result data

Examples

iex> Query.run(App.Post, App.Repo)
%Query.Result{data: ...results of query, meta: ...paging attributes}

iex> Query.run(App.Post, App.Repo, %{"page" => 2, "sort_by" => "some_attr"}, sort_permitted: ["some_attr"])
%Query.Result{data: ...results of query, meta: ...paging attributes}

iex> Query.run(App.Post, App.Repo, %{"published" => true}, scope: {App.Context, :with_scope}, scope_permitted: ["published"])
%Query.Result{data: ...results of query, meta: ...paging attributes}