mirror of
https://github.com/ash-project/ash_graphql.git
synced 2024-09-19 12:53:40 +12:00
improvement!: No longer automagically derive types
This commit is contained in:
parent
78c5b6a3bb
commit
349086fbb8
21 changed files with 577 additions and 1567 deletions
1232
CHANGELOG.md
1232
CHANGELOG.md
File diff suppressed because it is too large
Load diff
74
documentation/how_to/upgrade.md
Normal file
74
documentation/how_to/upgrade.md
Normal file
|
@ -0,0 +1,74 @@
|
|||
# Upgrading to 1.0
|
||||
|
||||
AshGraphql 1.0 is a major release that introduces 3.0 support as well as a few
|
||||
breaking changes for AshGraphql itself.
|
||||
|
||||
## Automagic atom/union/map types are no more
|
||||
|
||||
Pre 1.0: AshGraphql automatically generated types for attributes/arguments that were atom/union/map types, giving them a name like `postStatus`, for an attribute `status` on a resource `post`. While convenient, this incurred _significant_ internal complexity, and had room for strange ambiguity. For example, if you had two actions, that each had an argument called `:status`, and that `:status` was an enum with different values, you would get a conflict at compile time due to conflicting type names.
|
||||
|
||||
### What you'll need to change
|
||||
|
||||
AshGraphql will now _only_ generate types for types defined using `Ash.Type.NewType` or `Ash.Type.Enum`. For example, if you had:
|
||||
|
||||
```elixir
|
||||
attribute :post_status, :atom, constraints: [one_of: [:active, :archived]]
|
||||
```
|
||||
|
||||
in 3.0 this attribute would display as a `:string`. To fix this, you would define an `Ash.Type.Enum`:
|
||||
|
||||
```elixir
|
||||
defmodule MyApp.PostStatus do
|
||||
use Ash.Type.Enum, values: [:active, :archived]
|
||||
|
||||
def graphql_type(_), do: :post_status
|
||||
def graphql_input_type(_), do: :post_status
|
||||
end
|
||||
```
|
||||
|
||||
Then you could use it in your attribute:
|
||||
|
||||
```elixir
|
||||
attribute :post_status, MyApp.PostStatus
|
||||
```
|
||||
|
||||
The same goes for map types with the `:fields` constraint, as well as union types, except you must define those using `Ash.Type.NewType`. For example:
|
||||
|
||||
```elixir
|
||||
attribute :scale, :union, constraints: [
|
||||
types: [
|
||||
whole: [
|
||||
type: :integer
|
||||
],
|
||||
fractional: [
|
||||
type: :decimal
|
||||
]
|
||||
]
|
||||
]
|
||||
```
|
||||
|
||||
Here you would get a compile error, indicating that we cannot determine a type for `:union`. To resolve this, you would define an `Ash.Type.NewType`, like so:
|
||||
|
||||
```elixir
|
||||
defmodule MyApp.Scale do
|
||||
use Ash.Type.NewType, subtype_of: :union, constraints: [
|
||||
types: [
|
||||
whole: [
|
||||
type: :integer
|
||||
],
|
||||
fractional: [
|
||||
type: :decimal
|
||||
]
|
||||
]
|
||||
]
|
||||
|
||||
def graphql_type(_), do: :scale
|
||||
def graphql_input_type(_), do: :scale
|
||||
end
|
||||
```
|
||||
|
||||
Then you could use it in your application like so:
|
||||
|
||||
```elixir
|
||||
attribute :scale, MyApp.Scale
|
||||
```
|
|
@ -1,7 +1,6 @@
|
|||
# Use Unions with GraphQL
|
||||
|
||||
By default, if a union is used in your resource in line, it will get a nice type generated for it based on the
|
||||
resource/key name. Often, you'll want to define a union using `Ash.Type.NewType`. For example:
|
||||
Unions must be defined with `Ash.Type.NewType`:
|
||||
|
||||
```elixir
|
||||
defmodule MyApp.Armor do
|
||||
|
|
|
@ -87,22 +87,11 @@ defmodule AshGraphql do
|
|||
|
||||
for resource <- ash_resources do
|
||||
resource
|
||||
|> AshGraphql.Resource.get_auto_unions()
|
||||
|> Enum.concat(resource |> AshGraphql.Resource.global_unions() |> Enum.map(&elem(&1, 1)))
|
||||
|> AshGraphql.Resource.global_unions()
|
||||
|> Enum.map(&elem(&1, 1))
|
||||
|> Enum.map(fn attribute ->
|
||||
if Ash.Type.NewType.new_type?(attribute.type) do
|
||||
cond do
|
||||
function_exported?(attribute.type, :graphql_type, 0) ->
|
||||
attribute.type.graphql_type()
|
||||
|
||||
function_exported?(attribute.type, :graphql_type, 1) ->
|
||||
attribute.type.graphql_type(attribute.constraints)
|
||||
|
||||
true ->
|
||||
AshGraphql.Resource.atom_enum_type(resource, attribute.name)
|
||||
end
|
||||
else
|
||||
AshGraphql.Resource.atom_enum_type(resource, attribute.name)
|
||||
if function_exported?(attribute.type, :graphql_type, 1) do
|
||||
attribute.type.graphql_type(attribute.constraints)
|
||||
end
|
||||
end)
|
||||
|> Enum.uniq()
|
||||
|
@ -252,7 +241,7 @@ defmodule AshGraphql do
|
|||
{"DurationName", :duration_name}
|
||||
|
||||
type ->
|
||||
graphql_type = type.graphql_type()
|
||||
graphql_type = type.graphql_type([])
|
||||
{graphql_type |> to_string() |> Macro.camelize(), graphql_type}
|
||||
end
|
||||
|
||||
|
@ -305,23 +294,13 @@ defmodule AshGraphql do
|
|||
resource
|
||||
|> AshGraphql.Resource.global_unions()
|
||||
|> Enum.flat_map(fn {type, attribute} ->
|
||||
type_name =
|
||||
if function_exported?(type, :graphql_type, 0) do
|
||||
type.graphql_type()
|
||||
else
|
||||
type.graphql_type(attribute.constraints)
|
||||
end
|
||||
type_name = type.graphql_type(attribute.constraints)
|
||||
|
||||
input_type_name =
|
||||
cond do
|
||||
function_exported?(type, :graphql_input_type, 0) ->
|
||||
type.graphql_input_type()
|
||||
|
||||
function_exported?(type, :graphql_input_type, 1) ->
|
||||
type.graphql_input_type(attribute.constraints)
|
||||
|
||||
true ->
|
||||
"#{type_name}_input"
|
||||
if function_exported?(type, :graphql_input_type, 1) do
|
||||
type.graphql_input_type(attribute.constraints)
|
||||
else
|
||||
"#{type_name}_input"
|
||||
end
|
||||
|
||||
AshGraphql.Resource.union_type_definitions(
|
||||
|
@ -580,8 +559,7 @@ defmodule AshGraphql do
|
|||
defp union_type(type) do
|
||||
if Ash.Type.NewType.new_type?(type) &&
|
||||
Ash.Type.NewType.subtype_of(type) == Ash.Type.Union &&
|
||||
(function_exported?(type, :graphql_type, 0) ||
|
||||
function_exported?(type, :graphql_type, 1)) do
|
||||
function_exported?(type, :graphql_type, 1) do
|
||||
type
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1991,15 +1991,8 @@ defmodule AshGraphql.Graphql.Resolver do
|
|||
case original_type do
|
||||
{type, constraints} ->
|
||||
configured_type_name =
|
||||
cond do
|
||||
function_exported?(type, :graphql_type, 0) ->
|
||||
type.graphql_type()
|
||||
|
||||
function_exported?(type, :graphql_type, 1) ->
|
||||
type.graphql_type(constraints)
|
||||
|
||||
true ->
|
||||
nil
|
||||
if function_exported?(type, :graphql_type, 1) do
|
||||
type.graphql_type(constraints)
|
||||
end
|
||||
|
||||
unnested_unions =
|
||||
|
@ -2026,8 +2019,7 @@ defmodule AshGraphql.Graphql.Resolver do
|
|||
config[:type],
|
||||
%Ash.Resource.Attribute{
|
||||
name:
|
||||
configured_type_name ||
|
||||
AshGraphql.Resource.atom_enum_type(resource, field_name),
|
||||
configured_type_name,
|
||||
type: config[:type],
|
||||
constraints: config[:constraints]
|
||||
},
|
||||
|
|
|
@ -1710,14 +1710,12 @@ defmodule AshGraphql.Resource do
|
|||
List.wrap(keyset_page_of(resource, schema)) ++
|
||||
map_definitions(resource, schema, __ENV__) ++
|
||||
enum_definitions(resource, schema, __ENV__) ++
|
||||
union_definitions(resource, schema, __ENV__) ++
|
||||
managed_relationship_definitions(resource, schema)
|
||||
end
|
||||
|
||||
def no_graphql_types(resource, schema) do
|
||||
map_definitions(resource, schema, __ENV__) ++
|
||||
enum_definitions(resource, schema, __ENV__, true) ++
|
||||
union_definitions(resource, schema, __ENV__) ++
|
||||
enum_definitions(resource, schema, __ENV__) ++
|
||||
managed_relationship_definitions(resource, schema)
|
||||
end
|
||||
|
||||
|
@ -2774,48 +2772,18 @@ defmodule AshGraphql.Resource do
|
|||
def map_definitions(resource, schema, env) do
|
||||
if AshGraphql.Resource.Info.type(resource) do
|
||||
resource
|
||||
|> get_auto_maps()
|
||||
|> global_maps()
|
||||
|> Enum.flat_map(fn attribute ->
|
||||
constraints = Ash.Type.NewType.constraints(attribute.type, attribute.constraints)
|
||||
|
||||
type_name =
|
||||
if constraints[:fields] do
|
||||
if Ash.Type.NewType.new_type?(attribute.type) do
|
||||
cond do
|
||||
function_exported?(attribute.type, :graphql_type, 0) ->
|
||||
attribute.type.graphql_type()
|
||||
|
||||
function_exported?(attribute.type, :graphql_type, 1) ->
|
||||
attribute.type.graphql_type(attribute.constraints)
|
||||
|
||||
true ->
|
||||
map_type(resource, attribute.name)
|
||||
end
|
||||
else
|
||||
map_type(resource, attribute.name)
|
||||
end
|
||||
else
|
||||
nil
|
||||
if function_exported?(attribute.type, :graphql_type, 1) do
|
||||
attribute.type.graphql_type(attribute.constraints)
|
||||
end
|
||||
|
||||
input_type_name =
|
||||
if constraints[:fields] do
|
||||
if Ash.Type.NewType.new_type?(attribute.type) do
|
||||
cond do
|
||||
function_exported?(attribute.type, :graphql_input_type, 0) ->
|
||||
attribute.type.graphql_input_type()
|
||||
|
||||
function_exported?(attribute.type, :graphql_input_type, 1) ->
|
||||
attribute.type.graphql_input_type(attribute.constraints)
|
||||
|
||||
true ->
|
||||
map_type(resource, attribute.name, true)
|
||||
end
|
||||
else
|
||||
map_type(resource, attribute.name, true)
|
||||
end
|
||||
else
|
||||
nil
|
||||
if function_exported?(attribute.type, :graphql_input_type, 1) do
|
||||
attribute.type.graphql_input_type(attribute.constraints)
|
||||
end
|
||||
|
||||
[
|
||||
|
@ -3049,115 +3017,30 @@ defmodule AshGraphql.Resource do
|
|||
end)
|
||||
end
|
||||
|
||||
def enum_definitions(resource, schema, env, only_auto? \\ false) do
|
||||
def enum_definitions(resource, schema, env) do
|
||||
resource = Ash.Type.NewType.subtype_of(resource)
|
||||
|
||||
if AshGraphql.Resource.Info.type(resource) do
|
||||
atom_enums =
|
||||
resource
|
||||
|> get_auto_enums()
|
||||
|> Enum.flat_map(fn attribute ->
|
||||
constraints = Ash.Type.NewType.constraints(attribute.type, attribute.constraints)
|
||||
if AshGraphql.Resource.Info.type(resource) && AshGraphql.Resource.Info.derive_sort?(resource) do
|
||||
sort_values = sort_values(resource)
|
||||
|
||||
type_name =
|
||||
if constraints[:one_of] do
|
||||
if Ash.Type.NewType.new_type?(attribute.type) do
|
||||
cond do
|
||||
function_exported?(attribute.type, :graphql_type, 0) ->
|
||||
attribute.type.graphql_type()
|
||||
|
||||
function_exported?(attribute.type, :graphql_type, 1) ->
|
||||
attribute.type.graphql_type(attribute.constraints)
|
||||
|
||||
true ->
|
||||
atom_enum_type(resource, attribute.name)
|
||||
end
|
||||
else
|
||||
atom_enum_type(resource, attribute.name)
|
||||
end
|
||||
end
|
||||
|
||||
additional_type_name =
|
||||
if constraints[:one_of] && Ash.Type.NewType.new_type?(attribute.type) do
|
||||
cond do
|
||||
function_exported?(attribute.type, :graphql_input_type, 0) ->
|
||||
attribute.type.graphql_input_type()
|
||||
|
||||
function_exported?(attribute.type, :graphql_input_type, 1) ->
|
||||
attribute.type.graphql_input_type(attribute.constraints)
|
||||
|
||||
true ->
|
||||
atom_enum_type(resource, attribute.name)
|
||||
end
|
||||
else
|
||||
nil
|
||||
end
|
||||
|
||||
[
|
||||
type_name,
|
||||
additional_type_name
|
||||
]
|
||||
|> Enum.filter(& &1)
|
||||
|> Enum.map(fn type_name ->
|
||||
%Absinthe.Blueprint.Schema.EnumTypeDefinition{
|
||||
sort_order = %Absinthe.Blueprint.Schema.EnumTypeDefinition{
|
||||
module: schema,
|
||||
name: resource |> resource_sort_field_type() |> to_string() |> Macro.camelize(),
|
||||
identifier: resource_sort_field_type(resource),
|
||||
__reference__: ref(__ENV__),
|
||||
values:
|
||||
Enum.map(sort_values, fn {sort_value_alias, sort_value} ->
|
||||
%Absinthe.Blueprint.Schema.EnumValueDefinition{
|
||||
module: schema,
|
||||
name: type_name |> to_string() |> Macro.camelize(),
|
||||
values:
|
||||
Enum.map(constraints[:one_of], fn value ->
|
||||
%Absinthe.Blueprint.Schema.EnumValueDefinition{
|
||||
module: schema,
|
||||
identifier: value,
|
||||
__reference__: AshGraphql.Resource.ref(env),
|
||||
name: String.upcase(to_string(value)),
|
||||
value: value
|
||||
}
|
||||
end),
|
||||
identifier: type_name,
|
||||
__reference__: ref(__ENV__)
|
||||
identifier: sort_value_alias,
|
||||
__reference__: AshGraphql.Resource.ref(env),
|
||||
name: String.upcase(to_string(sort_value_alias)),
|
||||
value: sort_value
|
||||
}
|
||||
end)
|
||||
end)
|
||||
}
|
||||
|
||||
if only_auto? || !AshGraphql.Resource.Info.derive_sort?(resource) do
|
||||
atom_enums
|
||||
else
|
||||
sort_values = sort_values(resource)
|
||||
|
||||
sort_order = %Absinthe.Blueprint.Schema.EnumTypeDefinition{
|
||||
module: schema,
|
||||
name: resource |> resource_sort_field_type() |> to_string() |> Macro.camelize(),
|
||||
identifier: resource_sort_field_type(resource),
|
||||
__reference__: ref(__ENV__),
|
||||
values:
|
||||
Enum.map(sort_values, fn {sort_value_alias, sort_value} ->
|
||||
%Absinthe.Blueprint.Schema.EnumValueDefinition{
|
||||
module: schema,
|
||||
identifier: sort_value_alias,
|
||||
__reference__: AshGraphql.Resource.ref(env),
|
||||
name: String.upcase(to_string(sort_value_alias)),
|
||||
value: sort_value
|
||||
}
|
||||
end)
|
||||
}
|
||||
|
||||
[sort_order | atom_enums]
|
||||
end
|
||||
else
|
||||
[]
|
||||
end
|
||||
end
|
||||
|
||||
# sobelow_skip ["RCE.CodeModule", "DOS.BinToAtom", "DOS.StringToAtom"]
|
||||
def union_definitions(resource, schema, env) do
|
||||
if AshGraphql.Resource.Info.type(resource) do
|
||||
resource
|
||||
|> get_auto_unions()
|
||||
|> Enum.flat_map(fn attribute ->
|
||||
type_name = atom_enum_type(resource, attribute.name)
|
||||
input_type_name = "#{atom_enum_type(resource, attribute.name)}_input"
|
||||
|
||||
union_type_definitions(resource, attribute, type_name, schema, env, input_type_name)
|
||||
end)
|
||||
[sort_order]
|
||||
else
|
||||
[]
|
||||
end
|
||||
|
@ -3292,7 +3175,7 @@ defmodule AshGraphql.Resource do
|
|||
end
|
||||
|
||||
@doc false
|
||||
def get_auto_maps(resource) do
|
||||
def global_maps(resource) do
|
||||
resource
|
||||
|> AshGraphql.all_attributes_and_arguments([], false)
|
||||
|> Enum.map(&unnest/1)
|
||||
|
@ -3300,35 +3183,12 @@ defmodule AshGraphql.Resource do
|
|||
|> Enum.uniq_by(& &1.name)
|
||||
end
|
||||
|
||||
@doc false
|
||||
def get_auto_enums(resource) do
|
||||
resource
|
||||
|> AshGraphql.all_attributes_and_arguments([], false)
|
||||
|> Enum.map(&unnest/1)
|
||||
|> Enum.filter(&(Ash.Type.NewType.subtype_of(&1.type) == Ash.Type.Atom))
|
||||
|> Enum.uniq_by(& &1.name)
|
||||
end
|
||||
|
||||
defp unnest(%{type: {:array, type}, constraints: constraints} = attribute) do
|
||||
unnest(%{attribute | type: type, constraints: constraints[:items] || []})
|
||||
end
|
||||
|
||||
defp unnest(other), do: other
|
||||
|
||||
@doc false
|
||||
def get_auto_unions(resource) do
|
||||
resource
|
||||
|> AshGraphql.all_attributes_and_arguments()
|
||||
|> Enum.map(fn attribute ->
|
||||
unnest(attribute)
|
||||
end)
|
||||
|> Enum.reject(fn attribute ->
|
||||
function_exported?(attribute.type, :graphql_type, 0) ||
|
||||
function_exported?(attribute.type, :graphql_type, 1)
|
||||
end)
|
||||
|> Enum.filter(&(Ash.Type.NewType.subtype_of(&1.type) == Ash.Type.Union))
|
||||
end
|
||||
|
||||
@doc false
|
||||
def global_unions(resource) do
|
||||
resource
|
||||
|
@ -4201,15 +4061,10 @@ defmodule AshGraphql.Resource do
|
|||
end
|
||||
else
|
||||
if Spark.implements_behaviour?(type, Ash.Type.Enum) do
|
||||
cond do
|
||||
function_exported?(type, :graphql_type, 0) ->
|
||||
type.graphql_type()
|
||||
|
||||
function_exported?(type, :graphql_type, 1) ->
|
||||
type.graphql_type(attribute.constraints)
|
||||
|
||||
true ->
|
||||
:string
|
||||
if function_exported?(type, :graphql_type, 1) do
|
||||
type.graphql_type(attribute.constraints)
|
||||
else
|
||||
:string
|
||||
end
|
||||
else
|
||||
function =
|
||||
|
@ -4223,18 +4078,10 @@ defmodule AshGraphql.Resource do
|
|||
function_exported?(type, function, 1) ->
|
||||
apply(type, function, [constraints])
|
||||
|
||||
function_exported?(type, function, 0) ->
|
||||
apply(type, function, [])
|
||||
|
||||
input? && Ash.Type.NewType.new_type?(type) &&
|
||||
Ash.Type.NewType.subtype_of(type) == Ash.Type.Union &&
|
||||
(function_exported?(type, :graphql_type, 0) ||
|
||||
function_exported?(type, :graphql_type, 1)) ->
|
||||
if function_exported?(type, :graphql_type, 0) do
|
||||
:"#{type.graphql_type()}_input"
|
||||
else
|
||||
:"#{type.graphql_type(constraints)}_input"
|
||||
end
|
||||
function_exported?(type, :graphql_type, 1) ->
|
||||
:"#{type.graphql_type(constraints)}_input"
|
||||
|
||||
true ->
|
||||
if Ash.Type.NewType.new_type?(type) do
|
||||
|
@ -4266,58 +4113,24 @@ defmodule AshGraphql.Resource do
|
|||
|
||||
defp get_specific_field_type(
|
||||
Ash.Type.Atom,
|
||||
%{constraints: constraints, name: name},
|
||||
resource,
|
||||
_,
|
||||
_resource,
|
||||
_input?
|
||||
)
|
||||
when not is_nil(resource) do
|
||||
if is_list(constraints[:one_of]) && AshGraphql.Resource.Info.type(resource) do
|
||||
atom_enum_type(resource, name)
|
||||
else
|
||||
:string
|
||||
end
|
||||
end
|
||||
|
||||
# sobelow_skip ["DOS.BinToAtom"]
|
||||
defp get_specific_field_type(
|
||||
Ash.Type.Union,
|
||||
%{name: name},
|
||||
resource,
|
||||
input?
|
||||
)
|
||||
when not is_nil(resource) do
|
||||
# same logic for naming a union currently
|
||||
base_type_name = atom_enum_type(resource, name)
|
||||
|
||||
if input? do
|
||||
:"#{base_type_name}_input"
|
||||
else
|
||||
base_type_name
|
||||
end
|
||||
) do
|
||||
:string
|
||||
end
|
||||
|
||||
defp get_specific_field_type(
|
||||
Ash.Type.Map,
|
||||
%{constraints: constraints, name: name},
|
||||
resource,
|
||||
input?
|
||||
_attribute,
|
||||
_resource,
|
||||
_input?
|
||||
) do
|
||||
if is_list(constraints[:fields]) do
|
||||
map_type(resource, name, input?)
|
||||
else
|
||||
Application.get_env(:ash_graphql, :json_type) || :json_string
|
||||
end
|
||||
Application.get_env(:ash_graphql, :json_type) || :json_string
|
||||
end
|
||||
|
||||
defp get_specific_field_type(Ash.Type.Map, _, _, _),
|
||||
do: Application.get_env(:ash_graphql, :json_type) || :json_string
|
||||
|
||||
defp get_specific_field_type(Ash.Type.Boolean, _, _, _), do: :boolean
|
||||
|
||||
defp get_specific_field_type(Ash.Type.Atom, _, _, _) do
|
||||
:string
|
||||
end
|
||||
|
||||
defp get_specific_field_type(Ash.Type.CiString, _, _, _), do: :string
|
||||
defp get_specific_field_type(Ash.Type.Date, _, _, _), do: :date
|
||||
defp get_specific_field_type(Ash.Type.Decimal, _, _, _), do: :decimal
|
||||
|
@ -4328,13 +4141,13 @@ defmodule AshGraphql.Resource do
|
|||
defp get_specific_field_type(Ash.Type.Term, _, _, _), do: :string
|
||||
|
||||
defp get_specific_field_type(Ash.Type.DateTime, _, _, _),
|
||||
do: Application.get_env(:ash, :utc_datetime_type) || raise_datetime_error()
|
||||
do: Application.get_env(:ash, :utc_datetime_type) || :datetime
|
||||
|
||||
defp get_specific_field_type(Ash.Type.UtcDatetime, _, _, _),
|
||||
do: Application.get_env(:ash, :utc_datetime_type) || raise_datetime_error()
|
||||
do: Application.get_env(:ash, :utc_datetime_type) || :datetime
|
||||
|
||||
defp get_specific_field_type(Ash.Type.UtcDatetimeUsec, _, _, _),
|
||||
do: Application.get_env(:ash, :utc_datetime_type) || raise_datetime_error()
|
||||
do: Application.get_env(:ash, :utc_datetime_type) || :datetime
|
||||
|
||||
defp get_specific_field_type(Ash.Type.NaiveDatetime, _, _, _), do: :naive_datetime
|
||||
defp get_specific_field_type(Ash.Type.Time, _, _, _), do: :time
|
||||
|
@ -4356,67 +4169,19 @@ defmodule AshGraphql.Resource do
|
|||
raise """
|
||||
Could not determine graphql field type for #{inspect(type)} on #{inspect(resource)}.#{attribute.name}
|
||||
|
||||
If this is a custom type, you can add `def graphql_type/1` to your type to define the graphql type.
|
||||
If this is not your type, you will need to use `types` or `attribute_types` or `attribute_input_types`
|
||||
to configure the type for any field using this type. If this is an `Ash.Type.NewType`, you may need to define
|
||||
`graphql_type` and `graphql_input_type`s for it.
|
||||
If this is an `Ash.Type.Enum` or a custom type, you can add `def graphql_type/1` or `def graphql_input_type/1`
|
||||
to your type. This does not *define* the type, but tells us what type to use for it, so you may need
|
||||
to add a type to your absinthe schema if it does not map to a built in absinthe data type.
|
||||
|
||||
## Ash.Type.NewType
|
||||
|
||||
The exception to the above are special instances of `Ash.Type.NewType`. If you have an `Ash.Type.NewType`,
|
||||
that is a subset of `:union` or `:map`(with the `:fields` constraint), AshGraphql will define that type for you.
|
||||
If you are seeing this message, it likely means that you are missing `def graphql_type/1` or `def graphql_input_type/1`
|
||||
on your type definition.
|
||||
"""
|
||||
end
|
||||
|
||||
defp raise_datetime_error do
|
||||
raise """
|
||||
No type configured for utc_datetimes!
|
||||
|
||||
The existing default of using `:naive_datetime` for `:utc_datetime` and `:utc_datetime_usec` is being deprecated.
|
||||
|
||||
To prevent accidental API breakages, we are requiring that you configure your selected type for these, via
|
||||
|
||||
# This was the previous default, so use this if you want to ensure no unintended
|
||||
# change in your API, although switching to `:datetime` eventually is suggested.
|
||||
config :ash, :utc_datetime_type, :naive_datetime
|
||||
|
||||
or
|
||||
|
||||
config :ash, :utc_datetime_type, :datetime
|
||||
|
||||
When the 1.0 version of ash_graphql is released, the default will be changed to `:datetime`, and this error message will
|
||||
no longer be shown (but any configuration set will be retained indefinitely).
|
||||
"""
|
||||
end
|
||||
|
||||
# sobelow_skip ["DOS.StringToAtom"]
|
||||
@doc false
|
||||
def atom_enum_type(resource, attribute_name) do
|
||||
field_names = AshGraphql.Resource.Info.field_names(resource)
|
||||
|
||||
resource
|
||||
|> AshGraphql.Resource.Info.type()
|
||||
|> to_string()
|
||||
|> Kernel.<>("_")
|
||||
|> Kernel.<>(to_string(field_names[attribute_name] || attribute_name))
|
||||
|> String.to_atom()
|
||||
end
|
||||
|
||||
# sobelow_skip ["DOS.StringToAtom", "DOS.BinToAtom"]
|
||||
@doc false
|
||||
def map_type(resource, attribute_name, input? \\ false) do
|
||||
field_names = AshGraphql.Resource.Info.field_names(resource)
|
||||
|
||||
name =
|
||||
resource
|
||||
|> AshGraphql.Resource.Info.type()
|
||||
|> to_string()
|
||||
|> Kernel.<>("_")
|
||||
|> Kernel.<>(to_string(field_names[attribute_name] || attribute_name))
|
||||
|> String.to_atom()
|
||||
|
||||
if input? do
|
||||
:"#{name}_input"
|
||||
else
|
||||
name
|
||||
end
|
||||
end
|
||||
|
||||
def primary_key_get_query(resource) do
|
||||
# Find the get query with no identities, i.e. the one that uses the primary key
|
||||
resource
|
||||
|
|
|
@ -42,204 +42,6 @@ defmodule AshGraphql.AttributeTest do
|
|||
assert author_id_field["type"]["name"] == "ID"
|
||||
end
|
||||
|
||||
test "atom attribute with one_of constraints has enums automatically generated" do
|
||||
{:ok, %{data: data}} =
|
||||
"""
|
||||
query {
|
||||
__type(name: "PostVisibility") {
|
||||
enumValues {
|
||||
name
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
|> Absinthe.run(AshGraphql.Test.Schema)
|
||||
|
||||
assert data["__type"]
|
||||
end
|
||||
|
||||
test "atom attribute with one_of constraints uses enum for inputs" do
|
||||
{:ok, %{data: data}} =
|
||||
"""
|
||||
query {
|
||||
__type(name: "CreatePostInput") {
|
||||
inputFields {
|
||||
name
|
||||
type {
|
||||
kind
|
||||
name
|
||||
ofType {
|
||||
kind
|
||||
name
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
|> Absinthe.run(AshGraphql.Test.Schema)
|
||||
|
||||
visibility_field =
|
||||
data["__type"]["inputFields"]
|
||||
|> Enum.find(fn field -> field["name"] == "visibility" end)
|
||||
|
||||
assert visibility_field["type"]["kind"] == "ENUM"
|
||||
end
|
||||
|
||||
test "map attribute with field constraints get their own type" do
|
||||
{:ok, %{data: data}} =
|
||||
"""
|
||||
query {
|
||||
__type(name: "MapTypes") {
|
||||
fields {
|
||||
name
|
||||
type {
|
||||
kind
|
||||
name
|
||||
ofType {
|
||||
kind
|
||||
name
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
|> Absinthe.run(AshGraphql.Test.Schema)
|
||||
|
||||
fields = data["__type"]["fields"]
|
||||
|
||||
attributes_field =
|
||||
fields
|
||||
|> Enum.find(fn field -> field["name"] == "attributes" end)
|
||||
|
||||
values_field =
|
||||
fields
|
||||
|> Enum.find(fn field -> field["name"] == "values" end)
|
||||
|
||||
assert attributes_field == %{
|
||||
"name" => "attributes",
|
||||
"type" => %{
|
||||
"kind" => "NON_NULL",
|
||||
"name" => nil,
|
||||
"ofType" => %{"kind" => "OBJECT", "name" => "MapTypesAttributes"}
|
||||
}
|
||||
}
|
||||
|
||||
assert values_field == %{
|
||||
"name" => "values",
|
||||
"type" => %{"kind" => "OBJECT", "name" => "ConstrainedMap", "ofType" => nil}
|
||||
}
|
||||
end
|
||||
|
||||
test "map attribute with field constraints use input objects for inputs" do
|
||||
{:ok, %{data: data}} =
|
||||
"""
|
||||
query {
|
||||
__type(name: "MapTypesAttributesInput") {
|
||||
inputFields {
|
||||
name
|
||||
type {
|
||||
kind
|
||||
name
|
||||
ofType {
|
||||
kind
|
||||
name
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
|> Absinthe.run(AshGraphql.Test.Schema)
|
||||
|
||||
foo_field =
|
||||
data["__type"]["inputFields"]
|
||||
|> Enum.find(fn field -> field["name"] == "foo" end)
|
||||
|
||||
# non null field
|
||||
assert foo_field["type"]["kind"] == "NON_NULL"
|
||||
|
||||
assert foo_field["type"]["ofType"]["kind"] == "SCALAR"
|
||||
assert foo_field["type"]["ofType"]["name"] == "String"
|
||||
|
||||
bar_field =
|
||||
data["__type"]["inputFields"]
|
||||
|> Enum.find(fn field -> field["name"] == "bar" end)
|
||||
|
||||
assert bar_field["type"]["kind"] == "SCALAR"
|
||||
assert bar_field["type"]["name"] == "Int"
|
||||
|
||||
baz_field =
|
||||
data["__type"]["inputFields"]
|
||||
|> Enum.find(fn field -> field["name"] == "baz" end)
|
||||
|
||||
assert baz_field["type"]["kind"] == "SCALAR"
|
||||
assert baz_field["type"]["name"] == "JsonString"
|
||||
end
|
||||
|
||||
test "map arguments with constraints create an input object" do
|
||||
assert {:ok,
|
||||
%{
|
||||
data: %{
|
||||
"__type" => %{
|
||||
"inputFields" => [
|
||||
%{
|
||||
"name" => "attributes",
|
||||
"type" => %{
|
||||
"kind" => "INPUT_OBJECT",
|
||||
"name" => "MapTypesAttributesInput",
|
||||
"ofType" => nil
|
||||
}
|
||||
},
|
||||
%{
|
||||
"name" => "inlineValues",
|
||||
"type" => %{
|
||||
"kind" => "INPUT_OBJECT",
|
||||
"name" => "MapTypesInlineValuesInput",
|
||||
"ofType" => nil
|
||||
}
|
||||
},
|
||||
%{
|
||||
"name" => "jsonMap",
|
||||
"type" => %{
|
||||
"kind" => "SCALAR",
|
||||
"name" => "JsonString",
|
||||
"ofType" => nil
|
||||
}
|
||||
},
|
||||
%{
|
||||
"name" => "values",
|
||||
"type" => %{
|
||||
"kind" => "INPUT_OBJECT",
|
||||
"name" => "ConstrainedMapInput",
|
||||
"ofType" => nil
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}} =
|
||||
"""
|
||||
query {
|
||||
__type(name: "InlineUpdateMapTypesInput") {
|
||||
inputFields {
|
||||
name
|
||||
type {
|
||||
kind
|
||||
name
|
||||
ofType {
|
||||
kind
|
||||
name
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
|> Absinthe.run(AshGraphql.Test.Schema)
|
||||
end
|
||||
|
||||
test "nested maps with constraints create types for nested maps" do
|
||||
assert {:ok,
|
||||
%{
|
||||
|
@ -337,62 +139,4 @@ defmodule AshGraphql.AttributeTest do
|
|||
"""
|
||||
|> Absinthe.run(AshGraphql.Test.Schema)
|
||||
end
|
||||
|
||||
test "map subtypes with constraints used as arguments use the subtype input object" do
|
||||
assert {:ok,
|
||||
%{
|
||||
data: %{
|
||||
"__type" => %{
|
||||
"inputFields" => [
|
||||
%{
|
||||
"name" => "attributes",
|
||||
"type" => %{
|
||||
"kind" => "INPUT_OBJECT",
|
||||
"name" => "MapTypesAttributesInput",
|
||||
"ofType" => nil
|
||||
}
|
||||
},
|
||||
%{
|
||||
"name" => "jsonMap",
|
||||
"type" => %{"kind" => "SCALAR", "name" => "JsonString", "ofType" => nil}
|
||||
},
|
||||
%{
|
||||
"name" => "moduleValues",
|
||||
"type" => %{
|
||||
"kind" => "INPUT_OBJECT",
|
||||
"name" => "ConstrainedMapInput",
|
||||
"ofType" => nil
|
||||
}
|
||||
},
|
||||
%{
|
||||
"name" => "values",
|
||||
"type" => %{
|
||||
"kind" => "INPUT_OBJECT",
|
||||
"name" => "ConstrainedMapInput",
|
||||
"ofType" => nil
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}} =
|
||||
"""
|
||||
query {
|
||||
__type(name: "ModuleUpdateMapTypesInput") {
|
||||
inputFields {
|
||||
name
|
||||
type {
|
||||
kind
|
||||
name
|
||||
ofType {
|
||||
kind
|
||||
name
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
|> Absinthe.run(AshGraphql.Test.Schema)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -104,10 +104,10 @@ defmodule AshGraphql.CreateTest do
|
|||
result{
|
||||
text1
|
||||
simpleUnion {
|
||||
... on PostSimpleUnionString {
|
||||
... on SimpleUnionString {
|
||||
value
|
||||
}
|
||||
... on PostSimpleUnionInt {
|
||||
... on SimpleUnionInt {
|
||||
value
|
||||
}
|
||||
}
|
||||
|
@ -153,13 +153,13 @@ defmodule AshGraphql.CreateTest do
|
|||
simpleCreatePost(input: $input) {
|
||||
result{
|
||||
text1
|
||||
embedUnion {
|
||||
... on PostEmbedUnionFoo {
|
||||
embedUnionNewType {
|
||||
... on EmbedUnionNewTypeFoo {
|
||||
value {
|
||||
foo
|
||||
}
|
||||
}
|
||||
... on PostEmbedUnionBar {
|
||||
... on EmbedUnionNewTypeBar {
|
||||
value {
|
||||
bar
|
||||
}
|
||||
|
@ -176,7 +176,7 @@ defmodule AshGraphql.CreateTest do
|
|||
variables: %{
|
||||
"input" => %{
|
||||
"text1" => "foo",
|
||||
"embedUnion" => %{
|
||||
"embedUnionNewType" => %{
|
||||
"foo" => %{
|
||||
"foo" => "10"
|
||||
}
|
||||
|
@ -193,7 +193,7 @@ defmodule AshGraphql.CreateTest do
|
|||
data: %{
|
||||
"simpleCreatePost" => %{
|
||||
"result" => %{
|
||||
"embedUnion" => %{
|
||||
"embedUnionNewType" => %{
|
||||
"value" => %{
|
||||
"foo" => "10"
|
||||
}
|
||||
|
@ -212,12 +212,12 @@ defmodule AshGraphql.CreateTest do
|
|||
result{
|
||||
text1
|
||||
embedUnionNewType {
|
||||
... on FooBarFoo {
|
||||
... on EmbedUnionNewTypeFoo {
|
||||
value {
|
||||
foo
|
||||
}
|
||||
}
|
||||
... on FooBarBar {
|
||||
... on EmbedUnionNewTypeBar {
|
||||
value {
|
||||
bar
|
||||
}
|
||||
|
@ -718,44 +718,6 @@ defmodule AshGraphql.CreateTest do
|
|||
} = result
|
||||
end
|
||||
|
||||
test "enum newtypes can be written to" do
|
||||
resp =
|
||||
"""
|
||||
mutation CreatePost($input: CreatePostInput) {
|
||||
createPost(input: $input) {
|
||||
result{
|
||||
text
|
||||
enumNewType
|
||||
}
|
||||
errors{
|
||||
message
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
|> Absinthe.run(AshGraphql.Test.Schema,
|
||||
variables: %{
|
||||
"input" => %{
|
||||
"text" => "foobar",
|
||||
"confirmation" => "foobar",
|
||||
"enumNewType" => "BIZ"
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
assert {:ok, result} = resp
|
||||
|
||||
refute Map.has_key?(result, :errors)
|
||||
|
||||
assert %{
|
||||
data: %{
|
||||
"createPost" => %{
|
||||
"result" => %{"text" => "foobar", "enumNewType" => "BIZ"}
|
||||
}
|
||||
}
|
||||
} = result
|
||||
end
|
||||
|
||||
test "string newtypes can be written to" do
|
||||
resp =
|
||||
"""
|
||||
|
|
|
@ -53,10 +53,10 @@ defmodule AshGraphql.ReadTest do
|
|||
postLibrary {
|
||||
text
|
||||
simpleUnion {
|
||||
... on PostSimpleUnionString {
|
||||
... on SimpleUnionString {
|
||||
value
|
||||
}
|
||||
... on PostSimpleUnionInt {
|
||||
... on SimpleUnionInt {
|
||||
value
|
||||
}
|
||||
}
|
||||
|
@ -886,7 +886,7 @@ defmodule AshGraphql.ReadTest do
|
|||
AshGraphql.Test.Post
|
||||
|> Ash.Changeset.for_create(:create,
|
||||
text: "a",
|
||||
embed_union: %{type: :foo, foo: "fred"},
|
||||
embed_union_new_type: %{type: :foo, foo: "fred"},
|
||||
published: true
|
||||
)
|
||||
|> Ash.create!()
|
||||
|
@ -894,7 +894,7 @@ defmodule AshGraphql.ReadTest do
|
|||
AshGraphql.Test.Post
|
||||
|> Ash.Changeset.for_create(:create,
|
||||
text: "b",
|
||||
embed_union: %{type: :bar, bar: "george"},
|
||||
embed_union_new_type: %{type: :bar, bar: "george"},
|
||||
published: true
|
||||
)
|
||||
|> Ash.create!()
|
||||
|
@ -903,13 +903,13 @@ defmodule AshGraphql.ReadTest do
|
|||
"""
|
||||
query postLibrary {
|
||||
postLibrary(sort: {field: TEXT}) {
|
||||
embedUnion{
|
||||
...on PostEmbedUnionFoo {
|
||||
embedUnionNewType{
|
||||
...on EmbedUnionNewTypeFoo {
|
||||
value {
|
||||
alwaysNil
|
||||
}
|
||||
}
|
||||
...on PostEmbedUnionBar {
|
||||
...on EmbedUnionNewTypeBar {
|
||||
value {
|
||||
alwaysFalse
|
||||
}
|
||||
|
@ -928,14 +928,14 @@ defmodule AshGraphql.ReadTest do
|
|||
data: %{
|
||||
"postLibrary" => [
|
||||
%{
|
||||
"embedUnion" => %{
|
||||
"embedUnionNewType" => %{
|
||||
"value" => %{
|
||||
"alwaysNil" => nil
|
||||
}
|
||||
}
|
||||
},
|
||||
%{
|
||||
"embedUnion" => %{
|
||||
"embedUnionNewType" => %{
|
||||
"value" => %{
|
||||
"alwaysFalse" => false
|
||||
}
|
||||
|
|
|
@ -24,6 +24,6 @@ defmodule AshGraphql.Test.ConstrainedMap do
|
|||
]
|
||||
]
|
||||
|
||||
def graphql_type, do: :constrained_map
|
||||
def graphql_input_type, do: :constrained_map_input
|
||||
def graphql_type(_), do: :constrained_map
|
||||
def graphql_input_type(_), do: :constrained_map_input
|
||||
end
|
||||
|
|
|
@ -6,5 +6,5 @@ defmodule AshGraphql.Test.DoubleRelType do
|
|||
:second
|
||||
]
|
||||
|
||||
def graphql_type, do: :double_rel_type
|
||||
def graphql_type(_), do: :double_rel_type
|
||||
end
|
||||
|
|
|
@ -8,26 +8,6 @@ defmodule AshGraphql.Test.MapTypes do
|
|||
attributes do
|
||||
uuid_primary_key(:id)
|
||||
|
||||
attribute :attributes, :map do
|
||||
constraints(
|
||||
fields: [
|
||||
foo: [
|
||||
type: :string,
|
||||
allow_nil?: false
|
||||
],
|
||||
bar: [
|
||||
type: :integer
|
||||
],
|
||||
baz: [
|
||||
type: :map
|
||||
]
|
||||
]
|
||||
)
|
||||
|
||||
allow_nil? false
|
||||
public?(true)
|
||||
end
|
||||
|
||||
attribute(:json_map, :map, public?: true)
|
||||
|
||||
attribute :values, AshGraphql.Test.ConstrainedMap do
|
||||
|
@ -40,22 +20,6 @@ defmodule AshGraphql.Test.MapTypes do
|
|||
|
||||
defaults([:create, :read, :update, :destroy])
|
||||
|
||||
update :inline do
|
||||
argument :inline_values, :map do
|
||||
constraints(
|
||||
fields: [
|
||||
foo: [
|
||||
type: :string,
|
||||
allow_nil?: false
|
||||
],
|
||||
bar: [
|
||||
type: :integer
|
||||
]
|
||||
]
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
update :module do
|
||||
argument(:module_values, AshGraphql.Test.ConstrainedMap)
|
||||
end
|
||||
|
@ -69,7 +33,6 @@ defmodule AshGraphql.Test.MapTypes do
|
|||
end
|
||||
|
||||
mutations do
|
||||
update :inline_update_map_types, :inline
|
||||
update :module_update_map_types, :module
|
||||
end
|
||||
end
|
||||
|
|
|
@ -2,5 +2,5 @@ defmodule AshGraphql.Test.NestedEnum do
|
|||
@moduledoc false
|
||||
use Ash.Type.Enum, values: [:foo, :bar]
|
||||
|
||||
def graphql_type, do: :nested_enum
|
||||
def graphql_type(_), do: :nested_enum
|
||||
end
|
||||
|
|
|
@ -346,47 +346,16 @@ defmodule AshGraphql.Test.Post do
|
|||
attribute(:text2, :string, public?: true)
|
||||
attribute(:visibility, :atom, constraints: [one_of: [:public, :private]], public?: true)
|
||||
|
||||
attribute(:simple_union, :union,
|
||||
constraints: [
|
||||
types: [
|
||||
int: [
|
||||
type: :integer
|
||||
],
|
||||
string: [
|
||||
type: :string
|
||||
]
|
||||
]
|
||||
],
|
||||
public?: true
|
||||
)
|
||||
attribute(:simple_union, AshGraphql.Test.Types.SimpleUnion, public?: true)
|
||||
|
||||
attribute(:embed_foo, Foo, public?: true)
|
||||
|
||||
attribute(:embed_union, :union,
|
||||
constraints: [
|
||||
types: [
|
||||
foo: [
|
||||
type: Foo,
|
||||
tag: :type,
|
||||
tag_value: :foo
|
||||
],
|
||||
bar: [
|
||||
type: Bar,
|
||||
tag: :type,
|
||||
tag_value: :bar
|
||||
]
|
||||
]
|
||||
],
|
||||
public?: true
|
||||
)
|
||||
|
||||
attribute(:embed_union_new_type_list, {:array, AshGraphql.Types.EmbedUnionNewTypeUnnested},
|
||||
public?: true
|
||||
)
|
||||
|
||||
attribute(:embed_union_new_type, AshGraphql.Types.EmbedUnionNewType, public?: true)
|
||||
attribute(:embed_union_unnested, AshGraphql.Types.EmbedUnionNewTypeUnnested, public?: true)
|
||||
attribute(:enum_new_type, AshGraphql.Types.EnumNewType, public?: true)
|
||||
attribute(:string_new_type, AshGraphql.Types.StringNewType, public?: true)
|
||||
|
||||
attribute :required_string, :string do
|
||||
|
|
|
@ -17,5 +17,5 @@ defmodule AshGraphql.Types.EmbedUnionNewType do
|
|||
]
|
||||
]
|
||||
|
||||
def graphql_type, do: :foo_bar
|
||||
def graphql_type(_), do: :embed_union_new_type
|
||||
end
|
||||
|
|
|
@ -17,7 +17,7 @@ defmodule AshGraphql.Types.EmbedUnionNewTypeUnnested do
|
|||
]
|
||||
]
|
||||
|
||||
def graphql_type, do: :foo_bar_unnested
|
||||
def graphql_type(_), do: :foo_bar_unnested
|
||||
|
||||
def graphql_unnested_unions(_), do: [:foo, :bar]
|
||||
end
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
defmodule AshGraphql.Types.EnumNewType do
|
||||
@moduledoc false
|
||||
use Ash.Type.NewType, subtype_of: :atom, constraints: [one_of: [:biz, :buz]]
|
||||
use Ash.Type.Enum, values: [:biz, :buz]
|
||||
|
||||
def graphql_type, do: :biz_buz
|
||||
def graphql_type(_), do: :biz_buz
|
||||
end
|
||||
|
|
|
@ -6,5 +6,5 @@ defmodule AshGraphql.Test.EnumWithAshDescription do
|
|||
buzz: "A buzz"
|
||||
]
|
||||
|
||||
def graphql_type, do: :enum_with_ash_description
|
||||
def graphql_type(_), do: :enum_with_ash_description
|
||||
end
|
||||
|
|
|
@ -7,7 +7,7 @@ defmodule AshGraphql.Test.EnumWithAshGraphqlDescription do
|
|||
no_description: "And also this"
|
||||
]
|
||||
|
||||
def graphql_type, do: :enum_with_ash_graphql_description
|
||||
def graphql_type(_), do: :enum_with_ash_graphql_description
|
||||
|
||||
def graphql_describe_enum_value(:foo), do: "A foo"
|
||||
def graphql_describe_enum_value(:bar), do: "A bar"
|
||||
|
|
18
test/support/types/simple_union.ex
Normal file
18
test/support/types/simple_union.ex
Normal file
|
@ -0,0 +1,18 @@
|
|||
defmodule AshGraphql.Test.Types.SimpleUnion do
|
||||
@moduledoc false
|
||||
use Ash.Type.NewType, subtype_of: :union, constraints: [
|
||||
types: [
|
||||
int: [
|
||||
type: :integer
|
||||
],
|
||||
string: [
|
||||
type: :string
|
||||
]
|
||||
]
|
||||
]
|
||||
|
||||
use AshGraphql.Type
|
||||
|
||||
@impl AshGraphql.Type
|
||||
def graphql_type(_), do: :simple_union
|
||||
end
|
|
@ -2,5 +2,5 @@ defmodule AshGraphql.Test.StatusEnum do
|
|||
@moduledoc false
|
||||
use Ash.Type.Enum, values: [:open, :closed]
|
||||
|
||||
def graphql_type, do: :status_enum
|
||||
def graphql_type(_), do: :status_enum
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue