graphql 1.12.6 → 1.12.7

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.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ebd2e71516a89475e1617ee60250d4d88f6d3743090ae8010e6918ce425a71fc
4
- data.tar.gz: c0577dd5aac0765abf748f9ba86b3a3a814658abba7a2285b4e0d929959de50f
3
+ metadata.gz: a0b3eaaf2e8d1d263d8de4e509bbca1413c41981ac69d8f722eba16883fc9023
4
+ data.tar.gz: e9d0a083c8553cb650a2aff619a4c04bd5a01fb345dc8ae560563db09fe4d0b4
5
5
  SHA512:
6
- metadata.gz: 832d9464fe69bacc19d4a8715e5d2869d8ff15a4c1c34316d9c092b295e2175ac4f7a746a736773914ac4789478baa28a1f451c57cee732346901d5e4e10e430
7
- data.tar.gz: 84f4918a0473bf07c657ca39392866ece0a36ca592272f85580417882b762e7210cd6404ee1671ad651ac7608acdb0103a4a262253e48ccc9b75be2804c5caf4
6
+ metadata.gz: c1580219b7da1f62566e65eff2b2c11f124415dad818243260b2ebefddb4de5dad2d2e1953bc671f2080d1523c98f31e7eee581edf5b6b830761a96b970796ca
7
+ data.tar.gz: 1a886d5d664bb4352b9f75f1c448acb5e2d0b8299c6f1cf6debd441df2f700869912b8a7083363aac6c41874ae18dd5bd87955a9979e44b7e5e21811c25539f3
@@ -18,21 +18,83 @@ module GraphQL
18
18
  #
19
19
  class Errors
20
20
  def self.use(schema)
21
- if schema.plugins.any? { |(plugin, kwargs)| plugin == self }
22
- definition_line = caller(2, 1).first
23
- GraphQL::Deprecation.warn("GraphQL::Execution::Errors is now installed by default, remove `use GraphQL::Execution::Errors` from #{definition_line}")
24
- end
25
- schema.error_handler = self.new(schema)
21
+ definition_line = caller(2, 1).first
22
+ GraphQL::Deprecation.warn("GraphQL::Execution::Errors is now installed by default, remove `use GraphQL::Execution::Errors` from #{definition_line}")
26
23
  end
27
24
 
25
+ NEW_HANDLER_HASH = ->(h, k) {
26
+ h[k] = {
27
+ class: k,
28
+ handler: nil,
29
+ subclass_handlers: Hash.new(&NEW_HANDLER_HASH),
30
+ }
31
+ }
32
+
28
33
  def initialize(schema)
29
34
  @schema = schema
35
+ @handlers = {
36
+ class: nil,
37
+ handler: nil,
38
+ subclass_handlers: Hash.new(&NEW_HANDLER_HASH),
39
+ }
40
+ end
41
+
42
+ # @api private
43
+ def each_rescue
44
+ handlers = @handlers.values
45
+ while (handler = handlers.shift) do
46
+ yield(handler[:class], handler[:handler])
47
+ handlers.concat(handler[:subclass_handlers].values)
48
+ end
30
49
  end
31
50
 
32
- class NullErrorHandler
33
- def self.with_error_handling(_ctx)
34
- yield
51
+ # Register this handler, updating the
52
+ # internal handler index to maintain least-to-most specific.
53
+ #
54
+ # @param error_class [Class<Exception>]
55
+ # @param error_handler [Proc]
56
+ # @return [void]
57
+ def rescue_from(error_class, error_handler)
58
+ subclasses_handlers = {}
59
+ this_level_subclasses = []
60
+ # During this traversal, do two things:
61
+ # - Identify any already-registered subclasses of this error class
62
+ # and gather them up to be inserted _under_ this class
63
+ # - Find the point in the index where this handler should be inserted
64
+ # (That is, _under_ any superclasses, or at top-level, if there are no superclasses registered)
65
+ handlers = @handlers[:subclass_handlers]
66
+ while (handlers) do
67
+ this_level_subclasses.clear
68
+ # First, identify already-loaded handlers that belong
69
+ # _under_ this one. (That is, they're handlers
70
+ # for subclasses of `error_class`.)
71
+ handlers.each do |err_class, handler|
72
+ if err_class < error_class
73
+ subclasses_handlers[err_class] = handler
74
+ this_level_subclasses << err_class
75
+ end
76
+ end
77
+ # Any handlers that we'll be moving, delete them from this point in the index
78
+ this_level_subclasses.each do |err_class|
79
+ handlers.delete(err_class)
80
+ end
81
+
82
+ # See if any keys in this hash are superclasses of this new class:
83
+ next_index_point = handlers.find { |err_class, handler| error_class < err_class }
84
+ if next_index_point
85
+ handlers = next_index_point[1][:subclass_handlers]
86
+ else
87
+ # this new handler doesn't belong to any sub-handlers,
88
+ # so insert it in the current set of `handlers`
89
+ break
90
+ end
35
91
  end
