graphql 2.4.3 → 2.5.3

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 (171) hide show
  1. checksums.yaml +4 -4
  2. data/lib/graphql/analysis/analyzer.rb +2 -1
  3. data/lib/graphql/analysis/query_complexity.rb +87 -7
  4. data/lib/graphql/analysis/visitor.rb +38 -41
  5. data/lib/graphql/analysis.rb +15 -12
  6. data/lib/graphql/autoload.rb +38 -0
  7. data/lib/graphql/backtrace/table.rb +118 -55
  8. data/lib/graphql/backtrace.rb +1 -19
  9. data/lib/graphql/current.rb +7 -2
  10. data/lib/graphql/dashboard/detailed_traces.rb +47 -0
  11. data/lib/graphql/dashboard/installable.rb +22 -0
  12. data/lib/graphql/dashboard/limiters.rb +93 -0
  13. data/lib/graphql/dashboard/operation_store.rb +199 -0
  14. data/lib/graphql/dashboard/statics/bootstrap-5.3.3.min.css +6 -0
  15. data/lib/graphql/dashboard/statics/bootstrap-5.3.3.min.js +7 -0
  16. data/lib/graphql/dashboard/statics/charts.min.css +1 -0
  17. data/lib/graphql/dashboard/statics/dashboard.css +30 -0
  18. data/lib/graphql/dashboard/statics/dashboard.js +143 -0
  19. data/lib/graphql/dashboard/statics/header-icon.png +0 -0
  20. data/lib/graphql/dashboard/statics/icon.png +0 -0
  21. data/lib/graphql/dashboard/subscriptions.rb +96 -0
  22. data/lib/graphql/dashboard/views/graphql/dashboard/detailed_traces/traces/index.html.erb +45 -0
  23. data/lib/graphql/dashboard/views/graphql/dashboard/landings/show.html.erb +18 -0
  24. data/lib/graphql/dashboard/views/graphql/dashboard/limiters/limiters/show.html.erb +62 -0
  25. data/lib/graphql/dashboard/views/graphql/dashboard/not_installed.html.erb +18 -0
  26. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/_form.html.erb +23 -0
  27. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/edit.html.erb +21 -0
  28. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/index.html.erb +69 -0
  29. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/new.html.erb +7 -0
  30. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/index_entries/index.html.erb +39 -0
  31. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/index_entries/show.html.erb +32 -0
  32. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/operations/index.html.erb +81 -0
  33. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/operations/show.html.erb +71 -0
  34. data/lib/graphql/dashboard/views/graphql/dashboard/subscriptions/subscriptions/show.html.erb +41 -0
  35. data/lib/graphql/dashboard/views/graphql/dashboard/subscriptions/topics/index.html.erb +55 -0
  36. data/lib/graphql/dashboard/views/graphql/dashboard/subscriptions/topics/show.html.erb +40 -0
  37. data/lib/graphql/dashboard/views/layouts/graphql/dashboard/application.html.erb +108 -0
  38. data/lib/graphql/dashboard.rb +158 -0
  39. data/lib/graphql/dataloader/active_record_association_source.rb +64 -0
  40. data/lib/graphql/dataloader/active_record_source.rb +26 -0
  41. data/lib/graphql/dataloader/async_dataloader.rb +21 -9
  42. data/lib/graphql/dataloader/null_dataloader.rb +1 -1
  43. data/lib/graphql/dataloader/source.rb +3 -3
  44. data/lib/graphql/dataloader.rb +43 -14
  45. data/lib/graphql/dig.rb +2 -1
  46. data/lib/graphql/execution/interpreter/resolve.rb +3 -3
  47. data/lib/graphql/execution/interpreter/runtime/graphql_result.rb +34 -4
  48. data/lib/graphql/execution/interpreter/runtime.rb +96 -52
  49. data/lib/graphql/execution/interpreter.rb +16 -7
  50. data/lib/graphql/execution/multiplex.rb +6 -5
  51. data/lib/graphql/introspection/directive_location_enum.rb +1 -1
  52. data/lib/graphql/invalid_name_error.rb +1 -1
  53. data/lib/graphql/invalid_null_error.rb +19 -16
  54. data/lib/graphql/language/cache.rb +13 -0
  55. data/lib/graphql/language/document_from_schema_definition.rb +8 -7
  56. data/lib/graphql/language/lexer.rb +11 -4
  57. data/lib/graphql/language/nodes.rb +3 -0
  58. data/lib/graphql/language/parser.rb +15 -8
  59. data/lib/graphql/language/printer.rb +8 -8
  60. data/lib/graphql/language/static_visitor.rb +37 -33
  61. data/lib/graphql/language/visitor.rb +59 -55
  62. data/lib/graphql/pagination/connection.rb +1 -1
  63. data/lib/graphql/query/context/scoped_context.rb +1 -1
  64. data/lib/graphql/query/context.rb +7 -5
  65. data/lib/graphql/query/variable_validation_error.rb +1 -1
  66. data/lib/graphql/query.rb +22 -32
  67. data/lib/graphql/railtie.rb +7 -0
  68. data/lib/graphql/schema/addition.rb +1 -1
  69. data/lib/graphql/schema/always_visible.rb +1 -0
  70. data/lib/graphql/schema/argument.rb +7 -8
  71. data/lib/graphql/schema/build_from_definition.rb +99 -53
  72. data/lib/graphql/schema/directive/flagged.rb +3 -1
  73. data/lib/graphql/schema/directive.rb +2 -2
  74. data/lib/graphql/schema/enum.rb +36 -1
  75. data/lib/graphql/schema/enum_value.rb +1 -1
  76. data/lib/graphql/schema/field/scope_extension.rb +1 -1
  77. data/lib/graphql/schema/field.rb +27 -13
  78. data/lib/graphql/schema/field_extension.rb +1 -1
  79. data/lib/graphql/schema/has_single_input_argument.rb +3 -1
  80. data/lib/graphql/schema/input_object.rb +77 -40
  81. data/lib/graphql/schema/interface.rb +3 -2
  82. data/lib/graphql/schema/list.rb +1 -1
  83. data/lib/graphql/schema/loader.rb +1 -1
  84. data/lib/graphql/schema/member/has_arguments.rb +25 -17
  85. data/lib/graphql/schema/member/has_dataloader.rb +62 -0
  86. data/lib/graphql/schema/member/has_deprecation_reason.rb +15 -0
  87. data/lib/graphql/schema/member/has_directives.rb +4 -4
  88. data/lib/graphql/schema/member/has_fields.rb +19 -1
  89. data/lib/graphql/schema/member/has_interfaces.rb +5 -5
  90. data/lib/graphql/schema/member/has_validators.rb +1 -1
  91. data/lib/graphql/schema/member/scoped.rb +1 -1
  92. data/lib/graphql/schema/member/type_system_helpers.rb +1 -1
  93. data/lib/graphql/schema/member.rb +1 -0
  94. data/lib/graphql/schema/object.rb +25 -8
  95. data/lib/graphql/schema/relay_classic_mutation.rb +0 -1
  96. data/lib/graphql/schema/resolver.rb +12 -10
  97. data/lib/graphql/schema/subscription.rb +52 -6
  98. data/lib/graphql/schema/union.rb +1 -1
  99. data/lib/graphql/schema/validator/required_validator.rb +23 -6
  100. data/lib/graphql/schema/validator.rb +1 -1
  101. data/lib/graphql/schema/visibility/migration.rb +1 -0
  102. data/lib/graphql/schema/visibility/profile.rb +98 -244
  103. data/lib/graphql/schema/visibility/visit.rb +190 -0
  104. data/lib/graphql/schema/visibility.rb +178 -38
  105. data/lib/graphql/schema/warden.rb +18 -5
  106. data/lib/graphql/schema.rb +266 -54
  107. data/lib/graphql/static_validation/all_rules.rb +1 -1
  108. data/lib/graphql/static_validation/rules/argument_names_are_unique.rb +1 -1
  109. data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +47 -13
  110. data/lib/graphql/static_validation/rules/fields_will_merge.rb +79 -17
  111. data/lib/graphql/static_validation/rules/fields_will_merge_error.rb +10 -2
  112. data/lib/graphql/static_validation/rules/no_definitions_are_present.rb +1 -1
  113. data/lib/graphql/static_validation/rules/not_single_subscription_error.rb +25 -0
  114. data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +1 -1
  115. data/lib/graphql/static_validation/rules/subscription_root_exists_and_single_subscription_selection.rb +26 -0
  116. data/lib/graphql/static_validation/rules/unique_directives_per_location.rb +1 -1
  117. data/lib/graphql/static_validation/rules/variable_names_are_unique.rb +1 -1
  118. data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +1 -1
  119. data/lib/graphql/static_validation/validation_context.rb +1 -0
  120. data/lib/graphql/static_validation/validator.rb +6 -1
  121. data/lib/graphql/subscriptions/action_cable_subscriptions.rb +1 -1
  122. data/lib/graphql/subscriptions/default_subscription_resolve_extension.rb +12 -10
  123. data/lib/graphql/subscriptions/event.rb +12 -1
  124. data/lib/graphql/subscriptions/serialize.rb +1 -1
  125. data/lib/graphql/subscriptions.rb +1 -1
  126. data/lib/graphql/testing/helpers.rb +7 -4
  127. data/lib/graphql/tracing/active_support_notifications_trace.rb +14 -3
  128. data/lib/graphql/tracing/active_support_notifications_tracing.rb +1 -1
  129. data/lib/graphql/tracing/appoptics_trace.rb +9 -1
  130. data/lib/graphql/tracing/appoptics_tracing.rb +7 -0
  131. data/lib/graphql/tracing/appsignal_trace.rb +32 -55
  132. data/lib/graphql/tracing/appsignal_tracing.rb +2 -0
  133. data/lib/graphql/tracing/call_legacy_tracers.rb +66 -0
  134. data/lib/graphql/tracing/data_dog_trace.rb +46 -158
  135. data/lib/graphql/tracing/data_dog_tracing.rb +2 -0
  136. data/lib/graphql/tracing/detailed_trace/memory_backend.rb +60 -0
  137. data/lib/graphql/tracing/detailed_trace/redis_backend.rb +72 -0
  138. data/lib/graphql/tracing/detailed_trace.rb +93 -0
  139. data/lib/graphql/tracing/legacy_hooks_trace.rb +1 -0
  140. data/lib/graphql/tracing/legacy_trace.rb +4 -61
  141. data/lib/graphql/tracing/monitor_trace.rb +283 -0
  142. data/lib/graphql/tracing/new_relic_trace.rb +47 -54
  143. data/lib/graphql/tracing/new_relic_tracing.rb +2 -0
  144. data/lib/graphql/tracing/notifications_trace.rb +182 -34
  145. data/lib/graphql/tracing/notifications_tracing.rb +2 -0
  146. data/lib/graphql/tracing/null_trace.rb +9 -0
  147. data/lib/graphql/tracing/perfetto_trace/trace.proto +141 -0
  148. data/lib/graphql/tracing/perfetto_trace/trace_pb.rb +33 -0
  149. data/lib/graphql/tracing/perfetto_trace.rb +734 -0
  150. data/lib/graphql/tracing/platform_trace.rb +5 -0
  151. data/lib/graphql/tracing/prometheus_trace/graphql_collector.rb +2 -0
  152. data/lib/graphql/tracing/prometheus_trace.rb +72 -68
  153. data/lib/graphql/tracing/prometheus_tracing.rb +2 -0
  154. data/lib/graphql/tracing/scout_trace.rb +32 -55
  155. data/lib/graphql/tracing/scout_tracing.rb +2 -0
  156. data/lib/graphql/tracing/sentry_trace.rb +62 -94
  157. data/lib/graphql/tracing/statsd_trace.rb +33 -41
  158. data/lib/graphql/tracing/statsd_tracing.rb +2 -0
  159. data/lib/graphql/tracing/trace.rb +111 -1
  160. data/lib/graphql/tracing.rb +31 -30
  161. data/lib/graphql/types/relay/connection_behaviors.rb +3 -3
  162. data/lib/graphql/types/relay/edge_behaviors.rb +2 -2
  163. data/lib/graphql/types.rb +18 -11
  164. data/lib/graphql/version.rb +1 -1
  165. data/lib/graphql.rb +55 -47
  166. metadata +146 -11
  167. data/lib/graphql/backtrace/inspect_result.rb +0 -38
  168. data/lib/graphql/backtrace/trace.rb +0 -93
  169. data/lib/graphql/backtrace/tracer.rb +0 -80
  170. data/lib/graphql/schema/null_mask.rb +0 -11
  171. data/lib/graphql/static_validation/rules/subscription_root_exists.rb +0 -17
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
  require "graphql/schema/visibility/profile"
