graphql 2.3.5 → 2.3.11

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 (94) hide show
  1. checksums.yaml +4 -4
  2. data/lib/generators/graphql/install_generator.rb +46 -0
  3. data/lib/graphql/analysis/analyzer.rb +89 -0
  4. data/lib/graphql/analysis/field_usage.rb +82 -0
  5. data/lib/graphql/analysis/max_query_complexity.rb +20 -0
  6. data/lib/graphql/analysis/max_query_depth.rb +20 -0
  7. data/lib/graphql/analysis/query_complexity.rb +183 -0
  8. data/lib/graphql/analysis/{ast/query_depth.rb → query_depth.rb} +23 -25
  9. data/lib/graphql/analysis/visitor.rb +283 -0
  10. data/lib/graphql/analysis.rb +92 -1
  11. data/lib/graphql/current.rb +52 -0
  12. data/lib/graphql/dataloader/async_dataloader.rb +2 -0
  13. data/lib/graphql/dataloader/source.rb +5 -2
  14. data/lib/graphql/dataloader.rb +4 -1
  15. data/lib/graphql/execution/interpreter/arguments_cache.rb +5 -10
  16. data/lib/graphql/execution/interpreter/runtime.rb +8 -14
  17. data/lib/graphql/execution/interpreter.rb +3 -1
  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/language/document_from_schema_definition.rb +19 -26
  25. data/lib/graphql/language/lexer.rb +0 -3
  26. data/lib/graphql/language/nodes.rb +2 -2
  27. data/lib/graphql/language/parser.rb +9 -1
  28. data/lib/graphql/language/sanitized_printer.rb +1 -1
  29. data/lib/graphql/language.rb +0 -1
  30. data/lib/graphql/query/context.rb +7 -1
  31. data/lib/graphql/query/null_context.rb +2 -2
  32. data/lib/graphql/query/validation_pipeline.rb +2 -2
  33. data/lib/graphql/query.rb +26 -7
  34. data/lib/graphql/schema/always_visible.rb +1 -0
  35. data/lib/graphql/schema/argument.rb +19 -5
  36. data/lib/graphql/schema/build_from_definition.rb +8 -1
  37. data/lib/graphql/schema/directive/flagged.rb +1 -1
  38. data/lib/graphql/schema/directive.rb +2 -0
  39. data/lib/graphql/schema/enum.rb +9 -5
  40. data/lib/graphql/schema/field/connection_extension.rb +1 -1
  41. data/lib/graphql/schema/field.rb +13 -1
  42. data/lib/graphql/schema/has_single_input_argument.rb +2 -1
  43. data/lib/graphql/schema/input_object.rb +8 -7
  44. data/lib/graphql/schema/interface.rb +20 -4
  45. data/lib/graphql/schema/introspection_system.rb +5 -16
  46. data/lib/graphql/schema/member/has_arguments.rb +14 -9
  47. data/lib/graphql/schema/member/has_fields.rb +6 -4
  48. data/lib/graphql/schema/member/has_unresolved_type_error.rb +5 -1
  49. data/lib/graphql/schema/resolver.rb +5 -5
  50. data/lib/graphql/schema/subset.rb +510 -0
  51. data/lib/graphql/schema/type_expression.rb +2 -2
  52. data/lib/graphql/schema/types_migration.rb +185 -0
  53. data/lib/graphql/schema/validator/all_validator.rb +60 -0
  54. data/lib/graphql/schema/validator.rb +2 -0
  55. data/lib/graphql/schema/warden.rb +89 -5
  56. data/lib/graphql/schema.rb +74 -37
  57. data/lib/graphql/static_validation/base_visitor.rb +6 -5
  58. data/lib/graphql/static_validation/literal_validator.rb +4 -4
  59. data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +1 -1
  60. data/lib/graphql/static_validation/rules/arguments_are_defined.rb +1 -1
  61. data/lib/graphql/static_validation/rules/directives_are_defined.rb +1 -2
  62. data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +1 -1
  63. data/lib/graphql/static_validation/rules/fields_will_merge.rb +7 -7
  64. data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +3 -3
  65. data/lib/graphql/static_validation/rules/fragment_types_exist.rb +1 -1
  66. data/lib/graphql/static_validation/rules/fragments_are_on_composite_types.rb +1 -1
  67. data/lib/graphql/static_validation/rules/mutation_root_exists.rb +1 -1
  68. data/lib/graphql/static_validation/rules/query_root_exists.rb +1 -1
  69. data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +3 -3
  70. data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +3 -3
  71. data/lib/graphql/static_validation/rules/subscription_root_exists.rb +1 -1
  72. data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +18 -27
  73. data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +1 -1
  74. data/lib/graphql/static_validation/rules/variables_are_input_types.rb +1 -1
  75. data/lib/graphql/static_validation/validation_context.rb +2 -2
  76. data/lib/graphql/subscriptions/broadcast_analyzer.rb +11 -5
  77. data/lib/graphql/subscriptions/event.rb +1 -1
  78. data/lib/graphql/subscriptions.rb +3 -3
  79. data/lib/graphql/testing/helpers.rb +8 -5
  80. data/lib/graphql/types/relay/connection_behaviors.rb +10 -0
  81. data/lib/graphql/types/relay/edge_behaviors.rb +10 -0
  82. data/lib/graphql/types/relay/page_info_behaviors.rb +4 -0
  83. data/lib/graphql/version.rb +1 -1
  84. data/lib/graphql.rb +1 -0
  85. metadata +14 -13
  86. data/lib/graphql/analysis/ast/analyzer.rb +0 -91
  87. data/lib/graphql/analysis/ast/field_usage.rb +0 -84
  88. data/lib/graphql/analysis/ast/max_query_complexity.rb +0 -22
  89. data/lib/graphql/analysis/ast/max_query_depth.rb +0 -22
  90. data/lib/graphql/analysis/ast/query_complexity.rb +0 -185
  91. data/lib/graphql/analysis/ast/visitor.rb +0 -284
  92. data/lib/graphql/analysis/ast.rb +0 -94
  93. data/lib/graphql/language/token.rb +0 -34
  94. data/lib/graphql/schema/invalid_type_error.rb +0 -7
