graphql 1.12.6 → 1.12.7

Sign up to get free protection for your applications and to get access to all the features.
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