Skip to content

Commit 756f4e6

Browse files
committed
refactor(SerialExecution) make fewer objects
1 parent 47c4cac commit 756f4e6

File tree

5 files changed

+76
-135
lines changed

5 files changed

+76
-135
lines changed

lib/graphql/query/context.rb

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@ class Context
66
attr_accessor :execution_strategy
77

88
# @return [GraphQL::Language::Nodes::Field] The AST node for the currently-executing field
9-
attr_accessor :ast_node
9+
def ast_node
10+
irep_node.ast_node
11+
end
1012

1113
# @return [GraphQL::InternalRepresentation::Node] The internal representation for this query node
1214
attr_accessor :irep_node

lib/graphql/query/serial_execution/field_resolution.rb

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,15 @@ def get_finished_value(raw_value)
4040
end
4141
end
4242

43-
strategy_class = GraphQL::Query::SerialExecution::ValueResolution.get_strategy_for_kind(field.type.kind)
44-
result_strategy = strategy_class.new(raw_value, field.type, target, parent_type, irep_node, execution_context)
4543
begin
46-
result_strategy.result
44+
GraphQL::Query::SerialExecution::ValueResolution.resolve(
45+
parent_type,
46+
field,
47+
field.type,
48+
raw_value,
49+
irep_node,
50+
execution_context,
51+
)
4752
rescue GraphQL::InvalidNullError => err
4853
if field.type.kind.non_null?
4954
raise(err)
@@ -63,7 +68,6 @@ def get_raw_value
6368
middlewares = execution_context.query.schema.middleware
6469
query_context = execution_context.query.context
6570
# setup
66-
query_context.ast_node = @irep_node.ast_node
6771
query_context.irep_node = @irep_node
6872

6973
resolve_arguments = [parent_type, target, field, arguments, query_context]
@@ -84,7 +88,6 @@ def get_raw_value
8488
end
8589
ensure
8690
# teardown
87-
query_context.ast_node = nil
8891
query_context.irep_node = nil
8992
resolve_value
9093
end

lib/graphql/query/serial_execution/operation_resolution.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,12 @@ def initialize(irep_node, target, execution_context)
1111
end
1212

1313
def result
14-
execution_context.strategy.selection_resolution.new(
14+
execution_context.strategy.selection_resolution.resolve(
1515
execution_context.query.root_value,
1616
target,
1717
irep_node,
1818
execution_context
19-
).result
19+
)
2020
rescue GraphQL::InvalidNullError => err
2121
err.parent_error? || execution_context.add_error(err)
2222
nil

lib/graphql/query/serial_execution/selection_resolution.rb

Lines changed: 4 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,20 @@
11
module GraphQL
22
class Query
33
class SerialExecution
4-
class SelectionResolution
5-
attr_reader :target, :type, :irep_node, :execution_context
6-
7-
def initialize(target, type, irep_node, execution_context)
8-
@target = target
9-
@type = type
10-
@irep_node = irep_node
11-
@execution_context = execution_context
12-
end
13-
14-
def result
4+
module SelectionResolution
5+
def self.resolve(target, current_type, irep_node, execution_context)
156
irep_node.children.each_with_object({}) do |(name, irep_node), memo|
16-
if irep_node.included? && applies_to_type?(irep_node, type)
7+
if irep_node.included? && irep_node.definitions.any? { |potential_type, field_defn| GraphQL::Execution::Typecast.compatible?(current_type, potential_type, execution_context.query.context) }
178
field_result = execution_context.strategy.field_resolution.new(
189
irep_node,
19-
type,
10+
current_type,
2011
target,
2112
execution_context
2213
).result
2314
memo.merge!(field_result)
2415
end
2516
end
2617
end
27-
28-
private
29-
30-
def applies_to_type?(irep_node, current_type)
31-
irep_node.definitions.any? { |potential_type, field_defn|
32-
GraphQL::Execution::Typecast.compatible?(current_type, potential_type, execution_context.query.context)
33-
}
34-
end
3518
end
3619
end
3720
end

lib/graphql/query/serial_execution/value_resolution.rb

