graphql 2.5.23 → 2.6.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. checksums.yaml +4 -4
  2. data/lib/graphql/analysis/query_complexity.rb +29 -13
  3. data/lib/graphql/analysis.rb +20 -13
  4. data/lib/graphql/backtrace/table.rb +10 -1
  5. data/lib/graphql/current.rb +7 -1
  6. data/lib/graphql/dataloader.rb +1 -1
  7. data/lib/graphql/execution/directive_checks.rb +2 -0
  8. data/lib/graphql/execution/field_resolve_step.rb +744 -0
  9. data/lib/graphql/execution/finalize.rb +230 -0
  10. data/lib/graphql/execution/input_values.rb +333 -0
  11. data/lib/graphql/execution/interpreter/arguments_cache.rb +3 -0
  12. data/lib/graphql/execution/interpreter/handles_raw_value.rb +6 -0
  13. data/lib/graphql/execution/interpreter/runtime.rb +36 -15
  14. data/lib/graphql/execution/load_argument_step.rb +102 -0
  15. data/lib/graphql/execution/next.rb +42 -16
  16. data/lib/graphql/execution/prepare_object_step.rb +147 -0
  17. data/lib/graphql/execution/resolve_type_step.rb +27 -0
  18. data/lib/graphql/execution/runner.rb +445 -0
  19. data/lib/graphql/execution/selections_step.rb +91 -0
  20. data/lib/graphql/execution.rb +10 -3
  21. data/lib/graphql/execution_error.rb +7 -13
  22. data/lib/graphql/introspection/entry_points.rb +2 -2
  23. data/lib/graphql/introspection/schema_type.rb +6 -2
  24. data/lib/graphql/language/lexer.rb +12 -8
  25. data/lib/graphql/language/parser.rb +1 -1
  26. data/lib/graphql/language.rb +8 -2
  27. data/lib/graphql/pagination/connections.rb +1 -3
  28. data/lib/graphql/query/context.rb +6 -0
  29. data/lib/graphql/query/partial.rb +18 -3
  30. data/lib/graphql/query.rb +12 -3
  31. data/lib/graphql/runtime_error.rb +6 -0
  32. data/lib/graphql/schema/argument.rb +3 -3
  33. data/lib/graphql/schema/build_from_definition.rb +10 -0
  34. data/lib/graphql/schema/directive/feature.rb +4 -0
  35. data/lib/graphql/schema/directive/transform.rb +20 -0
  36. data/lib/graphql/schema/directive.rb +23 -9
  37. data/lib/graphql/schema/field/connection_extension.rb +2 -15
  38. data/lib/graphql/schema/field/scope_extension.rb +0 -4
  39. data/lib/graphql/schema/field.rb +20 -20
  40. data/lib/graphql/schema/field_extension.rb +11 -41
  41. data/lib/graphql/schema/has_single_input_argument.rb +24 -13
  42. data/lib/graphql/schema/input_object.rb +4 -0
  43. data/lib/graphql/schema/interface.rb +26 -0
  44. data/lib/graphql/schema/introspection_system.rb +6 -21
  45. data/lib/graphql/schema/list.rb +4 -0
  46. data/lib/graphql/schema/member/base_dsl_methods.rb +0 -10
  47. data/lib/graphql/schema/printer.rb +1 -1
  48. data/lib/graphql/schema/ractor_shareable.rb +1 -0
  49. data/lib/graphql/schema/relay_classic_mutation.rb +16 -2
  50. data/lib/graphql/schema/resolver.rb +30 -14
  51. data/lib/graphql/schema/subscription.rb +53 -8
  52. data/lib/graphql/schema/timeout.rb +2 -2
  53. data/lib/graphql/schema/validator/allow_blank_validator.rb +3 -3
  54. data/lib/graphql/schema/validator/allow_null_validator.rb +3 -3
  55. data/lib/graphql/schema/validator/exclusion_validator.rb +2 -2
  56. data/lib/graphql/schema/validator/format_validator.rb +3 -3
  57. data/lib/graphql/schema/validator/inclusion_validator.rb +2 -2
  58. data/lib/graphql/schema/validator/length_validator.rb +6 -6
  59. data/lib/graphql/schema/validator/numericality_validator.rb +19 -19
  60. data/lib/graphql/schema/validator/required_validator.rb +6 -4
  61. data/lib/graphql/schema/validator.rb +9 -0
  62. data/lib/graphql/schema/visibility/profile.rb +6 -4
  63. data/lib/graphql/schema/visibility/visit.rb +1 -1
  64. data/lib/graphql/schema/visibility.rb +30 -22
  65. data/lib/graphql/schema.rb +43 -20
  66. data/lib/graphql/subscriptions/default_subscription_resolve_extension.rb +31 -25
  67. data/lib/graphql/subscriptions/event.rb +0 -1
  68. data/lib/graphql/subscriptions.rb +15 -0
  69. data/lib/graphql/tracing/perfetto_trace.rb +5 -3
  70. data/lib/graphql/tracing/trace.rb +6 -0
  71. data/lib/graphql/unauthorized_error.rb +1 -1
  72. data/lib/graphql/version.rb +1 -1
  73. data/lib/graphql.rb +1 -3
  74. metadata +11 -7
  75. data/lib/graphql/execution/next/field_resolve_step.rb +0 -743
  76. data/lib/graphql/execution/next/load_argument_step.rb +0 -64
  77. data/lib/graphql/execution/next/prepare_object_step.rb +0 -129
  78. data/lib/graphql/execution/next/runner.rb +0 -411
  79. data/lib/graphql/execution/next/selections_step.rb +0 -37
