graphql 2.5.20 → 2.6.0
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/dashboard/views/layouts/graphql/dashboard/application.html.erb +3 -3
- 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/multiplex.rb +1 -1
- data/lib/graphql/execution/next.rb +90 -0
- 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 -4
- data/lib/graphql/execution_error.rb +5 -1
- data/lib/graphql/introspection/dynamic_fields.rb +5 -1
- data/lib/graphql/introspection/entry_points.rb +5 -1
- data/lib/graphql/pagination/connection.rb +2 -0
- data/lib/graphql/pagination/connections.rb +32 -0
- 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/argument.rb +1 -0
- data/lib/graphql/schema/build_from_definition.rb +22 -25
- data/lib/graphql/schema/directive.rb +23 -9
- data/lib/graphql/schema/field/connection_extension.rb +4 -37
- data/lib/graphql/schema/field/scope_extension.rb +18 -13
- data/lib/graphql/schema/field.rb +59 -62
- data/lib/graphql/schema/field_extension.rb +11 -8
- 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 +1 -11
- data/lib/graphql/schema/member/has_authorization.rb +35 -0
- data/lib/graphql/schema/member/has_dataloader.rb +28 -0
- data/lib/graphql/schema/member/has_fields.rb +11 -5
- data/lib/graphql/schema/member.rb +5 -0
- data/lib/graphql/schema/non_null.rb +1 -1
- data/lib/graphql/schema/object.rb +1 -0
- data/lib/graphql/schema/resolver.rb +80 -0
- 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/types/relay/has_node_field.rb +10 -2
- data/lib/graphql/types/relay/has_nodes_field.rb +10 -2
- data/lib/graphql/types/relay/node_behaviors.rb +13 -2
- data/lib/graphql/unauthorized_error.rb +4 -0
- data/lib/graphql/version.rb +1 -1
- data/lib/graphql.rb +1 -3
- metadata +13 -9
- data/lib/graphql/execution/batching/field_compatibility.rb +0 -150
- data/lib/graphql/execution/batching/field_resolve_step.rb +0 -408
- data/lib/graphql/execution/batching/prepare_object_step.rb +0 -112
- data/lib/graphql/execution/batching/runner.rb +0 -352
- data/lib/graphql/execution/batching/selections_step.rb +0 -37
- data/lib/graphql/execution/batching.rb +0 -62
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
module GraphQL
|
|
3
|
+
module Execution
|
|
4
|
+
class SelectionsStep
|
|
5
|
+
def initialize(parent_type:, selections:, objects:, results:, runner:, query:, path:, clobber: true)
|
|
6
|
+
@path = path
|
|
7
|
+
@parent_type = parent_type
|
|
8
|
+
@selections = selections
|
|
9
|
+
@runner = runner
|
|
10
|
+
@objects = objects
|
|
11
|
+
@results = results
|
|
12
|
+
@query = query
|
|
13
|
+
@graphql_objects = nil
|
|
14
|
+
@all_selections = nil
|
|
15
|
+
@clobber = clobber
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
attr_reader :path, :query, :objects, :results
|
|
19
|
+
|
|
20
|
+
def graphql_objects
|
|
21
|
+
@graphql_objects ||= @objects.map do |obj|
|
|
22
|
+
@parent_type.scoped_new(obj, @query.context)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def call
|
|
27
|
+
@all_selections = [{}, (prototype_result = {})]
|
|
28
|
+
@runner.gather_selections(@parent_type, @selections, self, self.query, @all_selections, @all_selections[1], into: @all_selections[0])
|
|
29
|
+
continue_selections = []
|
|
30
|
+
i = 0
|
|
31
|
+
l = @all_selections.length
|
|
32
|
+
while i < l
|
|
33
|
+
grouped_selections = @all_selections[i]
|
|
34
|
+
selections_prototype_result = @all_selections[i + 1]
|
|
35
|
+
if (directives_owner = grouped_selections.delete(:__node))
|
|
36
|
+
directives = directives_owner.directives
|
|
37
|
+
continue_execution = true
|
|
38
|
+
directives.each do |dir_node|
|
|
39
|
+
dir_defn = @runner.runtime_directives[dir_node.name]
|
|
40
|
+
if dir_defn # not present for `skip` or `include`
|
|
41
|
+
dir_args = @runner.input_values[query].argument_values(dir_defn, dir_node.arguments, nil) # rubocop:disable Development/ContextIsPassedCop
|
|
42
|
+
result = case directives_owner
|
|
43
|
+
when Language::Nodes::FragmentSpread
|
|
44
|
+
dir_defn.resolve_fragment_spread(directives_owner, @parent_type, @objects, dir_args, self.query.context)
|
|
45
|
+
when Language::Nodes::InlineFragment
|
|
46
|
+
dir_defn.resolve_inline_fragment(directives_owner, @parent_type, @objects, dir_args, self.query.context)
|
|
47
|
+
else
|
|
48
|
+
raise ArgumentError, "Unhandled directive owner (#{directives_owner.class}): #{directives_owner.inspect}"
|
|
49
|
+
end
|
|
50
|
+
if result.is_a?(Finalizer)
|
|
51
|
+
result.path = path
|
|
52
|
+
@results.each do |r|
|
|
53
|
+
@runner.add_finalizer(@query, r, nil, result)
|
|
54
|
+
end
|
|
55
|
+
if result.is_a?(HaltExecution)
|
|
56
|
+
continue_execution = false
|
|
57
|
+
break
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
if continue_execution
|
|
62
|
+
prototype_result.merge!(selections_prototype_result)
|
|
63
|
+
grouped_selections.each_value { |v| continue_selections << v }
|
|
64
|
+
end
|
|
65
|
+
else
|
|
66
|
+
grouped_selections.each_value { |v| continue_selections << v }
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
else
|
|
70
|
+
grouped_selections.each_value { |v| continue_selections << v }
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
if @clobber
|
|
74
|
+
i2 = 0
|
|
75
|
+
l2 = @results.length
|
|
76
|
+
while i2 < l2
|
|
77
|
+
@results[i2].replace(prototype_result)
|
|
78
|
+
i2 += 1
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
continue_selections.each do |frs|
|
|
83
|
+
@runner.add_step(frs)
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
i += 2
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
data/lib/graphql/execution.rb
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
require "graphql/execution/directive_checks"
|
|
3
|
+
require "graphql/execution/next"
|
|
3
4
|
require "graphql/execution/interpreter"
|
|
4
5
|
require "graphql/execution/lazy"
|
|
5
6
|
require "graphql/execution/lookahead"
|
|
@@ -9,10 +10,13 @@ require "graphql/execution/errors"
|
|
|
9
10
|
module GraphQL
|
|
10
11
|
module Execution
|
|
11
12
|
# @api private
|
|
12
|
-
class Skip < GraphQL::
|
|
13
|
+
class Skip < GraphQL::RuntimeError
|
|
14
|
+
attr_accessor :path
|
|
15
|
+
def ast_nodes=(_ignored); end
|
|
13
16
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
+
def finalize_graphql_result(query, result_data, key)
|
|
18
|
+
result_data.delete(key)
|
|
19
|
+
end
|
|
20
|
+
end
|
|
17
21
|
end
|
|
18
22
|
end
|
|
@@ -6,7 +6,7 @@ module GraphQL
|
|
|
6
6
|
class ExecutionError < GraphQL::RuntimeError
|
|
7
7
|
# @return [GraphQL::Language::Nodes::Field] the field where the error occurred
|
|
8
8
|
def ast_node
|
|
9
|
-
ast_nodes
|
|
9
|
+
ast_nodes&.first
|
|
10
10
|
end
|
|
11
11
|
|
|
12
12
|
def ast_node=(new_node)
|
|
@@ -36,6 +36,10 @@ module GraphQL
|
|
|
36
36
|
super(message)
|
|
37
37
|
end
|
|
38
38
|
|
|
39
|
+
def finalize_graphql_result(query, result_data, key)
|
|
40
|
+
result_data[key] = nil
|
|
41
|
+
end
|
|
42
|
+
|
|
39
43
|
# @return [Hash] An entry for the response's "errors" key
|
|
40
44
|
def to_h
|
|
41
45
|
hash = {
|
|
@@ -2,9 +2,13 @@
|
|
|
2
2
|
module GraphQL
|
|
3
3
|
module Introspection
|
|
4
4
|
class DynamicFields < Introspection::BaseObject
|
|
5
|
-
field :__typename, String, "The name of this type", null: false, dynamic_introspection: true
|
|
5
|
+
field :__typename, String, "The name of this type", null: false, dynamic_introspection: true, resolve_each: true
|
|
6
6
|
|
|
7
7
|
def __typename
|
|
8
|
+
self.class.__typename(object, context)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def self.__typename(object, context)
|
|
8
12
|
object.class.graphql_name
|
|
9
13
|
end
|
|
10
14
|
end
|
|
@@ -3,7 +3,7 @@ module GraphQL
|
|
|
3
3
|
module Introspection
|
|
4
4
|
class EntryPoints < Introspection::BaseObject
|
|
5
5
|
field :__schema, GraphQL::Schema::LateBoundType.new("__Schema"), "This GraphQL schema", null: false, dynamic_introspection: true, resolve_static: :__schema
|
|
6
|
-
field :__type, GraphQL::Schema::LateBoundType.new("__Type"), "A type in the GraphQL system", dynamic_introspection: true do
|
|
6
|
+
field :__type, GraphQL::Schema::LateBoundType.new("__Type"), "A type in the GraphQL system", dynamic_introspection: true, resolve_static: :__type do
|
|
7
7
|
argument :name, String
|
|
8
8
|
end
|
|
9
9
|
|
|
@@ -19,6 +19,10 @@ module GraphQL
|
|
|
19
19
|
end
|
|
20
20
|
|
|
21
21
|
def __type(name:)
|
|
22
|
+
self.class.__type(context, name: name)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def self.__type(context, name:)
|
|
22
26
|
if context.types.reachable_type?(name) && (type = context.types.type(name))
|
|
23
27
|
type
|
|
24
28
|
elsif (type = context.schema.extra_types.find { |t| t.graphql_name == name })
|
|
@@ -83,6 +83,38 @@ module GraphQL
|
|
|
83
83
|
end
|
|
84
84
|
end
|
|
85
85
|
|
|
86
|
+
def populate_connection(field, object, value, original_arguments, context)
|
|
87
|
+
if value.is_a? GraphQL::ExecutionError
|
|
88
|
+
# This isn't even going to work because context doesn't have ast_node anymore
|
|
89
|
+
context.add_error(value)
|
|
90
|
+
nil
|
|
91
|
+
elsif value.nil?
|
|
92
|
+
nil
|
|
93
|
+
elsif value.is_a?(GraphQL::Pagination::Connection)
|
|
94
|
+
# update the connection with some things that may not have been provided
|
|
95
|
+
value.context ||= context
|
|
96
|
+
value.parent ||= object
|
|
97
|
+
value.first_value ||= original_arguments[:first]
|
|
98
|
+
value.after_value ||= original_arguments[:after]
|
|
99
|
+
value.last_value ||= original_arguments[:last]
|
|
100
|
+
value.before_value ||= original_arguments[:before]
|
|
101
|
+
value.arguments ||= original_arguments # rubocop:disable Development/ContextIsPassedCop -- unrelated .arguments method
|
|
102
|
+
value.field ||= field
|
|
103
|
+
if field.has_max_page_size? && !value.has_max_page_size_override?
|
|
104
|
+
value.max_page_size = field.max_page_size
|
|
105
|
+
end
|
|
106
|
+
if field.has_default_page_size? && !value.has_default_page_size_override?
|
|
107
|
+
value.default_page_size = field.default_page_size
|
|
108
|
+
end
|
|
109
|
+
if (custom_t = context.schema.connections.edge_class_for_field(field))
|
|
110
|
+
value.edge_class = custom_t
|
|
111
|
+
end
|
|
112
|
+
value
|
|
113
|
+
else
|
|
114
|
+
context.namespace(:connections)[:all_wrappers] ||= context.schema.connections.all_wrappers
|
|
115
|
+
context.schema.connections.wrap(field, object, value, original_arguments, context)
|
|
116
|
+
end
|
|
117
|
+
end
|
|
86
118
|
# use an override if there is one
|
|
87
119
|
# @api private
|
|
88
120
|
def edge_class_for_field(field)
|
|
@@ -112,7 +112,7 @@ module GraphQL
|
|
|
112
112
|
# Return this value to tell the runtime
|
|
113
113
|
# to exclude this field from the response altogether
|
|
114
114
|
def skip
|
|
115
|
-
GraphQL::Execution::
|
|
115
|
+
GraphQL::Execution::Skip.new
|
|
116
116
|
end
|
|
117
117
|
|
|
118
118
|
# Add error at query-level.
|
|
@@ -126,6 +126,12 @@ module GraphQL
|
|
|
126
126
|
nil
|
|
127
127
|
end
|
|
128
128
|
|
|
129
|
+
# @param value [Object] Any object to be inserted directly into the final response
|
|
130
|
+
# @return [GraphQL::Execution::Interpreter::RawValue] Return this from the field
|
|
131
|
+
def raw_value(value)
|
|
132
|
+
GraphQL::Execution::Interpreter::RawValue.new(value)
|
|
133
|
+
end
|
|
134
|
+
|
|
129
135
|
# @example Print the GraphQL backtrace during field resolution
|
|
130
136
|
# puts ctx.backtrace
|
|
131
137
|
#
|
|
@@ -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
|
|
@@ -4,6 +4,7 @@ module GraphQL
|
|
|
4
4
|
class Argument
|
|
5
5
|
include GraphQL::Schema::Member::HasPath
|
|
6
6
|
include GraphQL::Schema::Member::HasAstNode
|
|
7
|
+
include GraphQL::Schema::Member::HasAuthorization
|
|
7
8
|
include GraphQL::Schema::Member::HasDirectives
|
|
8
9
|
include GraphQL::Schema::Member::HasDeprecationReason
|
|
9
10
|
include GraphQL::Schema::Member::HasValidators
|
|
@@ -99,6 +99,16 @@ module GraphQL
|
|
|
99
99
|
# It's possible that this was already loaded by the directives
|
|
100
100
|
prev_type = types[definition.name]
|
|
101
101
|
if prev_type.nil? || prev_type.is_a?(Schema::LateBoundType)
|
|
102
|
+
if definition.is_a?(GraphQL::Language::Nodes::ObjectTypeDefinition) || definition.is_a?(Language::Nodes::InterfaceTypeDefinition)
|
|
103
|
+
interface_names = definition.interfaces.map(&:name)
|
|
104
|
+
transitive_names = interface_names.map { |n| document.definitions.find { |d| d.respond_to?(:name) && d.name == n }&.interfaces&.map(&:name) }
|
|
105
|
+
transitive_names.flatten!
|
|
106
|
+
transitive_names.compact!
|
|
107
|
+
if !(missing_transitive_interfaces = transitive_names - interface_names).empty?
|
|
108
|
+
raise GraphQL::Schema::InvalidDocumentError, "type #{definition.name} is missing one or more transitive interface names: #{missing_transitive_interfaces.join(", ")}. Add them to the type's `implements` list and try again."
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
102
112
|
types[definition.name] = build_definition_from_node(definition, type_resolver, default_resolve, base_types)
|
|
103
113
|
end
|
|
104
114
|
end
|
|
@@ -519,35 +529,22 @@ module GraphQL
|
|
|
519
529
|
|
|
520
530
|
# Don't do this for interfaces
|
|
521
531
|
if default_resolve
|
|
522
|
-
define_field_resolve_method(owner, resolve_method_name, field_definition.name
|
|
532
|
+
define_field_resolve_method(owner, resolve_method_name, field_definition.name)
|
|
523
533
|
end
|
|
524
534
|
end
|
|
525
535
|
end
|
|
526
536
|
|
|
527
|
-
def define_field_resolve_method(owner, method_name, field_name
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
}
|
|
539
|
-
else
|
|
540
|
-
owner.define_method(method_name) { |**args|
|
|
541
|
-
field_instance = context.types.field(owner, field_name)
|
|
542
|
-
context.schema.definition_default_resolve.call(self.class, field_instance, object, args, context)
|
|
543
|
-
}
|
|
544
|
-
owner.define_singleton_method(method_name) { |objects, context, **args|
|
|
545
|
-
field_instance = context.types.field(owner, field_name)
|
|
546
|
-
objects.map do |object|
|
|
547
|
-
context.schema.definition_default_resolve.call(self, field_instance, object, args, context)
|
|
548
|
-
end
|
|
549
|
-
}
|
|
550
|
-
end
|
|
537
|
+
def define_field_resolve_method(owner, method_name, field_name)
|
|
538
|
+
owner.define_method(method_name) { |**args|
|
|
539
|
+
field_instance = context.types.field(owner, field_name)
|
|
540
|
+
context.schema.definition_default_resolve.call(self.class, field_instance, object, args, context)
|
|
541
|
+
}
|
|
542
|
+
owner.define_singleton_method(method_name) { |objects, context, **args|
|
|
543
|
+
field_instance = context.types.field(owner, field_name)
|
|
544
|
+
objects.map do |object|
|
|
545
|
+
context.schema.definition_default_resolve.call(self, field_instance, object, args, context)
|
|
546
|
+
end
|
|
547
|
+
}
|
|
551
548
|
end
|
|
552
549
|
|
|
553
550
|
def build_resolve_type(lookup_hash, directives, missing_type_handler)
|
|
@@ -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,52 +12,19 @@ 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)
|
|
21
|
+
yield(object || objects, next_args, arguments)
|
|
22
22
|
end
|
|
23
23
|
|
|
24
24
|
def after_resolve(value:, object:, arguments:, context:, memo:)
|
|
25
25
|
original_arguments = memo
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
value = nil
|
|
29
|
-
context.query.after_lazy(maybe_lazy) do |resolved_value|
|
|
30
|
-
value = resolved_value
|
|
31
|
-
if value.is_a? GraphQL::ExecutionError
|
|
32
|
-
# This isn't even going to work because context doesn't have ast_node anymore
|
|
33
|
-
context.add_error(value)
|
|
34
|
-
nil
|
|
35
|
-
elsif value.nil?
|
|
36
|
-
nil
|
|
37
|
-
elsif value.is_a?(GraphQL::Pagination::Connection)
|
|
38
|
-
# update the connection with some things that may not have been provided
|
|
39
|
-
value.context ||= context
|
|
40
|
-
value.parent ||= object.object
|
|
41
|
-
value.first_value ||= original_arguments[:first]
|
|
42
|
-
value.after_value ||= original_arguments[:after]
|
|
43
|
-
value.last_value ||= original_arguments[:last]
|
|
44
|
-
value.before_value ||= original_arguments[:before]
|
|
45
|
-
value.arguments ||= original_arguments # rubocop:disable Development/ContextIsPassedCop -- unrelated .arguments method
|
|
46
|
-
value.field ||= field
|
|
47
|
-
if field.has_max_page_size? && !value.has_max_page_size_override?
|
|
48
|
-
value.max_page_size = field.max_page_size
|
|
49
|
-
end
|
|
50
|
-
if field.has_default_page_size? && !value.has_default_page_size_override?
|
|
51
|
-
value.default_page_size = field.default_page_size
|
|
52
|
-
end
|
|
53
|
-
if (custom_t = context.schema.connections.edge_class_for_field(@field))
|
|
54
|
-
value.edge_class = custom_t
|
|
55
|
-
end
|
|
56
|
-
value
|
|
57
|
-
else
|
|
58
|
-
context.namespace(:connections)[:all_wrappers] ||= context.schema.connections.all_wrappers
|
|
59
|
-
context.schema.connections.wrap(field, object.object, value, original_arguments, context)
|
|
60
|
-
end
|
|
26
|
+
context.query.after_lazy(value) do |resolved_value|
|
|
27
|
+
context.schema.connections.populate_connection(field, object.object, resolved_value, original_arguments, context)
|
|
61
28
|
end
|
|
62
29
|
end
|
|
63
30
|
end
|
|
@@ -5,22 +5,27 @@ module GraphQL
|
|
|
5
5
|
class Field
|
|
6
6
|
class ScopeExtension < GraphQL::Schema::FieldExtension
|
|
7
7
|
def after_resolve(object:, arguments:, context:, value:, memo:)
|
|
8
|
-
if
|
|
9
|
-
value
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
if (
|
|
16
|
-
|
|
17
|
-
|
|
8
|
+
if object.is_a?(GraphQL::Schema::Object)
|
|
9
|
+
if value.nil?
|
|
10
|
+
value
|
|
11
|
+
else
|
|
12
|
+
return_type = field.type.unwrap
|
|
13
|
+
if return_type.respond_to?(:scope_items)
|
|
14
|
+
scoped_items = return_type.scope_items(value, context)
|
|
15
|
+
if !scoped_items.equal?(value) && !return_type.reauthorize_scoped_objects
|
|
16
|
+
if (current_runtime_state = Fiber[:__graphql_runtime_info]) &&
|
|
17
|
+
(query_runtime_state = current_runtime_state[context.query])
|
|
18
|
+
query_runtime_state.was_authorized_by_scope_items = true
|
|
19
|
+
end
|
|
18
20
|
end
|
|
21
|
+
scoped_items
|
|
22
|
+
else
|
|
23
|
+
value
|
|
19
24
|
end
|
|
20
|
-
scoped_items
|
|
21
|
-
else
|
|
22
|
-
value
|
|
23
25
|
end
|
|
26
|
+
else
|
|
27
|
+
# TODO skip this entirely?
|
|
28
|
+
value
|
|
24
29
|
end
|
|
25
30
|
end
|
|
26
31
|
end
|