Rummage.Ecto v2.0.0 Rummage.Ecto.Hook.Sort View Source
Rummage.Ecto.Hook.Sort is the default sort hook that comes with
Rummage.Ecto.
This module provides a operations that can add sorting functionality to
a pipeline of Ecto queries. This module works by taking the field that should
be used to order_by, order which can be asc or desc and assoc,
which is a keyword list of assocations associated with those fields.
NOTE: This module doesn't return a list of entries, but a Ecto.Query.t.
This module uses Rummage.Ecto.Hook.
ABOUT:
Arguments:
This Hook expects a queryable (an Ecto.Queryable) and
sort_params (a Map). The map should be in the format:
%{field: :field_name, assoc: [], order: :asc}
Details:
field: The field name (atom) to sorted by.assoc: List of associations in the sort.order: Specifies the type of orderascordesc.ci: Case Insensitivity. Defaults tofalse
For example, if we want to sort products with descending price, we would
do the following:
Rummage.Ecto.Hook.Sort.run(Product, %{field: :price,
assoc: [], order: :desc})Assoications:
Assocaitions can be given to this module's run function as a key corresponding to params associated with a field. For example, if we want to sort products that belong to a category by ascending category_name, we would do the following:
params = %{field: :category_name, assoc: [inner: :category],
order: :asc}
Rummage.Ecto.Hook.Sort.run(Product, params)The above operation will return an Ecto.Query.t struct which represents
a query equivalent to:
from p0 in Product
|> join(:inner, :category)
|> order_by([p, c], {asc, c.category_name})ASSUMPTIONS/NOTES:
- This Hook has the default
orderof:asc. - This Hook has the default
assocof[]. - This Hook assumes that the field passed is a field on the
Ecto.Schemathat corresponds to the last association in theassoclist or theEcto.Schemathat corresponds to thefrominqueryable, ifassocis an empty list.
NOTE: It is adviced to not use multiple associated sorts in one operation
as assoc still has some minor bugs when used with multiple sorts. If you
need to use two sorts with associations, I would pipe the call to another
sort operation:
Sort.run(queryable, params1}
|> Sort.run(%{field2: params2}USAGE:
For a regular sort:
This returns a queryable which upon running will give a list of Parent(s)
sorted by ascending field_1
alias Rummage.Ecto.Hook.Sort
sorted_queryable = Sort.run(Parent, %{assoc: [], field: :name, order: :asc}})For a case-insensitive sort:
This returns a queryable which upon running will give a list of Parent(s)
sorted by ascending case insensitive field_1.
Keep in mind that case_insensitive can only be called for text fields
alias Rummage.Ecto.Hook.Sort
sorted_queryable = Sort.run(Parent, %{assoc: [], field: :name, order: :asc, ci: true}})This module can be overridden with a custom module while using Rummage.Ecto
in Ecto struct module.
In the Ecto module:
Rummage.Ecto.rummage(queryable, rummage, sort: CustomHook)OR
Globally for all models in config.exs:
config :rummage_ecto,
Rummage.Ecto,
sort: CustomHookThe CustomHook must use Rummage.Ecto.Hook. For examples of CustomHook,
check out some custom_hooks that are shipped with Rummage.Ecto:
Rummage.Ecto.CustomHook.SimpleSearch, Rummage.Ecto.CustomHook.SimpleSort,
Rummage.Ecto.CustomHook.SimplePaginate
Link to this section Summary
Functions
Callback implementation for Rummage.Ecto.Hook.format_params/3.
This is the callback implementation of Rummage.Ecto.Hook.run/2.
Link to this section Functions
Specs
format_params(Ecto.Query.t(), map(), keyword()) :: map()
format_params(Ecto.Query.t(), map() | tuple(), keyword()) :: map()
Callback implementation for Rummage.Ecto.Hook.format_params/3.
This function ensures that params for each field have keys assoc, order1
which are essential for running this hook module.
Examples
iex> alias Rummage.Ecto.Hook.Sort
iex> Sort.format_params(Parent, %{}, [])
%{assoc: [], order: :asc} Specs
run(Ecto.Query.t(), map()) :: Ecto.Query.t()
run(Ecto.Query.t(), map()) :: Ecto.Query.t()
This is the callback implementation of Rummage.Ecto.Hook.run/2.
Builds a sort Ecto.Query.t on top of the given Ecto.Queryable variable
using given params.
Besides an Ecto.Query.t an Ecto.Schema module can also be passed as it
implements Ecto.Queryable
Params is a Map which is expected to have the keys field, order, assoc.
This funciton expects a field atom, order which can be asc or desc,
ci which is a boolean indicating the case-insensitivity and assoc which
is a list of associations with their join types.
Examples
When an empty map is passed as params:
iex> alias Rummage.Ecto.Hook.Sort
iex> Sort.run(Parent, %{})
** (RuntimeError) Error in params, No values given for keys: field, order, assocWhen a non-empty map is passed as params, but with a missing key:
iex> alias Rummage.Ecto.Hook.Sort
iex> Sort.run(Parent, %{field: :name})
** (RuntimeError) Error in params, No values given for keys: order, assocWhen a valid map of params is passed with an Ecto.Schema module:
iex> alias Rummage.Ecto.Hook.Sort
iex> Sort.run(Rummage.Ecto.Product, %{field: :name, assoc: [], order: :asc})
#Ecto.Query<from p0 in subquery(from p0 in Rummage.Ecto.Product), order_by: [asc: p0.name]>When the queryable passed is an Ecto.Query variable:
iex> alias Rummage.Ecto.Hook.Sort
iex> import Ecto.Query
iex> queryable = from u in "products"
#Ecto.Query<from p0 in "products">
iex> Sort.run(queryable, %{field: :name, assoc: [], order: :asc})
#Ecto.Query<from p0 in subquery(from p0 in "products"), order_by: [asc: p0.name]>When the queryable passed is an Ecto.Query variable, with desc order:
iex> alias Rummage.Ecto.Hook.Sort
iex> import Ecto.Query
iex> queryable = from u in "products"
#Ecto.Query<from p0 in "products">
iex> Sort.run(queryable, %{field: :name, assoc: [], order: :desc})
#Ecto.Query<from p0 in subquery(from p0 in "products"), order_by: [desc: p0.name]>When the queryable passed is an Ecto.Query variable, with ci true:
iex> alias Rummage.Ecto.Hook.Sort
iex> import Ecto.Query
iex> queryable = from u in "products"
#Ecto.Query<from p0 in "products">
iex> Sort.run(queryable, %{field: :name, assoc: [], order: :asc, ci: true})
#Ecto.Query<from p0 in subquery(from p0 in "products"), order_by: [asc: fragment("lower(?)", p0.name)]>When the queryable passed is an Ecto.Query variable, with associations:
iex> alias Rummage.Ecto.Hook.Sort
iex> import Ecto.Query
iex> queryable = from u in "products"
#Ecto.Query<from p0 in "products">
iex> Sort.run(queryable, %{field: :name, assoc: [inner: :category, left: :category], order: :asc})
#Ecto.Query<from p0 in subquery(from p0 in "products"), join: c1 in assoc(p0, :category), left_join: c2 in assoc(c1, :category), order_by: [asc: c2.name]>When the queryable passed is an Ecto.Schema module with associations,
desc order and ci true:
iex> alias Rummage.Ecto.Hook.Sort
iex> queryable = Rummage.Ecto.Product
Rummage.Ecto.Product
iex> Sort.run(queryable, %{field: :name, assoc: [inner: :category], order: :desc, ci: true})
#Ecto.Query<from p0 in subquery(from p0 in Rummage.Ecto.Product), join: c1 in assoc(p0, :category), order_by: [desc: fragment("lower(?)", c1.name)]>