92
+ # Having found the point at which to insert this handler,
93
+ # register it and merge any subclass handlers back in at this point.
94
+ this_class_handlers = handlers[error_class]
95
+ this_class_handlers[:handler] = error_handler
96
+ this_class_handlers[:subclass_handlers].merge!(subclasses_handlers)
97
+ nil
36
98
  end
37
99
 
38
100
  # Call the given block with the schema's configured error handlers.
@@ -44,8 +106,7 @@ module GraphQL
44
106
  def with_error_handling(ctx)
45
107
  yield
46
108
  rescue StandardError => err
47
- rescues = ctx.schema.rescues
48
- _err_class, handler = rescues.find { |err_class, handler| err.is_a?(err_class) }
109
+ handler = find_handler_for(err.class)
49
110
  if handler
50
111
  runtime_info = ctx.namespace(:interpreter) || {}
51
112
  obj = runtime_info[:current_object]
@@ -59,6 +120,43 @@ module GraphQL
59
120
  raise err
60
121
  end
61
122
  end
123
+
124
+ # @return [Proc, nil] The handler for `error_class`, if one was registered on this schema or inherited
125
+ def find_handler_for(error_class)
126
+ handlers = @handlers[:subclass_handlers]
127
+ handler = nil
128
+ while (handlers) do
129
+ _err_class, next_handler = handlers.find { |err_class, handler| error_class <= err_class }
130
+ if next_handler
131
+ handlers = next_handler[:subclass_handlers]
132
+ handler = next_handler
133
+ else
134
+ # Don't reassign `handler` --
135
+ # let the previous assignment carry over outside this block.
136
+ break
137
+ end
138
+ end
139
+
140
+ # check for a handler from a parent class:
141
+ if @schema.superclass.respond_to?(:error_handler) && (parent_errors = @schema.superclass.error_handler)
142
+ parent_handler = parent_errors.find_handler_for(error_class)
143
+ end
144
+
145
+ # If the inherited handler is more specific than the one defined here,
146
+ # use it.
147
+ # If it's a tie (or there is no parent handler), use the one defined here.
148
+ # If there's an inherited one, but not one defined here, use the inherited one.
149
+ # Otherwise, there's no handler for this error, return `nil`.
150
+ if parent_handler && handler && parent_handler[:class] < handler[:class]
151
+ parent_handler[:handler]
152
+ elsif handler
153
+ handler[:handler]
154
+ elsif parent_handler
155
+ parent_handler[:handler]
156
+ else
157
+ nil
158
+ end
159
+ end
62
160
  end
63
161
  end
64
162
  end
@@ -277,10 +277,7 @@ module GraphQL
277
277
  end
278
278
  after_lazy(app_result, owner: owner_type, field: field_defn, path: next_path, ast_node: ast_node, scoped_context: context.scoped_context, owner_object: object, arguments: kwarg_arguments) do |inner_result|
279
279
  continue_value = continue_value(next_path, inner_result, owner_type, field_defn, return_type.non_null?, ast_node)
280
- if RawValue === continue_value
281
- # Write raw value directly to the response without resolving nested objects
282
- write_in_response(next_path, continue_value.resolve)
283
- elsif HALT != continue_value
280
+ if HALT != continue_value
284
281
  continue_field(next_path, continue_value, owner_type, field_defn, return_type, ast_node, next_selections, false, object, kwarg_arguments)
