lib/query_elf/plugins/automatic_sorters.ex

defmodule QueryElf.Plugins.AutomaticSorters do
  @moduledoc """
  Plugin for automatically defining sorters for a set of fields.

  It accepts the following options:

    - `:fields` - the list of fields for which to define sorters. (required)

  ### Example

  This definition:

      defmodule MyQueryBuilder do
        use QueryElf,
          schema: MySchema,
          plugins: [
            {QueryElf.Plugins.AutomaticSorters, fields: ~w[inserted_at]a}
          ]
      end

  is equivalent to:

      defmodule MyQueryBuilder do
        use QueryElf,
          schema: MySchema

        def sort(:inserted_at, direction, _args, query) do
          case direction do
            :asc -> order_by(query, asc: :inserted_at)
            :desc -> order_by(query, desc: :inserted_at)
          end
        end
      end
  """

  use QueryElf.Plugin

  @impl QueryElf.Plugin
  def using(opts) do
    fields = Keyword.fetch!(opts, :fields)

    quote bind_quoted: [fields: fields] do
      require QueryElf.Plugins.AutomaticSorters

      fields
      |> Enum.map(fn field ->
        QueryElf.Plugins.AutomaticSorters.__define_sorter__(field)
      end)
      |> Code.eval_quoted([], __ENV__)
    end
  end

  @doc false
  @spec __define_sorter__(field :: atom) :: Macro.t()
  def __define_sorter__(field) do
    quote do
      def sort(unquote(field), direction, _args, query) do
        order_by(query, [{^direction, unquote(field)}])
      end
    end
  end
end