@@ -198,7 +198,7 @@ module GraphQL
198
198
 
199
199
  def each_gathered_selections(response_hash)
200
200
  ordered_result_keys = []
201
- gathered_selections = gather_selections(response_hash.graphql_application_value, response_hash.graphql_result_type, response_hash.graphql_selections, nil, {}, ordered_result_keys)
201
+ gathered_selections = gather_selections(response_hash, response_hash.graphql_application_value, response_hash.graphql_result_type, response_hash.graphql_selections, nil, {}, ordered_result_keys)
202
202
  ordered_result_keys.uniq!
203
203
  if gathered_selections.is_a?(Array)
204
204
  gathered_selections.each do |item|
@@ -209,15 +209,13 @@ module GraphQL
209
209
  end
210
210
  end
211
211
 
212
- def gather_selections(owner_object, owner_type, selections, selections_to_run, selections_by_name, ordered_result_keys)
212
+ def gather_selections(graphql_response, owner_object, owner_type, selections, selections_to_run, selections_by_name, ordered_result_keys)
213
213
  selections.each do |node|
214
- # Skip gathering this if the directive says so
215
- if !directives_include?(node, owner_object, owner_type)
216
- next
217
- end
218
-
219
214
  if node.is_a?(GraphQL::Language::Nodes::Field)
220
215
  response_key = node.alias || node.name
216
+ if !directives_include?(node, owner_object, owner_type, graphql_response, response_key)
217
+ next
218
+ end
221
219
  ordered_result_keys << response_key
222
220
  selections = selections_by_name[response_key]
223
221
  # if there was already a selection of this field,
@@ -234,6 +232,9 @@ module GraphQL
234
232
  selections_by_name[response_key] = node
235
233
  end
236
234
  else
235
+ if !directives_include?(node, owner_object, owner_type, graphql_response, nil)
236
+ next
237
+ end
237
238
  # This is an InlineFragment or a FragmentSpread
238
239
  if !@runtime_directive_names.empty? && node.directives.any? { |d| @runtime_directive_names.include?(d.name) }
239
240
  next_selections = {}
@@ -255,14 +256,14 @@ module GraphQL
255
256
  type_defn = query.types.type(node.type.name)
256
257
 
257
258
  if query.types.possible_types(type_defn).include?(owner_type)
