Skip to content

Commit 4dab451

Browse files
committed
Sketch out custom nodes
1 parent f2bd902 commit 4dab451

File tree

2 files changed

+78
-55
lines changed

2 files changed

+78
-55
lines changed

lib/graphql/execution/interpreter/runtime.rb

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -123,14 +123,14 @@ def run_eager
123123
case inner_type.kind.name
124124
when "SCALAR", "ENUM"
125125
result_name = ast_node.alias || ast_node.name
126-
owner_type = query.field_definition.owner
126+
field_defn = query.field_definition
127+
owner_type = field_defn.owner
127128
selection_result = GraphQLResultHash.new(nil, owner_type, nil, nil, false, EmptyObjects::EMPTY_ARRAY, false, ast_node, nil, nil)
128129
selection_result.base_path = base_path
129130
selection_result.ordered_result_keys = [result_name]
130131
runtime_state = get_current_runtime_state
131132
runtime_state.current_result = selection_result
132133
runtime_state.current_result_name = result_name
133-
field_defn = query.field_definition
134134
continue_value = continue_value(object, field_defn, false, ast_node, result_name, selection_result)
135135
if HALT != continue_value
136136
continue_field(continue_value, owner_type, field_defn, root_type, ast_node, nil, false, nil, nil, result_name, selection_result, false, runtime_state) # rubocop:disable Metrics/ParameterLists
@@ -156,14 +156,14 @@ def run_eager
156156
end
157157
when "SCALAR", "ENUM"
158158
result_name = ast_node.alias || ast_node.name
159-
owner_type = query.field_definition.owner
160-
selection_result = GraphQLResultHash.new(nil, query.parent_type, nil, nil, false, EmptyObjects::EMPTY_ARRAY, false, ast_node, nil, nil)
159+
field_defn = query.field_definition
160+
owner_type = field_defn.owner
161+
selection_result = GraphQLResultHash.new(nil, owner_type, nil, nil, false, EmptyObjects::EMPTY_ARRAY, false, ast_node, nil, nil)
161162
selection_result.ordered_result_keys = [result_name]
162163
selection_result.base_path = base_path
163164
runtime_state = get_current_runtime_state
164165
runtime_state.current_result = selection_result
165166
runtime_state.current_result_name = result_name
166-
field_defn = query.field_definition
167167
continue_value = continue_value(object, field_defn, false, ast_node, result_name, selection_result)
168168
if HALT != continue_value
169169
continue_field(continue_value, owner_type, field_defn, query.root_type, ast_node, nil, false, nil, nil, result_name, selection_result, false, runtime_state) # rubocop:disable Metrics/ParameterLists

lib/graphql/query/partial.rb

Lines changed: 73 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ class Partial
1818
# @param object [Object] A starting object for execution
1919
# @param query [GraphQL::Query] A full query instance that this partial is based on. Caches are shared.
2020
# @param context [Hash] Extra context values to merge into `query.context`, if provided
21-
def initialize(path:, object:, query:, context: nil)
21+
def initialize(path:, object:, query:, context: nil, node: nil)
2222
@path = path
2323
@object = object
2424
@query = query
@@ -31,65 +31,31 @@ def initialize(path:, object:, query:, context: nil)
3131
@multiplex = nil
3232
@result_values = nil
3333
@result = nil
34-
selections = [@query.selected_operation]
35-
type = @query.root_type
36-
parent_type = nil
37-
field_defn = nil
38-
@path.each do |name_in_doc|
39-
if name_in_doc.is_a?(Integer)
40-
if type.list?
41-
type = type.unwrap
42-
next
43-
else
44-
raise ArgumentError, "Received path with index `#{name_in_doc}`, but type wasn't a list. Type: #{type.to_type_signature}, path: #{@path}"
45-
end
46-
end
47-
48-
next_selections = []
49-
selections.each do |selection|
50-
selections_to_check = []
51-
selections_to_check.concat(selection.selections)
52-
while (sel = selections_to_check.shift)
53-
case sel
54-
when GraphQL::Language::Nodes::InlineFragment
55-
selections_to_check.concat(sel.selections)
56-
when GraphQL::Language::Nodes::FragmentSpread
57-
fragment = @query.fragments[sel.name]
58-
selections_to_check.concat(fragment.selections)
59-
when GraphQL::Language::Nodes::Field
60-
if sel.alias == name_in_doc || sel.name == name_in_doc
61-
next_selections << sel
62-
end
63-
else
64-
raise "Unexpected selection in partial path: #{sel.class}, #{sel.inspect}"
65-
end
66-
end
67-
end
6834

