graphql 2.0.21 → 2.0.32

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 (65) hide show
  1. checksums.yaml +4 -4
  2. data/lib/generators/graphql/mutation_delete_generator.rb +1 -1
  3. data/lib/generators/graphql/mutation_update_generator.rb +1 -1
  4. data/lib/generators/graphql/relay.rb +18 -1
  5. data/lib/graphql/backtrace.rb +0 -4
  6. data/lib/graphql/dataloader/source.rb +69 -45
  7. data/lib/graphql/dataloader.rb +4 -4
  8. data/lib/graphql/execution/interpreter/arguments_cache.rb +31 -30
  9. data/lib/graphql/execution/interpreter/runtime.rb +122 -101
  10. data/lib/graphql/execution/interpreter.rb +1 -2
  11. data/lib/graphql/execution/lookahead.rb +1 -1
  12. data/lib/graphql/filter.rb +2 -1
  13. data/lib/graphql/introspection/entry_points.rb +1 -1
  14. data/lib/graphql/language/document_from_schema_definition.rb +16 -9
  15. data/lib/graphql/language/lexer.rb +89 -57
  16. data/lib/graphql/language/nodes.rb +3 -0
  17. data/lib/graphql/language/parser.rb +706 -691
  18. data/lib/graphql/language/parser.y +1 -0
  19. data/lib/graphql/language/printer.rb +28 -14
  20. data/lib/graphql/language/visitor.rb +64 -61
  21. data/lib/graphql/query/context.rb +16 -7
  22. data/lib/graphql/query/null_context.rb +8 -18
  23. data/lib/graphql/query/validation_pipeline.rb +2 -1
  24. data/lib/graphql/query.rb +37 -12
  25. data/lib/graphql/schema/addition.rb +38 -12
  26. data/lib/graphql/schema/always_visible.rb +10 -0
  27. data/lib/graphql/schema/argument.rb +8 -10
  28. data/lib/graphql/schema/build_from_definition.rb +8 -7
  29. data/lib/graphql/schema/directive.rb +1 -1
  30. data/lib/graphql/schema/enum_value.rb +2 -2
  31. data/lib/graphql/schema/field/connection_extension.rb +1 -1
  32. data/lib/graphql/schema/field.rb +26 -15
  33. data/lib/graphql/schema/input_object.rb +9 -7
  34. data/lib/graphql/schema/interface.rb +5 -1
  35. data/lib/graphql/schema/introspection_system.rb +1 -1
  36. data/lib/graphql/schema/member/build_type.rb +10 -2
  37. data/lib/graphql/schema/member/has_arguments.rb +9 -7
  38. data/lib/graphql/schema/member/has_directives.rb +1 -1
  39. data/lib/graphql/schema/member/has_fields.rb +1 -1
  40. data/lib/graphql/schema/member/has_interfaces.rb +1 -1
  41. data/lib/graphql/schema/member/type_system_helpers.rb +1 -1
  42. data/lib/graphql/schema/object.rb +6 -1
  43. data/lib/graphql/schema/printer.rb +3 -1
  44. data/lib/graphql/schema/relay_classic_mutation.rb +1 -1
  45. data/lib/graphql/schema/resolver.rb +12 -10
  46. data/lib/graphql/schema/timeout.rb +1 -1
  47. data/lib/graphql/schema/validator.rb +1 -1
  48. data/lib/graphql/schema/warden.rb +37 -4
  49. data/lib/graphql/schema.rb +92 -23
  50. data/lib/graphql/tracing/appoptics_trace.rb +35 -11
  51. data/lib/graphql/tracing/appsignal_trace.rb +4 -0
  52. data/lib/graphql/tracing/data_dog_trace.rb +89 -50
  53. data/lib/graphql/tracing/data_dog_tracing.rb +7 -21
  54. data/lib/graphql/tracing/legacy_trace.rb +5 -1
  55. data/lib/graphql/tracing/notifications_trace.rb +7 -0
  56. data/lib/graphql/tracing/platform_trace.rb +26 -12
  57. data/lib/graphql/tracing/prometheus_trace.rb +4 -0
  58. data/lib/graphql/tracing/scout_trace.rb +3 -0
  59. data/lib/graphql/tracing/statsd_trace.rb +4 -0
  60. data/lib/graphql/tracing.rb +1 -0
  61. data/lib/graphql/types/relay/connection_behaviors.rb +1 -1
  62. data/lib/graphql/types/relay/edge_behaviors.rb +1 -1
  63. data/lib/graphql/version.rb +1 -1
  64. data/readme.md +1 -1
  65. metadata +36 -24
