graphql 1.5.3 → 1.5.4
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.
- checksums.yaml +4 -4
- data/lib/graphql/define/assign_enum_value.rb +1 -1
- data/lib/graphql/execution/directive_checks.rb +5 -5
- data/lib/graphql/internal_representation.rb +1 -0
- data/lib/graphql/internal_representation/node.rb +117 -16
- data/lib/graphql/internal_representation/rewrite.rb +39 -94
- data/lib/graphql/internal_representation/scope.rb +88 -0
- data/lib/graphql/introspection/schema_field.rb +5 -10
- data/lib/graphql/introspection/type_by_name_field.rb +8 -13
- data/lib/graphql/introspection/typename_field.rb +5 -10
- data/lib/graphql/query.rb +24 -155
- data/lib/graphql/query/arguments_cache.rb +25 -0
- data/lib/graphql/query/validation_pipeline.rb +114 -0
- data/lib/graphql/query/variables.rb +18 -14
- data/lib/graphql/schema.rb +4 -3
- data/lib/graphql/schema/mask.rb +55 -0
- data/lib/graphql/schema/possible_types.rb +2 -2
- data/lib/graphql/schema/type_expression.rb +19 -4
- data/lib/graphql/schema/warden.rb +1 -3
- data/lib/graphql/static_validation/rules/fields_will_merge.rb +3 -2
- data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +4 -2
- data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +3 -1
- data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +1 -20
- data/lib/graphql/static_validation/validation_context.rb +6 -18
- data/lib/graphql/version.rb +1 -1
- data/spec/graphql/enum_type_spec.rb +12 -0
- data/spec/graphql/internal_representation/rewrite_spec.rb +26 -5
- data/spec/graphql/query_spec.rb +23 -3
- data/spec/graphql/static_validation/rules/fields_will_merge_spec.rb +2 -2
- data/spec/graphql/static_validation/rules/variable_default_values_are_correctly_typed_spec.rb +12 -0
- data/spec/graphql/static_validation/rules/variables_are_input_types_spec.rb +14 -0
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: eacb69bcf39a028dc32debd2a0f266a6f920fd3d
|
4
|
+
data.tar.gz: 921436c519b6b6b8aff3e4dc03845f8d6108a275
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b8e1d965b82383e8cee0423fa06b7f20ea5fde13bedb8e9cd2316686c7f7e72dd409a55667b81ea9f0e502906bee45e7957cbdd79c44e96618a405bebf81fc98
|
7
|
+
data.tar.gz: 56c92576bee82ce626d332df1070079579c02007ad78718831301de4c815a6d61c57a17464e71498d9e6a4c51412e80de50e2090aca40fed8266b282b6c12a58
|
@@ -5,7 +5,7 @@ module GraphQL
|
|
5
5
|
module AssignEnumValue
|
6
6
|
def self.call(enum_type, name, desc = nil, deprecation_reason: nil, value: name, &block)
|
7
7
|
enum_value = GraphQL::EnumType::EnumValue.define(
|
8
|
-
name: name,
|
8
|
+
name: name.to_s,
|
9
9
|
description: desc,
|
10
10
|
deprecation_reason: deprecation_reason,
|
11
11
|
value: value,
|
@@ -11,18 +11,18 @@ module GraphQL
|
|
11
11
|
module_function
|
12
12
|
|
13
13
|
# @return [Boolean] Should this node be included in the query?
|
14
|
-
def include?(
|
15
|
-
|
16
|
-
name =
|
14
|
+
def include?(directive_ast_nodes, query)
|
15
|
+
directive_ast_nodes.each do |directive_ast_node|
|
16
|
+
name = directive_ast_node.name
|
17
17
|
directive_defn = query.schema.directives[name]
|
18
18
|
case name
|
19
19
|
when SKIP
|
20
|
-
args = query.arguments_for(
|
20
|
+
args = query.arguments_for(directive_ast_node, directive_defn)
|
21
21
|
if args['if'] == true
|
22
22
|
return false
|
23
23
|
end
|
24
24
|
when INCLUDE
|
25
|
-
args = query.arguments_for(
|
25
|
+
args = query.arguments_for(directive_ast_node, directive_defn)
|
26
26
|
if args['if'] == false
|
27
27
|
return false
|
28
28
|
end
|
@@ -8,42 +8,92 @@ module GraphQL
|
|
8
8
|
# @return [GraphQL::ObjectType]
|
9
9
|
attr_reader :owner_type
|
10
10
|
|
11
|
-
#
|
12
|
-
|
13
|
-
|
14
|
-
#
|
15
|
-
|
16
|
-
|
11
|
+
# Each key is a {GraphQL::ObjectType} which this selection _may_ be made on.
|
12
|
+
# The values for that key are selections which apply to that type.
|
13
|
+
#
|
14
|
+
# This value is derived from {#scoped_children} after the rewrite is finished.
|
15
|
+
# @return [Hash<GraphQL::ObjectType, Hash<String => Node>>]
|
16
|
+
def typed_children
|
17
|
+
@typed_childen ||= begin
|
18
|
+
new_tc = Hash.new { |h, k| h[k] = {} }
|
19
|
+
if @scoped_children.any?
|
20
|
+
all_object_types = Set.new
|
21
|
+
scoped_children.each_key { |t| all_object_types.merge(@query.possible_types(t)) }
|
22
|
+
all_object_types.each do |t|
|
23
|
+
new_tc[t] = get_typed_children(t)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
new_tc
|
27
|
+
end
|
17
28
|
end
|
18
29
|
|
19
|
-
#
|
20
|
-
|
21
|
-
|
22
|
-
|
30
|
+
# These children correspond closely to scopes in the AST.
|
31
|
+
# Keys _may_ be abstract types. They're assumed to be read-only after rewrite is finished
|
32
|
+
# because {#typed_children} is derived from them.
|
33
|
+
#
|
34
|
+
# Using {#scoped_children} during the rewrite step reduces the overhead of reifying
|
35
|
+
# abstract types because they're only reified _after_ the rewrite.
|
36
|
+
# @return [Hash<GraphQL::BaseType, Hash<String => Node>>]
|
37
|
+
attr_reader :scoped_children
|
38
|
+
|
39
|
+
# @return [Array<Language::Nodes::AbstractNode>] AST nodes which are represented by this node
|
40
|
+
attr_reader :ast_nodes
|
41
|
+
|
42
|
+
# @return [Array<GraphQL::Field>] Field definitions for this node (there should only be one!)
|
43
|
+
attr_reader :definitions
|
23
44
|
|
24
45
|
# @return [GraphQL::BaseType]
|
25
46
|
attr_reader :return_type
|
26
47
|
|
48
|
+
# @return [InternalRepresentation::Node, nil]
|
49
|
+
attr_reader :parent
|
50
|
+
|
27
51
|
def initialize(
|
28
|
-
name:, owner_type:, query:, return_type:,
|
29
|
-
ast_nodes:
|
30
|
-
definitions:
|
52
|
+
name:, owner_type:, query:, return_type:, parent:,
|
53
|
+
ast_nodes: [],
|
54
|
+
definitions: []
|
31
55
|
)
|
32
56
|
@name = name
|
33
57
|
@query = query
|
34
58
|
@owner_type = owner_type
|
35
|
-
@
|
59
|
+
@parent = parent
|
60
|
+
@typed_children = nil
|
61
|
+
@scoped_children = Hash.new { |h1, k1| h1[k1] = {} }
|
36
62
|
@ast_nodes = ast_nodes
|
37
63
|
@definitions = definitions
|
38
64
|
@return_type = return_type
|
39
65
|
end
|
40
66
|
|
67
|
+
def initialize_copy(other_node)
|
68
|
+
super
|
69
|
+
# Bust some caches:
|
70
|
+
@typed_children = nil
|
71
|
+
@definition = nil
|
72
|
+
@definition_name = nil
|
73
|
+
@ast_node = nil
|
74
|
+
# Shallow-copy some state:
|
75
|
+
@scoped_children = other_node.scoped_children.dup
|
76
|
+
@ast_nodes = other_node.ast_nodes.dup
|
77
|
+
@definitions = other_node.definitions.dup
|
78
|
+
end
|
79
|
+
|
80
|
+
def ==(other)
|
81
|
+
other.is_a?(self.class) &&
|
82
|
+
other.name == name &&
|
83
|
+
other.parent == parent &&
|
84
|
+
other.return_type == return_type &&
|
85
|
+
other.owner_type == owner_type &&
|
86
|
+
other.scoped_children == scoped_children &&
|
87
|
+
other.definitions == definitions &&
|
88
|
+
other.ast_nodes == ast_nodes
|
89
|
+
end
|
90
|
+
|
41
91
|
def definition_name
|
42
92
|
@definition_name ||= definition.name
|
43
93
|
end
|
44
94
|
|
45
95
|
def definition
|
46
|
-
@definition ||= definitions.first
|
96
|
+
@definition ||= @query.get_field(@owner_type, @definitions.first.name)
|
47
97
|
end
|
48
98
|
|
49
99
|
def ast_node
|
@@ -51,7 +101,58 @@ module GraphQL
|
|
51
101
|
end
|
52
102
|
|
53
103
|
def inspect
|
54
|
-
|
104
|
+
all_children_names = scoped_children.values.map(&:keys).flatten.uniq.join(", ")
|
105
|
+
all_locations = ast_nodes.map {|n| "#{n.line}:#{n.col}" }.join(", ")
|
106
|
+
"#<Node #{@owner_type}.#{@name} -> #{@return_type} {#{all_children_names}} @ [#{all_locations}] #{object_id}>"
|
107
|
+
end
|
108
|
+
|
109
|
+
# Merge selections from `new_parent` into `self`.
|
110
|
+
# Selections are merged in place, not copied.
|
111
|
+
def deep_merge_node(new_parent, merge_self: true)
|
112
|
+
if merge_self
|
113
|
+
@ast_nodes.concat(new_parent.ast_nodes)
|
114
|
+
@definitions.concat(new_parent.definitions)
|
115
|
+
end
|
116
|
+
new_parent.scoped_children.each do |obj_type, new_fields|
|
117
|
+
prev_fields = @scoped_children[obj_type]
|
118
|
+
new_fields.each do |name, new_node|
|
119
|
+
prev_node = prev_fields[name]
|
120
|
+
if prev_node
|
121
|
+
prev_node.deep_merge_node(new_node)
|
122
|
+
else
|
123
|
+
prev_fields[name] = new_node
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
protected
|
130
|
+
|
131
|
+
attr_writer :owner_type, :parent
|
132
|
+
|
133
|
+
private
|
134
|
+
|
135
|
+
# Get applicable children from {#scoped_children}
|
136
|
+
# @param obj_type [GraphQL::ObjectType]
|
137
|
+
# @return [Hash<String => Node>]
|
138
|
+
def get_typed_children(obj_type)
|
139
|
+
new_tc = {}
|
140
|
+
@scoped_children.each do |scope_type, scope_nodes|
|
141
|
+
if GraphQL::Execution::Typecast.subtype?(scope_type, obj_type)
|
142
|
+
scope_nodes.each do |name, new_node|
|
143
|
+
prev_node = new_tc[name]
|
144
|
+
if prev_node
|
145
|
+
prev_node.deep_merge_node(new_node)
|
146
|
+
else
|
147
|
+
copied_node = new_node.dup
|
148
|
+
copied_node.owner_type = obj_type
|
149
|
+
copied_node.parent = self
|
150
|
+
new_tc[name] = copied_node
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
new_tc
|
55
156
|
end
|
56
157
|
end
|
57
158
|
end
|
@@ -34,17 +34,17 @@ module GraphQL
|
|
34
34
|
# Array<Set<InternalRepresentation::Node>>
|
35
35
|
# The current point of the irep_tree during visitation
|
36
36
|
nodes_stack = []
|
37
|
-
# Array<
|
38
|
-
|
39
|
-
|
37
|
+
# Array<Scope>
|
38
|
+
scopes_stack = []
|
39
|
+
|
40
40
|
fragment_definitions = {}
|
41
41
|
skip_nodes = Set.new
|
42
42
|
|
43
|
-
visit_op = VisitDefinition.new(context, @operations, nodes_stack,
|
43
|
+
visit_op = VisitDefinition.new(context, @operations, nodes_stack, scopes_stack)
|
44
44
|
visitor[Nodes::OperationDefinition].enter << visit_op.method(:enter)
|
45
45
|
visitor[Nodes::OperationDefinition].leave << visit_op.method(:leave)
|
46
46
|
|
47
|
-
visit_frag = VisitDefinition.new(context, fragment_definitions, nodes_stack,
|
47
|
+
visit_frag = VisitDefinition.new(context, fragment_definitions, nodes_stack, scopes_stack)
|
48
48
|
visitor[Nodes::FragmentDefinition].enter << visit_frag.method(:enter)
|
49
49
|
visitor[Nodes::FragmentDefinition].leave << visit_frag.method(:leave)
|
50
50
|
|
@@ -52,28 +52,18 @@ module GraphQL
|
|
52
52
|
# Inline fragments provide two things to the rewritten tree:
|
53
53
|
# - They _may_ narrow the scope by their type condition
|
54
54
|
# - They _may_ apply their directives to their children
|
55
|
-
|
56
55
|
if skip?(ast_node, query)
|
57
56
|
skip_nodes.add(ast_node)
|
58
57
|
end
|
59
58
|
|
60
59
|
if skip_nodes.none?
|
61
|
-
|
62
|
-
prev_scope = scope_stack.last
|
63
|
-
each_type(query, context.type_definition) do |obj_type|
|
64
|
-
# What this fragment can apply to is also determined by
|
65
|
-
# the scope around it (it can't widen the scope)
|
66
|
-
if prev_scope.include?(obj_type)
|
67
|
-
next_scope.add(obj_type)
|
68
|
-
end
|
69
|
-
end
|
70
|
-
scope_stack.push(next_scope)
|
60
|
+
scopes_stack.push(scopes_stack.last.enter(context.type_definition))
|
71
61
|
end
|
72
62
|
}
|
73
63
|
|
74
64
|
visitor[Nodes::InlineFragment].leave << ->(ast_node, ast_parent) {
|
75
65
|
if skip_nodes.none?
|
76
|
-
|
66
|
+
scopes_stack.pop
|
77
67
|
end
|
78
68
|
|
79
69
|
if skip_nodes.include?(ast_node)
|
@@ -90,42 +80,39 @@ module GraphQL
|
|
90
80
|
node_name = ast_node.alias || ast_node.name
|
91
81
|
parent_nodes = nodes_stack.last
|
92
82
|
next_nodes = []
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
# It's a non-existent field
|
102
|
-
else
|
103
|
-
field_return_type = field_defn.type.unwrap
|
104
|
-
each_type(query, field_return_type) do |obj_type|
|
105
|
-
next_scope.add(obj_type)
|
106
|
-
end
|
83
|
+
|
84
|
+
field_defn = context.field_definition
|
85
|
+
if field_defn.nil?
|
86
|
+
# It's a non-existent field
|
87
|
+
new_scope = nil
|
88
|
+
else
|
89
|
+
field_return_type = field_defn.type.unwrap
|
90
|
+
scopes_stack.last.each do |scope_type|
|
107
91
|
parent_nodes.each do |parent_node|
|
108
|
-
node = parent_node.
|
92
|
+
node = parent_node.scoped_children[scope_type][node_name] ||= Node.new(
|
93
|
+
parent: parent_node,
|
109
94
|
name: node_name,
|
110
|
-
owner_type:
|
95
|
+
owner_type: scope_type,
|
111
96
|
query: query,
|
112
97
|
return_type: field_return_type,
|
113
98
|
)
|
114
|
-
node.ast_nodes
|
115
|
-
node.definitions
|
99
|
+
node.ast_nodes << ast_node
|
100
|
+
node.definitions << field_defn
|
116
101
|
next_nodes << node
|
117
102
|
end
|
118
103
|
end
|
104
|
+
new_scope = Scope.new(query, field_return_type)
|
119
105
|
end
|
106
|
+
|
120
107
|
nodes_stack.push(next_nodes)
|
121
|
-
|
108
|
+
scopes_stack.push(new_scope)
|
122
109
|
end
|
123
110
|
}
|
124
111
|
|
125
112
|
visitor[Nodes::Field].leave << ->(ast_node, ast_parent) {
|
126
113
|
if skip_nodes.none?
|
127
114
|
nodes_stack.pop
|
128
|
-
|
115
|
+
scopes_stack.pop
|
129
116
|
end
|
130
117
|
|
131
118
|
if skip_nodes.include?(ast_node)
|
@@ -147,97 +134,55 @@ module GraphQL
|
|
147
134
|
# can be shared between its usages.
|
148
135
|
context.on_dependency_resolve do |defn_ast_node, spread_ast_nodes, frag_ast_node|
|
149
136
|
frag_name = frag_ast_node.name
|
150
|
-
|
151
|
-
parent_nodes = spread_parents[spread_ast_node]
|
152
|
-
parent_nodes.each do |parent_node|
|
153
|
-
fragment_node = fragment_definitions[frag_name]
|
154
|
-
if fragment_node
|
155
|
-
deep_merge_selections(query, parent_node, fragment_node)
|
156
|
-
end
|
157
|
-
end
|
158
|
-
end
|
159
|
-
end
|
160
|
-
end
|
137
|
+
fragment_node = fragment_definitions[frag_name]
|
161
138
|
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
new_fields.each do |name, new_node|
|
169
|
-
prev_node = prev_fields[name]
|
170
|
-
if prev_node
|
171
|
-
prev_node.ast_nodes.merge(new_node.ast_nodes)
|
172
|
-
prev_node.definitions.merge(new_node.definitions)
|
173
|
-
deep_merge_selections(query, prev_node, new_node)
|
174
|
-
else
|
175
|
-
prev_fields[name] = new_node
|
139
|
+
if fragment_node
|
140
|
+
spread_ast_nodes.each do |spread_ast_node|
|
141
|
+
parent_nodes = spread_parents[spread_ast_node]
|
142
|
+
parent_nodes.each do |parent_node|
|
143
|
+
parent_node.deep_merge_node(fragment_node, merge_self: false)
|
144
|
+
end
|
176
145
|
end
|
177
146
|
end
|
178
147
|
end
|
179
148
|
end
|
180
149
|
|
181
|
-
# @see {.each_type}
|
182
|
-
def each_type(query, owner_type, &block)
|
183
|
-
self.class.each_type(query, owner_type, &block)
|
184
|
-
end
|
185
|
-
|
186
|
-
# Call the block for each of `owner_type`'s possible types
|
187
|
-
def self.each_type(query, owner_type)
|
188
|
-
case owner_type
|
189
|
-
when GraphQL::ObjectType, GraphQL::ScalarType, GraphQL::EnumType
|
190
|
-
yield(owner_type)
|
191
|
-
when GraphQL::UnionType, GraphQL::InterfaceType
|
192
|
-
query.possible_types(owner_type).each(&Proc.new)
|
193
|
-
when GraphQL::InputObjectType, nil
|
194
|
-
# this is an error, don't give 'em nothin
|
195
|
-
else
|
196
|
-
raise "Unexpected owner type: #{owner_type.inspect}"
|
197
|
-
end
|
198
|
-
end
|
199
|
-
|
200
150
|
def skip?(ast_node, query)
|
201
151
|
dir = ast_node.directives
|
202
152
|
dir.any? && !GraphQL::Execution::DirectiveChecks.include?(dir, query)
|
203
153
|
end
|
204
154
|
|
205
155
|
class VisitDefinition
|
206
|
-
def initialize(context, definitions, nodes_stack,
|
156
|
+
def initialize(context, definitions, nodes_stack, scopes_stack)
|
207
157
|
@context = context
|
208
158
|
@query = context.query
|
209
159
|
@definitions = definitions
|
210
160
|
@nodes_stack = nodes_stack
|
211
|
-
@
|
161
|
+
@scopes_stack = scopes_stack
|
212
162
|
end
|
213
163
|
|
214
164
|
def enter(ast_node, ast_parent)
|
215
165
|
# Either QueryType or the fragment type condition
|
216
166
|
owner_type = @context.type_definition && @context.type_definition.unwrap
|
217
|
-
next_nodes = []
|
218
|
-
next_scope = Set.new
|
219
167
|
defn_name = ast_node.name
|
220
|
-
Rewrite.each_type(@query, owner_type) do |obj_type|
|
221
|
-
next_scope.add(obj_type)
|
222
|
-
end
|
223
168
|
|
224
169
|
node = Node.new(
|
170
|
+
parent: nil,
|
225
171
|
name: defn_name,
|
226
172
|
owner_type: owner_type,
|
227
173
|
query: @query,
|
228
|
-
ast_nodes:
|
174
|
+
ast_nodes: [ast_node],
|
229
175
|
return_type: owner_type,
|
230
176
|
)
|
231
|
-
@definitions[defn_name] = node
|
232
|
-
next_nodes << node
|
233
177
|
|
234
|
-
@
|
235
|
-
@
|
178
|
+
@definitions[defn_name] = node
|
179
|
+
@scopes_stack.push(Scope.new(@query, owner_type))
|
180
|
+
@nodes_stack.push([node])
|
236
181
|
end
|
237
182
|
|
238
183
|
def leave(ast_node, ast_parent)
|
239
184
|
@nodes_stack.pop
|
240
|
-
@
|
185
|
+
@scopes_stack.pop
|
241
186
|
end
|
242
187
|
end
|
243
188
|
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module GraphQL
|
3
|
+
module InternalRepresentation
|
4
|
+
# At a point in the AST, selections may apply to one or more types.
|
5
|
+
# {Scope} represents those types which selections may apply to.
|
6
|
+
#
|
7
|
+
# Scopes can be defined by:
|
8
|
+
#
|
9
|
+
# - A single concrete or abstract type
|
10
|
+
# - An array of types
|
11
|
+
# - `nil`
|
12
|
+
#
|
13
|
+
# The AST may be scoped to an array of types when two abstractly-typed
|
14
|
+
# fragments occur in inside one another.
|
15
|
+
class Scope
|
16
|
+
NO_TYPES = [].freeze
|
17
|
+
|
18
|
+
# @param query [GraphQL::Query]
|
19
|
+
# @param type_defn [GraphQL::BaseType, Array<GraphQL::BaseType>, nil]
|
20
|
+
def initialize(query, type_defn)
|
21
|
+
@query = query
|
22
|
+
@type = type_defn
|
23
|
+
@abstract_type = false
|
24
|
+
@types = case type_defn
|
25
|
+
when Array
|
26
|
+
type_defn
|
27
|
+
when GraphQL::BaseType
|
28
|
+
@abstract_type = true
|
29
|
+
nil
|
30
|
+
when nil
|
31
|
+
NO_TYPES
|
32
|
+
else
|
33
|
+
raise "Unexpected scope type: #{type_defn}"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# From a starting point of `self`, create a new scope by condition `other_type_defn`.
|
38
|
+
# @param other_type_defn [GraphQL::BaseType, nil]
|
39
|
+
# @return [Scope]
|
40
|
+
def enter(other_type_defn)
|
41
|
+
case other_type_defn
|
42
|
+
when nil
|
43
|
+
# The type wasn't found, who cares
|
44
|
+
Scope.new(@query, nil)
|
45
|
+
when @type
|
46
|
+
# The condition is the same as current, so reuse self
|
47
|
+
self
|
48
|
+
when GraphQL::UnionType, GraphQL::InterfaceType
|
49
|
+
# Make a new scope of the intersection between the previous & next conditions
|
50
|
+
new_types = @query.possible_types(other_type_defn) & concrete_types
|
51
|
+
Scope.new(@query, new_types)
|
52
|
+
when GraphQL::BaseType
|
53
|
+
# If this type is valid within the current scope,
|
54
|
+
# return a new scope of _exactly_ this type.
|
55
|
+
# Otherwise, this type is out-of-scope so the scope is null.
|
56
|
+
if concrete_types.include?(other_type_defn)
|
57
|
+
Scope.new(@query, other_type_defn)
|
58
|
+
else
|
59
|
+
Scope.new(@query, nil)
|
60
|
+
end
|
61
|
+
else
|
62
|
+
raise "Unexpected scope: #{other_type_defn.inspect}"
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
# Call the block for each type in `self`.
|
67
|
+
# This uses the simplest possible expression of `self`,
|
68
|
+
# so if this scope is defined by an abstract type, it gets yielded.
|
69
|
+
def each
|
70
|
+
if @abstract_type
|
71
|
+
yield(@type)
|
72
|
+
else
|
73
|
+
@types.each { |t| yield(t) }
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
private
|
78
|
+
|
79
|
+
def concrete_types
|
80
|
+
@concrete_types ||= if @abstract_type
|
81
|
+
@query.possible_types(@type)
|
82
|
+
else
|
83
|
+
@types
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|