graphql 1.10.0.pre1 → 1.10.0.pre2
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.
- checksums.yaml +4 -4
- data/lib/generators/graphql/core.rb +1 -0
- data/lib/generators/graphql/install_generator.rb +1 -0
- data/lib/generators/graphql/mutation_generator.rb +1 -1
- data/lib/generators/graphql/templates/base_field.erb +0 -4
- data/lib/generators/graphql/templates/base_mutation.erb +8 -0
- data/lib/generators/graphql/templates/graphql_controller.erb +5 -0
- data/lib/generators/graphql/templates/mutation.erb +1 -1
- data/lib/generators/graphql/templates/schema.erb +1 -1
- data/lib/graphql.rb +4 -1
- data/lib/graphql/analysis/ast.rb +14 -13
- data/lib/graphql/analysis/ast/analyzer.rb +23 -4
- data/lib/graphql/analysis/ast/field_usage.rb +1 -1
- data/lib/graphql/analysis/ast/max_query_complexity.rb +3 -3
- data/lib/graphql/analysis/ast/max_query_depth.rb +7 -3
- data/lib/graphql/analysis/ast/query_complexity.rb +2 -2
- data/lib/graphql/analysis/ast/visitor.rb +3 -3
- data/lib/graphql/base_type.rb +1 -1
- data/lib/graphql/directive.rb +0 -1
- data/lib/graphql/directive/deprecated_directive.rb +1 -12
- data/lib/graphql/execution/errors.rb +4 -8
- data/lib/graphql/execution/interpreter.rb +5 -11
- data/lib/graphql/execution/interpreter/runtime.rb +56 -48
- data/lib/graphql/execution/lazy/lazy_method_map.rb +4 -0
- data/lib/graphql/execution/lookahead.rb +5 -5
- data/lib/graphql/execution/multiplex.rb +10 -0
- data/lib/graphql/function.rb +1 -1
- data/lib/graphql/input_object_type.rb +3 -2
- data/lib/graphql/interface_type.rb +1 -1
- data/lib/graphql/introspection/base_object.rb +2 -5
- data/lib/graphql/introspection/directive_type.rb +1 -1
- data/lib/graphql/introspection/entry_points.rb +6 -6
- data/lib/graphql/introspection/schema_type.rb +1 -6
- data/lib/graphql/introspection/type_type.rb +5 -5
- data/lib/graphql/language.rb +1 -1
- data/lib/graphql/language/block_string.rb +2 -2
- data/lib/graphql/language/definition_slice.rb +21 -10
- data/lib/graphql/language/document_from_schema_definition.rb +42 -42
- data/lib/graphql/language/lexer.rb +49 -48
- data/lib/graphql/language/lexer.rl +49 -48
- data/lib/graphql/language/nodes.rb +11 -8
- data/lib/graphql/language/parser.rb +4 -1
- data/lib/graphql/language/parser.y +4 -1
- data/lib/graphql/language/token.rb +1 -1
- data/lib/graphql/pagination/array_connection.rb +0 -1
- data/lib/graphql/pagination/connection.rb +31 -10
- data/lib/graphql/pagination/connections.rb +7 -2
- data/lib/graphql/pagination/relation_connection.rb +1 -7
- data/lib/graphql/query.rb +9 -4
- data/lib/graphql/query/arguments.rb +8 -1
- data/lib/graphql/query/literal_input.rb +2 -1
- data/lib/graphql/query/variables.rb +5 -1
- data/lib/graphql/relay/base_connection.rb +3 -3
- data/lib/graphql/relay/relation_connection.rb +9 -5
- data/lib/graphql/schema.rb +699 -153
- data/lib/graphql/schema/argument.rb +20 -4
- data/lib/graphql/schema/build_from_definition.rb +64 -31
- data/lib/graphql/schema/built_in_types.rb +5 -5
- data/lib/graphql/schema/directive.rb +16 -1
- data/lib/graphql/schema/directive/deprecated.rb +18 -0
- data/lib/graphql/schema/directive/feature.rb +1 -1
- data/lib/graphql/schema/enum.rb +39 -3
- data/lib/graphql/schema/field.rb +39 -9
- data/lib/graphql/schema/field/connection_extension.rb +4 -4
- data/lib/graphql/schema/find_inherited_value.rb +13 -0
- data/lib/graphql/schema/finder.rb +13 -11
- data/lib/graphql/schema/input_object.rb +109 -1
- data/lib/graphql/schema/interface.rb +8 -7
- data/lib/graphql/schema/introspection_system.rb +104 -36
- data/lib/graphql/schema/late_bound_type.rb +1 -0
- data/lib/graphql/schema/list.rb +26 -0
- data/lib/graphql/schema/loader.rb +10 -4
- data/lib/graphql/schema/member.rb +3 -0
- data/lib/graphql/schema/member/base_dsl_methods.rb +23 -13
- data/lib/graphql/schema/member/build_type.rb +1 -1
- data/lib/graphql/schema/member/has_arguments.rb +2 -2
- data/lib/graphql/schema/member/has_fields.rb +15 -6
- data/lib/graphql/schema/member/instrumentation.rb +6 -1
- data/lib/graphql/schema/member/type_system_helpers.rb +1 -1
- data/lib/graphql/schema/member/validates_input.rb +33 -0
- data/lib/graphql/schema/non_null.rb +25 -0
- data/lib/graphql/schema/object.rb +14 -1
- data/lib/graphql/schema/printer.rb +4 -3
- data/lib/graphql/schema/relay_classic_mutation.rb +5 -1
- data/lib/graphql/schema/resolver.rb +20 -2
- data/lib/graphql/schema/scalar.rb +18 -3
- data/lib/graphql/schema/subscription.rb +1 -1
- data/lib/graphql/schema/timeout_middleware.rb +3 -2
- data/lib/graphql/schema/traversal.rb +1 -1
- data/lib/graphql/schema/type_expression.rb +22 -24
- data/lib/graphql/schema/validation.rb +17 -1
- data/lib/graphql/schema/warden.rb +46 -17
- data/lib/graphql/schema/wrapper.rb +1 -1
- data/lib/graphql/static_validation/base_visitor.rb +10 -6
- data/lib/graphql/static_validation/definition_dependencies.rb +21 -12
- data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +4 -4
- data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +3 -3
- data/lib/graphql/static_validation/type_stack.rb +2 -2
- data/lib/graphql/static_validation/validator.rb +1 -1
- data/lib/graphql/subscriptions.rb +38 -13
- data/lib/graphql/subscriptions/event.rb +24 -7
- data/lib/graphql/subscriptions/instrumentation.rb +1 -1
- data/lib/graphql/subscriptions/subscription_root.rb +0 -1
- data/lib/graphql/tracing/active_support_notifications_tracing.rb +10 -10
- data/lib/graphql/tracing/platform_tracing.rb +1 -2
- data/lib/graphql/tracing/skylight_tracing.rb +1 -0
- data/lib/graphql/unresolved_type_error.rb +2 -2
- data/lib/graphql/upgrader/member.rb +1 -1
- data/lib/graphql/version.rb +1 -1
- metadata +5 -2
@@ -116,7 +116,9 @@ module GraphQL
|
|
116
116
|
elsif as_type.kind.input_object?
|
117
117
|
as_type.arguments.each do |_name, input_obj_arg|
|
118
118
|
input_obj_arg = input_obj_arg.type_class
|
119
|
-
|
119
|
+
# TODO: this skips input objects whose values were alread replaced with application objects.
|
120
|
+
# See: https://github.com/rmosolgo/graphql-ruby/issues/2633
|
121
|
+
if value.respond_to?(:key?) && value.key?(input_obj_arg.keyword) && !input_obj_arg.authorized?(obj, value[input_obj_arg.keyword], ctx)
|
120
122
|
return false
|
121
123
|
end
|
122
124
|
end
|
@@ -141,6 +143,8 @@ module GraphQL
|
|
141
143
|
argument
|
142
144
|
end
|
143
145
|
|
146
|
+
attr_writer :type
|
147
|
+
|
144
148
|
def type
|
145
149
|
@type ||= Member::BuildType.parse_type(@type_expr, null: @null)
|
146
150
|
rescue StandardError => err
|
@@ -150,13 +154,25 @@ module GraphQL
|
|
150
154
|
# Apply the {prepare} configuration to `value`, using methods from `obj`.
|
151
155
|
# Used by the runtime.
|
152
156
|
# @api private
|
153
|
-
def prepare_value(obj, value)
|
157
|
+
def prepare_value(obj, value, context: nil)
|
158
|
+
if value.is_a?(GraphQL::Schema::InputObject)
|
159
|
+
value = value.prepare
|
160
|
+
end
|
161
|
+
|
154
162
|
if @prepare.nil?
|
155
163
|
value
|
156
164
|
elsif @prepare.is_a?(String) || @prepare.is_a?(Symbol)
|
157
|
-
obj.
|
165
|
+
if obj.nil?
|
166
|
+
# The problem here is, we _used to_ prepare while building variables.
|
167
|
+
# But now we don't have the runtime object there.
|
168
|
+
#
|
169
|
+
# This will have to be called later, when the runtime object _is_ available.
|
170
|
+
value
|
171
|
+
else
|
172
|
+
obj.public_send(@prepare, value)
|
173
|
+
end
|
158
174
|
elsif @prepare.respond_to?(:call)
|
159
|
-
@prepare.call(value, obj.context)
|
175
|
+
@prepare.call(value, context || obj.context)
|
160
176
|
else
|
161
177
|
raise "Invalid prepare for #{@owner.name}.name: #{@prepare.inspect}"
|
162
178
|
end
|
@@ -5,9 +5,9 @@ module GraphQL
|
|
5
5
|
class Schema
|
6
6
|
module BuildFromDefinition
|
7
7
|
class << self
|
8
|
-
def from_definition(definition_string, default_resolve:, parser: DefaultParser)
|
8
|
+
def from_definition(definition_string, default_resolve:, using: {}, interpreter: true, parser: DefaultParser)
|
9
9
|
document = parser.parse(definition_string)
|
10
|
-
Builder.build(document, default_resolve: default_resolve)
|
10
|
+
Builder.build(document, default_resolve: default_resolve, using: using, interpreter: interpreter)
|
11
11
|
end
|
12
12
|
end
|
13
13
|
|
@@ -29,34 +29,39 @@ module GraphQL
|
|
29
29
|
module Builder
|
30
30
|
extend self
|
31
31
|
|
32
|
-
def build(document, default_resolve: DefaultResolve)
|
32
|
+
def build(document, default_resolve: DefaultResolve, using: {}, interpreter: true)
|
33
33
|
raise InvalidDocumentError.new('Must provide a document ast.') if !document || !document.is_a?(GraphQL::Language::Nodes::Document)
|
34
34
|
|
35
35
|
if default_resolve.is_a?(Hash)
|
36
36
|
default_resolve = ResolveMap.new(default_resolve)
|
37
37
|
end
|
38
38
|
|
39
|
-
|
39
|
+
schema_defns = document.definitions.select { |d| d.is_a?(GraphQL::Language::Nodes::SchemaDefinition) }
|
40
|
+
if schema_defns.size > 1
|
41
|
+
raise InvalidDocumentError.new('Must provide only one schema definition.')
|
42
|
+
end
|
43
|
+
schema_definition = schema_defns.first
|
40
44
|
types = {}
|
41
45
|
types.merge!(GraphQL::Schema::BUILT_IN_TYPES)
|
42
46
|
directives = {}
|
43
|
-
type_resolver = ->(type) {
|
47
|
+
type_resolver = ->(type) { resolve_type(types, type) }
|
44
48
|
|
45
49
|
document.definitions.each do |definition|
|
46
50
|
case definition
|
47
51
|
when GraphQL::Language::Nodes::SchemaDefinition
|
48
|
-
|
49
|
-
schema_definition = definition
|
52
|
+
nil # already handled
|
50
53
|
when GraphQL::Language::Nodes::EnumTypeDefinition
|
51
|
-
types[definition.name] = build_enum_type(definition, type_resolver)
|
54
|
+
types[definition.name] = build_enum_type(definition, type_resolver)
|
52
55
|
when GraphQL::Language::Nodes::ObjectTypeDefinition
|
53
|
-
|
56
|
+
is_subscription_root = (definition.name == "Subscription" && (schema_definition.nil? || schema_definition.subscription.nil?)) || (schema_definition && (definition.name == schema_definition.subscription))
|
57
|
+
should_extend_subscription_root = is_subscription_root && interpreter
|
58
|
+
types[definition.name] = build_object_type(definition, type_resolver, default_resolve: default_resolve, extend_subscription_root: should_extend_subscription_root)
|
54
59
|
when GraphQL::Language::Nodes::InterfaceTypeDefinition
|
55
|
-
types[definition.name] = build_interface_type(definition, type_resolver)
|
60
|
+
types[definition.name] = build_interface_type(definition, type_resolver)
|
56
61
|
when GraphQL::Language::Nodes::UnionTypeDefinition
|
57
|
-
types[definition.name] = build_union_type(definition, type_resolver)
|
62
|
+
types[definition.name] = build_union_type(definition, type_resolver)
|
58
63
|
when GraphQL::Language::Nodes::ScalarTypeDefinition
|
59
|
-
types[definition.name] = build_scalar_type(definition, type_resolver, default_resolve: default_resolve)
|
64
|
+
types[definition.name] = build_scalar_type(definition, type_resolver, default_resolve: default_resolve)
|
60
65
|
when GraphQL::Language::Nodes::InputObjectTypeDefinition
|
61
66
|
types[definition.name] = build_input_object_type(definition, type_resolver)
|
62
67
|
when GraphQL::Language::Nodes::DirectiveDefinition
|
@@ -90,10 +95,18 @@ module GraphQL
|
|
90
95
|
raise InvalidDocumentError.new('Must provide schema definition with query type or a type named Query.') unless query_root_type
|
91
96
|
|
92
97
|
Class.new(GraphQL::Schema) do
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
98
|
+
begin
|
99
|
+
# Add these first so that there's some chance of resolving late-bound types
|
100
|
+
orphan_types types.values
|
101
|
+
query query_root_type
|
102
|
+
mutation mutation_root_type
|
103
|
+
subscription subscription_root_type
|
104
|
+
rescue Schema::UnresolvedLateBoundTypeError => err
|
105
|
+
type_name = err.type.name
|
106
|
+
err_backtrace = err.backtrace
|
107
|
+
raise InvalidDocumentError, "Type \"#{type_name}\" not found in document.", err_backtrace
|
108
|
+
end
|
109
|
+
|
97
110
|
if default_resolve.respond_to?(:resolve_type)
|
98
111
|
define_singleton_method(:resolve_type) do |*args|
|
99
112
|
default_resolve.resolve_type(*args)
|
@@ -110,13 +123,19 @@ module GraphQL
|
|
110
123
|
ast_node(schema_definition)
|
111
124
|
end
|
112
125
|
|
113
|
-
|
114
|
-
|
126
|
+
if interpreter
|
127
|
+
use GraphQL::Execution::Interpreter
|
128
|
+
use GraphQL::Analysis::AST
|
129
|
+
end
|
130
|
+
|
131
|
+
using.each do |plugin, options|
|
132
|
+
use(plugin, options)
|
133
|
+
end
|
115
134
|
end
|
116
135
|
end
|
117
136
|
|
118
137
|
NullResolveType = ->(type, obj, ctx) {
|
119
|
-
raise(
|
138
|
+
raise(GraphQL::RequiredImplementationMissingError, "Generated Schema cannot use Interface or Union types for execution. Implement resolve_type on your resolver.")
|
120
139
|
}
|
121
140
|
|
122
141
|
def build_enum_type(enum_type_definition, type_resolver)
|
@@ -141,7 +160,7 @@ module GraphQL
|
|
141
160
|
return unless deprecated_directive
|
142
161
|
|
143
162
|
reason = deprecated_directive.arguments.find{ |a| a.name == 'reason' }
|
144
|
-
return GraphQL::Directive::DEFAULT_DEPRECATION_REASON unless reason
|
163
|
+
return GraphQL::Schema::Directive::DEFAULT_DEPRECATION_REASON unless reason
|
145
164
|
|
146
165
|
reason.value
|
147
166
|
end
|
@@ -173,15 +192,19 @@ module GraphQL
|
|
173
192
|
end
|
174
193
|
end
|
175
194
|
|
176
|
-
def build_object_type(object_type_definition, type_resolver, default_resolve:)
|
195
|
+
def build_object_type(object_type_definition, type_resolver, default_resolve:, extend_subscription_root:)
|
177
196
|
builder = self
|
178
197
|
type_def = nil
|
179
|
-
typed_resolve_fn = ->(field, obj, args, ctx) { default_resolve.call(type_def
|
198
|
+
typed_resolve_fn = ->(field, obj, args, ctx) { default_resolve.call(type_def, field, obj, args, ctx) }
|
180
199
|
Class.new(GraphQL::Schema::Object) do
|
181
200
|
type_def = self
|
182
201
|
graphql_name(object_type_definition.name)
|
183
202
|
description(object_type_definition.description)
|
184
203
|
ast_node(object_type_definition)
|
204
|
+
if extend_subscription_root
|
205
|
+
# This has to come before `field ...` configurations since it modifies them
|
206
|
+
extend Subscriptions::SubscriptionRoot
|
207
|
+
end
|
185
208
|
|
186
209
|
object_type_definition.interfaces.each do |interface_name|
|
187
210
|
interface_defn = type_resolver.call(interface_name)
|
@@ -268,32 +291,42 @@ module GraphQL
|
|
268
291
|
field_definitions.map do |field_definition|
|
269
292
|
type_name = resolve_type_name(field_definition.type)
|
270
293
|
|
271
|
-
|
294
|
+
owner.field(
|
272
295
|
field_definition.name,
|
273
296
|
description: field_definition.description,
|
274
297
|
type: type_resolver.call(field_definition.type),
|
275
298
|
null: true,
|
276
299
|
connection: type_name.end_with?("Connection"),
|
277
|
-
resolve: ->(obj, args, ctx) { default_resolve.call(field.graphql_definition, obj, args, ctx) },
|
278
300
|
deprecation_reason: build_deprecation_reason(field_definition.directives),
|
279
301
|
ast_node: field_definition,
|
280
302
|
method_conflict_warning: false,
|
281
303
|
camelize: false,
|
282
304
|
) do
|
283
305
|
builder.build_arguments(self, field_definition.arguments, type_resolver)
|
306
|
+
|
307
|
+
# Don't do this for interfaces
|
308
|
+
if default_resolve
|
309
|
+
# TODO fragile hack. formalize this API?
|
310
|
+
define_singleton_method :resolve_field_method do |obj, args, ctx|
|
311
|
+
default_resolve.call(self, obj.object, args, ctx)
|
312
|
+
end
|
313
|
+
end
|
284
314
|
end
|
285
315
|
end
|
286
316
|
end
|
287
317
|
|
288
318
|
def resolve_type(types, ast_node)
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
319
|
+
case ast_node
|
320
|
+
when GraphQL::Language::Nodes::TypeName
|
321
|
+
type_name = ast_node.name
|
322
|
+
types[type_name] ||= GraphQL::Schema::LateBoundType.new(type_name)
|
323
|
+
when GraphQL::Language::Nodes::NonNullType
|
324
|
+
resolve_type(types, ast_node.of_type).to_non_null_type
|
325
|
+
when GraphQL::Language::Nodes::ListType
|
326
|
+
resolve_type(types, ast_node.of_type).to_list_type
|
327
|
+
else
|
328
|
+
raise "Unexpected ast_node: #{ast_node.inspect}"
|
295
329
|
end
|
296
|
-
type
|
297
330
|
end
|
298
331
|
|
299
332
|
def resolve_type_name(type)
|
@@ -2,11 +2,11 @@
|
|
2
2
|
module GraphQL
|
3
3
|
class Schema
|
4
4
|
BUILT_IN_TYPES = {
|
5
|
-
"Int" =>
|
6
|
-
"String" =>
|
7
|
-
"Float" =>
|
8
|
-
"Boolean" =>
|
9
|
-
"ID" =>
|
5
|
+
"Int" => GraphQL::Types::Int,
|
6
|
+
"String" => GraphQL::Types::String,
|
7
|
+
"Float" => GraphQL::Types::Float,
|
8
|
+
"Boolean" => GraphQL::Types::Boolean,
|
9
|
+
"ID" => GraphQL::Types::ID,
|
10
10
|
}
|
11
11
|
end
|
12
12
|
end
|
@@ -27,7 +27,7 @@ module GraphQL
|
|
27
27
|
elsif @default_directive.nil?
|
28
28
|
@default_directive = (superclass.respond_to?(:default_directive) ? superclass.default_directive : false)
|
29
29
|
else
|
30
|
-
|
30
|
+
!!@default_directive
|
31
31
|
end
|
32
32
|
end
|
33
33
|
|
@@ -47,6 +47,9 @@ module GraphQL
|
|
47
47
|
arg_graphql = arg_defn.to_graphql
|
48
48
|
defn.arguments[arg_graphql.name] = arg_graphql
|
49
49
|
end
|
50
|
+
# Make a reference to a classic-style Arguments class
|
51
|
+
defn.arguments_class = GraphQL::Query::Arguments.construct_arguments_class(defn)
|
52
|
+
|
50
53
|
defn
|
51
54
|
end
|
52
55
|
|
@@ -59,6 +62,18 @@ module GraphQL
|
|
59
62
|
def resolve(object, arguments, context)
|
60
63
|
yield
|
61
64
|
end
|
65
|
+
|
66
|
+
def on_field?
|
67
|
+
locations.include?(FIELD)
|
68
|
+
end
|
69
|
+
|
70
|
+
def on_fragment?
|
71
|
+
locations.include?(FRAGMENT_SPREAD) && locations.include?(INLINE_FRAGMENT)
|
72
|
+
end
|
73
|
+
|
74
|
+
def on_operation?
|
75
|
+
locations.include?(QUERY) && locations.include?(MUTATION) && locations.include?(SUBSCRIPTION)
|
76
|
+
end
|
62
77
|
end
|
63
78
|
|
64
79
|
LOCATIONS = [
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module GraphQL
|
3
|
+
class Schema
|
4
|
+
class Directive < GraphQL::Schema::Member
|
5
|
+
class Deprecated < GraphQL::Schema::Directive
|
6
|
+
description "Marks an element of a GraphQL schema as no longer supported."
|
7
|
+
locations(GraphQL::Schema::Directive::FIELD_DEFINITION, GraphQL::Schema::Directive::ENUM_VALUE)
|
8
|
+
|
9
|
+
reason_description = "Explains why this element was deprecated, usually also including a "\
|
10
|
+
"suggestion for how to access supported similar data. Formatted "\
|
11
|
+
"in [Markdown](https://daringfireball.net/projects/markdown/)."
|
12
|
+
|
13
|
+
argument :reason, String, reason_description, default_value: Directive::DEFAULT_DEPRECATION_REASON, required: false
|
14
|
+
default_directive true
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -58,7 +58,7 @@ module GraphQL
|
|
58
58
|
# @param context [GraphQL::Query::Context]
|
59
59
|
# @return [Boolean] If truthy, execution will continue
|
60
60
|
def self.enabled?(flag_name, object, context)
|
61
|
-
raise
|
61
|
+
raise GraphQL::RequiredImplementationMissingError, "Implement `.enabled?(flag_name, object, context)` to return true or false for the feature flag (#{flag_name.inspect})"
|
62
62
|
end
|
63
63
|
end
|
64
64
|
end
|
data/lib/graphql/schema/enum.rb
CHANGED
@@ -21,11 +21,9 @@ module GraphQL
|
|
21
21
|
class Schema
|
22
22
|
class Enum < GraphQL::Schema::Member
|
23
23
|
extend GraphQL::Schema::Member::AcceptsDefinition
|
24
|
+
extend GraphQL::Schema::Member::ValidatesInput
|
24
25
|
|
25
26
|
class << self
|
26
|
-
extend Forwardable
|
27
|
-
def_delegators :graphql_definition, :coerce_isolated_input, :coerce_isolated_result, :coerce_input, :coerce_result
|
28
|
-
|
29
27
|
# Define a value for this enum
|
30
28
|
# @param graphql_name [String, Symbol] the GraphQL value for this, usually `SCREAMING_CASE`
|
31
29
|
# @param description [String], the GraphQL description for this value, present in documentation
|
@@ -73,6 +71,44 @@ module GraphQL
|
|
73
71
|
GraphQL::TypeKinds::ENUM
|
74
72
|
end
|
75
73
|
|
74
|
+
def validate_non_null_input(value_name, ctx)
|
75
|
+
result = GraphQL::Query::InputValidationResult.new
|
76
|
+
|
77
|
+
allowed_values = ctx.warden.enum_values(self)
|
78
|
+
matching_value = allowed_values.find { |v| v.graphql_name == value_name }
|
79
|
+
|
80
|
+
if matching_value.nil?
|
81
|
+
result.add_problem("Expected #{GraphQL::Language.serialize(value_name)} to be one of: #{allowed_values.map(&:graphql_name).join(', ')}")
|
82
|
+
end
|
83
|
+
|
84
|
+
result
|
85
|
+
end
|
86
|
+
|
87
|
+
def coerce_result(value, ctx)
|
88
|
+
warden = ctx.warden
|
89
|
+
all_values = warden ? warden.enum_values(self) : values.each_value
|
90
|
+
enum_value = all_values.find { |val| val.value == value }
|
91
|
+
if enum_value
|
92
|
+
enum_value.graphql_name
|
93
|
+
else
|
94
|
+
raise(GraphQL::EnumType::UnresolvedValueError, "Can't resolve enum #{graphql_name} for #{value.inspect}")
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def coerce_input(value_name, ctx)
|
99
|
+
all_values = ctx.warden ? ctx.warden.enum_values(self) : values.each_value
|
100
|
+
|
101
|
+
if v = all_values.find { |val| val.graphql_name == value_name }
|
102
|
+
v.value
|
103
|
+
elsif v = all_values.find { |val| val.value == value_name }
|
104
|
+
# this is for matching default values, which are "inputs", but they're
|
105
|
+
# the Ruby value, not the GraphQL string.
|
106
|
+
v.value
|
107
|
+
else
|
108
|
+
nil
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
76
112
|
private
|
77
113
|
|
78
114
|
def own_values
|
data/lib/graphql/schema/field.rb
CHANGED
@@ -15,6 +15,7 @@ module GraphQL
|
|
15
15
|
include GraphQL::Schema::Member::HasArguments
|
16
16
|
include GraphQL::Schema::Member::HasAstNode
|
17
17
|
include GraphQL::Schema::Member::HasPath
|
18
|
+
extend GraphQL::Schema::FindInheritedValue
|
18
19
|
|
19
20
|
# @return [String] the GraphQL name for this field, camelized unless `camelize: false` is provided
|
20
21
|
attr_reader :name
|
@@ -35,7 +36,7 @@ module GraphQL
|
|
35
36
|
attr_reader :resolver_method
|
36
37
|
|
37
38
|
# @return [Class] The type that this field belongs to
|
38
|
-
|
39
|
+
attr_accessor :owner
|
39
40
|
|
40
41
|
# @return [Symbol] the original name of the field, passed in by the user
|
41
42
|
attr_reader :original_name
|
@@ -51,7 +52,7 @@ module GraphQL
|
|
51
52
|
attr_reader :trace
|
52
53
|
|
53
54
|
# @return [String, nil]
|
54
|
-
|
55
|
+
attr_accessor :subscription_scope
|
55
56
|
|
56
57
|
# Create a field instance from a list of arguments, keyword arguments, and a block.
|
57
58
|
#
|
@@ -136,6 +137,25 @@ module GraphQL
|
|
136
137
|
end
|
137
138
|
end
|
138
139
|
|
140
|
+
# This extension is applied to fields when {#connection?} is true.
|
141
|
+
#
|
142
|
+
# You can override it in your base field definition.
|
143
|
+
# @return [Class] A {FieldExtension} subclass for implementing pagination behavior.
|
144
|
+
# @example Configuring a custom extension
|
145
|
+
# class Types::BaseField < GraphQL::Schema::Field
|
146
|
+
# connection_extension(MyCustomExtension)
|
147
|
+
# end
|
148
|
+
def self.connection_extension(new_extension_class = nil)
|
149
|
+
if new_extension_class
|
150
|
+
@connection_extension = new_extension_class
|
151
|
+
else
|
152
|
+
@connection_extension ||= find_inherited_value(:connection_extension, ConnectionExtension)
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
# @return Boolean
|
157
|
+
attr_reader :relay_node_field
|
158
|
+
|
139
159
|
# @return [Boolean] Should we warn if this field's name conflicts with a built-in method?
|
140
160
|
def method_conflict_warning?
|
141
161
|
@method_conflict_warning
|
@@ -256,7 +276,7 @@ module GraphQL
|
|
256
276
|
# The problem with putting this after the definition_block
|
257
277
|
# is that it would override arguments
|
258
278
|
if connection?
|
259
|
-
self.extension(
|
279
|
+
self.extension(self.class.connection_extension)
|
260
280
|
end
|
261
281
|
|
262
282
|
if definition_block
|
@@ -340,7 +360,7 @@ module GraphQL
|
|
340
360
|
end
|
341
361
|
end
|
342
362
|
|
343
|
-
def complexity(new_complexity)
|
363
|
+
def complexity(new_complexity = nil)
|
344
364
|
case new_complexity
|
345
365
|
when Proc
|
346
366
|
if new_complexity.parameters.size != 3
|
@@ -353,6 +373,8 @@ module GraphQL
|
|
353
373
|
end
|
354
374
|
when Numeric
|
355
375
|
@complexity = new_complexity
|
376
|
+
when nil
|
377
|
+
@complexity
|
356
378
|
else
|
357
379
|
raise("Invalid complexity: #{new_complexity.inspect} on #{@name}")
|
358
380
|
end
|
@@ -427,12 +449,20 @@ module GraphQL
|
|
427
449
|
|
428
450
|
# Ok, `self` isn't a class, but this is for consistency with the classes
|
429
451
|
field_defn.metadata[:type_class] = self
|
430
|
-
|
452
|
+
field_defn.arguments_class = GraphQL::Query::Arguments.construct_arguments_class(field_defn)
|
431
453
|
field_defn
|
432
454
|
end
|
433
455
|
|
456
|
+
attr_writer :type
|
457
|
+
|
434
458
|
def type
|
435
|
-
@type ||=
|
459
|
+
@type ||= if @function
|
460
|
+
Member::BuildType.parse_type(@function.type, null: false)
|
461
|
+
elsif @field
|
462
|
+
Member::BuildType.parse_type(@field.type, null: false)
|
463
|
+
else
|
464
|
+
Member::BuildType.parse_type(@return_type_expr, null: @return_type_null)
|
465
|
+
end
|
436
466
|
rescue GraphQL::Schema::InvalidDocumentError => err
|
437
467
|
# Let this propagate up
|
438
468
|
raise err
|
@@ -523,7 +553,7 @@ module GraphQL
|
|
523
553
|
else
|
524
554
|
extended_obj
|
525
555
|
end
|
526
|
-
@resolver_class.new(object: resolver_obj, context: ctx)
|
556
|
+
@resolver_class.new(object: resolver_obj, context: ctx, field: self)
|
527
557
|
else
|
528
558
|
extended_obj
|
529
559
|
end
|
@@ -597,7 +627,7 @@ module GraphQL
|
|
597
627
|
elsif ctx.respond_to?(extra_name)
|
598
628
|
ctx.public_send(extra_name)
|
599
629
|
else
|
600
|
-
raise
|
630
|
+
raise GraphQL::RequiredImplementationMissingError, "Unknown field extra for #{self.path}: #{extra_name.inspect}"
|
601
631
|
end
|
602
632
|
end
|
603
633
|
|
@@ -640,7 +670,7 @@ module GraphQL
|
|
640
670
|
if extended_obj.is_a?(GraphQL::Schema::Object)
|
641
671
|
extended_obj = extended_obj.object
|
642
672
|
end
|
643
|
-
extended_obj = @resolver_class.new(object: extended_obj, context: query_ctx)
|
673
|
+
extended_obj = @resolver_class.new(object: extended_obj, context: query_ctx, field: self)
|
644
674
|
end
|
645
675
|
|
646
676
|
if extended_obj.respond_to?(@resolver_method)
|