285
282
  end
286
283
  end
@@ -332,6 +329,10 @@ module GraphQL
332
329
  continue_value(path, next_value, parent_type, field, is_non_null, ast_node)
333
330
  elsif GraphQL::Execution::Execute::SKIP == value
334
331
  HALT
332
+ elsif value.is_a?(GraphQL::Execution::Interpreter::RawValue)
333
+ # Write raw value directly to the response without resolving nested objects
334
+ write_in_response(path, value.resolve)
335
+ HALT
335
336
  else
336
337
  value
337
338
  end
@@ -17,7 +17,7 @@ query IntrospectionQuery {
17
17
  name
18
18
  description
19
19
  locations
20
- args {
20
+ args#{include_deprecated_args ? '(includeDeprecated: true)' : ''} {
21
21
  ...InputValue
22
22
  }
23
23
  }
@@ -12,13 +12,17 @@ module GraphQL
12
12
  field :name, String, null: false, method: :graphql_name
13
13
  field :description, String, null: true
14
14
  field :locations, [GraphQL::Schema::LateBoundType.new("__DirectiveLocation")], null: false
15
- field :args, [GraphQL::Schema::LateBoundType.new("__InputValue")], null: false
15
+ field :args, [GraphQL::Schema::LateBoundType.new("__InputValue")], null: false do
16
+ argument :include_deprecated, Boolean, required: false, default_value: false
17
+ end
16
18
  field :on_operation, Boolean, null: false, deprecation_reason: "Use `locations`.", method: :on_operation?
17
19
  field :on_fragment, Boolean, null: false, deprecation_reason: "Use `locations`.", method: :on_fragment?
18
20
  field :on_field, Boolean, null: false, deprecation_reason: "Use `locations`.", method: :on_field?
19
21
 
20
- def args
21
- @context.warden.arguments(@object)
22
+ def args(include_deprecated:)
23
+ args = @context.warden.arguments(@object)
24
+ args = args.reject(&:deprecation_reason) unless include_deprecated
25
+ args
22
26
  end
23
27
  end
24
28
  end
@@ -5,6 +5,13 @@ module GraphQL
5
5
  module Pagination
6
6
  # Customizes `RelationConnection` to work with `ActiveRecord::Relation`s.
7
7
  class ActiveRecordRelationConnection < Pagination::RelationConnection
8
+ private
9
+
10
+ def relation_larger_than(relation, size)
11
+ initial_offset = relation.offset_value || 0
12
+ relation.offset(initial_offset + size).exists?
13
+ end
14
+
8
15
  def relation_count(relation)
9
16
  int_or_hash = if relation.respond_to?(:unscope)
10
17
  relation.unscope(:order).count(:all)
@@ -35,7 +35,7 @@ module GraphQL
35
35
  if @nodes && @nodes.count < first
36
36
  false
37
37
  else
38
- relation_count(set_limit(sliced_nodes, first + 1)) == first + 1
38
+ relation_larger_than(sliced_nodes, first)
39
39
  end
40
40
  else
41
41
  false
@@ -53,6 +53,13 @@ module GraphQL
53
53
 
54
54
  private
55
55
 
56
+ # @param relation [Object] A database query object
57
+ # @param size [Integer] The value against which we check the relation size
58
+ # @return [Boolean] True if the number of items in this relation is larger than `size`
59
+ def relation_larger_than(relation, size)
60
+ relation_count(set_limit(relation, size + 1)) == size + 1
61
+ end
62
+
56
63
  # @param relation [Object] A database query object
57
64
  # @return [Integer, nil] The offset value, or nil if there isn't one
58
65
  def relation_offset(relation)
data/lib/graphql/query.rb CHANGED
@@ -195,9 +195,7 @@ module GraphQL
195
195
  # @return [Hash] A GraphQL response, with `"data"` and/or `"errors"` keys
196
196
  def result
197
197
  if !@executed
198
- with_prepared_ast {
199
- Execution::Multiplex.run_queries(@schema, [self], context: @context)
200
- }
198
+ Execution::Multiplex.run_queries(@schema, [self], context: @context)
201
199
  end
