Best strategy to storing an Elixir struct type attribute using Ash

What’s the best approach to storing a simple Elixir struct as an Ash Resource attribute?

Should I be implementing the Ash.Type callbacks in the custom module?

I initially (naively!) tried to set the attribute to be of type Ash.Type.Struct - along the lines of:

 attribute :foo, Ash.Type.Struct do
      allow_nil? true
      constraints instance_of: Play.Foo
 end

And the Ash code generator created a migration adding a map to the table:

alter table(:things) do
      add(:foo, :map)
end

All looks fine until I try to “commit” the changeset when I hit a type mismatch:

  • ** (Ecto.ChangeError) value %Play.Foo{id: "John", name: 23} for Play.Model.Thing.foo in insert_all does not match type ash.Type.Struct.EctoType<[instance_of: Play.Foo, preserve_nil_values?: false]>

So is the correct approach to take control over the conversion using Ash.Type?

Thanks (and sorry for all of these questions - but I love exploring Ash)

Martin

You can specify the fields constraint and model the fields, which should allow you to do that. I fixed some bugs w/ the struct type recently so make sure to update.

attribute :foo, Ash.Type.Struct do
  constraints instance_of: Play.Foo, fields: [foo: [type: :string, allow_nil?: false]]
end

You can use Ash.Type.NewType to make this more seamless:

defmodule Play.Foo do
  destruct [:foo]
  use Ash.Type.NewType, subtype_of: :struct, constraints: [
    instance_of: __MODULE__,
    fields: [foo: [type: :string, allow_nil?: false]]
  ]
end

then you can say attribute :foo, Play.Foo

1 Like

Thanks for the above @zachdaniel .

I’m curious (however) as to what was the best path that I should have taken to discover the Ash.Type.NewType module. How best to attack the documentation and found it to exploit/use.

Is there a guide that mentions this as a strategy to explore?

I’ve just found it mentioned in the “Define Polymorphic Relationships” guide - but that wouldn’t have been a place that I would have considered for the scope of this mini-problem.

Is this worth adding to the Ash.Type module docs?

Martin

Yeah, you’re totally right. We should surface Ash.Type.NewType high up on the Ash.Type docs. If you could open a proposal or a PR that would be excellent :bowing_man:

Done. I created a PR - with some suggested (to be improved) updates to the module_doc for Ash.Type.

No improvements necessary :heart: looks great, merged :white_check_mark: