Skip to content

Commit

Permalink
Fix options atoms list and options as map (mirego#13)
Browse files Browse the repository at this point in the history
* Fix options atoms list and options as map

* Fixes mirego#7 by refactoring options key-value list
  • Loading branch information
simonprev authored and chubarovNick committed Apr 1, 2020
1 parent a6b5395 commit 77c97b4
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 28 deletions.
16 changes: 8 additions & 8 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
language: 'elixir'

elixir: 1.8.1
otp_release: 21.3
elixir: 1.10.2
otp_release: 22.0.7

matrix:
include:
- otp_release: 19.3
elixir: 1.6.6
- otp_release: 20.0
elixir: 1.6.5
- otp_release: 20.2
elixir: 1.7.4
- otp_release: 21.3
elixir: 1.8.1
- otp_release: 22.0.7
elixir: 1.9.4
- otp_release: 22.0.7
elixir: 1.10.2

cache:
directories:
Expand Down
39 changes: 32 additions & 7 deletions lib/absinthe_error_payload/changeset_parser.ex
Original file line number Diff line number Diff line change
Expand Up @@ -85,36 +85,61 @@ defmodule AbsintheErrorPayload.ChangesetParser do
def construct_message(field, error_tuple)

def construct_message(field, {message, opts}) do
options = build_opts(opts)

%ValidationMessage{
code: to_code({message, opts}),
field: construct_field(field, nil),
key: field,
template: message,
message: interpolate_message({message, opts}),
options: tidy_opts(opts)
message: interpolate_message({message, options}),
options: to_key_value(options)
}
end

defp tidy_opts(opts) do
Keyword.drop(opts, [:validation, :max, :is, :min, :code])
defp to_key_value(opts) do
Enum.map(opts, fn {key, value} ->
%{
key: key,
value: interpolated_value_to_string(value)
}
end)
end

defp build_opts(opts) do
opts
|> Keyword.drop([:validation, :max, :is, :min, :code])
|> Map.new()
end

@doc """
Inserts message variables into message.
Code inspired by Phoenix DataCase.on_errors/1 boilerplate.
## Examples
iex> interpolate_message({"length should be between %{one} and %{two}", [one: "1", two: "2", three: "3"]})
iex> interpolate_message({"length should be between %{one} and %{two}", %{one: "1", two: "2", three: "3"}})
"length should be between 1 and 2"
iex> interpolate_message({"is already taken: %{fields}", %{fields: [:one, :two]}})
"is already taken: one,two"
"""
# Code Taken from the Pheonix DataCase.on_errors/1 boilerplate"
def interpolate_message({message, opts}) do
Enum.reduce(opts, message, fn {key, value}, acc ->
String.replace(acc, "%{#{key}}", to_string(value))
String.replace(acc, "%{#{key}}", interpolated_value_to_string(value))
end)
end

defp interpolated_value_to_string([item | _] = value) when is_atom(item) do
value
|> Enum.map(&to_string(&1))
|> interpolated_value_to_string()
end

defp interpolated_value_to_string(value) when is_list(value), do: Enum.join(value, ",")

defp interpolated_value_to_string(value), do: to_string(value)

@doc """
Generate unique code for each validation type.
Expand Down
3 changes: 2 additions & 1 deletion lib/absinthe_error_payload/validation_message.ex
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ defmodule AbsintheErrorPayload.ValidationMessage do
See `AbsintheErrorPayload.ChangesetParser.to_code/1` for built in codes corresponding to most Ecto validations.
### :options
A Keyword List of substitutions to be applied to a validation message template.
A list of key value pair to be applied to a validation message template.
The structure is a list of `%{key: _, value: _}` to be able to serialize to a GraphQL type
### :key
Deprecated, use :field instead
Expand Down
53 changes: 41 additions & 12 deletions test/changeset_parser_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ defmodule AbsintheErrorPayload.ChangesetParserTest do
"""
use ExUnit.Case
doctest(AbsintheErrorPayload.ChangesetParser, import: true)

import Ecto.Changeset

Expand Down Expand Up @@ -193,7 +194,7 @@ defmodule AbsintheErrorPayload.ChangesetParserTest do
assert message.code == "foobar"
assert message.key == :title
assert message.field == :title
assert message.options == [illegal: "foobar"]
assert message.options == [%{key: :illegal, value: "foobar"}]
assert message.message =~ ~r/foobar/
assert message.template =~ ~r/%{illegal}/
end
Expand All @@ -210,7 +211,7 @@ defmodule AbsintheErrorPayload.ChangesetParserTest do
assert message.code == "foobar"
assert message.key == :title
assert message.field == :title
assert message.options == [illegal: "foobar"]
assert message.options == [%{key: :illegal, value: "foobar"}]
assert message.message =~ ~r/foobar/
assert message.template =~ ~r/%{illegal}/
end
Expand All @@ -225,7 +226,7 @@ defmodule AbsintheErrorPayload.ChangesetParserTest do
assert message.code == :unknown
assert message.key == :title
assert message.field == :title
assert message.options == [illegal: "foobar"]
assert message.options == [%{key: :illegal, value: "foobar"}]
assert message.message =~ ~r/foobar/
assert message.template =~ ~r/%{illegal}/
end
Expand Down Expand Up @@ -300,7 +301,13 @@ defmodule AbsintheErrorPayload.ChangesetParserTest do
assert message.code == :min
assert message.key == :title
assert message.field == :title
assert message.options == [count: 2, kind: :min, type: :string]

assert message.options == [
%{key: :count, value: "2"},
%{key: :kind, value: "min"},
%{key: :type, value: "string"}
]

assert message.message =~ ~r/2/
assert message.template =~ ~r/%{count}/
end
Expand All @@ -315,7 +322,7 @@ defmodule AbsintheErrorPayload.ChangesetParserTest do
assert message.code == :max
assert message.key == :title
assert message.field == :title
assert message.options == [count: 3, kind: :max, type: :string]
assert message.options == [%{key: :count, value: "3"}, %{key: :kind, value: "max"}, %{key: :type, value: "string"}]
assert message.message =~ ~r/3/
assert message.template =~ ~r/%{count}/
end
Expand All @@ -330,7 +337,13 @@ defmodule AbsintheErrorPayload.ChangesetParserTest do
assert message.code == :length
assert message.key == :title
assert message.field == :title
assert message.options == [count: 7, kind: :is, type: :string]

assert message.options == [
%{key: :count, value: "7"},
%{key: :kind, value: "is"},
%{key: :type, value: "string"}
]

assert message.message =~ ~r/7/
assert message.template =~ ~r/%{count}/
end
Expand All @@ -345,7 +358,7 @@ defmodule AbsintheErrorPayload.ChangesetParserTest do
assert message.code == :greater_than
assert message.key == :upvotes
assert message.field == :upvotes
assert message.options == [kind: :greater_than, number: 10]
assert message.options == [%{key: :kind, value: "greater_than"}, %{key: :number, value: "10"}]
assert message.message =~ ~r/10/
assert message.template =~ ~r/%{number}/
end
Expand All @@ -360,7 +373,12 @@ defmodule AbsintheErrorPayload.ChangesetParserTest do
assert message.code == :greater_than_or_equal_to
assert message.key == :upvotes
assert message.field == :upvotes
assert message.options == [kind: :greater_than_or_equal_to, number: 10]

assert message.options == [
%{key: :kind, value: "greater_than_or_equal_to"},
%{key: :number, value: "10"}
]

assert message.message =~ ~r/10/
assert message.template =~ ~r/%{number}/
end
Expand All @@ -375,7 +393,13 @@ defmodule AbsintheErrorPayload.ChangesetParserTest do
assert message.code == :less_than
assert message.key == :upvotes
assert message.field == :upvotes
assert message.options == [kind: :less_than, number: 1]

assert message.options ==
[
%{key: :kind, value: "less_than"},
%{key: :number, value: "1"}
]

assert message.message =~ ~r/1/
assert message.template =~ ~r/%{number}/
end
Expand All @@ -390,7 +414,12 @@ defmodule AbsintheErrorPayload.ChangesetParserTest do
assert message.code == :less_than_or_equal_to
assert message.key == :upvotes
assert message.field == :upvotes
assert message.options == [kind: :less_than_or_equal_to, number: 1]

assert message.options == [
%{key: :kind, value: "less_than_or_equal_to"},
%{key: :number, value: "1"}
]

assert message.message =~ ~r/1/
assert message.template =~ ~r/%{number}/
end
Expand All @@ -405,7 +434,7 @@ defmodule AbsintheErrorPayload.ChangesetParserTest do
assert message.code == :equal_to
assert message.key == :upvotes
assert message.field == :upvotes
assert message.options == [kind: :equal_to, number: 1]
assert message.options == [%{key: :kind, value: "equal_to"}, %{key: :number, value: "1"}]
assert message.message =~ ~r/1/
assert message.template =~ ~r/%{number}/
end
Expand Down Expand Up @@ -465,7 +494,7 @@ defmodule AbsintheErrorPayload.ChangesetParserTest do
assert message.code == :cast
assert message.key == :body
assert message.field == :body
assert message.options == [type: :string]
assert message.options == [%{key: :type, value: "string"}]
assert message.message != ""
assert message.template != ""
end
Expand Down

0 comments on commit 77c97b4

Please sign in to comment.