202
200
  @result ||= Query::Result.new(query: self, values: @result_values)
203
201
  end
@@ -36,7 +36,7 @@ module GraphQL
36
36
  @valid
37
37
  end
38
38
 
39
- # @return [Array<GraphQL::StaticValidation::Error >] Static validation errors for the query string
39
+ # @return [Array<GraphQL::StaticValidation::Error, GraphQL::Query::VariableValidationError>] Static validation errors for the query string
40
40
  def validation_errors
41
41
  ensure_has_validated
42
42
  @validation_errors
@@ -711,7 +711,7 @@ module GraphQL
711
711
  alias :_schema_class :class
712
712
  def_delegators :_schema_class, :unauthorized_object, :unauthorized_field, :inaccessible_fields
713
713
  def_delegators :_schema_class, :directive
714
- def_delegators :_schema_class, :error_handler, :rescues
714
+ def_delegators :_schema_class, :error_handler
715
715
 
716
716
 
717
717
  # Given this schema member, find the class-based definition object
@@ -989,7 +989,7 @@ module GraphQL
989
989
  schema_defn.lazy_methods.set(lazy_class, value_method)
990
990
  end
991
991
 
992
- rescues.each do |err_class, handler|
992
+ error_handler.each_rescue do |err_class, handler|
993
993
  schema_defn.rescue_from(err_class, &handler)
994
994
  end
995
995
 
@@ -1424,7 +1424,7 @@ module GraphQL
1424
1424
 
1425
1425
  def rescue_from(*err_classes, &handler_block)
1426
1426
  err_classes.each do |err_class|
1427
- own_rescues[err_class] = handler_block
1427
+ error_handler.rescue_from(err_class, handler_block)
1428
1428
  end
1429
1429
  end
1430
1430
 
@@ -1468,10 +1468,6 @@ module GraphQL
1468
1468
  super
1469
1469
  end
1470
1470
 
1471
- def rescues
1472
- find_inherited_value(:rescues, EMPTY_HASH).merge(own_rescues)
1473
- end
1474
-
1475
1471
  def object_from_id(node_id, ctx)
1476
1472
  raise GraphQL::RequiredImplementationMissingError, "#{self.name}.object_from_id(node_id, ctx) must be implemented to load by ID (tried to load from id `#{node_id}`)"
1477
1473
  end
@@ -1548,15 +1544,10 @@ module GraphQL
1548
1544
  def parse_error(parse_err, ctx)
1549
1545
  ctx.errors.push(parse_err)
1550
1546
  end
1551
- attr_writer :error_handler
1552
1547
 
1553
- # @return [GraphQL::Execution::Errors, Class<GraphQL::Execution::Errors::NullErrorHandler>]
1548
+ # @return [GraphQL::Execution::Errors]
1554
1549
  def error_handler
1555
- if defined?(@error_handler)
1556
- @error_handler
1557
- else
1558
- find_inherited_value(:error_handler, GraphQL::Execution::Errors::NullErrorHandler)
1559
- end
1550
+ @error_handler ||= GraphQL::Execution::Errors.new(self)
1560
1551
  end
1561
1552
 
1562
1553
  def lazy_resolve(lazy_class, value_method)
@@ -1744,10 +1735,6 @@ module GraphQL
1744
1735
  @own_plugins ||= []
1745
1736
  end
1746
1737
 
1747
- def own_rescues
1748
- @own_rescues ||= {}
1749
- end
1750
-
1751
1738
  def own_orphan_types
1752
1739
  @own_orphan_types ||= []
1753
1740
  end
@@ -1990,7 +1977,6 @@ module GraphQL
1990
1977
  end
1991
1978
 
1992
1979
  # Install these here so that subclasses will also install it.
1993
- use(GraphQL::Execution::Errors)
1994
1980
  use(GraphQL::Pagination::Connections)
1995
1981
 
1996
1982
  protected
@@ -41,7 +41,9 @@ module GraphQL
41
41
  error_options = {
42
42
  nodes: parent,
43
43
  type: kind_of_node,
44
- argument: node.name
44
+ argument_name: node.name,
45
+ argument: arg_defn,
46
+ value: node.value
45
47
  }
