graphql 2.0.30 → 2.3.6

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 (157) hide show
  1. checksums.yaml +4 -4
  2. data/lib/generators/graphql/install/mutation_root_generator.rb +2 -2
  3. data/lib/generators/graphql/install/templates/base_mutation.erb +2 -0
  4. data/lib/generators/graphql/install/templates/mutation_type.erb +2 -0
  5. data/lib/generators/graphql/install_generator.rb +3 -0
  6. data/lib/generators/graphql/templates/base_argument.erb +2 -0
  7. data/lib/generators/graphql/templates/base_connection.erb +2 -0
  8. data/lib/generators/graphql/templates/base_edge.erb +2 -0
  9. data/lib/generators/graphql/templates/base_enum.erb +2 -0
  10. data/lib/generators/graphql/templates/base_field.erb +2 -0
  11. data/lib/generators/graphql/templates/base_input_object.erb +2 -0
  12. data/lib/generators/graphql/templates/base_interface.erb +2 -0
  13. data/lib/generators/graphql/templates/base_object.erb +2 -0
  14. data/lib/generators/graphql/templates/base_resolver.erb +6 -0
  15. data/lib/generators/graphql/templates/base_scalar.erb +2 -0
  16. data/lib/generators/graphql/templates/base_union.erb +2 -0
  17. data/lib/generators/graphql/templates/graphql_controller.erb +2 -0
  18. data/lib/generators/graphql/templates/loader.erb +2 -0
  19. data/lib/generators/graphql/templates/mutation.erb +2 -0
  20. data/lib/generators/graphql/templates/node_type.erb +2 -0
  21. data/lib/generators/graphql/templates/query_type.erb +2 -0
  22. data/lib/generators/graphql/templates/schema.erb +5 -0
  23. data/lib/graphql/analysis/analyzer.rb +89 -0
  24. data/lib/graphql/analysis/field_usage.rb +82 -0
  25. data/lib/graphql/analysis/max_query_complexity.rb +20 -0
  26. data/lib/graphql/analysis/max_query_depth.rb +20 -0
  27. data/lib/graphql/analysis/query_complexity.rb +183 -0
  28. data/lib/graphql/analysis/query_depth.rb +58 -0
  29. data/lib/graphql/analysis/visitor.rb +282 -0
  30. data/lib/graphql/analysis.rb +92 -1
  31. data/lib/graphql/backtrace/inspect_result.rb +0 -12
  32. data/lib/graphql/backtrace/trace.rb +12 -15
  33. data/lib/graphql/coercion_error.rb +1 -9
  34. data/lib/graphql/dataloader/async_dataloader.rb +88 -0
  35. data/lib/graphql/dataloader/null_dataloader.rb +1 -1
  36. data/lib/graphql/dataloader/request.rb +5 -0
  37. data/lib/graphql/dataloader/source.rb +11 -3
  38. data/lib/graphql/dataloader.rb +112 -142
  39. data/lib/graphql/duration_encoding_error.rb +16 -0
  40. data/lib/graphql/execution/interpreter/argument_value.rb +5 -1
  41. data/lib/graphql/execution/interpreter/runtime/graphql_result.rb +175 -0
  42. data/lib/graphql/execution/interpreter/runtime.rb +163 -365
  43. data/lib/graphql/execution/interpreter.rb +92 -158
  44. data/lib/graphql/execution/lookahead.rb +88 -21
  45. data/lib/graphql/introspection/dynamic_fields.rb +1 -1
  46. data/lib/graphql/introspection/entry_points.rb +11 -5
  47. data/lib/graphql/introspection/schema_type.rb +3 -1
  48. data/lib/graphql/language/block_string.rb +34 -18
  49. data/lib/graphql/language/definition_slice.rb +1 -1
  50. data/lib/graphql/language/document_from_schema_definition.rb +38 -38
  51. data/lib/graphql/language/lexer.rb +305 -193
  52. data/lib/graphql/language/nodes.rb +113 -66
  53. data/lib/graphql/language/parser.rb +787 -1986
  54. data/lib/graphql/language/printer.rb +303 -146
  55. data/lib/graphql/language/sanitized_printer.rb +20 -22
  56. data/lib/graphql/language/static_visitor.rb +167 -0
  57. data/lib/graphql/language/visitor.rb +20 -81
  58. data/lib/graphql/language.rb +61 -0
  59. data/lib/graphql/load_application_object_failed_error.rb +5 -1
  60. data/lib/graphql/pagination/array_connection.rb +6 -6
  61. data/lib/graphql/pagination/connection.rb +28 -1
  62. data/lib/graphql/pagination/mongoid_relation_connection.rb +1 -2
  63. data/lib/graphql/query/context/scoped_context.rb +101 -0
  64. data/lib/graphql/query/context.rb +66 -131
  65. data/lib/graphql/query/null_context.rb +4 -11
  66. data/lib/graphql/query/validation_pipeline.rb +4 -4
  67. data/lib/graphql/query/variables.rb +3 -3
  68. data/lib/graphql/query.rb +17 -26
  69. data/lib/graphql/railtie.rb +9 -6
  70. data/lib/graphql/rake_task.rb +3 -12
  71. data/lib/graphql/rubocop/graphql/base_cop.rb +1 -1
  72. data/lib/graphql/schema/addition.rb +21 -11
  73. data/lib/graphql/schema/argument.rb +43 -8
  74. data/lib/graphql/schema/base_64_encoder.rb +3 -5
  75. data/lib/graphql/schema/build_from_definition.rb +9 -12
  76. data/lib/graphql/schema/directive/one_of.rb +12 -0
  77. data/lib/graphql/schema/directive/specified_by.rb +14 -0
  78. data/lib/graphql/schema/directive.rb +3 -1
  79. data/lib/graphql/schema/enum.rb +3 -3
  80. data/lib/graphql/schema/field/connection_extension.rb +1 -15
  81. data/lib/graphql/schema/field/scope_extension.rb +8 -1
  82. data/lib/graphql/schema/field.rb +49 -35
  83. data/lib/graphql/schema/has_single_input_argument.rb +157 -0
  84. data/lib/graphql/schema/input_object.rb +4 -4
  85. data/lib/graphql/schema/interface.rb +10 -10
  86. data/lib/graphql/schema/introspection_system.rb +4 -2
  87. data/lib/graphql/schema/late_bound_type.rb +4 -0
  88. data/lib/graphql/schema/list.rb +2 -2
  89. data/lib/graphql/schema/loader.rb +2 -3
  90. data/lib/graphql/schema/member/base_dsl_methods.rb +2 -1
  91. data/lib/graphql/schema/member/has_arguments.rb +63 -73
  92. data/lib/graphql/schema/member/has_directives.rb +1 -1
  93. data/lib/graphql/schema/member/has_fields.rb +8 -5
  94. data/lib/graphql/schema/member/has_interfaces.rb +23 -9
  95. data/lib/graphql/schema/member/relay_shortcuts.rb +1 -1
  96. data/lib/graphql/schema/member/scoped.rb +19 -0
  97. data/lib/graphql/schema/member/type_system_helpers.rb +1 -2
  98. data/lib/graphql/schema/member/validates_input.rb +3 -3
  99. data/lib/graphql/schema/mutation.rb +7 -0
  100. data/lib/graphql/schema/object.rb +8 -0
  101. data/lib/graphql/schema/printer.rb +8 -7
  102. data/lib/graphql/schema/relay_classic_mutation.rb +6 -128
  103. data/lib/graphql/schema/resolver.rb +27 -13
  104. data/lib/graphql/schema/scalar.rb +3 -3
  105. data/lib/graphql/schema/subscription.rb +11 -4
  106. data/lib/graphql/schema/union.rb +1 -1
  107. data/lib/graphql/schema/unique_within_type.rb +1 -1
  108. data/lib/graphql/schema/warden.rb +96 -95
  109. data/lib/graphql/schema.rb +323 -102
  110. data/lib/graphql/static_validation/all_rules.rb +1 -1
  111. data/lib/graphql/static_validation/base_visitor.rb +1 -1
  112. data/lib/graphql/static_validation/literal_validator.rb +2 -3
  113. data/lib/graphql/static_validation/rules/fields_will_merge.rb +2 -2
  114. data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +1 -1
  115. data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +2 -2
  116. data/lib/graphql/static_validation/validation_context.rb +5 -5
  117. data/lib/graphql/static_validation/validator.rb +3 -0
  118. data/lib/graphql/static_validation.rb +0 -1
  119. data/lib/graphql/subscriptions/action_cable_subscriptions.rb +4 -3
  120. data/lib/graphql/subscriptions/broadcast_analyzer.rb +1 -1
  121. data/lib/graphql/subscriptions/event.rb +8 -2
  122. data/lib/graphql/subscriptions/serialize.rb +2 -0
  123. data/lib/graphql/subscriptions.rb +15 -13
  124. data/lib/graphql/testing/helpers.rb +151 -0
  125. data/lib/graphql/testing.rb +2 -0
  126. data/lib/graphql/tracing/appoptics_trace.rb +2 -2
  127. data/lib/graphql/tracing/appoptics_tracing.rb +2 -2
  128. data/lib/graphql/tracing/legacy_hooks_trace.rb +74 -0
  129. data/lib/graphql/tracing/platform_tracing.rb +3 -1
  130. data/lib/graphql/tracing/{prometheus_tracing → prometheus_trace}/graphql_collector.rb +3 -1
  131. data/lib/graphql/tracing/prometheus_trace.rb +9 -9
  132. data/lib/graphql/tracing/sentry_trace.rb +112 -0
  133. data/lib/graphql/tracing/trace.rb +1 -0
  134. data/lib/graphql/tracing.rb +3 -1
  135. data/lib/graphql/type_kinds.rb +1 -1
  136. data/lib/graphql/types/iso_8601_duration.rb +77 -0
  137. data/lib/graphql/types/relay/connection_behaviors.rb +32 -2
  138. data/lib/graphql/types/relay/edge_behaviors.rb +7 -0
  139. data/lib/graphql/types.rb +1 -0
  140. data/lib/graphql/version.rb +1 -1
  141. data/lib/graphql.rb +13 -13
  142. data/readme.md +12 -2
  143. metadata +33 -26
  144. data/lib/graphql/analysis/ast/analyzer.rb +0 -84
  145. data/lib/graphql/analysis/ast/field_usage.rb +0 -57
  146. data/lib/graphql/analysis/ast/max_query_complexity.rb +0 -22
  147. data/lib/graphql/analysis/ast/max_query_depth.rb +0 -22
  148. data/lib/graphql/analysis/ast/query_complexity.rb +0 -230
  149. data/lib/graphql/analysis/ast/query_depth.rb +0 -55
  150. data/lib/graphql/analysis/ast/visitor.rb +0 -276
  151. data/lib/graphql/analysis/ast.rb +0 -81
  152. data/lib/graphql/deprecation.rb +0 -9
  153. data/lib/graphql/filter.rb +0 -59
  154. data/lib/graphql/language/parser.y +0 -560
  155. data/lib/graphql/schema/base_64_bp.rb +0 -26
  156. data/lib/graphql/static_validation/type_stack.rb +0 -216
  157. data/lib/graphql/subscriptions/instrumentation.rb +0 -28
