graphql 1.12.23 → 1.13.3
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/core.rb +3 -1
- data/lib/generators/graphql/install_generator.rb +9 -2
- data/lib/generators/graphql/mutation_generator.rb +1 -1
- data/lib/generators/graphql/type_generator.rb +0 -1
- data/lib/graphql/analysis/ast/field_usage.rb +2 -2
- data/lib/graphql/analysis/ast/query_complexity.rb +10 -14
- data/lib/graphql/analysis/ast/visitor.rb +4 -4
- data/lib/graphql/backtrace/table.rb +1 -1
- data/lib/graphql/base_type.rb +4 -2
- data/lib/graphql/boolean_type.rb +1 -1
- data/lib/graphql/dataloader.rb +55 -22
- data/lib/graphql/directive/deprecated_directive.rb +1 -1
- data/lib/graphql/directive/include_directive.rb +1 -1
- data/lib/graphql/directive/skip_directive.rb +1 -1
- data/lib/graphql/directive.rb +0 -4
- data/lib/graphql/enum_type.rb +5 -1
- data/lib/graphql/execution/errors.rb +1 -0
- data/lib/graphql/execution/interpreter/arguments.rb +1 -1
- data/lib/graphql/execution/interpreter/arguments_cache.rb +2 -2
- data/lib/graphql/execution/interpreter/runtime.rb +31 -19
- data/lib/graphql/execution/lookahead.rb +2 -2
- data/lib/graphql/execution/multiplex.rb +4 -1
- data/lib/graphql/float_type.rb +1 -1
- data/lib/graphql/id_type.rb +1 -1
- data/lib/graphql/int_type.rb +1 -1
- data/lib/graphql/introspection/directive_type.rb +1 -1
- data/lib/graphql/introspection/entry_points.rb +2 -2
- data/lib/graphql/introspection/enum_value_type.rb +2 -2
- data/lib/graphql/introspection/field_type.rb +2 -2
- data/lib/graphql/introspection/input_value_type.rb +4 -4
- data/lib/graphql/introspection/schema_type.rb +2 -2
- data/lib/graphql/introspection/type_type.rb +10 -10
- data/lib/graphql/language/block_string.rb +2 -6
- data/lib/graphql/language/document_from_schema_definition.rb +10 -4
- data/lib/graphql/language/lexer.rb +0 -3
- data/lib/graphql/language/lexer.rl +0 -4
- data/lib/graphql/language/nodes.rb +3 -2
- data/lib/graphql/language/parser.rb +442 -434
- data/lib/graphql/language/parser.y +5 -4
- data/lib/graphql/language/printer.rb +6 -1
- data/lib/graphql/language/sanitized_printer.rb +5 -5
- data/lib/graphql/language/token.rb +0 -4
- data/lib/graphql/name_validator.rb +0 -4
- data/lib/graphql/pagination/active_record_relation_connection.rb +43 -6
- data/lib/graphql/pagination/relation_connection.rb +55 -28
- data/lib/graphql/query/arguments.rb +1 -1
- data/lib/graphql/query/arguments_cache.rb +1 -1
- data/lib/graphql/query/context.rb +15 -2
- data/lib/graphql/query/literal_input.rb +1 -1
- data/lib/graphql/query/null_context.rb +12 -7
- data/lib/graphql/query/serial_execution/field_resolution.rb +1 -1
- data/lib/graphql/query/variables.rb +5 -1
- data/lib/graphql/relay/edges_instrumentation.rb +0 -1
- data/lib/graphql/relay/global_id_resolve.rb +1 -1
- data/lib/graphql/relay/page_info.rb +1 -1
- data/lib/graphql/rubocop/graphql/base_cop.rb +36 -0
- data/lib/graphql/rubocop/graphql/default_null_true.rb +43 -0
- data/lib/graphql/rubocop/graphql/default_required_true.rb +43 -0
- data/lib/graphql/rubocop.rb +4 -0
- data/lib/graphql/schema/addition.rb +37 -28
- data/lib/graphql/schema/argument.rb +13 -15
- data/lib/graphql/schema/build_from_definition.rb +5 -5
- data/lib/graphql/schema/directive/feature.rb +1 -1
- data/lib/graphql/schema/directive/flagged.rb +2 -2
- data/lib/graphql/schema/directive/include.rb +1 -1
- data/lib/graphql/schema/directive/skip.rb +1 -1
- data/lib/graphql/schema/directive/transform.rb +1 -1
- data/lib/graphql/schema/directive.rb +7 -3
- data/lib/graphql/schema/enum.rb +60 -10
- data/lib/graphql/schema/enum_value.rb +6 -0
- data/lib/graphql/schema/field/connection_extension.rb +1 -1
- data/lib/graphql/schema/field.rb +229 -77
- data/lib/graphql/schema/field_extension.rb +89 -2
- data/lib/graphql/schema/find_inherited_value.rb +1 -0
- data/lib/graphql/schema/finder.rb +5 -5
- data/lib/graphql/schema/input_object.rb +23 -5
- data/lib/graphql/schema/interface.rb +11 -20
- data/lib/graphql/schema/introspection_system.rb +1 -1
- data/lib/graphql/schema/list.rb +3 -1
- data/lib/graphql/schema/member/accepts_definition.rb +15 -3
- data/lib/graphql/schema/member/build_type.rb +0 -4
- data/lib/graphql/schema/member/cached_graphql_definition.rb +29 -2
- data/lib/graphql/schema/member/has_arguments.rb +55 -13
- data/lib/graphql/schema/member/has_deprecation_reason.rb +1 -1
- data/lib/graphql/schema/member/has_fields.rb +76 -18
- data/lib/graphql/schema/member/has_interfaces.rb +90 -0
- data/lib/graphql/schema/member.rb +1 -0
- data/lib/graphql/schema/non_null.rb +7 -1
- data/lib/graphql/schema/object.rb +10 -75
- data/lib/graphql/schema/printer.rb +1 -1
- data/lib/graphql/schema/relay_classic_mutation.rb +37 -3
- data/lib/graphql/schema/resolver/has_payload_type.rb +27 -2
- data/lib/graphql/schema/resolver.rb +37 -17
- data/lib/graphql/schema/scalar.rb +2 -0
- data/lib/graphql/schema/subscription.rb +11 -1
- data/lib/graphql/schema/traversal.rb +1 -1
- data/lib/graphql/schema/type_expression.rb +1 -1
- data/lib/graphql/schema/type_membership.rb +18 -4
- data/lib/graphql/schema/union.rb +8 -1
- data/lib/graphql/schema/validator/format_validator.rb +0 -4
- data/lib/graphql/schema/validator/numericality_validator.rb +1 -0
- data/lib/graphql/schema/validator/required_validator.rb +29 -15
- data/lib/graphql/schema/validator.rb +4 -7
- data/lib/graphql/schema/warden.rb +116 -52
- data/lib/graphql/schema.rb +111 -23
- data/lib/graphql/static_validation/all_rules.rb +1 -0
- data/lib/graphql/static_validation/base_visitor.rb +5 -5
- data/lib/graphql/static_validation/definition_dependencies.rb +0 -1
- data/lib/graphql/static_validation/literal_validator.rb +1 -1
- data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +1 -1
- data/lib/graphql/static_validation/rules/fields_will_merge.rb +1 -1
- data/lib/graphql/static_validation/rules/query_root_exists.rb +17 -0
- data/lib/graphql/static_validation/rules/query_root_exists_error.rb +26 -0
- data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +2 -2
- data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +4 -4
- data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +13 -7
- data/lib/graphql/string_type.rb +1 -1
- data/lib/graphql/subscriptions/action_cable_subscriptions.rb +8 -4
- data/lib/graphql/subscriptions/event.rb +20 -12
- data/lib/graphql/subscriptions/serialize.rb +22 -2
- data/lib/graphql/subscriptions.rb +17 -19
- data/lib/graphql/tracing/active_support_notifications_tracing.rb +6 -20
- data/lib/graphql/tracing/notifications_tracing.rb +59 -0
- data/lib/graphql/types/relay/connection_behaviors.rb +26 -9
- data/lib/graphql/types/relay/default_relay.rb +5 -1
- data/lib/graphql/types/relay/edge_behaviors.rb +13 -2
- data/lib/graphql/types/relay/has_node_field.rb +1 -1
- data/lib/graphql/types/relay/has_nodes_field.rb +1 -1
- data/lib/graphql/types/relay/node_field.rb +14 -3
- data/lib/graphql/types/relay/nodes_field.rb +13 -3
- data/lib/graphql/version.rb +1 -1
- data/lib/graphql.rb +10 -32
- metadata +13 -5
@@ -325,8 +325,9 @@ rule
|
|
325
325
|
| EXTEND TYPE name implements { result = make_node(:ObjectTypeExtension, name: val[2], interfaces: val[3], directives: [], fields: [], position_source: val[0]) }
|
326
326
|
|
327
327
|
interface_type_extension:
|
328
|
-
EXTEND INTERFACE name directives_list_opt LCURLY field_definition_list RCURLY { result = make_node(:InterfaceTypeExtension, name: val[2],
|
329
|
-
| EXTEND INTERFACE name directives_list { result = make_node(:InterfaceTypeExtension, name: val[2],
|
328
|
+
EXTEND INTERFACE name implements_opt directives_list_opt LCURLY field_definition_list RCURLY { result = make_node(:InterfaceTypeExtension, name: val[2], interfaces: val[3], directives: val[4], fields: val[6], position_source: val[0]) }
|
329
|
+
| EXTEND INTERFACE name implements_opt directives_list { result = make_node(:InterfaceTypeExtension, name: val[2], interfaces: val[3], directives: val[4], fields: [], position_source: val[0]) }
|
330
|
+
| EXTEND INTERFACE name implements { result = make_node(:InterfaceTypeExtension, name: val[2], interfaces: val[3], directives: [], fields: [], position_source: val[0]) }
|
330
331
|
|
331
332
|
union_type_extension:
|
332
333
|
EXTEND UNION name directives_list_opt EQUALS union_members { result = make_node(:UnionTypeExtension, name: val[2], directives: val[3], types: val[5], position_source: val[0]) }
|
@@ -397,8 +398,8 @@ rule
|
|
397
398
|
| field_definition_list field_definition { val[0] << val[1] }
|
398
399
|
|
399
400
|
interface_type_definition:
|
400
|
-
description_opt INTERFACE name directives_list_opt LCURLY field_definition_list RCURLY {
|
401
|
-
result = make_node(:InterfaceTypeDefinition, name: val[2],
|
401
|
+
description_opt INTERFACE name implements_opt directives_list_opt LCURLY field_definition_list RCURLY {
|
402
|
+
result = make_node(:InterfaceTypeDefinition, name: val[2], interfaces: val[3], directives: val[4], fields: val[6], description: val[0] || get_description(val[1]), definition_line: val[1].line, position_source: val[0] || val[1])
|
402
403
|
}
|
403
404
|
|
404
405
|
union_members:
|
@@ -164,11 +164,15 @@ module GraphQL
|
|
164
164
|
def print_object_type_definition(object_type)
|
165
165
|
out = print_description(object_type)
|
166
166
|
out << "type #{object_type.name}"
|
167
|
-
out <<
|
167
|
+
out << print_implements(object_type) unless object_type.interfaces.empty?
|
168
168
|
out << print_directives(object_type.directives)
|
169
169
|
out << print_field_definitions(object_type.fields)
|
170
170
|
end
|
171
171
|
|
172
|
+
def print_implements(type)
|
173
|
+
" implements #{type.interfaces.map(&:name).join(" & ")}"
|
174
|
+
end
|
175
|
+
|
172
176
|
def print_input_value_definition(input_value)
|
173
177
|
out = "#{input_value.name}: #{print_node(input_value.type)}".dup
|
174
178
|
out << " = #{print_node(input_value.default_value)}" unless input_value.default_value.nil?
|
@@ -200,6 +204,7 @@ module GraphQL
|
|
200
204
|
def print_interface_type_definition(interface_type)
|
201
205
|
out = print_description(interface_type)
|
202
206
|
out << "interface #{interface_type.name}"
|
207
|
+
out << print_implements(interface_type) if interface_type.interfaces.any?
|
203
208
|
out << print_directives(interface_type.directives)
|
204
209
|
out << print_field_definitions(interface_type.fields)
|
205
210
|
end
|
@@ -79,7 +79,7 @@ module GraphQL
|
|
79
79
|
|
80
80
|
arg_owner = @current_input_type || @current_directive || @current_field
|
81
81
|
old_current_argument = @current_argument
|
82
|
-
@current_argument = arg_owner.
|
82
|
+
@current_argument = arg_owner.get_argument(argument.name, @query.context)
|
83
83
|
|
84
84
|
old_input_type = @current_input_type
|
85
85
|
@current_input_type = @current_argument.type.non_null? ? @current_argument.type.of_type : @current_argument.type
|
@@ -113,7 +113,7 @@ module GraphQL
|
|
113
113
|
end
|
114
114
|
|
115
115
|
def print_field(field, indent: "")
|
116
|
-
@current_field = query.
|
116
|
+
@current_field = query.get_field(@current_type, field.name)
|
117
117
|
old_type = @current_type
|
118
118
|
@current_type = @current_field.type.unwrap
|
119
119
|
res = super
|
@@ -125,7 +125,7 @@ module GraphQL
|
|
125
125
|
old_type = @current_type
|
126
126
|
|
127
127
|
if inline_fragment.type
|
128
|
-
@current_type = query.
|
128
|
+
@current_type = query.get_type(inline_fragment.type.name)
|
129
129
|
end
|
130
130
|
|
131
131
|
res = super
|
@@ -137,7 +137,7 @@ module GraphQL
|
|
137
137
|
|
138
138
|
def print_fragment_definition(fragment_def, indent: "")
|
139
139
|
old_type = @current_type
|
140
|
-
@current_type = query.
|
140
|
+
@current_type = query.get_type(fragment_def.type.name)
|
141
141
|
|
142
142
|
res = super
|
143
143
|
|
@@ -193,7 +193,7 @@ module GraphQL
|
|
193
193
|
end
|
194
194
|
|
195
195
|
arguments = value.map do |key, val|
|
196
|
-
sub_type = type.
|
196
|
+
sub_type = type.get_argument(key.to_s, @query.context).type
|
197
197
|
|
198
198
|
GraphQL::Language::Nodes::Argument.new(
|
199
199
|
name: key.to_s,
|
@@ -4,10 +4,6 @@ module GraphQL
|
|
4
4
|
# Emitted by the lexer and passed to the parser.
|
5
5
|
# Contains type, value and position data.
|
6
6
|
class Token
|
7
|
-
if !String.method_defined?(:-@)
|
8
|
-
using GraphQL::StringDedupBackport
|
9
|
-
end
|
10
|
-
|
11
7
|
# @return [Symbol] The kind of token this is
|
12
8
|
attr_reader :name
|
13
9
|
# @return [String] The text of this token
|
@@ -7,13 +7,18 @@ module GraphQL
|
|
7
7
|
class ActiveRecordRelationConnection < Pagination::RelationConnection
|
8
8
|
private
|
9
9
|
|
10
|
-
def relation_larger_than(relation, size)
|
11
|
-
|
12
|
-
|
10
|
+
def relation_larger_than(relation, initial_offset, size)
|
11
|
+
if already_loaded?(relation)
|
12
|
+
(relation.size + initial_offset) > size
|
13
|
+
else
|
14
|
+
set_offset(sliced_nodes, initial_offset + size).exists?
|
15
|
+
end
|
13
16
|
end
|
14
17
|
|
15
18
|
def relation_count(relation)
|
16
|
-
int_or_hash = if
|
19
|
+
int_or_hash = if already_loaded?(relation)
|
20
|
+
relation.size
|
21
|
+
elsif relation.respond_to?(:unscope)
|
17
22
|
relation.unscope(:order).count(:all)
|
18
23
|
else
|
19
24
|
# Rails 3
|
@@ -28,11 +33,19 @@ module GraphQL
|
|
28
33
|
end
|
29
34
|
|
30
35
|
def relation_limit(relation)
|
31
|
-
relation.
|
36
|
+
if relation.is_a?(Array)
|
37
|
+
nil
|
38
|
+
else
|
39
|
+
relation.limit_value
|
40
|
+
end
|
32
41
|
end
|
33
42
|
|
34
43
|
def relation_offset(relation)
|
35
|
-
relation.
|
44
|
+
if relation.is_a?(Array)
|
45
|
+
nil
|
46
|
+
else
|
47
|
+
relation.offset_value
|
48
|
+
end
|
36
49
|
end
|
37
50
|
|
38
51
|
def null_relation(relation)
|
@@ -43,6 +56,30 @@ module GraphQL
|
|
43
56
|
relation.where("1=2")
|
44
57
|
end
|
45
58
|
end
|
59
|
+
|
60
|
+
def set_limit(nodes, limit)
|
61
|
+
if already_loaded?(nodes)
|
62
|
+
nodes.take(limit)
|
63
|
+
else
|
64
|
+
super
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def set_offset(nodes, offset)
|
69
|
+
if already_loaded?(nodes)
|
70
|
+
# If the client sent a bogus cursor beyond the size of the relation,
|
71
|
+
# it might get `nil` from `#[...]`, so return an empty array in that case
|
72
|
+
nodes[offset..-1] || []
|
73
|
+
else
|
74
|
+
super
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
private
|
79
|
+
|
80
|
+
def already_loaded?(relation)
|
81
|
+
relation.is_a?(Array) || relation.loaded?
|
82
|
+
end
|
46
83
|
end
|
47
84
|
end
|
48
85
|
end
|
@@ -35,7 +35,7 @@ module GraphQL
|
|
35
35
|
if @nodes && @nodes.count < first
|
36
36
|
false
|
37
37
|
else
|
38
|
-
relation_larger_than(sliced_nodes, first)
|
38
|
+
relation_larger_than(sliced_nodes, @sliced_nodes_offset, first)
|
39
39
|
end
|
40
40
|
else
|
41
41
|
false
|
@@ -54,9 +54,10 @@ module GraphQL
|
|
54
54
|
private
|
55
55
|
|
56
56
|
# @param relation [Object] A database query object
|
57
|
+
# @param _initial_offset [Integer] The number of items already excluded from the relation
|
57
58
|
# @param size [Integer] The value against which we check the relation size
|
58
59
|
# @return [Boolean] True if the number of items in this relation is larger than `size`
|
59
|
-
def relation_larger_than(relation, size)
|
60
|
+
def relation_larger_than(relation, _initial_offset, size)
|
60
61
|
relation_count(set_limit(relation, size + 1)) == size + 1
|
61
62
|
end
|
62
63
|
|
@@ -111,30 +112,51 @@ module GraphQL
|
|
111
112
|
end
|
112
113
|
end
|
113
114
|
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
paginated_nodes = items
|
119
|
-
|
115
|
+
def calculate_sliced_nodes_parameters
|
116
|
+
if defined?(@sliced_nodes_limit)
|
117
|
+
return
|
118
|
+
else
|
120
119
|
if after_offset
|
121
120
|
previous_offset = relation_offset(items) || 0
|
122
|
-
|
121
|
+
relation_offset = previous_offset + after_offset
|
123
122
|
end
|
124
123
|
|
125
124
|
if before_offset && after_offset
|
126
125
|
if after_offset < before_offset
|
127
126
|
# Get the number of items between the two cursors
|
128
127
|
space_between = before_offset - after_offset - 1
|
129
|
-
|
128
|
+
relation_limit = space_between
|
130
129
|
else
|
131
|
-
# TODO I think this is untested
|
132
130
|
# The cursors overextend one another to an empty set
|
133
|
-
|
131
|
+
@sliced_nodes_null_relation = true
|
134
132
|
end
|
135
133
|
elsif before_offset
|
136
134
|
# Use limit to cut off the tail of the relation
|
137
|
-
|
135
|
+
relation_limit = before_offset - 1
|
136
|
+
end
|
137
|
+
|
138
|
+
@sliced_nodes_limit = relation_limit
|
139
|
+
@sliced_nodes_offset = relation_offset || 0
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
# Apply `before` and `after` to the underlying `items`,
|
144
|
+
# returning a new relation.
|
145
|
+
def sliced_nodes
|
146
|
+
@sliced_nodes ||= begin
|
147
|
+
calculate_sliced_nodes_parameters
|
148
|
+
paginated_nodes = items
|
149
|
+
|
150
|
+
if @sliced_nodes_null_relation
|
151
|
+
paginated_nodes = null_relation(paginated_nodes)
|
152
|
+
else
|
153
|
+
if @sliced_nodes_limit
|
154
|
+
paginated_nodes = set_limit(paginated_nodes, @sliced_nodes_limit)
|
155
|
+
end
|
156
|
+
|
157
|
+
if @sliced_nodes_offset
|
158
|
+
paginated_nodes = set_offset(paginated_nodes, @sliced_nodes_offset)
|
159
|
+
end
|
138
160
|
end
|
139
161
|
|
140
162
|
paginated_nodes
|
@@ -155,33 +177,38 @@ module GraphQL
|
|
155
177
|
# returning a new relation
|
156
178
|
def limited_nodes
|
157
179
|
@limited_nodes ||= begin
|
158
|
-
|
159
|
-
|
180
|
+
calculate_sliced_nodes_parameters
|
181
|
+
if @sliced_nodes_null_relation
|
182
|
+
# it's an empty set
|
183
|
+
return sliced_nodes
|
184
|
+
end
|
185
|
+
relation_limit = @sliced_nodes_limit
|
186
|
+
relation_offset = @sliced_nodes_offset
|
160
187
|
|
161
|
-
if first && (
|
188
|
+
if first && (relation_limit.nil? || relation_limit > first)
|
162
189
|
# `first` would create a stricter limit that the one already applied, so add it
|
163
|
-
|
190
|
+
relation_limit = first
|
164
191
|
end
|
165
192
|
|
166
193
|
if last
|
167
|
-
if
|
168
|
-
if last <=
|
194
|
+
if relation_limit
|
195
|
+
if last <= relation_limit
|
169
196
|
# `last` is a smaller slice than the current limit, so apply it
|
170
|
-
|
171
|
-
|
172
|
-
paginated_nodes = set_limit(paginated_nodes, last)
|
197
|
+
relation_offset += (relation_limit - last)
|
198
|
+
relation_limit = last
|
173
199
|
end
|
174
200
|
else
|
175
201
|
# No limit, so get the last items
|
176
|
-
sliced_nodes_count = relation_count(
|
177
|
-
|
178
|
-
|
179
|
-
paginated_nodes = set_limit(paginated_nodes, last)
|
202
|
+
sliced_nodes_count = relation_count(sliced_nodes)
|
203
|
+
relation_offset += (sliced_nodes_count - [last, sliced_nodes_count].min)
|
204
|
+
relation_limit = last
|
180
205
|
end
|
181
206
|
end
|
182
207
|
|
183
|
-
@paged_nodes_offset = relation_offset
|
184
|
-
paginated_nodes
|
208
|
+
@paged_nodes_offset = relation_offset
|
209
|
+
paginated_nodes = items
|
210
|
+
paginated_nodes = set_offset(paginated_nodes, relation_offset)
|
211
|
+
set_limit(paginated_nodes, relation_limit)
|
185
212
|
end
|
186
213
|
end
|
187
214
|
|
@@ -9,7 +9,7 @@ module GraphQL
|
|
9
9
|
include GraphQL::Dig
|
10
10
|
|
11
11
|
def self.construct_arguments_class(argument_owner)
|
12
|
-
argument_definitions = argument_owner.arguments
|
12
|
+
argument_definitions = argument_owner.arguments # rubocop:disable Development/ContextIsPassedCop -- legacy-related
|
13
13
|
argument_owner.arguments_class = Class.new(self) do
|
14
14
|
self.argument_owner = argument_owner
|
15
15
|
self.argument_definitions = argument_definitions
|
@@ -7,7 +7,7 @@ module GraphQL
|
|
7
7
|
Hash.new do |h1, irep_or_ast_node|
|
8
8
|
h1[irep_or_ast_node] = Hash.new do |h2, definition|
|
9
9
|
ast_node = irep_or_ast_node.is_a?(GraphQL::InternalRepresentation::Node) ? irep_or_ast_node.ast_node : irep_or_ast_node
|
10
|
-
h2[definition] = if definition.arguments.empty?
|
10
|
+
h2[definition] = if definition.arguments(query.context).empty?
|
11
11
|
GraphQL::Query::Arguments::NO_ARGS
|
12
12
|
else
|
13
13
|
GraphQL::Query::LiteralInput.from_arguments(
|
@@ -156,8 +156,13 @@ module GraphQL
|
|
156
156
|
@scoped_context = {}
|
157
157
|
end
|
158
158
|
|
159
|
+
# @return [Hash] A hash that will be added verbatim to the result hash, as `"extensions" => { ... }`
|
160
|
+
def response_extensions
|
161
|
+
namespace(:__query_result_extensions__)
|
162
|
+
end
|
163
|
+
|
159
164
|
def dataloader
|
160
|
-
@dataloader ||= query.multiplex ? query.multiplex.dataloader : schema.dataloader_class.new
|
165
|
+
@dataloader ||= self[:dataloader] || (query.multiplex ? query.multiplex.dataloader : schema.dataloader_class.new)
|
161
166
|
end
|
162
167
|
|
163
168
|
# @api private
|
@@ -223,9 +228,12 @@ module GraphQL
|
|
223
228
|
|
224
229
|
# @return [GraphQL::Schema::Warden]
|
225
230
|
def warden
|
226
|
-
@warden ||= @query.warden
|
231
|
+
@warden ||= (@query && @query.warden)
|
227
232
|
end
|
228
233
|
|
234
|
+
# @api private
|
235
|
+
attr_writer :warden
|
236
|
+
|
229
237
|
# Get an isolated hash for `ns`. Doesn't affect user-provided storage.
|
230
238
|
# @param ns [Object] a usage-specific namespace identifier
|
231
239
|
# @return [Hash] namespaced storage
|
@@ -233,6 +241,11 @@ module GraphQL
|
|
233
241
|
@storage[ns]
|
234
242
|
end
|
235
243
|
|
244
|
+
# @return [Boolean] true if this namespace was accessed before
|
245
|
+
def namespace?(ns)
|
246
|
+
@storage.key?(ns)
|
247
|
+
end
|
248
|
+
|
236
249
|
def inspect
|
237
250
|
"#<Query::Context ...>"
|
238
251
|
end
|
@@ -62,7 +62,7 @@ module GraphQL
|
|
62
62
|
raise ArgumentError, "Unexpected ast_arguments: #{ast_arguments}"
|
63
63
|
end
|
64
64
|
|
65
|
-
argument_defns = argument_owner.arguments
|
65
|
+
argument_defns = argument_owner.arguments(context || GraphQL::Query::NullContext)
|
66
66
|
argument_defns.each do |arg_name, arg_defn|
|
67
67
|
ast_arg = indexed_arguments[arg_name]
|
68
68
|
# First, check the argument in the AST.
|
@@ -4,9 +4,11 @@ module GraphQL
|
|
4
4
|
# This object can be `ctx` in places where there is no query
|
5
5
|
class NullContext
|
6
6
|
class NullWarden < GraphQL::Schema::Warden
|
7
|
-
def
|
8
|
-
def
|
9
|
-
def visible_type?(
|
7
|
+
def visible_field?(field, ctx); true; end
|
8
|
+
def visible_argument?(arg, ctx); true; end
|
9
|
+
def visible_type?(type, ctx); true; end
|
10
|
+
def visible_enum_value?(ev, ctx); true; end
|
11
|
+
def visible_type_membership?(tm, ctx); true; end
|
10
12
|
end
|
11
13
|
|
12
14
|
class NullQuery
|
@@ -15,12 +17,15 @@ module GraphQL
|
|
15
17
|
end
|
16
18
|
end
|
17
19
|
|
20
|
+
class NullSchema < GraphQL::Schema
|
21
|
+
end
|
22
|
+
|
18
23
|
attr_reader :schema, :query, :warden, :dataloader
|
19
24
|
|
20
25
|
def initialize
|
21
26
|
@query = NullQuery.new
|
22
27
|
@dataloader = GraphQL::Dataloader::NullDataloader.new
|
23
|
-
@schema =
|
28
|
+
@schema = NullSchema
|
24
29
|
@warden = NullWarden.new(
|
25
30
|
GraphQL::Filter.new,
|
26
31
|
context: self,
|
@@ -31,7 +36,7 @@ module GraphQL
|
|
31
36
|
def [](key); end
|
32
37
|
|
33
38
|
def interpreter?
|
34
|
-
|
39
|
+
true
|
35
40
|
end
|
36
41
|
|
37
42
|
class << self
|
@@ -40,10 +45,10 @@ module GraphQL
|
|
40
45
|
def [](key); end
|
41
46
|
|
42
47
|
def instance
|
43
|
-
@instance
|
48
|
+
@instance ||= self.new
|
44
49
|
end
|
45
50
|
|
46
|
-
def_delegators :instance, :query, :
|
51
|
+
def_delegators :instance, :query, :warden, :schema, :interpreter?, :dataloader
|
47
52
|
end
|
48
53
|
end
|
49
54
|
end
|
@@ -81,7 +81,7 @@ module GraphQL
|
|
81
81
|
# is added to the "errors" key.
|
82
82
|
def get_raw_value
|
83
83
|
begin
|
84
|
-
@field_ctx.schema.middleware.invoke([parent_type, target, field, arguments, @field_ctx])
|
84
|
+
@field_ctx.schema.middleware.invoke([parent_type, target, field, arguments, @field_ctx]) # rubocop:disable Development/ContextIsPassedCop -- unrelated
|
85
85
|
rescue GraphQL::ExecutionError => err
|
86
86
|
err
|
87
87
|
end
|
@@ -45,7 +45,11 @@ module GraphQL
|
|
45
45
|
end
|
46
46
|
elsif default_value != nil
|
47
47
|
memo[variable_name] = if ctx.interpreter?
|
48
|
-
default_value
|
48
|
+
if default_value.is_a?(Language::Nodes::NullValue)
|
49
|
+
nil
|
50
|
+
else
|
51
|
+
default_value
|
52
|
+
end
|
49
53
|
else
|
50
54
|
# Add the variable if it wasn't provided but it has a default value (including `null`)
|
51
55
|
GraphQL::Query::LiteralInput.coerce(variable_type, default_value, self)
|
@@ -10,7 +10,7 @@ module GraphQL
|
|
10
10
|
if obj.is_a?(GraphQL::Schema::Object)
|
11
11
|
obj = obj.object
|
12
12
|
end
|
13
|
-
type = @type.respond_to?(:graphql_definition) ? @type.graphql_definition : @type
|
13
|
+
type = @type.respond_to?(:graphql_definition) ? @type.graphql_definition(silence_deprecation_warning: true) : @type
|
14
14
|
ctx.query.schema.id_from_object(obj, type, ctx)
|
15
15
|
end
|
16
16
|
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require "rubocop"
|
3
|
+
|
4
|
+
module GraphQL
|
5
|
+
module Rubocop
|
6
|
+
module GraphQL
|
7
|
+
class BaseCop < RuboCop::Cop::Base
|
8
|
+
extend RuboCop::Cop::AutoCorrector
|
9
|
+
|
10
|
+
# Return the source of `send_node`, but without the keyword argument represented by `pair_node`
|
11
|
+
def source_without_keyword_argument(send_node, pair_node)
|
12
|
+
# work back to the preceeding comma
|
13
|
+
first_pos = pair_node.location.expression.begin_pos
|
14
|
+
end_pos = pair_node.location.expression.end_pos
|
15
|
+
node_source = send_node.source_range.source
|
16
|
+
node_first_pos = send_node.location.expression.begin_pos
|
17
|
+
|
18
|
+
relative_first_pos = first_pos - node_first_pos
|
19
|
+
relative_last_pos = end_pos - node_first_pos
|
20
|
+
|
21
|
+
begin_removal_pos = relative_first_pos
|
22
|
+
while node_source[begin_removal_pos] != ","
|
23
|
+
begin_removal_pos -= 1
|
24
|
+
if begin_removal_pos < 1
|
25
|
+
raise "Invariant: somehow backtracked to beginning of node looking for a comma (node source: #{node_source.inspect})"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
end_removal_pos = relative_last_pos
|
30
|
+
cleaned_node_source = node_source[0...begin_removal_pos] + node_source[end_removal_pos..-1]
|
31
|
+
cleaned_node_source
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require_relative "base_cop"
|
3
|
+
|
4
|
+
module GraphQL
|
5
|
+
module Rubocop
|
6
|
+
module GraphQL
|
7
|
+
# Identify (and auto-correct) any field configuration which duplicates
|
8
|
+
# the default `null: true` property.
|
9
|
+
#
|
10
|
+
# `null: true` is default because nullable fields can always be converted
|
11
|
+
# to non-null fields (`null: false`) without a breaking change. (The opposite change, from `null: false`
|
12
|
+
# to `null: true`, change.)
|
13
|
+
#
|
14
|
+
# @example
|
15
|
+
# # Both of these define `name: String` in GraphQL:
|
16
|
+
#
|
17
|
+
# # bad
|
18
|
+
# field :name, String, null: true
|
19
|
+
#
|
20
|
+
# # good
|
21
|
+
# field :name, String
|
22
|
+
#
|
23
|
+
class DefaultNullTrue < BaseCop
|
24
|
+
MSG = "`null: true` is the default and can be removed."
|
25
|
+
|
26
|
+
def_node_matcher :field_config_with_null_true?, <<-Pattern
|
27
|
+
(
|
28
|
+
send nil? :field ... (hash $(pair (sym :null) (true)) ...)
|
29
|
+
)
|
30
|
+
Pattern
|
31
|
+
|
32
|
+
def on_send(node)
|
33
|
+
field_config_with_null_true?(node) do |null_config|
|
34
|
+
add_offense(null_config) do |corrector|
|
35
|
+
cleaned_node_source = source_without_keyword_argument(node, null_config)
|
36
|
+
corrector.replace(node.source_range, cleaned_node_source)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require_relative "./base_cop"
|
3
|
+
|
4
|
+
module GraphQL
|
5
|
+
module Rubocop
|
6
|
+
module GraphQL
|
7
|
+
# Identify (and auto-correct) any argument configuration which duplicates
|
8
|
+
# the default `required: true` property.
|
9
|
+
#
|
10
|
+
# `required: true` is default because required arguments can always be converted
|
11
|
+
# to optional arguments (`required: false`) without a breaking change. (The opposite change, from `required: false`
|
12
|
+
# to `required: true`, change.)
|
13
|
+
#
|
14
|
+
# @example
|
15
|
+
# # Both of these define `id: ID!` in GraphQL:
|
16
|
+
#
|
17
|
+
# # bad
|
18
|
+
# argument :id, ID, required: true
|
19
|
+
#
|
20
|
+
# # good
|
21
|
+
# argument :id, ID
|
22
|
+
#
|
23
|
+
class DefaultRequiredTrue < BaseCop
|
24
|
+
MSG = "`required: true` is the default and can be removed."
|
25
|
+
|
26
|
+
def_node_matcher :argument_config_with_required_true?, <<-Pattern
|
27
|
+
(
|
28
|
+
send nil? :argument ... (hash <$(pair (sym :required) (true)) ...>)
|
29
|
+
)
|
30
|
+
Pattern
|
31
|
+
|
32
|
+
def on_send(node)
|
33
|
+
argument_config_with_required_true?(node) do |required_config|
|
34
|
+
add_offense(required_config) do |corrector|
|
35
|
+
cleaned_node_source = source_without_keyword_argument(node, required_config)
|
36
|
+
corrector.replace(node, cleaned_node_source)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|