graphql 1.12.25 → 1.13.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.
Potentially problematic release.
This version of graphql might be problematic. Click here for more details.
- checksums.yaml +4 -4
- 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 +4 -8
- 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/dataloader.rb +55 -22
- 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 +20 -12
- data/lib/graphql/execution/lookahead.rb +2 -2
- data/lib/graphql/execution/multiplex.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 +0 -4
- data/lib/graphql/language/document_from_schema_definition.rb +4 -2
- data/lib/graphql/language/lexer.rb +0 -3
- data/lib/graphql/language/lexer.rl +0 -4
- data/lib/graphql/language/nodes.rb +3 -14
- 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/query/arguments.rb +1 -1
- data/lib/graphql/query/arguments_cache.rb +1 -1
- data/lib/graphql/query/context.rb +5 -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/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 +11 -9
- data/lib/graphql/schema/build_from_definition.rb +12 -13
- 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 +2 -6
- data/lib/graphql/schema/enum.rb +57 -9
- data/lib/graphql/schema/enum_value.rb +5 -1
- data/lib/graphql/schema/field/connection_extension.rb +1 -1
- data/lib/graphql/schema/field.rb +92 -18
- 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 +11 -13
- data/lib/graphql/schema/interface.rb +8 -19
- data/lib/graphql/schema/member/accepts_definition.rb +8 -1
- data/lib/graphql/schema/member/build_type.rb +0 -4
- 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/object.rb +7 -74
- data/lib/graphql/schema/printer.rb +1 -1
- data/lib/graphql/schema/relay_classic_mutation.rb +29 -3
- data/lib/graphql/schema/resolver/has_payload_type.rb +27 -2
- data/lib/graphql/schema/resolver.rb +19 -5
- data/lib/graphql/schema/subscription.rb +11 -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 +6 -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/warden.rb +116 -52
- data/lib/graphql/schema.rb +87 -15
- 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 +8 -15
- data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +1 -3
- 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 +7 -7
- data/lib/graphql/subscriptions/action_cable_subscriptions.rb +6 -4
- data/lib/graphql/subscriptions/event.rb +20 -12
- data/lib/graphql/subscriptions.rb +17 -19
- 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/version.rb +1 -1
- data/lib/graphql.rb +9 -31
- metadata +14 -6
@@ -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
|
@@ -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(
|
@@ -157,7 +157,7 @@ module GraphQL
|
|
157
157
|
end
|
158
158
|
|
159
159
|
def dataloader
|
160
|
-
@dataloader ||= query.multiplex ? query.multiplex.dataloader : schema.dataloader_class.new
|
160
|
+
@dataloader ||= self[:dataloader] || (query.multiplex ? query.multiplex.dataloader : schema.dataloader_class.new)
|
161
161
|
end
|
162
162
|
|
163
163
|
# @api private
|
@@ -223,9 +223,12 @@ module GraphQL
|
|
223
223
|
|
224
224
|
# @return [GraphQL::Schema::Warden]
|
225
225
|
def warden
|
226
|
-
@warden ||= @query.warden
|
226
|
+
@warden ||= (@query && @query.warden)
|
227
227
|
end
|
228
228
|
|
229
|
+
# @api private
|
230
|
+
attr_writer :warden
|
231
|
+
|
229
232
|
# Get an isolated hash for `ns`. Doesn't affect user-provided storage.
|
230
233
|
# @param ns [Object] a usage-specific namespace identifier
|
231
234
|
# @return [Hash] namespaced storage
|
@@ -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)
|
@@ -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
|
@@ -24,7 +24,13 @@ module GraphQL
|
|
24
24
|
end
|
25
25
|
|
26
26
|
def get_type(name)
|
27
|
-
@types[name]
|
27
|
+
local_type = @types[name]
|
28
|
+
# This isn't really sophisticated, but
|
29
|
+
# I think it's good enough to support the current usage of LateBoundTypes
|
30
|
+
if local_type.is_a?(Array)
|
31
|
+
local_type = local_type.first
|
32
|
+
end
|
33
|
+
local_type || @schema.get_type(name)
|
28
34
|
end
|
29
35
|
|
30
36
|
# Lookup using `own_types` here because it's ok to override
|
@@ -77,13 +83,13 @@ module GraphQL
|
|
77
83
|
|
78
84
|
def update_type_owner(owner, type)
|
79
85
|
case owner
|
80
|
-
when
|
86
|
+
when Module
|
81
87
|
if owner.kind.union?
|
82
88
|
# It's a union with possible_types
|
83
89
|
# Replace the item by class name
|
84
90
|
owner.assign_type_membership_object_type(type)
|
85
91
|
@possible_types[owner.graphql_name] = owner.possible_types
|
86
|
-
elsif type.kind.interface? && owner.kind.object?
|
92
|
+
elsif type.kind.interface? && (owner.kind.object? || owner.kind.interface?)
|
87
93
|
new_interfaces = []
|
88
94
|
owner.interfaces.each do |int_t|
|
89
95
|
if int_t.is_a?(String) && int_t == type.graphql_name
|
@@ -98,12 +104,11 @@ module GraphQL
|
|
98
104
|
owner.implements(*new_interfaces)
|
99
105
|
new_interfaces.each do |int|
|
100
106
|
pt = @possible_types[int.graphql_name] ||= []
|
101
|
-
if !pt.include?(owner)
|
107
|
+
if !pt.include?(owner) && owner.is_a?(Class)
|
102
108
|
pt << owner
|
103
109
|
end
|
104
110
|
end
|
105
111
|
end
|
106
|
-
|
107
112
|
when nil
|
108
113
|
# It's a root type
|
109
114
|
@types[type.graphql_name] = type
|
@@ -148,42 +153,42 @@ module GraphQL
|
|
148
153
|
um << owner
|
149
154
|
end
|
150
155
|
|
151
|
-
if (prev_type = get_local_type(type.graphql_name))
|
152
|
-
|
153
|
-
raise DuplicateTypeNamesError.new(
|
154
|
-
type_name: type.graphql_name,
|
155
|
-
first_definition: prev_type,
|
156
|
-
second_definition: type,
|
157
|
-
path: path,
|
158
|
-
)
|
159
|
-
else
|
160
|
-
# This type was already added
|
161
|
-
end
|
156
|
+
if (prev_type = get_local_type(type.graphql_name)) && prev_type == type
|
157
|
+
# No need to re-visit
|
162
158
|
elsif type.is_a?(Class) && type < GraphQL::Schema::Directive
|
163
159
|
@directives << type
|
164
|
-
type.
|
160
|
+
type.all_argument_definitions.each do |arg|
|
165
161
|
arg_type = arg.type.unwrap
|
166
162
|
references_to(arg_type, from: arg)
|
167
|
-
add_type(arg_type, owner: arg, late_types: late_types, path: path + [
|
163
|
+
add_type(arg_type, owner: arg, late_types: late_types, path: path + [arg.graphql_name])
|
168
164
|
if arg.default_value?
|
169
165
|
@arguments_with_default_values << arg
|
170
166
|
end
|
171
167
|
end
|
172
168
|
else
|
173
|
-
@types[type.graphql_name]
|
169
|
+
prev_type = @types[type.graphql_name]
|
170
|
+
if prev_type.nil?
|
171
|
+
@types[type.graphql_name] = type
|
172
|
+
elsif prev_type.is_a?(Array)
|
173
|
+
prev_type << type
|
174
|
+
else
|
175
|
+
@types[type.graphql_name] = [prev_type, type]
|
176
|
+
end
|
177
|
+
|
174
178
|
add_directives_from(type)
|
175
179
|
if type.kind.fields?
|
176
|
-
type.
|
180
|
+
type.all_field_definitions.each do |field|
|
181
|
+
name = field.graphql_name
|
177
182
|
field_type = field.type.unwrap
|
178
183
|
references_to(field_type, from: field)
|
179
184
|
field_path = path + [name]
|
180
185
|
add_type(field_type, owner: field, late_types: late_types, path: field_path)
|
181
186
|
add_directives_from(field)
|
182
|
-
field.
|
187
|
+
field.all_argument_definitions.each do |arg|
|
183
188
|
add_directives_from(arg)
|
184
189
|
arg_type = arg.type.unwrap
|
185
190
|
references_to(arg_type, from: arg)
|
186
|
-
add_type(arg_type, owner: arg, late_types: late_types, path: field_path + [
|
191
|
+
add_type(arg_type, owner: arg, late_types: late_types, path: field_path + [arg.graphql_name])
|
187
192
|
if arg.default_value?
|
188
193
|
@arguments_with_default_values << arg
|
189
194
|
end
|
@@ -191,19 +196,19 @@ module GraphQL
|
|
191
196
|
end
|
192
197
|
end
|
193
198
|
if type.kind.input_object?
|
194
|
-
type.
|
199
|
+
type.all_argument_definitions.each do |arg|
|
195
200
|
add_directives_from(arg)
|
196
201
|
arg_type = arg.type.unwrap
|
197
202
|
references_to(arg_type, from: arg)
|
198
|
-
add_type(arg_type, owner: arg, late_types: late_types, path: path + [
|
203
|
+
add_type(arg_type, owner: arg, late_types: late_types, path: path + [arg.graphql_name])
|
199
204
|
if arg.default_value?
|
200
205
|
@arguments_with_default_values << arg
|
201
206
|
end
|
202
207
|
end
|
203
208
|
end
|
204
209
|
if type.kind.union?
|
205
|
-
@possible_types[type.graphql_name] = type.
|
206
|
-
type.
|
210
|
+
@possible_types[type.graphql_name] = type.all_possible_types
|
211
|
+
type.all_possible_types.each do |t|
|
207
212
|
add_type(t, owner: type, late_types: late_types, path: path + ["possible_types"])
|
208
213
|
end
|
209
214
|
end
|
@@ -213,13 +218,17 @@ module GraphQL
|
|
213
218
|
end
|
214
219
|
end
|
215
220
|
if type.kind.object?
|
216
|
-
@possible_types[type.graphql_name]
|
221
|
+
possible_types_for_this_name = @possible_types[type.graphql_name] ||= []
|
222
|
+
possible_types_for_this_name << type
|
223
|
+
end
|
224
|
+
|
225
|
+
if type.kind.object? || type.kind.interface?
|
217
226
|
type.interface_type_memberships.each do |interface_type_membership|
|
218
227
|
case interface_type_membership
|
219
228
|
when Schema::TypeMembership
|
220
229
|
interface_type = interface_type_membership.abstract_type
|
221
230
|
# We can get these now; we'll have to get late-bound types later
|
222
|
-
if interface_type.is_a?(Module)
|
231
|
+
if interface_type.is_a?(Module) && type.is_a?(Class)
|
223
232
|
implementers = @possible_types[interface_type.graphql_name] ||= []
|
224
233
|
implementers << type
|
225
234
|
end
|
@@ -2,10 +2,6 @@
|
|
2
2
|
module GraphQL
|
3
3
|
class Schema
|
4
4
|
class Argument
|
5
|
-
if !String.method_defined?(:-@)
|
6
|
-
using GraphQL::StringDedupBackport
|
7
|
-
end
|
8
|
-
|
9
5
|
include GraphQL::Schema::Member::CachedGraphQLDefinition
|
10
6
|
include GraphQL::Schema::Member::AcceptsDefinition
|
11
7
|
include GraphQL::Schema::Member::HasPath
|
@@ -52,10 +48,9 @@ module GraphQL
|
|
52
48
|
# @param directives [Hash{Class => Hash}]
|
53
49
|
# @param deprecation_reason [String]
|
54
50
|
# @param validates [Hash, nil] Options for building validators, if any should be applied
|
55
|
-
def initialize(arg_name = nil, type_expr = nil, desc = nil, required
|
51
|
+
def initialize(arg_name = nil, type_expr = nil, desc = nil, required: true, type: nil, name: nil, loads: nil, description: nil, ast_node: nil, default_value: NO_DEFAULT, as: nil, from_resolver: false, camelize: true, prepare: nil, method_access: true, owner:, validates: nil, directives: nil, deprecation_reason: nil, &definition_block)
|
56
52
|
arg_name ||= name
|
57
53
|
@name = -(camelize ? Member::BuildType.camelize(arg_name.to_s) : arg_name.to_s)
|
58
|
-
NameValidator.validate!(@name)
|
59
54
|
@type_expr = type_expr || type
|
60
55
|
@description = desc || description
|
61
56
|
@null = !required
|
@@ -79,11 +74,18 @@ module GraphQL
|
|
79
74
|
self.validates(validates)
|
80
75
|
|
81
76
|
if definition_block
|
82
|
-
|
83
|
-
|
77
|
+
if definition_block.arity == 1
|
78
|
+
instance_exec(self, &definition_block)
|
79
|
+
else
|
80
|
+
instance_eval(&definition_block)
|
81
|
+
end
|
84
82
|
end
|
85
83
|
end
|
86
84
|
|
85
|
+
def inspect
|
86
|
+
"#<#{self.class} #{path}: #{type.to_type_signature}#{description ? " @description=#{description.inspect}" : ""}>"
|
87
|
+
end
|
88
|
+
|
87
89
|
# @return [Object] the value used when the client doesn't provide a value for this argument
|
88
90
|
attr_reader :default_value
|
89
91
|
|
@@ -145,7 +147,7 @@ module GraphQL
|
|
145
147
|
end
|
146
148
|
end
|
147
149
|
elsif as_type.kind.input_object?
|
148
|
-
as_type.arguments.each do |_name, input_obj_arg|
|
150
|
+
as_type.arguments(ctx).each do |_name, input_obj_arg|
|
149
151
|
input_obj_arg = input_obj_arg.type_class
|
150
152
|
# TODO: this skips input objects whose values were alread replaced with application objects.
|
151
153
|
# See: https://github.com/rmosolgo/graphql-ruby/issues/2633
|
@@ -3,12 +3,7 @@ require "graphql/schema/build_from_definition/resolve_map"
|
|
3
3
|
|
4
4
|
module GraphQL
|
5
5
|
class Schema
|
6
|
-
# TODO Populate `.directive(...)` from here
|
7
6
|
module BuildFromDefinition
|
8
|
-
if !String.method_defined?(:-@)
|
9
|
-
using GraphQL::StringDedupBackport
|
10
|
-
end
|
11
|
-
|
12
7
|
class << self
|
13
8
|
# @see {Schema.from_definition}
|
14
9
|
def from_definition(definition_string, parser: GraphQL.default_parser, **kwargs)
|
@@ -394,6 +389,11 @@ module GraphQL
|
|
394
389
|
include GraphQL::Schema::Interface
|
395
390
|
graphql_name(interface_type_definition.name)
|
396
391
|
description(interface_type_definition.description)
|
392
|
+
interface_type_definition.interfaces.each do |interface_name|
|
393
|
+
"Implements: #{interface_type_definition} -> #{interface_name}"
|
394
|
+
interface_defn = type_resolver.call(interface_name)
|
395
|
+
implements(interface_defn)
|
396
|
+
end
|
397
397
|
ast_node(interface_type_definition)
|
398
398
|
builder.build_directives(self, interface_type_definition, type_resolver)
|
399
399
|
|
@@ -426,18 +426,17 @@ module GraphQL
|
|
426
426
|
|
427
427
|
# Don't do this for interfaces
|
428
428
|
if default_resolve
|
429
|
-
|
429
|
+
owner.class_eval <<-RUBY, __FILE__, __LINE__
|
430
|
+
# frozen_string_literal: true
|
431
|
+
def #{resolve_method_name}(**args)
|
432
|
+
field_instance = self.class.get_field("#{field_definition.name}")
|
433
|
+
context.schema.definition_default_resolve.call(self.class, field_instance, object, args, context)
|
434
|
+
end
|
435
|
+
RUBY
|
430
436
|
end
|
431
437
|
end
|
432
438
|
end
|
433
439
|
|
434
|
-
def define_field_resolve_method(owner, method_name, field_name)
|
435
|
-
owner.define_method(method_name) { |**args|
|
436
|
-
field_instance = self.class.get_field(field_name)
|
437
|
-
context.schema.definition_default_resolve.call(self.class, field_instance, object, args, context)
|
438
|
-
}
|
439
|
-
end
|
440
|
-
|
441
440
|
def build_resolve_type(lookup_hash, directives, missing_type_handler)
|
442
441
|
resolve_type_proc = nil
|
443
442
|
resolve_type_proc = ->(ast_node) {
|