graphql 2.0.16 → 2.0.21

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 (90) hide show
  1. checksums.yaml +4 -4
  2. data/lib/graphql/analysis/ast/visitor.rb +42 -35
  3. data/lib/graphql/analysis/ast.rb +2 -2
  4. data/lib/graphql/backtrace/trace.rb +96 -0
  5. data/lib/graphql/backtrace/tracer.rb +1 -1
  6. data/lib/graphql/backtrace.rb +6 -1
  7. data/lib/graphql/execution/interpreter/arguments.rb +1 -1
  8. data/lib/graphql/execution/interpreter/arguments_cache.rb +2 -3
  9. data/lib/graphql/execution/interpreter/resolve.rb +19 -0
  10. data/lib/graphql/execution/interpreter/runtime.rb +264 -211
  11. data/lib/graphql/execution/interpreter.rb +15 -10
  12. data/lib/graphql/execution/lazy.rb +6 -12
  13. data/lib/graphql/execution/multiplex.rb +2 -1
  14. data/lib/graphql/filter.rb +7 -2
  15. data/lib/graphql/introspection/directive_type.rb +2 -2
  16. data/lib/graphql/introspection/field_type.rb +1 -1
  17. data/lib/graphql/introspection/schema_type.rb +2 -2
  18. data/lib/graphql/introspection/type_type.rb +5 -5
  19. data/lib/graphql/language/document_from_schema_definition.rb +25 -9
  20. data/lib/graphql/language/lexer.rb +216 -1505
  21. data/lib/graphql/language/nodes.rb +66 -40
  22. data/lib/graphql/language/parser.rb +509 -491
  23. data/lib/graphql/language/parser.y +43 -38
  24. data/lib/graphql/language/visitor.rb +191 -83
  25. data/lib/graphql/pagination/active_record_relation_connection.rb +0 -8
  26. data/lib/graphql/pagination/connection.rb +5 -5
  27. data/lib/graphql/query/context.rb +62 -31
  28. data/lib/graphql/query/null_context.rb +1 -1
  29. data/lib/graphql/query.rb +22 -5
  30. data/lib/graphql/schema/argument.rb +7 -13
  31. data/lib/graphql/schema/build_from_definition.rb +15 -3
  32. data/lib/graphql/schema/directive.rb +12 -2
  33. data/lib/graphql/schema/enum.rb +24 -17
  34. data/lib/graphql/schema/enum_value.rb +2 -3
  35. data/lib/graphql/schema/field.rb +68 -57
  36. data/lib/graphql/schema/field_extension.rb +1 -4
  37. data/lib/graphql/schema/find_inherited_value.rb +2 -7
  38. data/lib/graphql/schema/interface.rb +0 -10
  39. data/lib/graphql/schema/late_bound_type.rb +2 -0
  40. data/lib/graphql/schema/member/base_dsl_methods.rb +17 -14
  41. data/lib/graphql/schema/member/has_arguments.rb +105 -58
  42. data/lib/graphql/schema/member/has_ast_node.rb +12 -0
  43. data/lib/graphql/schema/member/has_deprecation_reason.rb +3 -4
  44. data/lib/graphql/schema/member/has_directives.rb +15 -10
  45. data/lib/graphql/schema/member/has_fields.rb +95 -38
  46. data/lib/graphql/schema/member/has_interfaces.rb +49 -8
  47. data/lib/graphql/schema/member/has_validators.rb +32 -6
  48. data/lib/graphql/schema/member/relay_shortcuts.rb +19 -0
  49. data/lib/graphql/schema/member/type_system_helpers.rb +17 -0
  50. data/lib/graphql/schema/object.rb +2 -4
  51. data/lib/graphql/schema/resolver/has_payload_type.rb +9 -9
  52. data/lib/graphql/schema/resolver.rb +4 -4
  53. data/lib/graphql/schema/timeout.rb +24 -28
  54. data/lib/graphql/schema/validator.rb +1 -1
  55. data/lib/graphql/schema/warden.rb +29 -5
  56. data/lib/graphql/schema.rb +76 -25
  57. data/lib/graphql/static_validation/literal_validator.rb +15 -1
  58. data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +12 -4
  59. data/lib/graphql/static_validation/rules/fields_will_merge.rb +2 -2
  60. data/lib/graphql/static_validation/validator.rb +1 -1
  61. data/lib/graphql/subscriptions/event.rb +2 -7
  62. data/lib/graphql/tracing/active_support_notifications_trace.rb +16 -0
  63. data/lib/graphql/tracing/appoptics_trace.rb +231 -0
  64. data/lib/graphql/tracing/appsignal_trace.rb +77 -0
  65. data/lib/graphql/tracing/data_dog_trace.rb +148 -0
  66. data/lib/graphql/tracing/legacy_trace.rb +65 -0
  67. data/lib/graphql/tracing/new_relic_trace.rb +75 -0
  68. data/lib/graphql/tracing/notifications_trace.rb +42 -0
  69. data/lib/graphql/tracing/platform_trace.rb +109 -0
  70. data/lib/graphql/tracing/platform_tracing.rb +15 -3
  71. data/lib/graphql/tracing/prometheus_trace.rb +89 -0
  72. data/lib/graphql/tracing/prometheus_tracing/graphql_collector.rb +1 -1
  73. data/lib/graphql/tracing/prometheus_tracing.rb +3 -3
  74. data/lib/graphql/tracing/scout_trace.rb +72 -0
  75. data/lib/graphql/tracing/statsd_trace.rb +56 -0
  76. data/lib/graphql/tracing/trace.rb +75 -0
  77. data/lib/graphql/tracing.rb +16 -39
  78. data/lib/graphql/type_kinds.rb +6 -3
  79. data/lib/graphql/types/relay/base_connection.rb +1 -1
  80. data/lib/graphql/types/relay/connection_behaviors.rb +24 -6
  81. data/lib/graphql/types/relay/edge_behaviors.rb +16 -6
  82. data/lib/graphql/types/relay/node_behaviors.rb +7 -1
  83. data/lib/graphql/types/relay/page_info_behaviors.rb +7 -2
  84. data/lib/graphql/types/relay.rb +0 -1
  85. data/lib/graphql/types/string.rb +1 -1
  86. data/lib/graphql/version.rb +1 -1
  87. data/lib/graphql.rb +16 -9
  88. metadata +34 -9
  89. data/lib/graphql/language/lexer.rl +0 -280
  90. data/lib/graphql/types/relay/default_relay.rb +0 -27