3
3
  require "graphql/schema/visibility/migration"
4
+ require "graphql/schema/visibility/visit"
4
5
 
5
6
  module GraphQL
6
7
  class Schema
@@ -12,41 +13,80 @@ module GraphQL
12
13
  # @param preload [Boolean] if `true`, load the default schema profile and all named profiles immediately (defaults to `true` for `Rails.env.production?`)
13
14
  # @param migration_errors [Boolean] if `true`, raise an error when `Visibility` and `Warden` return different results
14
15
  def self.use(schema, dynamic: false, profiles: EmptyObjects::EMPTY_HASH, preload: (defined?(Rails) ? Rails.env.production? : nil), migration_errors: false)
16
+ profiles&.each { |name, ctx|
17
+ ctx[:visibility_profile] = name
18
+ ctx.freeze
19
+ }
15
20
  schema.visibility = self.new(schema, dynamic: dynamic, preload: preload, profiles: profiles, migration_errors: migration_errors)
21
+ if preload
22
+ schema.visibility.preload
23
+ end
16
24
  end
17
25
 
18
26
  def initialize(schema, dynamic:, preload:, profiles:, migration_errors:)
19
27
  @schema = schema
20
28
  schema.use_visibility_profile = true
21
- if migration_errors
22
- schema.visibility_profile_class = Migration
29
+ schema.visibility_profile_class = if migration_errors
30
+ Visibility::Migration
31
+ else
32
+ Visibility::Profile
23
33
  end
