graphql 2.3.7 → 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 (101) 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/field_usage.rb +1 -1
  7. data/lib/graphql/analysis/query_complexity.rb +3 -3
  8. data/lib/graphql/analysis/visitor.rb +7 -6
  9. data/lib/graphql/analysis.rb +1 -1
  10. data/lib/graphql/current.rb +52 -0
  11. data/lib/graphql/dataloader/async_dataloader.rb +3 -2
  12. data/lib/graphql/dataloader/source.rb +6 -3
  13. data/lib/graphql/dataloader.rb +35 -11
  14. data/lib/graphql/execution/interpreter/arguments_cache.rb +5 -10
  15. data/lib/graphql/execution/interpreter/resolve.rb +10 -6
  16. data/lib/graphql/execution/interpreter/runtime.rb +29 -25
  17. data/lib/graphql/execution/interpreter.rb +2 -0
  18. data/lib/graphql/execution/lookahead.rb +10 -10
  19. data/lib/graphql/introspection/directive_type.rb +1 -1
  20. data/lib/graphql/introspection/entry_points.rb +2 -2
  21. data/lib/graphql/introspection/field_type.rb +1 -1
  22. data/lib/graphql/introspection/schema_type.rb +6 -11
  23. data/lib/graphql/introspection/type_type.rb +5 -5
  24. data/lib/graphql/invalid_null_error.rb +1 -1
  25. data/lib/graphql/language/comment.rb +18 -0
  26. data/lib/graphql/language/document_from_schema_definition.rb +55 -28
  27. data/lib/graphql/language/lexer.rb +15 -15
  28. data/lib/graphql/language/nodes.rb +24 -16
  29. data/lib/graphql/language/parser.rb +14 -1
  30. data/lib/graphql/language/printer.rb +23 -7
  31. data/lib/graphql/language/sanitized_printer.rb +1 -1
  32. data/lib/graphql/language.rb +6 -6
  33. data/lib/graphql/query/context.rb +7 -1
  34. data/lib/graphql/query/null_context.rb +2 -2
  35. data/lib/graphql/query.rb +60 -8
  36. data/lib/graphql/rubocop/graphql/field_type_in_block.rb +144 -0
  37. data/lib/graphql/rubocop/graphql/root_types_in_block.rb +38 -0
  38. data/lib/graphql/rubocop.rb +2 -0
  39. data/lib/graphql/schema/addition.rb +1 -0
  40. data/lib/graphql/schema/always_visible.rb +6 -2
  41. data/lib/graphql/schema/argument.rb +14 -1
  42. data/lib/graphql/schema/build_from_definition.rb +9 -1
  43. data/lib/graphql/schema/directive/flagged.rb +1 -1
  44. data/lib/graphql/schema/enum.rb +54 -20
  45. data/lib/graphql/schema/enum_value.rb +9 -1
  46. data/lib/graphql/schema/field/connection_extension.rb +1 -1
  47. data/lib/graphql/schema/field.rb +92 -37
  48. data/lib/graphql/schema/has_single_input_argument.rb +2 -1
  49. data/lib/graphql/schema/input_object.rb +27 -13
  50. data/lib/graphql/schema/interface.rb +21 -4
  51. data/lib/graphql/schema/introspection_system.rb +5 -16
  52. data/lib/graphql/schema/member/base_dsl_methods.rb +15 -0
  53. data/lib/graphql/schema/member/has_arguments.rb +14 -9
  54. data/lib/graphql/schema/member/has_fields.rb +8 -6
  55. data/lib/graphql/schema/member/has_unresolved_type_error.rb +5 -1
  56. data/lib/graphql/schema/printer.rb +1 -0
  57. data/lib/graphql/schema/resolver.rb +7 -9
  58. data/lib/graphql/schema/type_expression.rb +2 -2
  59. data/lib/graphql/schema/validator/all_validator.rb +62 -0
  60. data/lib/graphql/schema/validator/required_validator.rb +28 -4
  61. data/lib/graphql/schema/validator.rb +2 -0
  62. data/lib/graphql/schema/visibility/migration.rb +186 -0
  63. data/lib/graphql/schema/visibility/profile.rb +523 -0
  64. data/lib/graphql/schema/visibility.rb +75 -0
  65. data/lib/graphql/schema/warden.rb +156 -10
  66. data/lib/graphql/schema.rb +283 -85
  67. data/lib/graphql/static_validation/base_visitor.rb +6 -5
  68. data/lib/graphql/static_validation/literal_validator.rb +4 -4
  69. data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +1 -1
  70. data/lib/graphql/static_validation/rules/arguments_are_defined.rb +3 -2
  71. data/lib/graphql/static_validation/rules/directives_are_defined.rb +3 -3
  72. data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +2 -0
  73. data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +3 -2
  74. data/lib/graphql/static_validation/rules/fields_will_merge.rb +8 -7
  75. data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +3 -3
  76. data/lib/graphql/static_validation/rules/fragment_types_exist.rb +12 -2
  77. data/lib/graphql/static_validation/rules/fragments_are_on_composite_types.rb +1 -1
  78. data/lib/graphql/static_validation/rules/mutation_root_exists.rb +1 -1
  79. data/lib/graphql/static_validation/rules/query_root_exists.rb +1 -1
  80. data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +3 -3
  81. data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +3 -3
  82. data/lib/graphql/static_validation/rules/subscription_root_exists.rb +1 -1
  83. data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +18 -27
  84. data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +1 -1
  85. data/lib/graphql/static_validation/rules/variables_are_input_types.rb +11 -2
  86. data/lib/graphql/static_validation/validation_context.rb +17 -2
  87. data/lib/graphql/subscriptions/action_cable_subscriptions.rb +2 -1
  88. data/lib/graphql/subscriptions/broadcast_analyzer.rb +10 -4
  89. data/lib/graphql/subscriptions/event.rb +1 -1
  90. data/lib/graphql/subscriptions.rb +5 -3
  91. data/lib/graphql/testing/helpers.rb +9 -5
  92. data/lib/graphql/tracing/notifications_trace.rb +2 -2
  93. data/lib/graphql/types/relay/connection_behaviors.rb +10 -0
  94. data/lib/graphql/types/relay/edge_behaviors.rb +10 -0
  95. data/lib/graphql/types/relay/page_info_behaviors.rb +4 -0
  96. data/lib/graphql/unauthorized_enum_value_error.rb +13 -0
  97. data/lib/graphql/version.rb +1 -1
  98. data/lib/graphql.rb +3 -0
  99. metadata +29 -8
  100. data/lib/graphql/language/token.rb +0 -34
  101. data/lib/graphql/schema/invalid_type_error.rb +0 -7