258
- result = gather_selections(owner_object, owner_type, node.selections, selections_to_run, next_selections, ordered_result_keys)
259
+ result = gather_selections(graphql_response, owner_object, owner_type, node.selections, selections_to_run, next_selections, ordered_result_keys)
259
260
  if !result.equal?(next_selections)
260
261
  selections_to_run = result
261
262
  end
262
263
  end
263
264
  else
264
265
  # it's an untyped fragment, definitely continue
265
- result = gather_selections(owner_object, owner_type, node.selections, selections_to_run, next_selections, ordered_result_keys)
266
+ result = gather_selections(graphql_response, owner_object, owner_type, node.selections, selections_to_run, next_selections, ordered_result_keys)
266
267
  if !result.equal?(next_selections)
267
268
  selections_to_run = result
268
269
  end
@@ -271,7 +272,7 @@ module GraphQL
271
272
  fragment_def = query.fragments[node.name]
272
273
  type_defn = query.types.type(fragment_def.type.name)
273
274
  if query.types.possible_types(type_defn).include?(owner_type)
274
- result = gather_selections(owner_object, owner_type, fragment_def.selections, selections_to_run, next_selections, ordered_result_keys)
275
+ result = gather_selections(graphql_response, owner_object, owner_type, fragment_def.selections, selections_to_run, next_selections, ordered_result_keys)
275
276
  if !result.equal?(next_selections)
276
277
  selections_to_run = result
277
278
  end
@@ -339,7 +340,7 @@ module GraphQL
339
340
  end
340
341
  field_name = ast_node.name
341
342
  owner_type = selections_result.graphql_result_type
342
- field_defn = query.types.field(owner_type, field_name)
343
+ field_defn = query.types.field(owner_type, field_name) || raise(GraphQL::Error, "No field definition found for #{owner_type.graphql_name}.#{field_name} (at #{ast_node.position})")
343
344
 
344
345
  # Set this before calling `run_with_directives`, so that the directive can have the latest path
345
346
  runtime_state = get_current_runtime_state
@@ -579,7 +580,7 @@ module GraphQL
579
580
  value.path ||= current_path
580
581
  value.ast_node ||= ast_node
581
582
  context.errors << value
582
- if selection_result
583
+ if selection_result && result_name
583
584
  set_result(selection_result, result_name, nil, false, is_non_null)
584
585
  end
585
586
  end
@@ -856,11 +857,31 @@ module GraphQL
856
857
  end
857
858
 
858
859
  # Check {Schema::Directive.include?} for each directive that's present
859
- def directives_include?(node, graphql_object, parent_type)
860
+ def directives_include?(node, graphql_object, parent_type, selection_result, extra_path_part)
860
861
  node.directives.each do |dir_node|
861
862
  dir_defn = @schema_directives.fetch(dir_node.name)
862
- args = arguments(graphql_object, dir_defn, dir_node)
863
- if !dir_defn.include?(graphql_object, args, context)
863
+ raw_dir_args = arguments(nil, dir_defn, dir_node)
864
+ if !raw_dir_args.is_a?(GraphQL::ExecutionError)
865
+ begin
866
+ dir_defn.validate!(raw_dir_args, context)
867
+ rescue GraphQL::ExecutionError => err
868
+ raw_dir_args = err
869
+ end
870
+ end
871
+
872
+ if extra_path_part && raw_dir_args.is_a?(GraphQL::ExecutionError)
873
+ raw_dir_args.path = current_path + [extra_path_part]
874
+ end
875
+
876
+ dir_args = continue_value(
877
+ raw_dir_args, # value
878
+ nil, # field
879
+ false, # is_non_null
880
+ dir_node, # ast_node
881
+ nil, # result_name
882
+ selection_result
883
+ )
884
+ if dir_args == HALT || !dir_defn.include?(graphql_object, dir_args, context)
864
885
  return false
865
886
  end
866
887
  end