24
34
  @preload = preload
25
35
  @profiles = profiles
26
36
  @cached_profiles = {}
27
37
  @dynamic = dynamic
28
38
  @migration_errors = migration_errors
29
- if preload
30
- # Traverse the schema now (and in the *_configured hooks below)
31
- # To make sure things are loaded during boot
32
- @preloaded_types = Set.new
33
- types_to_visit = [
34
- @schema.query,
35
- @schema.mutation,
36
- @schema.subscription,
37
- *@schema.introspection_system.types.values,
38
- *@schema.introspection_system.entry_points.map { |ep| ep.type.unwrap },
39
- *@schema.orphan_types,
40
- ]
41
- # Root types may have been nil:
42
- types_to_visit.compact!
43
- ensure_all_loaded(types_to_visit)
44
-
45
- profiles.each do |profile_name, example_ctx|
46
- example_ctx[:visibility_profile] = profile_name
47
- prof = profile_for(example_ctx, profile_name)
48
- prof.all_types # force loading
49
- end
39
+ # Top-level type caches:
40
+ @visit = nil
41
+ @interface_type_memberships = nil
42
+ @directives = nil
43
+ @types = nil
44
+ @all_references = nil
45
+ @loaded_all = false
46
+ end
47
+
48
+ def all_directives
49
+ load_all
50
+ @directives
51
+ end
52
+
53
+ def all_interface_type_memberships
54
+ load_all
55
+ @interface_type_memberships
56
+ end
57
+
58
+ def all_references
59
+ load_all
60
+ @all_references
61
+ end
62
+
63
+ def get_type(type_name)
64
+ load_all
65
+ @types[type_name]
66
+ end
67
+
68
+ def preload?
69
+ @preload
70
+ end
71
+
72
+ def preload
73
+ # Traverse the schema now (and in the *_configured hooks below)
74
+ # To make sure things are loaded during boot
75
+ @preloaded_types = Set.new
76
+ types_to_visit = [
77
+ @schema.query,
78
+ @schema.mutation,
79
+ @schema.subscription,
80
+ *@schema.introspection_system.types.values,
81
+ *@schema.introspection_system.entry_points.map { |ep| ep.type.unwrap },
82
+ *@schema.orphan_types,
83
+ ]
84
+ # Root types may have been nil:
85
+ types_to_visit.compact!
86
+ ensure_all_loaded(types_to_visit)
87
+ @profiles.each do |profile_name, example_ctx|
88
+ prof = profile_for(example_ctx)
89
+ prof.all_types # force loading
50
90
  end
