graphql 1.9.7 → 1.9.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (113) hide show
  1. checksums.yaml +4 -4
  2. data/lib/generators/graphql/install_generator.rb +2 -1
  3. data/lib/generators/graphql/templates/base_argument.erb +4 -0
  4. data/lib/generators/graphql/templates/base_field.erb +2 -0
  5. data/lib/generators/graphql/templates/base_input_object.erb +1 -0
  6. data/lib/graphql/analysis/ast/query_complexity.rb +34 -18
  7. data/lib/graphql/argument.rb +8 -2
  8. data/lib/graphql/compatibility/lazy_execution_specification/lazy_schema.rb +1 -1
  9. data/lib/graphql/language/lexer.rb +24 -13
  10. data/lib/graphql/language/lexer.rl +23 -13
  11. data/lib/graphql/query/arguments.rb +16 -15
  12. data/lib/graphql/schema.rb +105 -48
  13. data/lib/graphql/schema/argument.rb +12 -1
  14. data/lib/graphql/schema/build_from_definition.rb +3 -0
  15. data/lib/graphql/schema/field.rb +3 -8
  16. data/lib/graphql/schema/find_inherited_value.rb +20 -0
  17. data/lib/graphql/schema/input_object.rb +1 -3
  18. data/lib/graphql/schema/loader.rb +1 -0
  19. data/lib/graphql/schema/member/base_dsl_methods.rb +7 -18
  20. data/lib/graphql/schema/member/has_arguments.rb +4 -9
  21. data/lib/graphql/schema/member/has_fields.rb +14 -0
  22. data/lib/graphql/schema/member/relay_shortcuts.rb +2 -2
  23. data/lib/graphql/schema/resolver.rb +31 -8
  24. data/lib/graphql/schema/resolver/has_payload_type.rb +3 -2
  25. data/lib/graphql/schema/subscription.rb +1 -1
  26. data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +1 -1
  27. data/lib/graphql/version.rb +1 -1
  28. data/spec/graphql/analysis/analyze_query_spec.rb +14 -25
  29. data/spec/graphql/analysis/ast/max_query_complexity_spec.rb +7 -19
  30. data/spec/graphql/analysis/ast/max_query_depth_spec.rb +5 -12
  31. data/spec/graphql/analysis/max_query_complexity_spec.rb +12 -20
  32. data/spec/graphql/analysis/max_query_depth_spec.rb +6 -13
  33. data/spec/graphql/language/lexer_spec.rb +19 -1
  34. data/spec/graphql/schema/argument_spec.rb +1 -1
  35. data/spec/graphql/schema/build_from_definition_spec.rb +10 -0
  36. data/spec/graphql/schema/catchall_middleware_spec.rb +6 -9
  37. data/spec/graphql/schema/input_object_spec.rb +25 -0
  38. data/spec/graphql/schema/loader_spec.rb +65 -1
  39. data/spec/graphql/schema/object_spec.rb +21 -0
  40. data/spec/graphql/schema/resolver_spec.rb +30 -1
  41. data/spec/graphql/schema_spec.rb +135 -0
  42. data/spec/graphql/static_validation/rules/required_arguments_are_present_spec.rb +25 -0
  43. data/spec/integration/rails/generators/graphql/install_generator_spec.rb +20 -0
  44. data/spec/integration/tmp/app/graphql/types/page_type.rb +5 -0
  45. data/spec/support/dummy/schema.rb +1 -1
  46. data/spec/support/lazy_helpers.rb +1 -1
  47. data/spec/support/parser/filename_example_invalid_utf8.graphql +1 -0
  48. metadata +10 -132
  49. data/spec/integration/tmp/app/graphql/types/date_type.rb +0 -14
  50. data/spec/integration/tmp/dummy/Gemfile +0 -50
  51. data/spec/integration/tmp/dummy/README.md +0 -24
  52. data/spec/integration/tmp/dummy/Rakefile +0 -6
  53. data/spec/integration/tmp/dummy/app/assets/config/manifest.js +0 -3
  54. data/spec/integration/tmp/dummy/app/assets/javascripts/application.js +0 -16
  55. data/spec/integration/tmp/dummy/app/assets/javascripts/cable.js +0 -13
  56. data/spec/integration/tmp/dummy/app/assets/stylesheets/application.css +0 -15
  57. data/spec/integration/tmp/dummy/app/channels/application_cable/channel.rb +0 -5
  58. data/spec/integration/tmp/dummy/app/channels/application_cable/connection.rb +0 -5
  59. data/spec/integration/tmp/dummy/app/controllers/application_controller.rb +0 -4
  60. data/spec/integration/tmp/dummy/app/controllers/graphql_controller.rb +0 -44
  61. data/spec/integration/tmp/dummy/app/helpers/application_helper.rb +0 -3
  62. data/spec/integration/tmp/dummy/app/jobs/application_job.rb +0 -3
  63. data/spec/integration/tmp/dummy/app/mailers/application_mailer.rb +0 -5
  64. data/spec/integration/tmp/dummy/app/mydirectory/dummy_schema.rb +0 -5
  65. data/spec/integration/tmp/dummy/app/mydirectory/mutations/update_name.rb +0 -15
  66. data/spec/integration/tmp/dummy/app/mydirectory/types/base_enum.rb +0 -5
  67. data/spec/integration/tmp/dummy/app/mydirectory/types/base_input_object.rb +0 -5
  68. data/spec/integration/tmp/dummy/app/mydirectory/types/base_interface.rb +0 -6
  69. data/spec/integration/tmp/dummy/app/mydirectory/types/base_object.rb +0 -5
  70. data/spec/integration/tmp/dummy/app/mydirectory/types/base_scalar.rb +0 -5
  71. data/spec/integration/tmp/dummy/app/mydirectory/types/base_union.rb +0 -5
  72. data/spec/integration/tmp/dummy/app/mydirectory/types/mutation_type.rb +0 -12
  73. data/spec/integration/tmp/dummy/app/mydirectory/types/query_type.rb +0 -14
  74. data/spec/integration/tmp/dummy/app/views/layouts/application.html.erb +0 -14
  75. data/spec/integration/tmp/dummy/app/views/layouts/mailer.html.erb +0 -13
  76. data/spec/integration/tmp/dummy/app/views/layouts/mailer.text.erb +0 -1
  77. data/spec/integration/tmp/dummy/bin/bundle +0 -3
  78. data/spec/integration/tmp/dummy/bin/rails +0 -4
  79. data/spec/integration/tmp/dummy/bin/rake +0 -4
  80. data/spec/integration/tmp/dummy/bin/setup +0 -34
  81. data/spec/integration/tmp/dummy/bin/update +0 -29
  82. data/spec/integration/tmp/dummy/config.ru +0 -5
  83. data/spec/integration/tmp/dummy/config/application.rb +0 -26
  84. data/spec/integration/tmp/dummy/config/boot.rb +0 -4
  85. data/spec/integration/tmp/dummy/config/cable.yml +0 -9
  86. data/spec/integration/tmp/dummy/config/environment.rb +0 -6
  87. data/spec/integration/tmp/dummy/config/environments/development.rb +0 -52
  88. data/spec/integration/tmp/dummy/config/environments/production.rb +0 -84
  89. data/spec/integration/tmp/dummy/config/environments/test.rb +0 -43
  90. data/spec/integration/tmp/dummy/config/initializers/application_controller_renderer.rb +0 -9
  91. data/spec/integration/tmp/dummy/config/initializers/assets.rb +0 -12
  92. data/spec/integration/tmp/dummy/config/initializers/backtrace_silencers.rb +0 -8
  93. data/spec/integration/tmp/dummy/config/initializers/cookies_serializer.rb +0 -6
  94. data/spec/integration/tmp/dummy/config/initializers/filter_parameter_logging.rb +0 -5
  95. data/spec/integration/tmp/dummy/config/initializers/inflections.rb +0 -17
  96. data/spec/integration/tmp/dummy/config/initializers/mime_types.rb +0 -5
  97. data/spec/integration/tmp/dummy/config/initializers/new_framework_defaults.rb +0 -24
  98. data/spec/integration/tmp/dummy/config/initializers/session_store.rb +0 -4
  99. data/spec/integration/tmp/dummy/config/initializers/wrap_parameters.rb +0 -10
  100. data/spec/integration/tmp/dummy/config/locales/en.yml +0 -23
  101. data/spec/integration/tmp/dummy/config/puma.rb +0 -48
  102. data/spec/integration/tmp/dummy/config/routes.rb +0 -9
  103. data/spec/integration/tmp/dummy/config/secrets.yml +0 -22
  104. data/spec/integration/tmp/dummy/db/seeds.rb +0 -8
  105. data/spec/integration/tmp/dummy/log/test.log +0 -0
  106. data/spec/integration/tmp/dummy/public/404.html +0 -67
  107. data/spec/integration/tmp/dummy/public/422.html +0 -67
  108. data/spec/integration/tmp/dummy/public/500.html +0 -66
  109. data/spec/integration/tmp/dummy/public/apple-touch-icon-precomposed.png +0 -0
  110. data/spec/integration/tmp/dummy/public/apple-touch-icon.png +0 -0
  111. data/spec/integration/tmp/dummy/public/favicon.ico +0 -0
  112. data/spec/integration/tmp/dummy/public/robots.txt +0 -5
  113. data/spec/integration/tmp/dummy/test/test_helper.rb +0 -8
