Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handle raised ExecutionErrors from prepare when calculating complexity #4079

Merged
merged 2 commits into from May 27, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
8 changes: 7 additions & 1 deletion lib/graphql/schema/field.rb
Expand Up @@ -496,7 +496,13 @@ def calculate_complexity(query:, nodes:, child_complexity:)
case defined_complexity
when Proc
arguments = query.arguments_for(nodes.first, self)
defined_complexity.call(query.context, arguments.keyword_arguments, child_complexity)
if arguments.is_a?(GraphQL::ExecutionError)
return child_complexity
elsif arguments.respond_to?(:keyword_arguments)
arguments = arguments.keyword_arguments
end

defined_complexity.call(query.context, arguments, child_complexity)
when Numeric
defined_complexity + child_complexity
else
Expand Down
29 changes: 26 additions & 3 deletions spec/graphql/analysis/ast/query_complexity_spec.rb
Expand Up @@ -8,7 +8,8 @@
GraphQL::Analysis::AST.analyze_multiplex(multiplex, [GraphQL::Analysis::AST::QueryComplexity])
}
let(:variables) { {} }
let(:query) { GraphQL::Query.new(schema, query_string, variables: variables) }
let(:query_context) { {} }
let(:query) { GraphQL::Query.new(schema, query_string, context: query_context, variables: variables) }
let(:multiplex) {
GraphQL::Execution::Multiplex.new(
schema: schema,
Expand Down Expand Up @@ -377,10 +378,20 @@ class DoubleComplexity < GraphQL::Schema::Object

class Query < GraphQL::Schema::Object
field :complexity, SingleComplexity do
argument :int_value, Int, required: false
argument :int_value, Int, required: false, prepare: ->(val, ctx) {
if ctx[:raise_prepare_error]
raise GraphQL::ExecutionError, "Boom"
else
val
end
}
complexity ->(ctx, args, child_complexity) { args[:int_value] + child_complexity }
end

def complexity(int_value:)
{ value: int_value }
end

field :inner_complexity, ComplexityInterface do
argument :value, Int, required: false
end
Expand All @@ -390,7 +401,7 @@ class Query < GraphQL::Schema::Object
orphan_types(DoubleComplexity)
end

let(:query) { GraphQL::Query.new(complexity_schema, query_string) }
let(:query) { GraphQL::Query.new(complexity_schema, query_string, context: query_context) }
let(:complexity_schema) { CustomComplexitySchema }
let(:query_string) {%|
{
Expand Down Expand Up @@ -426,6 +437,18 @@ class Query < GraphQL::Schema::Object
assert_equal 5, complexity
end
end

describe "when prepare raises an error" do
let(:query_string) { "{ complexity(intValue: 3) { value } }"}
let(:query_context) { { raise_prepare_error: true } }

it "handles it nicely" do
result = query.result
assert_equal ["Boom"], result["errors"].map { |e| e["message"] }
complexity = reduce_result.first
assert_equal 0.1, complexity
end
end
end

describe "custom complexities by complexity_for(...)" do
Expand Down