alexcastano
Hello,
I want to store a structured raw input in a JSONB column. This raw input is already in an embedded schema because it has been previously validated. However, the raw input can be of different type, some of the types being quite complex, as they have deeply nested structures.
When I had only 4 different types, I had a column for each one and I handled the polymorphism by myself:
schema "table" do
...
embeds_one type_one, TypeOne
embeds_one type_two, TypeTwo
...
end
But now, I want to add a lot more types, and I don’t think is efficient to have 30 different columns. So I would like to store the information in the same column, but when loading the record using a type field, it would load one structure or another.
I’m trying to use Ecto.Type to do this job, but I find myself doing a lot of work that was previously handled by Ecto:
First, I have to @derive {Jason.Encoder, only: [...]} in a lot of schemas. It feels wrong because I’m forced to use this protocol to store this information in one way. If I want to use the same protocol for another use, for example to encode in a JSON API, I won’t be able to do it in the future.
Also, I’m creating a lot of functions to load the raw JSON in the structures, basically using cast and cast_embed with all the stored fields.
So, I don’t know if I’m missing something, but I’d like to use functionalities that are already in Ecto with embeds_one to load, dump, embed_as, etc. my custom Ecto.Type. Do you think it would be possible?
Do you think is a good solution in general terms? Any advice?
Trending in Questions
Other Trending Topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #blog-post
- #phoenix_html
- #iex
- #graphql
- #ai
- #genstage
- #elixirconf-us
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #metaprogramming
- #security
- #hex










First 9 of 9 Posts
Eiji
@alexcastano Of course it’s possible, but
ectoitself does not helps in complex polymorphic use cases, so you would need to write it yourself.First of all you would need to have your
JSONlike:For it you would need to create a custom
Ecto.Type. For each callback you need to checktypefield and based on it you would need to creatennumber of modules which also implementsEcto.Type.Let’s say:
In such way you can simply write a code for each type. You only need to implement each
Ecto.Typerequired callback (cast,dumpandloadif I remember correctly).If you do this all you need to do (like migrations) is exactly the same as with
embeds_manyorembeds_one. I wrote all from memory, but it should work even with arrays.The only difference is that you no longer need to call
cast_embedand related functions as everything would be handled incast.alexcastano
Thank you for your response.
What I was wondering if I can save myself writing all the code of
MyApp.EctoTypes.FirstType,MyApp.EctoTypes.TwoType, etc; becauseEctoalready knows how todumpandloadanembed_schemaby itself. I mean, if I have:So what I’d like to do would be:
al2o3cr
Have you looked at GitHub - greenboxal/ecto_poly: Polymorphic embeds for Ecto · GitHub ? I haven’t tried it yet, but it seems pretty close to what you’re looking for.
EDIT: looks like Ecto 3 compatibility is still in-flight Ecto 3.x by jeanparpaillon · Pull Request #1 · greenboxal/ecto_poly · GitHub
Eiji
Just for sure you can just use map and don’t care about custom types and validations, but again you would lose a validations and if something goes wrong you would need to migrate all of inserted rows which I don’t think would be a nice for your “free weekend” time. In such case just use
:maptype infield/2macro.Those all custom types are for validating each type separately. Nobody forces you to validate every data you have.
tme_317
I had a similar issue and couldn’t figure it out so I am just storing compressed ETF in a
byteadatabase field that way I can store arbitrary highly nested structs/embedded_schemas in a single database field.It works using a custom Ecto type that dumps using
:erlang.term_to_binaryand loads using:erlang.binary_to_termOf course it’s not JSON so you can’t do PgSQL queries against it but I don’t need to do that in my use case.
alexcastano
Yeah, exactly. This was what I was looking for. I’ll take a look as soon as possible. Thank you.
The point is that I’ve already had the embedded schema validated. The only thing I want to do is the part of
dumpandload.Awesome! I’ve never thought about this solution. It doesn’t work for my current case, but I find it very interesting.
tme_317
I just found this issue/conversation that seems exactly what you are trying to do… maybe this helps?
https://github.com/Adzz/ecto_morph/issues/2
alexcastano
Yes! As far as I understood, they use EctoMorph to encode and decode the EmbedSchema in a JSON column.
EctoMorphuses Ecto Reflection to build this functionality. They also use theEcto.Typeto know which EmbedSchema it should be built. It is kind of manual work, but it works :).I think
EctoPolytried to do something very similar, more finished solution but it is not 100% working with the lastestEctoversions.mathieuprog
I published a library that brings support for polymorphic embeds
https://github.com/mathieuprog/polymorphic_embed