@@ -0,0 +1,102 @@
1
+ # frozen_string_literal: true
2
+ module GraphQL
3
+ module Execution
4
+ class LoadArgumentStep
5
+ def initialize(field_resolve_step:, arguments:, load_receiver:, argument_value:, argument_definition:, argument_key:)
6
+ @field_resolve_step = field_resolve_step
7
+ @load_receiver = load_receiver
8
+ @arguments = arguments
9
+ @argument_value = argument_value
10
+ @argument_definition = argument_definition
11
+ @argument_key = argument_key
12
+ @loaded_value = nil
13
+ @is_authorized = true
14
+ end
15
+
16
+ def value
17
+ @field_resolve_step.set_current_field
18
+ schema = @field_resolve_step.runner.schema
19
+ @loaded_value = schema.sync_lazy(@loaded_value)
20
+ assign_value
21
+ rescue GraphQL::UnauthorizedError => auth_err
22
+ @is_authorized = false
23
+ schema.unauthorized_object(auth_err)
24
+ rescue GraphQL::RuntimeError => err
25
+ @loaded_value = if err.is_a?(Schema::Subscription::EarlyUnsubscribe)
26
+ err.unsubscribed_result
27
+ else
28
+ err
29
+ end
30
+ assign_value
31
+ rescue StandardError => stderr
32
+ begin
33
+ @field_resolve_step.selections_step.query.handle_or_reraise(stderr, field: @field_definition, arguments: @arguments, object: nil)
34
+ rescue GraphQL::ExecutionError => ex_err
35
+ @loaded_value = ex_err
36
+ end
37
+ assign_value
38
+ ensure
39
+ @field_resolve_step.set_current_field(nil)
40
+ end
41
+
42
+ def call
43
+ @field_resolve_step.set_current_field
44
+ context = @field_resolve_step.selections_step.query.context
45
+ @loaded_value = begin
46
+ @load_receiver.load_and_authorize_application_object(@argument_definition, @argument_value, context)
47
+ rescue GraphQL::UnauthorizedError => auth_err
48
+ @is_authorized = false
49
+ context.schema.unauthorized_object(auth_err)
50
+ end
51
+ if (runner = @field_resolve_step.runner).resolves_lazies && runner.lazy?(@loaded_value)
52
+ runner.dataloader.lazy_at_depth(@field_resolve_step.path.size, self)
53
+ else
54
+ assign_value
55
+ end
56
+ rescue GraphQL::RuntimeError => err
57
+ @loaded_value = if err.is_a?(Schema::Subscription::EarlyUnsubscribe)
58
+ @is_authorized = false
59
+ err.unsubscribed_result
60
+ else
61
+ err
62
+ end
63
+ assign_value
64
+ rescue StandardError => stderr
65
+ @loaded_value = begin
66
+ context.query.handle_or_reraise(stderr, field: @field_resolve_step.field_definition, arguments: @field_resolve_step.arguments, object: nil) # rubocop:disable Development/ContextIsPassedCop
67
+ rescue GraphQL::ExecutionError => ex_err
68
+ ex_err
69
+ end
70
+ assign_value
71
+ ensure
72
+ @field_resolve_step.set_current_field(nil)
73
+ end
74
+
75
+ private
76
+
77
+ def assign_value
78
+ if @loaded_value.is_a?(GraphQL::RuntimeError)
79
+ @loaded_value.path = @field_resolve_step.path
80
+ @field_resolve_step.arguments = @loaded_value
81
+ elsif @is_authorized == false
82
+ # An unauthorized_object hook ate the error
83
+ @field_resolve_step.arguments = EmptyObjects::EMPTY_HASH
84
+ field_pending_steps = @field_resolve_step.pending_steps
85
+ field_pending_steps.clear
86
+ @field_resolve_step.build_errors_result(nil, nil)
87
+ return
88
+ else
89
+ query = @field_resolve_step.selections_step.query
90
+ query.current_trace.object_loaded(@argument_definition, @loaded_value, query.context)
91
+ @arguments[@argument_key] = @loaded_value
92
+ end
93
+
94
+ field_pending_steps = @field_resolve_step.pending_steps
95
+ field_pending_steps.delete(self)
96
+ if @field_resolve_step.arguments && field_pending_steps.size == 0 # rubocop:disable Development/ContextIsPassedCop
97
+ @field_resolve_step.runner.add_step(@field_resolve_step)
98
+ end
99
+ end
100
+ end
101
+ end
102
+ end
@@ -1,14 +1,44 @@
1
1
  # frozen_string_literal: true
