diff --git a/lib/resource/resource.ex b/lib/resource/resource.ex index 54e953a6..8da301cf 100644 --- a/lib/resource/resource.ex +++ b/lib/resource/resource.ex @@ -610,9 +610,7 @@ defmodule AshGraphql.Resource do module: schema, name: to_string(mutation.name), description: Ash.Resource.Info.action(resource, mutation.action).description, - type: %Absinthe.Blueprint.TypeReference.NonNull{ - of_type: String.to_atom("#{mutation.name}_result") - }, + type: mutation_result_type(mutation.name, api), __reference__: ref(__ENV__) } end @@ -656,9 +654,7 @@ defmodule AshGraphql.Resource do module: schema, name: to_string(mutation.name), description: Ash.Resource.Info.action(resource, mutation.action).description, - type: %Absinthe.Blueprint.TypeReference.NonNull{ - of_type: String.to_atom("#{mutation.name}_result") - }, + type: mutation_result_type(mutation.name, api), __reference__: ref(__ENV__) } @@ -710,13 +706,18 @@ defmodule AshGraphql.Resource do module: schema, name: to_string(mutation.name), description: Ash.Resource.Info.action(resource, mutation.action).description, - type: %Absinthe.Blueprint.TypeReference.NonNull{ - of_type: String.to_atom("#{mutation.name}_result") - }, + type: mutation_result_type(mutation.name, api), __reference__: ref(__ENV__) } end + defp mutation_result_type(mutation_name, api) do + type = String.to_atom("#{mutation_name}_result") + root_level_errors? = AshGraphql.Api.Info.root_level_errors?(api) + + maybe_wrap_non_null(type, not root_level_errors?) + end + defp mutation_args(%{identity: false} = mutation, resource, schema) do mutation_read_args(mutation, resource, schema) end diff --git a/test/errors_test.exs b/test/errors_test.exs index ad97f197..69a8e607 100644 --- a/test/errors_test.exs +++ b/test/errors_test.exs @@ -12,8 +12,6 @@ defmodule AshGraphql.ErrorsTest do end test "errors can be configured to be shown in the root" do - Application.put_env(:ash_graphql, AshGraphql.Test.Api, graphql: [root_level_errors?: true]) - resp = """ mutation CreatePost($input: CreatePostInput) { @@ -27,7 +25,7 @@ defmodule AshGraphql.ErrorsTest do } } """ - |> Absinthe.run(AshGraphql.Test.Schema, + |> Absinthe.run(AshGraphql.Test.RootLevelErrorsSchema, variables: %{ "input" => %{ "text" => "foobar", @@ -38,7 +36,7 @@ defmodule AshGraphql.ErrorsTest do assert {:ok, result} = resp - assert %{data: nil, errors: [%{message: message}]} = result + assert %{data: %{"createPost" => nil}, errors: [%{message: message}]} = result assert message =~ "confirmation did not match value" end @@ -111,8 +109,8 @@ defmodule AshGraphql.ErrorsTest do end test "showing raised errors alongside root errors shows raised errors in the root" do - Application.put_env(:ash_graphql, AshGraphql.Test.Api, - graphql: [show_raised_errors?: true, root_level_errors?: true] + Application.put_env(:ash_graphql, AshGraphql.Test.RootLevelErrorsApi, + graphql: [show_raised_errors?: true] ) resp = @@ -128,7 +126,7 @@ defmodule AshGraphql.ErrorsTest do } } """ - |> Absinthe.run(AshGraphql.Test.Schema, + |> Absinthe.run(AshGraphql.Test.RootLevelErrorsSchema, variables: %{ "input" => %{ "text" => "foobar" @@ -139,7 +137,7 @@ defmodule AshGraphql.ErrorsTest do assert {:ok, result} = resp assert %{ - data: nil, + data: %{"createPostWithError" => nil}, errors: [ %{message: message} ] @@ -415,4 +413,60 @@ defmodule AshGraphql.ErrorsTest do assert fields["type"]["ofType"]["kind"] == "NON_NULL" assert fields["type"]["ofType"]["ofType"]["name"] == "String" end + + test "mutation result is non nullable without root level errors" do + {:ok, %{data: data}} = + """ + query { + __schema { + mutationType { + name + fields { + name + type { + kind + ofType { + name + } + } + } + } + } + } + """ + |> Absinthe.run(AshGraphql.Test.Schema) + + create_post_mutation = + data["__schema"]["mutationType"]["fields"] + |> Enum.find(fn field -> field["name"] == "createPost" end) + + assert create_post_mutation["type"]["kind"] == "NON_NULL" + assert create_post_mutation["type"]["ofType"]["name"] == "CreatePostResult" + end + + test "mutation result is nullable with root level errors" do + {:ok, %{data: data}} = + """ + query { + __schema { + mutationType { + name + fields { + name + type { + name + } + } + } + } + } + """ + |> Absinthe.run(AshGraphql.Test.RootLevelErrorsSchema) + + create_post_mutation = + data["__schema"]["mutationType"]["fields"] + |> Enum.find(fn field -> field["name"] == "createPost" end) + + assert create_post_mutation["type"]["name"] == "CreatePostResult" + end end diff --git a/test/support/root_level_errors_api.ex b/test/support/root_level_errors_api.ex new file mode 100644 index 00000000..1c1cee76 --- /dev/null +++ b/test/support/root_level_errors_api.ex @@ -0,0 +1,17 @@ +defmodule AshGraphql.Test.RootLevelErrorsApi do + @moduledoc false + + use Ash.Api, + extensions: [ + AshGraphql.Api + ], + otp_app: :ash_graphql + + graphql do + root_level_errors? true + end + + resources do + registry(AshGraphql.Test.Registry) + end +end diff --git a/test/support/root_level_errors_schema.ex b/test/support/root_level_errors_schema.ex new file mode 100644 index 00000000..49743250 --- /dev/null +++ b/test/support/root_level_errors_schema.ex @@ -0,0 +1,30 @@ +defmodule AshGraphql.Test.RootLevelErrorsSchema do + @moduledoc false + + use Absinthe.Schema + + @apis [AshGraphql.Test.RootLevelErrorsApi] + + use AshGraphql, apis: @apis + + query do + end + + mutation do + end + + object :foo do + field(:foo, :string) + field(:bar, :string) + end + + input_object :foo_input do + field(:foo, non_null(:string)) + field(:bar, non_null(:string)) + end + + enum :status do + value(:open, description: "The post is open") + value(:closed, description: "The post is closed") + end +end