@@ -4,37 +4,12 @@ require 'set'
4
4
 
5
5
  module GraphQL
6
6
  class Schema
7
- # Restrict access to a {GraphQL::Schema} with a user-defined filter.
7
+ # Restrict access to a {GraphQL::Schema} with a user-defined `visible?` implementations.
8
8
  #
9
9
  # When validating and executing a query, all access to schema members
10
10
  # should go through a warden. If you access the schema directly,
11
11
  # you may show a client something that it shouldn't be allowed to see.
12
12
  #
13
- # @example Hiding private fields
14
- # private_members = -> (member, ctx) { member.metadata[:private] }
15
- # result = Schema.execute(query_string, except: private_members)
16
- #
17
- # @example Custom filter implementation
18
- # # It must respond to `#call(member)`.
19
- # class MissingRequiredFlags
20
- # def initialize(user)
21
- # @user = user
22
- # end
23
- #
24
- # # Return `false` if any required flags are missing
25
- # def call(member, ctx)
26
- # member.metadata[:required_flags].any? do |flag|
27
- # !@user.has_flag?(flag)
28
- # end
29
- # end
30
- # end
31
- #
32
- # # Then, use the custom filter in query:
33
- # missing_required_flags = MissingRequiredFlags.new(current_user)
34
- #
35
- # # This query can only access members which match the user's flags
36
- # result = Schema.execute(query_string, except: missing_required_flags)
37
- #
38
13
  # @api private
