polymorphic_embed icon indicating copy to clipboard operation
polymorphic_embed copied to clipboard

More ways to specify embedded schema module

Open pzingg opened this issue 4 years ago • 4 comments

I was working on a library that uses polymorphic embeds. Since it's a library that is used by applications, it cannot know all the polymorphic types ahead of time. This PR adds two more ways of specifying the :types option for a PolymorphicEmbed Ecto type: a lookup function that translates between "type" keys and schema modules, and a :by_module method that means that the type key atom (or a string version) IS the module.

Feel free to ignore, edit or implement this another way.

I added two more embeds to the test Reminder module, added a number of tests, and added instructions in the README file.

pzingg avatar Nov 13 '20 22:11 pzingg

Quite some work had to be done before I could look into this PR. I think we're definitely interested into adding this PR in the codebase. That's some quality work.

I guess you depend on your fork now? As there has been a lot of code refactoring in the meanwhile, would you be interested to bring these new functionalities into the current master code?

mathieuprog avatar Dec 25 '20 22:12 mathieuprog

This seems like a great feature that will make the library very dynamic. Any plans to merge this. What are the changes required to get this merged?

Ivor avatar Oct 03 '22 10:10 Ivor

The contributor created this PR while I was writing some major refactor when the library was in alpha.

It was created in November 2020 so the code changed quite a lot since then.

mathieuprog avatar Oct 03 '22 11:10 mathieuprog

I haven't looked through this PR, but I would find it useful (and more common in my experience) if the field that qualified the polymorphism were outside the arguments. For example, I might have a database with columns for type and data, where type qualifies the ad-hoc data map, e.g. as x, y, or z. Often the code pivots on such a field to determine how to handle the data.

I worked around this by adding an append_type function that read a field from the incoming parameters and then inserted it (as an atom) into the map field used by the polymorphic join:

def changeset(x, %{} = params, opts \\ []) do
    params = append_type(params, :qualifier, :args)
    x
    |> cast(params, [...])
    # ...
end

  defp append_type(params, src_field, target_embed_field) do
    qualifier = Map.fetch!(params, src_field)

    Map.put(
      params,
      :args,
      params
      |> Map.get(target_embed_field, %{})
      |> Map.put(:__type__, String.to_atom(qualifier))
    )
  end

This works, but it feels a bit awkward because it cannot rely on the usual get_change/get_field etc. and the requirement that the qualifying value has to be an atom threw me for bit.

fireproofsocks avatar Dec 22 '22 17:12 fireproofsocks