-
Notifications
You must be signed in to change notification settings - Fork 3
/
include_parser.ex
62 lines (47 loc) · 1.83 KB
/
include_parser.ex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
defmodule Surgex.Parser.IncludeParser do
@moduledoc """
Parses the JSON API's include parameter according to the
[JSON API spec](http://jsonapi.org/format/#fetching-includes).
Produces a list of includes constrained to the provided relationship paths.
"""
@type errors :: :invalid_relationship_path | :invalid_input
@type path :: atom() | String.t()
@doc false
@spec call(term(), [path()]) :: {:ok, [atom()]} | {:error, errors()}
def call(nil, _spec), do: {:ok, []}
def call("", _spec), do: {:ok, []}
def call(input, allowed_paths) when is_binary(input) do
paths = String.split(input, ",")
allowed_paths = Enum.map(allowed_paths, &convert_to_string/1)
validate_relationship_path(paths, allowed_paths)
end
def call(_input, _paths), do: {:error, :invalid_input}
defp convert_to_string(path) when is_binary(path), do: path
defp convert_to_string(path) when is_atom(path), do: Atom.to_string(path)
defp validate_relationship_path(paths, allowed_paths) do
case Enum.all?(paths, &Enum.member?(allowed_paths, &1)) do
true -> {:ok, Enum.map(paths, &String.to_atom/1)}
false -> {:error, :invalid_relationship_path}
end
end
@doc """
Flattens the result of the parser (inclusion list) into multiple keys.
## Examples
iex> IncludeParser.flatten({:ok, include: [:user]}, :include)
{:ok, include_user: true}
"""
@spec flatten({:ok, Keyword.t()}, String.t()) :: {:ok, Keyword.t()}
def flatten({:ok, opts}, key) do
case Keyword.pop(opts, key) do
{nil, _} ->
{:ok, opts}
{value_list, rem_opts} when is_list(value_list) ->
new_opts =
value_list
|> Enum.map(fn value -> {String.to_atom("#{key}_#{value}"), true} end)
|> Keyword.merge(rem_opts)
{:ok, new_opts}
end
end
def flatten(input, _key), do: input
end