@@ -4,6 +4,16 @@ module GraphQL
4
4
  class Schema
5
5
  class Member
6
6
  module HasDirectives
7
+ def self.extended(child_cls)
8
+ super
9
+ child_cls.module_eval { self.own_directives = nil }
10
+ end
11
+
12
+ def inherited(child_cls)
13
+ super
14
+ child_cls.own_directives = nil
15
+ end
16
+
7
17
  # Create an instance of `dir_class` for `self`, using `options`.
8
18
  #
9
19
  # It removes a previously-attached instance of `dir_class`, if there is one.
@@ -23,8 +33,6 @@ module GraphQL
23
33
  nil
24
34
  end
25
35
 
26
- NO_DIRECTIVES = [].freeze
27
-
28
36
  def directives
29
37
  HasDirectives.get_directives(self, @own_directives, :directives)
30
38
  end
@@ -45,7 +53,7 @@ module GraphQL
45
53
  inherited_directives = if schema_member.superclass.respond_to?(directives_method)
46
54
  get_directives(schema_member.superclass, schema_member.superclass.public_send(directives_method), directives_method)
47
55
  else
48
- NO_DIRECTIVES
56
+ GraphQL::EmptyObjects::EMPTY_ARRAY
49
57
  end
50
58
  if inherited_directives.any? && directives
51
59
  dirs = []
@@ -57,7 +65,7 @@ module GraphQL
57
65
  elsif inherited_directives.any?
58
66
  inherited_directives
59
67
  else
