Custom Ecto.Type - how to create virtual fields to be used in select_merge/3?

I have a use-case where I want a virtual ecto field to be used in select_merge/3:

schema "test" do
  field :test, Custom.Type, virtual: true
end

Then I want to do some custom data mapping on the received results on server-side(not database).

The problem is that none of the callbacks of the custom type are being fired. I would expect that the ones responsible for encoding when inserting data to not work, but not all of them.

Any ideas, suggestions on this behavior or ways to overcome it?

2 Likes

Why would it be virtual if you load it from the db?

It’s not related in any way to the table structure, it’s a field that is a result of a joined relation + some postgres aggregate functions.

Schemas are already not (enforced to be) related to table structures in the first place.

Yes, however when doing inserts I want that field to be ignored, if I don’t set it as a virtual, ecto will complain that such field doesn’t exist.

Afaik that’s only supposed to happen if there are changes for that field.

It does seem to happen, the field is not even added to cast in changeset and Postgrex raises with column not found error, the query includes that column.

Is this on an update or an insert? You can insert with and without using a changeset. Though curious what value it even tries to insert.

On insert with changeset at the very least. It seems that changeset is irrelevant as Postgrex crashes when building the query, I cannot inspect the query even without running it.

Also on this topic, if I remember well virtual fields are not even validated when used together with select_merge, even though not using them will throw an error of invalid schema. :face_with_raised_eyebrow:

Small update: I have read ecto documentation and there is this option:

:load_in_query - When false, the field will not be loaded when selecting the whole struct in a query, such as from p in Post, select: p. Defaults to true.

It does seem to work on inserts and selects, the problem with select_merge and lack of any kind of validation still persists as before.

Recently, I wanted to load an aggregated JSONB array into a virtual field and to validate and cast it to a schema. The only way I got it working was via Ecto.Repo.load/2. It probably isn’t exactly what you’re looking for but might do the job.

1 Like