@@ -19,7 +19,7 @@ module GraphQL
19
19
  end
20
20
 
21
21
  def args(include_deprecated:)
22
- args = @context.warden.arguments(@object)
22
+ args = @context.types.arguments(@object)
23
23
  args = args.reject(&:deprecation_reason) unless include_deprecated
24
24
  args
25
25
  end
@@ -20,31 +20,26 @@ module GraphQL
20
20
  end
21
21
 
22
22
  def types
23
- types = context.warden.reachable_types + context.schema.extra_types
23
+ query_types = context.types.all_types
24
+ types = query_types + context.schema.extra_types
24
25
  types.sort_by!(&:graphql_name)
25
26
  types
26
27
  end
27
28
 
28
29
  def query_type
29
- permitted_root_type("query")
30
+ @context.types.query_root
30
31
  end
31
32
 
32
33
  def mutation_type
33
- permitted_root_type("mutation")
34
+ @context.types.mutation_root
34
35
  end
35
36
 
36
37
  def subscription_type
37
- permitted_root_type("subscription")
38
+ @context.types.subscription_root
38
39
  end
39
40
 
40
41
  def directives
41
- @context.warden.directives
42
- end
43
-
44
- private
45
-
46
- def permitted_root_type(op_type)
47
- @context.warden.root_type_for_operation(op_type)
42
+ @context.types.directives.sort_by(&:graphql_name)
48
43
  end
49
44
  end
50
45
  end
@@ -52,7 +52,7 @@ module GraphQL
52
52
  if !@object.kind.enum?
53
53
  nil
54
54
  else
55
- enum_values = @context.warden.enum_values(@object)
55
+ enum_values = @context.types.enum_values(@object)
56
56
 
57
57
  if !include_deprecated
58
58
  enum_values = enum_values.select {|f| !f.deprecation_reason }
@@ -64,7 +64,7 @@ module GraphQL
64
64
 
65
65
  def interfaces
66
66
  if @object.kind.object? || @object.kind.interface?
