graphql 2.5.20 → 2.5.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.
- checksums.yaml +4 -4
- data/lib/graphql/dashboard/views/layouts/graphql/dashboard/application.html.erb +3 -3
- data/lib/graphql/execution/multiplex.rb +1 -1
- data/lib/graphql/execution/next/field_resolve_step.rb +690 -0
- data/lib/graphql/execution/next/load_argument_step.rb +60 -0
- data/lib/graphql/execution/{batching → next}/prepare_object_step.rb +26 -9
- data/lib/graphql/execution/{batching → next}/runner.rb +65 -28
- data/lib/graphql/execution/{batching → next}/selections_step.rb +1 -1
- data/lib/graphql/execution/{batching.rb → next.rb} +19 -12
- data/lib/graphql/execution.rb +1 -0
- 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/schema/argument.rb +1 -0
- data/lib/graphql/schema/build_from_definition.rb +12 -25
- data/lib/graphql/schema/field/connection_extension.rb +15 -35
- data/lib/graphql/schema/field/scope_extension.rb +22 -13
- data/lib/graphql/schema/field.rb +52 -58
- data/lib/graphql/schema/field_extension.rb +33 -0
- data/lib/graphql/schema/member/base_dsl_methods.rb +1 -1
- data/lib/graphql/schema/member/has_authorization.rb +35 -0
- data/lib/graphql/schema/member/has_dataloader.rb +8 -0
- data/lib/graphql/schema/member/has_fields.rb +5 -4
- data/lib/graphql/schema/member.rb +5 -0
- data/lib/graphql/schema/object.rb +1 -0
- data/lib/graphql/schema/resolver.rb +42 -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/version.rb +1 -1
- metadata +9 -8
- data/lib/graphql/execution/batching/field_compatibility.rb +0 -150
- data/lib/graphql/execution/batching/field_resolve_step.rb +0 -408
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
module GraphQL
|
|
3
|
+
module Execution
|
|
4
|
+
module Next
|
|
5
|
+
class LoadArgumentStep
|
|
6
|
+
def initialize(field_resolve_step:, arguments:, load_receiver:, argument_value:, argument_definition:, argument_key:)
|
|
7
|
+
@field_resolve_step = field_resolve_step
|
|
8
|
+
@load_receiver = load_receiver
|
|
9
|
+
@arguments = arguments
|
|
10
|
+
@argument_value = argument_value
|
|
11
|
+
@argument_definition = argument_definition
|
|
12
|
+
@argument_key = argument_key
|
|
13
|
+
@loaded_value = nil
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def value
|
|
17
|
+
@loaded_value = @field_resolve_step.sync(@loaded_value)
|
|
18
|
+
assign_value
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def call
|
|
22
|
+
context = @field_resolve_step.selections_step.query.context
|
|
23
|
+
@loaded_value = @load_receiver.load_and_authorize_application_object(@argument_definition, @argument_value, context)
|
|
24
|
+
if (runner = @field_resolve_step.runner).resolves_lazies && runner.lazy?(@loaded_value)
|
|
25
|
+
runner.dataloader.lazy_at_depth(@field_resolve_step.path.size, self)
|
|
26
|
+
else
|
|
27
|
+
assign_value
|
|
28
|
+
end
|
|
29
|
+
rescue GraphQL::RuntimeError => err
|
|
30
|
+
@loaded_value = err
|
|
31
|
+
assign_value
|
|
32
|
+
rescue StandardError => stderr
|
|
33
|
+
@loaded_value = begin
|
|
34
|
+
context.query.handle_or_reraise(stderr)
|
|
35
|
+
rescue GraphQL::ExecutionError => ex_err
|
|
36
|
+
ex_err
|
|
37
|
+
end
|
|
38
|
+
assign_value
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
private
|
|
42
|
+
|
|
43
|
+
def assign_value
|
|
44
|
+
if @loaded_value.is_a?(GraphQL::Error)
|
|
45
|
+
@loaded_value.path = @field_resolve_step.path
|
|
46
|
+
@field_resolve_step.arguments = @loaded_value
|
|
47
|
+
else
|
|
48
|
+
@arguments[@argument_key] = @loaded_value
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
field_pending_steps = @field_resolve_step.pending_steps
|
|
52
|
+
field_pending_steps.delete(self)
|
|
53
|
+
if @field_resolve_step.arguments && field_pending_steps.size == 0 # rubocop:disable Development/ContextIsPassedCop
|
|
54
|
+
@field_resolve_step.runner.add_step(@field_resolve_step)
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
module GraphQL
|
|
3
3
|
module Execution
|
|
4
|
-
module
|
|
4
|
+
module Next
|
|
5
5
|
class PrepareObjectStep
|
|
6
6
|
def initialize(static_type:, object:, runner:, graphql_result:, key:, is_non_null:, field_resolve_step:, next_objects:, next_results:, is_from_array:)
|
|
7
7
|
@static_type = static_type
|
|
@@ -22,9 +22,15 @@ module GraphQL
|
|
|
22
22
|
|
|
23
23
|
def value
|
|
24
24
|
if @authorized_value
|
|
25
|
+
query = @field_resolve_step.selections_step.query
|
|
26
|
+
query.current_trace.begin_authorized(@resolved_type, @object, query.context)
|
|
25
27
|
@authorized_value = @field_resolve_step.sync(@authorized_value)
|
|
28
|
+
query.current_trace.end_authorized(@resolved_type, @object, query.context, @authorized_value)
|
|
26
29
|
elsif @resolved_type
|
|
30
|
+
ctx = @field_resolve_step.selections_step.query.context
|
|
31
|
+
ctx.query.current_trace.begin_resolve_type(@static_type, @object, ctx)
|
|
27
32
|
@resolved_type, _ignored_value = @field_resolve_step.sync(@resolved_type)
|
|
33
|
+
ctx.query.current_trace.end_resolve_type(@static_type, @object, ctx, @resolved_type)
|
|
28
34
|
end
|
|
29
35
|
@runner.add_step(self)
|
|
30
36
|
end
|
|
@@ -33,11 +39,14 @@ module GraphQL
|
|
|
33
39
|
case @next_step
|
|
34
40
|
when :resolve_type
|
|
35
41
|
if @static_type.kind.abstract?
|
|
36
|
-
|
|
42
|
+
ctx = @field_resolve_step.selections_step.query.context
|
|
43
|
+
ctx.query.current_trace.begin_resolve_type(@static_type, @object, ctx)
|
|
44
|
+
@resolved_type, _ignored_value = @runner.schema.resolve_type(@static_type, @object, ctx)
|
|
45
|
+
ctx.query.current_trace.end_resolve_type(@static_type, @object, ctx, @resolved_type)
|
|
37
46
|
else
|
|
38
47
|
@resolved_type = @static_type
|
|
39
48
|
end
|
|
40
|
-
if @runner.resolves_lazies && @runner.
|
|
49
|
+
if @runner.resolves_lazies && @runner.lazy?(@resolved_type)
|
|
41
50
|
@next_step = :authorize
|
|
42
51
|
@runner.dataloader.lazy_at_depth(@field_resolve_step.path.size, self)
|
|
43
52
|
else
|
|
@@ -53,14 +62,22 @@ module GraphQL
|
|
|
53
62
|
end
|
|
54
63
|
|
|
55
64
|
def authorize
|
|
56
|
-
|
|
65
|
+
if @field_resolve_step.was_scoped && !@resolved_type.reauthorize_scoped_objects
|
|
66
|
+
@authorized_value = @object
|
|
67
|
+
create_result
|
|
68
|
+
return
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
query = @field_resolve_step.selections_step.query
|
|
57
72
|
begin
|
|
58
|
-
@
|
|
73
|
+
query.current_trace.begin_authorized(@resolved_type, @object, query.context)
|
|
74
|
+
@authorized_value = @resolved_type.authorized?(@object, query.context)
|
|
75
|
+
query.current_trace.end_authorized(@resolve_type, @object, query.context, @authorized_value)
|
|
59
76
|
rescue GraphQL::UnauthorizedError => auth_err
|
|
60
77
|
@authorization_error = auth_err
|
|
61
78
|
end
|
|
62
79
|
|
|
63
|
-
if @runner.resolves_lazies && @runner.
|
|
80
|
+
if @runner.resolves_lazies && @runner.lazy?(@authorized_value)
|
|
64
81
|
@runner.dataloader.lazy_at_depth(@field_resolve_step.path.size, self)
|
|
65
82
|
@next_step = :create_result
|
|
66
83
|
else
|
|
@@ -100,11 +117,11 @@ module GraphQL
|
|
|
100
117
|
@next_results << next_result_h
|
|
101
118
|
@next_objects << @object
|
|
102
119
|
@graphql_result[@key] = next_result_h
|
|
103
|
-
@runner.
|
|
104
|
-
@runner.
|
|
120
|
+
@runner.runtime_type_at[next_result_h] = @resolved_type
|
|
121
|
+
@runner.static_type_at[next_result_h] = @static_type
|
|
105
122
|
end
|
|
106
123
|
|
|
107
|
-
@field_resolve_step.authorized_finished
|
|
124
|
+
@field_resolve_step.authorized_finished(self)
|
|
108
125
|
end
|
|
109
126
|
end
|
|
110
127
|
end
|
|
@@ -1,26 +1,49 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
module GraphQL
|
|
3
3
|
module Execution
|
|
4
|
-
module
|
|
4
|
+
module Next
|
|
5
5
|
class Runner
|
|
6
|
-
def initialize(multiplex)
|
|
6
|
+
def initialize(multiplex, authorization:)
|
|
7
7
|
@multiplex = multiplex
|
|
8
8
|
@schema = multiplex.schema
|
|
9
9
|
@steps_queue = []
|
|
10
|
-
@
|
|
11
|
-
@
|
|
10
|
+
@runtime_type_at = {}.compare_by_identity
|
|
11
|
+
@static_type_at = {}.compare_by_identity
|
|
12
12
|
@selected_operation = nil
|
|
13
13
|
@dataloader = multiplex.context[:dataloader] ||= @schema.dataloader_class.new
|
|
14
14
|
@resolves_lazies = @schema.resolves_lazies?
|
|
15
|
+
@lazy_cache = resolves_lazies ? {}.compare_by_identity : nil
|
|
15
16
|
@field_resolve_step_class = @schema.uses_raw_value? ? RawValueFieldResolveStep : FieldResolveStep
|
|
16
|
-
@
|
|
17
|
+
@authorization = authorization
|
|
18
|
+
if @authorization
|
|
19
|
+
@authorizes_cache = Hash.new do |h, query_context|
|
|
20
|
+
h[query_context] = {}.compare_by_identity
|
|
21
|
+
end.compare_by_identity
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def resolve_type(type, object, query)
|
|
26
|
+
query.current_trace.begin_resolve_type(@static_type, object, query.context)
|
|
27
|
+
resolved_type, _ignored_new_value = query.resolve_type(type, object)
|
|
28
|
+
query.current_trace.end_resolve_type(@static_type, object, query.context, resolved_type)
|
|
29
|
+
resolved_type
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def authorizes?(graphql_definition, query_context)
|
|
33
|
+
auth_cache = @authorizes_cache[query_context]
|
|
34
|
+
case (auth_res = auth_cache[graphql_definition])
|
|
35
|
+
when nil
|
|
36
|
+
auth_cache[graphql_definition] = graphql_definition.authorizes?(query_context)
|
|
37
|
+
else
|
|
38
|
+
auth_res
|
|
39
|
+
end
|
|
17
40
|
end
|
|
18
41
|
|
|
19
42
|
def add_step(step)
|
|
20
43
|
@dataloader.append_job(step)
|
|
21
44
|
end
|
|
22
45
|
|
|
23
|
-
attr_reader :steps_queue, :schema, :variables, :
|
|
46
|
+
attr_reader :authorization, :steps_queue, :schema, :variables, :dataloader, :resolves_lazies, :authorizes, :static_type_at, :runtime_type_at
|
|
24
47
|
|
|
25
48
|
def execute
|
|
26
49
|
Fiber[:__graphql_current_multiplex] = @multiplex
|
|
@@ -60,27 +83,33 @@ module GraphQL
|
|
|
60
83
|
raise ArgumentError, "Unknown operation type: #{selected_operation.operation_type.inspect}"
|
|
61
84
|
end
|
|
62
85
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
query.root_value
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
86
|
+
if self.authorization && authorizes?(root_type, query.context)
|
|
87
|
+
query.current_trace.begin_authorized(root_type, query.root_value, query.context)
|
|
88
|
+
auth_check = schema.sync_lazy(root_type.authorized?(query.root_value, query.context))
|
|
89
|
+
query.current_trace.end_authorized(root_type, query.root_value, query.context, auth_check)
|
|
90
|
+
root_value = if auth_check
|
|
91
|
+
query.root_value
|
|
92
|
+
else
|
|
93
|
+
begin
|
|
94
|
+
auth_err = GraphQL::UnauthorizedError.new(object: query.root_value, type: root_type, context: query.context)
|
|
95
|
+
new_val = schema.unauthorized_object(auth_err)
|
|
96
|
+
if new_val
|
|
97
|
+
auth_check = true
|
|
98
|
+
end
|
|
99
|
+
new_val
|
|
100
|
+
rescue GraphQL::ExecutionError => ex_err
|
|
101
|
+
# The old runtime didn't add path and ast_nodes to this
|
|
102
|
+
query.context.add_error(ex_err)
|
|
103
|
+
nil
|
|
72
104
|
end
|
|
73
|
-
new_val
|
|
74
|
-
rescue GraphQL::ExecutionError => ex_err
|
|
75
|
-
# The old runtime didn't add path and ast_nodes to this
|
|
76
|
-
query.context.add_error(ex_err)
|
|
77
|
-
nil
|
|
78
105
|
end
|
|
79
|
-
end
|
|
80
106
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
107
|
+
if !auth_check
|
|
108
|
+
results << {}
|
|
109
|
+
next
|
|
110
|
+
end
|
|
111
|
+
else
|
|
112
|
+
root_value = query.root_value
|
|
84
113
|
end
|
|
85
114
|
|
|
86
115
|
results << { "data" => data }
|
|
@@ -116,8 +145,7 @@ module GraphQL
|
|
|
116
145
|
raise ArgumentError, "Unhandled operation type: #{operation.operation_type.inspect}"
|
|
117
146
|
end
|
|
118
147
|
|
|
119
|
-
@
|
|
120
|
-
@runtime_types_at_result[data] = root_type
|
|
148
|
+
@static_type_at[data] = root_type
|
|
121
149
|
|
|
122
150
|
# TODO This is stupid but makes multiplex_spec.rb pass
|
|
123
151
|
trace.execute_query(query: query) do
|
|
@@ -197,6 +225,15 @@ module GraphQL
|
|
|
197
225
|
end
|
|
198
226
|
end
|
|
199
227
|
|
|
228
|
+
def lazy?(object)
|
|
229
|
+
obj_class = object.class
|
|
230
|
+
is_lazy = @lazy_cache[obj_class]
|
|
231
|
+
if is_lazy.nil?
|
|
232
|
+
is_lazy = @lazy_cache[obj_class] = @schema.lazy?(object)
|
|
233
|
+
end
|
|
234
|
+
is_lazy
|
|
235
|
+
end
|
|
236
|
+
|
|
200
237
|
private
|
|
201
238
|
|
|
202
239
|
def propagate_errors(data, query)
|
|
@@ -256,13 +293,13 @@ module GraphQL
|
|
|
256
293
|
current_result_path.pop
|
|
257
294
|
end
|
|
258
295
|
when Language::Nodes::InlineFragment
|
|
259
|
-
static_type_at_result = @
|
|
296
|
+
static_type_at_result = @static_type_at[result_h]
|
|
260
297
|
if static_type_at_result && type_condition_applies?(query.context, static_type_at_result, ast_selection.type.name)
|
|
261
298
|
result_h = check_object_result(query, result_h, static_type, ast_selection.selections, current_exec_path, current_result_path, paths_to_check)
|
|
262
299
|
end
|
|
263
300
|
when Language::Nodes::FragmentSpread
|
|
264
301
|
fragment_defn = query.document.definitions.find { |defn| defn.is_a?(Language::Nodes::FragmentDefinition) && defn.name == ast_selection.name }
|
|
265
|
-
static_type_at_result = @
|
|
302
|
+
static_type_at_result = @static_type_at[result_h]
|
|
266
303
|
if static_type_at_result && type_condition_applies?(query.context, static_type_at_result, fragment_defn.type.name)
|
|
267
304
|
result_h = check_object_result(query, result_h, static_type, fragment_defn.selections, current_exec_path, current_result_path, paths_to_check)
|
|
268
305
|
end
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
|
-
require "graphql/execution/
|
|
3
|
-
require "graphql/execution/
|
|
4
|
-
require "graphql/execution/
|
|
5
|
-
require "graphql/execution/
|
|
6
|
-
require "graphql/execution/
|
|
2
|
+
require "graphql/execution/next/prepare_object_step"
|
|
3
|
+
require "graphql/execution/next/field_resolve_step"
|
|
4
|
+
require "graphql/execution/next/load_argument_step"
|
|
5
|
+
require "graphql/execution/next/runner"
|
|
6
|
+
require "graphql/execution/next/selections_step"
|
|
7
7
|
module GraphQL
|
|
8
8
|
module Execution
|
|
9
|
-
module
|
|
9
|
+
module Next
|
|
10
10
|
module SchemaExtension
|
|
11
|
-
def
|
|
11
|
+
def execute_next(query_str = nil, context: nil, document: nil, variables: nil, root_value: nil, validate: true, visibility_profile: nil)
|
|
12
12
|
multiplex_context = if context
|
|
13
13
|
{
|
|
14
14
|
backtrace: context[:backtrace],
|
|
@@ -29,17 +29,24 @@ module GraphQL
|
|
|
29
29
|
root_value: root_value,
|
|
30
30
|
visibility_profile: visibility_profile,
|
|
31
31
|
}
|
|
32
|
-
m_results =
|
|
32
|
+
m_results = multiplex_next([query_opts], context: multiplex_context, max_complexity: nil)
|
|
33
33
|
m_results[0]
|
|
34
34
|
end
|
|
35
35
|
|
|
36
|
-
def
|
|
37
|
-
|
|
36
|
+
def multiplex_next(query_options, context: {}, max_complexity: self.max_complexity)
|
|
37
|
+
Next.run_all(self, query_options, context: context, max_complexity: max_complexity)
|
|
38
38
|
end
|
|
39
|
+
|
|
40
|
+
def execution_next_options
|
|
41
|
+
@execution_next_options || find_inherited_value(:execution_next_options, EmptyObjects::EMPTY_HASH)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
attr_writer :execution_next_options
|
|
39
45
|
end
|
|
40
46
|
|
|
41
|
-
def self.use(schema)
|
|
47
|
+
def self.use(schema, authorization: true)
|
|
42
48
|
schema.extend(SchemaExtension)
|
|
49
|
+
schema.execution_next_options = { authorization: authorization }
|
|
43
50
|
end
|
|
44
51
|
|
|
45
52
|
def self.run_all(schema, query_options, context: {}, max_complexity: schema.max_complexity)
|
|
@@ -54,7 +61,7 @@ module GraphQL
|
|
|
54
61
|
end
|
|
55
62
|
end
|
|
56
63
|
multiplex = Execution::Multiplex.new(schema: schema, queries: queries, context: context, max_complexity: max_complexity)
|
|
57
|
-
runner = Runner.new(multiplex)
|
|
64
|
+
runner = Runner.new(multiplex, **schema.execution_next_options)
|
|
58
65
|
runner.execute
|
|
59
66
|
end
|
|
60
67
|
end
|
data/lib/graphql/execution.rb
CHANGED
|
@@ -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)
|
|
@@ -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
|
|
@@ -519,35 +519,22 @@ module GraphQL
|
|
|
519
519
|
|
|
520
520
|
# Don't do this for interfaces
|
|
521
521
|
if default_resolve
|
|
522
|
-
define_field_resolve_method(owner, resolve_method_name, field_definition.name
|
|
522
|
+
define_field_resolve_method(owner, resolve_method_name, field_definition.name)
|
|
523
523
|
end
|
|
524
524
|
end
|
|
525
525
|
end
|
|
526
526
|
|
|
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
|
|
527
|
+
def define_field_resolve_method(owner, method_name, field_name)
|
|
528
|
+
owner.define_method(method_name) { |**args|
|
|
529
|
+
field_instance = context.types.field(owner, field_name)
|
|
530
|
+
context.schema.definition_default_resolve.call(self.class, field_instance, object, args, context)
|
|
531
|
+
}
|
|
532
|
+
owner.define_singleton_method(method_name) { |objects, context, **args|
|
|
533
|
+
field_instance = context.types.field(owner, field_name)
|
|
534
|
+
objects.map do |object|
|
|
535
|
+
context.schema.definition_default_resolve.call(self, field_instance, object, args, context)
|
|
536
|
+
end
|
|
537
|
+
}
|
|
551
538
|
end
|
|
552
539
|
|
|
553
540
|
def build_resolve_type(lookup_hash, directives, missing_type_handler)
|
|
@@ -21,45 +21,25 @@ module GraphQL
|
|
|
21
21
|
yield(object, next_args, arguments)
|
|
22
22
|
end
|
|
23
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)
|
|
31
|
+
end
|
|
32
|
+
|
|
24
33
|
def after_resolve(value:, object:, arguments:, context:, memo:)
|
|
25
34
|
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
|
|
35
|
+
context.query.after_lazy(value) do |resolved_value|
|
|
36
|
+
context.schema.connections.populate_connection(field, object.object, resolved_value, original_arguments, context)
|
|
61
37
|
end
|
|
62
38
|
end
|
|
39
|
+
|
|
40
|
+
def after_resolve_next(**kwargs)
|
|
41
|
+
raise "This should never be called -- it's hardcoded in execution instead."
|
|
42
|
+
end
|
|
63
43
|
end
|
|
64
44
|
end
|
|
65
45
|
end
|
|
@@ -5,24 +5,33 @@ 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
|
|
31
|
+
|
|
32
|
+
def after_resolve_next(**kwargs)
|
|
33
|
+
raise "This should never be called -- it's hardcoded in execution instead."
|
|
34
|
+
end
|
|
26
35
|
end
|
|
27
36
|
end
|
|
28
37
|
end
|