Skip to content

Commit 245cc65

Browse files
authored
Merge pull request #5603 from rmosolgo/next-rename
Exec-next: remove next namespacing
2 parents c011759 + c39f096 commit 245cc65

24 files changed

Lines changed: 1860 additions & 1975 deletions

lib/graphql/execution/field_resolve_step.rb

Lines changed: 808 additions & 0 deletions
Large diffs are not rendered by default.

lib/graphql/execution/finalize.rb

Lines changed: 217 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,217 @@
1+
# frozen_string_literal: true
2+
module GraphQL
3+
module Execution
4+
class Finalize
5+
def initialize(query, data, runner)
6+
@query = query
7+
@data = data
8+
@static_type_at = runner.static_type_at
9+
@runner = runner
10+
@current_exec_path = query.path.dup
11+
@current_result_path = query.path.dup
12+
@finalizers = runner.finalizers ? runner.finalizers[query] : {}.compare_by_identity
13+
@finalizers_count = 0
14+
@finalizers.each do |key, values|
15+
values.each do |key2, values2|
16+
case values2
17+
when Array
18+
@finalizers_count += values2.size
19+
else
20+
@finalizers_count += 1
21+
end
22+
end
23+
end
24+
25+
query.context.errors.each do |err|
26+
err_path = err.path - @current_exec_path
27+
key = err_path.pop
28+
targets = [data]
29+
while (part = err_path.shift)
30+
targets.map! { |t| t[part] }
31+
targets.flatten!
32+
end
33+
34+
targets.each_with_index do |target, idx|
35+
if target.is_a?(Hash)
36+
if target[key].equal?(err)
37+
tf = @finalizers[target] ||= {}.compare_by_identity
38+
tf[key] = err
39+
@finalizers_count += 1
40+
elsif (arr = target[key]).is_a?(Array)
41+
arr.each_with_index do |el, idx|
42+
if el.equal?(err)
43+
tf = @finalizers[arr] ||= {}.compare_by_identity
44+
tf[idx] = err
45+
@finalizers_count += 1
46+
end
47+
end
48+
end
49+
end
50+
end
51+
end
52+
end
53+
54+
def run
55+
if (selected_operation = @query.selected_operation) && @data
56+
if @data.is_a?(Hash)
57+
check_object_result(@data, @query.root_type, selected_operation.selections)
58+
elsif @data.is_a?(Array)
59+
check_list_result(@data, @query.root_type, selected_operation.selections)
60+
elsif @data.is_a?(Finalizer)
61+
dummy_data = {}
62+
dummy_key = "__dummy"
63+
@data.path = @query.path
64+
@data.finalize_graphql_result(@query, dummy_data, dummy_key)
65+
dummy_data[dummy_key]
66+
else
67+
raise ArgumentError, "Unexpected @data: #{@data.inspect}"
68+
end
69+
else
70+
@data
71+
end
72+
end
73+
74+
private
75+
76+
def run_finalizers(result_path, finalizer_or_finalizers, result_data, result_key)
77+
if finalizer_or_finalizers.is_a?(Array)
78+
finalizer_or_finalizers.each { |f|
79+
f.path = result_path
80+
f.finalize_graphql_result(@query, result_data, result_key)
81+
}
82+
@finalizers_count -= finalizer_or_finalizers.size
83+
else
84+
f = finalizer_or_finalizers
85+
f.path = result_path
86+
f.finalize_graphql_result(@query, result_data, result_key)
87+
@finalizers_count -= 1
88+
end
89+
end
90+
91+
def finalizers(result_value, key)
92+
finalizers_for_value = @finalizers[result_value]
93+
finalizers_for_value && finalizers_for_value[key]
94+
end
95+
96+
def check_object_result(result_h, parent_type, ast_selections)
97+
if (f = finalizers(result_h, nil))
98+
run_finalizers(@current_result_path.dup, f, result_h, nil)
99+
return result_h if @finalizers_count == 0
100+
end
101+
102+
if parent_type.kind.abstract?
103+
parent_type = @runner.runtime_type_at[result_h]
104+
end
105+
106+
ast_selections.each do |ast_selection|
107+
case ast_selection
108+
when Language::Nodes::Field
109+
key = ast_selection.alias || ast_selection.name
110+
if (f = finalizers(result_h, key))
111+
result_value = result_h[key]
112+
run_finalizers(@current_result_path.dup << key, f, result_h, key)
113+
new_result_value = result_h.key?(key) ? result_h[key] : :unassigned
114+
end
115+
next if !(f || result_h.key?(key))
116+
begin
117+
@current_exec_path << key
118+
@current_result_path << key
119+
120+
field_defn = @query.context.types.field(parent_type, ast_selection.name) || raise("Invariant: No field found for #{static_type.to_type_signature}.#{ast_selection.name}")
121+
result_type = field_defn.type
122+
if (result_type_non_null = result_type.non_null?)
123+
result_type = result_type.of_type
124+
end
125+
126+
if !f
127+
result_value = result_h[key]
128+
new_result_value = if result_type.list? && result_value
129+
check_list_result(result_value, result_type.of_type, ast_selection.selections)
130+
elsif !result_type.kind.leaf? && result_value
131+
check_object_result(result_value, result_type, ast_selection.selections)
132+
else
133+
result_value
134+
end
135+
end
136+
137+
if new_result_value.nil? && result_type_non_null
138+
return nil
139+
elsif :unassigned.equal?(new_result_value)
140+
# Do nothing
141+
break if @finalizers_count == 0
142+
elsif !new_result_value.equal?(result_value)
143+
result_h[key] = new_result_value
144+
break if @finalizers_count == 0
145+
end
146+
ensure
147+
@current_exec_path.pop
148+
@current_result_path.pop
149+
end
150+
when Language::Nodes::InlineFragment
151+
static_type_at_result = @static_type_at[result_h]
152+
if static_type_at_result && (
153+
(t = ast_selection.type).nil? ||
154+
@runner.type_condition_applies?(@query.context, static_type_at_result, t.name)
155+
)
156+
result_h = check_object_result(result_h, parent_type, ast_selection.selections)
157+
end
158+
when Language::Nodes::FragmentSpread
159+
fragment_defn = @query.document.definitions.find { |defn| defn.is_a?(Language::Nodes::FragmentDefinition) && defn.name == ast_selection.name }
160+
static_type_at_result = @static_type_at[result_h]
161+
if static_type_at_result && @runner.type_condition_applies?(@query.context, static_type_at_result, fragment_defn.type.name)
162+
result_h = check_object_result(result_h, parent_type, fragment_defn.selections)
163+
end
164+
end
165+
end
166+
167+
result_h
168+
end
169+
170+
def check_list_result(result_arr, inner_type, ast_selections)
171+
inner_type_non_null = false
172+
if inner_type.non_null?
173+
inner_type_non_null = true
174+
inner_type = inner_type.of_type
175+
end
176+
177+
new_invalid_null = false
178+
179+
if (f = finalizers(result_arr, nil))
180+
run_finalizers(@current_result_path.dup, f, result_arr, nil)
181+
return result_arr if @finalizers_count == 0
182+
end
183+
184+
result_arr.each_with_index do |result_item, idx|
185+
@current_result_path << idx
186+
new_result = if (f = finalizers(result_arr, idx))
187+
run_finalizers(@current_result_path.dup, f, result_arr, idx)
188+
result_arr[idx]
189+
elsif inner_type.list? && result_item
190+
check_list_result(result_item, inner_type.of_type, ast_selections)
191+
elsif !inner_type.kind.leaf? && result_item
192+
check_object_result(result_item, inner_type, ast_selections)
193+
else
194+
result_item
195+
end
196+
197+
if new_result.nil? && inner_type_non_null
198+
new_invalid_null = true
199+
result_arr[idx] = nil
200+
break if @finalizers_count == 0
201+
elsif !new_result.equal?(result_item)
202+
result_arr[idx] = new_result
203+
break if @finalizers_count == 0
204+
end
205+
ensure
206+
@current_result_path.pop
207+
end
208+
209+
if new_invalid_null
210+
nil
211+
else
212+
result_arr
213+
end
214+
end
215+
end
216+
end
217+
end

