graphql 2.0.16 → 2.0.17.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (33) hide show
  1. checksums.yaml +4 -4
  2. data/lib/graphql/analysis/ast/visitor.rb +42 -35
  3. data/lib/graphql/execution/interpreter/runtime.rb +14 -4
  4. data/lib/graphql/execution/interpreter.rb +10 -0
  5. data/lib/graphql/execution/lazy.rb +4 -8
  6. data/lib/graphql/introspection/directive_type.rb +2 -2
  7. data/lib/graphql/introspection/field_type.rb +1 -1
  8. data/lib/graphql/introspection/schema_type.rb +2 -2
  9. data/lib/graphql/introspection/type_type.rb +5 -5
  10. data/lib/graphql/language/nodes.rb +39 -31
  11. data/lib/graphql/language/visitor.rb +191 -83
  12. data/lib/graphql/schema/argument.rb +0 -4
  13. data/lib/graphql/schema/directive.rb +12 -2
  14. data/lib/graphql/schema/enum.rb +24 -17
  15. data/lib/graphql/schema/enum_value.rb +5 -3
  16. data/lib/graphql/schema/field.rb +24 -26
  17. data/lib/graphql/schema/interface.rb +0 -10
  18. data/lib/graphql/schema/late_bound_type.rb +2 -0
  19. data/lib/graphql/schema/member/base_dsl_methods.rb +15 -14
  20. data/lib/graphql/schema/member/has_arguments.rb +104 -57
  21. data/lib/graphql/schema/member/has_fields.rb +8 -1
  22. data/lib/graphql/schema/member/has_interfaces.rb +49 -8
  23. data/lib/graphql/schema/member/has_validators.rb +31 -5
  24. data/lib/graphql/schema/member/type_system_helpers.rb +17 -0
  25. data/lib/graphql/schema/warden.rb +18 -3
  26. data/lib/graphql/schema.rb +3 -19
  27. data/lib/graphql/static_validation/literal_validator.rb +15 -1
  28. data/lib/graphql/subscriptions/event.rb +2 -7
  29. data/lib/graphql/types/relay/connection_behaviors.rb +0 -4
  30. data/lib/graphql/types/relay/edge_behaviors.rb +0 -4
  31. data/lib/graphql/types/string.rb +1 -1
  32. data/lib/graphql/version.rb +1 -1
  33. metadata +3 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d626d72a5ae0bfb10f8fcdb9cbd781f04b5bb38b3f90b20de062a78679c254a8
4
- data.tar.gz: 6793ba627f3f59a43426258e187567f391a44f8973816fb0b1e1eb7784ae19b0
3
+ metadata.gz: 533ea1a2fb1db8e861f4c227c3b580a12952ee08006675a2132856091971b821
4
+ data.tar.gz: 167f7d8de465ff655a1e5a14c159ad06347420f46954384075214b928ae145ac
5
5
  SHA512:
6
- metadata.gz: 5958721b08e45d886036f8afe0a5942e443117d9aa71d94450b727ec20d13b63a945a97c247f8605d4eb1ae8631ba301599e95b938355f18dc7c5bf64e2b1b44
7
- data.tar.gz: 9d029e7d0288c87cc9c09e627538b5e93b3d1ec7e785914b135088ec7bafcf8172458fa1d68a95a6385786d472c7260f6bc82b719e86743b5dac1f2a87501f7c
6
+ metadata.gz: c2b17a7bf459e836eee80146ccfbbec12e86c3dd795570fe632649946fb799a58708e006377a81097af980db6add831a453cd9a6c3aeb8df7c506cb04cb93fa8
7
+ data.tar.gz: bb033a2d03d99488522e7f829bfd0914eae993f4abc0a0e2fa251380e338733767fb0d4bc4cde15298714f3c48bd900f050b98d98faef7587a68029d5b9d30ab
@@ -65,14 +65,41 @@ module GraphQL
65
65
  end
66
66
 
67
67
  # Visitor Hooks
68
+ [
69
+ :operation_definition, :fragment_definition,
70
+ :inline_fragment, :field, :directive, :argument, :fragment_spread
71
+ ].each do |node_type|
72
+ module_eval <<-RUBY, __FILE__, __LINE__
73
+ def call_on_enter_#{node_type}(node, parent)
74
+ @analyzers.each do |a|
75
+ begin
76
+ a.on_enter_#{node_type}(node, parent, self)
77
+ rescue AnalysisError => err
78
+ @rescued_errors << err
79
+ end
80
+ end
81
+ end
82
+
83
+ def call_on_leave_#{node_type}(node, parent)
84
+ @analyzers.each do |a|
85
+ begin
86
+ a.on_leave_#{node_type}(node, parent, self)
87
+ rescue AnalysisError => err
88
+ @rescued_errors << err
89
+ end
90
+ end
91
+ end
92
+
93
+ RUBY
94
+ end
68
95
 
