mirror of
https://github.com/ash-project/ash.git
synced 2024-09-20 05:23:03 +12:00
improvement: expose union errors with path when tag is set
This commit is contained in:
parent
5549bbf290
commit
8c1f334075
3 changed files with 75 additions and 9 deletions
|
@ -455,10 +455,10 @@ defmodule Ash.Type do
|
||||||
|> Ash.Error.flatten_preserving_keywords()
|
|> Ash.Error.flatten_preserving_keywords()
|
||||||
|> Enum.map(fn
|
|> Enum.map(fn
|
||||||
message when is_binary(message) ->
|
message when is_binary(message) ->
|
||||||
[message: message, index: index]
|
[message: message, index: index, path: [index]]
|
||||||
|
|
||||||
keyword ->
|
keyword ->
|
||||||
Keyword.put(keyword, :index, index)
|
Keyword.merge(keyword, index: index, path: [index])
|
||||||
end)
|
end)
|
||||||
|
|
||||||
{:halt, {:error, errors}}
|
{:halt, {:error, errors}}
|
||||||
|
|
|
@ -234,9 +234,14 @@ defmodule Ash.Type.Union do
|
||||||
Map.get(value, config[:tag], Map.get(value, to_string(config[:tag])))
|
Map.get(value, config[:tag], Map.get(value, to_string(config[:tag])))
|
||||||
|
|
||||||
tags_equal? =
|
tags_equal? =
|
||||||
if is_atom(tag_value) do
|
cond do
|
||||||
|
is_atom(tag_value) ->
|
||||||
their_tag_value == tag_value || their_tag_value == to_string(tag_value)
|
their_tag_value == tag_value || their_tag_value == to_string(tag_value)
|
||||||
else
|
|
||||||
|
is_binary(tag_value) && is_atom(their_tag_value) ->
|
||||||
|
their_tag_value == tag_value || to_string(their_tag_value) == tag_value
|
||||||
|
|
||||||
|
true ->
|
||||||
their_tag_value == tag_value
|
their_tag_value == tag_value
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -253,11 +258,11 @@ defmodule Ash.Type.Union do
|
||||||
}}}
|
}}}
|
||||||
|
|
||||||
{:error, other} ->
|
{:error, other} ->
|
||||||
{:halt, {:error, "is not a valid #{type_name}: #{inspect(other)}"}}
|
{:halt, {:expose_error, other}}
|
||||||
end
|
end
|
||||||
|
|
||||||
{:error, other} ->
|
{:error, other} ->
|
||||||
{:halt, {:error, "is not a valid #{type_name}: #{inspect(other)}"}}
|
{:halt, {:expose_error, other}}
|
||||||
|
|
||||||
:error ->
|
:error ->
|
||||||
{:halt, {:error, "is not a valid #{type_name}"}}
|
{:halt, {:error, "is not a valid #{type_name}"}}
|
||||||
|
@ -302,6 +307,9 @@ defmodule Ash.Type.Union do
|
||||||
{:error, errors} ->
|
{:error, errors} ->
|
||||||
{:error, error_message(errors)}
|
{:error, error_message(errors)}
|
||||||
|
|
||||||
|
{:expose_error, errors} ->
|
||||||
|
{:error, errors}
|
||||||
|
|
||||||
{:ok, value} ->
|
{:ok, value} ->
|
||||||
{:ok, value}
|
{:ok, value}
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,32 @@ defmodule Ash.Test.Type.UnionTest do
|
||||||
@moduledoc false
|
@moduledoc false
|
||||||
use ExUnit.Case, async: true
|
use ExUnit.Case, async: true
|
||||||
|
|
||||||
|
defmodule Foo do
|
||||||
|
use Ash.Resource, data_layer: :embedded
|
||||||
|
|
||||||
|
attributes do
|
||||||
|
attribute :foo, :string, constraints: [match: ~r/foo/]
|
||||||
|
|
||||||
|
attribute :type, :string do
|
||||||
|
writable? false
|
||||||
|
default "foo"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
defmodule Bar do
|
||||||
|
use Ash.Resource, data_layer: :embedded
|
||||||
|
|
||||||
|
attributes do
|
||||||
|
attribute :bar, :string, constraints: [match: ~r/bar/]
|
||||||
|
|
||||||
|
attribute :type, :string do
|
||||||
|
writable? false
|
||||||
|
default "bar"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
test "it handles simple types" do
|
test "it handles simple types" do
|
||||||
constraints = [
|
constraints = [
|
||||||
types: [
|
types: [
|
||||||
|
@ -50,6 +76,38 @@ defmodule Ash.Test.Type.UnionTest do
|
||||||
assert {:ok, %Ash.Union{value: %{type: :bar, bar: 1}, type: :bar}} =
|
assert {:ok, %Ash.Union{value: %{type: :bar, bar: 1}, type: :bar}} =
|
||||||
Ash.Type.cast_input(:union, %{type: :bar, bar: 1}, constraints)
|
Ash.Type.cast_input(:union, %{type: :bar, bar: 1}, constraints)
|
||||||
|
|
||||||
assert {:error, _} = Ash.Type.cast_input(:union, %{type: :baz, bar: 1}, constraints)
|
assert {:error, _} =
|
||||||
|
Ash.Type.cast_input(:union, %{type: :baz, bar: 1}, constraints)
|
||||||
|
end
|
||||||
|
|
||||||
|
test "it handles paths" do
|
||||||
|
constraints = [
|
||||||
|
items: [
|
||||||
|
types: [
|
||||||
|
foo: [
|
||||||
|
type: Foo,
|
||||||
|
tag: :type,
|
||||||
|
tag_value: :foo
|
||||||
|
],
|
||||||
|
bar: [
|
||||||
|
type: Bar,
|
||||||
|
tag: :type,
|
||||||
|
tag_value: :bar
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
|
||||||
|
{:ok, %{type: type, constraints: constraints}} =
|
||||||
|
Ash.Type.set_type_transformation(%{
|
||||||
|
type: {:array, Ash.Type.Union},
|
||||||
|
constraints: constraints
|
||||||
|
})
|
||||||
|
|
||||||
|
assert {:ok, [%Ash.Union{value: %{type: "foo", foo: "foo"}, type: :foo}]} =
|
||||||
|
Ash.Type.cast_input(type, [%{type: :foo, foo: "foo"}], constraints)
|
||||||
|
|
||||||
|
# assert {:ok, [%Ash.Union{value: %{type: "foo", foo: "foo"}, type: :foo}]} =
|
||||||
|
Ash.Type.cast_input(type, [%{type: :foo, foo: "bar"}], constraints) |> IO.inspect()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue