graphql 1.12.3 → 1.12.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of graphql might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/lib/generators/graphql/install_generator.rb +4 -1
- data/lib/generators/graphql/loader_generator.rb +1 -0
- data/lib/generators/graphql/mutation_generator.rb +1 -0
- data/lib/generators/graphql/relay.rb +55 -0
- data/lib/generators/graphql/relay_generator.rb +4 -46
- data/lib/generators/graphql/type_generator.rb +1 -0
- data/lib/graphql.rb +4 -2
- data/lib/graphql/backtrace/inspect_result.rb +0 -1
- data/lib/graphql/backtrace/table.rb +0 -1
- data/lib/graphql/backtrace/traced_error.rb +0 -1
- data/lib/graphql/backtrace/tracer.rb +4 -8
- data/lib/graphql/dataloader.rb +102 -92
- data/lib/graphql/dataloader/null_dataloader.rb +5 -5
- data/lib/graphql/dataloader/request.rb +1 -6
- data/lib/graphql/dataloader/request_all.rb +1 -4
- data/lib/graphql/dataloader/source.rb +20 -6
- data/lib/graphql/execution/errors.rb +109 -11
- data/lib/graphql/execution/interpreter.rb +2 -2
- data/lib/graphql/execution/interpreter/arguments_cache.rb +37 -14
- data/lib/graphql/execution/interpreter/resolve.rb +33 -25
- data/lib/graphql/execution/interpreter/runtime.rb +41 -78
- data/lib/graphql/execution/multiplex.rb +21 -22
- data/lib/graphql/introspection.rb +1 -1
- data/lib/graphql/introspection/directive_type.rb +7 -3
- data/lib/graphql/language.rb +1 -0
- data/lib/graphql/language/cache.rb +37 -0
- data/lib/graphql/language/parser.rb +15 -5
- data/lib/graphql/language/parser.y +15 -5
- data/lib/graphql/object_type.rb +0 -2
- data/lib/graphql/pagination/active_record_relation_connection.rb +7 -0
- data/lib/graphql/pagination/connection.rb +15 -1
- data/lib/graphql/pagination/connections.rb +1 -0
- data/lib/graphql/pagination/relation_connection.rb +12 -1
- data/lib/graphql/parse_error.rb +0 -1
- data/lib/graphql/query.rb +9 -5
- data/lib/graphql/query/arguments_cache.rb +0 -1
- data/lib/graphql/query/context.rb +1 -3
- data/lib/graphql/query/executor.rb +0 -1
- data/lib/graphql/query/null_context.rb +3 -2
- data/lib/graphql/query/validation_pipeline.rb +1 -1
- data/lib/graphql/query/variable_validation_error.rb +1 -1
- data/lib/graphql/railtie.rb +9 -1
- data/lib/graphql/relay/range_add.rb +10 -5
- data/lib/graphql/schema.rb +14 -27
- data/lib/graphql/schema/argument.rb +61 -0
- data/lib/graphql/schema/field.rb +10 -5
- data/lib/graphql/schema/field/connection_extension.rb +1 -0
- data/lib/graphql/schema/find_inherited_value.rb +3 -1
- data/lib/graphql/schema/input_object.rb +6 -2
- data/lib/graphql/schema/member/has_arguments.rb +43 -56
- data/lib/graphql/schema/member/has_fields.rb +1 -4
- data/lib/graphql/schema/member/instrumentation.rb +0 -1
- data/lib/graphql/schema/resolver.rb +28 -1
- data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +3 -1
- data/lib/graphql/static_validation/rules/argument_literals_are_compatible_error.rb +6 -2
- data/lib/graphql/static_validation/rules/arguments_are_defined.rb +2 -1
- data/lib/graphql/static_validation/rules/arguments_are_defined_error.rb +4 -2
- data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +2 -2
- data/lib/graphql/subscriptions/broadcast_analyzer.rb +0 -3
- data/lib/graphql/subscriptions/event.rb +0 -1
- data/lib/graphql/subscriptions/instrumentation.rb +0 -1
- data/lib/graphql/subscriptions/serialize.rb +3 -1
- data/lib/graphql/tracing/active_support_notifications_tracing.rb +2 -1
- data/lib/graphql/types/relay/base_connection.rb +4 -0
- data/lib/graphql/types/relay/connection_behaviors.rb +38 -5
- data/lib/graphql/types/relay/edge_behaviors.rb +12 -1
- data/lib/graphql/version.rb +1 -1
- data/readme.md +1 -1
- metadata +8 -90
@@ -81,79 +81,66 @@ module GraphQL
|
|
81
81
|
end
|
82
82
|
|
83
83
|
# @api private
|
84
|
+
# If given a block, it will eventually yield the loaded args to the block.
|
85
|
+
#
|
86
|
+
# If no block is given, it will immediately dataload (but might return a Lazy).
|
87
|
+
#
|
84
88
|
# @param values [Hash<String, Object>]
|
85
89
|
# @param context [GraphQL::Query::Context]
|
86
|
-
# @
|
87
|
-
|
90
|
+
# @yield [Interpreter::Arguments, Execution::Lazy<Interpeter::Arguments>]
|
91
|
+
# @return [Interpreter::Arguments, Execution::Lazy<Interpeter::Arguments>]
|
92
|
+
def coerce_arguments(parent_object, values, context, &block)
|
88
93
|
# Cache this hash to avoid re-merging it
|
89
94
|
arg_defns = self.arguments
|
95
|
+
total_args_count = arg_defns.size
|
90
96
|
|
91
|
-
if
|
92
|
-
GraphQL::Execution::Interpreter::Arguments::EMPTY
|
97
|
+
if total_args_count == 0
|
98
|
+
final_args = GraphQL::Execution::Interpreter::Arguments::EMPTY
|
99
|
+
if block_given?
|
100
|
+
block.call(final_args)
|
101
|
+
nil
|
102
|
+
else
|
103
|
+
final_args
|
104
|
+
end
|
93
105
|
else
|
106
|
+
finished_args = nil
|
94
107
|
argument_values = {}
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
elsif arg_defn.default_value?
|
106
|
-
has_value = true
|
107
|
-
value = arg_defn.default_value
|
108
|
-
default_used = true
|
109
|
-
end
|
110
|
-
|
111
|
-
if has_value
|
112
|
-
loads = arg_defn.loads
|
113
|
-
loaded_value = nil
|
114
|
-
coerced_value = context.schema.error_handler.with_error_handling(context) do
|
115
|
-
arg_defn.type.coerce_input(value, context)
|
116
|
-
end
|
117
|
-
|
118
|
-
# TODO this should probably be inside after_lazy
|
119
|
-
if loads && !arg_defn.from_resolver?
|
120
|
-
loaded_value = if arg_defn.type.list?
|
121
|
-
loaded_values = coerced_value.map { |val| load_application_object(arg_defn, loads, val, context) }
|
122
|
-
context.schema.after_any_lazies(loaded_values) { |result| result }
|
108
|
+
resolved_args_count = 0
|
109
|
+
raised_error = false
|
110
|
+
arg_defns.each do |arg_name, arg_defn|
|
111
|
+
context.dataloader.append_job do
|
112
|
+
begin
|
113
|
+
arg_defn.coerce_into_values(parent_object, values, context, argument_values)
|
114
|
+
rescue GraphQL::ExecutionError, GraphQL::UnauthorizedError => err
|
115
|
+
raised_error = true
|
116
|
+
if block_given?
|
117
|
+
block.call(err)
|
123
118
|
else
|
124
|
-
|
119
|
+
finished_args = err
|
125
120
|
end
|
126
121
|
end
|
127
122
|
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
123
|
+
resolved_args_count += 1
|
124
|
+
if resolved_args_count == total_args_count && !raised_error
|
125
|
+
finished_args = context.schema.after_any_lazies(argument_values.values) {
|
126
|
+
GraphQL::Execution::Interpreter::Arguments.new(
|
127
|
+
argument_values: argument_values,
|
128
|
+
)
|
129
|
+
}
|
133
130
|
|
134
|
-
|
135
|
-
|
136
|
-
prepared_value = context.schema.error_handler.with_error_handling(context) do
|
137
|
-
arg_defn.prepare_value(parent_object, coerced_value, context: context)
|
131
|
+
if block_given?
|
132
|
+
block.call(finished_args)
|
138
133
|
end
|
139
|
-
|
140
|
-
# TODO code smell to access such a deeply-nested constant in a distant module
|
141
|
-
argument_values[arg_key] = GraphQL::Execution::Interpreter::ArgumentValue.new(
|
142
|
-
value: prepared_value,
|
143
|
-
definition: arg_defn,
|
144
|
-
default_used: default_used,
|
145
|
-
)
|
146
134
|
end
|
147
|
-
else
|
148
|
-
# has_value is false
|
149
|
-
validate_directive_argument(arg_defn, nil)
|
150
135
|
end
|
151
136
|
end
|
152
137
|
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
138
|
+
if block_given?
|
139
|
+
nil
|
140
|
+
else
|
141
|
+
# This API returns eagerly, gotta run it now
|
142
|
+
context.dataloader.run
|
143
|
+
finished_args
|
157
144
|
end
|
158
145
|
end
|
159
146
|
end
|
@@ -74,11 +74,8 @@ module GraphQL
|
|
74
74
|
@field_class = new_field_class
|
75
75
|
elsif defined?(@field_class) && @field_class
|
76
76
|
@field_class
|
77
|
-
elsif self.is_a?(Class)
|
78
|
-
superclass.respond_to?(:field_class) ? superclass.field_class : GraphQL::Schema::Field
|
79
77
|
else
|
80
|
-
|
81
|
-
ancestor ? ancestor.field_class : GraphQL::Schema::Field
|
78
|
+
find_inherited_value(:field_class, GraphQL::Schema::Field)
|
82
79
|
end
|
83
80
|
end
|
84
81
|
|
@@ -276,8 +276,29 @@ module GraphQL
|
|
276
276
|
end
|
277
277
|
end
|
278
278
|
|
279
|
+
# Get or set the `max_page_size:` which will be configured for fields using this resolver
|
280
|
+
# (`nil` means "unlimited max page size".)
|
281
|
+
# @param max_page_size [Integer, nil] Set a new value
|
282
|
+
# @return [Integer, nil] The `max_page_size` assigned to fields that use this resolver
|
283
|
+
def max_page_size(new_max_page_size = :not_given)
|
284
|
+
if new_max_page_size != :not_given
|
285
|
+
@max_page_size = new_max_page_size
|
286
|
+
elsif defined?(@max_page_size)
|
287
|
+
@max_page_size
|
288
|
+
elsif superclass.respond_to?(:max_page_size)
|
289
|
+
superclass.max_page_size
|
290
|
+
else
|
291
|
+
nil
|
292
|
+
end
|
293
|
+
end
|
294
|
+
|
295
|
+
# @return [Boolean] `true` if this resolver or a superclass has an assigned `max_page_size`
|
296
|
+
def has_max_page_size?
|
297
|
+
defined?(@max_page_size) || (superclass.respond_to?(:has_max_page_size?) && superclass.has_max_page_size?)
|
298
|
+
end
|
299
|
+
|
279
300
|
def field_options
|
280
|
-
{
|
301
|
+
field_opts = {
|
281
302
|
type: type_expr,
|
282
303
|
description: description,
|
283
304
|
extras: extras,
|
@@ -289,6 +310,12 @@ module GraphQL
|
|
289
310
|
extensions: extensions,
|
290
311
|
broadcastable: broadcastable?,
|
291
312
|
}
|
313
|
+
|
314
|
+
if has_max_page_size?
|
315
|
+
field_opts[:max_page_size] = max_page_size
|
316
|
+
end
|
317
|
+
|
318
|
+
field_opts
|
292
319
|
end
|
293
320
|
|
294
321
|
# A non-normalized type configuration, without `null` applied
|
@@ -41,7 +41,9 @@ module GraphQL
|
|
41
41
|
error_options = {
|
42
42
|
nodes: parent,
|
43
43
|
type: kind_of_node,
|
44
|
-
|
44
|
+
argument_name: node.name,
|
45
|
+
argument: arg_defn,
|
46
|
+
value: node.value
|
45
47
|
}
|
46
48
|
if coerce_extensions
|
47
49
|
error_options[:coerce_extensions] = coerce_extensions
|
@@ -4,13 +4,17 @@ module GraphQL
|
|
4
4
|
class ArgumentLiteralsAreCompatibleError < StaticValidation::Error
|
5
5
|
attr_reader :type_name
|
6
6
|
attr_reader :argument_name
|
7
|
+
attr_reader :argument
|
8
|
+
attr_reader :value
|
7
9
|
|
8
|
-
def initialize(message, path: nil, nodes: [], type:,
|
10
|
+
def initialize(message, path: nil, nodes: [], type:, argument_name: nil, extensions: nil, coerce_extensions: nil, argument: nil, value: nil)
|
9
11
|
super(message, path: path, nodes: nodes)
|
10
12
|
@type_name = type
|
11
|
-
@argument_name =
|
13
|
+
@argument_name = argument_name
|
12
14
|
@extensions = extensions
|
13
15
|
@coerce_extensions = coerce_extensions
|
16
|
+
@argument = argument
|
17
|
+
@value = value
|
14
18
|
end
|
15
19
|
|
16
20
|
# A hash representation of this Message
|
@@ -5,12 +5,14 @@ module GraphQL
|
|
5
5
|
attr_reader :name
|
6
6
|
attr_reader :type_name
|
7
7
|
attr_reader :argument_name
|
8
|
+
attr_reader :parent
|
8
9
|
|
9
|
-
def initialize(message, path: nil, nodes: [], name:, type:,
|
10
|
+
def initialize(message, path: nil, nodes: [], name:, type:, argument_name:, parent:)
|
10
11
|
super(message, path: path, nodes: nodes)
|
11
12
|
@name = name
|
12
13
|
@type_name = type
|
13
|
-
@argument_name =
|
14
|
+
@argument_name = argument_name
|
15
|
+
@parent = parent
|
14
16
|
end
|
15
17
|
|
16
18
|
# A hash representation of this Message
|
@@ -29,8 +29,8 @@ module GraphQL
|
|
29
29
|
context.directive_definition.arguments
|
30
30
|
when GraphQL::Language::Nodes::InputObject
|
31
31
|
arg_type = context.argument_definition.type.unwrap
|
32
|
-
if arg_type.
|
33
|
-
arguments = arg_type.
|
32
|
+
if arg_type.kind.input_object?
|
33
|
+
arguments = arg_type.arguments
|
34
34
|
else
|
35
35
|
# This is some kind of error
|
36
36
|
nil
|
@@ -35,9 +35,6 @@ module GraphQL
|
|
35
35
|
pt = @query.possible_types(current_type)
|
36
36
|
pt.each do |object_type|
|
37
37
|
ot_field = @query.get_field(object_type, current_field.graphql_name)
|
38
|
-
if !ot_field
|
39
|
-
binding.pry
|
40
|
-
end
|
41
38
|
# Inherited fields would be exactly the same object;
|
42
39
|
# only check fields that are overrides of the inherited one
|
43
40
|
if ot_field && ot_field != current_field
|
@@ -1,5 +1,4 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
# test_via: ../subscriptions.rb
|
3
2
|
require "set"
|
4
3
|
module GraphQL
|
5
4
|
class Subscriptions
|
@@ -71,6 +70,9 @@ module GraphQL
|
|
71
70
|
when OPEN_STRUCT_KEY
|
72
71
|
ostruct_values = load_value(value[OPEN_STRUCT_KEY])
|
73
72
|
OpenStruct.new(ostruct_values)
|
73
|
+
else
|
74
|
+
key = value.keys.first
|
75
|
+
{ key => load_value(value[key]) }
|
74
76
|
end
|
75
77
|
else
|
76
78
|
loaded_h = {}
|
@@ -3,8 +3,9 @@
|
|
3
3
|
module GraphQL
|
4
4
|
module Tracing
|
5
5
|
# This implementation forwards events to ActiveSupport::Notifications
|
6
|
-
# with a `graphql
|
6
|
+
# with a `graphql` suffix.
|
7
7
|
#
|
8
|
+
# @see KEYS for event names
|
8
9
|
module ActiveSupportNotificationsTracing
|
9
10
|
# A cache of frequently-used keys to avoid needless string allocations
|
10
11
|
KEYS = {
|
@@ -24,6 +24,10 @@ module GraphQL
|
|
24
24
|
# end
|
25
25
|
# class Types::PostConnection < Types::BaseConnection
|
26
26
|
# edge_type(Types::PostEdge)
|
27
|
+
# edges_nullable(true)
|
28
|
+
# edge_nullable(true)
|
29
|
+
# node_nullable(true)
|
30
|
+
# has_nodes_field(true)
|
27
31
|
# end
|
28
32
|
#
|
29
33
|
# @see Relay::BaseEdge for edge types
|
@@ -11,7 +11,10 @@ module GraphQL
|
|
11
11
|
child_class.extend(ClassMethods)
|
12
12
|
child_class.extend(Relay::DefaultRelay)
|
13
13
|
child_class.default_relay(true)
|
14
|
+
child_class.has_nodes_field(true)
|
14
15
|
child_class.node_nullable(true)
|
16
|
+
child_class.edges_nullable(true)
|
17
|
+
child_class.edge_nullable(true)
|
15
18
|
add_page_info_field(child_class)
|
16
19
|
end
|
17
20
|
|
@@ -32,7 +35,7 @@ module GraphQL
|
|
32
35
|
# It's called when you subclass this base connection, trying to use the
|
33
36
|
# class name to set defaults. You can call it again in the class definition
|
34
37
|
# to override the default (or provide a value, if the default lookup failed).
|
35
|
-
def edge_type(edge_type_class, edge_class: GraphQL::Relay::Edge, node_type: edge_type_class.node_type, nodes_field:
|
38
|
+
def edge_type(edge_type_class, edge_class: GraphQL::Relay::Edge, node_type: edge_type_class.node_type, nodes_field: self.has_nodes_field, node_nullable: self.node_nullable, edges_nullable: self.edges_nullable, edge_nullable: self.edge_nullable)
|
36
39
|
# Set this connection's graphql name
|
37
40
|
node_type_name = node_type.graphql_name
|
38
41
|
|
@@ -40,8 +43,8 @@ module GraphQL
|
|
40
43
|
@edge_type = edge_type_class
|
41
44
|
@edge_class = edge_class
|
42
45
|
|
43
|
-
field :edges, [edge_type_class, null:
|
44
|
-
null:
|
46
|
+
field :edges, [edge_type_class, null: edge_nullable],
|
47
|
+
null: edges_nullable,
|
45
48
|
description: "A list of edges.",
|
46
49
|
legacy_edge_class: edge_class, # This is used by the old runtime only, for EdgesInstrumentation
|
47
50
|
connection: false
|
@@ -77,9 +80,39 @@ module GraphQL
|
|
77
80
|
# Use `node_nullable(false)` in your base class to make non-null `node` and `nodes` fields.
|
78
81
|
def node_nullable(new_value = nil)
|
79
82
|
if new_value.nil?
|
80
|
-
@node_nullable
|
83
|
+
defined?(@node_nullable) ? @node_nullable : superclass.node_nullable
|
81
84
|
else
|
82
|
-
@node_nullable
|
85
|
+
@node_nullable = new_value
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
# Set the default `edges_nullable` for this class and its child classes. (Defaults to `true`.)
|
90
|
+
# Use `edges_nullable(false)` in your base class to make non-null `edges` fields.
|
91
|
+
def edges_nullable(new_value = nil)
|
92
|
+
if new_value.nil?
|
93
|
+
defined?(@edges_nullable) ? @edges_nullable : superclass.edges_nullable
|
94
|
+
else
|
95
|
+
@edges_nullable = new_value
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
# Set the default `edge_nullable` for this class and its child classes. (Defaults to `true`.)
|
100
|
+
# Use `edge_nullable(false)` in your base class to make non-null `edge` fields.
|
101
|
+
def edge_nullable(new_value = nil)
|
102
|
+
if new_value.nil?
|
103
|
+
defined?(@edge_nullable) ? @edge_nullable : superclass.edge_nullable
|
104
|
+
else
|
105
|
+
@edge_nullable = new_value
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
# Set the default `nodes_field` for this class and its child classes. (Defaults to `true`.)
|
110
|
+
# Use `nodes_field(false)` in your base class to prevent adding of a nodes field.
|
111
|
+
def has_nodes_field(new_value = nil)
|
112
|
+
if new_value.nil?
|
113
|
+
defined?(@nodes_field) ? @nodes_field : superclass.has_nodes_field
|
114
|
+
else
|
115
|
+
@nodes_field = new_value
|
83
116
|
end
|
84
117
|
end
|
85
118
|
|
@@ -8,6 +8,7 @@ module GraphQL
|
|
8
8
|
child_class.description("An edge in a connection.")
|
9
9
|
child_class.field(:cursor, String, null: false, description: "A cursor for use in pagination.")
|
10
10
|
child_class.extend(ClassMethods)
|
11
|
+
child_class.node_nullable(true)
|
11
12
|
end
|
12
13
|
|
13
14
|
module ClassMethods
|
@@ -15,7 +16,7 @@ module GraphQL
|
|
15
16
|
#
|
16
17
|
# @param node_type [Class] A `Schema::Object` subclass
|
17
18
|
# @param null [Boolean]
|
18
|
-
def node_type(node_type = nil, null:
|
19
|
+
def node_type(node_type = nil, null: self.node_nullable)
|
19
20
|
if node_type
|
20
21
|
@node_type = node_type
|
21
22
|
# Add a default `node` field
|
@@ -35,6 +36,16 @@ module GraphQL
|
|
35
36
|
def visible?(ctx)
|
36
37
|
node_type.visible?(ctx)
|
37
38
|
end
|
39
|
+
|
40
|
+
# Set the default `node_nullable` for this class and its child classes. (Defaults to `true`.)
|
41
|
+
# Use `node_nullable(false)` in your base class to make non-null `node` field.
|
42
|
+
def node_nullable(new_value = nil)
|
43
|
+
if new_value.nil?
|
44
|
+
defined?(@node_nullable) ? @node_nullable : superclass.node_nullable
|
45
|
+
else
|
46
|
+
@node_nullable = new_value
|
47
|
+
end
|
48
|
+
end
|
38
49
|
end
|
39
50
|
end
|
40
51
|
end
|
data/lib/graphql/version.rb
CHANGED
data/readme.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# graphql <img src="https://cloud.githubusercontent.com/assets/2231765/9094460/cb43861e-3b66-11e5-9fbf-71066ff3ab13.png" height="40" alt="graphql-ruby"/>
|
2
2
|
|
3
|
-
[](https://github.com/rmosolgo/graphql-ruby/actions/workflows/ci.yaml)
|
4
4
|
[](https://rubygems.org/gems/graphql)
|
5
5
|
[](https://codeclimate.com/github/rmosolgo/graphql-ruby)
|
6
6
|
[](https://codeclimate.com/github/rmosolgo/graphql-ruby)
|