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: :desc

The 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()
  end

Where 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()
  end

If 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
      end

Then 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

  1. Clone repo: git clone https://github.com/senconscious/ecto_juno
  2. Set DATABASE_URL environment variable before running tests locally
  3. Run mix check