Lines changed: 59 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -2,119 +2,72 @@ module GraphQL
22
class Query
33
class SerialExecution
44
module ValueResolution
5-
def self.get_strategy_for_kind(kind)
6-
TYPE_KIND_STRATEGIES[kind] || raise("No value resolution strategy for #{kind}!")
7-
end
8-
9-
class BaseResolution
10-
attr_reader :value, :field_type, :target, :parent_type,
11-
:irep_node, :execution_context
12-
def initialize(value, field_type, target, parent_type, irep_node, execution_context)
13-
@value = value
14-
@field_type = field_type
15-
@target = target
16-
@parent_type = parent_type
17-
@irep_node = irep_node
18-
@execution_context = execution_context
19-
end
20-
21-
def result
22-
if value.nil? || value.is_a?(GraphQL::ExecutionError)
23-
nil
5+
def self.resolve(parent_type, field_defn, field_type, value, irep_node, execution_context)
6+
if value.nil? || value.is_a?(GraphQL::ExecutionError)
7+
if field_type.kind.non_null?
8+
raise GraphQL::InvalidNullError.new(parent_type.name, field_defn.name, value)
249
else
25-
non_null_result
26-
end
27-
end
28-
29-
def non_null_result
30-
raise NotImplementedError, "Should return a value based on initialization params"
31-
end
32-
33-
def get_strategy_for_kind(*args)
34-
GraphQL::Query::SerialExecution::ValueResolution.get_strategy_for_kind(*args)
35-
end
36-
end
37-
38-
class ScalarResolution < BaseResolution
39-
# Apply the scalar's defined `coerce_result` method to the value
40-
def non_null_result
41-
field_type.coerce_result(value)
42-
end
43-
end
44-
45-
class EnumResolution < BaseResolution
46-
# Pick an enum value, but make sure it's allowed
47-
def non_null_result
48-
field_type.coerce_result(value, execution_context.query.warden)
49-
end
50-
end
51-
52-
class ListResolution < BaseResolution
53-
# For each item in the list,
54-
# Resolve it with the "wrapped" type of this list
55-
def non_null_result
56-
wrapped_type = field_type.of_type
57-
strategy_class = get_strategy_for_kind(wrapped_type.kind)
58-
result = value.each_with_index.map do |item, index|
59-
irep_node.index = index
60-
inner_strategy = strategy_class.new(item, wrapped_type, target, parent_type, irep_node, execution_context)
61-
inner_strategy.result
62-
end
63-
irep_node.index = nil
64-
result
65-
end
66-
end
67-
68-
class HasPossibleTypeResolution < BaseResolution
69-
def non_null_result
70-
resolved_type = execution_context.schema.resolve_type(value, execution_context.query.context)
71-
possible_types = execution_context.possible_types(field_type)
72-
73-
if !possible_types.include?(resolved_type)
74-
raise GraphQL::UnresolvedTypeError.new(irep_node.definition_name, field_type, parent_type, resolved_type, possible_types)
10+
nil
7511
end
12+
else
13+
case field_type.kind
14+
when GraphQL::TypeKinds::SCALAR
15+
field_type.coerce_result(value)
16+
when GraphQL::TypeKinds::ENUM
17+
field_type.coerce_result(value, execution_context.query.warden)
18+
when GraphQL::TypeKinds::LIST
19+
wrapped_type = field_type.of_type
20+
result = value.each_with_index.map do |inner_value, index|
21+
irep_node.index = index
22+
resolve(
23+
parent_type,
24+
field_defn,
25+
wrapped_type,
26+
inner_value,
27+
irep_node,
28+
execution_context,
29+
)
30+
end
31+
irep_node.index = nil
32+
result
33+
when GraphQL::TypeKinds::NON_NULL
34+
wrapped_type = field_type.of_type
35+
resolve(
36+
parent_type,
37+
field_defn,
38+
wrapped_type,
39+
value,
40+
irep_node,
41+
execution_context,
42+
)
43+
when GraphQL::TypeKinds::OBJECT
44+
execution_context.strategy.selection_resolution.resolve(
45+
value,
46+
field_type,
47+
irep_node,
48+
execution_context
49+
)
50+
when GraphQL::TypeKinds::UNION, GraphQL::TypeKinds::INTERFACE
51+
resolved_type = execution_context.schema.resolve_type(value, execution_context.query.context)
52+
possible_types = execution_context.possible_types(field_type)
7653

77-
strategy_class = get_strategy_for_kind(resolved_type.kind)
78-
inner_strategy = strategy_class.new(value, resolved_type, target, parent_type, irep_node, execution_context)
79-
inner_strategy.result
80-
end
81-
end
82-
83-
class ObjectResolution < BaseResolution
84-
# Resolve the selections on this object
85-
def non_null_result
86-
execution_context.strategy.selection_resolution.new(
87-
value,
88-
field_type,
89-
irep_node,
90-
execution_context
91-
).result
92-
end
93-
end
94-
95-
class NonNullResolution < BaseResolution
96-
# Get the "wrapped" type and resolve the value according to that type
97-
def result
98-
if value.nil? || value.is_a?(GraphQL::ExecutionError)
99-
raise GraphQL::InvalidNullError.new(parent_type.name, irep_node.definition_name, value)
54+
if !possible_types.include?(resolved_type)
55+
raise GraphQL::UnresolvedTypeError.new(irep_node.definition_name, field_type, parent_type, resolved_type, possible_types)
56+
else
57+
resolve(
58+
parent_type,
59+
field_defn,
60+
resolved_type,
61+
value,
62+
irep_node,
63+
execution_context,
64+
)
65+
end
10066
else
101-
wrapped_type = field_type.of_type
102-
strategy_class = get_strategy_for_kind(wrapped_type.kind)
103-
inner_strategy = strategy_class.new(value, wrapped_type, target, parent_type, irep_node, execution_context)
104-
inner_strategy.result
67+
raise("Unknown type kind: #{field_type.kind}")
10568
end
10669
end
10770
end
108-
109-
TYPE_KIND_STRATEGIES = {
110-
GraphQL::TypeKinds::SCALAR => ScalarResolution,
111-
GraphQL::TypeKinds::LIST => ListResolution,
112-
GraphQL::TypeKinds::OBJECT => ObjectResolution,
113-
GraphQL::TypeKinds::ENUM => EnumResolution,
114-
GraphQL::TypeKinds::NON_NULL => NonNullResolution,
115-
GraphQL::TypeKinds::INTERFACE => HasPossibleTypeResolution,
116-
GraphQL::TypeKinds::UNION => HasPossibleTypeResolution,
117-
}
11871
end
11972
end
12073
end

0 commit comments

Comments
 (0)