Computing a virtual field from multiple fields in schema

Skip to first unread message

May 7, 2018, 3:27:03 PM5/7/18
to elixir-ecto

Is there a way to compute virtual fields with other non virtual fields in a schema when loading from the database?

In my case I need to convert an amount and currency into a Money struct. The only way I see is to store a map in a single field, but I would like to keep this in multiple columns for SQL order, select and index.

I'm thinking about something similar to this:

defmodule Myapp.Cost do
  use Ecto.Schema
  alias Myapp.{Money, Product, Purchase}

  schema "cost" do
    belongs_to :product,          Product

    has_many :purchases,      Purchase

    field :amount,                     :integer,        null: false
    field :currency,                   :string,           null: false,   size: 3
    field :cost                           Money.Type, virtual: true, from: [:amount, :currency]


defmodule Myapp.Money.Type do
  @behaviour Ecto.Type
  def type, do: :any

  # Not sure if needed as it's a virtual field?
  def cast(_), do: :error

  # This is how I imagine computing the virtual field could work
  def load([amount, currency]) when is_integer(amount) and is_binary(currency)  do
    money = Money.from_integer(amount, currency)
    {:ok, money}
  def load(_), do: :error

  # Not sure if needed as it's a virtual field?
  def dump(_), do: :error
iex> Myapp.Repo.get_by(Myapp.Cost, id: 1)
%Myapp.Cost{id: 1, amount: 100, currency: "USD", cost: %Money{amount: 100, currency: :USD}}

iex> Myapp.Repo.get_by(Myapp.Purchase, id: 1) |> Myapp.Repo.preload(:cost)
%Myapp.Purchase{id: 1, cost: %Myapp.Cost{id: 1, amount: 100, currency: "USD", cost: %Money{amount: 100, currency: :USD}}}

Ivan Yurov

May 11, 2018, 12:11:28 AM5/11/18
to elixir-ecto
You can simply use something like select_merge:
select_merge(query, [c], %{cost: fragment("type_conversion_and_concatenation_function_that_your_db_provides(?, ?)", c.amount, c.currency)}
And your virtual field will be populated. But this will only work in simple cases that aren't involving application logic.

May 12, 2018, 12:14:47 AM5/12/18
to elixir-ecto
Thanks a lot, Ivan Yurov for your response but as you say yourself it only works in simple cases and that is not really what I'm looking for
I would argue that this could make Ecto way more powerful if we could do these kinds of post hooks.

Ivan Youroff

May 12, 2018, 2:24:39 AM5/12/18
I see what you mean, but I believe Elixir people would argue that this kind of computed attributes is something from OOP world, not FP. This might be implemented as a function that would inject this attribute inside of representation layer: JaSerializer/Absinthe or HTML.

You received this message because you are subscribed to the Google Groups "elixir-ecto" group.
To unsubscribe from this group and stop receiving emails from it, send an email to
To view this discussion on the web visit
For more options, visit

Kind regards,
Ivan Yurov
Reply all
Reply to author
0 new messages