graphql 2.3.14 → 2.3.15

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.

Potentially problematic release.


This version of graphql might be problematic. Click here for more details.

Files changed (34) hide show
  1. checksums.yaml +4 -4
  2. data/lib/generators/graphql/orm_mutations_base.rb +1 -1
  3. data/lib/generators/graphql/templates/base_resolver.erb +2 -0
  4. data/lib/generators/graphql/type_generator.rb +1 -1
  5. data/lib/graphql/analysis.rb +1 -1
  6. data/lib/graphql/execution/interpreter/resolve.rb +10 -6
  7. data/lib/graphql/language/comment.rb +18 -0
  8. data/lib/graphql/language/document_from_schema_definition.rb +38 -4
  9. data/lib/graphql/language/lexer.rb +15 -12
  10. data/lib/graphql/language/nodes.rb +22 -14
  11. data/lib/graphql/language/parser.rb +5 -0
  12. data/lib/graphql/language/printer.rb +23 -7
  13. data/lib/graphql/language.rb +6 -5
  14. data/lib/graphql/query.rb +1 -1
  15. data/lib/graphql/schema/argument.rb +13 -1
  16. data/lib/graphql/schema/enum.rb +1 -0
  17. data/lib/graphql/schema/enum_value.rb +9 -1
  18. data/lib/graphql/schema/field.rb +23 -3
  19. data/lib/graphql/schema/interface.rb +1 -0
  20. data/lib/graphql/schema/member/base_dsl_methods.rb +15 -0
  21. data/lib/graphql/schema/member/has_arguments.rb +2 -2
  22. data/lib/graphql/schema/member/has_fields.rb +2 -2
  23. data/lib/graphql/schema/resolver.rb +3 -4
  24. data/lib/graphql/schema/visibility/migration.rb +188 -0
  25. data/lib/graphql/schema/visibility/subset.rb +509 -0
  26. data/lib/graphql/schema/visibility.rb +30 -0
  27. data/lib/graphql/schema.rb +46 -41
  28. data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +2 -0
  29. data/lib/graphql/testing/helpers.rb +1 -1
  30. data/lib/graphql/tracing/notifications_trace.rb +2 -2
  31. data/lib/graphql/version.rb +1 -1
  32. metadata +6 -4
  33. data/lib/graphql/schema/subset.rb +0 -509
  34. data/lib/graphql/schema/types_migration.rb +0 -187