lib/graphql/execution/interpreter/handles_raw_value.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ module Execution
55
class Interpreter
66
# Wrapper for raw values
77
class RawValue
8-
include GraphQL::Execution::Next::Finalizer
8+
include GraphQL::Execution::Finalizer
99

1010
def finalize_graphql_result(query, result_data, result_key)
1111
result_data[result_key] = @object
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
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+
end
14+
15+
def value
16+
@loaded_value = @field_resolve_step.sync(@loaded_value)
17+
assign_value
18+
end
19+
20+
def call
21+
context = @field_resolve_step.selections_step.query.context
22+
@loaded_value = begin
23+
@load_receiver.load_and_authorize_application_object(@argument_definition, @argument_value, context)
24+
rescue GraphQL::UnauthorizedError => auth_err
25+
context.schema.unauthorized_object(auth_err)
26+
end
27+
if (runner = @field_resolve_step.runner).resolves_lazies && runner.lazy?(@loaded_value)
28+
runner.dataloader.lazy_at_depth(@field_resolve_step.path.size, self)
29+
else
30+
assign_value
31+
end
32+
rescue GraphQL::RuntimeError => err
33+
@loaded_value = err
34+
assign_value
35+
rescue StandardError => stderr
36+
@loaded_value = begin
37+
context.query.handle_or_reraise(stderr)
38+
rescue GraphQL::ExecutionError => ex_err
39+
ex_err
40+
end
41+
assign_value
42+
end
43+
44+
private
45+
46+
def assign_value
47+
if @loaded_value.is_a?(GraphQL::RuntimeError)
48+
@loaded_value.path = @field_resolve_step.path
49+
@field_resolve_step.arguments = @loaded_value
50+
else
51+
query = @field_resolve_step.selections_step.query
52+
query.current_trace.object_loaded(@argument_definition, @loaded_value, query.context)
53+
@arguments[@argument_key] = @loaded_value
54+
end
55+
56+
field_pending_steps = @field_resolve_step.pending_steps
57+
field_pending_steps.delete(self)
58+
if @field_resolve_step.arguments && field_pending_steps.size == 0 # rubocop:disable Development/ContextIsPassedCop
59+
@field_resolve_step.runner.add_step(@field_resolve_step)
60+
end
61+
end
62+
end
63+
end
64+
end