39
14
  class Warden
40
15
  def self.from_context(context)
@@ -85,6 +60,7 @@ module GraphQL
85
60
  def visible_type_membership?(tm, ctx); tm.visible?(ctx); end
86
61
  def interface_type_memberships(obj_t, ctx); obj_t.interface_type_memberships; end
87
62
  def arguments(owner, ctx); owner.arguments(ctx); end
63
+ def loadable?(type, ctx); type.visible?(ctx); end
88
64
  end
89
65
  end
90
66
 
@@ -109,33 +85,28 @@ module GraphQL
109
85
  def fields(type_defn); type_defn.all_field_definitions; end # rubocop:disable Development/ContextIsPassedCop
110
86
  def get_field(parent_type, field_name); @schema.get_field(parent_type, field_name); end
111
87
  def reachable_type?(type_name); true; end
88
+ def loadable?(type, _ctx); true; end
112
89
  def reachable_types; @schema.types.values; end # rubocop:disable Development/ContextIsPassedCop
113
90
  def possible_types(type_defn); @schema.possible_types(type_defn); end
114
91
  def interfaces(obj_type); obj_type.interfaces; end
115
92
  end
116
93
 
117
- # @param filter [<#call(member)>] Objects are hidden when `.call(member, ctx)` returns true
118
94
  # @param context [GraphQL::Query::Context]
