Complex types (postgres)

Is it possible to create (and use) complex types like this
CREATE DOMAIN dow AS integer
CHECK(
value BETWEEN 1 and 7
);

CREATE TYPE week_range as (
start_dow dow,
start_time time,
end_dow dow,
end_time time,
limit_in_seconds integer
);
CREATE DOMAIN dow AS integer
CHECK(
value BETWEEN 1 and 7
);

CREATE TYPE week_range as (
start_dow dow,
start_time time,
end_dow dow,
end_time time,
limit_in_seconds integer
);
?
13 Replies
kernel
kernel2y ago
is that possible in Ecto? if it is then the procedure for Ash would be creating an Ash type on top of the Ecto type
ZachDaniel
ZachDaniel2y ago
Definitely doable. As @kernel said you’d essentially start with a corresponding ecto type and create the underlying type yourself. Keep in mind you’ll likely need to register the type with postgrex I'd probably just do this particular one app side, using Ash.Type.NewType
defmodule MyApp.DayOfWeek do
use Ash.Type.NewType, subtype_of: :integer, constraints: [min: 1, max: 7]
end
defmodule MyApp.DayOfWeek do
use Ash.Type.NewType, subtype_of: :integer, constraints: [min: 1, max: 7]
end
tellesleandro
tellesleandroOP2y ago
Sure, it is: add :horarios, {:array, :week_range}, null: false, default: [] How do I register the type with postgres using Ash? I do it in a regular Phoenix/Ecto project adding a migration manually.
ZachDaniel
ZachDaniel2y ago
well, I was thinking you might need to register it with postgrex, but I'm not actually sure that will be necessary 🙂 As for actually creating the type, you can do mix ecto.gen.migration as normal and define the type just like you would have with ecto
tellesleandro
tellesleandroOP2y ago
Ok. I'll do that. Thanks.
ZachDaniel
ZachDaniel2y ago
FWIW, do you explicitly want that to be a complex type as opposed to something like jsonb?
tellesleandro
tellesleandroOP2y ago
Right now, I'm trying to migrate a regular Phoenix/Ecto project to Ash. I've already developed several modules that use this kind of struct. Actually, the system is based on a column that is a list of :weekrange and the weekrange type is composed of 5 fields: start_dow dow, start_time time, end_dow dow, end_time time, limit_in_seconds integer. I don't wanna refactor all modules that are already tested. I wanna use Ash with the same db resources that are in production. What's the side effect of defining (creating) migrations outside of Ash? Does Ash understand that there is a type in the db called weekrange and that there is a resource field using that type?
kernel
kernel2y ago
okay, so create an Ash.Type that essentially proxies that type in Ash, similar to the tstzrange I gave you
tellesleandro
tellesleandroOP2y ago
Ok
ZachDaniel
ZachDaniel2y ago
no issues 🙂 Ash doesn't care one way or the other
tellesleandro
tellesleandroOP2y ago
Ok. Thanks. What storage_type do I use for the Ash.Type?
@impl Ash.Type
def storage_type, do: :list

@impl Ash.Type
def cast_input(nil, _), do: {:ok, nil}
def cast_input({start_dow, start_time, end_dow, end_time, limit_in_seconds}, _) do
with {:ok, start_dow} <- Ecto.Type.cast(:integer, start_dow),
{:ok, start_time} <- Ecto.Type.cast(:time_usec, start_time),
{:ok, end_dow} <- Ecto.Type.cast(:integer, end_dow),
{:ok, end_time} <- Ecto.Type.cast(:time_usec, end_time),
{:ok, limit_in_seconds} <- Ecto.Type.cast(:integer, limit_in_seconds) do
{:ok, {start_dow, start_time, end_dow, end_time, limit_in_seconds}}
else
_ -> :error
end
end
...
@impl Ash.Type
def storage_type, do: :list

@impl Ash.Type
def cast_input(nil, _), do: {:ok, nil}
def cast_input({start_dow, start_time, end_dow, end_time, limit_in_seconds}, _) do
with {:ok, start_dow} <- Ecto.Type.cast(:integer, start_dow),
{:ok, start_time} <- Ecto.Type.cast(:time_usec, start_time),
{:ok, end_dow} <- Ecto.Type.cast(:integer, end_dow),
{:ok, end_time} <- Ecto.Type.cast(:time_usec, end_time),
{:ok, limit_in_seconds} <- Ecto.Type.cast(:integer, limit_in_seconds) do
{:ok, {start_dow, start_time, end_dow, end_time, limit_in_seconds}}
else
_ -> :error
end
end
...
kernel
kernel2y ago
the postgres type :week_range probably
tellesleandro
tellesleandroOP2y ago
Bingo. That worked (at least, the migration). I'll try to use the API (crud) and will keep you updated. Thanks.

Did you find this page helpful?