graphql 1.11.1 → 1.11.6
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 +8 -0
- data/lib/generators/graphql/templates/base_argument.erb +2 -0
- data/lib/generators/graphql/templates/base_enum.erb +2 -0
- data/lib/generators/graphql/templates/base_field.erb +2 -0
- data/lib/generators/graphql/templates/base_input_object.erb +2 -0
- data/lib/generators/graphql/templates/base_interface.erb +2 -0
- data/lib/generators/graphql/templates/base_mutation.erb +2 -0
- data/lib/generators/graphql/templates/base_object.erb +2 -0
- data/lib/generators/graphql/templates/base_scalar.erb +2 -0
- data/lib/generators/graphql/templates/base_union.erb +2 -0
- data/lib/generators/graphql/templates/enum.erb +2 -0
- data/lib/generators/graphql/templates/graphql_controller.erb +13 -9
- data/lib/generators/graphql/templates/interface.erb +2 -0
- data/lib/generators/graphql/templates/loader.erb +2 -0
- data/lib/generators/graphql/templates/mutation.erb +2 -0
- data/lib/generators/graphql/templates/mutation_type.erb +2 -0
- data/lib/generators/graphql/templates/object.erb +2 -0
- data/lib/generators/graphql/templates/query_type.erb +2 -0
- data/lib/generators/graphql/templates/scalar.erb +2 -0
- data/lib/generators/graphql/templates/schema.erb +2 -0
- data/lib/generators/graphql/templates/union.erb +3 -1
- data/lib/graphql.rb +16 -0
- data/lib/graphql/argument.rb +3 -3
- data/lib/graphql/backtrace/tracer.rb +2 -1
- data/lib/graphql/define/assign_global_id_field.rb +2 -2
- data/lib/graphql/directive.rb +4 -0
- data/lib/graphql/execution/interpreter.rb +10 -0
- data/lib/graphql/execution/interpreter/arguments.rb +1 -1
- data/lib/graphql/execution/interpreter/runtime.rb +59 -45
- data/lib/graphql/field.rb +4 -0
- data/lib/graphql/input_object_type.rb +4 -0
- data/lib/graphql/introspection.rb +96 -0
- data/lib/graphql/introspection/field_type.rb +7 -3
- data/lib/graphql/introspection/input_value_type.rb +6 -0
- data/lib/graphql/introspection/introspection_query.rb +6 -92
- data/lib/graphql/introspection/type_type.rb +7 -3
- data/lib/graphql/language/block_string.rb +24 -5
- data/lib/graphql/language/lexer.rb +7 -3
- data/lib/graphql/language/lexer.rl +7 -3
- data/lib/graphql/language/nodes.rb +2 -1
- data/lib/graphql/language/parser.rb +107 -103
- data/lib/graphql/language/parser.y +4 -0
- data/lib/graphql/language/sanitized_printer.rb +59 -26
- data/lib/graphql/language/visitor.rb +2 -2
- data/lib/graphql/name_validator.rb +6 -7
- data/lib/graphql/pagination/connection.rb +6 -8
- data/lib/graphql/pagination/connections.rb +23 -3
- data/lib/graphql/query.rb +2 -2
- data/lib/graphql/query/context.rb +30 -3
- data/lib/graphql/query/fingerprint.rb +2 -0
- data/lib/graphql/query/validation_pipeline.rb +3 -0
- data/lib/graphql/relay/range_add.rb +14 -5
- data/lib/graphql/schema.rb +40 -31
- data/lib/graphql/schema/argument.rb +56 -5
- data/lib/graphql/schema/build_from_definition.rb +67 -38
- data/lib/graphql/schema/build_from_definition/resolve_map.rb +3 -1
- data/lib/graphql/schema/directive/deprecated.rb +1 -1
- data/lib/graphql/schema/enum_value.rb +1 -0
- data/lib/graphql/schema/field.rb +17 -10
- data/lib/graphql/schema/field/connection_extension.rb +44 -34
- data/lib/graphql/schema/input_object.rb +21 -18
- data/lib/graphql/schema/interface.rb +1 -1
- data/lib/graphql/schema/late_bound_type.rb +2 -2
- data/lib/graphql/schema/loader.rb +20 -1
- data/lib/graphql/schema/member/build_type.rb +14 -4
- data/lib/graphql/schema/member/has_arguments.rb +19 -1
- data/lib/graphql/schema/member/has_fields.rb +17 -7
- data/lib/graphql/schema/member/type_system_helpers.rb +2 -2
- data/lib/graphql/schema/mutation.rb +4 -0
- data/lib/graphql/schema/relay_classic_mutation.rb +3 -1
- data/lib/graphql/schema/resolver.rb +6 -0
- data/lib/graphql/schema/resolver/has_payload_type.rb +2 -1
- data/lib/graphql/schema/subscription.rb +2 -12
- data/lib/graphql/schema/timeout.rb +29 -15
- data/lib/graphql/schema/union.rb +29 -0
- data/lib/graphql/schema/unique_within_type.rb +1 -2
- data/lib/graphql/schema/validation.rb +8 -0
- data/lib/graphql/schema/warden.rb +8 -3
- data/lib/graphql/static_validation/literal_validator.rb +7 -7
- data/lib/graphql/static_validation/rules/arguments_are_defined.rb +1 -1
- 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 +1 -2
- data/lib/graphql/static_validation/rules/variables_are_used_and_defined.rb +4 -2
- data/lib/graphql/static_validation/validator.rb +7 -4
- data/lib/graphql/subscriptions.rb +32 -22
- data/lib/graphql/subscriptions/action_cable_subscriptions.rb +45 -20
- data/lib/graphql/subscriptions/serialize.rb +22 -4
- data/lib/graphql/tracing/appoptics_tracing.rb +10 -2
- data/lib/graphql/types/iso_8601_date_time.rb +2 -1
- data/lib/graphql/types/relay/base_connection.rb +6 -5
- data/lib/graphql/unauthorized_error.rb +1 -1
- data/lib/graphql/version.rb +1 -1
- metadata +3 -3
@@ -466,6 +466,10 @@ def self.parse(query_string, filename: nil, tracer: GraphQL::Tracing::NullTracer
|
|
466
466
|
self.new(query_string, filename: filename, tracer: tracer).parse_document
|
467
467
|
end
|
468
468
|
|
469
|
+
def self.parse_file(filename, tracer: GraphQL::Tracing::NullTracer)
|
470
|
+
self.parse(File.read(filename), filename: filename, tracer: tracer)
|
471
|
+
end
|
472
|
+
|
469
473
|
private
|
470
474
|
|
471
475
|
def next_token
|
@@ -19,11 +19,12 @@ module GraphQL
|
|
19
19
|
|
20
20
|
REDACTED = "\"<REDACTED>\""
|
21
21
|
|
22
|
-
def initialize(query)
|
22
|
+
def initialize(query, inline_variables: true)
|
23
23
|
@query = query
|
24
24
|
@current_type = nil
|
25
25
|
@current_field = nil
|
26
26
|
@current_input_type = nil
|
27
|
+
@inline_variables = inline_variables
|
27
28
|
end
|
28
29
|
|
29
30
|
# @return [String, nil] A scrubbed query string, if the query was valid.
|
@@ -36,15 +37,14 @@ module GraphQL
|
|
36
37
|
end
|
37
38
|
|
38
39
|
def print_node(node, indent: "")
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
super
|
40
|
+
case node
|
41
|
+
when FalseClass, Float, Integer, String, TrueClass
|
42
|
+
if @current_argument && redact_argument_value?(@current_argument, node)
|
43
|
+
redacted_argument_value(@current_argument)
|
44
44
|
else
|
45
|
-
|
45
|
+
super
|
46
46
|
end
|
47
|
-
|
47
|
+
when Array
|
48
48
|
old_input_type = @current_input_type
|
49
49
|
if @current_input_type && @current_input_type.list?
|
50
50
|
@current_input_type = @current_input_type.of_type
|
@@ -59,28 +59,57 @@ module GraphQL
|
|
59
59
|
end
|
60
60
|
end
|
61
61
|
|
62
|
+
# Indicates whether or not to redact non-null values for the given argument. Defaults to redacting all strings
|
63
|
+
# arguments but this can be customized by subclasses.
|
64
|
+
def redact_argument_value?(argument, value)
|
65
|
+
# Default to redacting any strings or custom scalars encoded as strings
|
66
|
+
type = argument.type.unwrap
|
67
|
+
value.is_a?(String) && type.kind.scalar? && (type.graphql_name == "String" || !type.default_scalar?)
|
68
|
+
end
|
69
|
+
|
70
|
+
# Returns the value to use for redacted versions of the given argument. Defaults to the
|
71
|
+
# string "<REDACTED>".
|
72
|
+
def redacted_argument_value(argument)
|
73
|
+
REDACTED
|
74
|
+
end
|
75
|
+
|
62
76
|
def print_argument(argument)
|
77
|
+
# We won't have type information if we're recursing into a custom scalar
|
78
|
+
return super if @current_input_type && @current_input_type.kind.scalar?
|
79
|
+
|
63
80
|
arg_owner = @current_input_type || @current_directive || @current_field
|
64
|
-
|
81
|
+
old_current_argument = @current_argument
|
82
|
+
@current_argument = arg_owner.arguments[argument.name]
|
65
83
|
|
66
84
|
old_input_type = @current_input_type
|
67
|
-
@current_input_type =
|
68
|
-
|
85
|
+
@current_input_type = @current_argument.type.non_null? ? @current_argument.type.of_type : @current_argument.type
|
86
|
+
|
87
|
+
argument_value = if coerce_argument_value_to_list?(@current_input_type, argument.value)
|
88
|
+
[argument.value]
|
89
|
+
else
|
90
|
+
argument.value
|
91
|
+
end
|
92
|
+
res = "#{argument.name}: #{print_node(argument_value)}".dup
|
93
|
+
|
69
94
|
@current_input_type = old_input_type
|
95
|
+
@current_argument = old_current_argument
|
70
96
|
res
|
71
97
|
end
|
72
98
|
|
73
|
-
def
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
res
|
99
|
+
def coerce_argument_value_to_list?(type, value)
|
100
|
+
type.list? &&
|
101
|
+
!value.is_a?(Array) &&
|
102
|
+
!value.nil? &&
|
103
|
+
!value.is_a?(GraphQL::Language::Nodes::VariableIdentifier)
|
79
104
|
end
|
80
105
|
|
81
106
|
def print_variable_identifier(variable_id)
|
82
|
-
|
83
|
-
|
107
|
+
if @inline_variables
|
108
|
+
variable_value = query.variables[variable_id.name]
|
109
|
+
print_node(value_to_ast(variable_value, @current_input_type))
|
110
|
+
else
|
111
|
+
super
|
112
|
+
end
|
84
113
|
end
|
85
114
|
|
86
115
|
def print_field(field, indent: "")
|
@@ -132,10 +161,14 @@ module GraphQL
|
|
132
161
|
old_type = @current_type
|
133
162
|
@current_type = query.schema.public_send(operation_definition.operation_type)
|
134
163
|
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
164
|
+
if @inline_variables
|
165
|
+
out = "#{indent}#{operation_definition.operation_type}".dup
|
166
|
+
out << " #{operation_definition.name}" if operation_definition.name
|
167
|
+
out << print_directives(operation_definition.directives)
|
168
|
+
out << print_selections(operation_definition.selections, indent: indent)
|
169
|
+
else
|
170
|
+
out = super
|
171
|
+
end
|
139
172
|
|
140
173
|
@current_type = old_type
|
141
174
|
out
|
@@ -171,10 +204,10 @@ module GraphQL
|
|
171
204
|
arguments: arguments
|
172
205
|
)
|
173
206
|
when "LIST"
|
174
|
-
if value.
|
175
|
-
value.
|
207
|
+
if value.is_a?(Array)
|
208
|
+
value.map { |v| value_to_ast(v, type.of_type) }
|
176
209
|
else
|
177
|
-
[value].
|
210
|
+
[value].map { |v| value_to_ast(v, type.of_type) }
|
178
211
|
end
|
179
212
|
when "ENUM"
|
180
213
|
GraphQL::Language::Nodes::Enum.new(name: value)
|
@@ -89,7 +89,7 @@ module GraphQL
|
|
89
89
|
# @param parent [GraphQL::Language::Nodes::AbstractNode, nil] the previously-visited node, or `nil` if this is the root node.
|
90
90
|
# @return [Array, nil] If there were modifications, it returns an array of new nodes, otherwise, it returns `nil`.
|
91
91
|
def on_abstract_node(node, parent)
|
92
|
-
if node
|
92
|
+
if node.equal?(DELETE_NODE)
|
93
93
|
# This might be passed to `super(DELETE_NODE, ...)`
|
94
94
|
# by a user hook, don't want to keep visiting in that case.
|
95
95
|
nil
|
@@ -179,7 +179,7 @@ module GraphQL
|
|
179
179
|
# The user-provided hook returned a new node.
|
180
180
|
new_parent = new_parent && new_parent.replace_child(node, new_node)
|
181
181
|
return new_node, new_parent
|
182
|
-
elsif new_node
|
182
|
+
elsif new_node.equal?(DELETE_NODE)
|
183
183
|
# The user-provided hook requested to remove this node
|
184
184
|
new_parent = new_parent && new_parent.delete_child(node)
|
185
185
|
return nil, new_parent
|
@@ -1,16 +1,15 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
module GraphQL
|
3
3
|
class NameValidator
|
4
|
-
|
5
|
-
|
6
|
-
def self.validate!(name)
|
7
|
-
raise GraphQL::InvalidNameError.new(name, VALID_NAME_REGEX) unless valid?(name)
|
4
|
+
if !String.method_defined?(:match?)
|
5
|
+
using GraphQL::StringMatchBackport
|
8
6
|
end
|
9
7
|
|
10
|
-
|
8
|
+
VALID_NAME_REGEX = /^[_a-zA-Z][_a-zA-Z0-9]*$/
|
11
9
|
|
12
|
-
def self.
|
13
|
-
name
|
10
|
+
def self.validate!(name)
|
11
|
+
name = name.is_a?(String) ? name : name.to_s
|
12
|
+
raise GraphQL::InvalidNameError.new(name, VALID_NAME_REGEX) unless name.match?(VALID_NAME_REGEX)
|
14
13
|
end
|
15
14
|
end
|
16
15
|
end
|
@@ -15,11 +15,6 @@ module GraphQL
|
|
15
15
|
class PaginationImplementationMissingError < GraphQL::Error
|
16
16
|
end
|
17
17
|
|
18
|
-
# @return [Class] The class to use for wrapping items as `edges { ... }`. Defaults to `Connection::Edge`
|
19
|
-
def self.edge_class
|
20
|
-
self::Edge
|
21
|
-
end
|
22
|
-
|
23
18
|
# @return [Object] A list object, from the application. This is the unpaginated value passed into the connection.
|
24
19
|
attr_reader :items
|
25
20
|
|
@@ -58,7 +53,7 @@ module GraphQL
|
|
58
53
|
# @param last [Integer, nil] Limit parameter from the client, if provided
|
59
54
|
# @param before [String, nil] A cursor for pagination, if the client provided one.
|
60
55
|
# @param max_page_size [Integer, nil] A configured value to cap the result size. Applied as `first` if neither first or last are given.
|
61
|
-
def initialize(items, parent: nil, context: nil, first: nil, after: nil, max_page_size: :not_given, last: nil, before: nil)
|
56
|
+
def initialize(items, parent: nil, context: nil, first: nil, after: nil, max_page_size: :not_given, last: nil, before: nil, edge_class: nil)
|
62
57
|
@items = items
|
63
58
|
@parent = parent
|
64
59
|
@context = context
|
@@ -66,7 +61,7 @@ module GraphQL
|
|
66
61
|
@after_value = after
|
67
62
|
@last_value = last
|
68
63
|
@before_value = before
|
69
|
-
|
64
|
+
@edge_class = edge_class || self.class::Edge
|
70
65
|
# This is only true if the object was _initialized_ with an override
|
71
66
|
# or if one is assigned later.
|
72
67
|
@has_max_page_size_override = max_page_size != :not_given
|
@@ -117,9 +112,12 @@ module GraphQL
|
|
117
112
|
|
118
113
|
# @return [Array<Edge>] {nodes}, but wrapped with Edge instances
|
119
114
|
def edges
|
120
|
-
@edges ||= nodes.map { |n|
|
115
|
+
@edges ||= nodes.map { |n| @edge_class.new(n, self) }
|
121
116
|
end
|
122
117
|
|
118
|
+
# @return [Class] A wrapper class for edges of this connection
|
119
|
+
attr_accessor :edge_class
|
120
|
+
|
123
121
|
# @return [Array<Object>] A slice of {items}, constrained by {@first_value}/{@after_value}/{@last_value}/{@before_value}
|
124
122
|
def nodes
|
125
123
|
raise PaginationImplementationMissingError, "Implement #{self.class}#nodes to paginate `@items`"
|
@@ -63,9 +63,7 @@ module GraphQL
|
|
63
63
|
all_wrappers
|
64
64
|
end
|
65
65
|
|
66
|
-
|
67
|
-
# @api Private
|
68
|
-
def wrap(field, parent, items, arguments, context, wrappers: all_wrappers)
|
66
|
+
def wrapper_for(items, wrappers: all_wrappers)
|
69
67
|
impl = nil
|
70
68
|
|
71
69
|
items.class.ancestors.each { |cls|
|
@@ -73,6 +71,16 @@ module GraphQL
|
|
73
71
|
break if impl
|
74
72
|
}
|
75
73
|
|
74
|
+
impl
|
75
|
+
end
|
76
|
+
|
77
|
+
# Used by the runtime to wrap values in connection wrappers.
|
78
|
+
# @api Private
|
79
|
+
def wrap(field, parent, items, arguments, context, wrappers: all_wrappers)
|
80
|
+
return items if GraphQL::Execution::Interpreter::RawValue === items
|
81
|
+
|
82
|
+
impl = wrapper_for(items, wrappers: wrappers)
|
83
|
+
|
76
84
|
if impl.nil?
|
77
85
|
raise ImplementationMissingError, "Couldn't find a connection wrapper for #{items.class} during #{field.path} (#{items.inspect})"
|
78
86
|
end
|
@@ -86,9 +94,21 @@ module GraphQL
|
|
86
94
|
after: arguments[:after],
|
87
95
|
last: arguments[:last],
|
88
96
|
before: arguments[:before],
|
97
|
+
edge_class: edge_class_for_field(field),
|
89
98
|
)
|
90
99
|
end
|
91
100
|
|
101
|
+
# use an override if there is one
|
102
|
+
# @api private
|
103
|
+
def edge_class_for_field(field)
|
104
|
+
conn_type = field.type.unwrap
|
105
|
+
conn_type_edge_type = conn_type.respond_to?(:edge_class) && conn_type.edge_class
|
106
|
+
if conn_type_edge_type && conn_type_edge_type != Relay::Edge
|
107
|
+
conn_type_edge_type
|
108
|
+
else
|
109
|
+
nil
|
110
|
+
end
|
111
|
+
end
|
92
112
|
protected
|
93
113
|
|
94
114
|
attr_reader :wrappers
|
data/lib/graphql/query.rb
CHANGED
@@ -259,9 +259,9 @@ module GraphQL
|
|
259
259
|
# - Variables inlined to the query
|
260
260
|
# - Strings replaced with `<REDACTED>`
|
261
261
|
# @return [String, nil] Returns nil if the query is invalid.
|
262
|
-
def sanitized_query_string
|
262
|
+
def sanitized_query_string(inline_variables: true)
|
263
263
|
with_prepared_ast {
|
264
|
-
GraphQL::Language::SanitizedPrinter.new(self).sanitized_query_string
|
264
|
+
GraphQL::Language::SanitizedPrinter.new(self, inline_variables: inline_variables).sanitized_query_string
|
265
265
|
}
|
266
266
|
end
|
267
267
|
|
@@ -34,7 +34,7 @@ module GraphQL
|
|
34
34
|
# Remove this child from the result value
|
35
35
|
# (used for null propagation and skip)
|
36
36
|
# @api private
|
37
|
-
def
|
37
|
+
def delete_child(child_ctx)
|
38
38
|
@value.delete(child_ctx.key)
|
39
39
|
end
|
40
40
|
|
@@ -168,7 +168,6 @@ module GraphQL
|
|
168
168
|
attr_accessor :scoped_context
|
169
169
|
|
170
170
|
def_delegators :@provided_values, :[]=
|
171
|
-
def_delegators :to_h, :fetch, :dig
|
172
171
|
def_delegators :@query, :trace, :interpreter?
|
173
172
|
|
174
173
|
# @!method []=(key, value)
|
@@ -180,6 +179,34 @@ module GraphQL
|
|
180
179
|
@provided_values[key]
|
181
180
|
end
|
182
181
|
|
182
|
+
def delete(key)
|
183
|
+
if @scoped_context.key?(key)
|
184
|
+
@scoped_context.delete(key)
|
185
|
+
else
|
186
|
+
@provided_values.delete(key)
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
UNSPECIFIED_FETCH_DEFAULT = Object.new
|
191
|
+
|
192
|
+
def fetch(key, default = UNSPECIFIED_FETCH_DEFAULT)
|
193
|
+
if @scoped_context.key?(key)
|
194
|
+
@scoped_context[key]
|
195
|
+
elsif @provided_values.key?(key)
|
196
|
+
@provided_values[key]
|
197
|
+
elsif default != UNSPECIFIED_FETCH_DEFAULT
|
198
|
+
default
|
199
|
+
elsif block_given?
|
200
|
+
yield(self, key)
|
201
|
+
else
|
202
|
+
raise KeyError.new(key: key)
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
def dig(key, *other_keys)
|
207
|
+
@scoped_context.key?(key) ? @scoped_context.dig(key, *other_keys) : @provided_values.dig(key, *other_keys)
|
208
|
+
end
|
209
|
+
|
183
210
|
def to_h
|
184
211
|
@provided_values.merge(@scoped_context)
|
185
212
|
end
|
@@ -293,7 +320,7 @@ module GraphQL
|
|
293
320
|
end
|
294
321
|
when GraphQL::Execution::Execute::SKIP
|
295
322
|
@parent.skipped = true
|
296
|
-
@parent.
|
323
|
+
@parent.delete_child(self)
|
297
324
|
else
|
298
325
|
@value = new_value
|
299
326
|
end
|
@@ -33,12 +33,21 @@ module GraphQL
|
|
33
33
|
# @param item [Object] The newly-added item (will be wrapped in `edge_class`)
|
34
34
|
# @param parent [Object] The owner of `collection`, will be passed to the connection if provided
|
35
35
|
# @param context [GraphQL::Query::Context] The surrounding `ctx`, will be passed to the connection if provided (this is required for cursor encoders)
|
36
|
-
# @param edge_class [Class] The class to wrap `item` with
|
37
|
-
def initialize(collection:, item:, parent: nil, context: nil, edge_class:
|
38
|
-
|
36
|
+
# @param edge_class [Class] The class to wrap `item` with (defaults to the connection's edge class)
|
37
|
+
def initialize(collection:, item:, parent: nil, context: nil, edge_class: nil)
|
38
|
+
if context && context.schema.new_connections?
|
39
|
+
conn_class = context.schema.connections.wrapper_for(collection)
|
40
|
+
# The rest will be added by ConnectionExtension
|
41
|
+
@connection = conn_class.new(collection, parent: parent, context: context, edge_class: edge_class)
|
42
|
+
@edge = @connection.edge_class.new(item, @connection)
|
43
|
+
else
|
44
|
+
connection_class = BaseConnection.connection_for_nodes(collection)
|
45
|
+
@connection = connection_class.new(collection, {}, parent: parent, context: context)
|
46
|
+
edge_class ||= Relay::Edge
|
47
|
+
@edge = edge_class.new(item, @connection)
|
48
|
+
end
|
49
|
+
|
39
50
|
@parent = parent
|
40
|
-
@connection = connection_class.new(collection, {}, parent: parent, context: context)
|
41
|
-
@edge = edge_class.new(item, @connection)
|
42
51
|
end
|
43
52
|
end
|
44
53
|
end
|
data/lib/graphql/schema.rb
CHANGED
@@ -127,7 +127,7 @@ module GraphQL
|
|
127
127
|
end
|
128
128
|
end
|
129
129
|
|
130
|
-
# @return [Symbol, nil] The method name to lazily resolve `obj`, or nil if `obj`'s class wasn't registered
|
130
|
+
# @return [Symbol, nil] The method name to lazily resolve `obj`, or nil if `obj`'s class wasn't registered with {#lazy_resolve}.
|
131
131
|
def lazy_method_name(obj)
|
132
132
|
lazy_methods.get(obj)
|
133
133
|
end
|
@@ -789,20 +789,25 @@ module GraphQL
|
|
789
789
|
# @param using [Hash] Plugins to attach to the created schema with `use(key, value)`
|
790
790
|
# @param interpreter [Boolean] If false, the legacy {Execution::Execute} runtime will be used
|
791
791
|
# @return [Class] the schema described by `document`
|
792
|
-
def self.from_definition(definition_or_path, default_resolve: nil, interpreter: true, parser:
|
792
|
+
def self.from_definition(definition_or_path, default_resolve: nil, interpreter: true, parser: GraphQL.default_parser, using: {})
|
793
793
|
# If the file ends in `.graphql`, treat it like a filepath
|
794
|
-
|
795
|
-
|
794
|
+
if definition_or_path.end_with?(".graphql")
|
795
|
+
GraphQL::Schema::BuildFromDefinition.from_definition_path(
|
796
|
+
definition_or_path,
|
797
|
+
default_resolve: default_resolve,
|
798
|
+
parser: parser,
|
799
|
+
using: using,
|
800
|
+
interpreter: interpreter,
|
801
|
+
)
|
796
802
|
else
|
797
|
-
|
798
|
-
|
799
|
-
|
800
|
-
|
801
|
-
|
802
|
-
|
803
|
-
|
804
|
-
|
805
|
-
)
|
803
|
+
GraphQL::Schema::BuildFromDefinition.from_definition(
|
804
|
+
definition_or_path,
|
805
|
+
default_resolve: default_resolve,
|
806
|
+
parser: parser,
|
807
|
+
using: using,
|
808
|
+
interpreter: interpreter,
|
809
|
+
)
|
810
|
+
end
|
806
811
|
end
|
807
812
|
|
808
813
|
# Error that is raised when [#Schema#from_definition] is passed an invalid schema definition string.
|
@@ -832,7 +837,7 @@ module GraphQL
|
|
832
837
|
# @param except [<#call(member, ctx)>]
|
833
838
|
# @return [Hash] GraphQL result
|
834
839
|
def as_json(only: nil, except: nil, context: {})
|
835
|
-
execute(Introspection
|
840
|
+
execute(Introspection.query(include_deprecated_args: true), only: only, except: except, context: context).to_h
|
836
841
|
end
|
837
842
|
|
838
843
|
# Returns the JSON response of {Introspection::INTROSPECTION_QUERY}.
|
@@ -880,7 +885,7 @@ module GraphQL
|
|
880
885
|
# @param except [<#call(member, ctx)>]
|
881
886
|
# @return [Hash] GraphQL result
|
882
887
|
def as_json(only: nil, except: nil, context: {})
|
883
|
-
execute(Introspection
|
888
|
+
execute(Introspection.query(include_deprecated_args: true), only: only, except: except, context: context).to_h
|
884
889
|
end
|
885
890
|
|
886
891
|
# Return the GraphQL IDL for the schema
|
@@ -1112,7 +1117,16 @@ module GraphQL
|
|
1112
1117
|
if type.kind.union?
|
1113
1118
|
type.possible_types(context: context)
|
1114
1119
|
else
|
1115
|
-
own_possible_types[type.graphql_name]
|
1120
|
+
stored_possible_types = own_possible_types[type.graphql_name]
|
1121
|
+
visible_possible_types = stored_possible_types.select do |possible_type|
|
1122
|
+
next true unless type.kind.interface?
|
1123
|
+
next true unless possible_type.kind.object?
|
1124
|
+
|
1125
|
+
# Use `.graphql_name` comparison to match legacy vs class-based types.
|
1126
|
+
# When we don't need to support legacy `.define` types, use `.include?(type)` instead.
|
1127
|
+
possible_type.interfaces(context).any? { |interface| interface.graphql_name == type.graphql_name }
|
1128
|
+
end if stored_possible_types
|
1129
|
+
visible_possible_types ||
|
1116
1130
|
introspection_system.possible_types[type.graphql_name] ||
|
1117
1131
|
(
|
1118
1132
|
superclass.respond_to?(:possible_types) ?
|
@@ -1534,9 +1548,9 @@ module GraphQL
|
|
1534
1548
|
|
1535
1549
|
# Add several directives at once
|
1536
1550
|
# @param new_directives [Class]
|
1537
|
-
def directives(new_directives
|
1538
|
-
if new_directives
|
1539
|
-
new_directives.each { |d| directive(d) }
|
1551
|
+
def directives(*new_directives)
|
1552
|
+
if new_directives.any?
|
1553
|
+
new_directives.flatten.each { |d| directive(d) }
|
1540
1554
|
end
|
1541
1555
|
|
1542
1556
|
find_inherited_value(:directives, default_directives).merge(own_directives)
|
@@ -1550,11 +1564,11 @@ module GraphQL
|
|
1550
1564
|
end
|
1551
1565
|
|
1552
1566
|
def default_directives
|
1553
|
-
{
|
1567
|
+
@default_directives ||= {
|
1554
1568
|
"include" => GraphQL::Schema::Directive::Include,
|
1555
1569
|
"skip" => GraphQL::Schema::Directive::Skip,
|
1556
1570
|
"deprecated" => GraphQL::Schema::Directive::Deprecated,
|
1557
|
-
}
|
1571
|
+
}.freeze
|
1558
1572
|
end
|
1559
1573
|
|
1560
1574
|
def tracer(new_tracer)
|
@@ -1663,6 +1677,10 @@ module GraphQL
|
|
1663
1677
|
end
|
1664
1678
|
end
|
1665
1679
|
|
1680
|
+
def query_stack_error(query, err)
|
1681
|
+
query.context.errors.push(GraphQL::ExecutionError.new("This query is too large to execute."))
|
1682
|
+
end
|
1683
|
+
|
1666
1684
|
private
|
1667
1685
|
|
1668
1686
|
def lazy_methods
|
@@ -1783,16 +1801,7 @@ module GraphQL
|
|
1783
1801
|
if owner.kind.union?
|
1784
1802
|
# It's a union with possible_types
|
1785
1803
|
# Replace the item by class name
|
1786
|
-
owner.
|
1787
|
-
possible_type = tm.object_type
|
1788
|
-
if possible_type.is_a?(String) && (possible_type == type.name)
|
1789
|
-
# This is a match of Ruby class names, not graphql names,
|
1790
|
-
# since strings are used to refer to constants.
|
1791
|
-
tm.object_type = type
|
1792
|
-
elsif possible_type.is_a?(LateBoundType) && possible_type.graphql_name == type.graphql_name
|
1793
|
-
tm.object_type = type
|
1794
|
-
end
|
1795
|
-
}
|
1804
|
+
owner.assign_type_membership_object_type(type)
|
1796
1805
|
own_possible_types[owner.graphql_name] = owner.possible_types
|
1797
1806
|
elsif type.kind.interface? && owner.kind.object?
|
1798
1807
|
new_interfaces = []
|