Error when updating an atom field

There is a table with a Postgres ENUM type:

CREATE TYPE status AS ENUM(
'status_1',
'status_2'
);

CREATE TABLE public.tabela (
id uuid NOT NULL,
inserted_at timestamptz NOT NULL,
updated_at timestamptz NOT NULL,
status public.status NOT NULL,
CONSTRAINT estadias_pkey PRIMARY KEY (id)
);

and its Ash resource:

defmodule API.Tabela do

   ...

  attributes do
    uuid_primary_key(:id)
    create_timestamp(:inserted_at)
    update_timestamp(:updated_at)
    attribute :status, :atom do
      allow_nil?(false)
      constraints(one_of: [:status_1, :status2])
    end
  end

  ...
 
 end

I’m able to create a record with the following statement:

registro = API.Tabela.create!(%{
status: :status_1
})

but if I try to update it, with the statement:

API.Tabela.update!(registro, %{status: :status_2})

I get the following error:

** (Ash.Error.Unknown) Unknown Error

* ** (Postgrex.Error) ERROR 42804 (datatype_mismatch) column "status" is of type status but expression is of type character varying

    query: UPDATE "tabela" AS t0 SET "status" = $1::varchar WHERE (t0."id"::uuid = $2::uuid) ..."

    hint: You will need to rewrite or cast the expression.

Why is it possible to use :atom to create the record, but not to update?

This looks like a bug, unfortunately. Please open an issue on the ash_postgres repo. If you can also provide a reproduction in the form of a test that would be great as well.

Actually…this is interesting. It may just sort of be a happenstance that this works honestly. atom type is backed by a text in the database.

You would want something like this:

defmodule MyApp.Status do
  use Ash.Type.Enum, values: [:status_1, :status_2]

  def storage_type(_), do: :status
end

and then use that in your attribute:

attribute :status, MyApp.Status

Thanks, Zach. I’m trying to move on, but I’m facing another issue. If I add the type like in the example, I get the following error:

== Compilation error in file lib/lgs/operacional/resources/types/estadias_status.ex ==
** (RuntimeError) Must only define storage_type/0 or storage_type/1 but not both
    (stdlib 4.3.1.3) erl_eval.erl:744: :erl_eval.do_apply/7
    (stdlib 4.3.1.3) erl_eval.erl:136: :erl_eval.exprs/6
    (ash 2.19.14) /home/leandro/Development/2023/garagem/lgs/lib/lgs/operacional/resources/types/estadias_status.ex:1: Ash.Type.__before_compile__/1

If I remove the line def storage_type(_), do: :status, I get the same error as before.

It works with def storage_type, do: :status.

I’ll mark your answer as a solution and open an issue on GH.

Thanks.

1 Like