@@ -19,6 +19,10 @@ module GraphQL
19
19
  PassThruWarden
20
20
  end
21
21
 
22
+ def self.use(schema)
23
+ # no-op
24
+ end
25
+
22
26
  # @param visibility_method [Symbol] a Warden method to call for this entry
23
27
  # @param entry [Object, Array<Object>] One or more definitions for a given name in a GraphQL Schema
24
28
  # @param context [GraphQL::Query::Context]
@@ -61,21 +65,37 @@ module GraphQL
61
65
  def interface_type_memberships(obj_t, ctx); obj_t.interface_type_memberships; end
62
66
  def arguments(owner, ctx); owner.arguments(ctx); end
63
67
  def loadable?(type, ctx); type.visible?(ctx); end
68
+ def visibility_profile
69
+ @visibility_profile ||= Warden::VisibilityProfile.new(self)
70
+ end
64
71
  end
65
72
  end
66
73
 
67
74
  class NullWarden
68
75
  def initialize(_filter = nil, context:, schema:)
69
76
  @schema = schema
77
+ @visibility_profile = Warden::VisibilityProfile.new(self)
78
+ end
79
+
80
+ # No-op, but for compatibility:
81
+ attr_writer :skip_warning
82
+
83
+ # @api private
84
+ module NullVisibilityProfile
85
+ def self.new(context:, schema:)
86
+ NullWarden.new(context: context, schema: schema).visibility_profile
87
+ end
70
88
  end
71
89
 
90
+ attr_reader :visibility_profile
91
+
72
92
  def visible_field?(field_defn, _ctx = nil, owner = nil); true; end
73
93
  def visible_argument?(arg_defn, _ctx = nil); true; end
