with
February 7, 2020, 7:56pm
1
Hi,
I have an Absinthe field for the user’s gender that can be either :male
or :female
.
The problem is that the Ecto schema stores the type as a string
, while my Absinthe resolver receives an atom
.
Therefore I’m getting an error:
errors: [gender: {"is invalid", [type: :string, validation: :cast]}]
What is the idiomatic way to handle this type mismatch? I’ve tried converting the changeset
params with &Atom.to_string/1
, but this seems rather hacky:
defp fix_types(params) do
params
|> Map.update(:gender, nil, &Atom.to_string/1)
end
Is there a better solution?
Thank you!
idi527
February 7, 2020, 8:22pm
2
Is using atoms in the ecto schema an option? It can be implemented as a custom ecto type
defmodule YourApp.Gender do
use Ecto.Type
genders = [:male, :female]
def type, do: :string
for gender <- genders do
def cast(unquote(gender)), do: {:ok, unquote(gender)}
def cast(unquote(to_string(gender))), do: {:ok, unquote(gender)}
def load(unquote(to_string(gender))), do: {:ok, unquote(gender)}
def dump(unquote(gender)), do: {:ok, unquote(to_string(gender))}
def dump(unquote(to_string(gender))), do: {:ok, unquote(to_string(gender))}
end
def cast(_other), do: :error
def dump(_other), do: :error
end
or using https://hex.pm/packages/ecto_enum .
3 Likes
with
February 7, 2020, 9:29pm
4
Thank you, this seems to be the proper solution!
with
February 7, 2020, 9:29pm
5
Thanks, I’m already using it as follows:
enum :gender do
value :male
value :female
end
The problem is that the Ecto schema expects strings, while the Enum type contains atom values.
I think your problem can be solved by using Absinthe.Middleware.MapGet
.
In your schema.ex
, define a new apply
function which transforms :gender atoms to strings. I assume you have a middleware function like this:
def middleware(middleware, field, object) do
middleware
# |> ...your own apply functions
|> apply(:get_string, field, object)
end
defp apply(middleware, :get_string, field, %{identifier: :gender} = object) do
new_middleware = {Absinthe.Middleware.MapGet, to_string(field.identifier)}
middleware
|> Absinthe.Schema.replace_default(new_middleware, field, object)
end
I stole this technique almost verbatim from Craft GraphQL APIs in Elixir with Absinthe (Pragprog)
I think enums are coming to Ecto
elixir-ecto:master
← TheFirstAvenger:mb-parameterized-types-and-enum
opened 01:08AM - 24 Jun 20 UTC