graphql 2.3.5 → 2.3.8

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.

Potentially problematic release.


This version of graphql might be problematic. Click here for more details.

Files changed (79) hide show
  1. checksums.yaml +4 -4
  2. data/lib/graphql/analysis/analyzer.rb +89 -0
  3. data/lib/graphql/analysis/field_usage.rb +82 -0
  4. data/lib/graphql/analysis/max_query_complexity.rb +20 -0
  5. data/lib/graphql/analysis/max_query_depth.rb +20 -0
  6. data/lib/graphql/analysis/query_complexity.rb +183 -0
  7. data/lib/graphql/analysis/{ast/query_depth.rb → query_depth.rb} +23 -25
  8. data/lib/graphql/analysis/visitor.rb +283 -0
  9. data/lib/graphql/analysis.rb +92 -1
  10. data/lib/graphql/dataloader/async_dataloader.rb +2 -0
  11. data/lib/graphql/execution/interpreter/runtime.rb +6 -6
  12. data/lib/graphql/execution/interpreter.rb +1 -1
  13. data/lib/graphql/execution/lookahead.rb +10 -10
  14. data/lib/graphql/introspection/directive_type.rb +1 -1
  15. data/lib/graphql/introspection/entry_points.rb +2 -2
  16. data/lib/graphql/introspection/field_type.rb +1 -1
  17. data/lib/graphql/introspection/schema_type.rb +13 -3
  18. data/lib/graphql/introspection/type_type.rb +5 -5
  19. data/lib/graphql/language/document_from_schema_definition.rb +19 -26
  20. data/lib/graphql/language/lexer.rb +0 -3
  21. data/lib/graphql/language/sanitized_printer.rb +1 -1
  22. data/lib/graphql/language.rb +0 -1
  23. data/lib/graphql/query/context.rb +4 -0
  24. data/lib/graphql/query/null_context.rb +4 -0
  25. data/lib/graphql/query/validation_pipeline.rb +2 -2
  26. data/lib/graphql/query.rb +26 -3
  27. data/lib/graphql/schema/always_visible.rb +1 -0
  28. data/lib/graphql/schema/argument.rb +19 -5
  29. data/lib/graphql/schema/directive.rb +2 -0
  30. data/lib/graphql/schema/enum.rb +4 -4
  31. data/lib/graphql/schema/field.rb +13 -1
  32. data/lib/graphql/schema/has_single_input_argument.rb +2 -1
  33. data/lib/graphql/schema/input_object.rb +8 -7
  34. data/lib/graphql/schema/introspection_system.rb +2 -14
  35. data/lib/graphql/schema/member/has_arguments.rb +7 -6
  36. data/lib/graphql/schema/member/has_fields.rb +6 -4
  37. data/lib/graphql/schema/resolver.rb +5 -5
  38. data/lib/graphql/schema/subset.rb +397 -0
  39. data/lib/graphql/schema/type_expression.rb +2 -2
  40. data/lib/graphql/schema/validator/all_validator.rb +60 -0
  41. data/lib/graphql/schema/validator.rb +2 -0
  42. data/lib/graphql/schema/warden.rb +88 -1
  43. data/lib/graphql/schema.rb +44 -15
  44. data/lib/graphql/static_validation/base_visitor.rb +6 -5
  45. data/lib/graphql/static_validation/literal_validator.rb +4 -4
  46. data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +1 -1
  47. data/lib/graphql/static_validation/rules/arguments_are_defined.rb +1 -1
  48. data/lib/graphql/static_validation/rules/directives_are_defined.rb +1 -2
  49. data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +1 -1
  50. data/lib/graphql/static_validation/rules/fields_will_merge.rb +7 -7
  51. data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +3 -3
  52. data/lib/graphql/static_validation/rules/fragment_types_exist.rb +1 -1
  53. data/lib/graphql/static_validation/rules/fragments_are_on_composite_types.rb +1 -1
  54. data/lib/graphql/static_validation/rules/mutation_root_exists.rb +1 -1
  55. data/lib/graphql/static_validation/rules/query_root_exists.rb +1 -1
  56. data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +3 -3
  57. data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +3 -3
  58. data/lib/graphql/static_validation/rules/subscription_root_exists.rb +1 -1
  59. data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +1 -1
  60. data/lib/graphql/static_validation/rules/variables_are_input_types.rb +1 -1
  61. data/lib/graphql/static_validation/validation_context.rb +2 -2
  62. data/lib/graphql/subscriptions/broadcast_analyzer.rb +11 -5
  63. data/lib/graphql/subscriptions/event.rb +1 -1
  64. data/lib/graphql/subscriptions.rb +3 -3
  65. data/lib/graphql/testing/helpers.rb +2 -2
  66. data/lib/graphql/types/relay/connection_behaviors.rb +10 -0
  67. data/lib/graphql/types/relay/edge_behaviors.rb +10 -0
  68. data/lib/graphql/types/relay/page_info_behaviors.rb +4 -0
  69. data/lib/graphql/version.rb +1 -1
  70. metadata +12 -13
  71. data/lib/graphql/analysis/ast/analyzer.rb +0 -91
  72. data/lib/graphql/analysis/ast/field_usage.rb +0 -84
  73. data/lib/graphql/analysis/ast/max_query_complexity.rb +0 -22
  74. data/lib/graphql/analysis/ast/max_query_depth.rb +0 -22
  75. data/lib/graphql/analysis/ast/query_complexity.rb +0 -185
  76. data/lib/graphql/analysis/ast/visitor.rb +0 -284
  77. data/lib/graphql/analysis/ast.rb +0 -94
  78. data/lib/graphql/language/token.rb +0 -34
  79. data/lib/graphql/schema/invalid_type_error.rb +0 -7