74
94
  def visible_type?(type_defn, _ctx = nil); true; end
75
95
  def visible_enum_value?(enum_value, _ctx = nil); true; end
76
96
  def visible_type_membership?(type_membership, _ctx = nil); true; end
77
97
  def interface_type_memberships(obj_type, _ctx = nil); obj_type.interface_type_memberships; end
78
- def get_type(type_name); @schema.get_type(type_name); end # rubocop:disable Development/ContextIsPassedCop
98
+ def get_type(type_name); @schema.get_type(type_name, Query::NullContext.instance, false); end # rubocop:disable Development/ContextIsPassedCop
79
99
  def arguments(argument_owner, ctx = nil); argument_owner.all_argument_definitions; end
80
100
  def enum_values(enum_defn); enum_defn.enum_values; end # rubocop:disable Development/ContextIsPassedCop
81
101
  def get_argument(parent_type, argument_name); parent_type.get_argument(argument_name); end # rubocop:disable Development/ContextIsPassedCop
@@ -87,10 +107,84 @@ module GraphQL
87
107
  def reachable_type?(type_name); true; end
88
108
  def loadable?(type, _ctx); true; end
89
109
  def reachable_types; @schema.types.values; end # rubocop:disable Development/ContextIsPassedCop
90
- def possible_types(type_defn); @schema.possible_types(type_defn); end
110
+ def possible_types(type_defn); @schema.possible_types(type_defn, Query::NullContext.instance, false); end
91
111
  def interfaces(obj_type); obj_type.interfaces; end
92
112
  end
93
113
 
114
+ def visibility_profile
115
+ @visibility_profile ||= VisibilityProfile.new(self)
116
+ end
117
+
118
+ class VisibilityProfile
119
+ def initialize(warden)
120
+ @warden = warden
121
+ end
122
+
123
+ def directives
124
+ @warden.directives
125
+ end
126
+
127
+ def directive_exists?(dir_name)
128
+ @warden.directives.any? { |d| d.graphql_name == dir_name }
129
+ end
130
+
131
+ def type(name)
132
+ @warden.get_type(name)
133
+ end
134
+
135
+ def field(owner, field_name)
136
+ @warden.get_field(owner, field_name)
137
+ end
138
+
139
+ def argument(owner, arg_name)
140
+ @warden.get_argument(owner, arg_name)
141
+ end
142
+
143
+ def query_root
144
+ @warden.root_type_for_operation("query")
145
+ end
146
+
147
+ def mutation_root
148
+ @warden.root_type_for_operation("mutation")
149
+ end
150
+
151
+ def subscription_root
152
+ @warden.root_type_for_operation("subscription")
153
+ end
154
+
155
+ def arguments(owner)
156
+ @warden.arguments(owner)
157
+ end
158
+
159
+ def fields(owner)
160
+ @warden.fields(owner)
161
+ end
162
+
163
+ def possible_types(type)
164
+ @warden.possible_types(type)
165
+ end
166
+
167
+ def enum_values(enum_type)
168
+ @warden.enum_values(enum_type)
169
+ end
170
+
171
+ def all_types
172
+ @warden.reachable_types
173
+ end
174
+
175
+ def interfaces(obj_type)
176
+ @warden.interfaces(obj_type)
177
+ end
178
+
179
+ def loadable?(t, ctx) # TODO remove ctx here?
180
+ @warden.loadable?(t, ctx)
181
+ end
182
+
183
+ def reachable_type?(type_name)
184
+ !!@warden.reachable_type?(type_name)
185
+ end
186
+ end
187
+
94
188
  # @param context [GraphQL::Query::Context]
95
189
  # @param schema [GraphQL::Schema]
96
190
  def initialize(context:, schema:)
@@ -100,17 +194,19 @@ module GraphQL
100
194
  @mutation = @schema.mutation
101
195
  @subscription = @schema.subscription
102
196
  @context = context
103
- @visibility_cache = read_through { |m| schema.visible?(m, context) }
104
- @visibility_cache.compare_by_identity
197
+ @visibility_cache = read_through { |m| check_visible(schema, m) }
105
198
  # Initialize all ivars to improve object shape consistency:
106
199
  @types = @visible_types = @reachable_types = @visible_parent_fields =