@@ -1,509 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module GraphQL
4
- class Schema
5
- # This class filters the types, fields, arguments, enum values, and directives in a schema
6
- # based on the given `context`.
7
- #
8
- # It's like {Warden}, but has some differences:
9
- #
10
- # - It doesn't use {Schema}'s top-level caches (eg {Schema.references_to}, {Schema.possible_types}, {Schema.types})
11
- # - It doesn't hide Interface or Union types when all their possible types are hidden. (Instead, those types should implement `.visible?` to hide in that case.)
12
- # - It checks `.visible?` on root introspection types
13
- #
14
- # In the future, {Subset} will support lazy-loading types as needed during execution and multi-request caching of subsets.
15
- #
16
- # @see Schema::TypesMigration for a helper class in adopting this filter
17
- class Subset
18
- # @return [Schema::Subset]
19
- def self.from_context(ctx, schema)
20
- if ctx.respond_to?(:types) && (types = ctx.types).is_a?(self)
21
- types
22
- else
23
- # TODO use a cached instance from the schema
24
- self.new(context: ctx, schema: schema)
25
- end
26
- end
27
-
28
- def self.pass_thru(context:, schema:)
29
- subset = self.new(context: context, schema: schema)
30
- subset.instance_variable_set(:@cached_visible, Hash.new { |h,k| h[k] = true })
31
- subset
32
- end
33
-
34
- def initialize(context:, schema:)
35
- @context = context
36
- @schema = schema
37
- @all_types = {}
38
- @all_types_loaded = false
39
- @unvisited_types = []
40
- @referenced_types = Hash.new { |h, type_defn| h[type_defn] = [] }.compare_by_identity
41
- @cached_directives = {}
42
- @all_directives = nil
43
- @cached_visible = Hash.new { |h, member|
44
- h[member] = @schema.visible?(member, @context)
45
- }.compare_by_identity
46
-
47
- @cached_visible_fields = Hash.new { |h, owner|
48
- h[owner] = Hash.new do |h2, field|
49
- h2[field] = if @cached_visible[field] &&
50
- (ret_type = field.type.unwrap) &&
51
- @cached_visible[ret_type] &&
52
- (owner == field.owner || (!owner.kind.object?) || field_on_visible_interface?(field, owner))
53
-
54
- if !field.introspection?
55
- # The problem is that some introspection fields may have references
56
- # to non-custom introspection types.
57
- # If those were added here, they'd cause a DuplicateNamesError.
58
- # This is basically a bug -- those fields _should_ reference the custom types.
59
- add_type(ret_type, field)
60
- end
61
- true
62
- else
63
- false
64
- end
65
- end.compare_by_identity
66
- }.compare_by_identity
67
-
68
- @cached_visible_arguments = Hash.new do |h, arg|
69
- h[arg] = if @cached_visible[arg] && (arg_type = arg.type.unwrap) && @cached_visible[arg_type]
70
- add_type(arg_type, arg)
71
- true
72
- else
73
- false
74
- end
75
- end.compare_by_identity
76
-
77
- @cached_parent_fields = Hash.new do |h, type|
78
- h[type] = Hash.new do |h2, field_name|
79
- h2[field_name] = type.get_field(field_name, @context)
80
- end
81
- end.compare_by_identity
82
-
83
- @cached_parent_arguments = Hash.new do |h, arg_owner|
84
- h[arg_owner] = Hash.new do |h2, arg_name|
85
- h2[arg_name] = arg_owner.get_argument(arg_name, @context)
86
- end
87
- end.compare_by_identity
88
-
89
- @cached_possible_types = Hash.new do |h, type|
90
- h[type] = case type.kind.name
91
- when "INTERFACE"
92
- load_all_types
93
- pts = []
94
- @unfiltered_interface_type_memberships[type].each { |itm|
95
- if @cached_visible[itm] && (ot = itm.object_type) && @cached_visible[ot] && referenced?(ot)
96
- pts << ot
97
- end
98
- }
99
- pts
100
- when "UNION"
101
- pts = []
102
- type.type_memberships.each { |tm|
103
- if @cached_visible[tm] &&
104
- (ot = tm.object_type) &&
105
- @cached_visible[ot] &&
106
- referenced?(ot)
107
- pts << ot
108
- end
109
- }
110
- pts
111
- when "OBJECT"
112
- load_all_types
113
- if @all_types[type.graphql_name] == type
114
- [type]
115
- else
116
- EmptyObjects::EMPTY_ARRAY
117
- end
118
- else
119
- GraphQL::EmptyObjects::EMPTY_ARRAY
120
- end
121
- end.compare_by_identity
122
-
123
- @cached_enum_values = Hash.new do |h, enum_t|
124
- values = non_duplicate_items(enum_t.all_enum_value_definitions, @cached_visible)
125
- if values.size == 0
126
- raise GraphQL::Schema::Enum::MissingValuesError.new(enum_t)
127
- end
128
- h[enum_t] = values
129
- end.compare_by_identity
130
-
131
- @cached_fields = Hash.new do |h, owner|
132
- h[owner] = non_duplicate_items(owner.all_field_definitions.each(&:ensure_loaded), @cached_visible_fields[owner])
133
- end.compare_by_identity
134
-
135
- @cached_arguments = Hash.new do |h, owner|
136
- h[owner] = non_duplicate_items(owner.all_argument_definitions, @cached_visible_arguments)
137
- end.compare_by_identity
138
- end
139
-
140
- def field_on_visible_interface?(field, owner)
141
- ints = owner.interface_type_memberships.map(&:abstract_type)
142
- field_name = field.graphql_name
143
- filtered_ints = interfaces(owner)
144
- any_interface_has_field = false
145
- any_interface_has_visible_field = false
146
- ints.each do |int_t|
147
- if (_int_f_defn = @cached_parent_fields[int_t][field_name])
148
- any_interface_has_field = true
149
-
150
- if filtered_ints.include?(int_t) # TODO cycles, or maybe not necessary since previously checked? && @cached_visible_fields[owner][field]
151
- any_interface_has_visible_field = true
152
- break
153
- end
154
- end
155
- end
156
-
157
- if any_interface_has_field
158
- any_interface_has_visible_field
159
- else
160
- true
161
- end
162
- end
163
-
164
- def type(type_name)
165
- t = if (loaded_t = @all_types[type_name])
166
- loaded_t
167
- elsif !@all_types_loaded
168
- load_all_types
169
- @all_types[type_name]
170
- end
171
- if t
172
- if t.is_a?(Array)
173
- vis_t = nil
174
- t.each do |t_defn|
175
- if @cached_visible[t_defn]
176
- if vis_t.nil?
177
- vis_t = t_defn
178
- else
179
- raise_duplicate_definition(vis_t, t_defn)
180
- end
181
- end
182
- end
183
- vis_t
184
- else
185
- if t && @cached_visible[t]
186
- t
187
- else
188
- nil
189
- end
190
- end
191
- end
192
- end
193
-
194
- def field(owner, field_name)
195
- f = if owner.kind.fields? && (field = @cached_parent_fields[owner][field_name])
196
- field
197
- elsif owner == query_root && (entry_point_field = @schema.introspection_system.entry_point(name: field_name))
198
- entry_point_field
199
- elsif (dynamic_field = @schema.introspection_system.dynamic_field(name: field_name))
200
- dynamic_field
201
- else
202
- nil
203
- end
204
- if f.is_a?(Array)
205
- visible_f = nil
206
- f.each do |f_defn|
207
- if @cached_visible_fields[owner][f_defn]
208
-
209
- if visible_f.nil?
210
- visible_f = f_defn
211
- else
212
- raise_duplicate_definition(visible_f, f_defn)
213
- end
214
- end
215
- end
216
- visible_f.ensure_loaded
217
- elsif f && @cached_visible_fields[owner][f.ensure_loaded]
218
- f
219
- else
220
- nil
221
- end
222
- end
223
-
224
- def fields(owner)
225
- @cached_fields[owner]
226
- end
227
-
228
- def arguments(owner)
229
- @cached_arguments[owner]
230
- end
231
-
232
- def argument(owner, arg_name)
233
- arg = @cached_parent_arguments[owner][arg_name]
234
- if arg.is_a?(Array)
235
- visible_arg = nil
236
- arg.each do |arg_defn|
237
- if @cached_visible_arguments[arg_defn]
238
- if visible_arg.nil?
239
- visible_arg = arg_defn
240
- else
241
- raise_duplicate_definition(visible_arg, arg_defn)
242
- end
243
- end
244
- end
245
- visible_arg
246
- else
247
- if arg && @cached_visible_arguments[arg]
248
- arg
249
- else
250
- nil
251
- end
252
- end
253
- end
254
-
255
- def possible_types(type)
256
- @cached_possible_types[type]
257
- end
258
-
259
- def interfaces(obj_or_int_type)
260
- ints = obj_or_int_type.interface_type_memberships
261
- .select { |itm| @cached_visible[itm] && @cached_visible[itm.abstract_type] }
262
- .map!(&:abstract_type)
263
- ints.uniq! # Remove any duplicate interfaces implemented via other interfaces
264
- ints
265
- end
266
-
267
- def query_root
268
- add_if_visible(@schema.query)
269
- end
270
-
271
- def mutation_root
272
- add_if_visible(@schema.mutation)
273
- end
274
-
275
- def subscription_root
276
- add_if_visible(@schema.subscription)
277
- end
278
-
279
- def all_types
280
- load_all_types
281
- @all_types.values
282
- end
283
-
284
- def all_types_h
285
- load_all_types
286
- @all_types
287
- end
288
-
289
- def enum_values(owner)
290
- @cached_enum_values[owner]
291
- end
292
-
293
- def directive_exists?(dir_name)
294
- if (dir = @schema.directives[dir_name]) && @cached_visible[dir]
295
- !!dir
296
- else
297
- load_all_types
298
- !!@cached_directives[dir_name]
299
- end
300
- end
301
-
302
- def directives
303
- @all_directives ||= begin
304
- load_all_types
305
- dirs = []
306
- @schema.directives.each do |name, dir_defn|
307
- if !@cached_directives[name] && @cached_visible[dir_defn]
308
- dirs << dir_defn
309
- end
310
- end
311
- dirs.concat(@cached_directives.values)
312
- end
313
- end
314
-
315
- def loadable?(t, _ctx)
316
- !@all_types[t.graphql_name] && @cached_visible[t]
317
- end
318
-
319
- def loaded_types
320
- @all_types.values
321
- end
322
-
323
- def reachable_type?(name)
324
- load_all_types
325
- !!@all_types[name]
326
- end
327
-
328
- private
329
-
330
- def add_if_visible(t)
331
- (t && @cached_visible[t]) ? (add_type(t, true); t) : nil
332
- end
333
-
334
- def add_type(t, by_member)
335
- if t && @cached_visible[t]
336
- n = t.graphql_name
337
- if (prev_t = @all_types[n])
338
- if !prev_t.equal?(t)
339
- raise_duplicate_definition(prev_t, t)
340
- end
341
- false
342
- else
343
- @referenced_types[t] << by_member
344
- @all_types[n] = t
345
- @unvisited_types << t
346
- true
347
- end
348
- else
349
- false
350
- end
351
- end
352
-
353
- def non_duplicate_items(definitions, visibility_cache)
354
- non_dups = []
355
- definitions.each do |defn|
356
- if visibility_cache[defn]
357
- if (dup_defn = non_dups.find { |d| d.graphql_name == defn.graphql_name })
358
- raise_duplicate_definition(dup_defn, defn)
359
- end
360
- non_dups << defn
361
- end
362
- end
363
- non_dups
364
- end
365
-
366
- def raise_duplicate_definition(first_defn, second_defn)
367
- raise DuplicateNamesError.new(duplicated_name: first_defn.path, duplicated_definition_1: first_defn.inspect, duplicated_definition_2: second_defn.inspect)
368
- end
369
-
370
- def referenced?(t)
371
- load_all_types
372
- @referenced_types[t].any? { |reference| (reference == true) || @cached_visible[reference] }
373
- end
374
-
375
- def load_all_types
376
- return if @all_types_loaded
377
- @all_types_loaded = true
378
- entry_point_types = [
379
- query_root,
380
- mutation_root,
381
- subscription_root,
382
- *@schema.introspection_system.types.values,
383
- ]
384
-
385
- # Don't include any orphan_types whose interfaces aren't visible.
386
- @schema.orphan_types.each do |orphan_type|
387
- if @cached_visible[orphan_type] &&
388
- orphan_type.interface_type_memberships.any? { |tm| @cached_visible[tm] && @cached_visible[tm.abstract_type] }
389
- entry_point_types << orphan_type
390
- end
391
- end
392
-
393
- @schema.directives.each do |_dir_name, dir_class|
394
- if @cached_visible[dir_class]
395
- arguments(dir_class).each do |arg|
396
- entry_point_types << arg.type.unwrap
397
- end
398
- end
399
- end
400
-
401
- entry_point_types.compact! # TODO why is this necessary?!
402
- entry_point_types.flatten! # handle multiple defns
403
- entry_point_types.each { |t| add_type(t, true) }
404
-
405
- @unfiltered_interface_type_memberships = Hash.new { |h, k| h[k] = [] }.compare_by_identity
406
- @add_possible_types = Set.new
407
-
408
- while @unvisited_types.any?
409
- while t = @unvisited_types.pop
410
- # These have already been checked for `.visible?`
411
- visit_type(t)
412
- end
413
- @add_possible_types.each do |int_t|
414
- itms = @unfiltered_interface_type_memberships[int_t]
415
- itms.each do |itm|
416
- if @cached_visible[itm] && (obj_type = itm.object_type) && @cached_visible[obj_type]
417
- add_type(obj_type, itm)
418
- end
419
- end
420
- end
421
- @add_possible_types.clear
422
- end
423
-
424
- @all_types.delete_if { |type_name, type_defn| !referenced?(type_defn) }
425
- nil
426
- end
427
-
428
- def visit_type(type)
429
- visit_directives(type)
430
- case type.kind.name
431
- when "OBJECT", "INTERFACE"
432
- if type.kind.object?
433
- type.interface_type_memberships.each do |itm|
434
- @unfiltered_interface_type_memberships[itm.abstract_type] << itm
435
- end
436
- # recurse into visible implemented interfaces
437
- interfaces(type).each do |interface|
438
- add_type(interface, type)
439
- end
440
- else
441
- type.orphan_types.each { |t| add_type(t, type)}
442
- end
443
-
444
- # recurse into visible fields
445
- t_f = type.all_field_definitions
446
- t_f.each do |field|
447
- field.ensure_loaded
448
- if @cached_visible[field]
449
- visit_directives(field)
450
- field_type = field.type.unwrap
451
- if field_type.kind.interface?
452
- @add_possible_types.add(field_type)
453
- end
454
- add_type(field_type, field)
455
-
456
- # recurse into visible arguments
457
- arguments(field).each do |argument|
458
- visit_directives(argument)
459
- add_type(argument.type.unwrap, argument)
460
- end
461
- end
462
- end
463
- when "INPUT_OBJECT"
464
- # recurse into visible arguments
465
- arguments(type).each do |argument|
466
- visit_directives(argument)
467
- add_type(argument.type.unwrap, argument)
468
- end
469
- when "UNION"
470
- # recurse into visible possible types
471
- type.type_memberships.each do |tm|
472
- if @cached_visible[tm]
473
- obj_t = tm.object_type
474
- if obj_t.is_a?(String)
475
- obj_t = Member::BuildType.constantize(obj_t)
476
- tm.object_type = obj_t
477
- end
478
- if @cached_visible[obj_t]
479
- add_type(obj_t, tm)
480
- end
481
- end
482
- end
483
- when "ENUM"
484
- enum_values(type).each do |val|
485
- visit_directives(val)
486
- end
487
- when "SCALAR"
488
- # pass
489
- end
490
- end
491
-
492
- def visit_directives(member)
493
- member.directives.each { |dir|
494
- dir_class = dir.class
495
- if @cached_visible[dir_class]
496
- dir_name = dir_class.graphql_name
497
- if (existing_dir = @cached_directives[dir_name])
498
- if existing_dir != dir_class
499
- raise ArgumentError, "Two directives for `@#{dir_name}`: #{existing_dir}, #{dir.class}"
500
- end
501
- else
502
- @cached_directives[dir.graphql_name] = dir_class
503
- end
504
- end
505
- }
506
- end
507
- end
508
- end
509
- end
@@ -1,187 +0,0 @@
1
- # frozen_string_literal: true
2
- module GraphQL
3
- class Schema
4
- # You can add this plugin to your schema to see how {GraphQL::Schema::Warden} and {GraphQL::Schema::Subset}
5
- # handle `.visible?` differently in your schema.
6
- #
7
- # This plugin runs the same method on both implementations and raises an error when the results diverge.
8
- #
9
- # To fix the error, modify your schema so that both implementations return the same thing.
10
- # Or, open an issue on GitHub to discuss the difference.
11
- #
12
- # This plugin adds overhead to runtime and may cause unexpected crashes -- **don't** use it in production!
13
- #
14
- # This plugin adds two keys to `context` when running:
15
- #
16
- # - `types_migration_running: true`
17
- # - For the {Warden} which it instantiates, it adds `types_migration_warden_running: true`.
18
- #
19
- # Use those keys to modify your `visible?` behavior as needed.
20
- #
21
- # Also, in a pinch, you can set `skip_types_migration_error: true` in context to turn off this plugin's behavior per-query.
22
- # (In that case, it uses {Subset} directly.)
23
- #
24
- # @example Adding this plugin
25
- #
26
- # if !Rails.env.production?
27
- # use GraphQL::Schema::TypesMigration
28
- # end
29
- class TypesMigration < GraphQL::Schema::Subset
30
- def self.use(schema)
31
- schema.subset_class = self
32
- end
33
-
34
- class RuntimeTypesMismatchError < GraphQL::Error
35
- def initialize(method_called, warden_result, subset_result, method_args)
36
- super(<<~ERR)
37
- Mismatch in types for `##{method_called}(#{method_args.map(&:inspect).join(", ")})`:
38
-
39
- #{compare_results(warden_result, subset_result)}
40
-
41
- Update your `.visible?` implementation to make these implementations return the same value.
42
-
43
- See: https://graphql-ruby.org/authorization/visibility_migration.html
44
- ERR
45
- end
46
-
47
- private
48
- def compare_results(warden_result, subset_result)
49
- if warden_result.is_a?(Array) && subset_result.is_a?(Array)
50
- all_results = warden_result | subset_result
51
- all_results.sort_by!(&:graphql_name)
52
-
53
- entries_text = all_results.map { |entry| "#{entry.graphql_name} (#{entry})"}
54
- width = entries_text.map(&:size).max
55
- yes = " ✔ "
56
- no = " "
57
- res = "".dup
58
- res << "#{"Result".center(width)} Warden Subset \n"
59
- all_results.each_with_index do |entry, idx|
60
- res << "#{entries_text[idx].ljust(width)}#{warden_result.include?(entry) ? yes : no}#{subset_result.include?(entry) ? yes : no}\n"
61
- end
62
- res << "\n"
63
- else
64
- "- Warden returned: #{humanize(warden_result)}\n\n- Subset returned: #{humanize(subset_result)}"
65
- end
66
- end
67
- def humanize(val)
68
- case val
69
- when Array
70
- "#{val.size}: #{val.map { |v| humanize(v) }.sort.inspect}"
71
- when Module
72
- if val.respond_to?(:graphql_name)
73
- "#{val.graphql_name} (#{val.inspect})"
74
- else
75
- val.inspect
76
- end
77
- else
78
- val.inspect
79
- end
80
- end
81
- end
82
-
83
- def initialize(context:, schema:)
84
- @skip_error = context[:skip_types_migration_error]
85
- context[:types_migration_running] = true
86
- @subset_types = GraphQL::Schema::Subset.new(context: context, schema: schema)
87
- if !@skip_error
88
- warden_ctx_vals = context.to_h.dup
89
- warden_ctx_vals[:types_migration_warden_running] = true
90
- if defined?(schema::WardenCompatSchema)
91
- warden_schema = schema::WardenCompatSchema
92
- else
93
- warden_schema = Class.new(schema)
94
- warden_schema.use_schema_subset = false
95
- # TODO public API
96
- warden_schema.send(:add_type_and_traverse, [warden_schema.query, warden_schema.mutation, warden_schema.subscription].compact, root: true)
97
- warden_schema.send(:add_type_and_traverse, warden_schema.directives.values + warden_schema.orphan_types, root: false)
98
- end
99
- warden_ctx = GraphQL::Query::Context.new(query: context.query, values: warden_ctx_vals)
100
- example_warden = GraphQL::Schema::Warden.new(schema: warden_schema, context: warden_ctx)
101
- @warden_types = example_warden.schema_subset
102
- warden_ctx.warden = example_warden
103
- warden_ctx.types = @warden_types
104
- end
105
- end
106
-
107
- def loaded_types
108
- @subset_types.loaded_types
109
- end
110
-
111
- PUBLIC_SUBSET_METHODS = [
112
- :enum_values,
113
- :interfaces,
114
- :all_types,
115
- :fields,
116
- :loadable?,
117
- :type,
118
- :arguments,
119
- :argument,
120
- :directive_exists?,
121
- :directives,
122
- :field,
123
- :query_root,
124
- :mutation_root,
125
- :possible_types,
126
- :subscription_root,
127
- :reachable_type?
128
- ]
129
-
130
- PUBLIC_SUBSET_METHODS.each do |subset_method|
131
- define_method(subset_method) do |*args|
132
- call_method_and_compare(subset_method, args)
133
- end
134
- end
135
-
136
- def call_method_and_compare(method, args)
137
- res_1 = @subset_types.public_send(method, *args)
138
- if @skip_error
139
- return res_1
140
- end
141
-
142
- res_2 = @warden_types.public_send(method, *args)
143
- normalized_res_1 = res_1.is_a?(Array) ? Set.new(res_1) : res_1
144
- normalized_res_2 = res_2.is_a?(Array) ? Set.new(res_2) : res_2
145
- if !equivalent_schema_members?(normalized_res_1, normalized_res_2)
146
- # Raise the errors with the orignally returned values:
147
- err = RuntimeTypesMismatchError.new(method, res_2, res_1, args)
148
- raise err
149
- else
150
- res_1
151
- end
152
- end
153
-
154
- def equivalent_schema_members?(member1, member2)
155
- if member1.class != member2.class
156
- return false
157
- end
158
-
159
- case member1
160
- when Set
161
- member1_array = member1.to_a.sort_by(&:graphql_name)
162
- member2_array = member2.to_a.sort_by(&:graphql_name)
163
- member1_array.each_with_index do |inner_member1, idx|
164
- inner_member2 = member2_array[idx]
165
- equivalent_schema_members?(inner_member1, inner_member2)
166
- end
167
- when GraphQL::Schema::Field
168
- member1.ensure_loaded
169
- member2.ensure_loaded
170
- if member1.introspection? && member2.introspection?
171
- member1.inspect == member2.inspect
172
- else
173
- member1 == member2
174
- end
175
- when Module
176
- if member1.introspection? && member2.introspection?
177
- member1.graphql_name == member2.graphql_name
178
- else
179
- member1 == member2
180
- end
181
- else
182
- member1 == member2
183
- end
184
- end
185
- end
186
- end
187
- end