View Source EctoJuno
A simple query sorting library
installation
Installation
Add :ecto_juno to the list of dependencies in mix.exs
def deps do
[
{:ecto_juno, "~> 0.3.0"}
]
end
configuration
Configuration
You can specify default sorting field and mode in your config.exs:
config :ecto_juno, sort_by: :id, sort_direction: :descThe default sorting is by inserted_at field with asc mode
general-sorting
General sorting
Lets assume you have Accounts context with User schema and Repo module.
To sort users pass your query, schema module and params into EctoJuno.Query.Sorting.sort_query/3
alias EctoJuno.Query.Sorting
def list_sorted_users(params) do
User
|> Sorting.sort_query(User, params)
|> Repo.all()
endWhere params structure is
%{"sort_by" => "id", "sort_direction" => "desc"}You can also pass sorting parameters keys as atoms:
Sorting.sort_query(query, User, %{sort_by: "id", sort_direction: "desc"})Moreover, instead of the User schema module, you can pass a list of which elements are atoms:
Sorting.sort_query(query, [:id, :age, :name, :inserted_at], %{sort_by: "id", sort_direction: "desc"})If you not specify any of sorting parameters, than the default ones will be used:
# The default sort_direction will be used
Sorting.sort_query(query, User, %{sort_by: "id"})
# The default sort_by will be used
Sorting.sort_query(query, User, %{sort_direction: "desc"})
# The default sorting which configurable will be used
Sorting.sort_query(query, User)If you'll pass invalid sorting parameters, than default sorting ones will be used for your query:
Sorting.sort_query(query, User, %{sort_by: "invalid_field", sort_direction: "invalid_mode"})by default will sort query by inserted_at field with asc mode
sorting-by-joint-query
Sorting by joint query
To apply sorting by joint query use EctoJuno.Query.Sorting.sort_query/4 which accepts the same arguments as
EctoJuno.Query.Sorting.sort_query/3 except new fourth argument - joint query binding name.
Let's assume that you also have a posts table that related to users table as many to one. And posts have title column. Than your sorting function will be something like:
alias EctoJuno.Query.Sorting
def sort_users_by_posts do
params = %{"sort_by" => "title", "sort_direction" => "desc"}
User
|> join(:left, [u], p in assoc(u, :posts), as: :posts)
|> Sorting.sort_query(Post, params, :posts)
|> Repo.all()
endIf you provide binding that query doesn't have than sorting by base query in default mode will be applied
custom-sorting
Custom sorting
Define your custom sorting module
defmodule Sample.UserSorting do
use EctoJuno.Query.SortingTemplate
def prepare_sorting_params("post_" <> field) do
{Post, field, :posts}
end
def prepare_sorting_params(nil) do
{User, "inserted_at"}
end
def prepare_sorting_params(field) do
{User, field}
end
endThen you can use it like
alias Sample.UserSorting
query = join(User, :left, [u], p in assoc(u, :posts), as: :posts)
# Sort users by posts title in desc mode
query
|> UserSorting.sort_query(%{sort_by: "post_title", sort_direction: "desc"})
|> Repo.all()
# Sort users by users age
query
|> UserSorting.sort_query(%{"sort_by" => "age", "sort_direction" => "desc"})
|> Repo.all()Passing parameters may be done with a map either with string either atom keys. But not mixed.
be-aware-of
Be aware of
- Sorting with modes different from asc and desc is not supported
- If you pass sort_by and sort_direction values not as strings you'll get exception
testing
Testing
- Clone repo:
git clone https://github.com/senconscious/ecto_juno - Set
DATABASE_URLenvironment variable before running tests locally - Run
mix check