60
- NO_DIRECTIVES
68
+ GraphQL::EmptyObjects::EMPTY_ARRAY
61
69
  end
62
70
  when Module
63
71
  dirs = nil
@@ -72,9 +80,9 @@ module GraphQL
72
80
  dirs ||= []
73
81
  merge_directives(dirs, directives)
74
82
  end
75
- dirs || NO_DIRECTIVES
83
+ dirs || GraphQL::EmptyObjects::EMPTY_ARRAY
76
84
  when HasDirectives
77
- directives || NO_DIRECTIVES
85
+ directives || GraphQL::EmptyObjects::EMPTY_ARRAY
78
86
  else
79
87
  raise "Invariant: how could #{schema_member} not be a Class, Module, or instance of HasDirectives?"
80
88
  end
@@ -101,12 +109,9 @@ module GraphQL
101
109
  end
102
110
  end
103
111
 
104
-
105
112
  protected
106
113
 
107
- def own_directives
108
- @own_directives
109
- end
114
+ attr_accessor :own_directives
110
115
  end
111
116
  end
112
117
  end
@@ -14,42 +14,6 @@ module GraphQL
14
14
  field_defn
15
15
  end
16
16
 
17
- # @return [Hash<String => GraphQL::Schema::Field>] Fields on this object, keyed by name, including inherited fields
18
- def fields(context = GraphQL::Query::NullContext)
19
- warden = Warden.from_context(context)
20
- is_object = self.respond_to?(:kind) && self.kind.object?
21
- # Local overrides take precedence over inherited fields
22
- visible_fields = {}
23
- for ancestor in ancestors
24
- if ancestor.respond_to?(:own_fields) &&
25
- (is_object ? visible_interface_implementation?(ancestor, context, warden) : true)
26
-
27
- ancestor.own_fields.each do |field_name, fields_entry|
28
- # Choose the most local definition that passes `.visible?` --
29
- # stop checking for fields by name once one has been found.
30
- if !visible_fields.key?(field_name) && (f = Warden.visible_entry?(:visible_field?, fields_entry, context, warden))
31
- visible_fields[field_name] = f
32
- end
33
- end
34
- end
35
- end
36
- visible_fields
37
- end
38
-
39
- def get_field(field_name, context = GraphQL::Query::NullContext)
40
- warden = Warden.from_context(context)
41
- is_object = self.respond_to?(:kind) && self.kind.object?
42
- for ancestor in ancestors
43
- if ancestor.respond_to?(:own_fields) &&
44
- (is_object ? visible_interface_implementation?(ancestor, context, warden) : true) &&
45
- (f_entry = ancestor.own_fields[field_name]) &&
46
- (f = Warden.visible_entry?(:visible_field?, f_entry, context, warden))
47
- return f
48
- end
49
- end
50
- nil
51
- end
52
-
53
17
  # A list of Ruby keywords.
54
18
  #
55
19
  # @api private
@@ -72,7 +36,12 @@ module GraphQL
72
36
  def add_field(field_defn, method_conflict_warning: field_defn.method_conflict_warning?)
73
37
  # Check that `field_defn.original_name` equals `resolver_method` and `method_sym` --
74
38
  # that shows that no override value was given manually.
75
- if method_conflict_warning && CONFLICT_FIELD_NAMES.include?(field_defn.resolver_method) && field_defn.original_name == field_defn.resolver_method && field_defn.original_name == field_defn.method_sym && field_defn.hash_key.nil? && field_defn.dig_keys.nil?
39
+ if method_conflict_warning &&
40
+ CONFLICT_FIELD_NAMES.include?(field_defn.resolver_method) &&
41
+ field_defn.original_name == field_defn.resolver_method &&
42
+ field_defn.original_name == field_defn.method_sym &&
43
+ field_defn.hash_key == NOT_CONFIGURED &&
44
+ field_defn.dig_keys.nil?
76
45
  warn(conflict_field_name_warning(field_defn))
77
46
  end
78
47
  prev_defn = own_fields[field_defn.name]
@@ -127,14 +96,102 @@ module GraphQL
127
96
  all_fields
