graphql 2.3.8 → 2.4.0
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/generators/graphql/install_generator.rb +46 -0
- data/lib/generators/graphql/orm_mutations_base.rb +1 -1
- data/lib/generators/graphql/templates/base_resolver.erb +2 -0
- data/lib/generators/graphql/type_generator.rb +1 -1
- data/lib/graphql/analysis.rb +1 -1
- data/lib/graphql/current.rb +52 -0
- data/lib/graphql/dataloader/async_dataloader.rb +3 -2
- data/lib/graphql/dataloader/source.rb +6 -3
- data/lib/graphql/dataloader.rb +35 -11
- data/lib/graphql/execution/interpreter/arguments_cache.rb +5 -10
- data/lib/graphql/execution/interpreter/resolve.rb +10 -6
- data/lib/graphql/execution/interpreter/runtime.rb +23 -19
- data/lib/graphql/execution/interpreter.rb +2 -0
- data/lib/graphql/introspection/entry_points.rb +2 -2
- data/lib/graphql/introspection/schema_type.rb +4 -19
- data/lib/graphql/invalid_null_error.rb +1 -1
- data/lib/graphql/language/comment.rb +18 -0
- data/lib/graphql/language/document_from_schema_definition.rb +38 -4
- data/lib/graphql/language/lexer.rb +15 -12
- data/lib/graphql/language/nodes.rb +24 -16
- data/lib/graphql/language/parser.rb +14 -1
- data/lib/graphql/language/printer.rb +23 -7
- data/lib/graphql/language.rb +6 -5
- data/lib/graphql/query/context.rb +4 -2
- data/lib/graphql/query/null_context.rb +1 -5
- data/lib/graphql/query.rb +49 -20
- data/lib/graphql/rubocop/graphql/field_type_in_block.rb +144 -0
- data/lib/graphql/rubocop/graphql/root_types_in_block.rb +38 -0
- data/lib/graphql/rubocop.rb +2 -0
- data/lib/graphql/schema/addition.rb +1 -0
- data/lib/graphql/schema/always_visible.rb +6 -3
- data/lib/graphql/schema/argument.rb +14 -1
- data/lib/graphql/schema/build_from_definition.rb +9 -1
- data/lib/graphql/schema/directive/flagged.rb +1 -1
- data/lib/graphql/schema/enum.rb +49 -15
- data/lib/graphql/schema/enum_value.rb +9 -1
- data/lib/graphql/schema/field/connection_extension.rb +1 -1
- data/lib/graphql/schema/field.rb +91 -36
- data/lib/graphql/schema/input_object.rb +20 -7
- data/lib/graphql/schema/interface.rb +21 -4
- data/lib/graphql/schema/introspection_system.rb +3 -2
- data/lib/graphql/schema/member/base_dsl_methods.rb +15 -0
- data/lib/graphql/schema/member/has_arguments.rb +9 -5
- data/lib/graphql/schema/member/has_fields.rb +5 -5
- data/lib/graphql/schema/member/has_unresolved_type_error.rb +5 -1
- data/lib/graphql/schema/printer.rb +1 -0
- data/lib/graphql/schema/resolver.rb +3 -4
- data/lib/graphql/schema/validator/all_validator.rb +2 -0
- data/lib/graphql/schema/validator/required_validator.rb +28 -4
- data/lib/graphql/schema/visibility/migration.rb +186 -0
- data/lib/graphql/schema/visibility/profile.rb +523 -0
- data/lib/graphql/schema/visibility.rb +75 -0
- data/lib/graphql/schema/warden.rb +80 -21
- data/lib/graphql/schema.rb +254 -85
- data/lib/graphql/static_validation/rules/arguments_are_defined.rb +2 -1
- data/lib/graphql/static_validation/rules/directives_are_defined.rb +2 -1
- data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +2 -0
- data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +2 -1
- data/lib/graphql/static_validation/rules/fields_will_merge.rb +1 -0
- data/lib/graphql/static_validation/rules/fragment_types_exist.rb +11 -1
- data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +18 -27
- data/lib/graphql/static_validation/rules/variables_are_input_types.rb +10 -1
- data/lib/graphql/static_validation/validation_context.rb +15 -0
- data/lib/graphql/subscriptions/action_cable_subscriptions.rb +2 -1
- data/lib/graphql/subscriptions.rb +3 -1
- data/lib/graphql/testing/helpers.rb +7 -3
- data/lib/graphql/tracing/notifications_trace.rb +2 -2
- data/lib/graphql/unauthorized_enum_value_error.rb +13 -0
- data/lib/graphql/version.rb +1 -1
- data/lib/graphql.rb +3 -0
- metadata +28 -7
- data/lib/graphql/schema/subset.rb +0 -397
|
@@ -1,397 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module GraphQL
|
|
4
|
-
class Schema
|
|
5
|
-
class Subset
|
|
6
|
-
def initialize(query)
|
|
7
|
-
@query = query
|
|
8
|
-
@context = query.context
|
|
9
|
-
@schema = query.schema
|
|
10
|
-
@all_types = {}
|
|
11
|
-
@all_types_loaded = false
|
|
12
|
-
@unvisited_types = []
|
|
13
|
-
@referenced_types = Hash.new { |h, type_defn| h[type_defn] = [] }.compare_by_identity
|
|
14
|
-
@cached_possible_types = nil
|
|
15
|
-
@cached_visible = Hash.new { |h, member|
|
|
16
|
-
h[member] = @schema.visible?(member, @context)
|
|
17
|
-
}.compare_by_identity
|
|
18
|
-
|
|
19
|
-
@cached_visible_fields = Hash.new { |h, owner|
|
|
20
|
-
h[owner] = Hash.new do |h2, field|
|
|
21
|
-
h2[field] = if @cached_visible[field] &&
|
|
22
|
-
(ret_type = field.type.unwrap) &&
|
|
23
|
-
@cached_visible[ret_type] &&
|
|
24
|
-
reachable_type?(ret_type.graphql_name) &&
|
|
25
|
-
(owner == field.owner || (!owner.kind.object?) || field_on_visible_interface?(field, owner))
|
|
26
|
-
|
|
27
|
-
if !field.introspection?
|
|
28
|
-
# The problem is that some introspection fields may have references
|
|
29
|
-
# to non-custom introspection types.
|
|
30
|
-
# If those were added here, they'd cause a DuplicateNamesError.
|
|
31
|
-
# This is basically a bug -- those fields _should_ reference the custom types.
|
|
32
|
-
add_type(ret_type, field)
|
|
33
|
-
end
|
|
34
|
-
true
|
|
35
|
-
else
|
|
36
|
-
false
|
|
37
|
-
end
|
|
38
|
-
end.compare_by_identity
|
|
39
|
-
}.compare_by_identity
|
|
40
|
-
|
|
41
|
-
@cached_visible_arguments = Hash.new do |h, arg|
|
|
42
|
-
h[arg] = if @cached_visible[arg] && (arg_type = arg.type.unwrap) && @cached_visible[arg_type]
|
|
43
|
-
add_type(arg_type, arg)
|
|
44
|
-
true
|
|
45
|
-
else
|
|
46
|
-
false
|
|
47
|
-
end
|
|
48
|
-
end.compare_by_identity
|
|
49
|
-
|
|
50
|
-
@unfiltered_pt = Hash.new do |hash, type|
|
|
51
|
-
hash[type] = @schema.possible_types(type)
|
|
52
|
-
end.compare_by_identity
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
def field_on_visible_interface?(field, owner)
|
|
56
|
-
ints = owner.interface_type_memberships.map(&:abstract_type)
|
|
57
|
-
field_name = field.graphql_name
|
|
58
|
-
filtered_ints = interfaces(owner)
|
|
59
|
-
any_interface_has_field = false
|
|
60
|
-
any_interface_has_visible_field = false
|
|
61
|
-
ints.each do |int_t|
|
|
62
|
-
if (_int_f_defn = int_t.get_field(field_name, @context))
|
|
63
|
-
any_interface_has_field = true
|
|
64
|
-
|
|
65
|
-
if filtered_ints.include?(int_t) # TODO cycles, or maybe not necessary since previously checked? && @cached_visible_fields[owner][field]
|
|
66
|
-
any_interface_has_visible_field = true
|
|
67
|
-
break
|
|
68
|
-
end
|
|
69
|
-
end
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
if any_interface_has_field
|
|
73
|
-
any_interface_has_visible_field
|
|
74
|
-
else
|
|
75
|
-
true
|
|
76
|
-
end
|
|
77
|
-
end
|
|
78
|
-
|
|
79
|
-
def type(type_name)
|
|
80
|
-
t = if (loaded_t = @all_types[type_name])
|
|
81
|
-
loaded_t
|
|
82
|
-
elsif !@all_types_loaded
|
|
83
|
-
load_all_types
|
|
84
|
-
@all_types[type_name]
|
|
85
|
-
end
|
|
86
|
-
|
|
87
|
-
if t
|
|
88
|
-
if t.is_a?(Array)
|
|
89
|
-
vis_t = nil
|
|
90
|
-
t.each do |t_defn|
|
|
91
|
-
if @cached_visible[t_defn]
|
|
92
|
-
if vis_t.nil?
|
|
93
|
-
vis_t = t_defn
|
|
94
|
-
else
|
|
95
|
-
raise_duplicate_definition(vis_t, t_defn)
|
|
96
|
-
end
|
|
97
|
-
end
|
|
98
|
-
end
|
|
99
|
-
vis_t
|
|
100
|
-
else
|
|
101
|
-
if t && @cached_visible[t]
|
|
102
|
-
t
|
|
103
|
-
else
|
|
104
|
-
nil
|
|
105
|
-
end
|
|
106
|
-
end
|
|
107
|
-
end
|
|
108
|
-
end
|
|
109
|
-
|
|
110
|
-
def field(owner, field_name)
|
|
111
|
-
f = if owner.kind.fields? && (field = owner.get_field(field_name, @context))
|
|
112
|
-
field
|
|
113
|
-
elsif owner == query_root && (entry_point_field = @schema.introspection_system.entry_point(name: field_name))
|
|
114
|
-
entry_point_field
|
|
115
|
-
elsif (dynamic_field = @schema.introspection_system.dynamic_field(name: field_name))
|
|
116
|
-
dynamic_field
|
|
117
|
-
else
|
|
118
|
-
nil
|
|
119
|
-
end
|
|
120
|
-
if f.is_a?(Array)
|
|
121
|
-
visible_f = nil
|
|
122
|
-
f.each do |f_defn|
|
|
123
|
-
if @cached_visible_fields[owner][f_defn]
|
|
124
|
-
|
|
125
|
-
if visible_f.nil?
|
|
126
|
-
visible_f = f_defn
|
|
127
|
-
else
|
|
128
|
-
raise_duplicate_definition(visible_f, f_defn)
|
|
129
|
-
end
|
|
130
|
-
end
|
|
131
|
-
end
|
|
132
|
-
visible_f
|
|
133
|
-
else
|
|
134
|
-
if f && @cached_visible_fields[owner][f]
|
|
135
|
-
f
|
|
136
|
-
else
|
|
137
|
-
nil
|
|
138
|
-
end
|
|
139
|
-
end
|
|
140
|
-
end
|
|
141
|
-
|
|
142
|
-
def fields(owner)
|
|
143
|
-
non_duplicate_items(owner.all_field_definitions, @cached_visible_fields[owner])
|
|
144
|
-
end
|
|
145
|
-
|
|
146
|
-
def arguments(owner)
|
|
147
|
-
non_duplicate_items(owner.all_argument_definitions, @cached_visible_arguments)
|
|
148
|
-
end
|
|
149
|
-
|
|
150
|
-
def argument(owner, arg_name)
|
|
151
|
-
# TODO this makes a Warden.visible_entry call down the stack
|
|
152
|
-
# I need a non-Warden implementation
|
|
153
|
-
arg = owner.get_argument(arg_name, @context)
|
|
154
|
-
if arg.is_a?(Array)
|
|
155
|
-
visible_arg = nil
|
|
156
|
-
arg.each do |arg_defn|
|
|
157
|
-
if @cached_visible_arguments[arg_defn]
|
|
158
|
-
if arg_defn&.loads
|
|
159
|
-
add_type(arg_defn.loads, arg_defn)
|
|
160
|
-
end
|
|
161
|
-
if visible_arg.nil?
|
|
162
|
-
visible_arg = arg_defn
|
|
163
|
-
else
|
|
164
|
-
raise_duplicate_definition(visible_arg, arg_defn)
|
|
165
|
-
end
|
|
166
|
-
end
|
|
167
|
-
end
|
|
168
|
-
visible_arg
|
|
169
|
-
else
|
|
170
|
-
if arg && @cached_visible_arguments[arg]
|
|
171
|
-
if arg&.loads
|
|
172
|
-
add_type(arg.loads, arg)
|
|
173
|
-
end
|
|
174
|
-
arg
|
|
175
|
-
else
|
|
176
|
-
nil
|
|
177
|
-
end
|
|
178
|
-
end
|
|
179
|
-
end
|
|
180
|
-
|
|
181
|
-
def possible_types(type)
|
|
182
|
-
@cached_possible_types ||= Hash.new do |h, type|
|
|
183
|
-
pt = case type.kind.name
|
|
184
|
-
when "INTERFACE"
|
|
185
|
-
# TODO this requires the global map
|
|
186
|
-
@unfiltered_pt[type]
|
|
187
|
-
when "UNION"
|
|
188
|
-
type.type_memberships.select { |tm| @cached_visible[tm] && @cached_visible[tm.object_type] }.map!(&:object_type)
|
|
189
|
-
else
|
|
190
|
-
[type]
|
|
191
|
-
end
|
|
192
|
-
|
|
193
|
-
# TODO use `select!` when possible, skip it for `[type]`
|
|
194
|
-
h[type] = pt.select { |t|
|
|
195
|
-
@cached_visible[t] && referenced?(t)
|
|
196
|
-
}
|
|
197
|
-
end.compare_by_identity
|
|
198
|
-
@cached_possible_types[type]
|
|
199
|
-
end
|
|
200
|
-
|
|
201
|
-
def interfaces(obj_or_int_type)
|
|
202
|
-
ints = obj_or_int_type.interface_type_memberships
|
|
203
|
-
.select { |itm| @cached_visible[itm] && @cached_visible[itm.abstract_type] }
|
|
204
|
-
.map!(&:abstract_type)
|
|
205
|
-
ints.uniq! # Remove any duplicate interfaces implemented via other interfaces
|
|
206
|
-
ints
|
|
207
|
-
end
|
|
208
|
-
|
|
209
|
-
def query_root
|
|
210
|
-
add_if_visible(@schema.query)
|
|
211
|
-
end
|
|
212
|
-
|
|
213
|
-
def mutation_root
|
|
214
|
-
add_if_visible(@schema.mutation)
|
|
215
|
-
end
|
|
216
|
-
|
|
217
|
-
def subscription_root
|
|
218
|
-
add_if_visible(@schema.subscription)
|
|
219
|
-
end
|
|
220
|
-
|
|
221
|
-
def all_types
|
|
222
|
-
@all_types_filtered ||= begin
|
|
223
|
-
load_all_types
|
|
224
|
-
at = []
|
|
225
|
-
@all_types.each do |_name, type_defn|
|
|
226
|
-
if possible_types(type_defn).any? || referenced?(type_defn)
|
|
227
|
-
at << type_defn
|
|
228
|
-
end
|
|
229
|
-
end
|
|
230
|
-
at
|
|
231
|
-
end
|
|
232
|
-
end
|
|
233
|
-
|
|
234
|
-
def enum_values(owner)
|
|
235
|
-
values = non_duplicate_items(owner.all_enum_value_definitions, @cached_visible)
|
|
236
|
-
if values.size == 0
|
|
237
|
-
raise GraphQL::Schema::Enum::MissingValuesError.new(owner)
|
|
238
|
-
end
|
|
239
|
-
values
|
|
240
|
-
end
|
|
241
|
-
|
|
242
|
-
def directive_exists?(dir_name)
|
|
243
|
-
dir = @schema.directives[dir_name]
|
|
244
|
-
dir && @cached_visible[dir]
|
|
245
|
-
end
|
|
246
|
-
|
|
247
|
-
def directives
|
|
248
|
-
@schema.directives.each_value.select { |d| @cached_visible[d] }
|
|
249
|
-
end
|
|
250
|
-
|
|
251
|
-
def loadable?(t, _ctx)
|
|
252
|
-
!@all_types[t.graphql_name] # TODO make sure t is not reachable but t is visible
|
|
253
|
-
end
|
|
254
|
-
|
|
255
|
-
# TODO rename this to indicate that it is called with a typename
|
|
256
|
-
def reachable_type?(type_name)
|
|
257
|
-
load_all_types
|
|
258
|
-
!!((t = @all_types[type_name]) && referenced?(t))
|
|
259
|
-
end
|
|
260
|
-
|
|
261
|
-
def loaded_types
|
|
262
|
-
@all_types.values
|
|
263
|
-
end
|
|
264
|
-
|
|
265
|
-
private
|
|
266
|
-
|
|
267
|
-
def add_if_visible(t)
|
|
268
|
-
(t && @cached_visible[t]) ? (add_type(t, true); t) : nil
|
|
269
|
-
end
|
|
270
|
-
|
|
271
|
-
def add_type(t, by_member)
|
|
272
|
-
if t && @cached_visible[t]
|
|
273
|
-
n = t.graphql_name
|
|
274
|
-
if (prev_t = @all_types[n])
|
|
275
|
-
if !prev_t.equal?(t)
|
|
276
|
-
raise_duplicate_definition(prev_t, t)
|
|
277
|
-
end
|
|
278
|
-
false
|
|
279
|
-
else
|
|
280
|
-
@referenced_types[t] << by_member
|
|
281
|
-
@all_types[n] = t
|
|
282
|
-
@unvisited_types << t
|
|
283
|
-
true
|
|
284
|
-
end
|
|
285
|
-
else
|
|
286
|
-
false
|
|
287
|
-
end
|
|
288
|
-
end
|
|
289
|
-
|
|
290
|
-
def non_duplicate_items(definitions, visibility_cache)
|
|
291
|
-
non_dups = []
|
|
292
|
-
definitions.each do |defn|
|
|
293
|
-
if visibility_cache[defn]
|
|
294
|
-
if (dup_defn = non_dups.find { |d| d.graphql_name == defn.graphql_name })
|
|
295
|
-
raise_duplicate_definition(dup_defn, defn)
|
|
296
|
-
end
|
|
297
|
-
non_dups << defn
|
|
298
|
-
end
|
|
299
|
-
end
|
|
300
|
-
non_dups
|
|
301
|
-
end
|
|
302
|
-
|
|
303
|
-
def raise_duplicate_definition(first_defn, second_defn)
|
|
304
|
-
raise DuplicateNamesError.new(duplicated_name: first_defn.path, duplicated_definition_1: first_defn.inspect, duplicated_definition_2: second_defn.inspect)
|
|
305
|
-
end
|
|
306
|
-
|
|
307
|
-
def referenced?(t)
|
|
308
|
-
load_all_types
|
|
309
|
-
res = if @referenced_types[t].any? { |member| (member == true) || @cached_visible[member] }
|
|
310
|
-
if t.kind.abstract?
|
|
311
|
-
possible_types(t).any?
|
|
312
|
-
else
|
|
313
|
-
true
|
|
314
|
-
end
|
|
315
|
-
end
|
|
316
|
-
res
|
|
317
|
-
end
|
|
318
|
-
|
|
319
|
-
def load_all_types
|
|
320
|
-
return if @all_types_loaded
|
|
321
|
-
@all_types_loaded = true
|
|
322
|
-
schema_types = [
|
|
323
|
-
query_root,
|
|
324
|
-
mutation_root,
|
|
325
|
-
subscription_root,
|
|
326
|
-
*@schema.introspection_system.types.values,
|
|
327
|
-
]
|
|
328
|
-
|
|
329
|
-
# Don't include any orphan_types whose interfaces aren't visible.
|
|
330
|
-
@schema.orphan_types.each do |orphan_type|
|
|
331
|
-
if @cached_visible[orphan_type] &&
|
|
332
|
-
orphan_type.interface_type_memberships.any? { |tm| @cached_visible[tm] && @cached_visible[tm.abstract_type] }
|
|
333
|
-
schema_types << orphan_type
|
|
334
|
-
end
|
|
335
|
-
end
|
|
336
|
-
schema_types.compact! # TODO why is this necessary?!
|
|
337
|
-
schema_types.flatten! # handle multiple defns
|
|
338
|
-
schema_types.each { |t| add_type(t, true) }
|
|
339
|
-
|
|
340
|
-
while t = @unvisited_types.pop
|
|
341
|
-
# These have already been checked for `.visible?`
|
|
342
|
-
visit_type(t)
|
|
343
|
-
end
|
|
344
|
-
|
|
345
|
-
@all_types.delete_if { |type_name, type_defn| !referenced?(type_defn) }
|
|
346
|
-
nil
|
|
347
|
-
end
|
|
348
|
-
|
|
349
|
-
def visit_type(type)
|
|
350
|
-
if type.kind.input_object?
|
|
351
|
-
# recurse into visible arguments
|
|
352
|
-
arguments(type).each do |argument|
|
|
353
|
-
add_type(argument.type.unwrap, argument)
|
|
354
|
-
end
|
|
355
|
-
elsif type.kind.union?
|
|
356
|
-
# recurse into visible possible types
|
|
357
|
-
type.type_memberships.each do |tm|
|
|
358
|
-
if @cached_visible[tm] && @cached_visible[tm.object_type]
|
|
359
|
-
add_type(tm.object_type, tm)
|
|
360
|
-
end
|
|
361
|
-
end
|
|
362
|
-
elsif type.kind.fields?
|
|
363
|
-
if type.kind.object?
|
|
364
|
-
# recurse into visible implemented interfaces
|
|
365
|
-
interfaces(type).each do |interface|
|
|
366
|
-
add_type(interface, type)
|
|
367
|
-
end
|
|
368
|
-
end
|
|
369
|
-
|
|
370
|
-
# recurse into visible fields
|
|
371
|
-
t_f = type.all_field_definitions
|
|
372
|
-
t_f.each do |field|
|
|
373
|
-
if @cached_visible[field]
|
|
374
|
-
field_type = field.type.unwrap
|
|
375
|
-
if field_type.kind.interface?
|
|
376
|
-
pt = @unfiltered_pt[field_type]
|
|
377
|
-
pt.each do |obj_type|
|
|
378
|
-
if @cached_visible[obj_type] &&
|
|
379
|
-
(tm = obj_type.interface_type_memberships.find { |tm| tm.abstract_type == field_type }) &&
|
|
380
|
-
@cached_visible[tm]
|
|
381
|
-
add_type(obj_type, tm)
|
|
382
|
-
end
|
|
383
|
-
end
|
|
384
|
-
end
|
|
385
|
-
add_type(field_type, field)
|
|
386
|
-
|
|
387
|
-
# recurse into visible arguments
|
|
388
|
-
arguments(field).each do |argument|
|
|
389
|
-
add_type(argument.type.unwrap, argument)
|
|
390
|
-
end
|
|
391
|
-
end
|
|
392
|
-
end
|
|
393
|
-
end
|
|
394
|
-
end
|
|
395
|
-
end
|
|
396
|
-
end
|
|
397
|
-
end
|