119
95
  # @param schema [GraphQL::Schema]
120
- def initialize(filter = nil, context:, schema:)
96
+ def initialize(context:, schema:)
121
97
  @schema = schema
122
98
  # Cache these to avoid repeated hits to the inheritance chain when one isn't present
123
99
  @query = @schema.query
124
100
  @mutation = @schema.mutation
125
101
  @subscription = @schema.subscription
126
102
  @context = context
127
- @visibility_cache = if filter
128
- read_through { |m| filter.call(m, context) }
129
- else
130
- read_through { |m| schema.visible?(m, context) }
131
- end
132
-
103
+ @visibility_cache = read_through { |m| schema.visible?(m, context) }
133
104
  @visibility_cache.compare_by_identity
134
105
  # Initialize all ivars to improve object shape consistency:
135
106
  @types = @visible_types = @reachable_types = @visible_parent_fields =
136
107
  @visible_possible_types = @visible_fields = @visible_arguments = @visible_enum_arrays =
137
108
  @visible_enum_values = @visible_interfaces = @type_visibility = @type_memberships =
138
- @visible_and_reachable_type = @unions = @unfiltered_interfaces = @references_to =
109
+ @visible_and_reachable_type = @unions = @unfiltered_interfaces =
139
110
  @reachable_type_set =
140
111
  nil
141
112
  end
@@ -153,6 +124,11 @@ module GraphQL
153
124
  end
154
125
  end
155
126
 
127
+ # @return [Boolean] True if this type is used for `loads:` but not in the schema otherwise and not _explicitly_ hidden.
128
+ def loadable?(type, _ctx)
129
+ !reachable_type_set.include?(type) && visible_type?(type)
130
+ end
131
+
156
132
  # @return [GraphQL::BaseType, nil] The type named `type_name`, if it exists (else `nil`)
157
133
  def get_type(type_name)
158
134
  @visible_types ||= read_through do |name|
@@ -219,7 +195,16 @@ module GraphQL
219
195
  # @param argument_owner [GraphQL::Field, GraphQL::InputObjectType]
220
196
  # @return [Array<GraphQL::Argument>] Visible arguments on `argument_owner`