128
97
  end
129
98
 
99
+ module InterfaceMethods
100
+ def get_field(field_name, context = GraphQL::Query::NullContext)
101
+ warden = Warden.from_context(context)
102
+ for ancestor in ancestors
103
+ if ancestor.respond_to?(:own_fields) &&
104
+ (f_entry = ancestor.own_fields[field_name]) &&
105
+ (f = Warden.visible_entry?(:visible_field?, f_entry, context, warden))
106
+ return f
107
+ end
108
+ end
109
+ nil
110
+ end
111
+
112
+ # @return [Hash<String => GraphQL::Schema::Field>] Fields on this object, keyed by name, including inherited fields
113
+ def fields(context = GraphQL::Query::NullContext)
114
+ warden = Warden.from_context(context)
115
+ # Local overrides take precedence over inherited fields
116
+ visible_fields = {}
117
+ for ancestor in ancestors
118
+ if ancestor.respond_to?(:own_fields)
119
+ ancestor.own_fields.each do |field_name, fields_entry|
120
+ # Choose the most local definition that passes `.visible?` --
121
+ # stop checking for fields by name once one has been found.
122
+ if !visible_fields.key?(field_name) && (f = Warden.visible_entry?(:visible_field?, fields_entry, context, warden))
123
+ visible_fields[field_name] = f
124
+ end
125
+ end
126
+ end
127
+ end
128
+ visible_fields
129
+ end
130
+ end
131
+
132
+ module ObjectMethods
133
+ def get_field(field_name, context = GraphQL::Query::NullContext)
134
+ # Objects need to check that the interface implementation is visible, too
135
+ warden = Warden.from_context(context)
136
+ for ancestor in ancestors
137
+ if ancestor.respond_to?(:own_fields) &&
138
+ visible_interface_implementation?(ancestor, context, warden) &&
139
+ (f_entry = ancestor.own_fields[field_name]) &&
140
+ (f = Warden.visible_entry?(:visible_field?, f_entry, context, warden))
141
+ return f
142
+ end
143
+ end
144
+ nil
145
+ end
146
+
147
+ # @return [Hash<String => GraphQL::Schema::Field>] Fields on this object, keyed by name, including inherited fields
148
+ def fields(context = GraphQL::Query::NullContext)
149
+ # Objects need to check that the interface implementation is visible, too
150
+ warden = Warden.from_context(context)
151
+ # Local overrides take precedence over inherited fields
152
+ visible_fields = {}
153
+ for ancestor in ancestors
154
+ if ancestor.respond_to?(:own_fields) && visible_interface_implementation?(ancestor, context, warden)
155
+ ancestor.own_fields.each do |field_name, fields_entry|
156
+ # Choose the most local definition that passes `.visible?` --
157
+ # stop checking for fields by name once one has been found.
158
+ if !visible_fields.key?(field_name) && (f = Warden.visible_entry?(:visible_field?, fields_entry, context, warden))
159
+ visible_fields[field_name] = f
160
+ end
161
+ end
162
+ end
163
+ end
164
+ visible_fields
165
+ end
166
+ end
167
+
168
+ def self.included(child_class)
169
+ # Included in an interface definition methods module
170
+ child_class.include(InterfaceMethods)
171
+ super
172
+ end
173
+
174
+ def self.extended(child_class)
175
+ child_class.extend(ObjectMethods)
176
+ super
177
+ end
178
+
130
179
  private
131
180
 
181
+ def inherited(subclass)
182
+ super
183
+ subclass.class_eval do
184
+ @own_fields ||= nil
185
+ @field_class ||= nil
186
+ end
187
+ end
188
+
132
189
  # If `type` is an interface, and `self` has a type membership for `type`, then make sure it's visible.
133
190
  def visible_interface_implementation?(type, context, warden)
134
191
  if type.respond_to?(:kind) && type.kind.interface?
135
192
  implements_this_interface = false
136
193
  implementation_is_visible = false
137
- interface_type_memberships.each do |tm|
194
+ warden.interface_type_memberships(self, context).each do |tm|
138
195
  if tm.abstract_type == type
