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 orderasc
ordesc
.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
order
of:asc
. - This Hook has the default
assoc
of[]
. - This Hook assumes that the field passed is a field on the
Ecto.Schema
that corresponds to the last association in theassoc
list or theEcto.Schema
that corresponds to thefrom
inqueryable
, ifassoc
is 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: CustomHook
The 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, assoc
When 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, assoc
When 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)]>