51
91
  end
52
92
 
@@ -108,22 +148,22 @@ module GraphQL
108
148
 
109
149
  attr_reader :cached_profiles
110
150
 
111
- def profile_for(context, visibility_profile)
112
- if @profiles.any?
113
- if visibility_profile.nil?
114
- if @dynamic
115
- if context.is_a?(Query::NullContext)
116
- top_level_profile
117
- else
118
- @schema.visibility_profile_class.new(context: context, schema: @schema)
119
- end
120
- elsif @profiles.any?
121
- raise ArgumentError, "#{@schema} expects a visibility profile, but `visibility_profile:` wasn't passed. Provide a `visibility_profile:` value or add `dynamic: true` to your visibility configuration."
151
+ def profile_for(context)
152
+ if !@profiles.empty?
153
+ visibility_profile = context[:visibility_profile]
154
+ if @profiles.include?(visibility_profile)
155
+ profile_ctx = @profiles[visibility_profile]
156
+ @cached_profiles[visibility_profile] ||= @schema.visibility_profile_class.new(name: visibility_profile, context: profile_ctx, schema: @schema)
157
+ elsif @dynamic
158
+ if context.is_a?(Query::NullContext)
159
+ top_level_profile
160
+ else
161
+ @schema.visibility_profile_class.new(context: context, schema: @schema)
122
162
  end
