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.
Files changed (73) hide show
  1. checksums.yaml +4 -4
  2. data/lib/generators/graphql/install_generator.rb +46 -0
  3. data/lib/generators/graphql/orm_mutations_base.rb +1 -1
  4. data/lib/generators/graphql/templates/base_resolver.erb +2 -0
  5. data/lib/generators/graphql/type_generator.rb +1 -1
  6. data/lib/graphql/analysis.rb +1 -1
  7. data/lib/graphql/current.rb +52 -0
  8. data/lib/graphql/dataloader/async_dataloader.rb +3 -2
  9. data/lib/graphql/dataloader/source.rb +6 -3
  10. data/lib/graphql/dataloader.rb +35 -11
  11. data/lib/graphql/execution/interpreter/arguments_cache.rb +5 -10
  12. data/lib/graphql/execution/interpreter/resolve.rb +10 -6
  13. data/lib/graphql/execution/interpreter/runtime.rb +23 -19
  14. data/lib/graphql/execution/interpreter.rb +2 -0
  15. data/lib/graphql/introspection/entry_points.rb +2 -2
  16. data/lib/graphql/introspection/schema_type.rb +4 -19
  17. data/lib/graphql/invalid_null_error.rb +1 -1
  18. data/lib/graphql/language/comment.rb +18 -0
  19. data/lib/graphql/language/document_from_schema_definition.rb +38 -4
  20. data/lib/graphql/language/lexer.rb +15 -12
  21. data/lib/graphql/language/nodes.rb +24 -16
  22. data/lib/graphql/language/parser.rb +14 -1
  23. data/lib/graphql/language/printer.rb +23 -7
  24. data/lib/graphql/language.rb +6 -5
  25. data/lib/graphql/query/context.rb +4 -2
  26. data/lib/graphql/query/null_context.rb +1 -5
  27. data/lib/graphql/query.rb +49 -20
  28. data/lib/graphql/rubocop/graphql/field_type_in_block.rb +144 -0
  29. data/lib/graphql/rubocop/graphql/root_types_in_block.rb +38 -0
  30. data/lib/graphql/rubocop.rb +2 -0
  31. data/lib/graphql/schema/addition.rb +1 -0
  32. data/lib/graphql/schema/always_visible.rb +6 -3
  33. data/lib/graphql/schema/argument.rb +14 -1
  34. data/lib/graphql/schema/build_from_definition.rb +9 -1
  35. data/lib/graphql/schema/directive/flagged.rb +1 -1
  36. data/lib/graphql/schema/enum.rb +49 -15
  37. data/lib/graphql/schema/enum_value.rb +9 -1
  38. data/lib/graphql/schema/field/connection_extension.rb +1 -1
  39. data/lib/graphql/schema/field.rb +91 -36
  40. data/lib/graphql/schema/input_object.rb +20 -7
  41. data/lib/graphql/schema/interface.rb +21 -4
  42. data/lib/graphql/schema/introspection_system.rb +3 -2
  43. data/lib/graphql/schema/member/base_dsl_methods.rb +15 -0
  44. data/lib/graphql/schema/member/has_arguments.rb +9 -5
  45. data/lib/graphql/schema/member/has_fields.rb +5 -5
  46. data/lib/graphql/schema/member/has_unresolved_type_error.rb +5 -1
  47. data/lib/graphql/schema/printer.rb +1 -0
  48. data/lib/graphql/schema/resolver.rb +3 -4
  49. data/lib/graphql/schema/validator/all_validator.rb +2 -0
  50. data/lib/graphql/schema/validator/required_validator.rb +28 -4
  51. data/lib/graphql/schema/visibility/migration.rb +186 -0
  52. data/lib/graphql/schema/visibility/profile.rb +523 -0
  53. data/lib/graphql/schema/visibility.rb +75 -0
  54. data/lib/graphql/schema/warden.rb +80 -21
  55. data/lib/graphql/schema.rb +254 -85
  56. data/lib/graphql/static_validation/rules/arguments_are_defined.rb +2 -1
  57. data/lib/graphql/static_validation/rules/directives_are_defined.rb +2 -1
  58. data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +2 -0
  59. data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +2 -1
  60. data/lib/graphql/static_validation/rules/fields_will_merge.rb +1 -0
  61. data/lib/graphql/static_validation/rules/fragment_types_exist.rb +11 -1
  62. data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +18 -27
  63. data/lib/graphql/static_validation/rules/variables_are_input_types.rb +10 -1
  64. data/lib/graphql/static_validation/validation_context.rb +15 -0
  65. data/lib/graphql/subscriptions/action_cable_subscriptions.rb +2 -1
  66. data/lib/graphql/subscriptions.rb +3 -1
  67. data/lib/graphql/testing/helpers.rb +7 -3
  68. data/lib/graphql/tracing/notifications_trace.rb +2 -2
  69. data/lib/graphql/unauthorized_enum_value_error.rb +13 -0
  70. data/lib/graphql/version.rb +1 -1
  71. data/lib/graphql.rb +3 -0
  72. metadata +28 -7
  73. 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