graphql 2.5.22 → 2.5.24
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.
- checksums.yaml +4 -4
- data/lib/graphql/analysis.rb +20 -13
- data/lib/graphql/execution/field_resolve_step.rb +631 -0
- data/lib/graphql/execution/finalize.rb +217 -0
- data/lib/graphql/execution/input_values.rb +261 -0
- data/lib/graphql/execution/interpreter/handles_raw_value.rb +6 -0
- data/lib/graphql/execution/interpreter/runtime.rb +3 -2
- data/lib/graphql/execution/interpreter.rb +6 -9
- data/lib/graphql/execution/lazy.rb +1 -1
- data/lib/graphql/execution/load_argument_step.rb +64 -0
- data/lib/graphql/execution/next.rb +26 -6
- data/lib/graphql/execution/prepare_object_step.rb +128 -0
- data/lib/graphql/execution/runner.rb +410 -0
- data/lib/graphql/execution/selections_step.rb +91 -0
- data/lib/graphql/execution.rb +8 -5
- data/lib/graphql/execution_error.rb +5 -1
- data/lib/graphql/query/context.rb +7 -1
- data/lib/graphql/query/partial.rb +18 -3
- data/lib/graphql/query.rb +10 -1
- data/lib/graphql/runtime_error.rb +6 -0
- data/lib/graphql/schema/directive.rb +23 -9
- data/lib/graphql/schema/field/connection_extension.rb +2 -15
- data/lib/graphql/schema/field/scope_extension.rb +0 -4
- data/lib/graphql/schema/field.rb +23 -24
- data/lib/graphql/schema/field_extension.rb +11 -41
- data/lib/graphql/schema/interface.rb +26 -0
- data/lib/graphql/schema/list.rb +5 -1
- data/lib/graphql/schema/member/base_dsl_methods.rb +0 -10
- data/lib/graphql/schema/member/has_fields.rb +5 -1
- data/lib/graphql/schema/non_null.rb +1 -1
- data/lib/graphql/schema/resolver.rb +18 -3
- data/lib/graphql/schema/subscription.rb +0 -2
- data/lib/graphql/schema/visibility/profile.rb +68 -49
- data/lib/graphql/schema/wrapper.rb +7 -1
- data/lib/graphql/schema.rb +12 -10
- data/lib/graphql/static_validation/base_visitor.rb +90 -66
- data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +1 -1
- data/lib/graphql/static_validation/rules/argument_names_are_unique.rb +18 -6
- data/lib/graphql/static_validation/rules/arguments_are_defined.rb +5 -2
- data/lib/graphql/static_validation/rules/directives_are_defined.rb +5 -2
- data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +4 -3
- data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +12 -2
- data/lib/graphql/static_validation/rules/fields_will_merge.rb +322 -256
- data/lib/graphql/static_validation/rules/fields_will_merge_error.rb +4 -4
- data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +3 -3
- data/lib/graphql/static_validation/rules/fragment_types_exist.rb +10 -7
- data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +27 -7
- data/lib/graphql/static_validation/rules/variables_are_input_types.rb +12 -9
- data/lib/graphql/static_validation/validation_context.rb +1 -1
- data/lib/graphql/subscriptions/default_subscription_resolve_extension.rb +34 -10
- data/lib/graphql/subscriptions/event.rb +1 -0
- data/lib/graphql/subscriptions.rb +35 -0
- data/lib/graphql/tracing/perfetto_trace.rb +2 -2
- data/lib/graphql/tracing/trace.rb +6 -0
- data/lib/graphql/unauthorized_error.rb +4 -0
- data/lib/graphql/version.rb +1 -1
- data/lib/graphql.rb +1 -3
- metadata +11 -8
- data/lib/graphql/execution/next/field_resolve_step.rb +0 -711
- data/lib/graphql/execution/next/load_argument_step.rb +0 -60
- data/lib/graphql/execution/next/prepare_object_step.rb +0 -129
- data/lib/graphql/execution/next/runner.rb +0 -389
- data/lib/graphql/execution/next/selections_step.rb +0 -37
|
@@ -32,6 +32,7 @@ module GraphQL
|
|
|
32
32
|
@multiplex = nil
|
|
33
33
|
@result_values = nil
|
|
34
34
|
@result = nil
|
|
35
|
+
@finalizers = @top_level_finalizers = nil
|
|
35
36
|
|
|
36
37
|
if fragment_node
|
|
37
38
|
@ast_nodes = [fragment_node]
|
|
@@ -51,6 +52,10 @@ module GraphQL
|
|
|
51
52
|
@leaf
|
|
52
53
|
end
|
|
53
54
|
|
|
55
|
+
def root_value
|
|
56
|
+
object
|
|
57
|
+
end
|
|
58
|
+
|
|
54
59
|
attr_reader :context, :query, :ast_nodes, :root_type, :object, :field_definition, :path, :schema
|
|
55
60
|
|
|
56
61
|
attr_accessor :multiplex, :result_values
|
|
@@ -90,10 +95,22 @@ module GraphQL
|
|
|
90
95
|
@query.fragments
|
|
91
96
|
end
|
|
92
97
|
|
|
98
|
+
def validate
|
|
99
|
+
@query.validate
|
|
100
|
+
end
|
|
101
|
+
|
|
93
102
|
def valid?
|
|
94
103
|
@query.valid?
|
|
95
104
|
end
|
|
96
105
|
|
|
106
|
+
def query?
|
|
107
|
+
true
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def run_partials(...)
|
|
111
|
+
@query.run_partials(...)
|
|
112
|
+
end
|
|
113
|
+
|
|
97
114
|
def analyzers
|
|
98
115
|
EmptyObjects::EMPTY_ARRAY
|
|
99
116
|
end
|
|
@@ -107,7 +124,7 @@ module GraphQL
|
|
|
107
124
|
end
|
|
108
125
|
|
|
109
126
|
def selected_operation
|
|
110
|
-
ast_nodes.
|
|
127
|
+
Language::Nodes::OperationDefinition.new(selections: ast_nodes.flat_map(&:selections))
|
|
111
128
|
end
|
|
112
129
|
|
|
113
130
|
def static_errors
|
|
@@ -123,7 +140,6 @@ module GraphQL
|
|
|
123
140
|
def set_type_info_from_path
|
|
124
141
|
selections = [@query.selected_operation]
|
|
125
142
|
type = @query.root_type
|
|
126
|
-
parent_type = nil
|
|
127
143
|
field_defn = nil
|
|
128
144
|
|
|
129
145
|
@path.each do |name_in_doc|
|
|
@@ -162,7 +178,6 @@ module GraphQL
|
|
|
162
178
|
end
|
|
163
179
|
field_name = next_selections.first.name
|
|
164
180
|
field_defn = @schema.get_field(type, field_name, @query.context) || raise("Invariant: no field called #{field_name} on #{type.graphql_name}")
|
|
165
|
-
parent_type = type
|
|
166
181
|
type = field_defn.type
|
|
167
182
|
if type.non_null?
|
|
168
183
|
type = type.of_type
|
data/lib/graphql/query.rb
CHANGED
|
@@ -159,6 +159,7 @@ module GraphQL
|
|
|
159
159
|
@root_value = root_value
|
|
160
160
|
@fragments = nil
|
|
161
161
|
@operations = nil
|
|
162
|
+
@finalizers = @top_level_finalizers = nil
|
|
162
163
|
@validate = validate
|
|
163
164
|
self.static_validator = static_validator if static_validator
|
|
164
165
|
context_tracers = (context ? context.fetch(:tracers, []) : [])
|
|
@@ -262,6 +263,10 @@ module GraphQL
|
|
|
262
263
|
with_prepared_ast { @operations }
|
|
263
264
|
end
|
|
264
265
|
|
|
266
|
+
def path
|
|
267
|
+
EmptyObjects::EMPTY_ARRAY
|
|
268
|
+
end
|
|
269
|
+
|
|
265
270
|
# Run subtree partials of this query and return their results.
|
|
266
271
|
# Each partial is identified with a `path:` and `object:`
|
|
267
272
|
# where the path references a field in the AST and the object will be treated
|
|
@@ -271,7 +276,11 @@ module GraphQL
|
|
|
271
276
|
# @return [Array<GraphQL::Query::Result>]
|
|
272
277
|
def run_partials(partials_hashes)
|
|
273
278
|
partials = partials_hashes.map { |partial_options| Partial.new(query: self, **partial_options) }
|
|
274
|
-
|
|
279
|
+
if context[:__graphql_execute_next]
|
|
280
|
+
Execution::Next.run_all(@schema, partials, context: @context)
|
|
281
|
+
else
|
|
282
|
+
Execution::Interpreter.run_all(@schema, partials, context: @context)
|
|
283
|
+
end
|
|
275
284
|
end
|
|
276
285
|
|
|
277
286
|
# Get the result for this query, executing it once
|
|
@@ -31,17 +31,25 @@ module GraphQL
|
|
|
31
31
|
|
|
32
32
|
def locations(*new_locations)
|
|
33
33
|
if !new_locations.empty?
|
|
34
|
+
is_runtime = false
|
|
34
35
|
new_locations.each do |new_loc|
|
|
35
|
-
|
|
36
|
+
loc_sym = new_loc.to_sym
|
|
37
|
+
if !LOCATIONS.include?(loc_sym)
|
|
36
38
|
raise ArgumentError, "#{self} (#{self.graphql_name}) has an invalid directive location: `locations #{new_loc}` "
|
|
37
39
|
end
|
|
40
|
+
is_runtime ||= RUNTIME_LOCATIONS.include?(loc_sym)
|
|
38
41
|
end
|
|
39
42
|
@locations = new_locations
|
|
43
|
+
@is_runtime = is_runtime
|
|
40
44
|
else
|
|
41
45
|
@locations ||= (superclass.respond_to?(:locations) ? superclass.locations : [])
|
|
42
46
|
end
|
|
43
47
|
end
|
|
44
48
|
|
|
49
|
+
def runtime?
|
|
50
|
+
@is_runtime
|
|
51
|
+
end
|
|
52
|
+
|
|
45
53
|
def default_directive(new_default_directive = nil)
|
|
46
54
|
if new_default_directive != nil
|
|
47
55
|
@default_directive = new_default_directive
|
|
@@ -104,8 +112,12 @@ module GraphQL
|
|
|
104
112
|
|
|
105
113
|
def inherited(subclass)
|
|
106
114
|
super
|
|
115
|
+
parent_class = self
|
|
107
116
|
subclass.class_exec do
|
|
108
117
|
@default_graphql_name ||= nil
|
|
118
|
+
@locations = parent_class.locations
|
|
119
|
+
@is_runtime = parent_class.runtime?
|
|
120
|
+
@repeatable = false
|
|
109
121
|
end
|
|
110
122
|
end
|
|
111
123
|
end
|
|
@@ -177,13 +189,16 @@ module GraphQL
|
|
|
177
189
|
end
|
|
178
190
|
|
|
179
191
|
LOCATIONS = [
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
192
|
+
*(RUNTIME_LOCATIONS = [
|
|
193
|
+
QUERY = :QUERY,
|
|
194
|
+
MUTATION = :MUTATION,
|
|
195
|
+
SUBSCRIPTION = :SUBSCRIPTION,
|
|
196
|
+
FIELD = :FIELD,
|
|
197
|
+
FRAGMENT_DEFINITION = :FRAGMENT_DEFINITION,
|
|
198
|
+
FRAGMENT_SPREAD = :FRAGMENT_SPREAD,
|
|
199
|
+
INLINE_FRAGMENT = :INLINE_FRAGMENT,
|
|
200
|
+
VARIABLE_DEFINITION = :VARIABLE_DEFINITION,
|
|
201
|
+
]),
|
|
187
202
|
SCHEMA = :SCHEMA,
|
|
188
203
|
SCALAR = :SCALAR,
|
|
189
204
|
OBJECT = :OBJECT,
|
|
@@ -195,7 +210,6 @@ module GraphQL
|
|
|
195
210
|
ENUM_VALUE = :ENUM_VALUE,
|
|
196
211
|
INPUT_OBJECT = :INPUT_OBJECT,
|
|
197
212
|
INPUT_FIELD_DEFINITION = :INPUT_FIELD_DEFINITION,
|
|
198
|
-
VARIABLE_DEFINITION = :VARIABLE_DEFINITION,
|
|
199
213
|
]
|
|
200
214
|
|
|
201
215
|
DEFAULT_DEPRECATION_REASON = 'No longer supported'
|
|
@@ -12,22 +12,13 @@ module GraphQL
|
|
|
12
12
|
end
|
|
13
13
|
|
|
14
14
|
# Remove pagination args before passing it to a user method
|
|
15
|
-
def resolve(object
|
|
15
|
+
def resolve(object: nil, objects: nil, arguments:, context:)
|
|
16
16
|
next_args = arguments.dup
|
|
17
17
|
next_args.delete(:first)
|
|
18
18
|
next_args.delete(:last)
|
|
19
19
|
next_args.delete(:before)
|
|
20
20
|
next_args.delete(:after)
|
|
21
|
-
yield(object, next_args, arguments)
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
def resolve_next(objects:, arguments:, context:)
|
|
25
|
-
next_args = arguments.dup
|
|
26
|
-
next_args.delete(:first)
|
|
27
|
-
next_args.delete(:last)
|
|
28
|
-
next_args.delete(:before)
|
|
29
|
-
next_args.delete(:after)
|
|
30
|
-
yield(objects, next_args, arguments)
|
|
21
|
+
yield(object || objects, next_args, arguments)
|
|
31
22
|
end
|
|
32
23
|
|
|
33
24
|
def after_resolve(value:, object:, arguments:, context:, memo:)
|
|
@@ -36,10 +27,6 @@ module GraphQL
|
|
|
36
27
|
context.schema.connections.populate_connection(field, object.object, resolved_value, original_arguments, context)
|
|
37
28
|
end
|
|
38
29
|
end
|
|
39
|
-
|
|
40
|
-
def after_resolve_next(**kwargs)
|
|
41
|
-
raise "This should never be called -- it's hardcoded in execution instead."
|
|
42
|
-
end
|
|
43
30
|
end
|
|
44
31
|
end
|
|
45
32
|
end
|
data/lib/graphql/schema/field.rb
CHANGED
|
@@ -270,32 +270,32 @@ module GraphQL
|
|
|
270
270
|
@resolver_method = (resolver_method || name_s).to_sym
|
|
271
271
|
|
|
272
272
|
if resolve_static
|
|
273
|
-
@
|
|
274
|
-
@
|
|
273
|
+
@execution_mode = :resolve_static
|
|
274
|
+
@execution_mode_key = resolve_static == true ? @method_sym : resolve_static
|
|
275
275
|
elsif resolve_batch
|
|
276
|
-
@
|
|
277
|
-
@
|
|
276
|
+
@execution_mode = :resolve_batch
|
|
277
|
+
@execution_mode_key = resolve_batch == true ? @method_sym : resolve_batch
|
|
278
278
|
elsif resolve_each
|
|
279
|
-
@
|
|
280
|
-
@
|
|
279
|
+
@execution_mode = :resolve_each
|
|
280
|
+
@execution_mode_key = resolve_each == true ? @method_sym : resolve_each
|
|
281
281
|
elsif hash_key
|
|
282
|
-
@
|
|
283
|
-
@
|
|
282
|
+
@execution_mode = :hash_key
|
|
283
|
+
@execution_mode_key = hash_key
|
|
284
284
|
elsif dig
|
|
285
|
-
@
|
|
286
|
-
@
|
|
285
|
+
@execution_mode = :dig
|
|
286
|
+
@execution_mode_key = dig
|
|
287
287
|
elsif resolver_class
|
|
288
|
-
@
|
|
289
|
-
@
|
|
288
|
+
@execution_mode = :resolver_class
|
|
289
|
+
@execution_mode_key = resolver_class
|
|
290
290
|
elsif resolve_legacy_instance_method
|
|
291
|
-
@
|
|
292
|
-
@
|
|
291
|
+
@execution_mode = :resolve_legacy_instance_method
|
|
292
|
+
@execution_mode_key = resolve_legacy_instance_method == true ? @method_sym : resolve_legacy_instance_method
|
|
293
293
|
elsif dataload
|
|
294
|
-
@
|
|
295
|
-
@
|
|
294
|
+
@execution_mode = :dataload
|
|
295
|
+
@execution_mode_key = dataload
|
|
296
296
|
else
|
|
297
|
-
@
|
|
298
|
-
@
|
|
297
|
+
@execution_mode = :direct_send
|
|
298
|
+
@execution_mode_key = @method_sym
|
|
299
299
|
end
|
|
300
300
|
|
|
301
301
|
@complexity = complexity
|
|
@@ -369,7 +369,7 @@ module GraphQL
|
|
|
369
369
|
end
|
|
370
370
|
|
|
371
371
|
# @api private
|
|
372
|
-
attr_reader :
|
|
372
|
+
attr_reader :execution_mode_key, :execution_mode
|
|
373
373
|
|
|
374
374
|
# Calls the definition block, if one was given.
|
|
375
375
|
# This is deferred so that references to the return type
|
|
@@ -665,10 +665,9 @@ module GraphQL
|
|
|
665
665
|
end
|
|
666
666
|
|
|
667
667
|
def authorizes?(context)
|
|
668
|
-
method(:authorized?).owner != GraphQL::Schema::Field ||
|
|
669
|
-
(args = context.types.arguments(self)) &&
|
|
670
|
-
|
|
671
|
-
)
|
|
668
|
+
method(:authorized?).owner != GraphQL::Schema::Field ||
|
|
669
|
+
((args = context.types.arguments(self)) && (args.any? { |a| a.authorizes?(context) })) ||
|
|
670
|
+
(@resolver_class&.authorizes?(context)) || false
|
|
672
671
|
end
|
|
673
672
|
|
|
674
673
|
def authorized?(object, args, context)
|
|
@@ -930,7 +929,7 @@ ERR
|
|
|
930
929
|
def run_next_extensions_before_resolve(objs, args, ctx, extended, idx: 0, &block)
|
|
931
930
|
extension = @extensions[idx]
|
|
932
931
|
if extension
|
|
933
|
-
extension.
|
|
932
|
+
extension.resolve(objects: objs, arguments: args, context: ctx) do |extended_objs, extended_args, memo|
|
|
934
933
|
if memo
|
|
935
934
|
memos = extended.memos ||= {}
|
|
936
935
|
memos[idx] = memo
|
|
@@ -123,33 +123,16 @@ module GraphQL
|
|
|
123
123
|
#
|
|
124
124
|
# Whatever this method returns will be used for execution.
|
|
125
125
|
#
|
|
126
|
-
# @param object [Object] The object the field is being resolved on
|
|
126
|
+
# @param object [Object] The object the field is being resolved on (not passed by new execution)
|
|
127
|
+
# @param objects [Array<Object>] The objects the field is being resolved on (passed by new execution)
|
|
127
128
|
# @param arguments [Hash] Ruby keyword arguments for resolving this field
|
|
128
129
|
# @param context [Query::Context] the context for this query
|
|
129
|
-
# @yieldparam
|
|
130
|
+
# @yieldparam object_or_objects [Object, Array<Object>] The object or objects (new execution) to continue resolving the field on
|
|
130
131
|
# @yieldparam arguments [Hash] The keyword arguments to continue resolving with
|
|
131
132
|
# @yieldparam memo [Object] Any extension-specific value which will be passed to {#after_resolve} later
|
|
132
133
|
# @return [Object] The return value for this field.
|
|
133
|
-
def resolve(object
|
|
134
|
-
yield(object, arguments, nil)
|
|
135
|
-
end
|
|
136
|
-
|
|
137
|
-
# Called before batch-resolving {#field}. It should either:
|
|
138
|
-
#
|
|
139
|
-
# - `yield` values to continue execution; OR
|
|
140
|
-
# - return something else to shortcut field execution.
|
|
141
|
-
#
|
|
142
|
-
# Whatever this method returns will be used for execution.
|
|
143
|
-
#
|
|
144
|
-
# @param objects [Array<Object>] The objects the field is being resolved on
|
|
145
|
-
# @param arguments [Hash] Ruby keyword arguments for resolving this field
|
|
146
|
-
# @param context [Query::Context] the context for this query
|
|
147
|
-
# @yieldparam objects [Array<Object>] The objects to continue resolving the field on. Length must be the same as passed-in `objects:`
|
|
148
|
-
# @yieldparam arguments [Hash] The keyword arguments to continue resolving with
|
|
149
|
-
# @yieldparam memo [Object] Any extension-specific value which will be passed to {#after_resolve} later
|
|
150
|
-
# @return [Array<Object>] The return value for this field, length matching passed-in `objects:`.
|
|
151
|
-
def resolve_next(objects:, arguments:, context:)
|
|
152
|
-
yield(objects, arguments, nil)
|
|
134
|
+
def resolve(object: nil, objects: nil, arguments:, context:)
|
|
135
|
+
yield(object || objects, arguments, nil)
|
|
153
136
|
end
|
|
154
137
|
|
|
155
138
|
# Called after {#field} was resolved, and after any lazy values (like `Promise`s) were synced,
|
|
@@ -157,29 +140,16 @@ module GraphQL
|
|
|
157
140
|
#
|
|
158
141
|
# Whatever this hook returns will be used as the return value.
|
|
159
142
|
#
|
|
160
|
-
# @param object [Object] The object the field is being resolved on
|
|
143
|
+
# @param object [Object] The object the field is being resolved on (not passed by new execution)
|
|
144
|
+
# @param objects [Array<Object>] The object the field is being resolved on (passed by new execution)
|
|
161
145
|
# @param arguments [Hash] Ruby keyword arguments for resolving this field
|
|
162
146
|
# @param context [Query::Context] the context for this query
|
|
163
|
-
# @param value [Object] Whatever the field previously returned
|
|
147
|
+
# @param value [Object] Whatever the field previously returned (not passed by new execution)
|
|
148
|
+
# @param values [Array<Object>] Whatever the field previously returned (passed by new execution)
|
|
164
149
|
# @param memo [Object] The third value yielded by {#resolve}, or `nil` if there wasn't one
|
|
165
150
|
# @return [Object] The return value for this field.
|
|
166
|
-
def after_resolve(object
|
|
167
|
-
value
|
|
168
|
-
end
|
|
169
|
-
|
|
170
|
-
# Called after {#field} was batch-resolved, and after any lazy values (like `Promise`s) were synced,
|
|
171
|
-
# but before the value was added to the GraphQL response.
|
|
172
|
-
#
|
|
173
|
-
# Whatever this hook returns will be used as the return value.
|
|
174
|
-
#
|
|
175
|
-
# @param objects [Array<Object>] The objects the field is being resolved on
|
|
176
|
-
# @param arguments [Hash] Ruby keyword arguments for resolving this field
|
|
177
|
-
# @param context [Query::Context] the context for this query
|
|
178
|
-
# @param values [Array<Object>] Whatever the field returned, one for each of `objects`
|
|
179
|
-
# @param memo [Object] The third value yielded by {#resolve}, or `nil` if there wasn't one
|
|
180
|
-
# @return [Array<Object>] The return values for this field, length matching `objects:`.
|
|
181
|
-
def after_resolve_next(objects:, arguments:, context:, values:, memo:)
|
|
182
|
-
values
|
|
151
|
+
def after_resolve(object: nil, objects: nil, arguments:, context:, values: nil, value: nil, memo:)
|
|
152
|
+
value || values
|
|
183
153
|
end
|
|
184
154
|
end
|
|
185
155
|
end
|
|
@@ -33,6 +33,26 @@ module GraphQL
|
|
|
33
33
|
self::DefinitionMethods.module_exec(&block)
|
|
34
34
|
end
|
|
35
35
|
|
|
36
|
+
# Instance methods defined in this block will become class methods on objects that implement this interface.
|
|
37
|
+
# Use it to implement `resolve_each:`, `resolve_batch:`, and `resolve_static:` fields.
|
|
38
|
+
# @example
|
|
39
|
+
# field :thing, String, resolve_static: true
|
|
40
|
+
#
|
|
41
|
+
# resolver_methods do
|
|
42
|
+
# def thing
|
|
43
|
+
# Somehow.get.thing
|
|
44
|
+
# end
|
|
45
|
+
# end
|
|
46
|
+
def resolver_methods(&block)
|
|
47
|
+
if !defined?(@_resolver_methods)
|
|
48
|
+
resolver_methods_module = Module.new
|
|
49
|
+
@_resolver_methods = resolver_methods_module
|
|
50
|
+
const_set(:ResolverMethods, resolver_methods_module)
|
|
51
|
+
extend(self::ResolverMethods)
|
|
52
|
+
end
|
|
53
|
+
self::ResolverMethods.module_exec(&block)
|
|
54
|
+
end
|
|
55
|
+
|
|
36
56
|
# @see {Schema::Warden} hides interfaces without visible implementations
|
|
37
57
|
def visible?(context)
|
|
38
58
|
true
|
|
@@ -79,6 +99,12 @@ module GraphQL
|
|
|
79
99
|
if !backtrace_line
|
|
80
100
|
raise "Attach interfaces using `implements(#{self})`, not `include(#{self})`"
|
|
81
101
|
end
|
|
102
|
+
|
|
103
|
+
child_class.ancestors.reverse_each do |ancestor|
|
|
104
|
+
if ancestor.const_defined?(:ResolverMethods)
|
|
105
|
+
child_class.extend(ancestor::ResolverMethods)
|
|
106
|
+
end
|
|
107
|
+
end
|
|
82
108
|
end
|
|
83
109
|
|
|
84
110
|
super
|
data/lib/graphql/schema/list.rb
CHANGED
|
@@ -19,7 +19,11 @@ module GraphQL
|
|
|
19
19
|
end
|
|
20
20
|
|
|
21
21
|
def to_type_signature
|
|
22
|
-
"[#{@of_type.to_type_signature}]"
|
|
22
|
+
@type_signature ||= -"[#{@of_type.to_type_signature}]"
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def authorizes?(ctx)
|
|
26
|
+
of_type.authorizes?(ctx)
|
|
23
27
|
end
|
|
24
28
|
|
|
25
29
|
# This is for introspection, where it's expected the name will be `null`
|
|
@@ -26,16 +26,6 @@ module GraphQL
|
|
|
26
26
|
end
|
|
27
27
|
end
|
|
28
28
|
|
|
29
|
-
# Just a convenience method to point out that people should use graphql_name instead
|
|
30
|
-
def name(new_name = nil)
|
|
31
|
-
return super() if new_name.nil?
|
|
32
|
-
|
|
33
|
-
fail(
|
|
34
|
-
"The new name override method is `graphql_name`, not `name`. Usage: "\
|
|
35
|
-
"graphql_name \"#{new_name}\""
|
|
36
|
-
)
|
|
37
|
-
end
|
|
38
|
-
|
|
39
29
|
# Call this method to provide a new description; OR
|
|
40
30
|
# call it without an argument to get the description
|
|
41
31
|
# @param new_description [String]
|
|
@@ -150,10 +150,14 @@ module GraphQL
|
|
|
150
150
|
|
|
151
151
|
def global_id_field(field_name, **kwargs)
|
|
152
152
|
type = self
|
|
153
|
-
field field_name, "ID", **kwargs, null: false
|
|
153
|
+
field field_name, "ID", **kwargs, null: false, resolve_each: true
|
|
154
154
|
define_method(field_name) do
|
|
155
155
|
context.schema.id_from_object(object, type, context)
|
|
156
156
|
end
|
|
157
|
+
|
|
158
|
+
define_singleton_method(field_name) do |object, context|
|
|
159
|
+
context.schema.id_from_object(object, type, context)
|
|
160
|
+
end
|
|
157
161
|
end
|
|
158
162
|
|
|
159
163
|
# @param new_has_no_fields [Boolean] Call with `true` to make this Object type ignore the requirement to have any defined fields.
|
|
@@ -46,7 +46,7 @@ module GraphQL
|
|
|
46
46
|
@prepared_arguments = nil
|
|
47
47
|
end
|
|
48
48
|
|
|
49
|
-
attr_accessor :exec_result, :exec_index, :field_resolve_step
|
|
49
|
+
attr_accessor :exec_result, :exec_index, :field_resolve_step, :raw_arguments
|
|
50
50
|
|
|
51
51
|
# @return [Object] The application object this field is being resolved on
|
|
52
52
|
attr_accessor :object
|
|
@@ -66,7 +66,12 @@ module GraphQL
|
|
|
66
66
|
q = context.query
|
|
67
67
|
trace_objs = [object]
|
|
68
68
|
q.current_trace.begin_execute_field(field, @prepared_arguments, trace_objs, q)
|
|
69
|
-
|
|
69
|
+
begin
|
|
70
|
+
is_authed, new_return_value = authorized?(**@prepared_arguments)
|
|
71
|
+
rescue GraphQL::UnauthorizedError => err
|
|
72
|
+
new_return_value = q.schema.unauthorized_object(err)
|
|
73
|
+
is_authed = true # the error was handled
|
|
74
|
+
end
|
|
70
75
|
|
|
71
76
|
if (runner = @field_resolve_step.runner).resolves_lazies && runner.schema.lazy?(is_authed)
|
|
72
77
|
is_authed, new_return_value = runner.schema.sync_lazy(is_authed)
|
|
@@ -74,13 +79,19 @@ module GraphQL
|
|
|
74
79
|
|
|
75
80
|
result = if is_authed
|
|
76
81
|
Schema::Validator.validate!(self.class.validators, object, context, @prepared_arguments, as: @field)
|
|
82
|
+
if q.subscription? && @field.owner == context.schema.subscription
|
|
83
|
+
# This needs to use arguments without `loads:`. TODO extract this into subscription-related code somehow?
|
|
84
|
+
@original_arguments = @field_resolve_step.runner.input_values[q].argument_values(@field, @field_resolve_step.ast_node.arguments, nil)
|
|
85
|
+
end
|
|
77
86
|
call_resolve(@prepared_arguments)
|
|
87
|
+
elsif new_return_value.nil?
|
|
88
|
+
err = UnauthorizedFieldError.new(object: object, type: @field_resolve_step.parent_type, context: context, field: @field)
|
|
89
|
+
context.schema.unauthorized_field(err)
|
|
78
90
|
else
|
|
79
91
|
new_return_value
|
|
80
92
|
end
|
|
81
93
|
q = context.query
|
|
82
94
|
q.current_trace.end_execute_field(field, @prepared_arguments, trace_objs, q, [result])
|
|
83
|
-
|
|
84
95
|
exec_result[exec_index] = result
|
|
85
96
|
rescue RuntimeError => err
|
|
86
97
|
exec_result[exec_index] = err
|
|
@@ -198,6 +209,10 @@ module GraphQL
|
|
|
198
209
|
authorize_arguments(args, inputs)
|
|
199
210
|
end
|
|
200
211
|
|
|
212
|
+
def self.authorizes?(context)
|
|
213
|
+
self.instance_method(:authorized?).owner != GraphQL::Schema::Resolver
|
|
214
|
+
end
|
|
215
|
+
|
|
201
216
|
# Called when an object loaded by `loads:` fails the `.authorized?` check for its resolved GraphQL object type.
|
|
202
217
|
#
|
|
203
218
|
# By default, the error is re-raised and passed along to {{Schema.unauthorized_object}}.
|
|
@@ -15,8 +15,6 @@ module GraphQL
|
|
|
15
15
|
extend GraphQL::Schema::Resolver::HasPayloadType
|
|
16
16
|
extend GraphQL::Schema::Member::HasFields
|
|
17
17
|
NO_UPDATE = :no_update
|
|
18
|
-
# The generated payload type is required; If there's no payload,
|
|
19
|
-
# propagate null.
|
|
20
18
|
null false
|
|
21
19
|
|
|
22
20
|
# @api private
|