Using ex_money_sql with Ash
metlnerd:
I’m hoping to use the
Money type defined in the
ex_money library as an attribute in Ash resources. This library has a companion,
ex_money_sql that creates a Postgres migration and creates a custom type:
def up do
execute("CREATE TYPE public.money_with_currency AS (currency_code varchar, amount numeric);")
end
In the documentation, there’s a
Money struct, a
:money_with_currency , a
Money.Ecto.Composite.Type all used in various places. I’m very new to Elixir, Ash, and Ecto so it’s all a bit confusing.
I’m assuming I need a Custom Ash Type (right?), but not sure which identifiers mean what - for example, the existing examples for an Ash custom type all use an atom like
:map or
:string for
storage_type , but it isn’t clear to me how they get defined, and if Ash would be able to see custom types in Postgres. Should I bypass the
_sql library and roll my own
:map -based solution?
ZachDaniel:
I believe using
storage_type of
:money_with_currency should pretty much do it for you as that will end up mapping to the exact sql type. There are a lot of layers there, basically because we build on top of ecto and they have some named storage types (like :map)
metlnerd:
Thanks, I ended up with this:
metlnerd:
defmodule Worthy.AshMoney do
use Ash.Type
@impl true
def storage_type, do: :money_with_currency
@impl true
def cast_input(value, _) do
Ecto.Type.cast(Money.Ecto.Composite.Type, value)
end
@impl true
def cast_stored(value, _) do
Ecto.Type.load(Money.Ecto.Composite.Type, value)
end
@impl true
def dump_to_native(value, _) do
Ecto.Type.dump(Money.Ecto.Composite.Type, value)
end
end
ZachDaniel:
You’ll probably want to handle nil values in those callbacks
ZachDaniel:
Unlike ecto we give types control over nil values
metlnerd:
SG, thanks