@@ -24,6 +24,11 @@ module GraphQL
24
24
  # @return [Class, Module, nil] If this argument should load an application object, this is the type of object to load
25
25
  attr_reader :loads
26
26
 
27
+ # @return [Boolean] true if a resolver defined this argument
28
+ def from_resolver?
29
+ @from_resolver
30
+ end
31
+
27
32
  # @param arg_name [Symbol]
28
33
  # @param type_expr
29
34
  # @param desc [String]
@@ -33,7 +38,9 @@ module GraphQL
33
38
  # @param as [Symbol] Override the keyword name when passed to a method
34
39
  # @param prepare [Symbol] A method to call to transform this argument's valuebefore sending it to field resolution
35
40
  # @param camelize [Boolean] if true, the name will be camelized when building the schema
36
- def initialize(arg_name = nil, type_expr = nil, desc = nil, required:, type: nil, name: nil, loads: nil, description: nil, default_value: NO_DEFAULT, as: nil, camelize: true, prepare: nil, owner:, &definition_block)
41
+ # @param from_resolver [Boolean] if true, a Resolver class defined this argument
42
+ # @param method_access [Boolean] If false, don't build method access on legacy {Query::Arguments} instances.
43
+ def initialize(arg_name = nil, type_expr = nil, desc = nil, required:, type: nil, name: nil, loads: nil, description: nil, ast_node: nil, default_value: NO_DEFAULT, as: nil, from_resolver: false, camelize: true, prepare: nil, method_access: true, owner:, &definition_block)
37
44
  arg_name ||= name