@@ -24,15 +24,8 @@ module GraphQL
24
24
  @include_built_in_directives = include_built_in_directives
25
25
  @include_one_of = false
26
26
 
27
- schema_context = schema.context_class.new(query: nil, schema: schema, values: context)
28
-
29
-
30
- @warden = @schema.warden_class.new(
31
- schema: @schema,
32
- context: schema_context,
33
- )
34
-
35
- schema_context.warden = @warden
27
+ dummy_query = @schema.query_class.new(@schema, "{ __typename }", validate: false, context: context)
28
+ @types = dummy_query.types # rubocop:disable Development/ContextIsPassedCop
36
29
  end
37
30
 
38
31
  def document
@@ -44,9 +37,9 @@ module GraphQL
44
37
  def build_schema_node
45
38
  if !schema_respects_root_name_conventions?(@schema)
46
39
  GraphQL::Language::Nodes::SchemaDefinition.new(
47
- query: (q = warden.root_type_for_operation("query")) && q.graphql_name,
48
- mutation: (m = warden.root_type_for_operation("mutation")) && m.graphql_name,
49
- subscription: (s = warden.root_type_for_operation("subscription")) && s.graphql_name,
40
+ query: @types.query_root&.graphql_name,
41
+ mutation: @types.mutation_root&.graphql_name,
42
+ subscription: @types.subscription_root&.graphql_name,
50
43
  directives: definition_directives(@schema, :schema_directives)
51
44
  )
52
45
  else
@@ -57,7 +50,7 @@ module GraphQL
57
50
  end
58
51
 
59
52
  def build_object_type_node(object_type)
60
- ints = warden.interfaces(object_type)
53
+ ints = @types.interfaces(object_type)
61
54
  if ints.any?
62
55
  ints.sort_by!(&:graphql_name)
63
56
  ints.map! { |iface| build_type_name_node(iface) }
@@ -66,7 +59,7 @@ module GraphQL
66
59
  GraphQL::Language::Nodes::ObjectTypeDefinition.new(
67
60
  name: object_type.graphql_name,
68
61
  interfaces: ints,
69
- fields: build_field_nodes(warden.fields(object_type)),
62
+ fields: build_field_nodes(@types.fields(object_type)),
70
63
  description: object_type.description,
71
64
  directives: directives(object_type),
72
65
  )
@@ -75,7 +68,7 @@ module GraphQL
75
68
  def build_field_node(field)