67
- @context.warden.interfaces(@object).sort_by(&:graphql_name)
67
+ @context.types.interfaces(@object).sort_by(&:graphql_name)
68
68
  else
69
69
  nil
70
70
  end
@@ -72,7 +72,7 @@ module GraphQL
72
72
 
73
73
  def input_fields(include_deprecated:)
74
74
  if @object.kind.input_object?
75
- args = @context.warden.arguments(@object)
75
+ args = @context.types.arguments(@object)
76
76
  args = args.reject(&:deprecation_reason) unless include_deprecated
77
77
  args
78
78
  else
@@ -82,7 +82,7 @@ module GraphQL
82
82
 
83
83
  def possible_types
84
84
  if @object.kind.abstract?
85
- @context.warden.possible_types(@object).sort_by(&:graphql_name)
85
+ @context.types.possible_types(@object).sort_by(&:graphql_name)
86
86
  else
87
87
  nil
88
88
  end
@@ -92,7 +92,7 @@ module GraphQL
92
92
  if !@object.kind.fields?
93
93
  nil
94
94
  else
95
- fields = @context.warden.fields(@object)
95
+ fields = @context.types.fields(@object)
96
96
  if !include_deprecated
97
97
  fields = fields.select {|f| !f.deprecation_reason }
98
98
  end
@@ -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
@@ -34,11 +34,11 @@ module GraphQL
34
34
  attr_reader :filename
35
35
 
36
36
  def line
37
- @line ||= @source.line_at(@pos)
37
+ @line ||= @source&.line_at(@pos)
38
38
  end
39
39
 
40
40
  def col
41
- @col ||= @source.column_at(@pos)
41
+ @col ||= @source&.column_at(@pos)
42
42
  end
43
43
 
44
44
  def definition_line
@@ -141,7 +141,12 @@ module GraphQL
141
141
  parse_operation_type
142
142
  end
143
143
 
144
- op_name = at?(:IDENTIFIER) ? parse_name : nil
144
+ op_name = case token_name
145
+ when :LPAREN, :LCURLY, :DIR_SIGN
146
+ nil
147
+ else
148
+ parse_name
149
+ end
145
150
 
146
151
  variable_definitions = if at?(:LPAREN)
147
152
  expect_token(:LPAREN)
@@ -398,6 +403,9 @@ module GraphQL
398
403
  def parse_union_members
399
404
  if at?(:EQUALS)
400
405
  expect_token :EQUALS
406
+ if at?(:PIPE)
407
+ advance_token
408
+ end
401
409
  list = [parse_type_name]
402
410
  while at?(:PIPE)
403
411
  advance_token
@@ -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"
@@ -82,7 +82,13 @@ module GraphQL
82
82
  @provided_values[key] = value
83
83
  end
84
84
 
85
- def_delegators :@query, :trace, :interpreter?
85
+ def_delegators :@query, :trace
86
+
87
+ def types
88
+ @types ||= @query.types
89
+ end
90
+
91
+ attr_writer :types
86
92
 
87
93
  RUNTIME_METADATA_KEYS = Set.new([:current_object, :current_arguments, :current_field, :current_path])
88
94
  # @!method []=(key, value)
@@ -27,8 +27,8 @@ module GraphQL
27
27
  @warden = Schema::Warden::NullWarden.new(context: self, schema: @schema)
28
28
  end
29
29
 
30
- def interpreter?
31
- true
30
+ def types
31
+ @types ||= GraphQL::Schema::Warden::SchemaSubset.new(@warden)
32
32
  end
33
33
  end
34
34
  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(context: @context, schema: @schema)