123
- elsif !@profiles.include?(visibility_profile)
124
- raise ArgumentError, "`#{visibility_profile.inspect}` isn't allowed for `visibility_profile:` (must be one of #{@profiles.keys.map(&:inspect).join(", ")}). Or, add `#{visibility_profile.inspect}` to the list of profiles in the schema definition."
163
+ elsif !context.key?(:visibility_profile)
164
+ raise ArgumentError, "#{@schema} expects a visibility profile, but `visibility_profile:` wasn't passed. Provide a `visibility_profile:` value or add `dynamic: true` to your visibility configuration."
125
165
  else
126
- @cached_profiles[visibility_profile] ||= @schema.visibility_profile_class.new(name: visibility_profile, context: context, schema: @schema)
166
+ raise ArgumentError, "`#{visibility_profile.inspect}` isn't allowed for `visibility_profile:` (must be one of #{@profiles.keys.map(&:inspect).join(", ")}). Or, add `#{visibility_profile.inspect}` to the list of profiles in the schema definition."
127
167
  end
128
168
  elsif context.is_a?(Query::NullContext)
129
169
  top_level_profile
@@ -132,7 +172,10 @@ module GraphQL
132
172
  end
133
173
  end
134
174
 
135
- private
175
+ attr_reader :top_level
176
+
177
+ # @api private
178
+ attr_reader :unfiltered_interface_type_memberships
136
179
 
137
180
  def top_level_profile(refresh: false)
138
181
  if refresh
@@ -141,6 +184,8 @@ module GraphQL
141
184
  @top_level_profile ||= @schema.visibility_profile_class.new(context: Query::NullContext.instance, schema: @schema)
142
185
  end
143
186
 
187
+ private
188
+
144
189
  def ensure_all_loaded(types_to_visit)
145
190
  while (type = types_to_visit.shift)
146
191
  if type.kind.fields? && @preloaded_types.add?(type)
@@ -153,6 +198,101 @@ module GraphQL
153
198
  top_level_profile(refresh: true)
154
199
  nil
155
200
  end
