graphql 1.11.1 → 1.11.6
Sign up to get free protection for your applications and to get access to all the features.
- 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 = []
|