graphql 1.11.4 → 1.11.5
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/templates/union.erb +1 -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/execution/interpreter.rb +10 -0
- data/lib/graphql/execution/interpreter/arguments.rb +1 -1
- data/lib/graphql/execution/interpreter/runtime.rb +32 -18
- 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 +1 -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/name_validator.rb +6 -7
- data/lib/graphql/pagination/connections.rb +2 -0
- data/lib/graphql/query.rb +2 -2
- data/lib/graphql/query/context.rb +10 -2
- data/lib/graphql/schema.rb +30 -16
- data/lib/graphql/schema/argument.rb +56 -5
- data/lib/graphql/schema/build_from_definition.rb +60 -35
- data/lib/graphql/schema/directive/deprecated.rb +1 -1
- data/lib/graphql/schema/field.rb +10 -4
- data/lib/graphql/schema/input_object.rb +5 -3
- data/lib/graphql/schema/interface.rb +1 -1
- data/lib/graphql/schema/late_bound_type.rb +2 -2
- data/lib/graphql/schema/loader.rb +1 -0
- data/lib/graphql/schema/member/build_type.rb +14 -4
- data/lib/graphql/schema/member/has_arguments.rb +3 -1
- data/lib/graphql/schema/member/type_system_helpers.rb +2 -2
- data/lib/graphql/schema/relay_classic_mutation.rb +3 -1
- data/lib/graphql/schema/timeout.rb +29 -15
- data/lib/graphql/schema/validation.rb +8 -0
- data/lib/graphql/static_validation/validator.rb +7 -4
- data/lib/graphql/subscriptions.rb +1 -3
- data/lib/graphql/subscriptions/action_cable_subscriptions.rb +21 -7
- data/lib/graphql/version.rb +1 -1
- metadata +2 -2
@@ -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)
|
@@ -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
|
@@ -66,6 +66,8 @@ module GraphQL
|
|
66
66
|
# Used by the runtime to wrap values in connection wrappers.
|
67
67
|
# @api Private
|
68
68
|
def wrap(field, parent, items, arguments, context, wrappers: all_wrappers)
|
69
|
+
return items if GraphQL::Execution::Interpreter::RawValue === items
|
70
|
+
|
69
71
|
impl = nil
|
70
72
|
|
71
73
|
items.class.ancestors.each { |cls|
|
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
|
|
@@ -179,6 +179,14 @@ module GraphQL
|
|
179
179
|
@provided_values[key]
|
180
180
|
end
|
181
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
|
+
|
182
190
|
UNSPECIFIED_FETCH_DEFAULT = Object.new
|
183
191
|
|
184
192
|
def fetch(key, default = UNSPECIFIED_FETCH_DEFAULT)
|
@@ -312,7 +320,7 @@ module GraphQL
|
|
312
320
|
end
|
313
321
|
when GraphQL::Execution::Execute::SKIP
|
314
322
|
@parent.skipped = true
|
315
|
-
@parent.
|
323
|
+
@parent.delete_child(self)
|
316
324
|
else
|
317
325
|
@value = new_value
|
318
326
|
end
|
data/lib/graphql/schema.rb
CHANGED
@@ -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) ?
|
@@ -1664,7 +1678,7 @@ module GraphQL
|
|
1664
1678
|
end
|
1665
1679
|
|
1666
1680
|
def query_stack_error(query, err)
|
1667
|
-
query.
|
1681
|
+
query.context.errors.push(GraphQL::ExecutionError.new("This query is too large to execute."))
|
1668
1682
|
end
|
1669
1683
|
|
1670
1684
|
private
|
@@ -45,7 +45,8 @@ module GraphQL
|
|
45
45
|
# @param camelize [Boolean] if true, the name will be camelized when building the schema
|
46
46
|
# @param from_resolver [Boolean] if true, a Resolver class defined this argument
|
47
47
|
# @param method_access [Boolean] If false, don't build method access on legacy {Query::Arguments} instances.
|
48
|
-
|
48
|
+
# @param deprecation_reason [String]
|
49
|
+
def initialize(arg_name = nil, type_expr = nil, desc = nil, required:, 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:, deprecation_reason: nil, &definition_block)
|
49
50
|
arg_name ||= name
|
50
51
|
@name = -(camelize ? Member::BuildType.camelize(arg_name.to_s) : arg_name.to_s)
|
51
52
|
@type_expr = type_expr || type
|
@@ -60,6 +61,7 @@ module GraphQL
|
|
60
61
|
@ast_node = ast_node
|
61
62
|
@from_resolver = from_resolver
|
62
63
|
@method_access = method_access
|
64
|
+
self.deprecation_reason = deprecation_reason
|
63
65
|
|
64
66
|
if definition_block
|
65
67
|
if definition_block.arity == 1
|
@@ -89,6 +91,18 @@ module GraphQL
|
|
89
91
|
end
|
90
92
|
end
|
91
93
|
|
94
|
+
# @return [String] Deprecation reason for this argument
|
95
|
+
def deprecation_reason(text = nil)
|
96
|
+
if text
|
97
|
+
validate_deprecated_or_optional(null: @null, deprecation_reason: text)
|
98
|
+
@deprecation_reason = text
|
99
|
+
else
|
100
|
+
@deprecation_reason
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
alias_method :deprecation_reason=, :deprecation_reason
|
105
|
+
|
92
106
|
def visible?(context)
|
93
107
|
true
|
94
108
|
end
|
@@ -143,15 +157,32 @@ module GraphQL
|
|
143
157
|
if NO_DEFAULT != @default_value
|
144
158
|
argument.default_value = @default_value
|
145
159
|
end
|
160
|
+
if @deprecation_reason
|
161
|
+
argument.deprecation_reason = @deprecation_reason
|
162
|
+
end
|
146
163
|
argument
|
147
164
|
end
|
148
165
|
|
149
|
-
|
166
|
+
def type=(new_type)
|
167
|
+
validate_input_type(new_type)
|
168
|
+
# This isn't true for LateBoundTypes, but we can assume those will
|
169
|
+
# be updated via this codepath later in schema setup.
|
170
|
+
if new_type.respond_to?(:non_null?)
|
171
|
+
validate_deprecated_or_optional(null: !new_type.non_null?, deprecation_reason: deprecation_reason)
|
172
|
+
end
|
173
|
+
@type = new_type
|
174
|
+
end
|
150
175
|
|
151
176
|
def type
|
152
|
-
@type ||=
|
153
|
-
|
154
|
-
|
177
|
+
@type ||= begin
|
178
|
+
parsed_type = begin
|
179
|
+
Member::BuildType.parse_type(@type_expr, null: @null)
|
180
|
+
rescue StandardError => err
|
181
|
+
raise ArgumentError, "Couldn't build type for Argument #{@owner.name}.#{name}: #{err.class.name}: #{err.message}", err.backtrace
|
182
|
+
end
|
183
|
+
# Use the setter method to get validations
|
184
|
+
self.type = parsed_type
|
185
|
+
end
|
155
186
|
end
|
156
187
|
|
157
188
|
def statically_coercible?
|
@@ -186,6 +217,26 @@ module GraphQL
|
|
186
217
|
raise "Invalid prepare for #{@owner.name}.name: #{@prepare.inspect}"
|
187
218
|
end
|
188
219
|
end
|
220
|
+
|
221
|
+
private
|
222
|
+
|
223
|
+
def validate_input_type(input_type)
|
224
|
+
if input_type.is_a?(String) || input_type.is_a?(GraphQL::Schema::LateBoundType)
|
225
|
+
# Do nothing; assume this will be validated later
|
226
|
+
elsif input_type.kind.non_null? || input_type.kind.list?
|
227
|
+
validate_input_type(input_type.unwrap)
|
228
|
+
elsif !input_type.kind.input?
|
229
|
+
raise ArgumentError, "Invalid input type for #{path}: #{input_type.graphql_name}. Must be scalar, enum, or input object, not #{input_type.kind.name}."
|
230
|
+
else
|
231
|
+
# It's an input type, we're OK
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
def validate_deprecated_or_optional(null:, deprecation_reason:)
|
236
|
+
if deprecation_reason && !null
|
237
|
+
raise ArgumentError, "Required arguments cannot be deprecated: #{path}."
|
238
|
+
end
|
239
|
+
end
|
189
240
|
end
|
190
241
|
end
|
191
242
|
end
|
@@ -4,17 +4,24 @@ require "graphql/schema/build_from_definition/resolve_map"
|
|
4
4
|
module GraphQL
|
5
5
|
class Schema
|
6
6
|
module BuildFromDefinition
|
7
|
+
if !String.method_defined?(:-@)
|
8
|
+
using GraphQL::StringDedupBackport
|
9
|
+
end
|
10
|
+
|
7
11
|
class << self
|
8
12
|
# @see {Schema.from_definition}
|
9
|
-
def from_definition(definition_string,
|
10
|
-
|
11
|
-
default_resolve ||= {}
|
12
|
-
Builder.build(document, default_resolve: default_resolve, relay: relay, using: using, interpreter: interpreter)
|
13
|
+
def from_definition(definition_string, parser: GraphQL.default_parser, **kwargs)
|
14
|
+
from_document(parser.parse(definition_string), **kwargs)
|
13
15
|
end
|
14
|
-
end
|
15
16
|
|
16
|
-
|
17
|
-
|
17
|
+
def from_definition_path(definition_path, parser: GraphQL.default_parser, **kwargs)
|
18
|
+
from_document(parser.parse_file(definition_path), **kwargs)
|
19
|
+
end
|
20
|
+
|
21
|
+
def from_document(document, default_resolve:, using: {}, relay: false, interpreter: true)
|
22
|
+
Builder.build(document, default_resolve: default_resolve || {}, relay: relay, using: using, interpreter: interpreter)
|
23
|
+
end
|
24
|
+
end
|
18
25
|
|
19
26
|
# @api private
|
20
27
|
module Builder
|
@@ -43,7 +50,7 @@ module GraphQL
|
|
43
50
|
when GraphQL::Language::Nodes::EnumTypeDefinition
|
44
51
|
types[definition.name] = build_enum_type(definition, type_resolver)
|
45
52
|
when GraphQL::Language::Nodes::ObjectTypeDefinition
|
46
|
-
types[definition.name] = build_object_type(definition, type_resolver
|
53
|
+
types[definition.name] = build_object_type(definition, type_resolver)
|
47
54
|
when GraphQL::Language::Nodes::InterfaceTypeDefinition
|
48
55
|
types[definition.name] = build_interface_type(definition, type_resolver)
|
49
56
|
when GraphQL::Language::Nodes::UnionTypeDefinition
|
@@ -111,11 +118,11 @@ module GraphQL
|
|
111
118
|
end
|
112
119
|
|
113
120
|
if default_resolve.respond_to?(:resolve_type)
|
114
|
-
|
115
|
-
|
121
|
+
def self.resolve_type(*args)
|
122
|
+
self.definition_default_resolve.resolve_type(*args)
|
116
123
|
end
|
117
124
|
else
|
118
|
-
|
125
|
+
def self.resolve_type(*args)
|
119
126
|
NullResolveType.call(*args)
|
120
127
|
end
|
121
128
|
end
|
@@ -141,6 +148,20 @@ module GraphQL
|
|
141
148
|
|
142
149
|
# Empty `orphan_types` -- this will make unreachable types ... unreachable.
|
143
150
|
own_orphan_types.clear
|
151
|
+
|
152
|
+
class << self
|
153
|
+
attr_accessor :definition_default_resolve
|
154
|
+
end
|
155
|
+
|
156
|
+
self.definition_default_resolve = default_resolve
|
157
|
+
|
158
|
+
def definition_default_resolve
|
159
|
+
self.class.definition_default_resolve
|
160
|
+
end
|
161
|
+
|
162
|
+
def self.inherited(child_class)
|
163
|
+
child_class.definition_default_resolve = self.definition_default_resolve
|
164
|
+
end
|
144
165
|
end
|
145
166
|
end
|
146
167
|
|
@@ -182,12 +203,12 @@ module GraphQL
|
|
182
203
|
ast_node(scalar_type_definition)
|
183
204
|
|
184
205
|
if default_resolve.respond_to?(:coerce_input)
|
185
|
-
|
186
|
-
|
206
|
+
def self.coerce_input(val, ctx)
|
207
|
+
ctx.schema.definition_default_resolve.coerce_input(self, val, ctx)
|
187
208
|
end
|
188
209
|
|
189
|
-
|
190
|
-
|
210
|
+
def self.coerce_result(val, ctx)
|
211
|
+
ctx.schema.definition_default_resolve.coerce_result(self, val, ctx)
|
191
212
|
end
|
192
213
|
end
|
193
214
|
end
|
@@ -202,13 +223,10 @@ module GraphQL
|
|
202
223
|
end
|
203
224
|
end
|
204
225
|
|
205
|
-
def build_object_type(object_type_definition, type_resolver
|
226
|
+
def build_object_type(object_type_definition, type_resolver)
|
206
227
|
builder = self
|
207
|
-
type_def = nil
|
208
|
-
typed_resolve_fn = ->(field, obj, args, ctx) { default_resolve.call(type_def, field, obj, args, ctx) }
|
209
228
|
|
210
229
|
Class.new(GraphQL::Schema::Object) do
|
211
|
-
type_def = self
|
212
230
|
graphql_name(object_type_definition.name)
|
213
231
|
description(object_type_definition.description)
|
214
232
|
ast_node(object_type_definition)
|
@@ -218,7 +236,7 @@ module GraphQL
|
|
218
236
|
implements(interface_defn)
|
219
237
|
end
|
220
238
|
|
221
|
-
builder.build_fields(self, object_type_definition.fields, type_resolver, default_resolve:
|
239
|
+
builder.build_fields(self, object_type_definition.fields, type_resolver, default_resolve: true)
|
222
240
|
end
|
223
241
|
end
|
224
242
|
|
@@ -247,13 +265,16 @@ module GraphQL
|
|
247
265
|
end
|
248
266
|
end
|
249
267
|
|
268
|
+
NO_DEFAULT_VALUE = {}.freeze
|
269
|
+
|
250
270
|
def build_arguments(type_class, arguments, type_resolver)
|
251
271
|
builder = self
|
252
272
|
|
253
273
|
arguments.each do |argument_defn|
|
254
|
-
default_value_kwargs =
|
255
|
-
|
256
|
-
|
274
|
+
default_value_kwargs = if !argument_defn.default_value.nil?
|
275
|
+
{ default_value: builder.build_default_value(argument_defn.default_value) }
|
276
|
+
else
|
277
|
+
NO_DEFAULT_VALUE
|
257
278
|
end
|
258
279
|
|
259
280
|
type_class.argument(
|
@@ -261,6 +282,7 @@ module GraphQL
|
|
261
282
|
type: type_resolver.call(argument_defn.type),
|
262
283
|
required: false,
|
263
284
|
description: argument_defn.description,
|
285
|
+
deprecation_reason: builder.build_deprecation_reason(argument_defn.directives),
|
264
286
|
ast_node: argument_defn,
|
265
287
|
camelize: false,
|
266
288
|
method_access: false,
|
@@ -295,10 +317,10 @@ module GraphQL
|
|
295
317
|
def build_fields(owner, field_definitions, type_resolver, default_resolve:)
|
296
318
|
builder = self
|
297
319
|
|
298
|
-
field_definitions.
|
320
|
+
field_definitions.each do |field_definition|
|
299
321
|
type_name = resolve_type_name(field_definition.type)
|
300
|
-
resolve_method_name = "resolve_field_#{field_definition.name}"
|
301
|
-
owner.field(
|
322
|
+
resolve_method_name = -"resolve_field_#{field_definition.name}"
|
323
|
+
schema_field_defn = owner.field(
|
302
324
|
field_definition.name,
|
303
325
|
description: field_definition.description,
|
304
326
|
type: type_resolver.call(field_definition.type),
|
@@ -310,16 +332,19 @@ module GraphQL
|
|
310
332
|
method_conflict_warning: false,
|
311
333
|
camelize: false,
|
312
334
|
resolver_method: resolve_method_name,
|
313
|
-
)
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
335
|
+
)
|
336
|
+
|
337
|
+
builder.build_arguments(schema_field_defn, field_definition.arguments, type_resolver)
|
338
|
+
|
339
|
+
# Don't do this for interfaces
|
340
|
+
if default_resolve
|
341
|
+
owner.class_eval <<-RUBY, __FILE__, __LINE__
|
342
|
+
# frozen_string_literal: true
|
343
|
+
def #{resolve_method_name}(**args)
|
344
|
+
field_instance = self.class.get_field("#{field_definition.name}")
|
345
|
+
context.schema.definition_default_resolve.call(self.class, field_instance, object, args, context)
|
321
346
|
end
|
322
|
-
|
347
|
+
RUBY
|
323
348
|
end
|
324
349
|
end
|
325
350
|
end
|