Fire-Dragon-DoL
Hello,
I’m being curious about why Ecto needs explicit casting when passing arguments to a query. I faced the following situation:
amount = %Amount{value: 1, type: "spa"}
Iris.Repo
|> Ecto.Adapters.SQL.query!("insert into prospect_overview(amount) values ($1)", [amount])
The Amount struct implements the behaviour Ecto.Type.
This example doesn’t work though, it require me to explicitly state the type:
amount = %Amount{value: 1, type: "spa"}
Iris.Repo
|> Ecto.Adapters.SQL.query!("insert into prospect_overview(amount) values ($1)", [type(Amount, amount)])
If amount was one of the basic types (string, integer, binaries, booleans, float and array of basic types), I don’t need to cast, however for everything else I need to.
While it totally make sense when using Ecto.Query DSL, since some things might need conversions (e.g. is_nil(something) becomes IS NULL in SQL, I can’t figure out why this is needed when passing params to a “string-based” query:
The struct can definitely implement some kind of protocol to request “auto casting” to the DB type, the basic types are detectable and covered. Shouldn’t the conversion be possible automatically?
Trending in Questions
Other Trending Topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #library
- #deployment
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #elixirconf
- #channels
- #exunit
- #discussion
- #code-sync
- #podcasts
- #javascript
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixirconf-us
- #ai
- #blog-post
- #elixir-ls
- #phoenix_html
- #iex
- #graphql
- #genstage
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #hex
- #security
- #metaprogramming










Showing Posts 1 to 10- Show Best Posts
- Show All (oldest first)
- Show All (newest first)
landric
This isn’t actually answering your question, but why are you inserting in this manner?
You could just…
idi527
I think OP stated that
%Amount{}is not necessarily an ecto schema struct, so there is no information about which table to insert it into forRepo.insertto work.peerreynders
I think this is the source of the confusion.
When I read the
Ecto.Typedocumentation I’m seeing a way of defining a type converter for an existing type - you are treatingEcto.Typeas some kind of interface for the type to implement.So given an existing
%Amount{}type,Ecto.Typecan be used to define anEctoAmountconverter module. With this more general use case there is no inherent link betweenAmountandEctoAmountso “autocasting” can’t happen without additional configuration facilities.At this point
type(^amount, EctoAmount)is an explicit way to specify which converter to use to convert theamountruntime data to an Ecto native type.Having
AmountandEctoAmountseparated also means thatAmountis no longer coupled to Ecto which would generally be viewed as beneficial.Fire-Dragon-DoL
Thanks for the answers.
I don’t mind if
Amountrequires Ecto or not in my specific case at least (type was created specifically to deal with a special postgres type).I’m surprised though that there is no protocol to implement which would prevent having to specify the casting at all.
Not to mention, you can easily provide the “ecto support” at compile-time based on the presence or absence of ecto itself (or just as a flag really)
peerreynders
That’s about convenience.
I think the argument is that
Amountshould be about the business rules surrounding the data. MeanwhileEctoAmountis simply about converting to and from Ecto native types.Fire-Dragon-DoL
Yes, and it would also make your type feels less like “second-class citizen”. It works for some native types (not for map though) but it doesn’t work for your own types. That’s an inconsistency in my point of view.
For what is worth, you could even have a package having only the protocol, so you won’t depend on entire Ecto, and still being able to split Amount/EctoAmount.
For now, I’ll solve by providing a method that automatically casts all the arguments in a given list
dimitarvp
Transparently [de-]serializing Ecto schemas is very possible since they are structs – which are basically maps.
However there’s the danger that Ecto can thus [de-]serialize a privacy-sensitive field like a password or a phone which you might not always want. So it opts for explicitness.
Also, your “entire Ecto” statement seems like a way to chase micro-optimization (and a premature one at that). Your app definitely won’t bloat due to Ecto and it offers a lot (like changesets / validation).
EDIT: If you need to work with arbitrary maps without promoting them to Ecto schemas you can always make a JSONB column in your PG database and add a field to an Ecto schema you have. Then you can unload pretty much anything in it.
Fire-Dragon-DoL
I’m honestly not understanding what you are talking about:
Apologize if I’m getting it wrong, but I’m afraid there is a misunderstanding in what we are talking about
dimitarvp
Sorry for misunderstanding. I got under the impression that you wanted Ecto to blindly accept arbitrary maps and inject them into SQL.
Fire-Dragon-DoL
No problem, all good!