46
48
  if coerce_extensions
47
49
  error_options[:coerce_extensions] = coerce_extensions
@@ -4,13 +4,17 @@ module GraphQL
4
4
  class ArgumentLiteralsAreCompatibleError < StaticValidation::Error
5
5
  attr_reader :type_name
6
6
  attr_reader :argument_name
7
+ attr_reader :argument
8
+ attr_reader :value
7
9
 
8
- def initialize(message, path: nil, nodes: [], type:, argument: nil, extensions: nil, coerce_extensions: nil)
10
+ def initialize(message, path: nil, nodes: [], type:, argument_name: nil, extensions: nil, coerce_extensions: nil, argument: nil, value: nil)
9
11
  super(message, path: path, nodes: nodes)
10
12
  @type_name = type
11
- @argument_name = argument
13
+ @argument_name = argument_name
12
14
  @extensions = extensions
13
15
  @coerce_extensions = coerce_extensions
16
+ @argument = argument
17
+ @value = value
14
18
  end
15
19
 
16
20
  # A hash representation of this Message
@@ -15,7 +15,8 @@ module GraphQL
15
15
  nodes: node,
16
16
  name: error_arg_name,
17
17
  type: kind_of_node,
18
- argument: node.name
18
+ argument_name: node.name,
19
+ parent: parent_defn
19
20
  ))
20
21
  else
21
22
  # Some other weird error
@@ -5,12 +5,14 @@ module GraphQL
5
5
  attr_reader :name
6
6
  attr_reader :type_name
7
7
  attr_reader :argument_name
8
+ attr_reader :parent
8
9
 
9
- def initialize(message, path: nil, nodes: [], name:, type:, argument:)
10
+ def initialize(message, path: nil, nodes: [], name:, type:, argument_name:, parent:)
10
11
  super(message, path: path, nodes: nodes)
11
12
  @name = name
12
13
  @type_name = type
13
- @argument_name = argument
14
+ @argument_name = argument_name
15
+ @parent = parent
14
16
  end
15
17
 
16
18
  # A hash representation of this Message
@@ -35,9 +35,6 @@ module GraphQL
35
35
  pt = @query.possible_types(current_type)
36
36
  pt.each do |object_type|
37
37
  ot_field = @query.get_field(object_type, current_field.graphql_name)
38
- if !ot_field
39
- binding.pry
40
- end
41
38
  # Inherited fields would be exactly the same object;
42
39
  # only check fields that are overrides of the inherited one
43
40
  if ot_field && ot_field != current_field
@@ -24,6 +24,10 @@ module GraphQL
24
24
  # end
25
25
  # class Types::PostConnection < Types::BaseConnection
26
26
  # edge_type(Types::PostEdge)
27
+ # edges_nullable(true)
28
+ # edge_nullable(true)
29
+ # node_nullable(true)
30
+ # has_nodes_field(true)
27
31
  # end
28
32
  #
29
33
  # @see Relay::BaseEdge for edge types
@@ -11,6 +11,7 @@ module GraphQL
11
11
  child_class.extend(ClassMethods)
12
12
  child_class.extend(Relay::DefaultRelay)
13
13
  child_class.default_relay(true)
14
+ child_class.has_nodes_field(true)
14
15
  child_class.node_nullable(true)
15
16
  child_class.edges_nullable(true)
16
17
  child_class.edge_nullable(true)
@@ -34,7 +35,7 @@ module GraphQL
34
35
  # It's called when you subclass this base connection, trying to use the
35
36
  # class name to set defaults. You can call it again in the class definition
36
37
  # to override the default (or provide a value, if the default lookup failed).
37
- def edge_type(edge_type_class, edge_class: GraphQL::Relay::Edge, node_type: edge_type_class.node_type, nodes_field: true, node_nullable: self.node_nullable, edges_nullable: self.edges_nullable, edge_nullable: self.edge_nullable)
38
+ def edge_type(edge_type_class, edge_class: GraphQL::Relay::Edge, node_type: edge_type_class.node_type, nodes_field: self.has_nodes_field, node_nullable: self.node_nullable, edges_nullable: self.edges_nullable, edge_nullable: self.edge_nullable)
38
39
  # Set this connection's graphql name
