diff --git a/lib/polymorphic_embed.ex b/lib/polymorphic_embed.ex index 77a8226..47e8ad9 100644 --- a/lib/polymorphic_embed.ex +++ b/lib/polymorphic_embed.ex @@ -360,6 +360,16 @@ defmodule PolymorphicEmbed do to_string(type_from_parent_field) != to_string(type_from_map) -> raise "type specified in the parent field \"#{type_from_parent_field}\" does not match the type in the embedded map \"#{type_from_map}\"" + + true -> + # type_from_parent_field and type_from_map match + module = get_polymorphic_module_for_type(type_from_parent_field, types_metadata) + + if is_nil(data_for_field) or data_for_field.__struct__ != module do + {:insert, struct(module)} + else + {:update, data_for_field} + end end else case get_polymorphic_module_from_map(params, type_field_name, types_metadata) do diff --git a/test/polymorphic_embed_test.exs b/test/polymorphic_embed_test.exs index 7dced00..fd8a19e 100644 --- a/test/polymorphic_embed_test.exs +++ b/test/polymorphic_embed_test.exs @@ -199,6 +199,35 @@ defmodule PolymorphicEmbedTest do assert {:error, %Ecto.Changeset{}} = insert_result end + test "infer type from parent field when type in embed map matches parent field type" do + generator = :polymorphic + reminder_module = get_module(Reminder, generator) + + # Both parent field type and embed __type__ are "sms" - they match + sms_reminder_attrs = %{ + date: ~U[2020-05-28 02:57:19Z], + text: "This is an SMS reminder #{generator}", + type: "sms", + channel4: %{ + __type__: "sms", + number: "02/807.05.53", + country_code: 1, + provider: %{ + __type__: "twilio", + api_key: "foo" + } + } + } + + insert_result = + struct(reminder_module) + |> reminder_module.changeset(sms_reminder_attrs) + |> Repo.insert() + + assert {:ok, %{channel4: %PolymorphicEmbed.Channel.SMS{number: "02/807.05.53"}}} = + insert_result + end + test "validations before casting polymorphic embed still work" do for generator <- @generators do reminder_module = get_module(Reminder, generator)