110
+ @warden = Schema::Warden::NullWarden.new(context: @context, 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
@@ -175,10 +187,6 @@ module GraphQL
175
187
  @query_string ||= (document ? document.to_query_string : nil)
176
188
  end
177
189
 
178
- def interpreter?
179
- true
180
- end
181
-
182
190
  attr_accessor :multiplex
183
191
 
184
192
  # @return [GraphQL::Tracing::Trace]
@@ -195,7 +203,14 @@ module GraphQL
195
203
  def lookahead
196
204
  @lookahead ||= begin
197
205
  ast_node = selected_operation
198
- root_type = warden.root_type_for_operation(ast_node.operation_type || "query")
206
+ root_type = case ast_node.operation_type
207
+ when nil, "query"
208
+ types.query_root # rubocop:disable Development/ContextIsPassedCop
209
+ when "mutation"
210
+ types.mutation_root # rubocop:disable Development/ContextIsPassedCop
211
+ when "subscription"
212
+ types.subscription_root # rubocop:disable Development/ContextIsPassedCop
213
+ end
199
214
  GraphQL::Execution::Lookahead.new(query: self, root_type: root_type, ast_nodes: [ast_node])
200
215
  end
201
216
  end
@@ -330,6 +345,10 @@ module GraphQL
330
345
 
331
346
  def_delegators :warden, :get_type, :get_field, :possible_types, :root_type_for_operation
332
347
 
348
+ def types
349
+ @schema_subset || warden.schema_subset
350
+ end
351
+
333
352
  # @param abstract_type [GraphQL::UnionType, GraphQL::InterfaceType]
334
353
  # @param value [Object] Any runtime value
335
354
  # @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)
@@ -127,11 +127,12 @@ module GraphQL
127
127
  builder = self
128
128
 
129
129
  found_types = types.values
130
+ object_types = found_types.select { |t| t.respond_to?(:kind) && t.kind.object? }
130
131
  schema_class = Class.new(schema_superclass) do
131
132
  begin
132
133
  # Add these first so that there's some chance of resolving late-bound types
133
134
  add_type_and_traverse(found_types, root: false)
134
- orphan_types(found_types.select { |t| t.respond_to?(:kind) && t.kind.object? })
135
+ orphan_types(object_types)
135
136
  query query_root_type
136
137
  mutation mutation_root_type
137
138
  subscription subscription_root_type
@@ -141,6 +142,12 @@ module GraphQL
141
142
  raise InvalidDocumentError, "Type \"#{type_name}\" not found in document.", err_backtrace
142
143
  end
143
144
 
145
+ object_types.each do |t|
146
+ t.interfaces.each do |int_t|
147
+ int_t.orphan_types(t)
148
+ end
149
+ end
150
+
144
151
  if default_resolve.respond_to?(:resolve_type)
145
152
  def self.resolve_type(*args)
146
153
  self.definition_default_resolve.resolve_type(*args)
@@ -7,7 +7,7 @@ module GraphQL
7
7
  # In this case, the server hides types and fields _entirely_, unless the current context has certain `:flags` present.
8
8
  class Flagged < GraphQL::Schema::Directive
9
9
  def initialize(target, **options)
10
- if target.is_a?(Module) && !target.ancestors.include?(VisibleByFlag)
10
+ if target.is_a?(Module)
11
11
  # This is type class of some kind, `include` will put this module
12
12
  # in between the type class itself and its super class, so `super` will work fine
13
13
  target.include(VisibleByFlag)
@@ -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
@@ -166,7 +166,11 @@ module GraphQL
166
166
  end
167
167
 
168
168
  def inherited(child_class)
169
- child_class.const_set(:UnresolvedValueError, Class.new(Schema::Enum::UnresolvedValueError))
169
+ if child_class.name
170
+ # Don't assign a custom error class to anonymous classes
171
+ # because they would end up with names like `#<Class0x1234>::UnresolvedValueError` which messes up bug trackers
172
+ child_class.const_set(:UnresolvedValueError, Class.new(Schema::Enum::UnresolvedValueError))
173
+ end
170
174
  super
171
175
  end
172
176
 
@@ -50,7 +50,7 @@ module GraphQL
50
50
  if field.has_default_page_size? && !value.has_default_page_size_override?
51
51
  value.default_page_size = field.default_page_size
52
52
  end
53
- if context.schema.new_connections? && (custom_t = context.schema.connections.edge_class_for_field(@field))
53
+ if (custom_t = context.schema.connections.edge_class_for_field(@field))
54
54
  value.edge_class = custom_t
55
55
  end
56
56
  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