76
69
  GraphQL::Language::Nodes::FieldDefinition.new(
77
70
  name: field.graphql_name,
78
- arguments: build_argument_nodes(warden.arguments(field)),
71
+ arguments: build_argument_nodes(@types.arguments(field)),
79
72
  type: build_type_name_node(field.type),
80
73
  description: field.description,
81
74
  directives: directives(field),
@@ -86,7 +79,7 @@ module GraphQL
86
79
  GraphQL::Language::Nodes::UnionTypeDefinition.new(
87
80
  name: union_type.graphql_name,
88
81
  description: union_type.description,
89
- types: warden.possible_types(union_type).sort_by(&:graphql_name).map { |type| build_type_name_node(type) },
82
+ types: @types.possible_types(union_type).sort_by(&:graphql_name).map { |type| build_type_name_node(type) },
90
83
  directives: directives(union_type),
91
84
  )
92
85
  end
@@ -94,9 +87,9 @@ module GraphQL
94
87
  def build_interface_type_node(interface_type)
95
88
  GraphQL::Language::Nodes::InterfaceTypeDefinition.new(
96
89
  name: interface_type.graphql_name,
97
- interfaces: warden.interfaces(interface_type).sort_by(&:graphql_name).map { |type| build_type_name_node(type) },
90
+ interfaces: @types.interfaces(interface_type).sort_by(&:graphql_name).map { |type| build_type_name_node(type) },
98
91
  description: interface_type.description,
99
- fields: build_field_nodes(warden.fields(interface_type)),
92
+ fields: build_field_nodes(@types.fields(interface_type)),
100
93
  directives: directives(interface_type),
101
94
  )
102
95
  end
@@ -104,7 +97,7 @@ module GraphQL
104
97
  def build_enum_type_node(enum_type)
105
98
  GraphQL::Language::Nodes::EnumTypeDefinition.new(
106
99
  name: enum_type.graphql_name,
107
- values: warden.enum_values(enum_type).sort_by(&:graphql_name).map do |enum_value|
100
+ values: @types.enum_values(enum_type).sort_by(&:graphql_name).map do |enum_value|
108
101
  build_enum_value_node(enum_value)
109
102
  end,
110
103
  description: enum_type.description,
@@ -149,7 +142,7 @@ module GraphQL
149
142
  def build_input_object_node(input_object)
150
143
  GraphQL::Language::Nodes::InputObjectTypeDefinition.new(
151
144
  name: input_object.graphql_name,
152
- fields: build_argument_nodes(warden.arguments(input_object)),
145
+ fields: build_argument_nodes(@types.arguments(input_object)),
153
146
  description: input_object.description,
154
147
  directives: directives(input_object),
155
148
  )
@@ -159,7 +152,7 @@ module GraphQL
159
152
  GraphQL::Language::Nodes::DirectiveDefinition.new(
160
153
  name: directive.graphql_name,
161
154
  repeatable: directive.repeatable?,
162
- arguments: build_argument_nodes(warden.arguments(directive)),
155
+ arguments: build_argument_nodes(@types.arguments(directive)),
163
156
  locations: build_directive_location_nodes(directive.locations),
164
157
  description: directive.description,
165
158
  )
@@ -204,7 +197,7 @@ module GraphQL
204
197
  when "INPUT_OBJECT"
205
198
  GraphQL::Language::Nodes::InputObject.new(
206
199
  arguments: default_value.to_h.map do |arg_name, arg_value|
207
- args = @warden.arguments(type)
200
+ args = @types.arguments(type)
208
201
  arg = args.find { |a| a.keyword.to_s == arg_name.to_s }
209
202
  if arg.nil?
210
203
  raise ArgumentError, "No argument definition on #{type.graphql_name} for argument: #{arg_name.inspect} (expected one of: #{args.map(&:keyword)})"
@@ -260,13 +253,13 @@ module GraphQL
260
253
  end
261
254
 
262
255
  def build_definition_nodes
263
- dirs_to_build = warden.directives
256
+ dirs_to_build = @types.directives
264
257
  if !include_built_in_directives
265
258
  dirs_to_build = dirs_to_build.reject { |directive| directive.default_directive? }
266
259
  end
267
260
  definitions = build_directive_nodes(dirs_to_build)
268
-
269
- type_nodes = build_type_definition_nodes(warden.reachable_types + schema.extra_types)
261
+ all_types = @types.all_types
262
+ type_nodes = build_type_definition_nodes(all_types + schema.extra_types)
270
263
  if @include_one_of
271
264
  # This may have been set to true when iterating over all types
272
265
  definitions.concat(build_directive_nodes([GraphQL::Schema::Directive::OneOf]))
@@ -351,7 +344,7 @@ module GraphQL
351
344
  dirs
352
345
  end
353
346
 
354
- attr_reader :schema, :warden, :always_include_schema,
347
+ attr_reader :schema, :always_include_schema,
355
348
  :include_introspection_types, :include_built_in_directives, :include_built_in_scalars
356
349
  end
357
350
  end
@@ -345,17 +345,14 @@ module GraphQL
345
345
  def self.tokenize(string)
346
346
  lexer = GraphQL::Language::Lexer.new(string)
347
347
  tokens = []
348
- prev_token = nil
349
348
  while (token_name = lexer.advance)
350
349
  new_token = [
351
350
  token_name,
352
351
  lexer.line_number,
353
352
  lexer.column_number,
354
353
  lexer.debug_token_value(token_name),
355
- prev_token,
356
354
  ]
357
355
  tokens << new_token
358
- prev_token = new_token
359
356
  end
360
357
  tokens
361
358
  end
@@ -113,7 +113,7 @@ module GraphQL
113
113
  end
114
114
 
115
115
  def print_field(field, indent: "")
116
- @current_field = query.get_field(@current_type, field.name)
116
+ @current_field = query.types.field(@current_type, field.name)
117
117
  old_type = @current_type
118
118
  @current_type = @current_field.type.unwrap
119
119
  super
@@ -9,7 +9,6 @@ require "graphql/language/nodes"
9
9
  require "graphql/language/cache"
10
10
  require "graphql/language/parser"
11
11
  require "graphql/language/static_visitor"
12
- require "graphql/language/token"
13
12
  require "graphql/language/visitor"
14
13
  require "graphql/language/definition_slice"
15
14
  require "strscan"
@@ -84,6 +84,10 @@ module GraphQL
84
84
 
85
85
  def_delegators :@query, :trace, :interpreter?
86
86
 
87
+ def types
88
+ @query.types
89
+ end
90
+
87
91
  RUNTIME_METADATA_KEYS = Set.new([:current_object, :current_arguments, :current_field, :current_path])
88
92
  # @!method []=(key, value)
89
93
  # Reassign `key` to the hash passed to {Schema#execute} as `context:`
@@ -30,6 +30,10 @@ module GraphQL
30
30
  def interpreter?
31
31
  true
32
32
  end
33
+
34
+ def types
35
+ @types ||= GraphQL::Schema::Warden::SchemaSubset.new(@warden)
36
+ end
33
37
  end
34
38
  end
35
39
  end
@@ -100,10 +100,10 @@ module GraphQL
100
100
  # Depending on the analysis engine, we must use different analyzers
101
101
  # remove this once everything has switched over to AST analyzers
102
102
  if max_depth
103
- qa << GraphQL::Analysis::AST::MaxQueryDepth
103
+ qa << GraphQL::Analysis::MaxQueryDepth
104
104
  end
105
105
  if max_complexity
106
- qa << GraphQL::Analysis::AST::MaxQueryComplexity
106
+ qa << GraphQL::Analysis::MaxQueryComplexity
107
107
  end
108
108
  qa
109
109
  else
data/lib/graphql/query.rb CHANGED
@@ -95,12 +95,24 @@ module GraphQL
95
95
  # @param root_value [Object] the object used to resolve fields on the root type
96
96
  # @param max_depth [Numeric] the maximum number of nested selections allowed for this query (falls back to schema-level value)
97
97
  # @param max_complexity [Numeric] the maximum field complexity for this query (falls back to schema-level value)
98
- def initialize(schema, query_string = nil, query: nil, document: nil, context: nil, variables: nil, validate: true, static_validator: nil, subscription_topic: nil, operation_name: nil, root_value: nil, max_depth: schema.max_depth, max_complexity: schema.max_complexity, warden: nil)
98
+ def initialize(schema, query_string = nil, query: nil, document: nil, context: nil, variables: nil, validate: true, static_validator: nil, subscription_topic: nil, operation_name: nil, root_value: nil, max_depth: schema.max_depth, max_complexity: schema.max_complexity, warden: nil, use_schema_subset: nil)
99
99
  # Even if `variables: nil` is passed, use an empty hash for simpler logic
100
100
  variables ||= {}
101
101
  @schema = schema
102
102
  @context = schema.context_class.new(query: self, values: context)
103
- @warden = warden
103
+
104
+ if use_schema_subset.nil?
105
+ use_schema_subset = warden ? false : schema.use_schema_subset?
106
+ end
107
+
108
+ if use_schema_subset
109
+ @schema_subset = @schema.subset_class.new(self)
110
+ @warden = Schema::Warden::NullWarden.new(context: self, schema: @schema)
111
+ else
112
+ @schema_subset = nil
113
+ @warden = warden
114
+ end
115
+
104
116
  @subscription_topic = subscription_topic
105
117
  @root_value = root_value
106
118
  @fragments = nil
@@ -195,7 +207,14 @@ module GraphQL
195
207
  def lookahead
196
208
  @lookahead ||= begin
197
209
  ast_node = selected_operation
198
- root_type = warden.root_type_for_operation(ast_node.operation_type || "query")
210
+ root_type = case ast_node.operation_type
211
+ when nil, "query"
212
+ types.query_root # rubocop:disable Development/ContextIsPassedCop
213
+ when "mutation"
214
+ types.mutation_root # rubocop:disable Development/ContextIsPassedCop
215
+ when "subscription"
216
+ types.subscription_root # rubocop:disable Development/ContextIsPassedCop
217
+ end
199
218
  GraphQL::Execution::Lookahead.new(query: self, root_type: root_type, ast_nodes: [ast_node])
200
219
  end
201
220
  end
@@ -330,6 +349,10 @@ module GraphQL
330
349
 
331
350
  def_delegators :warden, :get_type, :get_field, :possible_types, :root_type_for_operation
332
351
 
352
+ def types
353
+ @schema_subset || warden.schema_subset
354
+ end
355
+
333
356
  # @param abstract_type [GraphQL::UnionType, GraphQL::InterfaceType]
334
357
  # @param value [Object] Any runtime value
335
358
  # @return [GraphQL::ObjectType, nil] The runtime type of `value` from {Schema#resolve_type}
@@ -4,6 +4,7 @@ module GraphQL
4
4
  class AlwaysVisible
5
5
  def self.use(schema, **opts)
6
6
  schema.warden_class = GraphQL::Schema::Warden::NullWarden
7
+ schema.subset_class = GraphQL::Schema::Warden::NullWarden::NullSubset
7
8
  end
8
9
  end
9
10
  end
@@ -312,10 +312,15 @@ module GraphQL
312
312
  context.query.after_lazy(custom_loaded_value) do |custom_value|
313
313
  if loads
314
314
  if type.list?
315
- loaded_values = custom_value.each_with_index.map { |custom_val, idx|
316
- id = coerced_value[idx]
317
- load_method_owner.authorize_application_object(self, id, context, custom_val)
318
- }
315
+ loaded_values = []
316
+ context.dataloader.run_isolated do
317
+ custom_value.each_with_index.map { |custom_val, idx|
318
+ id = coerced_value[idx]
319
+ context.dataloader.append_job do
320
+ loaded_values[idx] = load_method_owner.authorize_application_object(self, id, context, custom_val)
321
+ end
322
+ }
323
+ end
319
324
  context.schema.after_any_lazies(loaded_values, &:itself)
320
325
  else
321
326
  load_method_owner.authorize_application_object(self, coerced_value, context, custom_loaded_value)
@@ -326,7 +331,16 @@ module GraphQL
326
331
  end
327
332
  elsif loads
328
333
  if type.list?
329
- loaded_values = coerced_value.map { |val| load_method_owner.load_and_authorize_application_object(self, val, context) }
334
+ loaded_values = []
335
+ # We want to run these list items all together,
336
+ # but we also need to wait for the result so we can return it :S
337
+ context.dataloader.run_isolated do
338
+ coerced_value.each_with_index { |val, idx|
339
+ context.dataloader.append_job do
340
+ loaded_values[idx] = load_method_owner.load_and_authorize_application_object(self, val, context)
341
+ end
342
+ }
343
+ end
330
344
  context.schema.after_any_lazies(loaded_values, &:itself)
331
345
  else
332
346
  load_method_owner.load_and_authorize_application_object(self, coerced_value, context)
@@ -188,6 +188,8 @@ module GraphQL
188
188
  assert_has_location(SCALAR)
189
189
  elsif @owner < GraphQL::Schema
190
190
  assert_has_location(SCHEMA)
191
+ elsif @owner < GraphQL::Schema::Resolver
192
+ assert_has_location(FIELD_DEFINITION)
191
193
  else
192
194
  raise "Unexpected directive owner class: #{@owner}"
193
195
  end
@@ -130,7 +130,7 @@ module GraphQL
130
130
  end
131
131
 
132
132
  def validate_non_null_input(value_name, ctx, max_errors: nil)
133
- allowed_values = ctx.warden.enum_values(self)
133
+ allowed_values = ctx.types.enum_values(self)
134
134
  matching_value = allowed_values.find { |v| v.graphql_name == value_name }
135
135
 
136
136
  if matching_value.nil?
@@ -141,8 +141,8 @@ module GraphQL
141
141
  end
142
142
 
143
143
  def coerce_result(value, ctx)
144
- warden = ctx.warden
145
- all_values = warden ? warden.enum_values(self) : values.each_value
144
+ types = ctx.types
145
+ all_values = types ? types.enum_values(self) : values.each_value
146
146
  enum_value = all_values.find { |val| val.value == value }
147
147
  if enum_value
148
148
  enum_value.graphql_name
@@ -152,7 +152,7 @@ module GraphQL
152
152
  end
153
153
 
154
154
  def coerce_input(value_name, ctx)
155
- all_values = ctx.warden ? ctx.warden.enum_values(self) : values.each_value
155
+ all_values = ctx.types ? ctx.types.enum_values(self) : values.each_value
156
156
 
157
157
  if v = all_values.find { |val| val.graphql_name == value_name }
158
158
  v.value
@@ -41,6 +41,18 @@ module GraphQL
41
41
  end
42
42
  end
43
43
 
44
+ def directives
45
+ if @resolver_class && (r_dirs = @resolver_class.directives).any?
46
+ if (own_dirs = super).any?
47
+ own_dirs + r_dirs
48
+ else
49
+ r_dirs
50
+ end
51
+ else
52
+ super
53
+ end
54
+ end
55
+
44
56
  # @return [Class] The thing this field was defined on (type, mutation, resolver)
45
57
  attr_accessor :owner
46
58
 
@@ -606,7 +618,7 @@ module GraphQL
606
618
  using_arg_values = false
607
619
  end
608
620
 
609
- args = context.warden.arguments(self)
621
+ args = context.types.arguments(self)
610
622
  args.each do |arg|
611
623
  arg_key = arg.keyword
612
624
  if arg_values.key?(arg_key)
@@ -149,7 +149,8 @@ module GraphQL
149
149
 
150
150
  def authorize_arguments(args, values)
151
151
  # remove the `input` wrapper to match values
152
- input_args = args["input"].type.unwrap.arguments(context)
152
+ input_type = args.find { |a| a.graphql_name == "input" }.type.unwrap
153
+ input_args = context.types.arguments(input_type)
153
154
  super(input_args, values)
154
155
  end
155
156
  end
@@ -23,7 +23,8 @@ module GraphQL
23
23
  @ruby_style_hash = ruby_kwargs
24
24
  @arguments = arguments
25
25
  # Apply prepares, not great to have it duplicated here.
26
- self.class.arguments(context).each_value do |arg_defn|
26
+ arg_defns = context ? context.types.arguments(self.class) : self.class.arguments(context).each_value
27
+ arg_defns.each do |arg_defn|
27
28
  ruby_kwargs_key = arg_defn.keyword
28
29
  if @ruby_style_hash.key?(ruby_kwargs_key)
29
30
  # Weirdly, procs are applied during coercion, but not methods.
@@ -58,7 +59,7 @@ module GraphQL
58
59
  def self.authorized?(obj, value, ctx)
59
60
  # Authorize each argument (but this doesn't apply if `prepare` is implemented):
60
61
  if value.respond_to?(:key?)
61
- arguments(ctx).each do |_name, input_obj_arg|
62
+ ctx.types.arguments(self).each do |input_obj_arg|
62
63
  if value.key?(input_obj_arg.keyword) &&
63
64
  !input_obj_arg.authorized?(obj, value[input_obj_arg.keyword], ctx)
64
65
  return false
@@ -149,7 +150,7 @@ module GraphQL
149
150
  INVALID_OBJECT_MESSAGE = "Expected %{object} to be a key-value object."
150
151
 
151
152
  def validate_non_null_input(input, ctx, max_errors: nil)
152
- warden = ctx.warden
153
+ types = ctx.types
153
154
 
154
155
  if input.is_a?(Array)
155
156
  return GraphQL::Query::InputValidationResult.from_problem(INVALID_OBJECT_MESSAGE % { object: JSON.generate(input, quirks_mode: true) })
@@ -161,9 +162,9 @@ module GraphQL
161
162
  end
162
163
 
163
164
  # Inject missing required arguments
164
- missing_required_inputs = self.arguments(ctx).reduce({}) do |m, (argument_name, argument)|
165
- if !input.key?(argument_name) && argument.type.non_null? && warden.get_argument(self, argument_name)
166
- m[argument_name] = nil
165
+ missing_required_inputs = ctx.types.arguments(self).reduce({}) do |m, (argument)|
166
+ if !input.key?(argument.graphql_name) && argument.type.non_null? && types.argument(self, argument.graphql_name)
167
+ m[argument.graphql_name] = nil
167
168
  end
168
169
 
169
170
  m
@@ -172,7 +173,7 @@ module GraphQL
172
173
  result = nil
173
174
  [input, missing_required_inputs].each do |args_to_validate|
174
175
  args_to_validate.each do |argument_name, value|
175
- argument = warden.get_argument(self, argument_name)
176
+ argument = types.argument(self, argument_name)
176
177
  # Items in the input that are unexpected
177
178
  if argument.nil?
178
179
  result ||= Query::InputValidationResult.new
@@ -69,7 +69,7 @@ module GraphQL
69
69
  def resolve_late_bindings
70
70
  @types.each do |name, t|
71
71
  if t.kind.fields?
72
- t.fields.each do |_name, field_defn|
72
+ t.all_field_definitions.each do |field_defn|
73
73
  field_defn.type = resolve_late_binding(field_defn.type)
74
74
  end
75
75
  end
@@ -113,19 +113,7 @@ module GraphQL
113
113
 
114
114
  def get_fields_from_class(class_sym:)
115
115
  object_type_defn = load_constant(class_sym)
116
-
117
- if object_type_defn.is_a?(Module)
118
- object_type_defn.fields
119
- else
120
- extracted_field_defns = {}
121
- object_class = object_type_defn.metadata[:type_class]
122
- object_type_defn.all_fields.each do |field_defn|
123
- inner_resolve = field_defn.resolve_proc
124
- resolve_with_instantiate = PerFieldProxyResolve.new(object_class: object_class, inner_resolve: inner_resolve)
125
- extracted_field_defns[field_defn.name] = field_defn.redefine(resolve: resolve_with_instantiate)
126
- end
127
- extracted_field_defns
128
- end
116
+ object_type_defn.fields
129
117
  end
130
118
 
131
119
  # This is probably not 100% robust -- but it has to be good enough to avoid modifying the built-in introspection types
@@ -135,10 +135,11 @@ module GraphQL
135
135
 
136
136
  def get_argument(argument_name, context = GraphQL::Query::NullContext.instance)
137
137
  warden = Warden.from_context(context)
138
+ skip_visible = context.respond_to?(:types) && context.types.is_a?(GraphQL::Schema::Subset)
138
139
  for ancestor in ancestors
139
140
  if ancestor.respond_to?(:own_arguments) &&
140
141
  (a = ancestor.own_arguments[argument_name]) &&
141
- (a = Warden.visible_entry?(:visible_argument?, a, context, warden))
142
+ (skip_visible || (a = Warden.visible_entry?(:visible_argument?, a, context, warden)))
142
143
  return a
143
144
  end
144
145
  end
@@ -205,8 +206,8 @@ module GraphQL
205
206
  # @return [GraphQL::Schema::Argument, nil] Argument defined on this thing, fetched by name.
206
207
  def get_argument(argument_name, context = GraphQL::Query::NullContext.instance)
207
208
  warden = Warden.from_context(context)
208
- if (arg_config = own_arguments[argument_name]) && (visible_arg = Warden.visible_entry?(:visible_argument?, arg_config, context, warden))
209
- visible_arg
209
+ if (arg_config = own_arguments[argument_name]) && ((context.respond_to?(:types) && context.types.is_a?(GraphQL::Schema::Subset)) || (visible_arg = Warden.visible_entry?(:visible_argument?, arg_config, context, warden)))
210
+ visible_arg || arg_config
210
211
  elsif defined?(@resolver_class) && @resolver_class
211
212
  @resolver_class.get_field_argument(argument_name, context)
212
213
  else
@@ -230,7 +231,7 @@ module GraphQL
230
231
  # @return [Interpreter::Arguments, Execution::Lazy<Interpreter::Arguments>]
231
232
  def coerce_arguments(parent_object, values, context, &block)
232
233
  # Cache this hash to avoid re-merging it
233
- arg_defns = context.warden.arguments(self)
234
+ arg_defns = context.types.arguments(self)
234
235
  total_args_count = arg_defns.size
235
236
 
236
237
  finished_args = nil
@@ -364,8 +365,8 @@ module GraphQL
364
365
  end
365
366
 
366
367
  if !(
367
- context.warden.possible_types(argument.loads).include?(application_object_type) ||
368
- context.warden.loadable?(argument.loads, context)
368
+ context.types.possible_types(argument.loads).include?(application_object_type) ||
369
+ context.types.loadable?(argument.loads, context)
369
370
  )
370
371
  err = GraphQL::LoadApplicationObjectFailedError.new(context: context, argument: argument, id: id, object: application_object)
371
372
  application_object = load_application_object_failed(err)
@@ -99,11 +99,12 @@ module GraphQL
99
99
  module InterfaceMethods
100
100
  def get_field(field_name, context = GraphQL::Query::NullContext.instance)
101
101
  warden = Warden.from_context(context)
102
+ skip_visible = context.respond_to?(:types) && context.types.is_a?(GraphQL::Schema::Subset)
102
103
  for ancestor in ancestors
103
104
  if ancestor.respond_to?(:own_fields) &&
104
105
  (f_entry = ancestor.own_fields[field_name]) &&
105
- (f = Warden.visible_entry?(:visible_field?, f_entry, context, warden))
106
- return f
106
+ (skip_visible || (f_entry = Warden.visible_entry?(:visible_field?, f_entry, context, warden)))
107
+ return f_entry
107
108
  end
108
109
  end
109
110
  nil
@@ -134,13 +135,14 @@ module GraphQL
134
135
  # Objects need to check that the interface implementation is visible, too
135
136
  warden = Warden.from_context(context)
136
137
  ancs = ancestors
138
+ skip_visible = context.respond_to?(:types) && context.types.is_a?(GraphQL::Schema::Subset)
137
139
  i = 0
138
140
  while (ancestor = ancs[i])
139
141
  if ancestor.respond_to?(:own_fields) &&
140
142
  visible_interface_implementation?(ancestor, context, warden) &&
141
143
  (f_entry = ancestor.own_fields[field_name]) &&
142
- (f = Warden.visible_entry?(:visible_field?, f_entry, context, warden))
143
- return f
144
+ (skip_visible || (f_entry = Warden.visible_entry?(:visible_field?, f_entry, context, warden)))
145
+ return f_entry
144
146
  end
145
147
  i += 1
146
148
  end
@@ -25,6 +25,7 @@ module GraphQL
25
25
  extend GraphQL::Schema::Member::HasValidators
26
26
  include Schema::Member::HasPath
27
27
  extend Schema::Member::HasPath
28
+ extend Schema::Member::HasDirectives
28
29
 
29
30
  # @param object [Object] The application object that this field is being resolved on
30
31
  # @param context [GraphQL::Query::Context]
@@ -35,7 +36,7 @@ module GraphQL
35
36
  @field = field
36
37
  # Since this hash is constantly rebuilt, cache it for this call
37
38
  @arguments_by_keyword = {}
38
- self.class.arguments(context).each do |name, arg|
39
+ context.types.arguments(self.class).each do |arg|
39
40
  @arguments_by_keyword[arg.keyword] = arg
40
41
  end
41
42
  @prepared_arguments = nil
@@ -151,7 +152,7 @@ module GraphQL
151
152
  # @return [Boolean, early_return_data] If `false`, execution will stop (and `early_return_data` will be returned instead, if present.)
152
153
  def authorized?(**inputs)
153
154
  arg_owner = @field # || self.class
154
- args = arg_owner.arguments(context)
155
+ args = context.types.arguments(arg_owner)
155
156
  authorize_arguments(args, inputs)
156
157
  end
157
158
 
@@ -168,7 +169,7 @@ module GraphQL
168
169
  private
169
170
 
170
171
  def authorize_arguments(args, inputs)
171
- args.each_value do |argument|
172
+ args.each do |argument|
172
173
  arg_keyword = argument.keyword
173
174
  if inputs.key?(arg_keyword) && !(arg_value = inputs[arg_keyword]).nil? && (arg_value != argument.default_value)
174
175
  auth_result = argument.authorized?(self, arg_value, context)
@@ -181,10 +182,9 @@ module GraphQL
181
182
  elsif auth_result == false
182
183
  return auth_result
183
184
  end
184
- else
185
- true
186
185
  end
187
186
  end
187
+ true
188
188
  end
189
189
 
190
190
  def load_arguments(args)