69-
if next_selections.empty?
70-
raise ArgumentError, "Path `#{@path.inspect}` is not present in this query. `#{name_in_doc.inspect}` was not found. Try a different path or rewrite the query to include it."
71-
end
72-
field_name = next_selections.first.name
73-
field_defn = @schema.get_field(type, field_name, @query.context) || raise("Invariant: no field called #{field_name} on #{type.graphql_name}")
74-
parent_type = type
75-
type = field_defn.type
76-
if type.non_null?
77-
type = type.of_type
35+
if node && type
36+
@ast_nodes = case node
37+
when GraphQL::Language::Nodes::Field
38+
[node]
39+
when GraphQL::Language::Nodes::InlineFragment, GraphQL::Language::Nodes::FragmentDefinition
40+
node.selections
41+
else
42+
raise ArgumentError, "AST node not supported by Query::Partial"
7843
end
79-
selections = next_selections
44+
@root_type = type
45+
# This is only used when `@leaf` -- probably could be based on `node`
46+
@field_definition = nil
47+
else
48+
set_type_info_from_path
8049
end
81-
@parent_type = parent_type
82-
@ast_nodes = selections
83-
@root_type = type
84-
@field_definition = field_defn
50+
8551
@leaf = @root_type.unwrap.kind.leaf?
8652
end
8753

8854
def leaf?
8955
@leaf
9056
end
9157

92-
attr_reader :context, :query, :ast_nodes, :root_type, :object, :field_definition, :path, :parent_type, :schema
58+
attr_reader :context, :query, :ast_nodes, :root_type, :object, :field_definition, :path, :schema
9359

9460
attr_accessor :multiplex, :result_values
9561

@@ -155,6 +121,63 @@ def static_errors
155121
def selected_operation_name
156122
@query.selected_operation_name
157123
end
124+
125+
private
126+
127+
def set_type_info_from_path
128+
selections = [@query.selected_operation]
129+
type = @query.root_type
130+
parent_type = nil
131+
field_defn = nil
132+
133+
@path.each do |name_in_doc|
134+
if name_in_doc.is_a?(Integer)
135+
if type.list?
136+
type = type.unwrap
137+
next
138+
else
139+
raise ArgumentError, "Received path with index `#{name_in_doc}`, but type wasn't a list. Type: #{type.to_type_signature}, path: #{@path}"
140+
end
141+
end
142+
143+
next_selections = []
144+
selections.each do |selection|
145+
selections_to_check = []
146+
selections_to_check.concat(selection.selections)
147+
while (sel = selections_to_check.shift)
148+
case sel
149+
when GraphQL::Language::Nodes::InlineFragment
150+
selections_to_check.concat(sel.selections)
151+
when GraphQL::Language::Nodes::FragmentSpread
152+
fragment = @query.fragments[sel.name]
153+
selections_to_check.concat(fragment.selections)
154+
when GraphQL::Language::Nodes::Field
155+
if sel.alias == name_in_doc || sel.name == name_in_doc
156+
next_selections << sel
157+
end
158+
else
159+
raise "Unexpected selection in partial path: #{sel.class}, #{sel.inspect}"
160+
end
161+
end
162+
end
163+
164+
if next_selections.empty?
165+
raise ArgumentError, "Path `#{@path.inspect}` is not present in this query. `#{name_in_doc.inspect}` was not found. Try a different path or rewrite the query to include it."
166+
end
167+
field_name = next_selections.first.name
168+
field_defn = @schema.get_field(type, field_name, @query.context) || raise("Invariant: no field called #{field_name} on #{type.graphql_name}")
169+
parent_type = type
170+
type = field_defn.type
171+
if type.non_null?
172+
type = type.of_type
173+
end
174+
selections = next_selections
175+
end
176+
177+
@ast_nodes = selections
178+
@root_type = type
179+
@field_definition = field_defn
180+
end
158181
end
159182
end
160183
end

0 commit comments

Comments
 (0)