139
196
  implements_this_interface ||= true
140
197
  if warden.visible_type_membership?(tm, context)
@@ -55,7 +55,38 @@ module GraphQL
55
55
  end
56
56
 
57
57
  def interface_type_memberships
58
- own_interface_type_memberships + ((self.is_a?(Class) && superclass.respond_to?(:interface_type_memberships)) ? superclass.interface_type_memberships : [])
58
+ own_interface_type_memberships
59
+ end
60
+
61
+ module ClassConfigured
62
+ # This combination of extended -> inherited -> extended
63
+ # means that the base class (`Schema::Object`) *won't*
64
+ # have the superclass-related code in `InheritedInterfaces`,
65
+ # but child classes of `Schema::Object` will have it.
66
+ # That way, we don't need a `superclass.respond_to?(...)` check.
67
+ def inherited(child_class)
68
+ super
69
+ child_class.extend(InheritedInterfaces)
70
+ end
71
+
72
+ module InheritedInterfaces
73
+ def interfaces(context = GraphQL::Query::NullContext)
74
+ visible_interfaces = super
75
+ visible_interfaces.concat(superclass.interfaces(context))
76
+ visible_interfaces.uniq!
77
+ visible_interfaces
78
+ end
79
+
80
+ def interface_type_memberships
81
+ own_tms = super
82
+ inherited_tms = superclass.interface_type_memberships
83
+ if inherited_tms.size > 0
84
+ own_tms + inherited_tms
85
+ else
86
+ own_tms
87
+ end
88
+ end
89
+ end
59
90
  end
60
91
 
61
92
  # param context [Query::Context] If omitted, skip filtering.
@@ -63,24 +94,34 @@ module GraphQL
63
94
  warden = Warden.from_context(context)
64
95
  visible_interfaces = []
65
96
  own_interface_type_memberships.each do |type_membership|
66
- # During initialization, `type_memberships` can hold late-bound types
67
97
  case type_membership
68
- when String, Schema::LateBoundType
69
- visible_interfaces << type_membership
70
98
  when Schema::TypeMembership
71
99
  if warden.visible_type_membership?(type_membership, context)
72
100
  visible_interfaces << type_membership.abstract_type
73
101
  end
102
+ when String, Schema::LateBoundType
103
+ # During initialization, `type_memberships` can hold late-bound types
104
+ visible_interfaces << type_membership
74
105
  else
75
106
  raise "Invariant: Unexpected type_membership #{type_membership.class}: #{type_membership.inspect}"
76
107
  end
77
108
  end
109
+ visible_interfaces.uniq!
78
110
 
79
- if self.is_a?(Class) && superclass <= GraphQL::Schema::Object
80
- visible_interfaces.concat(superclass.interfaces(context))
81
- end
111
+ visible_interfaces
112
+ end
82
113
 
83
- visible_interfaces.uniq
114
+ private
115
+
116
+ def self.extended(child_class)
117
+ child_class.extend(ClassConfigured)
118
+ end
119
+
120
+ def inherited(subclass)
121
+ super
122
+ subclass.class_eval do
123
+ @own_interface_type_memberships ||= nil
124
+ end
84
125
  end
85
126
  end
86
127
  end
@@ -3,7 +3,7 @@ module GraphQL
3
3
  class Schema
4
4
  class Member
5
5
  module HasValidators
6
- include Schema::FindInheritedValue::EmptyObjects
6
+ include GraphQL::EmptyObjects
7
7
 
8
8
  # Build {GraphQL::Schema::Validator}s based on the given configuration
9
9
  # and use them for this schema member
@@ -18,12 +18,38 @@ module GraphQL
18
18
 
19
19
  # @return [Array<GraphQL::Schema::Validator>]
20
20
  def validators
21
- own_validators = @own_validators || EMPTY_ARRAY
22
- if self.is_a?(Class) && superclass.respond_to?(:validators) && (inherited_validators = superclass.validators).any?
23
- inherited_validators + own_validators
24
- else
25
- own_validators
21
+ @own_validators || EMPTY_ARRAY
22
+ end
23
+
24
+ module ClassConfigured
25
+ def inherited(child_cls)
26
+ super
27
+ child_cls.extend(ClassValidators)
26
28
  end