39
40
  node_type_name = node_type.graphql_name
40
41
 
@@ -79,9 +80,9 @@ module GraphQL
79
80
  # Use `node_nullable(false)` in your base class to make non-null `node` and `nodes` fields.
80
81
  def node_nullable(new_value = nil)
81
82
  if new_value.nil?
82
- @node_nullable || superclass.node_nullable
83
+ defined?(@node_nullable) ? @node_nullable : superclass.node_nullable
83
84
  else
84
- @node_nullable ||= new_value
85
+ @node_nullable = new_value
85
86
  end
86
87
  end
87
88
 
@@ -89,21 +90,31 @@ module GraphQL
89
90
  # Use `edges_nullable(false)` in your base class to make non-null `edges` fields.
90
91
  def edges_nullable(new_value = nil)
91
92
  if new_value.nil?
92
- @edges_nullable || superclass.edges_nullable
93
+ defined?(@edges_nullable) ? @edges_nullable : superclass.edges_nullable
93
94
  else
94
- @edges_nullable ||= new_value
95
+ @edges_nullable = new_value
95
96
  end
96
- end
97
-
97
+ end
98
+
98
99
  # Set the default `edge_nullable` for this class and its child classes. (Defaults to `true`.)
99
100
  # Use `edge_nullable(false)` in your base class to make non-null `edge` fields.
100
101
  def edge_nullable(new_value = nil)
101
102
  if new_value.nil?
102
- @edge_nullable || superclass.edge_nullable
103
+ defined?(@edge_nullable) ? @edge_nullable : superclass.edge_nullable
104
+ else
105
+ @edge_nullable = new_value
106
+ end
107
+ end
108
+
109
+ # Set the default `nodes_field` for this class and its child classes. (Defaults to `true`.)
110
+ # Use `nodes_field(false)` in your base class to prevent adding of a nodes field.
111
+ def has_nodes_field(new_value = nil)
112
+ if new_value.nil?
113
+ defined?(@nodes_field) ? @nodes_field : superclass.has_nodes_field
103
114
  else
104
- @edge_nullable ||= new_value
115
+ @nodes_field = new_value
105
116
  end
106
- end
117
+ end
107
118
 
108
119
  private
109
120
 
@@ -8,6 +8,7 @@ module GraphQL
8
8
  child_class.description("An edge in a connection.")
9
9
  child_class.field(:cursor, String, null: false, description: "A cursor for use in pagination.")
10
10
  child_class.extend(ClassMethods)
11
+ child_class.node_nullable(true)
11
12
  end
12
13
 
13
14
  module ClassMethods
@@ -15,7 +16,7 @@ module GraphQL
15
16
  #
16
17
  # @param node_type [Class] A `Schema::Object` subclass
17
18
  # @param null [Boolean]
18
- def node_type(node_type = nil, null: true)
19
+ def node_type(node_type = nil, null: self.node_nullable)
19
20
  if node_type
20
21
  @node_type = node_type
21
22
  # Add a default `node` field
@@ -35,6 +36,16 @@ module GraphQL
35
36
  def visible?(ctx)
36
37
  node_type.visible?(ctx)
37
38
  end
39
+
40
+ # Set the default `node_nullable` for this class and its child classes. (Defaults to `true`.)
41
+ # Use `node_nullable(false)` in your base class to make non-null `node` field.
42
+ def node_nullable(new_value = nil)
43
+ if new_value.nil?
44
+ defined?(@node_nullable) ? @node_nullable : superclass.node_nullable
45
+ else
46
+ @node_nullable = new_value
47
+ end
48
+ end
38
49
  end
39
50
  end
40
51
  end
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module GraphQL
3
- VERSION = "1.12.6"
3
+ VERSION = "1.12.7"
4
4
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: graphql
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.12.6
4
+ version: 1.12.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Robert Mosolgo
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-03-11 00:00:00.000000000 Z
11
+ date: 2021-04-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: benchmark-ips