2
- require "graphql/execution/next/prepare_object_step"
3
- require "graphql/execution/next/field_resolve_step"
4
- require "graphql/execution/next/load_argument_step"
5
- require "graphql/execution/next/runner"
6
- require "graphql/execution/next/selections_step"
2
+ require "graphql/execution/prepare_object_step"
3
+ require "graphql/execution/input_values"
4
+ require "graphql/execution/field_resolve_step"
5
+ require "graphql/execution/finalize"
6
+ require "graphql/execution/load_argument_step"
7
+ require "graphql/execution/resolve_type_step"
8
+ require "graphql/execution/runner"
9
+ require "graphql/execution/selections_step"
7
10
  module GraphQL
8
11
  module Execution
12
+ module Finalizer
13
+ attr_accessor :path
14
+
15
+ def finalize_graphql_result(query, result_data, result_key)
16
+ raise RequiredImplementationMissingError, "#{self.class} must implement #finalize_graphql_result(query, result_data, result_key)\n\nresult_data: #{result_data}\nresult_key: #{result_key.inspect}"
17
+ end
18
+
19
+ def ast_node
20
+ ast_nodes&.first
21
+ end
22
+
23
+ def ast_node=(new_node)
24
+ @ast_nodes = [new_node]
25
+ end
26
+
27
+ attr_accessor :ast_nodes
28
+ end
29
+
30
+ module HaltExecution
31
+ end
32
+
33
+ module PostProcessor
34
+ def after_resolve(field_results)
35
+ raise RequiredImplementationMissingError, "#{self.class}#after_resolve should handle `field_results` and return a new value to use"
36
+ end
37
+ end
38
+
9
39
  module Next
10
40
  module SchemaExtension
11
- def execute_next(query_str = nil, context: nil, document: nil, operation_name: nil, variables: nil, root_value: nil, validate: true, visibility_profile: nil)
41
+ def execute_next(query_str = nil, query: nil, subscription_topic: nil, context: nil, document: nil, operation_name: nil, variables: nil, warden: nil, root_value: nil, validate: true, visibility_profile: nil)
12
42
  multiplex_context = if context
