Skip to content

Commit c8069d7

Browse files
authored
Merge pull request #4804 from lukes/ld-FieldUsage-detect-deprecated-enum-values
Allow GraphQL::Analysis::AST::FieldUsage to detect use of deprecated enum value as argument
2 parents 3adaba5 + 9c1deaa commit c8069d7

File tree

3 files changed

+78
-8
lines changed

3 files changed

+78
-8
lines changed

lib/graphql/analysis/ast/field_usage.rb

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,15 @@ def initialize(query)
88
@used_fields = Set.new
99
@used_deprecated_fields = Set.new
1010
@used_deprecated_arguments = Set.new
11+
@used_deprecated_enum_values = Set.new
1112
end
1213

1314
def on_leave_field(node, parent, visitor)
1415
field_defn = visitor.field_definition
1516
field = "#{visitor.parent_type_definition.graphql_name}.#{field_defn.graphql_name}"
1617
@used_fields << field
1718
@used_deprecated_fields << field if field_defn.deprecation_reason
18-
arguments = visitor.query.arguments_for(node, visitor.field_definition)
19+
arguments = visitor.query.arguments_for(node, field_defn)
1920
# If there was an error when preparing this argument object,
2021
# then this might be an error or something:
2122
if arguments.respond_to?(:argument_values)
@@ -28,6 +29,7 @@ def result
2829
used_fields: @used_fields.to_a,
2930
used_deprecated_fields: @used_deprecated_fields.to_a,
3031
used_deprecated_arguments: @used_deprecated_arguments.to_a,
32+
used_deprecated_enum_values: @used_deprecated_enum_values.to_a,
3133
}
3234
end
3335

@@ -41,16 +43,39 @@ def extract_deprecated_arguments(argument_values)
4143

4244
next if argument.value.nil?
4345

44-
if argument.definition.type.kind.input_object?
46+
argument_type = argument.definition.type
47+
if argument_type.non_null?
48+
argument_type = argument_type.of_type
49+
end
50+
51+
if argument_type.kind.input_object?
4552
extract_deprecated_arguments(argument.value.arguments.argument_values) # rubocop:disable Development/ContextIsPassedCop -- runtime args instance
46-
elsif argument.definition.type.list?
47-
argument
48-
.value
49-
.select { |value| value.respond_to?(:arguments) }
50-
.each { |value| extract_deprecated_arguments(value.arguments.argument_values) } # rubocop:disable Development/ContextIsPassedCop -- runtime args instance
53+
elsif argument_type.kind.enum?
54+
extract_deprecated_enum_value(argument_type, argument.value)
55+
elsif argument_type.list?
56+
inner_type = argument_type.unwrap
57+
case inner_type.kind
58+
when TypeKinds::INPUT_OBJECT
59+
argument.value.each do |value|
60+
extract_deprecated_arguments(value.arguments.argument_values) # rubocop:disable Development/ContextIsPassedCop -- runtime args instance
61+
end
62+
when TypeKinds::ENUM
63+
argument.value.each do |value|
64+
extract_deprecated_enum_value(inner_type, value)
65+
end
66+
else
67+
# Not a kind of input that we track
68+
end
5169
end
5270
end
5371
end
72+
73+
def extract_deprecated_enum_value(enum_type, value)
74+
enum_value = @query.warden.enum_values(enum_type).find { |ev| ev.value == value }
75+
if enum_value&.deprecation_reason
76+
@used_deprecated_enum_values << enum_value.path
77+
end
78+
end
5479
end
5580
end
5681
end

spec/graphql/analysis/ast/field_usage_spec.rb

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,36 @@
138138
end
139139
end
140140

141+
describe "query with deprecated enum argument" do
142+
let(:query_string) {%|
143+
query {
144+
fromSource(source: YAK) {
145+
id
146+
}
147+
}
148+
|}
149+
150+
it "keeps track of deprecated arguments" do
151+
assert_equal ['DairyAnimal.YAK'], result[:used_deprecated_enum_values]
152+
end
153+
154+
describe "tracks non-null/list enums" do
155+
let(:query_string) {%|
156+
query {
157+
cheese(id: 1) {
158+
similarCheese(source: [YAK]) {
159+
id
160+
}
161+
}
162+
}
163+
|}
164+
165+
it "keeps track of deprecated arguments" do
166+
assert_equal ['DairyAnimal.YAK'], result[:used_deprecated_enum_values]
167+
end
168+
end
169+
end
170+
141171
describe "query with an array argument sent as null" do
142172
let(:query_string) {%|
143173
query {
@@ -211,6 +241,20 @@
211241
end
212242
end
213243

244+
245+
describe "mutation with deprecated argument" do
246+
let(:query_string) {%|
247+
mutation {
248+
pushValue(deprecatedTestInput: { oldSource: "deprecated" })
249+
}
250+
|}
251+
252+
it "keeps track of nested deprecated arguments" do
253+
assert_equal ['DairyProductInput.oldSource'], result[:used_deprecated_arguments]
254+
end
255+
end
256+
257+
214258
describe "when an argument prepare raises a GraphQL::ExecutionError" do
215259
class ArgumentErrorFieldUsageSchema < GraphQL::Schema
216260
class FieldUsage < GraphQL::Analysis::AST::FieldUsage
@@ -234,7 +278,7 @@ class Query < GraphQL::Schema::Object
234278
it "skips analysis of those arguments" do
235279
res = ArgumentErrorFieldUsageSchema.execute("{ f(i: 1) }")
236280
assert_equal ["boom!"], res["errors"].map { |e| e["message"] }
237-
assert_equal({used_fields: ["Query.f"], used_deprecated_arguments: [], used_deprecated_fields: []}, res.context[:field_usage])
281+
assert_equal({used_fields: ["Query.f"], used_deprecated_arguments: [], used_deprecated_fields: [], used_deprecated_enum_values: []}, res.context[:field_usage])
238282
end
239283
end
240284
end

spec/support/dummy/schema.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -489,6 +489,7 @@ class DairyAppMutation < BaseObject
489489
description "The root for mutations in this schema"
490490
field :push_value, [Integer], null: false, description: "Push a value onto a global array :D" do
491491
argument :value, Integer, as: :val
492+
argument :deprecated_test_input, DairyProductInput, required: false
492493
end
493494
def push_value(val:)
494495
GLOBAL_VALUES << val

0 commit comments

Comments
 (0)