@@ -53,6 +53,7 @@ module GraphQL
53
53
  def initialize(arg_name = nil, type_expr = nil, desc = nil, required: true, type: nil, name: nil, loads: nil, description: nil, ast_node: nil, default_value: NOT_CONFIGURED, as: nil, from_resolver: false, camelize: true, prepare: nil, owner:, validates: nil, directives: nil, deprecation_reason: nil, replace_null_with_default: false, &definition_block)
54
54
  arg_name ||= name
55
55
  @name = -(camelize ? Member::BuildType.camelize(arg_name.to_s) : arg_name.to_s)
56
+ NameValidator.validate!(@name)
56
57
  @type_expr = type_expr || type
57
58
  @description = desc || description
58
59
  @null = required != true
@@ -88,11 +89,8 @@ module GraphQL
88
89
  end
89
90
 
90
91
  if definition_block
91
- if definition_block.arity == 1
92
- instance_exec(self, &definition_block)
93
- else
94
- instance_eval(&definition_block)
95
- end
92
+ # `self` will still be self, it will also be the first argument to the block:
93
+ instance_exec(self, &definition_block)
96
94
  end
97
95
  end
98
96
 
@@ -198,8 +196,8 @@ module GraphQL
198
196
 
199
197
  def statically_coercible?
200
198
  return @statically_coercible if defined?(@statically_coercible)
201
-
202
- @statically_coercible = !@prepare.is_a?(String) && !@prepare.is_a?(Symbol)
199
+ requires_parent_object = @prepare.is_a?(String) || @prepare.is_a?(Symbol) || @own_validators
200
+ @statically_coercible = !requires_parent_object
203
201
  end
204
202
 
205
203
  # Apply the {prepare} configuration to `value`, using methods from `obj`.
@@ -264,7 +262,7 @@ module GraphQL
264
262
 
265
263
  # If this isn't lazy, then the block returns eagerly and assigns the result here
266
264
  # If it _is_ lazy, then we write the lazy to the hash, then update it later
267
- argument_values[arg_key] = context.schema.after_lazy(coerced_value) do |resolved_coerced_value|
265
+ argument_values[arg_key] = context.query.after_lazy(coerced_value) do |resolved_coerced_value|
268
266
  owner.validate_directive_argument(self, resolved_coerced_value)
269
267
  prepared_value = begin
270
268
  prepare_value(parent_object, resolved_coerced_value, context: context)
@@ -281,7 +279,7 @@ module GraphQL
281
279
  end
282
280
 
283
281
  maybe_loaded_value = loaded_value || prepared_value
284
- context.schema.after_lazy(maybe_loaded_value) do |resolved_loaded_value|
282
+ context.query.after_lazy(maybe_loaded_value) do |resolved_loaded_value|
285
283
  # TODO code smell to access such a deeply-nested constant in a distant module
