Current section

Files

Jump to
surgex lib surgex parser parsers sort_parser.ex
Raw

lib/surgex/parser/parsers/sort_parser.ex

defmodule Surgex.Parser.SortParser do
@moduledoc """
Parses the JSON API's sort parameter according to the
[JSON API spec](http://jsonapi.org/format/#fetching-sorting).
Produces a `{direction, column}` tuple, in which `direction` is either `:asc` or `:desc` and
`column` is a safely atomized and underscored column name.
"""
def call(nil, _allowed_columns), do: {:ok, nil}
def call(input, allowed_columns) when is_binary(input) do
case input do
"-" <> column ->
validate_allowed_columns(column, allowed_columns, :desc)
column ->
validate_allowed_columns(column, allowed_columns, :asc)
end
end
defp validate_allowed_columns(column, allowed_columns, direction) do
column_atom = atomize_maybe_dasherized(column)
if column_atom && column_atom in allowed_columns do
{:ok, {direction, column_atom}}
else
{:error, :invalid_sort_column}
end
end
defp atomize_maybe_dasherized(string) do
atomize(string) || (
string
|> String.replace("-", "_")
|> atomize
)
end
defp atomize(string) do
String.to_existing_atom(string)
rescue
ArgumentError -> nil
end
def flatten({:ok, opts}, key) do
case Keyword.pop(opts, key) do
{nil, _} ->
{:ok, opts}
{{direction, column}, rem_opts} ->
final_opts = Keyword.merge(rem_opts, sort_by: column, sort_direction: direction)
{:ok, final_opts}
end
end
def flatten(input, _key), do: input
end