Using ex_money_sql with Ash

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
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?
4 Replies
ZachDaniel
ZachDaniel2y ago
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)
5avage
5avageOP2y ago
Thanks, I ended up with this:
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
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
ZachDaniel2y ago
You’ll probably want to handle nil values in those callbacks Unlike ecto we give types control over nil values
5avage
5avageOP2y ago
SG, thanks

Did you find this page helpful?