ash_graphql/documentation/how_to/use-enums-with-graphql.md

98 lines
2.3 KiB
Markdown
Raw Normal View History

# Use Enums with GraphQL
2021-03-29 08:46:23 +13:00
## Automatically created enums
Enums are implemented automatically for any `atom` *attribute* (not arguments) with a `one_of` constraint. For example:
2021-03-29 08:46:23 +13:00
```elixir
# On the resource of type `:ticket`
attribute :type, :atom do
constraints one_of: [:foo, :bar, :baz]
end
2021-03-29 08:46:23 +13:00
```
This would produce an enum called `:ticket_type`/`TicketType`.
## Custom enums
### Using Ash Enum types
If you define an `Ash.Type.Enum`, that enum type can be used both in attributes *and* arguments. You will need to add `graphql_type/0` to your implementation. AshGraphql will ensure that a single type is defined for it, which will be reused across all occurrences. If an enum
type is referenced, but does not have `graphql_type/0` defined, it will
be treated as a string input.
For example:
```elixir
defmodule AshPostgres.Test.Types.Status do
@moduledoc false
use Ash.Type.Enum, values: [:open, :closed]
def graphql_type, do: :ticket_status
end
```
### Using custom absinthe types
2021-03-29 08:46:23 +13:00
You can implement a custom enum by first adding the enum type to your absinthe schema (more [here](https://hexdocs.pm/absinthe/Absinthe.Type.Enum.html)). Then you can define a custom Ash type that refers to that absinthe enum type.
```elixir
# In your absinthe schema:
enum :status do
value(:open, description: "The post is open")
value(:closed, description: "The post is closed")
end
```
```elixir
# Your cusotm Ash Type
defmodule AshGraphql.Test.Status do
use Ash.Type
@values [:open, :closed]
@string_values Enum.map(@values, &to_string/1)
def graphql_input_type(_), do: :status
def graphql_type(_), do: :status
@impl true
def storage_type, do: :string
@impl true
def cast_input(value, _) when value in @values do
{:ok, value}
end
def cast_input(value, _) when is_binary(value) do
value = String.downcase(value)
if value in @string_values do
{:ok, String.to_existing_atom(value)}
else
:error
end
end
@impl true
def cast_stored(value, _) when value in @values do
{:ok, value}
end
def cast_stored(value, _) when value in @string_values do
{:ok, String.to_existing_atom(value)}
rescue
ArgumentError ->
:error
end
@impl true
def dump_to_native(value, _) when is_atom(value) do
{:ok, to_string(value)}
end
def dump_to_native(_, _), do: :error
end
```