38
45
  name_str = camelize ? Member::BuildType.camelize(arg_name.to_s) : arg_name.to_s
39
46
  @name = name_str.freeze
@@ -46,6 +53,9 @@ module GraphQL
46
53
  @loads = loads
47
54
  @keyword = as || Schema::Member::BuildType.underscore(@name).to_sym
48
55
  @prepare = prepare
56
+ @ast_node = ast_node
57
+ @from_resolver = from_resolver
58
+ @method_access = method_access
49
59
 
50
60
  if definition_block
51
61
  if definition_block.arity == 1
@@ -94,6 +104,7 @@ module GraphQL
94
104
  argument.description = @description
95
105
  argument.metadata[:type_class] = self
96
106
  argument.as = @as
107
+ argument.method_access = @method_access
97
108
  if NO_DEFAULT != @default_value
98
109
  argument.default_value = @default_value
99
110
  end
@@ -232,6 +232,7 @@ module GraphQL
232
232
  name: input_argument.name,
233
233
  type: type_resolver.call(input_argument.type),
234
234
  description: input_argument.description,
235
+ method_access: false,
235
236
  **kwargs,
236
237
  )
237
238
 
@@ -269,6 +270,7 @@ module GraphQL
269
270
  name: directive_argument.name,
270
271
  type: type_resolver.call(directive_argument.type),
271
272
  description: directive_argument.description,
273
+ method_access: false,
272
274
  **kwargs,
273
275
  )
274
276
 
@@ -306,6 +308,7 @@ module GraphQL
306
308
  name: argument.name,
307
309
  description: argument.description,
308
310
  type: type_resolver.call(argument.type),
311
+ method_access: false,
309
312
  **kwargs,
310
313
  )
311
314
 
@@ -205,7 +205,7 @@ module GraphQL
205
205
 
206
206
  # TODO: I think non-string/symbol hash keys are wrongly normalized (eg `1` will not work)
207
207
  method_name = method || hash_key || @underscored_name
208
- resolver_method ||= @underscored_name
208
+ resolver_method ||= @underscored_name.to_sym
209
209
 