29
+
30
+ module ClassValidators
31
+ include GraphQL::EmptyObjects
32
+
33
+ def validators
34
+ inherited_validators = superclass.validators
35
+ if inherited_validators.any?
36
+ if @own_validators.nil?
37
+ inherited_validators
38
+ else
39
+ inherited_validators + @own_validators
40
+ end
41
+ elsif @own_validators.nil?
42
+ EMPTY_ARRAY
43
+ else
44
+ @own_validators
45
+ end
46
+ end
47
+ end
48
+ end
49
+
50
+ def self.extended(child_cls)
51
+ super
52
+ child_cls.extend(ClassConfigured)
27
53
  end
28
54
  end
29
55
  end
@@ -6,6 +6,7 @@ module GraphQL
6
6
  module RelayShortcuts
7
7
  def edge_type_class(new_edge_type_class = nil)
8
8
  if new_edge_type_class
9
+ initialize_relay_metadata
9
10
  @edge_type_class = new_edge_type_class
10
11
  else
11
12
  # Don't call `ancestor.edge_type_class`
@@ -22,6 +23,7 @@ module GraphQL
22
23
 
23
24
  def connection_type_class(new_connection_type_class = nil)
24
25
  if new_connection_type_class
26
+ initialize_relay_metadata
25
27
  @connection_type_class = new_connection_type_class
26
28
  else
27
29
  # Don't call `ancestor.connection_type_class`
@@ -37,6 +39,7 @@ module GraphQL
37
39
  end
38
40
 
39
41
  def edge_type
42
+ initialize_relay_metadata
40
43
  @edge_type ||= begin
41
44
  edge_name = self.graphql_name + "Edge"
42
45
  node_type_class = self
@@ -48,6 +51,7 @@ module GraphQL
48
51
  end
49
52
 
50
53
  def connection_type
54
+ initialize_relay_metadata
51
55
  @connection_type ||= begin
52
56
  conn_name = self.graphql_name + "Connection"
53
57
  edge_type_class = self.edge_type
@@ -67,6 +71,21 @@ module GraphQL
67
71
  def configured_edge_type_class
68
72
  @edge_type_class
69
73
  end
74
+
75
+ attr_writer :edge_type, :connection_type, :connection_type_class, :edge_type_class
76
+
77
+ private
78
+
79
+ # If one of thse values is accessed, initialize all the instance variables to retain
80
+ # a consistent object shape.
81
+ def initialize_relay_metadata
82
+ if !defined?(@connection_type)
83
+ @connection_type = nil
84
+ @edge_type = nil
85
+ @connection_type_class = nil
86
+ @edge_type_class = nil
87
+ end
88
+ end
70
89
  end
71
90
  end
72
91
  end
@@ -4,6 +4,13 @@ module GraphQL
4
4
  class Schema
5
5
  class Member
6
6
  module TypeSystemHelpers
7
+ def initialize(*args, &block)
8
+ super
9
+ @to_non_null_type ||= nil
10
+ @to_list_type ||= nil
11
+ end
12
+ ruby2_keywords :initialize if respond_to?(:ruby2_keywords, true)
13
+
7
14
  # @return [Schema::NonNull] Make a non-null-type representation of this type
8
15
  def to_non_null_type
9
16
  @to_non_null_type ||= GraphQL::Schema::NonNull.new(self)
@@ -32,6 +39,16 @@ module GraphQL
32
39
  def kind
33
40
  raise GraphQL::RequiredImplementationMissingError, "No `.kind` defined for #{self}"
34
41
  end
42
+
43
+ private
44
+
45
+ def inherited(subclass)
46
+ subclass.class_eval do
47
+ @to_non_null_type ||= nil
48
+ @to_list_type ||= nil
49
+ end
50
+ super
51
+ end
35
52
  end
36
53
  end
37
54
  end
