Skip to content

Commit c08688c

Browse files
committed
Store represented_value in the result objects
1 parent 050718f commit c08688c

File tree

1 file changed

+14
-9
lines changed

1 file changed

+14
-9
lines changed

lib/graphql/execution/interpreter/runtime.rb

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,23 @@ class Interpreter
1010
class Runtime
1111

1212
module GraphQLResult
13-
def initialize(result_name, parent_result)
13+
# FIXME: storing `represented_value` here holds onto a lot of objects, keeping them from GCing and increasing peak memory.
14+
# ... but the value is only needed for lists with skippable items.
15+
# Maybe we can set to `nil` unless we know this object is a skippable list item
16+
# (i.e. a direct child of a list with `skip_items_on_raise: true`)
17+
def initialize(result_name, parent_result, represented_value)
1418
@graphql_parent = parent_result
1519
if parent_result && parent_result.graphql_dead
1620
@graphql_dead = true
1721
end
1822
@graphql_result_name = result_name
1923
# Jump through some hoops to avoid creating this duplicate storage if at all possible.
2024
@graphql_metadata = nil
25+
@represented_value = represented_value
2126
end
2227

2328
attr_accessor :graphql_dead
24-
attr_reader :graphql_parent, :graphql_result_name
29+
attr_reader :graphql_parent, :graphql_result_name, :represented_value
2530

2631
# Although these are used by only one of the Result classes,
2732
# it's handy to have the methods implemented on both (even though they just return `nil`)
@@ -48,7 +53,7 @@ def can_be_skipped?
4853
end
4954

5055
class GraphQLResultHash
51-
def initialize(_result_name, _parent_result)
56+
def initialize(_result_name, _parent_result, _represented_value)
5257
super
5358
@graphql_result_data = {}
5459
end
@@ -109,7 +114,7 @@ def [](k)
109114
class GraphQLResultArray
110115
include GraphQLResult
111116

112-
def initialize(_result_name, _parent_result)
117+
def initialize(_result_name, _parent_result, _represented_value)
113118
super
114119
@graphql_result_data = []
115120
end
@@ -177,7 +182,7 @@ def initialize(query:)
177182
@multiplex_context = query.multiplex.context
178183
# Start this off empty:
179184
Thread.current[:__graphql_runtime_info] = nil
180-
@response = GraphQLResultHash.new(nil, nil)
185+
@response = GraphQLResultHash.new(nil, nil, query.root_value)
181186
# Identify runtime directives by checking which of this schema's directives have overridden `def self.resolve`
182187
@runtime_directive_names = []
183188
noop_resolve_owner = GraphQL::Schema::Directive.singleton_class
@@ -240,7 +245,7 @@ def run_eager
240245
# directly evaluated and the results can be written right into the main response hash.
241246
tap_or_each(gathered_selections) do |selections, is_selection_array|
242247
if is_selection_array
243-
selection_response = GraphQLResultHash.new(nil, nil)
248+
selection_response = GraphQLResultHash.new(nil, nil, query.root_value)
244249
final_response = @response
245250
else
246251
selection_response = @response
@@ -773,7 +778,7 @@ def continue_field(path, value, owner_type, field, current_type, ast_node, next_
773778
after_lazy(object_proxy, owner: current_type, path: path, ast_node: ast_node, field: field, owner_object: owner_object, arguments: arguments, trace: false, result_name: result_name, result: selection_result) do |inner_object|
774779
continue_value = continue_value(path, inner_object, owner_type, field, is_non_null, ast_node, result_name, selection_result)
775780
if HALT != continue_value
776-
response_hash = GraphQLResultHash.new(result_name, selection_result)
781+
response_hash = GraphQLResultHash.new(result_name, selection_result, continue_value)
777782
set_result(selection_result, result_name, response_hash)
778783
gathered_selections = gather_selections(continue_value, current_type, next_selections)
779784
# There are two possibilities for `gathered_selections`:
@@ -786,7 +791,7 @@ def continue_field(path, value, owner_type, field, current_type, ast_node, next_
786791
# (Technically, it's possible that one of those entries _doesn't_ require isolation.)
787792
tap_or_each(gathered_selections) do |selections, is_selection_array|
788793
if is_selection_array
789-
this_result = GraphQLResultHash.new(result_name, selection_result)
794+
this_result = GraphQLResultHash.new(result_name, selection_result, continue_value)
790795
final_result = response_hash
791796
else
792797
this_result = response_hash
@@ -813,7 +818,7 @@ def continue_field(path, value, owner_type, field, current_type, ast_node, next_
813818
inner_type = current_type.of_type
814819
# This is true for objects, unions, and interfaces
815820
use_dataloader_job = !inner_type.unwrap.kind.input?
816-
response_list = GraphQLResultArray.new(result_name, selection_result)
821+
response_list = GraphQLResultArray.new(result_name, selection_result, value)
817822
response_list.graphql_non_null_list_items = inner_type.non_null?
818823
response_list.graphql_skip_list_items_that_raise = current_type.skip_nodes_on_raise?
819824
set_result(selection_result, result_name, response_list)

0 commit comments

Comments
 (0)