graphql 1.12.23 → 1.13.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/generators/graphql/mutation_generator.rb +1 -1
- data/lib/generators/graphql/type_generator.rb +0 -1
- data/lib/graphql/analysis/ast/field_usage.rb +4 -8
- data/lib/graphql/analysis/ast/query_complexity.rb +10 -14
- data/lib/graphql/analysis/ast/visitor.rb +4 -4
- data/lib/graphql/backtrace/table.rb +1 -1
- data/lib/graphql/dataloader.rb +55 -22
- data/lib/graphql/directive.rb +0 -4
- data/lib/graphql/enum_type.rb +5 -1
- data/lib/graphql/execution/errors.rb +1 -0
- data/lib/graphql/execution/interpreter/arguments.rb +1 -1
- data/lib/graphql/execution/interpreter/arguments_cache.rb +2 -2
- data/lib/graphql/execution/interpreter/runtime.rb +20 -12
- data/lib/graphql/execution/lookahead.rb +2 -2
- data/lib/graphql/execution/multiplex.rb +1 -1
- data/lib/graphql/introspection/directive_type.rb +1 -1
- data/lib/graphql/introspection/entry_points.rb +2 -2
- data/lib/graphql/introspection/enum_value_type.rb +2 -2
- data/lib/graphql/introspection/field_type.rb +2 -2
- data/lib/graphql/introspection/input_value_type.rb +4 -4
- data/lib/graphql/introspection/schema_type.rb +2 -2
- data/lib/graphql/introspection/type_type.rb +10 -10
- data/lib/graphql/language/block_string.rb +0 -4
- data/lib/graphql/language/document_from_schema_definition.rb +4 -2
- data/lib/graphql/language/lexer.rb +0 -3
- data/lib/graphql/language/lexer.rl +0 -4
- data/lib/graphql/language/nodes.rb +3 -11
- data/lib/graphql/language/parser.rb +442 -434
- data/lib/graphql/language/parser.y +5 -4
- data/lib/graphql/language/printer.rb +6 -1
- data/lib/graphql/language/sanitized_printer.rb +5 -5
- data/lib/graphql/language/token.rb +0 -4
- data/lib/graphql/name_validator.rb +0 -4
- data/lib/graphql/query/arguments.rb +1 -1
- data/lib/graphql/query/arguments_cache.rb +1 -1
- data/lib/graphql/query/context.rb +5 -2
- data/lib/graphql/query/literal_input.rb +1 -1
- data/lib/graphql/query/null_context.rb +12 -7
- data/lib/graphql/query/serial_execution/field_resolution.rb +1 -1
- data/lib/graphql/query/variables.rb +5 -1
- data/lib/graphql/relay/edges_instrumentation.rb +0 -1
- data/lib/graphql/rubocop/graphql/base_cop.rb +36 -0
- data/lib/graphql/rubocop/graphql/default_null_true.rb +43 -0
- data/lib/graphql/rubocop/graphql/default_required_true.rb +43 -0
- data/lib/graphql/rubocop.rb +4 -0
- data/lib/graphql/schema/addition.rb +37 -28
- data/lib/graphql/schema/argument.rb +6 -6
- data/lib/graphql/schema/build_from_definition.rb +5 -5
- data/lib/graphql/schema/directive/feature.rb +1 -1
- data/lib/graphql/schema/directive/flagged.rb +2 -2
- data/lib/graphql/schema/directive/include.rb +1 -1
- data/lib/graphql/schema/directive/skip.rb +1 -1
- data/lib/graphql/schema/directive/transform.rb +1 -1
- data/lib/graphql/schema/directive.rb +2 -2
- data/lib/graphql/schema/enum.rb +57 -9
- data/lib/graphql/schema/enum_value.rb +4 -0
- data/lib/graphql/schema/field/connection_extension.rb +1 -1
- data/lib/graphql/schema/field.rb +92 -17
- data/lib/graphql/schema/find_inherited_value.rb +1 -0
- data/lib/graphql/schema/finder.rb +5 -5
- data/lib/graphql/schema/input_object.rb +6 -5
- data/lib/graphql/schema/interface.rb +8 -19
- data/lib/graphql/schema/member/accepts_definition.rb +8 -1
- data/lib/graphql/schema/member/build_type.rb +0 -4
- data/lib/graphql/schema/member/has_arguments.rb +55 -13
- data/lib/graphql/schema/member/has_deprecation_reason.rb +1 -1
- data/lib/graphql/schema/member/has_fields.rb +76 -18
- data/lib/graphql/schema/member/has_interfaces.rb +90 -0
- data/lib/graphql/schema/member.rb +1 -0
- data/lib/graphql/schema/object.rb +7 -74
- data/lib/graphql/schema/printer.rb +1 -1
- data/lib/graphql/schema/relay_classic_mutation.rb +29 -3
- data/lib/graphql/schema/resolver/has_payload_type.rb +27 -2
- data/lib/graphql/schema/resolver.rb +19 -5
- data/lib/graphql/schema/subscription.rb +11 -1
- data/lib/graphql/schema/type_expression.rb +1 -1
- data/lib/graphql/schema/type_membership.rb +18 -4
- data/lib/graphql/schema/union.rb +6 -1
- data/lib/graphql/schema/validator/format_validator.rb +0 -4
- data/lib/graphql/schema/validator/numericality_validator.rb +1 -0
- data/lib/graphql/schema/warden.rb +116 -52
- data/lib/graphql/schema.rb +87 -15
- data/lib/graphql/static_validation/base_visitor.rb +5 -5
- data/lib/graphql/static_validation/definition_dependencies.rb +0 -1
- data/lib/graphql/static_validation/literal_validator.rb +1 -1
- data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +1 -1
- data/lib/graphql/static_validation/rules/fields_will_merge.rb +8 -15
- data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +1 -3
- data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +4 -4
- data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +7 -7
- data/lib/graphql/subscriptions/action_cable_subscriptions.rb +6 -4
- data/lib/graphql/subscriptions/event.rb +20 -12
- data/lib/graphql/subscriptions.rb +17 -19
- data/lib/graphql/types/relay/has_node_field.rb +1 -1
- data/lib/graphql/types/relay/has_nodes_field.rb +1 -1
- data/lib/graphql/version.rb +1 -1
- data/lib/graphql.rb +9 -31
- metadata +10 -5
@@ -37,6 +37,50 @@ module GraphQL
|
|
37
37
|
#
|
38
38
|
# @api private
|
39
39
|
class Warden
|
40
|
+
def self.from_context(context)
|
41
|
+
(context.respond_to?(:warden) && context.warden) || PassThruWarden
|
42
|
+
end
|
43
|
+
|
44
|
+
# @param visibility_method [Symbol] a Warden method to call for this entry
|
45
|
+
# @param entry [Object, Array<Object>] One or more definitions for a given name in a GraphQL Schema
|
46
|
+
# @param context [GraphQL::Query::Context]
|
47
|
+
# @param warden [Warden]
|
48
|
+
# @return [Object] `entry` or one of `entry`'s items if exactly one of them is visible for this context
|
49
|
+
# @return [nil] If neither `entry` nor any of `entry`'s items are visible for this context
|
50
|
+
def self.visible_entry?(visibility_method, entry, context, warden = Warden.from_context(context))
|
51
|
+
if entry.is_a?(Array)
|
52
|
+
visible_item = nil
|
53
|
+
entry.each do |item|
|
54
|
+
if warden.public_send(visibility_method, item, context)
|
55
|
+
if visible_item.nil?
|
56
|
+
visible_item = item
|
57
|
+
else
|
58
|
+
raise Schema::DuplicateNamesError, "Found two visible definitions for `#{item.path}`: #{visible_item.inspect}, #{item.inspect}"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
visible_item
|
63
|
+
elsif warden.public_send(visibility_method, entry, context)
|
64
|
+
entry
|
65
|
+
else
|
66
|
+
nil
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
# This is used when a caller provides a Hash for context.
|
71
|
+
# We want to call the schema's hooks, but we don't have a full-blown warden.
|
72
|
+
# The `context` arguments to these methods exist purely to simplify the code that
|
73
|
+
# calls methods on this object, so it will have everything it needs.
|
74
|
+
class PassThruWarden
|
75
|
+
class << self
|
76
|
+
def visible_field?(field, ctx); field.visible?(ctx); end
|
77
|
+
def visible_argument?(arg, ctx); arg.visible?(ctx); end
|
78
|
+
def visible_type?(type, ctx); type.visible?(ctx); end
|
79
|
+
def visible_enum_value?(ev, ctx); ev.visible?(ctx); end
|
80
|
+
def visible_type_membership?(tm, ctx); tm.visible?(ctx); end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
40
84
|
# @param filter [<#call(member)>] Objects are hidden when `.call(member, ctx)` returns true
|
41
85
|
# @param context [GraphQL::Query::Context]
|
42
86
|
# @param schema [GraphQL::Schema]
|
@@ -54,8 +98,8 @@ module GraphQL
|
|
54
98
|
def types
|
55
99
|
@types ||= begin
|
56
100
|
vis_types = {}
|
57
|
-
@schema.types.each do |n, t|
|
58
|
-
if
|
101
|
+
@schema.types(@context).each do |n, t|
|
102
|
+
if visible_and_reachable_type?(t)
|
59
103
|
vis_types[n] = t
|
60
104
|
end
|
61
105
|
end
|
@@ -66,8 +110,8 @@ module GraphQL
|
|
66
110
|
# @return [GraphQL::BaseType, nil] The type named `type_name`, if it exists (else `nil`)
|
67
111
|
def get_type(type_name)
|
68
112
|
@visible_types ||= read_through do |name|
|
69
|
-
type_defn = @schema.get_type(name)
|
70
|
-
if type_defn &&
|
113
|
+
type_defn = @schema.get_type(name, @context)
|
114
|
+
if type_defn && visible_and_reachable_type?(type_defn)
|
71
115
|
type_defn
|
72
116
|
else
|
73
117
|
nil
|
@@ -84,7 +128,7 @@ module GraphQL
|
|
84
128
|
|
85
129
|
# @return Boolean True if the type is visible and reachable in the schema
|
86
130
|
def reachable_type?(type_name)
|
87
|
-
type = get_type(type_name)
|
131
|
+
type = get_type(type_name) # rubocop:disable Development/ContextIsPassedCop -- `self` is query-aware
|
88
132
|
type && reachable_type_set.include?(type)
|
89
133
|
end
|
90
134
|
|
@@ -92,8 +136,8 @@ module GraphQL
|
|
92
136
|
def get_field(parent_type, field_name)
|
93
137
|
@visible_parent_fields ||= read_through do |type|
|
94
138
|
read_through do |f_name|
|
95
|
-
field_defn = @schema.get_field(type, f_name)
|
96
|
-
if field_defn && visible_field?(
|
139
|
+
field_defn = @schema.get_field(type, f_name, @context)
|
140
|
+
if field_defn && visible_field?(field_defn, nil, type)
|
97
141
|
field_defn
|
98
142
|
else
|
99
143
|
nil
|
@@ -106,15 +150,15 @@ module GraphQL
|
|
106
150
|
|
107
151
|
# @return [GraphQL::Argument, nil] The argument named `argument_name` on `parent_type`, if it exists and is visible
|
108
152
|
def get_argument(parent_type, argument_name)
|
109
|
-
argument = parent_type.get_argument(argument_name)
|
110
|
-
return argument if argument && visible_argument?(argument)
|
153
|
+
argument = parent_type.get_argument(argument_name, @context)
|
154
|
+
return argument if argument && visible_argument?(argument, @context)
|
111
155
|
end
|
112
156
|
|
113
157
|
# @return [Array<GraphQL::BaseType>] The types which may be member of `type_defn`
|
114
158
|
def possible_types(type_defn)
|
115
159
|
@visible_possible_types ||= read_through { |type_defn|
|
116
160
|
pt = @schema.possible_types(type_defn, @context)
|
117
|
-
pt.select { |t|
|
161
|
+
pt.select { |t| visible_and_reachable_type?(t) }
|
118
162
|
}
|
119
163
|
@visible_possible_types[type_defn]
|
120
164
|
end
|
@@ -122,26 +166,31 @@ module GraphQL
|
|
122
166
|
# @param type_defn [GraphQL::ObjectType, GraphQL::InterfaceType]
|
123
167
|
# @return [Array<GraphQL::Field>] Fields on `type_defn`
|
124
168
|
def fields(type_defn)
|
125
|
-
@visible_fields ||= read_through { |t| @schema.get_fields(t
|
169
|
+
@visible_fields ||= read_through { |t| @schema.get_fields(t, @context).values }
|
126
170
|
@visible_fields[type_defn]
|
127
171
|
end
|
128
172
|
|
129
173
|
# @param argument_owner [GraphQL::Field, GraphQL::InputObjectType]
|
130
174
|
# @return [Array<GraphQL::Argument>] Visible arguments on `argument_owner`
|
131
175
|
def arguments(argument_owner)
|
132
|
-
@visible_arguments ||= read_through { |o| o.arguments.each_value.select { |a| visible_argument?(a) } }
|
176
|
+
@visible_arguments ||= read_through { |o| o.arguments(@context).each_value.select { |a| visible_argument?(a) } }
|
133
177
|
@visible_arguments[argument_owner]
|
134
178
|
end
|
135
179
|
|
136
180
|
# @return [Array<GraphQL::EnumType::EnumValue>] Visible members of `enum_defn`
|
137
181
|
def enum_values(enum_defn)
|
138
|
-
@
|
139
|
-
@
|
182
|
+
@visible_enum_arrays ||= read_through { |e| e.enum_values(@context) }
|
183
|
+
@visible_enum_arrays[enum_defn]
|
184
|
+
end
|
185
|
+
|
186
|
+
def visible_enum_value?(enum_value, _ctx = nil)
|
187
|
+
@visible_enum_values ||= read_through { |ev| visible?(ev) }
|
188
|
+
@visible_enum_values[enum_value]
|
140
189
|
end
|
141
190
|
|
142
191
|
# @return [Array<GraphQL::InterfaceType>] Visible interfaces implemented by `obj_type`
|
143
192
|
def interfaces(obj_type)
|
144
|
-
@visible_interfaces ||= read_through { |t| t.interfaces(@context).select { |i|
|
193
|
+
@visible_interfaces ||= read_through { |t| t.interfaces(@context).select { |i| visible_type?(i) } }
|
145
194
|
@visible_interfaces[obj_type]
|
146
195
|
end
|
147
196
|
|
@@ -158,25 +207,52 @@ module GraphQL
|
|
158
207
|
end
|
159
208
|
end
|
160
209
|
|
161
|
-
|
162
|
-
|
163
|
-
def union_memberships(obj_type)
|
164
|
-
@unions ||= read_through { |obj_type| @schema.union_memberships(obj_type).select { |u| visible?(u) } }
|
165
|
-
@unions[obj_type]
|
166
|
-
end
|
167
|
-
|
168
|
-
def visible_argument?(arg_defn)
|
169
|
-
visible?(arg_defn) && visible_type?(arg_defn.type.unwrap)
|
170
|
-
end
|
171
|
-
|
172
|
-
def visible_field?(owner_type, field_defn)
|
210
|
+
# @param owner [Class, Module] If provided, confirm that field has the given owner.
|
211
|
+
def visible_field?(field_defn, _ctx = nil, owner = field_defn.owner)
|
173
212
|
# This field is visible in its own right
|
174
213
|
visible?(field_defn) &&
|
175
214
|
# This field's return type is visible
|
176
|
-
|
215
|
+
visible_and_reachable_type?(field_defn.type.unwrap) &&
|
177
216
|
# This field is either defined on this object type,
|
178
217
|
# or the interface it's inherited from is also visible
|
179
|
-
((field_defn.respond_to?(:owner) && field_defn.owner ==
|
218
|
+
((field_defn.respond_to?(:owner) && field_defn.owner == owner) || field_on_visible_interface?(field_defn, owner))
|
219
|
+
end
|
220
|
+
|
221
|
+
def visible_argument?(arg_defn, _ctx = nil)
|
222
|
+
visible?(arg_defn) && visible_and_reachable_type?(arg_defn.type.unwrap)
|
223
|
+
end
|
224
|
+
|
225
|
+
def visible_type?(type_defn, _ctx = nil)
|
226
|
+
@type_visibility ||= read_through { |type_defn| visible?(type_defn) }
|
227
|
+
@type_visibility[type_defn]
|
228
|
+
end
|
229
|
+
|
230
|
+
def visible_type_membership?(type_membership, _ctx = nil)
|
231
|
+
visible?(type_membership)
|
232
|
+
end
|
233
|
+
|
234
|
+
private
|
235
|
+
|
236
|
+
def visible_and_reachable_type?(type_defn)
|
237
|
+
@visible_and_reachable_type ||= read_through do |type_defn|
|
238
|
+
next false unless visible_type?(type_defn)
|
239
|
+
next true if root_type?(type_defn) || type_defn.introspection?
|
240
|
+
|
241
|
+
if type_defn.kind.union?
|
242
|
+
visible_possible_types?(type_defn) && (referenced?(type_defn) || orphan_type?(type_defn))
|
243
|
+
elsif type_defn.kind.interface?
|
244
|
+
visible_possible_types?(type_defn)
|
245
|
+
else
|
246
|
+
referenced?(type_defn) || visible_abstract_type?(type_defn)
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
@visible_and_reachable_type[type_defn]
|
251
|
+
end
|
252
|
+
|
253
|
+
def union_memberships(obj_type)
|
254
|
+
@unions ||= read_through { |obj_type| @schema.union_memberships(obj_type).select { |u| visible?(u) } }
|
255
|
+
@unions[obj_type]
|
180
256
|
end
|
181
257
|
|
182
258
|
# We need this to tell whether a field was inherited by an interface
|
@@ -195,10 +271,10 @@ module GraphQL
|
|
195
271
|
any_interface_has_visible_field = false
|
196
272
|
ints = unfiltered_interfaces(type_defn)
|
197
273
|
ints.each do |interface_type|
|
198
|
-
if (iface_field_defn = interface_type.get_field(field_defn.graphql_name))
|
274
|
+
if (iface_field_defn = interface_type.get_field(field_defn.graphql_name, @context))
|
199
275
|
any_interface_has_field = true
|
200
276
|
|
201
|
-
if interfaces(type_defn).include?(interface_type) && visible_field?(
|
277
|
+
if interfaces(type_defn).include?(interface_type) && visible_field?(iface_field_defn, nil, interface_type)
|
202
278
|
any_interface_has_visible_field = true
|
203
279
|
end
|
204
280
|
end
|
@@ -215,23 +291,6 @@ module GraphQL
|
|
215
291
|
end
|
216
292
|
end
|
217
293
|
|
218
|
-
def visible_type?(type_defn)
|
219
|
-
@type_visibility ||= read_through do |type_defn|
|
220
|
-
next false unless visible?(type_defn)
|
221
|
-
next true if root_type?(type_defn) || type_defn.introspection?
|
222
|
-
|
223
|
-
if type_defn.kind.union?
|
224
|
-
visible_possible_types?(type_defn) && (referenced?(type_defn) || orphan_type?(type_defn))
|
225
|
-
elsif type_defn.kind.interface?
|
226
|
-
visible_possible_types?(type_defn)
|
227
|
-
else
|
228
|
-
referenced?(type_defn) || visible_abstract_type?(type_defn)
|
229
|
-
end
|
230
|
-
end
|
231
|
-
|
232
|
-
@type_visibility[type_defn]
|
233
|
-
end
|
234
|
-
|
235
294
|
def root_type?(type_defn)
|
236
295
|
@query == type_defn ||
|
237
296
|
@mutation == type_defn ||
|
@@ -259,7 +318,7 @@ module GraphQL
|
|
259
318
|
end
|
260
319
|
|
261
320
|
def visible_possible_types?(type_defn)
|
262
|
-
possible_types(type_defn).any? { |t|
|
321
|
+
possible_types(type_defn).any? { |t| visible_and_reachable_type?(t) }
|
263
322
|
end
|
264
323
|
|
265
324
|
def visible?(member)
|
@@ -274,6 +333,7 @@ module GraphQL
|
|
274
333
|
return @reachable_type_set if defined?(@reachable_type_set)
|
275
334
|
|
276
335
|
@reachable_type_set = Set.new
|
336
|
+
rt_hash = {}
|
277
337
|
|
278
338
|
unvisited_types = []
|
279
339
|
['query', 'mutation', 'subscription'].each do |op_name|
|
@@ -283,16 +343,16 @@ module GraphQL
|
|
283
343
|
unvisited_types.concat(@schema.introspection_system.types.values)
|
284
344
|
|
285
345
|
directives.each do |dir_class|
|
286
|
-
dir_class.
|
346
|
+
arguments(dir_class).each do |arg_defn|
|
287
347
|
arg_t = arg_defn.type.unwrap
|
288
|
-
if get_type(arg_t.graphql_name)
|
348
|
+
if get_type(arg_t.graphql_name) # rubocop:disable Development/ContextIsPassedCop -- `self` is query-aware
|
289
349
|
unvisited_types << arg_t
|
290
350
|
end
|
291
351
|
end
|
292
352
|
end
|
293
353
|
|
294
354
|
@schema.orphan_types.each do |orphan_type|
|
295
|
-
if get_type(orphan_type.graphql_name)
|
355
|
+
if get_type(orphan_type.graphql_name) == orphan_type # rubocop:disable Development/ContextIsPassedCop -- `self` is query-aware
|
296
356
|
unvisited_types << orphan_type
|
297
357
|
end
|
298
358
|
end
|
@@ -300,6 +360,10 @@ module GraphQL
|
|
300
360
|
until unvisited_types.empty?
|
301
361
|
type = unvisited_types.pop
|
302
362
|
if @reachable_type_set.add?(type)
|
363
|
+
type_by_name = rt_hash[type.graphql_name] ||= type
|
364
|
+
if type_by_name != type
|
365
|
+
raise DuplicateNamesError, "Found two visible type definitions for `#{type.graphql_name}`: #{type.inspect}, #{type_by_name.inspect}"
|
366
|
+
end
|
303
367
|
if type.kind.input_object?
|
304
368
|
# recurse into visible arguments
|
305
369
|
arguments(type).each do |argument|
|
data/lib/graphql/schema.rb
CHANGED
@@ -92,6 +92,8 @@ module GraphQL
|
|
92
92
|
end
|
93
93
|
end
|
94
94
|
|
95
|
+
class DuplicateNamesError < GraphQL::Error; end
|
96
|
+
|
95
97
|
class UnresolvedLateBoundTypeError < GraphQL::Error
|
96
98
|
attr_reader :type
|
97
99
|
def initialize(type:)
|
@@ -996,16 +998,58 @@ module GraphQL
|
|
996
998
|
# Build a map of `{ name => type }` and return it
|
997
999
|
# @return [Hash<String => Class>] A dictionary of type classes by their GraphQL name
|
998
1000
|
# @see get_type Which is more efficient for finding _one type_ by name, because it doesn't merge hashes.
|
999
|
-
def types
|
1000
|
-
non_introspection_types.merge(introspection_system.types)
|
1001
|
+
def types(context = GraphQL::Query::NullContext)
|
1002
|
+
all_types = non_introspection_types.merge(introspection_system.types)
|
1003
|
+
visible_types = {}
|
1004
|
+
all_types.each do |k, v|
|
1005
|
+
visible_types[k] =if v.is_a?(Array)
|
1006
|
+
visible_t = nil
|
1007
|
+
v.each do |t|
|
1008
|
+
if t.visible?(context)
|
1009
|
+
if visible_t.nil?
|
1010
|
+
visible_t = t
|
1011
|
+
else
|
1012
|
+
raise DuplicateNamesError, "Found two visible type definitions for `#{k}`: #{visible_t.inspect}, #{t.inspect}"
|
1013
|
+
end
|
1014
|
+
end
|
1015
|
+
end
|
1016
|
+
visible_t
|
1017
|
+
else
|
1018
|
+
v
|
1019
|
+
end
|
1020
|
+
end
|
1021
|
+
visible_types
|
1001
1022
|
end
|
1002
1023
|
|
1003
1024
|
# @param type_name [String]
|
1004
1025
|
# @return [Module, nil] A type, or nil if there's no type called `type_name`
|
1005
|
-
def get_type(type_name)
|
1006
|
-
own_types[type_name]
|
1007
|
-
|
1008
|
-
|
1026
|
+
def get_type(type_name, context = GraphQL::Query::NullContext)
|
1027
|
+
local_entry = own_types[type_name]
|
1028
|
+
type_defn = case local_entry
|
1029
|
+
when nil
|
1030
|
+
nil
|
1031
|
+
when Array
|
1032
|
+
visible_t = nil
|
1033
|
+
warden = Warden.from_context(context)
|
1034
|
+
local_entry.each do |t|
|
1035
|
+
if warden.visible_type?(t, context)
|
1036
|
+
if visible_t.nil?
|
1037
|
+
visible_t = t
|
1038
|
+
else
|
1039
|
+
raise DuplicateNamesError, "Found two visible type definitions for `#{type_name}`: #{visible_t.inspect}, #{t.inspect}"
|
1040
|
+
end
|
1041
|
+
end
|
1042
|
+
end
|
1043
|
+
visible_t
|
1044
|
+
when Module
|
1045
|
+
local_entry
|
1046
|
+
else
|
1047
|
+
raise "Invariant: unexpected own_types[#{type_name.inspect}]: #{local_entry.inspect}"
|
1048
|
+
end
|
1049
|
+
|
1050
|
+
type_defn ||
|
1051
|
+
introspection_system.types[type_name] || # todo context-specific introspection?
|
1052
|
+
(superclass.respond_to?(:get_type) ? superclass.get_type(type_name, context) : nil)
|
1009
1053
|
end
|
1010
1054
|
|
1011
1055
|
# @api private
|
@@ -1182,19 +1226,19 @@ module GraphQL
|
|
1182
1226
|
GraphQL::Schema::TypeExpression.build_type(type_owner, ast_node)
|
1183
1227
|
end
|
1184
1228
|
|
1185
|
-
def get_field(type_or_name, field_name)
|
1229
|
+
def get_field(type_or_name, field_name, context = GraphQL::Query::NullContext)
|
1186
1230
|
parent_type = case type_or_name
|
1187
1231
|
when LateBoundType
|
1188
|
-
get_type(type_or_name.name)
|
1232
|
+
get_type(type_or_name.name, context)
|
1189
1233
|
when String
|
1190
|
-
get_type(type_or_name)
|
1234
|
+
get_type(type_or_name, context)
|
1191
1235
|
when Module
|
1192
1236
|
type_or_name
|
1193
1237
|
else
|
1194
1238
|
raise ArgumentError, "unexpected field owner for #{field_name.inspect}: #{type_or_name.inspect} (#{type_or_name.class})"
|
1195
1239
|
end
|
1196
1240
|
|
1197
|
-
if parent_type.kind.fields? && (field = parent_type.get_field(field_name))
|
1241
|
+
if parent_type.kind.fields? && (field = parent_type.get_field(field_name, context))
|
1198
1242
|
field
|
1199
1243
|
elsif parent_type == query && (entry_point_field = introspection_system.entry_point(name: field_name))
|
1200
1244
|
entry_point_field
|
@@ -1205,8 +1249,8 @@ module GraphQL
|
|
1205
1249
|
end
|
1206
1250
|
end
|
1207
1251
|
|
1208
|
-
def get_fields(type)
|
1209
|
-
type.fields
|
1252
|
+
def get_fields(type, context = GraphQL::Query::NullContext)
|
1253
|
+
type.fields(context)
|
1210
1254
|
end
|
1211
1255
|
|
1212
1256
|
def introspection(new_introspection_namespace = nil)
|
@@ -1405,7 +1449,6 @@ module GraphQL
|
|
1405
1449
|
if new_orphan_types.any?
|
1406
1450
|
new_orphan_types = new_orphan_types.flatten
|
1407
1451
|
add_type_and_traverse(new_orphan_types, root: false)
|
1408
|
-
@orphan_types = new_orphan_types
|
1409
1452
|
own_orphan_types.concat(new_orphan_types.flatten)
|
1410
1453
|
end
|
1411
1454
|
|
@@ -1715,7 +1758,7 @@ module GraphQL
|
|
1715
1758
|
if subscription.singleton_class.ancestors.include?(Subscriptions::SubscriptionRoot)
|
1716
1759
|
GraphQL::Deprecation.warn("`extend Subscriptions::SubscriptionRoot` is no longer required; you may remove it from #{self}'s `subscription` root type (#{subscription}).")
|
1717
1760
|
else
|
1718
|
-
subscription.
|
1761
|
+
subscription.all_field_definitions.each do |field|
|
1719
1762
|
field.extension(Subscriptions::DefaultSubscriptionResolveExtension)
|
1720
1763
|
end
|
1721
1764
|
end
|
@@ -1737,7 +1780,36 @@ module GraphQL
|
|
1737
1780
|
end
|
1738
1781
|
new_types = Array(t)
|
1739
1782
|
addition = Schema::Addition.new(schema: self, own_types: own_types, new_types: new_types)
|
1740
|
-
|
1783
|
+
addition.types.each do |name, types_entry| # rubocop:disable Development/ContextIsPassedCop -- build-time, not query-time
|
1784
|
+
if (prev_entry = own_types[name])
|
1785
|
+
prev_entries = case prev_entry
|
1786
|
+
when Array
|
1787
|
+
prev_entry
|
1788
|
+
when Module
|
1789
|
+
own_types[name] = [prev_entry]
|
1790
|
+
else
|
1791
|
+
raise "Invariant: unexpected prev_entry at #{name.inspect} when adding #{t.inspect}"
|
1792
|
+
end
|
1793
|
+
|
1794
|
+
case types_entry
|
1795
|
+
when Array
|
1796
|
+
prev_entries.concat(types_entry)
|
1797
|
+
prev_entries.uniq! # in case any are being re-visited
|
1798
|
+
when Module
|
1799
|
+
if !prev_entries.include?(types_entry)
|
1800
|
+
prev_entries << types_entry
|
1801
|
+
end
|
1802
|
+
else
|
1803
|
+
raise "Invariant: unexpected types_entry at #{name} when adding #{t.inspect}"
|
1804
|
+
end
|
1805
|
+
else
|
1806
|
+
if types_entry.is_a?(Array)
|
1807
|
+
types_entry.uniq!
|
1808
|
+
end
|
1809
|
+
own_types[name] = types_entry
|
1810
|
+
end
|
1811
|
+
end
|
1812
|
+
|
1741
1813
|
own_possible_types.merge!(addition.possible_types) { |key, old_val, new_val| old_val + new_val }
|
1742
1814
|
own_union_memberships.merge!(addition.union_memberships)
|
1743
1815
|
|
@@ -94,7 +94,7 @@ module GraphQL
|
|
94
94
|
|
95
95
|
def on_field(node, parent)
|
96
96
|
parent_type = @object_types.last
|
97
|
-
field_definition = @schema.get_field(parent_type, node.name)
|
97
|
+
field_definition = @schema.get_field(parent_type, node.name, @context.query.context)
|
98
98
|
@field_definitions.push(field_definition)
|
99
99
|
if !field_definition.nil?
|
100
100
|
next_object_type = field_definition.type.unwrap
|
@@ -120,14 +120,14 @@ module GraphQL
|
|
120
120
|
argument_defn = if (arg = @argument_definitions.last)
|
121
121
|
arg_type = arg.type.unwrap
|
122
122
|
if arg_type.kind.input_object?
|
123
|
-
arg_type
|
123
|
+
@context.warden.get_argument(arg_type, node.name)
|
124
124
|
else
|
125
125
|
nil
|
126
126
|
end
|
127
127
|
elsif (directive_defn = @directive_definitions.last)
|
128
|
-
directive_defn
|
128
|
+
@context.warden.get_argument(directive_defn, node.name)
|
129
129
|
elsif (field_defn = @field_definitions.last)
|
130
|
-
field_defn
|
130
|
+
@context.warden.get_argument(field_defn, node.name)
|
131
131
|
else
|
132
132
|
nil
|
133
133
|
end
|
@@ -187,7 +187,7 @@ module GraphQL
|
|
187
187
|
|
188
188
|
def on_fragment_with_type(node)
|
189
189
|
object_type = if node.type
|
190
|
-
@
|
190
|
+
@context.warden.get_type(node.type.name)
|
191
191
|
else
|
192
192
|
@object_types.last
|
193
193
|
end
|
@@ -95,7 +95,7 @@ module GraphQL
|
|
95
95
|
def required_input_fields_are_present(type, ast_node)
|
96
96
|
# TODO - would be nice to use these to create an error message so the caller knows
|
97
97
|
# that required fields are missing
|
98
|
-
required_field_names =
|
98
|
+
required_field_names = @warden.arguments(type)
|
99
99
|
.select { |argument| argument.type.kind.non_null? && @warden.get_argument(type, argument.name) }
|
100
100
|
.map(&:name)
|
101
101
|
|
@@ -15,7 +15,7 @@ module GraphQL
|
|
15
15
|
if @context.schema.error_bubbling || context.errors.none? { |err| err.path.take(@path.size) == @path }
|
16
16
|
parent_defn = parent_definition(parent)
|
17
17
|
|
18
|
-
if parent_defn && (arg_defn = parent_defn
|
18
|
+
if parent_defn && (arg_defn = context.warden.get_argument(parent_defn, node.name))
|
19
19
|
validation_result = context.validate_literal(node.value, arg_defn.type)
|
20
20
|
if !validation_result.valid?
|
21
21
|
kind_of_node = node_type(parent)
|
@@ -50,15 +50,15 @@ module GraphQL
|
|
50
50
|
@arg_conflicts = nil
|
51
51
|
|
52
52
|
yield
|
53
|
-
|
54
|
-
|
55
|
-
|
53
|
+
|
54
|
+
field_conflicts.each_value { |error| add_error(error) }
|
55
|
+
arg_conflicts.each_value { |error| add_error(error) }
|
56
56
|
end
|
57
57
|
|
58
58
|
def conflicts_within_selection_set(node, parent_type)
|
59
59
|
return if parent_type.nil?
|
60
60
|
|
61
|
-
fields, fragment_spreads = fields_and_fragments_from_selection(node, owner_type: parent_type, parents:
|
61
|
+
fields, fragment_spreads = fields_and_fragments_from_selection(node, owner_type: parent_type, parents: [])
|
62
62
|
|
63
63
|
# (A) Find find all conflicts "within" the fields of this selection set.
|
64
64
|
find_conflicts_within(fields)
|
@@ -198,14 +198,10 @@ module GraphQL
|
|
198
198
|
response_keys.each do |key, fields|
|
199
199
|
next if fields.size < 2
|
200
200
|
# find conflicts within nodes
|
201
|
-
i
|
202
|
-
|
203
|
-
j = i + 1
|
204
|
-
while j < fields.size
|
201
|
+
for i in 0..fields.size - 1
|
202
|
+
for j in i + 1..fields.size - 1
|
205
203
|
find_conflict(key, fields[i], fields[j])
|
206
|
-
j += 1
|
207
204
|
end
|
208
|
-
i += 1
|
209
205
|
end
|
210
206
|
end
|
211
207
|
end
|
@@ -247,9 +243,7 @@ module GraphQL
|
|
247
243
|
end
|
248
244
|
|
249
245
|
def find_conflicts_between_sub_selection_sets(field1, field2, mutually_exclusive:)
|
250
|
-
return if field1.definition.nil? ||
|
251
|
-
field2.definition.nil? ||
|
252
|
-
(field1.node.selections.empty? && field2.node.selections.empty?)
|
246
|
+
return if field1.definition.nil? || field2.definition.nil?
|
253
247
|
|
254
248
|
return_type1 = field1.definition.type.unwrap
|
255
249
|
return_type2 = field2.definition.type.unwrap
|
@@ -329,7 +323,6 @@ module GraphQL
|
|
329
323
|
if node.selections.empty?
|
330
324
|
NO_SELECTIONS
|
331
325
|
else
|
332
|
-
parents ||= []
|
333
326
|
fields, fragment_spreads = find_fields_and_fragments(node.selections, owner_type: owner_type, parents: parents, fields: [], fragment_spreads: [])
|
334
327
|
response_keys = fields.group_by { |f| f.node.alias || f.node.name }
|
335
328
|
[response_keys, fragment_spreads]
|
@@ -340,7 +333,7 @@ module GraphQL
|
|
340
333
|
selections.each do |node|
|
341
334
|
case node
|
342
335
|
when GraphQL::Language::Nodes::Field
|
343
|
-
definition = context.
|
336
|
+
definition = context.query.get_field(owner_type, node.name)
|
344
337
|
fields << Field.new(node, definition, owner_type, parents)
|
345
338
|
when GraphQL::Language::Nodes::InlineFragment
|
346
339
|
fragment_type = node.type ? context.warden.get_type(node.type.name) : owner_type
|
@@ -16,10 +16,8 @@ module GraphQL
|
|
16
16
|
private
|
17
17
|
|
18
18
|
def assert_required_args(ast_node, defn)
|
19
|
-
args = defn.arguments
|
20
|
-
return if args.empty?
|
21
19
|
present_argument_names = ast_node.arguments.map(&:name)
|
22
|
-
required_argument_names =
|
20
|
+
required_argument_names = context.warden.arguments(defn)
|
23
21
|
.select { |a| a.type.kind.non_null? && !a.default_value? && context.warden.get_argument(defn, a.name) }
|
24
22
|
.map(&:name)
|
25
23
|
|
@@ -34,16 +34,16 @@ module GraphQL
|
|
34
34
|
parent_type = get_parent_type(context, parent)
|
35
35
|
return unless parent_type && parent_type.kind.input_object?
|
36
36
|
|
37
|
-
required_fields =
|
38
|
-
.select{|
|
39
|
-
.
|
37
|
+
required_fields = context.warden.arguments(parent_type)
|
38
|
+
.select{|arg| arg.type.kind.non_null?}
|
39
|
+
.map(&:graphql_name)
|
40
40
|
|
41
41
|
present_fields = ast_node.arguments.map(&:name)
|
42
42
|
missing_fields = required_fields - present_fields
|
43
43
|
|
44
44
|
missing_fields.each do |missing_field|
|
45
45
|
path = [*context.path, missing_field]
|
46
|
-
missing_field_type = parent_type
|
46
|
+
missing_field_type = context.warden.get_argument(parent_type, missing_field).type
|
47
47
|
add_error(RequiredInputObjectAttributesArePresentError.new(
|
48
48
|
"Argument '#{missing_field}' on InputObject '#{parent_type.to_type_signature}' is required. Expected type #{missing_field_type.to_type_signature}",
|
49
49
|
argument_name: missing_field,
|
@@ -22,15 +22,15 @@ module GraphQL
|
|
22
22
|
node_values = node_values.select { |value| value.is_a? GraphQL::Language::Nodes::VariableIdentifier }
|
23
23
|
|
24
24
|
if node_values.any?
|
25
|
-
|
25
|
+
argument_owner = case parent
|
26
26
|
when GraphQL::Language::Nodes::Field
|
27
|
-
context.field_definition
|
27
|
+
context.field_definition
|
28
28
|
when GraphQL::Language::Nodes::Directive
|
29
|
-
context.directive_definition
|
29
|
+
context.directive_definition
|
30
30
|
when GraphQL::Language::Nodes::InputObject
|
31
31
|
arg_type = context.argument_definition.type.unwrap
|
32
32
|
if arg_type.kind.input_object?
|
33
|
-
|
33
|
+
arg_type
|
34
34
|
else
|
35
35
|
# This is some kind of error
|
36
36
|
nil
|
@@ -43,7 +43,7 @@ module GraphQL
|
|
43
43
|
var_defn_ast = @declared_variables[node_value.name]
|
44
44
|
# Might be undefined :(
|
45
45
|
# VariablesAreUsedAndDefined can't finalize its search until the end of the document.
|
46
|
-
var_defn_ast &&
|
46
|
+
var_defn_ast && argument_owner && validate_usage(argument_owner, node, var_defn_ast)
|
47
47
|
end
|
48
48
|
end
|
49
49
|
super
|
@@ -51,7 +51,7 @@ module GraphQL
|
|
51
51
|
|
52
52
|
private
|
53
53
|
|
54
|
-
def validate_usage(
|
54
|
+
def validate_usage(argument_owner, arg_node, ast_var)
|
55
55
|
var_type = context.schema.type_from_ast(ast_var.type, context: context)
|
56
56
|
if var_type.nil?
|
57
57
|
return
|
@@ -65,7 +65,7 @@ module GraphQL
|
|
65
65
|
end
|
66
66
|
end
|
67
67
|
|
68
|
-
arg_defn =
|
68
|
+
arg_defn = context.warden.get_argument(argument_owner, arg_node.name)
|
69
69
|
arg_defn_type = arg_defn.type
|
70
70
|
|
71
71
|
var_inner_type = var_type.unwrap
|