@@ -48,9 +48,7 @@ module GraphQL
48
48
  # @return [GraphQL::Schema::Object, GraphQL::Execution::Lazy]
49
49
  # @raise [GraphQL::UnauthorizedError] if the user-provided hook returns `false`
50
50
  def authorized_new(object, context)
51
- trace_payload = { context: context, type: self, object: object, path: context[:current_path] }
52
-
53
- maybe_lazy_auth_val = context.query.trace("authorized", trace_payload) do
51
+ maybe_lazy_auth_val = context.query.current_trace.authorized(query: context.query, type: self, object: object) do
54
52
  begin
55
53
  authorized?(object, context)
56
54
  rescue GraphQL::UnauthorizedError => err
@@ -62,7 +60,7 @@ module GraphQL
62
60
 
63
61
  auth_val = if context.schema.lazy?(maybe_lazy_auth_val)
64
62
  GraphQL::Execution::Lazy.new do
65
- context.query.trace("authorized_lazy", trace_payload) do
63
+ context.query.current_trace.authorized_lazy(query: context.query, type: self, object: object) do
66
64
  context.schema.sync_lazy(maybe_lazy_auth_val)
67
65
  end
68
66
  end
@@ -89,16 +89,16 @@ module GraphQL
89
89
  def generate_payload_type
90
90
  resolver_name = graphql_name
91
91
  resolver_fields = all_field_definitions
92
- Class.new(object_class) do
93
- graphql_name("#{resolver_name}Payload")
94
- description("Autogenerated return type of #{resolver_name}.")
95
- resolver_fields.each do |f|
96
- # Reattach the already-defined field here
97
- # (The field's `.owner` will still point to the mutation, not the object type, I think)
98
- # Don't re-warn about a method conflict. Since this type is generated, it should be fixed in the resolver instead.
99
- add_field(f, method_conflict_warning: false)
100
- end
92
+ pt = Class.new(object_class)
93
+ pt.graphql_name("#{resolver_name}Payload")
94
+ pt.description("Autogenerated return type of #{resolver_name}.")
95
+ resolver_fields.each do |f|
96
+ # Reattach the already-defined field here
97
+ # (The field's `.owner` will still point to the mutation, not the object type, I think)
98
+ # Don't re-warn about a method conflict. Since this type is generated, it should be fixed in the resolver instead.
99
+ pt.add_field(f, method_conflict_warning: false)
101
100
  end
101
+ pt
102
102
  end
103
103
  end
104
104
  end
@@ -311,8 +311,8 @@ module GraphQL
311
311
  # (`nil` means "unlimited max page size".)
312
312
  # @param max_page_size [Integer, nil] Set a new value
313
313
  # @return [Integer, nil] The `max_page_size` assigned to fields that use this resolver
314
- def max_page_size(new_max_page_size = :not_given)
315
- if new_max_page_size != :not_given
314
+ def max_page_size(new_max_page_size = NOT_CONFIGURED)
315
+ if new_max_page_size != NOT_CONFIGURED
316
316
  @max_page_size = new_max_page_size
317
317
  elsif defined?(@max_page_size)
318
318
  @max_page_size
@@ -332,8 +332,8 @@ module GraphQL
332
332
  # (`nil` means "unlimited default page size".)
333
333
  # @param default_page_size [Integer, nil] Set a new value
334
334
  # @return [Integer, nil] The `default_page_size` assigned to fields that use this resolver
335
- def default_page_size(new_default_page_size = :not_given)
336
- if new_default_page_size != :not_given
335
+ def default_page_size(new_default_page_size = NOT_CONFIGURED)
336
+ if new_default_page_size != NOT_CONFIGURED
337
337
  @default_page_size = new_default_page_size
338
338
  elsif defined?(@default_page_size)
339
339
  @default_page_size
@@ -33,60 +33,56 @@ module GraphQL
33
33
  # end
34
34
  #
35
35
  class Timeout