221
197
  def arguments(argument_owner, ctx = nil)
222
- @visible_arguments ||= read_through { |o| o.arguments(@context).each_value.select { |a| visible_argument?(a, @context) } }
198
+ @visible_arguments ||= read_through { |o|
199
+ args = o.arguments(@context)
200
+ if args.any?
201
+ args = args.values
202
+ args.select! { |a| visible_argument?(a, @context) }
203
+ args
204
+ else
205
+ EmptyObjects::EMPTY_ARRAY
206
+ end
207
+ }
223
208
  @visible_arguments[argument_owner]
224
209
  end
225
210
 
@@ -242,7 +227,13 @@ module GraphQL
242
227
 
243
228
  # @return [Array<GraphQL::InterfaceType>] Visible interfaces implemented by `obj_type`
244
229
  def interfaces(obj_type)
245
- @visible_interfaces ||= read_through { |t| t.interfaces(@context).select { |i| visible_type?(i) } }
230
+ @visible_interfaces ||= read_through { |t|
231
+ ints = t.interfaces(@context)
232
+ if ints.any?
233
+ ints.select! { |i| visible_type?(i) }
234
+ end
235
+ ints
236
+ }
246
237
  @visible_interfaces[obj_type]
247
238
  end
248
239
 
@@ -298,11 +289,26 @@ module GraphQL
298
289
  next true if root_type?(type_defn) || type_defn.introspection?
299
290
 
300
291
  if type_defn.kind.union?
301
- visible_possible_types?(type_defn) && (referenced?(type_defn) || orphan_type?(type_defn))
292
+ possible_types(type_defn).any? && (referenced?(type_defn) || orphan_type?(type_defn))
302
293
  elsif type_defn.kind.interface?
303
- visible_possible_types?(type_defn)
294
+ if possible_types(type_defn).any?
295
+ true
296
+ else
297
+ if @context.respond_to?(:logger) && (logger = @context.logger)
298
+ logger.debug { "Interface `#{type_defn.graphql_name}` hidden because it has no visible implementers" }
299
+ end
300
+ false
301
+ end
304
302
  else
305
- referenced?(type_defn) || visible_abstract_type?(type_defn)
303
+ if referenced?(type_defn)
304
+ true
305
+ elsif type_defn.kind.object?
306
+ # Show this object if it belongs to ...
307
+ interfaces(type_defn).any? { |t| referenced?(t) } || # an interface which is referenced in the schema
308
+ union_memberships(type_defn).any? { |t| referenced?(t) || orphan_type?(t) } # or a union which is referenced or added via orphan_types
309
+ else
310
+ false
311
+ end
306
312
  end
307
313
  end
308
314
 
@@ -357,35 +363,22 @@ module GraphQL
357
363
  end
358
364
 
359
365
  def referenced?(type_defn)
360
- @references_to ||= @schema.references_to
361
- graphql_name = type_defn.unwrap.graphql_name
362
- members = @references_to[graphql_name] || NO_REFERENCES
366
+ members = @schema.references_to(type_defn)
363
367
  members.any? { |m| visible?(m) }
364
368
  end
365
369
 
366
- NO_REFERENCES = [].freeze
367
-
368
370
  def orphan_type?(type_defn)
369
371
  @schema.orphan_types.include?(type_defn)
370
372
  end
371
373
 
372
- def visible_abstract_type?(type_defn)
373
- type_defn.kind.object? && (
374
- interfaces(type_defn).any? ||
375
- union_memberships(type_defn).any?
376
- )
377
- end
378
-
379
- def visible_possible_types?(type_defn)
380
- possible_types(type_defn).any? { |t| visible_and_reachable_type?(t) }
381
- end
382
-
383
374
  def visible?(member)
384
375
  @visibility_cache[member]
385
376
  end
386
377
 
387
378
  def read_through
388
- Hash.new { |h, k| h[k] = yield(k) }
379
+ h = Hash.new { |h, k| h[k] = yield(k) }
380
+ h.compare_by_identity
381
+ h
389
382
  end
390
383
 
391
384
  def reachable_type_set