201
+
202
+ def load_all(types: nil)
203
+ if @visit.nil?
204
+ # Set up the visit system
205
+ @interface_type_memberships = Hash.new { |h, interface_type| h[interface_type] = [] }.compare_by_identity
206
+ @directives = []
207
+ @types = {} # String => Module
208
+ @all_references = Hash.new { |h, member| h[member] = Set.new.compare_by_identity }.compare_by_identity
209
+ @unions_for_references = Set.new
210
+ @visit = Visibility::Visit.new(@schema) do |member|
211
+ if member.is_a?(Module)
212
+ type_name = member.graphql_name
213
+ if (prev_t = @types[type_name])
214
+ if prev_t.is_a?(Array)
215
+ prev_t << member
216
+ else
217
+ @types[type_name] = [member, prev_t]
218
+ end
219
+ else
220
+ @types[member.graphql_name] = member
221
+ end
222
+ member.directives.each { |dir| @all_references[dir.class] << member }
223
+ if member < GraphQL::Schema::Directive
224
+ @directives << member
225
+ elsif member.respond_to?(:interface_type_memberships)
226
+ member.interface_type_memberships.each do |itm|
227
+ @all_references[itm.abstract_type] << member
228
+ # `itm.object_type` may not actually be `member` if this implementation
229
+ # is inherited from a superclass
230
+ @interface_type_memberships[itm.abstract_type] << [itm, member]
231
+ end
232
+ elsif member < GraphQL::Schema::Union
233
+ @unions_for_references << member
234
+ end
235
+ elsif member.is_a?(GraphQL::Schema::Argument)
236
+ member.validate_default_value
237
+ @all_references[member.type.unwrap] << member
238
+ if !(dirs = member.directives).empty?
239
+ dir_owner = member.owner
240
+ if dir_owner.respond_to?(:owner)
241
+ dir_owner = dir_owner.owner
242
+ end
243
+ dirs.each { |dir| @all_references[dir.class] << dir_owner }
244
+ end
245
+ elsif member.is_a?(GraphQL::Schema::Field)
246
+ @all_references[member.type.unwrap] << member
247
+ if !(dirs = member.directives).empty?
248
+ dir_owner = member.owner
249
+ dirs.each { |dir| @all_references[dir.class] << dir_owner }
250
+ end
251
+ elsif member.is_a?(GraphQL::Schema::EnumValue)
252
+ if !(dirs = member.directives).empty?
253
+ dir_owner = member.owner
254
+ dirs.each { |dir| @all_references[dir.class] << dir_owner }
255
+ end
256
+ end
257
+ true
258
+ end
259
+
260
+ @schema.root_types.each { |t| @all_references[t] << true }
261
+ @schema.introspection_system.types.each_value { |t| @all_references[t] << true }
262
+ @schema.directives.each_value { |dir_class| @all_references[dir_class] << true }
263
+
264
+ @visit.visit_each(types: []) # visit default directives
265
+ end
266
+
267
+ if types
268
+ @visit.visit_each(types: types, directives: [])
269
+ elsif @loaded_all == false
270
+ @loaded_all = true
271
+ @visit.visit_each
272
+ else
273
+ # already loaded all
274
+ return
275
+ end
276
+
277
+ # TODO: somehow don't iterate over all these,
278
+ # only the ones that may have been modified
279
+ @interface_type_memberships.each do |int_type, type_membership_pairs|
280
+ referers = @all_references[int_type].select { |r| r.is_a?(GraphQL::Schema::Field) }
281
+ if !referers.empty?
282
+ type_membership_pairs.each do |(type_membership, impl_type)|
283
+ # Add new items only:
284
+ @all_references[impl_type] |= referers
285
+ end
286
+ end
287
+ end
288
+
289
+ @unions_for_references.each do |union_type|
290
+ refs = @all_references[union_type]
291
+ union_type.all_possible_types.each do |object_type|
292
+ @all_references[object_type] |= refs # Add new items
293
+ end
294
+ end
295
+ end
156
296
  end
157
297
  end
158
298
  end
@@ -72,6 +72,7 @@ module GraphQL
72
72
  def interface_type_memberships(obj_t, ctx); obj_t.interface_type_memberships; end