210
210
  @method_str = method_name.to_s
211
211
  @method_sym = method_name.to_sym
@@ -418,13 +418,10 @@ module GraphQL
418
418
  end
419
419
 
420
420
  def authorized?(object, context)
421
- self_auth = if @resolver_class
421
+ if @resolver_class
422
+ # The resolver will check itself during `resolve()`
422
423
  @resolver_class.authorized?(object, context)
423
424
  else
424
- true
425
- end
426
-
427
- if self_auth
428
425
  # Faster than `.any?`
429
426
  arguments.each_value do |arg|
430
427
  if !arg.authorized?(object, context)
@@ -432,8 +429,6 @@ module GraphQL
432
429
  end
433
430
  end
434
431
  true
435
- else
436
- false
437
432
  end
438
433
  end
439
434
 
@@ -0,0 +1,20 @@
1
+ module GraphQL
2
+ class Schema
3
+ module FindInheritedValue
4
+ private
5
+
6
+ def find_inherited_value(method_name, default_value = nil)
7
+ if self.is_a?(Class)
8
+ superclass.respond_to?(method_name, true) ? superclass.send(method_name) : default_value
9
+ else
10
+ ancestors[1..-1].each do |ancestor|
11
+ if ancestor.respond_to?(method_name, true)
12
+ return ancestor.send(method_name)
13
+ end
14
+ end
15
+ default_value
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -23,7 +23,7 @@ module GraphQL
23
23
  ruby_kwargs_key = arg_defn.keyword
24
24
  loads = arg_defn.loads
25
25
 
26
- if @ruby_style_hash.key?(ruby_kwargs_key) && loads
26
+ if @ruby_style_hash.key?(ruby_kwargs_key) && loads && !arg_defn.from_resolver?
27
27
  value = @ruby_style_hash[ruby_kwargs_key]
28
28
  @ruby_style_hash[ruby_kwargs_key] = if arg_defn.type.list?
29
29
  GraphQL::Execution::Lazy.all(value.map { |val| load_application_object(arg_defn, loads, val) })
@@ -99,8 +99,6 @@ module GraphQL
99
99
  attr_accessor :arguments_class
100
100
 
101
101
  def argument(*args, **kwargs, &block)
102
- # Translate `loads:` to `as:` if needed`
103
- *args, kwargs = argument_with_loads(*args, **kwargs, &block)
104
102
  argument_defn = super(*args, **kwargs, &block)
105
103
  # Add a method access
106
104
  method_name = argument_defn.keyword
@@ -148,6 +148,7 @@ module GraphQL
148
148
  name: type["name"],
149
149
  type: type_resolver.call(type["type"]),
150
150
  description: type["description"],
151
+ method_access: false,
151
152
  **kwargs
152
153
  )
153
154
  when "SCALAR"
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "graphql/schema/find_inherited_value"
4
+
3
5
  module GraphQL
4
6
  class Schema
5
7
  class Member
@@ -7,6 +9,8 @@ module GraphQL
7
9
  # @api private
8
10
  # @see Classes that extend this, eg {GraphQL::Schema::Object}
9
11
  module BaseDSLMethods
12
+ include GraphQL::Schema::FindInheritedValue
13
+
10
14
  # Call this with a new name to override the default name for this schema member; OR
11
15
  # call it without an argument to get the name of this schema member
12
16
  #
@@ -42,7 +46,7 @@ module GraphQL
42
46
  if new_description
43
47
  @description = new_description
44
48
  else
45
- @description || find_inherited_method(:description, nil)
49
+ @description || find_inherited_value(:description)
46
50
  end
47
51
  end
48
52
 
@@ -51,7 +55,7 @@ module GraphQL
51
55
  if !new_introspection.nil?
52
56
  @introspection = new_introspection
53
57
  else
54
- @introspection || find_inherited_method(:introspection, false)
58
+ @introspection || find_inherited_value(:introspection, false)
55
59
  end
56
60
  end
57
61
 
@@ -76,7 +80,7 @@ module GraphQL
76
80
  alias :unwrap :itself
77
81
 
78
82
  def overridden_graphql_name
79
- @graphql_name || find_inherited_method(:overridden_graphql_name, nil)
83
+ @graphql_name || find_inherited_value(:overridden_graphql_name)
80
84
  end
81
85
 
82
86
  # Creates the default name for a schema member.