@@ -416,54 +409,62 @@ module GraphQL
416
409
  end
417
410
  end
418
411
 
412
+ included_interface_possible_types_set = Set.new
413
+
419
414
  until unvisited_types.empty?
420
415
  type = unvisited_types.pop
421
- if @reachable_type_set.add?(type)
422
- type_by_name = rt_hash[type.graphql_name] ||= type
423
- if type_by_name != type
424
- raise DuplicateNamesError.new(
425
- duplicated_name: type.graphql_name, duplicated_definition_1: type.inspect, duplicated_definition_2: type_by_name.inspect
426
- )
416
+ visit_type(type, unvisited_types, @reachable_type_set, rt_hash, included_interface_possible_types_set, include_interface_possible_types: false)
417
+ end
418
+
419
+ @reachable_type_set
420
+ end
421
+
422
+ def visit_type(type, unvisited_types, visited_type_set, type_by_name_hash, included_interface_possible_types_set, include_interface_possible_types:)
423
+ if visited_type_set.add?(type) || (include_interface_possible_types && type.kind.interface? && included_interface_possible_types_set.add?(type))
424
+ type_by_name = type_by_name_hash[type.graphql_name] ||= type
425
+ if type_by_name != type
426
+ name_1, name_2 = [type.inspect, type_by_name.inspect].sort
427
+ raise DuplicateNamesError.new(
428
+ duplicated_name: type.graphql_name, duplicated_definition_1: name_1, duplicated_definition_2: name_2
429
+ )
430
+ end
431
+ if type.kind.input_object?
432
+ # recurse into visible arguments
433
+ arguments(type).each do |argument|
434
+ argument_type = argument.type.unwrap
435
+ unvisited_types << argument_type
427
436
  end
428
- if type.kind.input_object?
429
- # recurse into visible arguments
430
- arguments(type).each do |argument|
431
- argument_type = argument.type.unwrap
432
- unvisited_types << argument_type
433
- end
434
- elsif type.kind.union?
435
- # recurse into visible possible types
436
- possible_types(type).each do |possible_type|
437
- unvisited_types << possible_type
437
+ elsif type.kind.union?
438
+ # recurse into visible possible types
439
+ possible_types(type).each do |possible_type|
440
+ unvisited_types << possible_type
441
+ end
442
+ elsif type.kind.fields?
443
+ if type.kind.object?
444
+ # recurse into visible implemented interfaces
445
+ interfaces(type).each do |interface|
446
+ unvisited_types << interface
438
447
  end
439
- elsif type.kind.fields?
440
- if type.kind.interface?
441
- # recurse into visible possible types
442
- possible_types(type).each do |possible_type|
443
- unvisited_types << possible_type
444
- end
445
- elsif type.kind.object?
446
- # recurse into visible implemented interfaces
447
- interfaces(type).each do |interface|
448
- unvisited_types << interface
449
- end
448
+ elsif include_interface_possible_types
449
+ possible_types(type).each do |pt|
450
+ unvisited_types << pt
450
451
  end
452
+ end
453
+ # Don't visit interface possible types -- it's not enough to justify visibility
451
454
 
452
- # recurse into visible fields
453
- fields(type).each do |field|
454
- field_type = field.type.unwrap
455
- unvisited_types << field_type
456
- # recurse into visible arguments
457
- arguments(field).each do |argument|
458
- argument_type = argument.type.unwrap
459
- unvisited_types << argument_type
460
- end
455
+ # recurse into visible fields
456
+ fields(type).each do |field|
457
+ field_type = field.type.unwrap
458
+ # In this case, if it's an interface, we want to include
459
+ visit_type(field_type, unvisited_types, visited_type_set, type_by_name_hash, included_interface_possible_types_set, include_interface_possible_types: true)
460
+ # recurse into visible arguments
461
+ arguments(field).each do |argument|
462
+ argument_type = argument.type.unwrap
463
+ unvisited_types << argument_type
461
464
  end
462
465
  end
463
466
  end
464
467
  end
465
-
466
- @reachable_type_set
467
468
  end
468
469
  end
469
470
  end