improvement: expose union errors with path when tag is set

This commit is contained in:
Zach Daniel 2023-08-15 14:07:28 -07:00
parent 5549bbf290
commit 8c1f334075
3 changed files with 75 additions and 9 deletions

View file

@ -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}}

View file

@ -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}

View file

@ -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