@@ -113,21 +117,6 @@ module GraphQL
113
117
  true
114
118
  end
115
119
  end
116
-
117
- private
118
-
119
- def find_inherited_method(method_name, default_value)
120
- if self.is_a?(Class)
121
- superclass.respond_to?(method_name) ? superclass.public_send(method_name) : default_value
122
- else
123
- ancestors[1..-1].each do |ancestor|
124
- if ancestor.respond_to?(method_name)
125
- return ancestor.public_send(method_name)
126
- end
127
- end
128
- default_value
129
- end
130
- end
131
120
  end
132
121
  end
133
122
  end
@@ -13,7 +13,10 @@ module GraphQL
13
13
  cls.include(ArgumentObjectLoader)
14
14
  end
15
15
 
16
- def argument_with_loads(*args, **kwargs)
16
+ # @see {GraphQL::Schema::Argument#initialize} for parameters
17
+ # @return [GraphQL::Schema::Argument] An instance of {arguments_class}, created from `*args`
18
+ def argument(*args, **kwargs, &block)
19
+ kwargs[:owner] = self
17
20
  loads = kwargs[:loads]
18
21
  if loads
19
22
  name = args[0]
@@ -32,14 +35,6 @@ module GraphQL
32
35
 
33
36
  kwargs[:as] ||= inferred_arg_name
34
37
  end
35
-
36
- return [*args, **kwargs]
37
- end
38
-
39
- # @see {GraphQL::Schema::Argument#initialize} for parameters
40
- # @return [GraphQL::Schema::Argument] An instance of {arguments_class}, created from `*args`
41
- def argument(*args, **kwargs, &block)
42
- kwargs[:owner] = self
43
38
  arg_defn = self.argument_class.new(*args, **kwargs, &block)
44
39
  add_argument(arg_defn)
45
40
  end
@@ -38,10 +38,24 @@ module GraphQL
38
38
  end
39
39
  end
40
40
 
41
+ # A list of field names that we should advise users to pick a different
42
+ # resolve method name.
43
+ #
44
+ # @api private
45
+ CONFLICT_FIELD_NAMES = Set.new([
46
+ # GraphQL-Ruby conflicts
47
+ :context, :object,
48
+ # Ruby built-ins conflicts
49
+ :method, :class
50
+ ])
51
+
41
52
  # Register this field with the class, overriding a previous one if needed.
42
53
  # @param field_defn [GraphQL::Schema::Field]
43
54
  # @return [void]
44
55
  def add_field(field_defn)
56
+ if CONFLICT_FIELD_NAMES.include?(field_defn.resolver_method)
57
+ warn "#{self.graphql_name}'s `field :#{field_defn.name}` conflicts with a built-in method, use `resolver_method:` to pick a different resolver method for this field (for example, `resolver_method: :resolve_#{field_defn.resolver_method}` and `def resolve_#{field_defn.resolver_method}`)"
58
+ end
45
59
  own_fields[field_defn.name] = field_defn
46
60
  nil
47
61
  end
@@ -8,7 +8,7 @@ module GraphQL
8
8
  if new_edge_type_class
9
9
  @edge_type_class = new_edge_type_class
10
10
  else
11
- @edge_type_class || find_inherited_method(:edge_type_class, Types::Relay::BaseEdge)
11
+ @edge_type_class || find_inherited_value(:edge_type_class, Types::Relay::BaseEdge)
12
12
  end
13
13
  end
14
14
 
@@ -16,7 +16,7 @@ module GraphQL
16
16
  if new_connection_type_class
17
17
  @connection_type_class = new_connection_type_class
18
18
  else
19
- @connection_type_class || find_inherited_method(:connection_type_class, Types::Relay::BaseConnection)
19
+ @connection_type_class || find_inherited_value(:connection_type_class, Types::Relay::BaseConnection)
20
20
  end
21
21
  end
22
22
 
@@ -123,12 +123,36 @@ module GraphQL
123
123
  # Called after arguments are loaded, but before resolving.
124
124
  #
125
125
  # Override it to check everything before calling the mutation.
126
- # @param args [Hash] The input arguments
126
+ # @param inputs [Hash] The input arguments
127
127
  # @raise [GraphQL::ExecutionError] To add an error to the response
128
128
  # @raise [GraphQL::UnauthorizedError] To signal an authorization failure
129
129
  # @return [Boolean, early_return_data] If `false`, execution will stop (and `early_return_data` will be returned instead, if present.)
