diff --git a/lib/absinthe/type/built_ins/introspection.ex b/lib/absinthe/type/built_ins/introspection.ex index 15ec76fe1a..61544a13ab 100644 --- a/lib/absinthe/type/built_ins/introspection.ex +++ b/lib/absinthe/type/built_ins/introspection.ex @@ -69,10 +69,17 @@ defmodule Absinthe.Type.BuiltIns.Introspection do field :args, type: non_null(list_of(non_null(:__inputvalue))), - resolve: fn _, %{source: source} -> + args: [ + include_deprecated: [ + type: :boolean, + default_value: false + ] + ], + resolve: fn %{include_deprecated: show_deprecated}, %{source: source} -> args = source.args |> Map.values() + |> filter_deprecated(show_deprecated) |> Enum.sort_by(& &1.identifier) {:ok, args} @@ -108,18 +115,9 @@ defmodule Absinthe.Type.BuiltIns.Introspection do when str in [Absinthe.Type.Object, Absinthe.Type.Interface] -> result = fields - |> Enum.flat_map(fn {_, %{deprecation: is_deprecated} = field} -> - cond do - Absinthe.Type.introspection?(field) -> - [] - - !is_deprecated || (is_deprecated && show_deprecated) -> - [field] - - true -> - [] - end - end) + |> Map.values() + |> filter_deprecated(show_deprecated) + |> Enum.filter(&(!Absinthe.Type.introspection?(&1))) |> Enum.sort_by(& &1.identifier) {:ok, result} @@ -174,13 +172,8 @@ defmodule Absinthe.Type.BuiltIns.Introspection do %{include_deprecated: show_deprecated}, %{source: %Absinthe.Type.Enum{values: values}} -> result = values - |> Enum.flat_map(fn {_, %{deprecation: is_deprecated} = value} -> - if !is_deprecated || (is_deprecated && show_deprecated) do - [value] - else - [] - end - end) + |> Map.values() + |> filter_deprecated(show_deprecated) |> Enum.sort_by(& &1.value) {:ok, result} @@ -191,11 +184,19 @@ defmodule Absinthe.Type.BuiltIns.Introspection do field :input_fields, type: list_of(non_null(:__inputvalue)), + args: [ + include_deprecated: [ + type: :boolean, + default_value: false + ] + ], resolve: fn - _, %{source: %Absinthe.Type.InputObject{fields: fields}} -> + %{include_deprecated: show_deprecated}, + %{source: %Absinthe.Type.InputObject{fields: fields}} -> input_fields = fields |> Map.values() + |> filter_deprecated(show_deprecated) |> Enum.sort_by(& &1.identifier) {:ok, input_fields} @@ -226,10 +227,17 @@ defmodule Absinthe.Type.BuiltIns.Introspection do field :args, type: non_null(list_of(non_null(:__inputvalue))), - resolve: fn _, %{source: %{args: args}} -> + args: [ + include_deprecated: [ + type: :boolean, + default_value: false + ] + ], + resolve: fn %{include_deprecated: show_deprecated}, %{source: %{args: args}} -> args = args |> Map.values() + |> filter_deprecated(show_deprecated) |> Enum.sort_by(& &1.identifier) {:ok, args} @@ -299,6 +307,26 @@ defmodule Absinthe.Type.BuiltIns.Introspection do _, %{source: _} -> {:ok, nil} end + + field :is_deprecated, + type: non_null(:boolean), + resolve: fn + _, %{source: %{deprecation: nil}} -> + {:ok, false} + + _, _ -> + {:ok, true} + end + + field :deprecation_reason, + type: :string, + resolve: fn + _, %{source: %{deprecation: nil}} -> + {:ok, nil} + + _, %{source: %{deprecation: dep}} -> + {:ok, dep.reason} + end end object :__enumvalue, name: "__EnumValue" do @@ -364,4 +392,10 @@ defmodule Absinthe.Type.BuiltIns.Introspection do inspect(Absinthe.Type.Scalar.serialize(sc, value)) end end + + defp filter_deprecated(values, show_deprecated) do + Enum.filter(values, fn %{deprecation: is_deprecated} -> + !is_deprecated || show_deprecated + end) + end end diff --git a/test/absinthe/introspection_test.exs b/test/absinthe/introspection_test.exs index 3575efb9d1..c2e5dd1eba 100644 --- a/test/absinthe/introspection_test.exs +++ b/test/absinthe/introspection_test.exs @@ -278,6 +278,93 @@ defmodule Absinthe.IntrospectionTest do assert !match?({:ok, %{data: %{"__type" => %{"fields" => _}}}}, result) end + test "can include deprecated fields based on an arg" do + result = + """ + { + __type(name: "ProfileInput") { + kind + name + description + inputFields(includeDeprecated: true) { + name + description + type { + kind + name + ofType { + kind + name + } + } + defaultValue + isDeprecated + deprecationReason + } + } + } + """ + |> run(Absinthe.Fixtures.ContactSchema) + + assert_result( + {:ok, + %{ + data: %{ + "__type" => %{ + "description" => "The basic details for a person", + "inputFields" => [ + %{ + "defaultValue" => nil, + "description" => nil, + "name" => "address", + "type" => %{ + "kind" => "SCALAR", + "name" => "String", + "ofType" => nil + }, + "deprecationReason" => "change of privacy policy", + "isDeprecated" => true + }, + %{ + "defaultValue" => "43", + "description" => "The person's age", + "name" => "age", + "type" => %{"kind" => "SCALAR", "name" => "Int", "ofType" => nil}, + "deprecationReason" => nil, + "isDeprecated" => false + }, + %{ + "defaultValue" => nil, + "description" => nil, + "name" => "code", + "type" => %{ + "kind" => "NON_NULL", + "name" => nil, + "ofType" => %{"kind" => "SCALAR", "name" => "String"} + }, + "deprecationReason" => nil, + "isDeprecated" => false + }, + %{ + "defaultValue" => "\"Janet\"", + "description" => "The person's name", + "name" => "name", + "type" => %{"kind" => "SCALAR", "name" => "String", "ofType" => nil}, + "deprecationReason" => nil, + "isDeprecated" => false + } + ], + "kind" => "INPUT_OBJECT", + "name" => "ProfileInput" + } + } + }}, + result + ) + + assert !match?({:ok, %{data: %{"__type" => %{"fields" => _}}}}, result) + end + defmodule ComplexDefaultSchema do use Absinthe.Schema diff --git a/test/support/fixtures/contact_schema.ex b/test/support/fixtures/contact_schema.ex index ef0d247783..f2658ca74a 100644 --- a/test/support/fixtures/contact_schema.ex +++ b/test/support/fixtures/contact_schema.ex @@ -75,6 +75,7 @@ defmodule Absinthe.Fixtures.ContactSchema do field :code, type: non_null(:string) field :name, type: :string, description: "The person's name", default_value: "Janet" field :age, type: :integer, description: "The person's age", default_value: 43 + field :address, type: :string, deprecate: "change of privacy policy" end interface :named_entity do