13
43
  {
14
44
  backtrace: context[:backtrace],
@@ -21,7 +51,8 @@ module GraphQL
21
51
  {}
22
52
  end
23
53
  query_opts = {
24
- query: query_str,
54
+ query: query || query_str,
55
+ subscription_topic: subscription_topic,
25
56
  document: document,
26
57
  context: context,
27
58
  validate: validate,
@@ -29,6 +60,7 @@ module GraphQL
29
60
  root_value: root_value,
30
61
  operation_name: operation_name,
31
62
  visibility_profile: visibility_profile,
63
+ warden: warden,
32
64
  }
33
65
  m_results = multiplex_next([query_opts], context: multiplex_context, max_complexity: nil)
34
66
  m_results[0]
@@ -37,17 +69,11 @@ module GraphQL
37
69
  def multiplex_next(query_options, context: {}, max_complexity: self.max_complexity)
38
70
  Next.run_all(self, query_options, context: context, max_complexity: max_complexity)
39
71
  end
40
-
41
- def execution_next_options
42
- @execution_next_options || find_inherited_value(:execution_next_options, EmptyObjects::EMPTY_HASH)
43
- end
44
-
45
- attr_writer :execution_next_options
46
72
  end
47
73
 
48
- def self.use(schema, authorization: true)
74
+ def self.use(schema, as_default: false)
49
75
  schema.extend(SchemaExtension)
50
- schema.execution_next_options = { authorization: authorization }
76
+ schema.default_execution_next(as_default)
51
77
  end
52
78
 
53
79
  def self.run_all(schema, query_options, context: {}, max_complexity: schema.max_complexity)
@@ -64,7 +90,7 @@ module GraphQL
64
90
  query
65
91
  end
66
92
  multiplex = Execution::Multiplex.new(schema: schema, queries: queries, context: context, max_complexity: max_complexity)
67
- runner = Runner.new(multiplex, **schema.execution_next_options)
93
+ runner = Runner.new(multiplex)
68
94
  runner.execute
69
95
  end
70
96
  end
@@ -0,0 +1,147 @@
1
+ # frozen_string_literal: true
2
+ module GraphQL
3
+ module Execution
4
+ class PrepareObjectStep
5
+ def initialize(object:, runner:, graphql_result:, key:, is_non_null:, field_resolve_step:, next_objects:, next_results:, is_from_array:)
6
+ @object = object
7
+ @runner = runner
8
+ @field_resolve_step = field_resolve_step
9
+ @is_non_null = is_non_null
10
+ @next_objects = next_objects
11
+ @next_results = next_results
12
+ @graphql_result = graphql_result
13
+ @resolved_type = nil
14
+ @authorized_value = nil
15
+ @authorization_error = nil
16
+ @key = key
17
+ @next_step = :resolve_type
18
+ @is_from_array = is_from_array
19
+ end
20
+
21
+ def value
22
+ @field_resolve_step.set_current_field
23
+ if @authorized_value
24
+ query = @field_resolve_step.selections_step.query
25
+ query.current_trace.begin_authorized(@resolved_type, @object, query.context)
26
+ @authorized_value = @field_resolve_step.sync(@authorized_value)
27
+ query.current_trace.end_authorized(@resolved_type, @object, query.context, @authorized_value)
28
+ elsif @resolved_type
29
+ ctx = @field_resolve_step.selections_step.query.context
30
+ st = @field_resolve_step.static_type
31
+ ctx.query.current_trace.begin_resolve_type(st, @object, ctx)
32
+ @resolved_type, new_value = @field_resolve_step.sync(@resolved_type)
33
+ ResolveTypeStep.assert_valid_resolved_type(st, @resolved_type, new_value, @field_resolve_step)
34
+ if new_value
35
+ @object = new_value
36
+ end
37
+ ctx.query.current_trace.end_resolve_type(st, @object, ctx, @resolved_type)
38
+ end
39
+ @runner.add_step(self)
40
+ ensure
41
+ @field_resolve_step.set_current_field(nil)
42
+ end
43
+
44
+ def call
45
+ @field_resolve_step.set_current_field
46
+ case @next_step
47
+ when :resolve_type
48
+ static_type = @field_resolve_step.static_type
49
+ if static_type.kind.abstract?
50
+ query = @field_resolve_step.selections_step.query
51
+ @resolved_type, new_value = ResolveTypeStep.resolve_type(static_type, @object, query)
52
+ if new_value
53
+ ResolveTypeStep.assert_valid_resolved_type(static_type, @resolved_type, new_value, @field_resolve_step)
54
+ @object = new_value
55
+ end
56
+ else
57
+ @resolved_type = static_type
58
+ end
59
+ if @runner.resolves_lazies && @runner.lazy?(@resolved_type)
60
+ @next_step = :authorize
61
+ @runner.dataloader.lazy_at_depth(@field_resolve_step.path.size, self)
62
+ else
63
+ authorize
64
+ end
65
+ when :authorize
66
+ authorize
67
+ when :create_result
68
+ create_result
69
+ else
70
+ raise ArgumentError, "This is a bug, unknown step: #{@next_step.inspect}"
71
+ end
72
+ ensure
73
+ @field_resolve_step.set_current_field(nil)
74
+ end
75
+
76
+ def authorize
77
+ if @field_resolve_step.was_scoped && !@resolved_type.reauthorize_scoped_objects
78
+ @authorized_value = @object
79
+ create_result
80
+ return
81
+ end
82
+
83
+ query = @field_resolve_step.selections_step.query
84
+ begin
85
+ query.current_trace.begin_authorized(@resolved_type, @object, query.context)
86
+ @authorized_value = @resolved_type.authorized?(@object, query.context)
87
+ query.current_trace.end_authorized(@resolved_type, @object, query.context, @authorized_value)
88
+ rescue GraphQL::UnauthorizedError => auth_err
89
+ @authorization_error = auth_err
90
+ end
91
+
92
+ if @runner.resolves_lazies && @runner.lazy?(@authorized_value)
93
+ @runner.dataloader.lazy_at_depth(@field_resolve_step.path.size, self)
94
+ @next_step = :create_result
95
+ else
96
+ create_result
97
+ end
98
+ rescue GraphQL::RuntimeError => err
99
+ @graphql_result[@key] = @field_resolve_step.add_graphql_error(err)
100
+ rescue StandardError => err
101
+ query ||= @field_resolve_step.selections_step.query
102
+ begin
103
+ query.handle_or_reraise(err, field: @field_resolve_step.field_definition, arguments: @field_resolve_step.arguments, object: @object) # rubocop:disable Development/ContextIsPassedCop
104
+ rescue GraphQL::RuntimeError => err
105
+ @graphql_result[@key] = @field_resolve_step.add_graphql_error(err)
106
+ end
107
+ end
108
+
109
+ def create_result
110
+ if !@authorized_value
111
+ @authorization_error ||= GraphQL::UnauthorizedError.new(object: @object, type: @resolved_type, context: @field_resolve_step.selections_step.query.context)
112
+ end
113
+
114
+ if @authorization_error
115
+ begin
116
+ new_obj = @runner.schema.unauthorized_object(@authorization_error)
117
+ if new_obj
118
+ @authorized_value = true
119
+ @object = new_obj
120
+ elsif @is_non_null
121
+ @graphql_result[@key] = @field_resolve_step.add_non_null_error(@is_from_array)
122
+ else
123
+ @graphql_result[@key] = @field_resolve_step.add_graphql_error(@authorization_error)
124
+ end
125
+ rescue GraphQL::RuntimeError => err
126
+ if @is_non_null
127
+ @graphql_result[@key] = @field_resolve_step.add_non_null_error(@is_from_array)
128
+ else
129
+ @graphql_result[@key] = @field_resolve_step.add_graphql_error(err)
130
+ end
131
+ end
132
+ end
133
+
134
+ if @authorized_value
135
+ next_result_h = {}
136
+ @next_results << next_result_h
137
+ @next_objects << @object
138
+ @graphql_result[@key] = next_result_h
139
+ @runner.runtime_type_at[next_result_h] = @resolved_type
140
+ @runner.static_type_at[next_result_h] = @field_resolve_step.static_type
141
+ end
142
+
143
+ @field_resolve_step.authorized_finished(self)
144
+ end
145
+ end
146
+ end
147
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+ module GraphQL
3
+ module Execution
4
+ class ResolveTypeStep
5
+ def self.resolve_type(type, object, query)
6
+ query.current_trace.begin_resolve_type(type, object, query.context)
7
+ resolved_type_response = query.resolve_type(type, object)
8
+ resolved_type = if resolved_type_response.is_a?(Array)
9
+ resolved_type_response.first
10
+ else
11
+ resolved_type_response
12
+ end
13
+ query.current_trace.end_resolve_type(type, object, query.context, resolved_type)
14
+ resolved_type_response
15
+ end
16
+
17
+ def self.assert_valid_resolved_type(abstract_type, resolved_type, object, field_resolution_step, query: field_resolution_step.selections_step.query)
18
+ possible_types = query.types.possible_types(abstract_type)
19
+ if !possible_types.include?(resolved_type)
20
+ err_class = abstract_type::UnresolvedTypeError
21
+ type_error = err_class.new(object, field_resolution_step.field_definition, abstract_type, resolved_type, possible_types)
22
+ query.schema.type_error(type_error, query.context)
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end