130
- def authorized?(**args)
131
- true
130
+ def authorized?(**inputs)
131
+ self.class.arguments.each_value do |argument|
132
+ arg_keyword = argument.keyword
133
+ if inputs.key?(arg_keyword) && !(value = inputs[arg_keyword]).nil? && (value != argument.default_value)
134
+ loads_type = @arguments_loads_as_type[arg_keyword]
135
+ # If this argument resulted in an object being loaded,
136
+ # then authorize this loaded object with its own policy.
137
+ #
138
+ # But if this argument was "just" a plain argument, like
139
+ # a boolean, then authorize it based on the mutation.
140
+ authorization_value = if loads_type
141
+ value
142
+ else
143
+ self
144
+ end
145
+
146
+ arg_auth, err = argument.authorized?(authorization_value, context)
147
+ if !arg_auth
148
+ return arg_auth, err
149
+ else
150
+ true
151
+ end
152
+ else
153
+ true
154
+ end
155
+ end
132
156
  end
133
157
 
134
158
  private
@@ -254,12 +278,11 @@ module GraphQL
254
278
  # Add an argument to this field's signature, but
255
279
  # also add some preparation hook methods which will be used for this argument
256
280
  # @see {GraphQL::Schema::Argument#initialize} for the signature
257
- def argument(name, type, *rest, loads: nil, **kwargs, &block)
258
- *args, kwargs = argument_with_loads(name, type, *rest, loads: loads, **kwargs, &block)
259
- # Short-circuit the InputObject's own `loads:` implementation
281
+ def argument(*args, **kwargs, &block)
282
+ loads = kwargs[:loads]
283
+ # Use `from_resolver: true` to short-circuit the InputObject's own `loads:` implementation
260
284
  # so that we can support `#load_{x}` methods below.
261
- kwargs.delete(:loads)
262
- arg_defn = super(*args, **kwargs)
285
+ arg_defn = super(*args, from_resolver: true, **kwargs)
263
286
  own_arguments_loads_as_type[arg_defn.keyword] = loads if loads
264
287
 
265
288
  if loads && arg_defn.type.list?
@@ -27,7 +27,7 @@ module GraphQL
27
27
  if new_class
28
28
  @field_class = new_class
29
29
  else
30
- @field_class || find_inherited_method(:field_class, GraphQL::Schema::Field)
30
+ @field_class || find_inherited_value(:field_class, GraphQL::Schema::Field)
31
31
  end
32
32
  end
33
33
 
@@ -37,8 +37,9 @@ module GraphQL
37
37
  def object_class(new_class = nil)
38
38
  if new_class
39
39
  @object_class = new_class
40
+ else
41
+ @object_class || find_inherited_value(:object_class, GraphQL::Schema::Object)
40
42
  end
41
- @object_class || (superclass.respond_to?(:object_class) ? superclass.object_class : GraphQL::Schema::Object)
42
43
  end
43
44
 
44
45
  private
@@ -104,7 +104,7 @@ module GraphQL
104
104
  elsif defined?(@subscription_scope)
105
105
  @subscription_scope
106
106
  else
107
- find_inherited_method(:subscription_scope, nil)
107
+ find_inherited_value(:subscription_scope)
108
108
  end
109
109
  end
110
110
 
@@ -17,7 +17,7 @@ module GraphQL
17
17
 
18
18
  def assert_required_args(ast_node, defn)
19
19
  present_argument_names = ast_node.arguments.map(&:name)
20
- required_argument_names = defn.arguments.values
20
+ required_argument_names = context.warden.arguments(defn)
21
21
  .select { |a| a.type.kind.non_null? }
22
22
  .map(&:name)
23
23
 
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module GraphQL
3
- VERSION = "1.9.7"
3
+ VERSION = "1.9.8"
4
4
  end
@@ -31,6 +31,8 @@ describe GraphQL::Analysis do
31
31
  end
32
32
  end
33
33
 
34
+ let(:schema) { Class.new(Dummy::Schema) }
35
+
34
36
  describe ".analyze_query" do