286
284
  argument_values[arg_key] = GraphQL::Execution::Interpreter::ArgumentValue.new(
287
285
  value: resolved_loaded_value,
@@ -303,7 +301,7 @@ module GraphQL
303
301
  else
304
302
  load_method_owner.public_send(arg_load_method, coerced_value)
305
303
  end
306
- context.schema.after_lazy(custom_loaded_value) do |custom_value|
304
+ context.query.after_lazy(custom_loaded_value) do |custom_value|
307
305
  if loads
308
306
  if type.list?
309
307
  loaded_values = custom_value.each_with_index.map { |custom_val, idx|
@@ -453,17 +453,18 @@ module GraphQL
453
453
 
454
454
  # Don't do this for interfaces
455
455
  if default_resolve
456
- owner.class_eval <<-RUBY, __FILE__, __LINE__
457
- # frozen_string_literal: true
458
- def #{resolve_method_name}(**args)
459
- field_instance = self.class.get_field("#{field_definition.name}")
460
- context.schema.definition_default_resolve.call(self.class, field_instance, object, args, context)
461
- end
462
- RUBY
456
+ define_field_resolve_method(owner, resolve_method_name, field_definition.name)
463
457
  end
464
458
  end
465
459
  end
466
460
 
461
+ def define_field_resolve_method(owner, method_name, field_name)
462
+ owner.define_method(method_name) { |**args|
463
+ field_instance = self.class.get_field(field_name)
464
+ context.schema.definition_default_resolve.call(self.class, field_instance, object, args, context)
465
+ }
466
+ end
467
+
467
468
  def build_resolve_type(lookup_hash, directives, missing_type_handler)
468
469
  resolve_type_proc = nil
469
470
  resolve_type_proc = ->(ast_node) {
@@ -99,7 +99,7 @@ module GraphQL
99
99
 
100
100
  def inherited(subclass)
101
101
  super
102
- subclass.class_eval do
102
+ subclass.class_exec do
103
103
  @default_graphql_name ||= nil
104
104
  end
105
105
  end
@@ -34,7 +34,7 @@ module GraphQL
34
34
  @graphql_name = graphql_name.to_s
35
35
  GraphQL::NameValidator.validate!(@graphql_name)
36
36
  @description = desc || description
37
- @value = value === NOT_CONFIGURED ? @graphql_name : value
37
+ @value = value == NOT_CONFIGURED ? @graphql_name : value
38
38
  if deprecation_reason
39
39
  self.deprecation_reason = deprecation_reason
40
40
  end
@@ -47,7 +47,7 @@ module GraphQL
47
47
  end
48
48
 
49
49
  if block_given?
50
- instance_eval(&block)
50
+ instance_exec(self, &block)
51
51
  end
52
52
  end
53
53
 
@@ -26,7 +26,7 @@ module GraphQL
26
26
  # rename some inputs to avoid conflicts inside the block
27
27
  maybe_lazy = value
28
28
  value = nil
29
- context.schema.after_lazy(maybe_lazy) do |resolved_value|
29
+ context.query.after_lazy(maybe_lazy) do |resolved_value|
30
30
  value = resolved_value
31
31
  if value.is_a? GraphQL::ExecutionError
32
32
  # This isn't even going to work because context doesn't have ast_node anymore
@@ -92,7 +92,7 @@ module GraphQL
92
92
  # @param resolver [Class] A {GraphQL::Schema::Resolver} class to use for field configuration
93
93
  # @param mutation [Class] A {GraphQL::Schema::Mutation} class to use for field configuration
94
94
  # @param subscription [Class] A {GraphQL::Schema::Subscription} class to use for field configuration
95
- # @return [GraphQL::Schema:Field] an instance of `self
95
+ # @return [GraphQL::Schema:Field] an instance of `self`
96
96
  # @see {.initialize} for other options
97
97
  def self.from_options(name = nil, type = nil, desc = nil, resolver: nil, mutation: nil, subscription: nil,**kwargs, &block)
98
98
  if (resolver_class = resolver || mutation || subscription)
@@ -233,9 +233,9 @@ module GraphQL
233
233
 
234
234
  @underscored_name = -Member::BuildType.underscore(name_s)
235
235
  @name = -(camelize ? Member::BuildType.camelize(name_s) : name_s)
236
-
236
+ NameValidator.validate!(@name)
237
237
  @description = description
238
- @type = @owner_type = @own_validators = @own_directives = @own_arguments = nil # these will be prepared later if necessary
238
+ @type = @owner_type = @own_validators = @own_directives = @own_arguments = @arguments_statically_coercible = nil # these will be prepared later if necessary
239
239
 
240
240
  self.deprecation_reason = deprecation_reason
241
241
 
@@ -339,7 +339,7 @@ module GraphQL
339
339
  self.validates(validates)
340
340
  end
341
341
 
342
- if definition_block
342
+ if block_given?
343
343
  if definition_block.arity == 1
344
344
  yield self
345
345
  else
@@ -661,7 +661,7 @@ module GraphQL
661
661
 
662
662
  Schema::Validator.validate!(validators, application_object, query_ctx, args)
663
663
 
664
- query_ctx.schema.after_lazy(self.authorized?(application_object, args, query_ctx)) do |is_authorized|
664
+ query_ctx.query.after_lazy(self.authorized?(application_object, args, query_ctx)) do |is_authorized|
665
665
  if is_authorized
666
666
  with_extensions(object, args, query_ctx) do |obj, ruby_kwargs|
667
667
  method_args = ruby_kwargs
@@ -810,6 +810,17 @@ ERR
810
810
  end
811
811
  end
812
812
 
813
+ class ExtendedState
814
+ def initialize(args, object)
815
+ @arguments = args
816
+ @object = object
817
+ @memos = nil
818
+ @added_extras = nil
819
+ end
820
+
821
+ attr_accessor :arguments, :object, :memos, :added_extras
822
+ end
823
+
813
824
  # Wrap execution with hooks.
814
825
  # Written iteratively to avoid big stack traces.
815
826
  # @return [Object] Whatever the
@@ -820,20 +831,20 @@ ERR
820
831
  # This is a hack to get the _last_ value for extended obj and args,
821
832
  # in case one of the extensions doesn't `yield`.
822
833
  # (There's another implementation that uses multiple-return, but I'm wary of the perf cost of the extra arrays)
823
- extended = { args: args, obj: obj, memos: nil, added_extras: nil }
834
+ extended = ExtendedState.new(args, obj)
824
835
  value = run_extensions_before_resolve(obj, args, ctx, extended) do |obj, args|
825
- if (added_extras = extended[:added_extras])
836
+ if (added_extras = extended.added_extras)
826
837
  args = args.dup
827
838
  added_extras.each { |e| args.delete(e) }
828
839
  end
829
840
  yield(obj, args)
830
841
  end
831
842
 
832
- extended_obj = extended[:obj]
833
- extended_args = extended[:args]
834
- memos = extended[:memos] || EMPTY_HASH
843
+ extended_obj = extended.object
844
+ extended_args = extended.arguments # rubocop:disable Development/ContextIsPassedCop
845
+ memos = extended.memos || EMPTY_HASH
835
846
 
836
- ctx.schema.after_lazy(value) do |resolved_value|
847
+ ctx.query.after_lazy(value) do |resolved_value|
837
848
  idx = 0
838
849
  @extensions.each do |ext|
839
850
  memo = memos[idx]
@@ -851,17 +862,17 @@ ERR
851
862
  if extension
852
863
  extension.resolve(object: obj, arguments: args, context: ctx) do |extended_obj, extended_args, memo|
853
864
  if memo
854
- memos = extended[:memos] ||= {}
865
+ memos = extended.memos ||= {}
855
866
  memos[idx] = memo
856
867
  end
857
868
 
858
869
  if (extras = extension.added_extras)
859
- ae = extended[:added_extras] ||= []
870
+ ae = extended.added_extras ||= []
860
871
  ae.concat(extras)
861
872
  end
862
873
 
863
- extended[:obj] = extended_obj
864
- extended[:args] = extended_args
874
+ extended.object = extended_obj
875
+ extended.arguments = extended_args
865
876
  run_extensions_before_resolve(extended_obj, extended_args, ctx, extended, idx: idx + 1) { |o, a| yield(o, a) }
866
877
  end
867
878
  else
@@ -131,12 +131,7 @@ module GraphQL
131
131
  end
132
132
  end
133
133
  # Add a method access
134
- method_name = argument_defn.keyword
135
- class_eval <<-RUBY, __FILE__, __LINE__
136
- def #{method_name}
137
- self[#{method_name.inspect}]
138
- end
139
- RUBY
134
+ define_accessor_method(argument_defn.keyword)
140
135
  argument_defn
141
136
  end
142
137
 
@@ -211,7 +206,7 @@ module GraphQL
211
206
 
212
207
  arguments = coerce_arguments(nil, value, ctx)
213
208
 
214
- ctx.schema.after_lazy(arguments) do |resolved_arguments|
209
+ ctx.query.after_lazy(arguments) do |resolved_arguments|
215
210
  if resolved_arguments.is_a?(GraphQL::Error)
216
211
  raise resolved_arguments
217
212
  else
@@ -242,6 +237,13 @@ module GraphQL
242
237
 
243
238
  result
244
239
  end
240
+
241
+ private
242
+
243
+ def define_accessor_method(method_name)
244
+ define_method(method_name) { self[method_name] }
245
+ alias_method(method_name, method_name)
246
+ end
245
247
  end
246
248
 
247
249
  private
@@ -69,7 +69,11 @@ module GraphQL
69
69
  end
70
70
  elsif child_class < GraphQL::Schema::Object
71
71
  # This is being included into an object type, make sure it's using `implements(...)`
72
- backtrace_line = caller(0, 10).find { |line| line.include?("schema/member/has_interfaces.rb") && line.include?("in `implements'")}
72
+ backtrace_line = caller_locations(0, 10).find do |location|
73
+ location.base_label == "implements" &&
74
+ location.path.end_with?("schema/member/has_interfaces.rb")
75
+ end
76
+
73
77
  if !backtrace_line
74
78
  raise "Attach interfaces using `implements(#{self})`, not `include(#{self})`"
75
79
  end
@@ -155,7 +155,7 @@ module GraphQL
155
155
  if obj.is_a?(GraphQL::Schema::Object)
156
156
  obj = obj.object
157
157
  end
158
- wrapped_object = @object_class.authorized_new(obj, query_ctx)
158
+ wrapped_object = @object_class.wrap(obj, query_ctx)
159
159
  @inner_resolve.call(wrapped_object, args, ctx)
160
160
  end
161
161
  end
@@ -109,7 +109,14 @@ module GraphQL
109
109
  to_type_name(something.name)
110
110
  end
111
111
  when String
112
- something.gsub(/\]\[\!/, "").split("::").last
112
+ if something.include?("]") ||
113
+ something.include?("[") ||
114
+ something.include?("!") ||
115
+ something.include?("::")
116
+ something.gsub(/\]\[\!/, "").split("::").last
117
+ else
118
+ something
119
+ end
113
120
  when GraphQL::Schema::NonNull, GraphQL::Schema::List
114
121
  to_type_name(something.unwrap)
115
122
  else
@@ -122,7 +129,8 @@ module GraphQL
122
129
  return string unless string.include?("_")
123
130
  camelized = string.split('_').each(&:capitalize!).join
124
131
  camelized[0] = camelized[0].downcase
125
- if (match_data = string.match(/\A(_+)/))
132
+ if string.start_with?("_")
133
+ match_data = string.match(/\A(_+)/)
126
134
  camelized = "#{match_data[0]}#{camelized}"
127
135
  end
128
136
  camelized
@@ -51,7 +51,7 @@ module GraphQL
51
51
  class_eval <<-RUBY, __FILE__, __LINE__ + 1
52
52
  def #{method_owner}load_#{arg_defn.keyword}(values, context = nil)
53
53
  argument = get_argument("#{arg_defn.graphql_name}")
54
- (context || self.context).schema.after_lazy(values) do |values2|
54
+ (context || self.context).query.after_lazy(values) do |values2|
55
55
  GraphQL::Execution::Lazy.all(values2.map { |value| load_application_object(argument, value, context || self.context) })
56
56
  end
57
57
  end
@@ -320,9 +320,11 @@ module GraphQL
320
320
  end
321
321
 
322
322
  def arguments_statically_coercible?
323
- return @arguments_statically_coercible if defined?(@arguments_statically_coercible)
324
-
325
- @arguments_statically_coercible = all_argument_definitions.all?(&:statically_coercible?)
323
+ if defined?(@arguments_statically_coercible) && !@arguments_statically_coercible.nil?
324
+ @arguments_statically_coercible
325
+ else
326
+ @arguments_statically_coercible = all_argument_definitions.all?(&:statically_coercible?)
327
+ end
326
328
  end
327
329
 
328
330
  module ArgumentClassAccessor
@@ -363,7 +365,7 @@ module GraphQL
363
365
  end
364
366
 
365
367
  def authorize_application_object(argument, id, context, loaded_application_object)
366
- context.schema.after_lazy(loaded_application_object) do |application_object|
368
+ context.query.after_lazy(loaded_application_object) do |application_object|
367
369
  if application_object.nil?
368
370
  err = GraphQL::LoadApplicationObjectFailedError.new(argument: argument, id: id, object: application_object)
369
371
  load_application_object_failed(err)
@@ -371,7 +373,7 @@ module GraphQL
371
373
  # Double-check that the located object is actually of this type
372
374
  # (Don't want to allow arbitrary access to objects this way)
373
375
  maybe_lazy_resolve_type = context.schema.resolve_type(argument.loads, application_object, context)
374
- context.schema.after_lazy(maybe_lazy_resolve_type) do |resolve_type_result|
376
+ context.query.after_lazy(maybe_lazy_resolve_type) do |resolve_type_result|
375
377
  if resolve_type_result.is_a?(Array) && resolve_type_result.size == 2
376
378
  application_object_type, application_object = resolve_type_result
377
379
  else
@@ -386,7 +388,7 @@ module GraphQL
386
388
  # This object was loaded successfully
387
389
  # and resolved to the right type,
388
390
  # now apply the `.authorized?` class method if there is one
389
- context.schema.after_lazy(application_object_type.authorized?(application_object, context)) do |authed|
391
+ context.query.after_lazy(application_object_type.authorized?(application_object, context)) do |authed|
390
392
  if authed
391
393
  application_object
392
394
  else
@@ -6,7 +6,7 @@ module GraphQL
6
6
  module HasDirectives
7
7
  def self.extended(child_cls)
8
8
  super
9
- child_cls.module_eval { self.own_directives = nil }
9
+ child_cls.module_exec { self.own_directives = nil }
10
10
  end
11
11
 
12
12
  def inherited(child_cls)
@@ -180,7 +180,7 @@ module GraphQL
180
180
 
181
181
  def inherited(subclass)
182
182
  super
183
- subclass.class_eval do
183
+ subclass.class_exec do
184
184
  @own_fields ||= nil
185
185
  @field_class ||= nil
186
186
  end
@@ -119,7 +119,7 @@ module GraphQL
119
119
 
120
120
  def inherited(subclass)
121
121
  super
122
- subclass.class_eval do
122
+ subclass.class_exec do
123
123
  @own_interface_type_memberships ||= nil
124
124
  end
125
125
  end
@@ -43,7 +43,7 @@ module GraphQL
43
43
  private
44
44
 
45
45
  def inherited(subclass)
46
- subclass.class_eval do
46
+ subclass.class_exec do
47
47
  @to_non_null_type ||= nil
48
48
  @to_list_type ||= nil
49
49
  end
@@ -30,6 +30,11 @@ module GraphQL
30
30
  # @see authorized_new to make instances
31
31
  protected :new
32
32
 
33
+ # This is called by the runtime to return an object to call methods on.
34
+ def wrap(object, context)
35
+ authorized_new(object, context)
36
+ end
37
+
33
38
  # Make a new instance of this type _if_ the auth check passes,
34
39
  # otherwise, raise an error.
35
40
  #
@@ -68,7 +73,7 @@ module GraphQL
68
73
  maybe_lazy_auth_val
69
74
  end
70
75
 
71
- context.schema.after_lazy(auth_val) do |is_authorized|
76
+ context.query.after_lazy(auth_val) do |is_authorized|
72
77
  if is_authorized
73
78
  self.new(object, context)
74
79
  else
@@ -57,12 +57,14 @@ module GraphQL
57
57
  query_root = Class.new(GraphQL::Schema::Object) do
58
58
  graphql_name "Root"
59
59
  field :throwaway_field, String
60
+ def self.visible?(ctx)
61
+ false
62
+ end
60
63
  end
61
64
  schema = Class.new(GraphQL::Schema) { query(query_root) }
62
65
 
63
66
  introspection_schema_ast = GraphQL::Language::DocumentFromSchemaDefinition.new(
64
67
  schema,
65
- except: ->(member, _) { member.graphql_name == "Root" },
66
68
  include_introspection_types: true,
67
69
  include_built_in_directives: true,
68
70
  ).document
@@ -60,7 +60,7 @@ module GraphQL
60
60
  super()
61
61
  end
62
62
 
63
- context.schema.after_lazy(return_value) do |return_hash|
63
+ context.query.after_lazy(return_value) do |return_hash|
64
64
  # It might be an error
65
65
  if return_hash.is_a?(Hash)
66
66
  return_hash[:client_mutation_id] = client_mutation_id
@@ -65,41 +65,43 @@ module GraphQL
65
65
  # @api private
66
66
  def resolve_with_support(**args)
67
67
  # First call the ready? hook which may raise
68
- ready_val = if args.any?
68
+ raw_ready_val = if args.any?
69
69
  ready?(**args)
70
70
  else
71
71
  ready?
72
72
  end
73
- context.schema.after_lazy(ready_val) do |is_ready, ready_early_return|
74
- if ready_early_return
73
+ context.query.after_lazy(raw_ready_val) do |ready_val|
74
+ if ready_val.is_a?(Array)
75
+ is_ready, ready_early_return = ready_val
75
76
  if is_ready != false
76
77
  raise "Unexpected result from #ready? (expected `true`, `false` or `[false, {...}]`): [#{is_ready.inspect}, #{ready_early_return.inspect}]"
77
78
  else
78
79
  ready_early_return
79
80
  end
80
- elsif is_ready
81
+ elsif ready_val
81
82
  # Then call each prepare hook, which may return a different value
82
83
  # for that argument, or may return a lazy object
83
84
  load_arguments_val = load_arguments(args)
84
- context.schema.after_lazy(load_arguments_val) do |loaded_args|
85
+ context.query.after_lazy(load_arguments_val) do |loaded_args|
85
86
  @prepared_arguments = loaded_args
86
87
  Schema::Validator.validate!(self.class.validators, object, context, loaded_args, as: @field)
87
88
  # Then call `authorized?`, which may raise or may return a lazy object
88
- authorized_val = if loaded_args.any?
89
+ raw_authorized_val = if loaded_args.any?
89
90
  authorized?(**loaded_args)
90
91
  else
91
92
  authorized?
92
93
  end
93
- context.schema.after_lazy(authorized_val) do |(authorized_result, early_return)|
94
+ context.query.after_lazy(raw_authorized_val) do |authorized_val|
94
95
  # If the `authorized?` returned two values, `false, early_return`,
95
96
  # then use the early return value instead of continuing
96
- if early_return
97
+ if authorized_val.is_a?(Array)
98
+ authorized_result, early_return = authorized_val
97
99
  if authorized_result == false
98
100
  early_return
99
101
  else
100
102
  raise "Unexpected result from #authorized? (expected `true`, `false` or `[false, {...}]`): [#{authorized_result.inspect}, #{early_return.inspect}]"
101
103
  end
102
- elsif authorized_result
104
+ elsif authorized_val
103
105
  # Finally, all the hooks have passed, so resolve it
104
106
  if loaded_args.any?
105
107
  public_send(self.class.resolve_method, **loaded_args)
@@ -185,7 +187,7 @@ module GraphQL
185
187
  if arg_defn
186
188
  prepped_value = prepared_args[key] = arg_defn.load_and_authorize_value(self, value, context)
187
189
  if context.schema.lazy?(prepped_value)
188
- prepare_lazies << context.schema.after_lazy(prepped_value) do |finished_prepped_value|
190
+ prepare_lazies << context.query.after_lazy(prepped_value) do |finished_prepped_value|
189
191
  prepared_args[key] = finished_prepped_value
190
192
  end
191
193
  end
@@ -90,7 +90,7 @@ module GraphQL
90
90
  # The default implementation returns the `max_seconds:` value from installing this plugin.
91
91
  #
92
92
  # @param query [GraphQL::Query] The query that's about to run
93
- # @return [Integer, false] The number of seconds after which to interrupt query execution and call {#handle_error}, or `false` to bypass the timeout.
93
+ # @return [Numeric, false] The number of seconds after which to interrupt query execution and call {#handle_error}, or `false` to bypass the timeout.
94
94
  def max_seconds(query)
95
95
  @max_seconds
96
96
  end
@@ -133,7 +133,7 @@ module GraphQL
133
133
  if all_errors.frozen? # It's empty
134
134
  all_errors = []
135
135
  end
136
- interpolation_vars = { validated: validated.graphql_name }
136
+ interpolation_vars = { validated: validated.graphql_name, value: value.inspect }
137
137
  if errors.is_a?(String)
138
138
  all_errors << (errors % interpolation_vars)
139
139
  else
@@ -38,8 +38,9 @@ module GraphQL
38
38
  # @api private
39
39
  class Warden
40
40
  def self.from_context(context)
41
- context.warden # this might be a hash which won't respond to this
42
- rescue
41
+ context.warden || PassThruWarden
42
+ rescue NoMethodError
43
+ # this might be a hash which won't respond to #warden
43
44
  PassThruWarden
44
45
  end
45
46
 
@@ -87,17 +88,49 @@ module GraphQL
87
88
  end
88
89
  end
89
90
 
91
+ class NullWarden
92
+ def initialize(_filter = nil, context:, schema:)
93
+ @schema = schema
94
+ end
95
+
96
+ def visible_field?(field_defn, _ctx = nil, owner = nil); true; end
97
+ def visible_argument?(arg_defn, _ctx = nil); true; end
98
+ def visible_type?(type_defn, _ctx = nil); true; end
99
+ def visible_enum_value?(enum_value, _ctx = nil); true; end
100
+ def visible_type_membership?(type_membership, _ctx = nil); true; end
101
+ def interface_type_memberships(obj_type, _ctx = nil); obj_type.interface_type_memberships; end
102
+ def get_type(type_name); @schema.get_type(type_name); end # rubocop:disable Development/ContextIsPassedCop
103
+ def arguments(argument_owner, ctx = nil); argument_owner.all_argument_definitions; end
104
+ def enum_values(enum_defn); enum_defn.enum_values; end # rubocop:disable Development/ContextIsPassedCop
105
+ def get_argument(parent_type, argument_name); parent_type.get_argument(argument_name); end # rubocop:disable Development/ContextIsPassedCop
106
+ def types; @schema.types; end # rubocop:disable Development/ContextIsPassedCop
107
+ def root_type_for_operation(op_name); @schema.root_type_for_operation(op_name); end
108
+ def directives; @schema.directives.values; end
109
+ def fields(type_defn); type_defn.all_field_definitions; end # rubocop:disable Development/ContextIsPassedCop
110
+ def get_field(parent_type, field_name); @schema.get_field(parent_type, field_name); end
111
+ def reachable_type?(type_name); true; end
112
+ def reachable_types; @schema.types.values; end # rubocop:disable Development/ContextIsPassedCop
113
+ def possible_types(type_defn); @schema.possible_types(type_defn); end
114
+ def interfaces(obj_type); obj_type.interfaces; end
115
+ end
116
+
90
117
  # @param filter [<#call(member)>] Objects are hidden when `.call(member, ctx)` returns true
91
118
  # @param context [GraphQL::Query::Context]
92
119
  # @param schema [GraphQL::Schema]
93
- def initialize(filter, context:, schema:)
120
+ def initialize(filter = nil, context:, schema:)
94
121
  @schema = schema
95
122
  # Cache these to avoid repeated hits to the inheritance chain when one isn't present
96
123
  @query = @schema.query
97
124
  @mutation = @schema.mutation
98
125
  @subscription = @schema.subscription
99
126
  @context = context
100
- @visibility_cache = read_through { |m| filter.call(m, 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
+
133
+ @visibility_cache.compare_by_identity
101
134
  # Initialize all ivars to improve object shape consistency:
102
135
  @types = @visible_types = @reachable_types = @visible_parent_fields =
103
136
  @visible_possible_types = @visible_fields = @visible_arguments = @visible_enum_arrays =