69
96
  def on_operation_definition(node, parent)
70
97
  object_type = @schema.root_type_for_operation(node.operation_type)
71
98
  @object_types.push(object_type)
72
99
  @path.push("#{node.operation_type}#{node.name ? " #{node.name}" : ""}")
73
- call_analyzers(:on_enter_operation_definition, node, parent)
100
+ call_on_enter_operation_definition(node, parent)
74
101
  super
75
- call_analyzers(:on_leave_operation_definition, node, parent)
102
+ call_on_leave_operation_definition(node, parent)
76
103
  @object_types.pop
77
104
  @path.pop
78
105
  end
@@ -81,19 +108,19 @@ module GraphQL
81
108
  on_fragment_with_type(node) do
82
109
  @path.push("fragment #{node.name}")
83
110
  @in_fragment_def = false
84
- call_analyzers(:on_enter_fragment_definition, node, parent)
111
+ call_on_enter_fragment_definition(node, parent)
85
112
  super
86
113
  @in_fragment_def = false
87
- call_analyzers(:on_leave_fragment_definition, node, parent)
114
+ call_on_leave_fragment_definition(node, parent)
88
115
  end
89
116
  end
90
117
 
91
118
  def on_inline_fragment(node, parent)
92
119
  on_fragment_with_type(node) do
93
120
  @path.push("...#{node.type ? " on #{node.type.name}" : ""}")
94
- call_analyzers(:on_enter_inline_fragment, node, parent)
121
+ call_on_enter_inline_fragment(node, parent)
95
122
  super
96
- call_analyzers(:on_leave_inline_fragment, node, parent)
123
+ call_on_leave_inline_fragment(node, parent)
97
124
  end
98
125
  end
99
126
 
@@ -114,12 +141,10 @@ module GraphQL
114
141
  @skipping = @skip_stack.last || skip?(node)
115
142
  @skip_stack << @skipping
116
143
 
117
- call_analyzers(:on_enter_field, node, parent)
144
+ call_on_enter_field(node, parent)
118
145
  super
119
-
120
146
  @skipping = @skip_stack.pop
121
-
122
- call_analyzers(:on_leave_field, node, parent)
147
+ call_on_leave_field(node, parent)
123
148
  @response_path.pop
124
149
  @field_definitions.pop
125
150
  @object_types.pop
@@ -129,9 +154,9 @@ module GraphQL
129
154
  def on_directive(node, parent)
130
155
  directive_defn = @schema.directives[node.name]
131
156
  @directive_definitions.push(directive_defn)
132
- call_analyzers(:on_enter_directive, node, parent)
157
+ call_on_enter_directive(node, parent)
133
158
  super
134
- call_analyzers(:on_leave_directive, node, parent)
159
+ call_on_leave_directive(node, parent)
135
160
  @directive_definitions.pop
136
161
  end
137
162
 
@@ -153,29 +178,23 @@ module GraphQL
153
178
 
154
179
  @argument_definitions.push(argument_defn)
155
180
  @path.push(node.name)
156
- call_analyzers(:on_enter_argument, node, parent)
181
+ call_on_enter_argument(node, parent)
157
182
  super
158
- call_analyzers(:on_leave_argument, node, parent)
183
+ call_on_leave_argument(node, parent)
159
184
  @argument_definitions.pop
160
185
  @path.pop
161
186
  end
162
187
 
163
188
  def on_fragment_spread(node, parent)
164
189
  @path.push("... #{node.name}")
165
- call_analyzers(:on_enter_fragment_spread, node, parent)
190
+ call_on_enter_fragment_spread(node, parent)
166
191
  enter_fragment_spread_inline(node)
167
192
  super
168
193
  leave_fragment_spread_inline(node)
169
- call_analyzers(:on_leave_fragment_spread, node, parent)
194
+ call_on_leave_fragment_spread(node, parent)
170
195
  @path.pop
171
196
  end
172
197
 
173
- def on_abstract_node(node, parent)
174
- call_analyzers(:on_enter_abstract_node, node, parent)
175
- super
176
- call_analyzers(:on_leave_abstract_node, node, parent)
177
- end
178
-
179
198
  # @return [GraphQL::BaseType] The current object type
180
199
  def type_definition
181
200
  @object_types.last
@@ -226,9 +245,7 @@ module GraphQL
226
245
 
227
246
  object_types << object_type
228
247
 
229
- fragment_def.selections.each do |selection|
230
- visit_node(selection, fragment_def)
231
- end
248
+ on_fragment_definition_children(fragment_def)
232
249
  end
233
250
 
234
251
  # Visit a fragment spread inline instead of visiting the definition
@@ -242,16 +259,6 @@ module GraphQL
242
259
  dir.any? && !GraphQL::Execution::DirectiveChecks.include?(dir, query)
243
260
  end
244
261
 
245
- def call_analyzers(method, node, parent)
246
- @analyzers.each do |analyzer|
247
- begin
248
- analyzer.public_send(method, node, parent, self)
249
- rescue AnalysisError => err
250
- @rescued_errors << err
251
- end
252
- end
253
- end
254
-
255
262
  def on_fragment_with_type(node)
256
263
  object_type = if node.type
257
264
  @query.warden.get_type(node.type.name)
@@ -409,6 +409,7 @@ module GraphQL
409
409
  raise "Invariant: no field for #{owner_type}.#{field_name}"
410
410
  end
411
411
  end
412
+
412
413
  return_type = field_defn.type
413
414
 
414
415
  next_path = path + [result_name]
@@ -431,17 +432,16 @@ module GraphQL
431
432
  total_args_count = field_defn.arguments(context).size
432
433
  if total_args_count == 0
433
434
  resolved_arguments = GraphQL::Execution::Interpreter::Arguments::EMPTY
434
- evaluate_selection_with_args(resolved_arguments, field_defn, next_path, ast_node, field_ast_nodes, owner_type, object, is_eager_field, result_name, selections_result, parent_object)
435
+ evaluate_selection_with_args(resolved_arguments, field_defn, next_path, ast_node, field_ast_nodes, owner_type, object, is_eager_field, result_name, selections_result, parent_object, return_type)
435
436
  else
436
437
  # TODO remove all arguments(...) usages?
437
438
  @query.arguments_cache.dataload_for(ast_node, field_defn, object) do |resolved_arguments|
438
- evaluate_selection_with_args(resolved_arguments, field_defn, next_path, ast_node, field_ast_nodes, owner_type, object, is_eager_field, result_name, selections_result, parent_object)
439
+ evaluate_selection_with_args(resolved_arguments, field_defn, next_path, ast_node, field_ast_nodes, owner_type, object, is_eager_field, result_name, selections_result, parent_object, return_type)
439
440
  end
440
441
  end
441
442
  end
442
443
 
443
- def evaluate_selection_with_args(arguments, field_defn, next_path, ast_node, field_ast_nodes, owner_type, object, is_eager_field, result_name, selection_result, parent_object) # rubocop:disable Metrics/ParameterLists
444
- return_type = field_defn.type
444
+ def evaluate_selection_with_args(arguments, field_defn, next_path, ast_node, field_ast_nodes, owner_type, object, is_eager_field, result_name, selection_result, parent_object, return_type) # rubocop:disable Metrics/ParameterLists
445
445
  after_lazy(arguments, owner: owner_type, field: field_defn, path: next_path, ast_node: ast_node, owner_object: object, arguments: arguments, result_name: result_name, result: selection_result) do |resolved_arguments|
446
446
  if resolved_arguments.is_a?(GraphQL::ExecutionError) || resolved_arguments.is_a?(GraphQL::UnauthorizedError)
447
447
  continue_value(next_path, resolved_arguments, owner_type, field_defn, return_type.non_null?, ast_node, result_name, selection_result)
@@ -615,6 +615,16 @@ module GraphQL
615
615
  end
616
616
  end
617
617
  HALT
618
+ elsif value.is_a?(GraphQL::UnauthorizedFieldError)
619
+ value.field ||= field
620
+ # this hook might raise & crash, or it might return
621
+ # a replacement value
622
+ next_value = begin
623
+ schema.unauthorized_field(value)
624
+ rescue GraphQL::ExecutionError => err
625
+ err
626
+ end
627
+ continue_value(path, next_value, parent_type, field, is_non_null, ast_node, result_name, selection_result)
618
628
  elsif value.is_a?(GraphQL::UnauthorizedError)
619
629
  # this hook might raise & crash, or it might return
620
630
  # a replacement value
@@ -146,6 +146,16 @@ module GraphQL
146
146
  # Assign values here so that the query's `@executed` becomes true
147
147
  queries.map { |q| q.result_values ||= {} }
148
148
  raise
149
+ ensure
150
+ queries.map { |query|
151
+ runtime = query.context.namespace(:interpreter_runtime)[:runtime]
152
+ if runtime
153
+ runtime.delete_interpreter_context(:current_path)
154
+ runtime.delete_interpreter_context(:current_field)
155
+ runtime.delete_interpreter_context(:current_object)
156
+ runtime.delete_interpreter_context(:current_arguments)
157
+ end
158
+ }
149
159
  end
150
160
  end
151
161
  end
@@ -29,15 +29,11 @@ module GraphQL
29
29
  def value
30
30
  if !@resolved
31
31
  @resolved = true
32
- @value = begin
33
- v = @get_value_func.call
34
- if v.is_a?(Lazy)
35
- v = v.value
36
- end
37
- v
38
- rescue GraphQL::ExecutionError => err
39
- err
32
+ v = @get_value_func.call
33
+ if v.is_a?(Lazy)
34
+ v = v.value
40
35
  end
36
+ @value = v
41
37
  end
42
38
 
43
39
  # `SKIP` was made into a subclass of `GraphQL::Error` to improve runtime performance
@@ -11,8 +11,8 @@ module GraphQL
11
11
  "to the executor."
12
12
  field :name, String, null: false, method: :graphql_name
13
13
  field :description, String
14
- field :locations, [GraphQL::Schema::LateBoundType.new("__DirectiveLocation")], null: false
15
- field :args, [GraphQL::Schema::LateBoundType.new("__InputValue")], null: false do
14
+ field :locations, [GraphQL::Schema::LateBoundType.new("__DirectiveLocation")], null: false, scope: false
15
+ field :args, [GraphQL::Schema::LateBoundType.new("__InputValue")], null: false, scope: false do
16
16
  argument :include_deprecated, Boolean, required: false, default_value: false
17
17
  end
18
18
  field :on_operation, Boolean, null: false, deprecation_reason: "Use `locations`.", method: :on_operation?
@@ -7,7 +7,7 @@ module GraphQL
7
7
  "a name, potentially a list of arguments, and a return type."
8
8
  field :name, String, null: false
9
9
  field :description, String
10
- field :args, [GraphQL::Schema::LateBoundType.new("__InputValue")], null: false do
10
+ field :args, [GraphQL::Schema::LateBoundType.new("__InputValue")], null: false, scope: false do
11
11
  argument :include_deprecated, Boolean, required: false, default_value: false
12
12
  end
13
13
  field :type, GraphQL::Schema::LateBoundType.new("__Type"), null: false
@@ -8,11 +8,11 @@ module GraphQL
8
8
  "available types and directives on the server, as well as the entry points for "\
9
9
  "query, mutation, and subscription operations."
10
10
 
11
- field :types, [GraphQL::Schema::LateBoundType.new("__Type")], "A list of all types supported by this server.", null: false
11
+ field :types, [GraphQL::Schema::LateBoundType.new("__Type")], "A list of all types supported by this server.", null: false, scope: false
12
12
  field :query_type, GraphQL::Schema::LateBoundType.new("__Type"), "The type that query operations will be rooted at.", null: false
13
13
  field :mutation_type, GraphQL::Schema::LateBoundType.new("__Type"), "If this server supports mutation, the type that mutation operations will be rooted at."
14
14
  field :subscription_type, GraphQL::Schema::LateBoundType.new("__Type"), "If this server support subscription, the type that subscription operations will be rooted at."
15
- field :directives, [GraphQL::Schema::LateBoundType.new("__Directive")], "A list of all directives supported by this server.", null: false
15
+ field :directives, [GraphQL::Schema::LateBoundType.new("__Directive")], "A list of all directives supported by this server.", null: false, scope: false
16
16
  field :description, String, resolver_method: :schema_description
17
17
 
18
18
  def schema_description
@@ -14,15 +14,15 @@ module GraphQL
14
14
  field :kind, GraphQL::Schema::LateBoundType.new("__TypeKind"), null: false
15
15
  field :name, String, method: :graphql_name
16
16
  field :description, String
17
- field :fields, [GraphQL::Schema::LateBoundType.new("__Field")] do
17
+ field :fields, [GraphQL::Schema::LateBoundType.new("__Field")], scope: false do
18
18
  argument :include_deprecated, Boolean, required: false, default_value: false
19
19
  end
20
- field :interfaces, [GraphQL::Schema::LateBoundType.new("__Type")]
21
- field :possible_types, [GraphQL::Schema::LateBoundType.new("__Type")]
22
- field :enum_values, [GraphQL::Schema::LateBoundType.new("__EnumValue")] do
20
+ field :interfaces, [GraphQL::Schema::LateBoundType.new("__Type")], scope: false
21
+ field :possible_types, [GraphQL::Schema::LateBoundType.new("__Type")], scope: false
22
+ field :enum_values, [GraphQL::Schema::LateBoundType.new("__EnumValue")], scope: false do
23
23
  argument :include_deprecated, Boolean, required: false, default_value: false
24
24
  end
25
- field :input_fields, [GraphQL::Schema::LateBoundType.new("__InputValue")] do
25
+ field :input_fields, [GraphQL::Schema::LateBoundType.new("__InputValue")], scope: false do
26
26
  argument :include_deprecated, Boolean, required: false, default_value: false
27
27
  end
28
28
  field :of_type, GraphQL::Schema::LateBoundType.new("__Type")
@@ -141,18 +141,26 @@ module GraphQL
141
141
  .gsub(/([a-z])([A-Z])/,'\1_\2') # insert underscores
142
142
  .downcase # remove caps
143
143
 
144
- child_class.module_eval <<-RUBY
144
+ child_class.module_eval <<-RUBY, __FILE__, __LINE__
145
145
  def visit_method
146
146
  :on_#{name_underscored}
147
147
  end
148
148
 
149
149
  class << self
150
150
  attr_accessor :children_method_name
151
+
152
+ def visit_method
153
+ :on_#{name_underscored}
154
+ end
151
155
  end
152
156
  self.children_method_name = :#{name_underscored}s
153
157
  RUBY
154
158
  end
155
159
 
160
+ def children_of_type
161
+ @children_methods
162
+ end
163
+
156
164
  private
157
165
 
158
166
  # Name accessors which return lists of nodes,
@@ -300,7 +308,7 @@ module GraphQL
300
308
  # @return [String] the key for this argument
301
309
 
302
310
  # @!attribute value
303
- # @return [String, Float, Integer, Boolean, Array, InputObject] The value passed for this key
311
+ # @return [String, Float, Integer, Boolean, Array, InputObject, VariableIdentifier] The value passed for this key
304
312
 
305
313
  def children
306
314
  @children ||= Array(value).flatten.select { |v| v.is_a?(AbstractNode) }
@@ -325,35 +333,6 @@ module GraphQL
325
333
  )
326
334
  end
327
335
 
328
- # This is the AST root for normal queries
329
- #
330
- # @example Deriving a document by parsing a string
331
- # document = GraphQL.parse(query_string)
332
- #
333
- # @example Creating a string from a document
334
- # document.to_query_string
335
- # # { ... }
336
- #
337
- # @example Creating a custom string from a document
338
- # class VariableScrubber < GraphQL::Language::Printer
339
- # def print_argument(arg)
340
- # "#{arg.name}: <HIDDEN>"
341
- # end
342
- # end
343
- #
344
- # document.to_query_string(printer: VariableScrubber.new)
345
- #
346
- class Document < AbstractNode
347
- scalar_methods false
348
- children_methods(definitions: nil)
349
- # @!attribute definitions
350
- # @return [Array<OperationDefinition, FragmentDefinition>] top-level GraphQL units: operations or fragments
351
-
352
- def slice_definition(name)
353
- GraphQL::Language::DefinitionSlice.slice(self, name)
354
- end
355
- end
356
-
357
336
  # An enum value. The string is available as {#name}.
358
337
  class Enum < NameOnlyNode
359
338
  end
@@ -526,6 +505,35 @@ module GraphQL
526
505
  self.children_method_name = :definitions
527
506
  end
528
507
 
508
+ # This is the AST root for normal queries
509
+ #
510
+ # @example Deriving a document by parsing a string
511
+ # document = GraphQL.parse(query_string)
512
+ #
513
+ # @example Creating a string from a document
514
+ # document.to_query_string
515
+ # # { ... }
516
+ #
517
+ # @example Creating a custom string from a document
518
+ # class VariableScrubber < GraphQL::Language::Printer
519
+ # def print_argument(arg)
520
+ # "#{arg.name}: <HIDDEN>"
521
+ # end
522
+ # end
523
+ #
524
+ # document.to_query_string(printer: VariableScrubber.new)
525
+ #
526
+ class Document < AbstractNode
527
+ scalar_methods false
528
+ children_methods(definitions: nil)
529
+ # @!attribute definitions
530
+ # @return [Array<OperationDefinition, FragmentDefinition>] top-level GraphQL units: operations or fragments
531
+
532
+ def slice_definition(name)
533
+ GraphQL::Language::DefinitionSlice.slice(self, name)
534
+ end
535
+ end
536
+
529
537
  # A type name, used for variable definitions
530
538
  class TypeName < NameOnlyNode
531
539
  end