lib/graphql/execution/next.rb

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,28 @@
11
# 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/finalize"
5-
require "graphql/execution/next/load_argument_step"
6-
require "graphql/execution/next/runner"
7-
require "graphql/execution/next/selections_step"
2+
require "graphql/execution/prepare_object_step"
3+
require "graphql/execution/field_resolve_step"
4+
require "graphql/execution/finalize"
5+
require "graphql/execution/load_argument_step"
6+
require "graphql/execution/runner"
7+
require "graphql/execution/selections_step"
88
module GraphQL
99
module Execution
10+
module Finalizer
11+
attr_accessor :path
12+
def finalize_graphql_result(query, result_data, result_key)
13+
raise RequiredImplementationMissingError
14+
end
15+
end
16+
17+
module HaltExecution
18+
end
19+
20+
module PostProcessor
21+
def after_resolve(field_results)
22+
raise RequiredImplementationMissingError, "#{self.class}#after_resolve should handle `field_results` and return a new value to use"
23+
end
24+
end
25+
1026
module Next
1127
module SchemaExtension
1228
def execute_next(query_str = nil, context: nil, document: nil, operation_name: nil, variables: nil, root_value: nil, validate: true, visibility_profile: nil)
@@ -68,22 +84,6 @@ def self.run_all(schema, query_options, context: {}, max_complexity: schema.max_
6884
runner = Runner.new(multiplex, **schema.execution_next_options)
6985
runner.execute
7086
end
71-
72-
module Finalizer
73-
attr_accessor :path
74-
def finalize_graphql_result(query, result_data, result_key)
75-
raise RequiredImplementationMissingError
76-
end
77-
end
78-
79-
module HaltExecution
80-
end
81-
82-
module PostProcessor
83-
def after_resolve(field_results)
84-
raise RequiredImplementationMissingError, "#{self.class}#after_resolve should handle `field_results` and return a new value to use"
85-
end
86-
end
8787
end
8888
end
8989
end

0 commit comments

Comments
 (0)