Hi,
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]
timestamps()
end
end
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}
end
def load(_), do: :error
# Not sure if needed as it's a virtual field?
def dump(_), do: :error
end```
```
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}}}
```