35
37
  let(:node_counter) {
36
38
  ->(memo, visit_type, irep_node) {
@@ -43,7 +45,7 @@ describe GraphQL::Analysis do
43
45
  let(:analyzers) { [type_collector, node_counter] }
44
46
  let(:reduce_result) { GraphQL::Analysis.analyze_query(query, analyzers) }
45
47
  let(:variables) { {} }
46
- let(:query) { GraphQL::Query.new(Dummy::Schema, query_string, variables: variables) }
48
+ let(:query) { GraphQL::Query.new(schema, query_string, variables: variables) }
47
49
  let(:query_string) {%|
48
50
  {
49
51
  cheese(id: 1) {
@@ -58,7 +60,7 @@ describe GraphQL::Analysis do
58
60
  let(:analyzers) { [type_collector, conditional_analyzer] }
59
61
 
60
62
  describe "when analyze? returns false" do
61
- let(:query) { GraphQL::Query.new(Dummy::Schema, query_string, variables: variables, context: { analyze: false }) }
63
+ let(:query) { GraphQL::Query.new(schema, query_string, variables: variables, context: { analyze: false }) }
62
64
 
63
65
  it "does not run the analyzer" do
64
66
  # Only type_collector ran
@@ -67,7 +69,7 @@ describe GraphQL::Analysis do
67
69
  end
68
70
 
69
71
  describe "when analyze? returns true" do
70
- let(:query) { GraphQL::Query.new(Dummy::Schema, query_string, variables: variables, context: { analyze: true }) }
72
+ let(:query) { GraphQL::Query.new(schema, query_string, variables: variables, context: { analyze: true }) }
71
73
 
72
74
  it "it runs the analyzer" do
73
75
  # Both analyzers ran
@@ -93,7 +95,7 @@ describe GraphQL::Analysis do
93
95
  it "emits traces" do
94
96
  traces = TestTracing.with_trace do
95
97
  ctx = { tracers: [TestTracing] }
96
- Dummy::Schema.execute(query_string, context: ctx)
98
+ schema.execute(query_string, context: ctx)
97
99
  end
98
100
 
99
101
  # The query_trace is on the list _first_ because it finished first
@@ -119,14 +121,7 @@ describe GraphQL::Analysis do
119
121
  let(:variable_accessor) { ->(memo, visit_type, irep_node) { query.variables["cheeseId"] } }
120
122
 
121
123
  before do
122
- @previous_query_analyzers = Dummy::Schema.query_analyzers.dup
123
- Dummy::Schema.query_analyzers.clear
124
- Dummy::Schema.query_analyzers << variable_accessor
125
- end
126
-
127
- after do
128
- Dummy::Schema.query_analyzers.clear
129
- Dummy::Schema.query_analyzers.push(*@previous_query_analyzers)
124
+ schema.query_analyzer(variable_accessor)
130
125
  end
131
126
 
132
127
  it "returns an error" do
@@ -213,7 +208,7 @@ describe GraphQL::Analysis do
213
208
  let(:flavor_catcher) { FlavorCatcher.new }
214
209
  let(:analyzers) { [id_catcher, flavor_catcher] }
215
210
  let(:reduce_result) { GraphQL::Analysis.analyze_query(query, analyzers) }
216
- let(:query) { GraphQL::Query.new(Dummy::Schema, query_string) }
211
+ let(:query) { GraphQL::Query.new(schema, query_string) }
217
212
  let(:query_string) {%|
218
213
  {
219
214
  cheese(id: 1) {
@@ -222,7 +217,12 @@ describe GraphQL::Analysis do
222
217
  }
223
218
  }
224
219
  |}
225
- let(:schema) { Dummy::Schema }
220
+ let(:schema) do
221
+ schema = Class.new(Dummy::Schema)
222
+ schema.query_analyzer(id_catcher)
223
+ schema.query_analyzer(flavor_catcher)
224
+ schema
225
+ end
226
226
  let(:result) { schema.execute(query_string) }
227
227
  let(:query_string) {%|
228
228
  {
@@ -233,17 +233,6 @@ describe GraphQL::Analysis do
233
233
  }
234
234
  |}
235
235
 
236
- before do
237
- @previous_query_analyzers = Dummy::Schema.query_analyzers.dup
238
- Dummy::Schema.query_analyzers.clear
239
- Dummy::Schema.query_analyzers << id_catcher << flavor_catcher
240
- end
241
-
242
- after do
243
- Dummy::Schema.query_analyzers.clear
244
- Dummy::Schema.query_analyzers.push(*@previous_query_analyzers)
245
- end
246
-
247
236
  it "groups all errors together" do
248
237
  data = result["data"]
249
238
  errors = result["errors"]