graphql 2.0.16 → 2.0.18
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/graphql/analysis/ast/visitor.rb +42 -35
- data/lib/graphql/analysis/ast.rb +2 -2
- data/lib/graphql/backtrace/tracer.rb +1 -1
- data/lib/graphql/execution/interpreter/resolve.rb +19 -0
- data/lib/graphql/execution/interpreter/runtime.rb +106 -88
- data/lib/graphql/execution/interpreter.rb +14 -9
- data/lib/graphql/execution/lazy.rb +6 -12
- data/lib/graphql/execution/multiplex.rb +2 -1
- data/lib/graphql/graphql_ext.bundle +0 -0
- data/lib/graphql/introspection/directive_type.rb +2 -2
- data/lib/graphql/introspection/field_type.rb +1 -1
- data/lib/graphql/introspection/schema_type.rb +2 -2
- data/lib/graphql/introspection/type_type.rb +5 -5
- data/lib/graphql/language/lexer.rb +216 -1505
- data/lib/graphql/language/lexer.ri +744 -0
- data/lib/graphql/language/nodes.rb +39 -31
- data/lib/graphql/language/parser.rb +9 -9
- data/lib/graphql/language/parser.y +9 -9
- data/lib/graphql/language/visitor.rb +191 -83
- data/lib/graphql/pagination/active_record_relation_connection.rb +0 -8
- data/lib/graphql/query/context.rb +45 -11
- data/lib/graphql/query.rb +15 -2
- data/lib/graphql/schema/argument.rb +0 -4
- data/lib/graphql/schema/directive.rb +12 -2
- data/lib/graphql/schema/enum.rb +24 -17
- data/lib/graphql/schema/enum_value.rb +5 -3
- data/lib/graphql/schema/field.rb +53 -45
- data/lib/graphql/schema/interface.rb +0 -10
- data/lib/graphql/schema/late_bound_type.rb +2 -0
- data/lib/graphql/schema/member/base_dsl_methods.rb +15 -14
- data/lib/graphql/schema/member/has_arguments.rb +104 -57
- data/lib/graphql/schema/member/has_deprecation_reason.rb +3 -4
- data/lib/graphql/schema/member/has_fields.rb +14 -2
- data/lib/graphql/schema/member/has_interfaces.rb +49 -8
- data/lib/graphql/schema/member/has_validators.rb +31 -5
- data/lib/graphql/schema/member/type_system_helpers.rb +17 -0
- data/lib/graphql/schema/object.rb +2 -4
- data/lib/graphql/schema/resolver/has_payload_type.rb +9 -9
- data/lib/graphql/schema/timeout.rb +23 -27
- data/lib/graphql/schema/warden.rb +26 -4
- data/lib/graphql/schema.rb +37 -19
- data/lib/graphql/static_validation/literal_validator.rb +15 -1
- data/lib/graphql/static_validation/validator.rb +1 -1
- data/lib/graphql/subscriptions/event.rb +2 -7
- data/lib/graphql/tracing/active_support_notifications_trace.rb +16 -0
- data/lib/graphql/tracing/appoptics_trace.rb +231 -0
- data/lib/graphql/tracing/appsignal_trace.rb +66 -0
- data/lib/graphql/tracing/data_dog_trace.rb +148 -0
- data/lib/graphql/tracing/new_relic_trace.rb +75 -0
- data/lib/graphql/tracing/notifications_trace.rb +41 -0
- data/lib/graphql/tracing/platform_trace.rb +107 -0
- data/lib/graphql/tracing/platform_tracing.rb +15 -3
- data/lib/graphql/tracing/prometheus_trace.rb +89 -0
- data/lib/graphql/tracing/prometheus_tracing.rb +3 -3
- data/lib/graphql/tracing/scout_trace.rb +72 -0
- data/lib/graphql/tracing/statsd_trace.rb +56 -0
- data/lib/graphql/tracing.rb +136 -39
- data/lib/graphql/type_kinds.rb +6 -3
- data/lib/graphql/types/relay/connection_behaviors.rb +0 -4
- data/lib/graphql/types/relay/edge_behaviors.rb +0 -4
- data/lib/graphql/types/string.rb +1 -1
- data/lib/graphql/version.rb +1 -1
- data/lib/graphql.rb +7 -8
- metadata +15 -4
- data/lib/graphql/language/lexer.rl +0 -280
@@ -11,6 +11,7 @@ module GraphQL
|
|
11
11
|
def self.extended(cls)
|
12
12
|
cls.extend(ArgumentClassAccessor)
|
13
13
|
cls.include(ArgumentObjectLoader)
|
14
|
+
cls.extend(ClassConfigured)
|
14
15
|
end
|
15
16
|
|
16
17
|
# @see {GraphQL::Schema::Argument#initialize} for parameters
|
@@ -109,14 +110,6 @@ module GraphQL
|
|
109
110
|
|
110
111
|
# @return [Hash<String => GraphQL::Schema::Argument] Arguments defined on this thing, keyed by name. Includes inherited definitions
|
111
112
|
def arguments(context = GraphQL::Query::NullContext)
|
112
|
-
inherited_arguments = if self.is_a?(Class) && superclass.respond_to?(:arguments)
|
113
|
-
superclass.arguments(context)
|
114
|
-
elsif defined?(@resolver_class) && @resolver_class
|
115
|
-
@resolver_class.field_arguments(context)
|
116
|
-
else
|
117
|
-
nil
|
118
|
-
end
|
119
|
-
# Local definitions override inherited ones
|
120
113
|
if own_arguments.any?
|
121
114
|
own_arguments_that_apply = {}
|
122
115
|
own_arguments.each do |name, args_entry|
|
@@ -125,47 +118,107 @@ module GraphQL
|
|
125
118
|
end
|
126
119
|
end
|
127
120
|
end
|
121
|
+
# might be nil if there are actually no arguments
|
122
|
+
own_arguments_that_apply || own_arguments
|
123
|
+
end
|
128
124
|
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
125
|
+
module ClassConfigured
|
126
|
+
def inherited(child_class)
|
127
|
+
super
|
128
|
+
child_class.extend(InheritedArguments)
|
129
|
+
end
|
130
|
+
|
131
|
+
module InheritedArguments
|
132
|
+
def arguments(context = GraphQL::Query::NullContext)
|
133
|
+
own_arguments = super
|
134
|
+
inherited_arguments = superclass.arguments(context)
|
135
|
+
|
136
|
+
if own_arguments.any?
|
137
|
+
if inherited_arguments.any?
|
138
|
+
# Local definitions override inherited ones
|
139
|
+
inherited_arguments.merge(own_arguments)
|
140
|
+
else
|
141
|
+
own_arguments
|
142
|
+
end
|
143
|
+
else
|
144
|
+
inherited_arguments
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
def all_argument_definitions
|
149
|
+
all_defns = {}
|
150
|
+
ancestors.reverse_each do |ancestor|
|
151
|
+
if ancestor.respond_to?(:own_arguments)
|
152
|
+
all_defns.merge!(ancestor.own_arguments)
|
153
|
+
end
|
154
|
+
end
|
155
|
+
all_defns = all_defns.values
|
156
|
+
all_defns.flatten!
|
157
|
+
all_defns
|
158
|
+
end
|
159
|
+
|
160
|
+
|
161
|
+
def get_argument(argument_name, context = GraphQL::Query::NullContext)
|
162
|
+
warden = Warden.from_context(context)
|
163
|
+
for ancestor in ancestors
|
164
|
+
if ancestor.respond_to?(:own_arguments) &&
|
165
|
+
(a = ancestor.own_arguments[argument_name]) &&
|
166
|
+
(a = Warden.visible_entry?(:visible_argument?, a, context, warden))
|
167
|
+
return a
|
168
|
+
end
|
169
|
+
end
|
170
|
+
nil
|
134
171
|
end
|
135
|
-
else
|
136
|
-
# might be nil if there are actually no arguments
|
137
|
-
own_arguments_that_apply || own_arguments
|
138
172
|
end
|
139
173
|
end
|
140
174
|
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
175
|
+
module FieldConfigured
|
176
|
+
def arguments(context = GraphQL::Query::NullContext)
|
177
|
+
own_arguments = super
|
178
|
+
if defined?(@resolver_class) && @resolver_class
|
179
|
+
inherited_arguments = @resolver_class.field_arguments(context)
|
180
|
+
if own_arguments.any?
|
181
|
+
if inherited_arguments.any?
|
182
|
+
inherited_arguments.merge(own_arguments)
|
183
|
+
else
|
184
|
+
own_arguments
|
185
|
+
end
|
186
|
+
else
|
187
|
+
inherited_arguments
|
147
188
|
end
|
189
|
+
else
|
190
|
+
own_arguments
|
148
191
|
end
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
192
|
+
end
|
193
|
+
|
194
|
+
def all_argument_definitions
|
195
|
+
if defined?(@resolver_class) && @resolver_class
|
196
|
+
all_defns = {}
|
197
|
+
@resolver_class.all_field_argument_definitions.each do |arg_defn|
|
198
|
+
key = arg_defn.graphql_name
|
199
|
+
case (current_value = all_defns[key])
|
200
|
+
when nil
|
201
|
+
all_defns[key] = arg_defn
|
202
|
+
when Array
|
203
|
+
current_value << arg_defn
|
204
|
+
when GraphQL::Schema::Argument
|
205
|
+
all_defns[key] = [current_value, arg_defn]
|
206
|
+
else
|
207
|
+
raise "Invariant: Unexpected argument definition, #{current_value.class}: #{current_value.inspect}"
|
208
|
+
end
|
162
209
|
end
|
210
|
+
all_defns.merge!(own_arguments)
|
211
|
+
all_defns = all_defns.values
|
212
|
+
all_defns.flatten!
|
213
|
+
all_defns
|
214
|
+
else
|
215
|
+
super
|
163
216
|
end
|
164
|
-
all_defns.merge!(own_arguments)
|
165
|
-
else
|
166
|
-
all_defns = own_arguments
|
167
217
|
end
|
168
|
-
|
218
|
+
end
|
219
|
+
|
220
|
+
def all_argument_definitions
|
221
|
+
all_defns = own_arguments.values
|
169
222
|
all_defns.flatten!
|
170
223
|
all_defns
|
171
224
|
end
|
@@ -173,22 +226,11 @@ module GraphQL
|
|
173
226
|
# @return [GraphQL::Schema::Argument, nil] Argument defined on this thing, fetched by name.
|
174
227
|
def get_argument(argument_name, context = GraphQL::Query::NullContext)
|
175
228
|
warden = Warden.from_context(context)
|
176
|
-
if
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
@resolver_class.get_field_argument(argument_name, context)
|
181
|
-
else
|
182
|
-
nil
|
183
|
-
end
|
229
|
+
if (arg_config = own_arguments[argument_name]) && (visible_arg = Warden.visible_entry?(:visible_argument?, arg_config, context, warden))
|
230
|
+
visible_arg
|
231
|
+
elsif defined?(@resolver_class) && @resolver_class
|
232
|
+
@resolver_class.get_field_argument(argument_name, context)
|
184
233
|
else
|
185
|
-
for ancestor in ancestors
|
186
|
-
if ancestor.respond_to?(:own_arguments) &&
|
187
|
-
(a = ancestor.own_arguments[argument_name]) &&
|
188
|
-
(a = Warden.visible_entry?(:visible_argument?, a, context, warden))
|
189
|
-
return a
|
190
|
-
end
|
191
|
-
end
|
192
234
|
nil
|
193
235
|
end
|
194
236
|
end
|
@@ -209,7 +251,7 @@ module GraphQL
|
|
209
251
|
# @return [Interpreter::Arguments, Execution::Lazy<Interpeter::Arguments>]
|
210
252
|
def coerce_arguments(parent_object, values, context, &block)
|
211
253
|
# Cache this hash to avoid re-merging it
|
212
|
-
arg_defns =
|
254
|
+
arg_defns = context.warden.arguments(self)
|
213
255
|
total_args_count = arg_defns.size
|
214
256
|
|
215
257
|
finished_args = nil
|
@@ -223,7 +265,7 @@ module GraphQL
|
|
223
265
|
argument_values = {}
|
224
266
|
resolved_args_count = 0
|
225
267
|
raised_error = false
|
226
|
-
arg_defns.each do |
|
268
|
+
arg_defns.each do |arg_defn|
|
227
269
|
context.dataloader.append_job do
|
228
270
|
begin
|
229
271
|
arg_defn.coerce_into_values(parent_object, values, context, argument_values)
|
@@ -265,7 +307,12 @@ module GraphQL
|
|
265
307
|
# but not for directives.
|
266
308
|
# TODO apply static validations on schema definitions?
|
267
309
|
def validate_directive_argument(arg_defn, value)
|
268
|
-
|
310
|
+
# this is only implemented on directives.
|
311
|
+
nil
|
312
|
+
end
|
313
|
+
|
314
|
+
module HasDirectiveArguments
|
315
|
+
def validate_directive_argument(arg_defn, value)
|
269
316
|
if value.nil? && arg_defn.type.non_null?
|
270
317
|
raise ArgumentError, "#{arg_defn.path} is required, but no value was given"
|
271
318
|
end
|
@@ -5,17 +5,16 @@ module GraphQL
|
|
5
5
|
class Member
|
6
6
|
module HasDeprecationReason
|
7
7
|
# @return [String, nil] Explains why this member was deprecated (if present, this will be marked deprecated in introspection)
|
8
|
-
|
9
|
-
dir = self.directives.find { |d| d.is_a?(GraphQL::Schema::Directive::Deprecated) }
|
10
|
-
dir && dir.arguments[:reason] # rubocop:disable Development/ContextIsPassedCop -- definition-related
|
11
|
-
end
|
8
|
+
attr_reader :deprecation_reason
|
12
9
|
|
13
10
|
# Set the deprecation reason for this member, or remove it by assigning `nil`
|
14
11
|
# @param text [String, nil]
|
15
12
|
def deprecation_reason=(text)
|
13
|
+
@deprecation_reason = text
|
16
14
|
if text.nil?
|
17
15
|
remove_directive(GraphQL::Schema::Directive::Deprecated)
|
18
16
|
else
|
17
|
+
# This removes a previously-attached directive, if there is one:
|
19
18
|
directive(GraphQL::Schema::Directive::Deprecated, reason: text)
|
20
19
|
end
|
21
20
|
end
|
@@ -72,7 +72,12 @@ module GraphQL
|
|
72
72
|
def add_field(field_defn, method_conflict_warning: field_defn.method_conflict_warning?)
|
73
73
|
# Check that `field_defn.original_name` equals `resolver_method` and `method_sym` --
|
74
74
|
# that shows that no override value was given manually.
|
75
|
-
if method_conflict_warning &&
|
75
|
+
if method_conflict_warning &&
|
76
|
+
CONFLICT_FIELD_NAMES.include?(field_defn.resolver_method) &&
|
77
|
+
field_defn.original_name == field_defn.resolver_method &&
|
78
|
+
field_defn.original_name == field_defn.method_sym &&
|
79
|
+
field_defn.hash_key == NOT_CONFIGURED &&
|
80
|
+
field_defn.dig_keys.nil?
|
76
81
|
warn(conflict_field_name_warning(field_defn))
|
77
82
|
end
|
78
83
|
prev_defn = own_fields[field_defn.name]
|
@@ -129,12 +134,19 @@ module GraphQL
|
|
129
134
|
|
130
135
|
private
|
131
136
|
|
137
|
+
def inherited(subclass)
|
138
|
+
super
|
139
|
+
subclass.class_eval do
|
140
|
+
@own_fields ||= nil
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
132
144
|
# If `type` is an interface, and `self` has a type membership for `type`, then make sure it's visible.
|
133
145
|
def visible_interface_implementation?(type, context, warden)
|
134
146
|
if type.respond_to?(:kind) && type.kind.interface?
|
135
147
|
implements_this_interface = false
|
136
148
|
implementation_is_visible = false
|
137
|
-
interface_type_memberships.each do |tm|
|
149
|
+
warden.interface_type_memberships(self, context).each do |tm|
|
138
150
|
if tm.abstract_type == type
|
139
151
|
implements_this_interface ||= true
|
140
152
|
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
|
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
|
-
|
80
|
-
|
81
|
-
end
|
111
|
+
visible_interfaces
|
112
|
+
end
|
82
113
|
|
83
|
-
|
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
|
@@ -18,12 +18,38 @@ module GraphQL
|
|
18
18
|
|
19
19
|
# @return [Array<GraphQL::Schema::Validator>]
|
20
20
|
def validators
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
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 Schema::FindInheritedValue::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
|
@@ -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
|
+
super
|
47
|
+
subclass.class_eval do
|
48
|
+
@to_non_null_type ||= nil
|
49
|
+
@to_list_type ||= nil
|
50
|
+
end
|
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
|
-
|
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.
|
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)
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
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
|
@@ -33,60 +33,56 @@ module GraphQL
|
|
33
33
|
# end
|
34
34
|
#
|
35
35
|
class Timeout
|
36
|
-
def self.use(schema,
|
37
|
-
|
38
|
-
schema.
|
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
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
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 + (
|
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(
|
66
|
+
query.context.namespace(@timeout)[:state] = timeout_state
|
63
67
|
end
|
68
|
+
super
|
69
|
+
end
|
64
70
|
|
65
|
-
|
66
|
-
|
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 =
|
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,
|
79
|
+
@timeout.handle_timeout(error, query)
|
82
80
|
end
|
83
81
|
|
84
82
|
error
|
85
83
|
else
|
86
84
|
yield
|
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(
|
118
|
-
super("Timeout on #{
|
113
|
+
def initialize(field)
|
114
|
+
super("Timeout on #{field.path}")
|
119
115
|
end
|
120
116
|
end
|
121
117
|
end
|
@@ -80,6 +80,8 @@ module GraphQL
|
|
80
80
|
def visible_type?(type, ctx); type.visible?(ctx); end
|
81
81
|
def visible_enum_value?(ev, ctx); ev.visible?(ctx); end
|
82
82
|
def visible_type_membership?(tm, ctx); tm.visible?(ctx); end
|
83
|
+
def interface_type_memberships(obj_t, ctx); obj_t.interface_type_memberships; end
|
84
|
+
def arguments(owner, ctx); owner.arguments(ctx); end
|
83
85
|
end
|
84
86
|
end
|
85
87
|
|
@@ -94,6 +96,13 @@ module GraphQL
|
|
94
96
|
@subscription = @schema.subscription
|
95
97
|
@context = context
|
96
98
|
@visibility_cache = read_through { |m| filter.call(m, context) }
|
99
|
+
# Initialize all ivars to improve object shape consistency:
|
100
|
+
@types = @visible_types = @reachable_types = @visible_parent_fields =
|
101
|
+
@visible_possible_types = @visible_fields = @visible_arguments = @visible_enum_arrays =
|
102
|
+
@visible_enum_values = @visible_interfaces = @type_visibility = @type_memberships =
|
103
|
+
@visible_and_reachable_type = @unions = @unfiltered_interfaces = @references_to =
|
104
|
+
@reachable_type_set =
|
105
|
+
nil
|
97
106
|
end
|
98
107
|
|
99
108
|
# @return [Hash<String, GraphQL::BaseType>] Visible types in the schema
|
@@ -174,14 +183,20 @@ module GraphQL
|
|
174
183
|
|
175
184
|
# @param argument_owner [GraphQL::Field, GraphQL::InputObjectType]
|
176
185
|
# @return [Array<GraphQL::Argument>] Visible arguments on `argument_owner`
|
177
|
-
def arguments(argument_owner)
|
178
|
-
@visible_arguments ||= read_through { |o| o.arguments(@context).each_value.select { |a| visible_argument?(a) } }
|
186
|
+
def arguments(argument_owner, ctx = nil)
|
187
|
+
@visible_arguments ||= read_through { |o| o.arguments(@context).each_value.select { |a| visible_argument?(a, @context) } }
|
179
188
|
@visible_arguments[argument_owner]
|
180
189
|
end
|
181
190
|
|
182
191
|
# @return [Array<GraphQL::EnumType::EnumValue>] Visible members of `enum_defn`
|
183
192
|
def enum_values(enum_defn)
|
184
|
-
@visible_enum_arrays ||= read_through { |e|
|
193
|
+
@visible_enum_arrays ||= read_through { |e|
|
194
|
+
values = e.enum_values(@context)
|
195
|
+
if values.size == 0
|
196
|
+
raise GraphQL::Schema::Enum::MissingValuesError.new(e)
|
197
|
+
end
|
198
|
+
values
|
199
|
+
}
|
185
200
|
@visible_enum_arrays[enum_defn]
|
186
201
|
end
|
187
202
|
|
@@ -233,6 +248,13 @@ module GraphQL
|
|
233
248
|
visible?(type_membership)
|
234
249
|
end
|
235
250
|
|
251
|
+
def interface_type_memberships(obj_type, _ctx = nil)
|
252
|
+
@type_memberships ||= read_through do |obj_t|
|
253
|
+
obj_t.interface_type_memberships
|
254
|
+
end
|
255
|
+
@type_memberships[obj_type]
|
256
|
+
end
|
257
|
+
|
236
258
|
private
|
237
259
|
|
238
260
|
def visible_and_reachable_type?(type_defn)
|
@@ -332,7 +354,7 @@ module GraphQL
|
|
332
354
|
end
|
333
355
|
|
334
356
|
def reachable_type_set
|
335
|
-
return @reachable_type_set if
|
357
|
+
return @reachable_type_set if @reachable_type_set
|
336
358
|
|
337
359
|
@reachable_type_set = Set.new
|
338
360
|
rt_hash = {}
|