73
73
  def arguments(owner, ctx); owner.arguments(ctx); end
74
74
  def loadable?(type, ctx); type.visible?(ctx); end
75
+ def loadable_possible_types(type, ctx); type.possible_types(ctx); end
75
76
  def visibility_profile
76
77
  @visibility_profile ||= Warden::VisibilityProfile.new(self)
77
78
  end
@@ -106,6 +107,7 @@ module GraphQL
106
107
  def get_field(parent_type, field_name); @schema.get_field(parent_type, field_name); end
107
108
  def reachable_type?(type_name); true; end
108
109
  def loadable?(type, _ctx); true; end
110
+ def loadable_possible_types(union_type, _ctx); union_type.possible_types; end
109
111
  def reachable_types; @schema.types.values; end # rubocop:disable Development/ContextIsPassedCop
110
112
  def possible_types(type_defn); @schema.possible_types(type_defn, Query::NullContext.instance, false); end
111
113
  def interfaces(obj_type); obj_type.interfaces; end
@@ -180,6 +182,10 @@ module GraphQL
180
182
  @warden.loadable?(t, ctx)
181
183
  end
182
184
 
185
+ def loadable_possible_types(t, ctx)
186
+ @warden.loadable_possible_types(t, ctx)
187
+ end
188
+
183
189
  def reachable_type?(type_name)
184
190
  !!@warden.reachable_type?(type_name)
185
191
  end
@@ -204,7 +210,7 @@ module GraphQL
204
210
  @visible_possible_types = @visible_fields = @visible_arguments = @visible_enum_arrays =
205
211
  @visible_enum_values = @visible_interfaces = @type_visibility = @type_memberships =
206
212
  @visible_and_reachable_type = @unions = @unfiltered_interfaces =
207
- @reachable_type_set = @visibility_profile =
213
+ @reachable_type_set = @visibility_profile = @loadable_possible_types =
208
214
  nil
209
215
  @skip_warning = schema.plugins.any? { |(plugin, _opts)| plugin == GraphQL::Schema::Warden }
210
216
  end
@@ -229,6 +235,13 @@ module GraphQL
229
235
  !reachable_type_set.include?(type) && visible_type?(type)
230
236
  end
231
237
 
238
+ def loadable_possible_types(union_type, _ctx)
239
+ @loadable_possible_types ||= read_through do |t|
240
+ t.possible_types # unfiltered
241
+ end
242
+ @loadable_possible_types[union_type]
243
+ end
244
+
232
245
  # @return [GraphQL::BaseType, nil] The type named `type_name`, if it exists (else `nil`)
233
246
  def get_type(type_name)
234
247
  @visible_types ||= read_through do |name|
@@ -297,7 +310,7 @@ module GraphQL
297
310
  def arguments(argument_owner, ctx = nil)
298
311
  @visible_arguments ||= read_through { |o|
299
312
  args = o.arguments(@context)
300
- if args.any?
313
+ if !args.empty?
301
314
  args = args.values
302
315
  args.select! { |a| visible_argument?(a, @context) }
303
316
  args
@@ -329,7 +342,7 @@ module GraphQL
329
342
  def interfaces(obj_type)
330
343
  @visible_interfaces ||= read_through { |t|
331
344
  ints = t.interfaces(@context)
332
- if ints.any?
345
+ if !ints.empty?
333
346
  ints.select! { |i| visible_type?(i) }
334
347
  end
335
348
  ints
@@ -389,9 +402,9 @@ module GraphQL
389
402
  next true if root_type?(type_defn) || type_defn.introspection?
390
403
 
391
404
  if type_defn.kind.union?
392
- possible_types(type_defn).any? && (referenced?(type_defn) || orphan_type?(type_defn))
405
+ !possible_types(type_defn).empty? && (referenced?(type_defn) || orphan_type?(type_defn))
393
406
  elsif type_defn.kind.interface?
394
- if possible_types(type_defn).any?
407
+ if !possible_types(type_defn).empty?
395
408
  true
396
409
  else
397
410
  if @context.respond_to?(:logger) && (logger = @context.logger)