36
- def self.use(schema, **options)
37
- tracer = new(**options)
38
- schema.tracer(tracer)
36
+ def self.use(schema, max_seconds: nil)
37
+ timeout = self.new(max_seconds: max_seconds)
38
+ schema.trace_with(self::Trace, timeout: timeout)
39
39
  end
40
40
 
41
- # @param max_seconds [Numeric] how many seconds the query should be allowed to resolve new fields
42
41
  def initialize(max_seconds:)
43
42
  @max_seconds = max_seconds
44
43
  end
45
44
 
46
- def trace(key, data)
47
- case key
48
- when 'execute_multiplex'
49
- data.fetch(:multiplex).queries.each do |query|
50
- timeout_duration_s = max_seconds(query)
45
+ module Trace
46
+ # @param max_seconds [Numeric] how many seconds the query should be allowed to resolve new fields
47
+ def initialize(timeout:, **rest)
48
+ @timeout = timeout
49
+ super
50
+ end
51
+
52
+ def execute_multiplex(multiplex:)
53
+ multiplex.queries.each do |query|
54
+ timeout_duration_s = @timeout.max_seconds(query)
51
55
  timeout_state = if timeout_duration_s == false
52
56
  # if the method returns `false`, don't apply a timeout
53
57
  false
54
58
  else
55
59
  now = Process.clock_gettime(Process::CLOCK_MONOTONIC, :millisecond)
56
- timeout_at = now + (max_seconds(query) * 1000)
60
+ timeout_at = now + (timeout_duration_s * 1000)
57
61
  {
58
62
  timeout_at: timeout_at,
59
63
  timed_out: false
60
64
  }
61
65
  end
62
- query.context.namespace(self.class)[:state] = timeout_state
66
+ query.context.namespace(@timeout)[:state] = timeout_state
63
67
  end
68
+ super
69
+ end
64
70
 
65
- yield
66
- when 'execute_field', 'execute_field_lazy'
67
- query_context = data[:context] || data[:query].context
68
- timeout_state = query_context.namespace(self.class).fetch(:state)
71
+ def execute_field(query:, field:, **_rest)
72
+ timeout_state = query.context.namespace(@timeout).fetch(:state)
69
73
  # If the `:state` is `false`, then `max_seconds(query)` opted out of timeout for this query.
70
74
  if timeout_state != false && Process.clock_gettime(Process::CLOCK_MONOTONIC, :millisecond) > timeout_state.fetch(:timeout_at)
71
- error = if data[:context]
72
- GraphQL::Schema::Timeout::TimeoutError.new(query_context.parent_type, query_context.field)
73
- else
74
- field = data.fetch(:field)
75
- GraphQL::Schema::Timeout::TimeoutError.new(field.owner, field)
76
- end
77
-
75
+ error = GraphQL::Schema::Timeout::TimeoutError.new(field)
78
76
  # Only invoke the timeout callback for the first timeout
79
77
  if !timeout_state[:timed_out]
80
78
  timeout_state[:timed_out] = true
81
- handle_timeout(error, query_context.query)
79
+ @timeout.handle_timeout(error, query)
82
80
  end
83
81
 
84
82
  error
85
83
  else
86
- yield
84
+ super
87
85
  end
88
- else
89
- yield
90
86
  end
91
87
  end
92
88
 
@@ -114,8 +110,8 @@ module GraphQL
114
110
  # to take this error and raise a new one which _doesn't_ descend from {GraphQL::ExecutionError},
115
111
  # such as `RuntimeError`.
116
112
  class TimeoutError < GraphQL::ExecutionError
117
- def initialize(parent_type, field)
118
- super("Timeout on #{parent_type.graphql_name}.#{field.graphql_name}")
113
+ def initialize(field)
114
+ super("Timeout on #{field.path}")
119
115
  end
120
116
  end
121
117
  end
@@ -102,7 +102,7 @@ module GraphQL
102
102
 
103
103
  self.all_validators = {}
104
104
 
105
- include Schema::FindInheritedValue::EmptyObjects
105
+ include GraphQL::EmptyObjects
106
106
 
107
107
  class ValidationFailedError < GraphQL::ExecutionError
108
108
  attr_reader :errors