107
200
  @visible_possible_types = @visible_fields = @visible_arguments = @visible_enum_arrays =
108
201
  @visible_enum_values = @visible_interfaces = @type_visibility = @type_memberships =
109
202
  @visible_and_reachable_type = @unions = @unfiltered_interfaces =
110
- @reachable_type_set =
203
+ @reachable_type_set = @visibility_profile =
111
204
  nil
205
+ @skip_warning = schema.plugins.any? { |(plugin, _opts)| plugin == GraphQL::Schema::Warden }
112
206
  end
113
207
 
208
+ attr_writer :skip_warning
209
+
114
210
  # @return [Hash<String, GraphQL::BaseType>] Visible types in the schema
115
211
  def types
116
212
  @types ||= begin
@@ -132,7 +228,7 @@ module GraphQL
132
228
  # @return [GraphQL::BaseType, nil] The type named `type_name`, if it exists (else `nil`)
133
229
  def get_type(type_name)
134
230
  @visible_types ||= read_through do |name|
135
- type_defn = @schema.get_type(name, @context)
231
+ type_defn = @schema.get_type(name, @context, false)
136
232
  if type_defn && visible_and_reachable_type?(type_defn)
137
233
  type_defn
138
234
  else
@@ -179,7 +275,7 @@ module GraphQL
179
275
  # @return [Array<GraphQL::BaseType>] The types which may be member of `type_defn`
180
276
  def possible_types(type_defn)
181
277
  @visible_possible_types ||= read_through { |type_defn|
182
- pt = @schema.possible_types(type_defn, @context)
278
+ pt = @schema.possible_types(type_defn, @context, false)
183
279
  pt.select { |t| visible_and_reachable_type?(t) }
184
280
  }
185
281
  @visible_possible_types[type_defn]
@@ -376,11 +472,61 @@ module GraphQL
376
472
  end
377
473
 
378
474
  def read_through
379
- h = Hash.new { |h, k| h[k] = yield(k) }
380
- h.compare_by_identity
381
- h
475
+ Hash.new { |h, k| h[k] = yield(k) }.compare_by_identity
476
+ end
477
+
478
+ def check_visible(schema, member)
479
+ if schema.visible?(member, @context)
480
+ true
481
+ elsif @skip_warning
482
+ false
483
+ else
484
+ member_s = member.respond_to?(:path) ? member.path : member.inspect
485
+ member_type = case member
486
+ when Module
487
+ if member.respond_to?(:kind)
488
+ member.kind.name.downcase
489
+ else
490
+ ""
491
+ end
492
+ when GraphQL::Schema::Field
493
+ "field"
494
+ when GraphQL::Schema::EnumValue
495
+ "enum value"
496
+ when GraphQL::Schema::Argument
497
+ "argument"
498
+ else
499
+ ""
500
+ end
501
+
502
+ schema_s = schema.name ? "#{schema.name}'s" : ""
503
+ schema_name = schema.name ? "#{schema.name}" : "your schema"
504
+ warn(ADD_WARDEN_WARNING % { schema_s: schema_s, schema_name: schema_name, member: member_s, member_type: member_type })
505
+ @skip_warning = true # only warn once per query
506
+ # If there's no schema name, add the backtrace for additional context:
507
+ if schema_s == ""
508
+ puts caller.map { |l| " #{l}"}
509
+ end
510
+ false
511
+ end
382
512
  end
383
513
 
514
+ ADD_WARDEN_WARNING = <<~WARNING
515
+ DEPRECATION: %{schema_s} "%{member}" %{member_type} returned `false` for `.visible?` but `GraphQL::Schema::Visibility` isn't configured yet.
516
+
517
+ Address this warning by adding:
518
+
519
+ use GraphQL::Schema::Visibility
520
+
521
+ to the definition for %{schema_name}. (Future GraphQL-Ruby versions won't check `.visible?` methods by default.)
522
+
523
+ Alternatively, for legacy behavior, add:
524
+
525
+ use GraphQL::Schema::Warden # legacy visibility behavior
526
+
527
+ For more information see: https://graphql-ruby.org/authorization/visibility.html
528
+ WARNING
529
+
384
530
  def reachable_type_set
385
531
  return @reachable_type_set if @reachable_type_set
386
532