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
data/lib/graphql/schema/list.rb
CHANGED
@@ -6,6 +6,8 @@ module GraphQL
|
|
6
6
|
# Wraps a {Schema::Member} as a list type.
|
7
7
|
# @see {Schema::Member::TypeSystemHelpers#to_list_type}
|
8
8
|
class List < GraphQL::Schema::Wrapper
|
9
|
+
include Schema::Member::ValidatesInput
|
10
|
+
|
9
11
|
def to_graphql
|
10
12
|
@of_type.graphql_definition.to_list_type
|
11
13
|
end
|
@@ -23,6 +25,30 @@ module GraphQL
|
|
23
25
|
def to_type_signature
|
24
26
|
"[#{@of_type.to_type_signature}]"
|
25
27
|
end
|
28
|
+
|
29
|
+
# This is for introspection, where it's expected the name will be `null`
|
30
|
+
def graphql_name
|
31
|
+
nil
|
32
|
+
end
|
33
|
+
|
34
|
+
def coerce_result(value, ctx)
|
35
|
+
value.map { |i| i.nil? ? nil : of_type.coerce_result(i, ctx) }
|
36
|
+
end
|
37
|
+
|
38
|
+
def coerce_input(value, ctx)
|
39
|
+
Array(value).map { |item| item.nil? ? item : of_type.coerce_input(item, ctx) }
|
40
|
+
end
|
41
|
+
|
42
|
+
def validate_non_null_input(value, ctx)
|
43
|
+
result = GraphQL::Query::InputValidationResult.new
|
44
|
+
Array(value).each_with_index do |item, index|
|
45
|
+
item_result = of_type.validate_input(item, ctx)
|
46
|
+
if !item_result.valid?
|
47
|
+
result.merge_result!(index, item_result)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
result
|
51
|
+
end
|
26
52
|
end
|
27
53
|
end
|
28
54
|
end
|
@@ -34,7 +34,7 @@ module GraphQL
|
|
34
34
|
end
|
35
35
|
|
36
36
|
NullResolveType = ->(type, obj, ctx) {
|
37
|
-
raise(
|
37
|
+
raise(GraphQL::RequiredImplementationMissingError, "This schema was loaded from string, so it can't resolve types for objects")
|
38
38
|
}
|
39
39
|
|
40
40
|
NullScalarCoerce = ->(val, _ctx) { val }
|
@@ -45,13 +45,19 @@ module GraphQL
|
|
45
45
|
def resolve_type(types, type)
|
46
46
|
case kind = type.fetch("kind")
|
47
47
|
when "ENUM", "INTERFACE", "INPUT_OBJECT", "OBJECT", "SCALAR", "UNION"
|
48
|
-
|
48
|
+
type_name = type.fetch("name")
|
49
|
+
type = types[type_name] || Schema::BUILT_IN_TYPES[type_name]
|
50
|
+
if type.nil?
|
51
|
+
raise "Type not found: #{type_name.inspect} among #{types.keys.sort}"
|
52
|
+
else
|
53
|
+
type.graphql_definition
|
54
|
+
end
|
49
55
|
when "LIST"
|
50
56
|
ListType.new(of_type: resolve_type(types, type.fetch("ofType")))
|
51
57
|
when "NON_NULL"
|
52
58
|
NonNullType.new(of_type: resolve_type(types, type.fetch("ofType")))
|
53
59
|
else
|
54
|
-
fail
|
60
|
+
fail GraphQL::RequiredImplementationMissingError, "#{kind} not implemented"
|
55
61
|
end
|
56
62
|
end
|
57
63
|
|
@@ -171,7 +177,7 @@ module GraphQL
|
|
171
177
|
}
|
172
178
|
)
|
173
179
|
else
|
174
|
-
fail
|
180
|
+
fail GraphQL::RequiredImplementationMissingError, "#{type["kind"]} not implemented"
|
175
181
|
end
|
176
182
|
end
|
177
183
|
end
|
@@ -8,6 +8,7 @@ require 'graphql/schema/member/has_path'
|
|
8
8
|
require 'graphql/schema/member/relay_shortcuts'
|
9
9
|
require 'graphql/schema/member/scoped'
|
10
10
|
require 'graphql/schema/member/type_system_helpers'
|
11
|
+
require 'graphql/schema/member/validates_input'
|
11
12
|
require "graphql/relay/type_extensions"
|
12
13
|
|
13
14
|
module GraphQL
|
@@ -21,6 +22,8 @@ module GraphQL
|
|
21
22
|
extend CachedGraphQLDefinition
|
22
23
|
extend GraphQL::Relay::TypeExtensions
|
23
24
|
extend BaseDSLMethods
|
25
|
+
extend BaseDSLMethods::ConfigurationExtension
|
26
|
+
introspection(false)
|
24
27
|
extend TypeSystemHelpers
|
25
28
|
extend Scoped
|
26
29
|
extend RelayShortcuts
|
@@ -18,16 +18,17 @@ module GraphQL
|
|
18
18
|
# @param new_name [String]
|
19
19
|
# @return [String]
|
20
20
|
def graphql_name(new_name = nil)
|
21
|
-
|
22
|
-
when new_name
|
21
|
+
if new_name
|
23
22
|
@graphql_name = new_name
|
24
|
-
when overridden = overridden_graphql_name
|
25
|
-
overridden
|
26
23
|
else
|
27
|
-
default_graphql_name
|
24
|
+
overridden_graphql_name || default_graphql_name
|
28
25
|
end
|
29
26
|
end
|
30
27
|
|
28
|
+
def overridden_graphql_name
|
29
|
+
@graphql_name
|
30
|
+
end
|
31
|
+
|
31
32
|
# Just a convenience method to point out that people should use graphql_name instead
|
32
33
|
def name(new_name = nil)
|
33
34
|
return super() if new_name.nil?
|
@@ -46,7 +47,20 @@ module GraphQL
|
|
46
47
|
if new_description
|
47
48
|
@description = new_description
|
48
49
|
else
|
49
|
-
@description
|
50
|
+
@description
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# This pushes some configurations _down_ the inheritance tree,
|
55
|
+
# in order to prevent repetitive lookups at runtime.
|
56
|
+
module ConfigurationExtension
|
57
|
+
def inherited(child_class)
|
58
|
+
child_class.introspection(introspection)
|
59
|
+
child_class.description(description)
|
60
|
+
if overridden_graphql_name
|
61
|
+
child_class.graphql_name(overridden_graphql_name)
|
62
|
+
end
|
63
|
+
super
|
50
64
|
end
|
51
65
|
end
|
52
66
|
|
@@ -55,7 +69,7 @@ module GraphQL
|
|
55
69
|
if !new_introspection.nil?
|
56
70
|
@introspection = new_introspection
|
57
71
|
else
|
58
|
-
@introspection
|
72
|
+
@introspection
|
59
73
|
end
|
60
74
|
end
|
61
75
|
|
@@ -74,21 +88,17 @@ module GraphQL
|
|
74
88
|
|
75
89
|
# @return [GraphQL::BaseType] Convert this type to a legacy-style object.
|
76
90
|
def to_graphql
|
77
|
-
raise
|
91
|
+
raise GraphQL::RequiredImplementationMissingError
|
78
92
|
end
|
79
93
|
|
80
94
|
alias :unwrap :itself
|
81
95
|
|
82
|
-
def overridden_graphql_name
|
83
|
-
@graphql_name || find_inherited_value(:overridden_graphql_name)
|
84
|
-
end
|
85
|
-
|
86
96
|
# Creates the default name for a schema member.
|
87
97
|
# The default name is the Ruby constant name,
|
88
98
|
# without any namespaces and with any `-Type` suffix removed
|
89
99
|
def default_graphql_name
|
90
100
|
@default_graphql_name ||= begin
|
91
|
-
raise
|
101
|
+
raise GraphQL::RequiredImplementationMissingError, 'Anonymous class should declare a `graphql_name`' if name.nil?
|
92
102
|
|
93
103
|
name.split("::").last.sub(/Type\Z/, "")
|
94
104
|
end
|
@@ -97,7 +97,7 @@ module GraphQL
|
|
97
97
|
# (Don't want to allow arbitrary access to objects this way)
|
98
98
|
resolved_application_object_type = context.schema.resolve_type(lookup_as_type, application_object, context)
|
99
99
|
context.schema.after_lazy(resolved_application_object_type) do |application_object_type|
|
100
|
-
possible_object_types = context.
|
100
|
+
possible_object_types = context.warden.possible_types(lookup_as_type)
|
101
101
|
if !possible_object_types.include?(application_object_type)
|
102
102
|
err = GraphQL::LoadApplicationObjectFailedError.new(argument: argument, id: id, object: application_object)
|
103
103
|
load_application_object_failed(err)
|
@@ -105,7 +105,7 @@ module GraphQL
|
|
105
105
|
# This object was loaded successfully
|
106
106
|
# and resolved to the right type,
|
107
107
|
# now apply the `.authorized?` class method if there is one
|
108
|
-
if (class_based_type = application_object_type.
|
108
|
+
if (class_based_type = application_object_type.type_class)
|
109
109
|
context.schema.after_lazy(class_based_type.authorized?(application_object, context)) do |authed|
|
110
110
|
if authed
|
111
111
|
application_object
|
@@ -1,4 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
require 'irb/ruby-token'
|
3
|
+
|
2
4
|
module GraphQL
|
3
5
|
class Schema
|
4
6
|
class Member
|
@@ -38,16 +40,23 @@ module GraphQL
|
|
38
40
|
end
|
39
41
|
end
|
40
42
|
|
43
|
+
# A list of Ruby keywords.
|
44
|
+
#
|
45
|
+
# @api private
|
46
|
+
RUBY_KEYWORDS = RubyToken::TokenDefinitions.select { |definition| definition[1] == RubyToken::TkId }
|
47
|
+
.map { |definition| definition[2] }
|
48
|
+
.compact
|
49
|
+
|
50
|
+
# A list of GraphQL-Ruby keywords.
|
51
|
+
#
|
52
|
+
# @api private
|
53
|
+
GRAPHQL_RUBY_KEYWORDS = [:context, :object, :method]
|
54
|
+
|
41
55
|
# A list of field names that we should advise users to pick a different
|
42
56
|
# resolve method name.
|
43
57
|
#
|
44
58
|
# @api private
|
45
|
-
CONFLICT_FIELD_NAMES = Set.new(
|
46
|
-
# GraphQL-Ruby conflicts
|
47
|
-
:context, :object,
|
48
|
-
# Ruby built-ins conflicts
|
49
|
-
:method, :class
|
50
|
-
])
|
59
|
+
CONFLICT_FIELD_NAMES = Set.new(GRAPHQL_RUBY_KEYWORDS + RUBY_KEYWORDS)
|
51
60
|
|
52
61
|
# Register this field with the class, overriding a previous one if needed.
|
53
62
|
# @param field_defn [GraphQL::Schema::Field]
|
@@ -78,7 +78,7 @@ module GraphQL
|
|
78
78
|
|
79
79
|
def call(obj, args, ctx)
|
80
80
|
result = @inner_resolve.call(obj, args, ctx)
|
81
|
-
if ctx.skip == result || ctx.schema.lazy?(result) || result.nil? ||
|
81
|
+
if ctx.skip == result || ctx.schema.lazy?(result) || result.nil? || execution_errors?(result) || ctx.wrapped_object
|
82
82
|
result
|
83
83
|
else
|
84
84
|
ctx.wrapped_object = true
|
@@ -88,6 +88,11 @@ module GraphQL
|
|
88
88
|
|
89
89
|
private
|
90
90
|
|
91
|
+
def execution_errors?(result)
|
92
|
+
result.is_a?(GraphQL::ExecutionError) ||
|
93
|
+
(result.is_a?(Array) && result.any? && result.all? { |v| v.is_a?(GraphQL::ExecutionError) })
|
94
|
+
end
|
95
|
+
|
91
96
|
def proxy_to_depth(inner_obj, depth, ctx)
|
92
97
|
if depth > 0
|
93
98
|
inner_obj.map { |i| proxy_to_depth(i, depth - 1, ctx) }
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module GraphQL
|
4
|
+
class Schema
|
5
|
+
class Member
|
6
|
+
module ValidatesInput
|
7
|
+
def valid_input?(val, ctx)
|
8
|
+
validate_input(val, ctx).valid?
|
9
|
+
end
|
10
|
+
|
11
|
+
def validate_input(val, ctx)
|
12
|
+
if val.nil?
|
13
|
+
GraphQL::Query::InputValidationResult.new
|
14
|
+
else
|
15
|
+
validate_non_null_input(val, ctx)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def valid_isolated_input?(v)
|
20
|
+
valid_input?(v, GraphQL::Query::NullContext)
|
21
|
+
end
|
22
|
+
|
23
|
+
def coerce_isolated_input(v)
|
24
|
+
coerce_input(v, GraphQL::Query::NullContext)
|
25
|
+
end
|
26
|
+
|
27
|
+
def coerce_isolated_result(v)
|
28
|
+
coerce_result(v, GraphQL::Query::NullContext)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -6,6 +6,8 @@ module GraphQL
|
|
6
6
|
# Wraps a {Schema::Member} when it is required.
|
7
7
|
# @see {Schema::Member::TypeSystemHelpers#to_non_null_type}
|
8
8
|
class NonNull < GraphQL::Schema::Wrapper
|
9
|
+
include Schema::Member::ValidatesInput
|
10
|
+
|
9
11
|
def to_graphql
|
10
12
|
@of_type.graphql_definition.to_non_null_type
|
11
13
|
end
|
@@ -32,6 +34,29 @@ module GraphQL
|
|
32
34
|
def inspect
|
33
35
|
"#<#{self.class.name} @of_type=#{@of_type.inspect}>"
|
34
36
|
end
|
37
|
+
|
38
|
+
def validate_input(value, ctx)
|
39
|
+
if value.nil?
|
40
|
+
result = GraphQL::Query::InputValidationResult.new
|
41
|
+
result.add_problem("Expected value to not be null")
|
42
|
+
result
|
43
|
+
else
|
44
|
+
of_type.validate_input(value, ctx)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# This is for introspection, where it's expected the name will be `null`
|
49
|
+
def graphql_name
|
50
|
+
nil
|
51
|
+
end
|
52
|
+
|
53
|
+
def coerce_input(value, ctx)
|
54
|
+
of_type.coerce_input(value, ctx)
|
55
|
+
end
|
56
|
+
|
57
|
+
def coerce_result(value, ctx)
|
58
|
+
of_type.coerce_result(value, ctx)
|
59
|
+
end
|
35
60
|
end
|
36
61
|
end
|
37
62
|
end
|
@@ -84,11 +84,24 @@ module GraphQL
|
|
84
84
|
include(int)
|
85
85
|
end
|
86
86
|
end
|
87
|
+
# Remove any interfaces which are being replaced (late-bound types are updated in place this way)
|
88
|
+
own_interfaces.reject! { |i|
|
89
|
+
new_interfaces.any? { |new_i|
|
90
|
+
new_name = new_i.is_a?(String) ? new_i : new_i.graphql_name
|
91
|
+
old_name = i.is_a?(String) ? i : i.graphql_name
|
92
|
+
new_name == old_name
|
93
|
+
}
|
94
|
+
}
|
87
95
|
own_interfaces.concat(new_interfaces)
|
88
96
|
end
|
89
97
|
|
90
98
|
def interfaces
|
91
|
-
|
99
|
+
inherited_interfaces = (superclass.respond_to?(:interfaces) ? superclass.interfaces : nil)
|
100
|
+
if inherited_interfaces && !inherited_interfaces.empty?
|
101
|
+
own_interfaces + inherited_interfaces
|
102
|
+
else
|
103
|
+
own_interfaces
|
104
|
+
end
|
92
105
|
end
|
93
106
|
|
94
107
|
def own_interfaces
|
@@ -54,13 +54,14 @@ module GraphQL
|
|
54
54
|
)
|
55
55
|
|
56
56
|
@document = @document_from_schema.document
|
57
|
-
|
58
57
|
@schema = schema
|
59
58
|
end
|
60
59
|
|
61
60
|
# Return the GraphQL schema string for the introspection type system
|
62
61
|
def self.print_introspection_schema
|
63
|
-
query_root = ObjectType.define(name: "Root")
|
62
|
+
query_root = ObjectType.define(name: "Root") do
|
63
|
+
field :throwaway_field, types.String
|
64
|
+
end
|
64
65
|
schema = GraphQL::Schema.define(query: query_root)
|
65
66
|
|
66
67
|
introspection_schema_ast = GraphQL::Language::DocumentFromSchemaDefinition.new(
|
@@ -97,7 +98,7 @@ module GraphQL
|
|
97
98
|
if directive.name == "deprecated"
|
98
99
|
reason = directive.arguments.find { |arg| arg.name == "reason" }
|
99
100
|
|
100
|
-
if reason.value == GraphQL::Directive::DEFAULT_DEPRECATION_REASON
|
101
|
+
if reason.value == GraphQL::Schema::Directive::DEFAULT_DEPRECATION_REASON
|
101
102
|
"@deprecated"
|
102
103
|
else
|
103
104
|
"@deprecated(reason: #{reason.value.to_s.inspect})"
|
@@ -33,9 +33,13 @@ module GraphQL
|
|
33
33
|
# But when using the interpreter, no instrumenters are applied.
|
34
34
|
if context.interpreter?
|
35
35
|
input = inputs[:input].to_kwargs
|
36
|
+
|
37
|
+
new_extras = field ? field.extras : []
|
38
|
+
all_extras = self.class.extras + new_extras
|
39
|
+
|
36
40
|
# Transfer these from the top-level hash to the
|
37
41
|
# shortcutted `input:` object
|
38
|
-
|
42
|
+
all_extras.each do |ext|
|
39
43
|
# It's possible that the `extra` was not passed along by this point,
|
40
44
|
# don't re-add it if it wasn't given here.
|
41
45
|
if inputs.key?(ext)
|
@@ -29,9 +29,11 @@ module GraphQL
|
|
29
29
|
|
30
30
|
# @param object [Object] the initialize object, pass to {Query.initialize} as `root_value`
|
31
31
|
# @param context [GraphQL::Query::Context]
|
32
|
-
|
32
|
+
# @param field [GraphQL::Schema::Field]
|
33
|
+
def initialize(object:, context:, field:)
|
33
34
|
@object = object
|
34
35
|
@context = context
|
36
|
+
@field = field
|
35
37
|
# Since this hash is constantly rebuilt, cache it for this call
|
36
38
|
@arguments_by_keyword = {}
|
37
39
|
self.class.arguments.each do |name, arg|
|
@@ -46,6 +48,9 @@ module GraphQL
|
|
46
48
|
# @return [GraphQL::Query::Context]
|
47
49
|
attr_reader :context
|
48
50
|
|
51
|
+
# @return [GraphQL::Schema::Field]
|
52
|
+
attr_reader :field
|
53
|
+
|
49
54
|
# This method is _actually_ called by the runtime,
|
50
55
|
# it does some preparation and then eventually calls
|
51
56
|
# the user-defined `#resolve` method.
|
@@ -103,7 +108,7 @@ module GraphQL
|
|
103
108
|
# Do the work. Everything happens here.
|
104
109
|
# @return [Object] An object corresponding to the return type
|
105
110
|
def resolve(**args)
|
106
|
-
raise
|
111
|
+
raise GraphQL::RequiredImplementationMissingError, "#{self.class.name}#resolve should execute the field's logic"
|
107
112
|
end
|
108
113
|
|
109
114
|
# Called before arguments are prepared.
|
@@ -255,6 +260,7 @@ module GraphQL
|
|
255
260
|
arguments: arguments,
|
256
261
|
null: null,
|
257
262
|
complexity: complexity,
|
263
|
+
extensions: extensions,
|
258
264
|
}
|
259
265
|
end
|
260
266
|
|
@@ -308,6 +314,18 @@ module GraphQL
|
|
308
314
|
inherited_lookups.merge(own_arguments_loads_as_type)
|
309
315
|
end
|
310
316
|
|
317
|
+
# Registers new extension
|
318
|
+
# @param extension [Class] Extension class
|
319
|
+
# @param options [Hash] Optional extension options
|
320
|
+
def extension(extension, **options)
|
321
|
+
extensions << {extension => options}
|
322
|
+
end
|
323
|
+
|
324
|
+
# @api private
|
325
|
+
def extensions
|
326
|
+
@extensions ||= []
|
327
|
+
end
|
328
|
+
|
311
329
|
private
|
312
330
|
|
313
331
|
def own_arguments_loads_as_type
|