From f03b6a4370d741b23cdd1b7432cb1fdc6f10eaa5 Mon Sep 17 00:00:00 2001 From: Robert Graff Date: Wed, 25 Oct 2023 05:31:25 -0700 Subject: [PATCH] fix: handle builtin types in unions (#752) --- .gitpod.yml | 5 ++++ lib/ash/type/union.ex | 2 ++ test/type/union_test.exs | 56 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 63 insertions(+) create mode 100644 .gitpod.yml diff --git a/.gitpod.yml b/.gitpod.yml new file mode 100644 index 00000000..326062b1 --- /dev/null +++ b/.gitpod.yml @@ -0,0 +1,5 @@ +image: elixir:latest + +tasks: + - init: mix deps.get && mix compile + command: iex -S mix \ No newline at end of file diff --git a/lib/ash/type/union.ex b/lib/ash/type/union.ex index 31ffa4b6..9addfc3a 100644 --- a/lib/ash/type/union.ex +++ b/lib/ash/type/union.ex @@ -521,6 +521,7 @@ defmodule Ash.Type.Union do {:ok, type_config} <- Keyword.fetch(type_configs, type_name), {:ok, type} <- Keyword.fetch(type_config, :type), type_constraints <- Keyword.get(type_config, :constraints, []), + type <- Ash.Type.get_type(type), {:ok, new_value} <- type.handle_change(nil, new_value, type_constraints) do {:ok, %Ash.Union{type: type_name, value: new_value}} end @@ -574,6 +575,7 @@ defmodule Ash.Type.Union do {:ok, type_config} <- Keyword.fetch(type_configs, type_name), {:ok, type} <- Keyword.fetch(type_config, :type), type_constraints <- Keyword.get(type_config, :constraints, []), + type <- Ash.Type.get_type(type), {:ok, value} <- type.prepare_change(old_value, new_value, type_constraints) do {:ok, %Ash.Union{type: type_name, value: value}} end diff --git a/test/type/union_test.exs b/test/type/union_test.exs index 78d010aa..d5a2c4f1 100644 --- a/test/type/union_test.exs +++ b/test/type/union_test.exs @@ -84,6 +84,62 @@ defmodule Ash.Test.Type.UnionTest do assert {:error, _} = Ash.Type.cast_input(:union, 11, constraints) end + test "it handles changes between native types" do + constraints = [ + types: [ + foo: [ + type: :integer + ], + bar: [ + type: :string + ] + ] + ] + + assert {:ok, %Ash.Union{type: :bar, value: "bar"}} = + Ash.Type.Union.prepare_change( + %Ash.Union{type: :foo, value: 1}, + "bar", + constraints + ) + + assert {:ok, %Ash.Union{type: :bar, value: "bar"}} = + Ash.Type.Union.handle_change( + %Ash.Union{type: :foo, value: 1}, + %Ash.Union{type: :bar, value: "bar"}, + constraints + ) + end + + test "it handles changes between native and tagged types" do + constraints = [ + types: [ + foo: [ + type: Foo, + tag: :type, + tag_value: :foo + ], + bar: [ + type: :string + ] + ] + ] + + assert {:ok, %Ash.Union{type: :bar, value: "bar"}} = + Ash.Type.Union.prepare_change( + %Ash.Union{type: :foo, value: %Foo{}}, + "bar", + constraints + ) + + assert {:ok, %Ash.Union{type: :bar, value: "bar"}} = + Ash.Type.Union.handle_change( + %Ash.Union{type: :foo, value: %{}}, + %Ash.Union{type: :bar, value: "bar"}, + constraints + ) + end + test "it handles tagged types" do constraints = [ types: [