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
@@ -31,10 +31,10 @@ module GraphQL
|
|
31
31
|
elsif value.is_a?(GraphQL::Pagination::Connection)
|
32
32
|
# update the connection with some things that may not have been provided
|
33
33
|
value.context ||= context
|
34
|
-
value.
|
35
|
-
value.
|
36
|
-
value.
|
37
|
-
value.
|
34
|
+
value.first_value ||= arguments[:first]
|
35
|
+
value.after_value ||= arguments[:after]
|
36
|
+
value.last_value ||= arguments[:last]
|
37
|
+
value.before_value ||= arguments[:before]
|
38
38
|
value.max_page_size ||= field.max_page_size
|
39
39
|
value
|
40
40
|
elsif context.schema.new_connections?
|
@@ -1,6 +1,19 @@
|
|
1
1
|
module GraphQL
|
2
2
|
class Schema
|
3
3
|
module FindInheritedValue
|
4
|
+
module EmptyObjects
|
5
|
+
EMPTY_HASH = {}.freeze
|
6
|
+
EMPTY_ARRAY = [].freeze
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.extended(child_cls)
|
10
|
+
child_cls.singleton_class.include(EmptyObjects)
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.included(child_cls)
|
14
|
+
child_cls.include(EmptyObjects)
|
15
|
+
end
|
16
|
+
|
4
17
|
private
|
5
18
|
|
6
19
|
def find_inherited_value(method_name, default_value = nil)
|
@@ -38,7 +38,7 @@ module GraphQL
|
|
38
38
|
|
39
39
|
find_in_directive(directive, path: path)
|
40
40
|
else
|
41
|
-
type = schema.
|
41
|
+
type = schema.get_type(type_or_directive)
|
42
42
|
|
43
43
|
if type.nil?
|
44
44
|
raise MemberNotFoundError, "Could not find type `#{type_or_directive}` in schema."
|
@@ -66,22 +66,24 @@ module GraphQL
|
|
66
66
|
end
|
67
67
|
|
68
68
|
def find_in_type(type, path:)
|
69
|
-
case type
|
70
|
-
when
|
69
|
+
case type.kind.name
|
70
|
+
when "OBJECT"
|
71
71
|
find_in_fields_type(type, kind: "object", path: path)
|
72
|
-
when
|
72
|
+
when "INTERFACE"
|
73
73
|
find_in_fields_type(type, kind: "interface", path: path)
|
74
|
-
when
|
74
|
+
when "INPUT_OBJECT"
|
75
75
|
find_in_input_object(type, path: path)
|
76
|
-
when
|
76
|
+
when "UNION"
|
77
77
|
# Error out if path that was provided is too long
|
78
78
|
# i.e UnionType.PossibleType.aField
|
79
79
|
# Use PossibleType.aField instead.
|
80
80
|
if invalid = path.first
|
81
81
|
raise MemberNotFoundError, "Cannot select union possible type `#{invalid}`. Select the type directly instead."
|
82
82
|
end
|
83
|
-
when
|
83
|
+
when "ENUM"
|
84
84
|
find_in_enum_type(type, path: path)
|
85
|
+
else
|
86
|
+
raise "Unexpected find_in_type: #{type.inspect} (#{path})"
|
85
87
|
end
|
86
88
|
end
|
87
89
|
|
@@ -90,7 +92,7 @@ module GraphQL
|
|
90
92
|
field = schema.get_field(type, field_name)
|
91
93
|
|
92
94
|
if field.nil?
|
93
|
-
raise MemberNotFoundError, "Could not find field `#{field_name}` on #{kind} type `#{type}`."
|
95
|
+
raise MemberNotFoundError, "Could not find field `#{field_name}` on #{kind} type `#{type.graphql_name}`."
|
94
96
|
end
|
95
97
|
|
96
98
|
return field if path.empty?
|
@@ -117,10 +119,10 @@ module GraphQL
|
|
117
119
|
|
118
120
|
def find_in_input_object(input_object, path:)
|
119
121
|
field_name = path.shift
|
120
|
-
input_field = input_object.
|
122
|
+
input_field = input_object.arguments[field_name]
|
121
123
|
|
122
124
|
if input_field.nil?
|
123
|
-
raise MemberNotFoundError, "Could not find input field `#{field_name}` on input object type `#{input_object}`."
|
125
|
+
raise MemberNotFoundError, "Could not find input field `#{field_name}` on input object type `#{input_object.graphql_name}`."
|
124
126
|
end
|
125
127
|
|
126
128
|
# Error out if path that was provided is too long
|
@@ -137,7 +139,7 @@ module GraphQL
|
|
137
139
|
enum_value = enum_type.values[value_name]
|
138
140
|
|
139
141
|
if enum_value.nil?
|
140
|
-
raise MemberNotFoundError, "Could not find enum value `#{value_name}` on enum type `#{enum_type}`."
|
142
|
+
raise MemberNotFoundError, "Could not find enum value `#{value_name}` on enum type `#{enum_type.graphql_name}`."
|
141
143
|
end
|
142
144
|
|
143
145
|
# Error out if path that was provided is too long
|
@@ -5,6 +5,8 @@ module GraphQL
|
|
5
5
|
extend GraphQL::Schema::Member::AcceptsDefinition
|
6
6
|
extend Forwardable
|
7
7
|
extend GraphQL::Schema::Member::HasArguments
|
8
|
+
extend GraphQL::Schema::Member::ValidatesInput
|
9
|
+
|
8
10
|
include GraphQL::Dig
|
9
11
|
|
10
12
|
def initialize(values = nil, ruby_kwargs: nil, context:, defaults_used:)
|
@@ -57,6 +59,10 @@ module GraphQL
|
|
57
59
|
to_h
|
58
60
|
end
|
59
61
|
|
62
|
+
def prepare
|
63
|
+
self
|
64
|
+
end
|
65
|
+
|
60
66
|
def unwrap_value(value)
|
61
67
|
case value
|
62
68
|
when Array
|
@@ -86,7 +92,7 @@ module GraphQL
|
|
86
92
|
end
|
87
93
|
|
88
94
|
def key?(key)
|
89
|
-
@ruby_style_hash.key?(key) || (@arguments && @arguments.key?(key))
|
95
|
+
@ruby_style_hash.key?(key) || (@arguments && @arguments.key?(key)) || false
|
90
96
|
end
|
91
97
|
|
92
98
|
# A copy of the Ruby-style hash
|
@@ -127,6 +133,108 @@ module GraphQL
|
|
127
133
|
def kind
|
128
134
|
GraphQL::TypeKinds::INPUT_OBJECT
|
129
135
|
end
|
136
|
+
|
137
|
+
# @api private
|
138
|
+
INVALID_OBJECT_MESSAGE = "Expected %{object} to be a key-value object responding to `to_h` or `to_unsafe_h`."
|
139
|
+
|
140
|
+
|
141
|
+
def validate_non_null_input(input, ctx)
|
142
|
+
result = GraphQL::Query::InputValidationResult.new
|
143
|
+
|
144
|
+
warden = ctx.warden
|
145
|
+
|
146
|
+
if input.is_a?(Array)
|
147
|
+
result.add_problem(INVALID_OBJECT_MESSAGE % { object: JSON.generate(input, quirks_mode: true) })
|
148
|
+
return result
|
149
|
+
end
|
150
|
+
|
151
|
+
# We're not actually _using_ the coerced result, we're just
|
152
|
+
# using these methods to make sure that the object will
|
153
|
+
# behave like a hash below, when we call `each` on it.
|
154
|
+
begin
|
155
|
+
input.to_h
|
156
|
+
rescue
|
157
|
+
begin
|
158
|
+
# Handle ActionController::Parameters:
|
159
|
+
input.to_unsafe_h
|
160
|
+
rescue
|
161
|
+
# We're not sure it'll act like a hash, so reject it:
|
162
|
+
result.add_problem(INVALID_OBJECT_MESSAGE % { object: JSON.generate(input, quirks_mode: true) })
|
163
|
+
return result
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
visible_arguments_map = warden.arguments(self).reduce({}) { |m, f| m[f.name] = f; m}
|
168
|
+
|
169
|
+
# Items in the input that are unexpected
|
170
|
+
input.each do |name, value|
|
171
|
+
if visible_arguments_map[name].nil?
|
172
|
+
result.add_problem("Argument is not defined on #{self.graphql_name}", [name])
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
# Items in the input that are expected, but have invalid values
|
177
|
+
visible_arguments_map.map do |name, argument|
|
178
|
+
argument_result = argument.type.validate_input(input[name], ctx)
|
179
|
+
if !argument_result.valid?
|
180
|
+
result.merge_result!(name, argument_result)
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
result
|
185
|
+
end
|
186
|
+
|
187
|
+
def coerce_input(value, ctx)
|
188
|
+
input_values = {}
|
189
|
+
|
190
|
+
arguments.each do |name, argument_defn|
|
191
|
+
arg_key = argument_defn.keyword
|
192
|
+
has_value = false
|
193
|
+
# Accept either string or symbol
|
194
|
+
field_value = if value.key?(name)
|
195
|
+
has_value = true
|
196
|
+
value[name]
|
197
|
+
elsif value.key?(arg_key)
|
198
|
+
has_value = true
|
199
|
+
value[arg_key]
|
200
|
+
elsif argument_defn.default_value?
|
201
|
+
has_value = true
|
202
|
+
argument_defn.default_value
|
203
|
+
else
|
204
|
+
nil
|
205
|
+
end
|
206
|
+
# Only continue if some value was found for this argument
|
207
|
+
if has_value
|
208
|
+
coerced_value = argument_defn.type.coerce_input(field_value, ctx)
|
209
|
+
prepared_value = argument_defn.prepare_value(nil, coerced_value, context: ctx)
|
210
|
+
input_values[arg_key] = prepared_value
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
input_values
|
215
|
+
end
|
216
|
+
|
217
|
+
# It's funny to think of a _result_ of an input object.
|
218
|
+
# This is used for rendering the default value in introspection responses.
|
219
|
+
def coerce_result(value, ctx)
|
220
|
+
# Allow the application to provide values as :symbols, and convert them to the strings
|
221
|
+
value = value.reduce({}) { |memo, (k, v)| memo[k.to_s] = v; memo }
|
222
|
+
|
223
|
+
result = {}
|
224
|
+
|
225
|
+
arguments.each do |input_key, input_field_defn|
|
226
|
+
input_value = value[input_key]
|
227
|
+
if value.key?(input_key)
|
228
|
+
result[input_key] = if input_value.nil?
|
229
|
+
nil
|
230
|
+
else
|
231
|
+
input_field_defn.type.coerce_result(input_value, ctx)
|
232
|
+
end
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
result
|
237
|
+
end
|
130
238
|
end
|
131
239
|
end
|
132
240
|
end
|
@@ -7,6 +7,7 @@ module GraphQL
|
|
7
7
|
include GraphQL::Schema::Member::CachedGraphQLDefinition
|
8
8
|
include GraphQL::Relay::TypeExtensions
|
9
9
|
include GraphQL::Schema::Member::BaseDSLMethods
|
10
|
+
# ConfigurationExtension's responsibilities are in `def included` below
|
10
11
|
include GraphQL::Schema::Member::TypeSystemHelpers
|
11
12
|
include GraphQL::Schema::Member::HasFields
|
12
13
|
include GraphQL::Schema::Member::HasPath
|
@@ -21,14 +22,9 @@ module GraphQL
|
|
21
22
|
self::DefinitionMethods.module_eval(&block)
|
22
23
|
end
|
23
24
|
|
24
|
-
#
|
25
|
+
# @see {Schema::Warden} hides interfaces without visible implementations
|
25
26
|
def visible?(context)
|
26
|
-
|
27
|
-
if context.schema.visible?(type, context)
|
28
|
-
return true
|
29
|
-
end
|
30
|
-
end
|
31
|
-
false
|
27
|
+
true
|
32
28
|
end
|
33
29
|
|
34
30
|
# The interface is accessible if any of its possible types are accessible
|
@@ -64,6 +60,11 @@ module GraphQL
|
|
64
60
|
child_class.const_set(:DefinitionMethods, defn_methods_module)
|
65
61
|
child_class.extend(child_class::DefinitionMethods)
|
66
62
|
end
|
63
|
+
child_class.introspection(introspection)
|
64
|
+
child_class.description(description)
|
65
|
+
if overridden_graphql_name
|
66
|
+
child_class.graphql_name(overridden_graphql_name)
|
67
|
+
end
|
67
68
|
elsif child_class < GraphQL::Schema::Object
|
68
69
|
# This is being included into an object type, make sure it's using `implements(...)`
|
69
70
|
backtrace_line = caller(0, 10).find { |line| line.include?("schema/object.rb") && line.include?("in `implements'")}
|
@@ -2,24 +2,36 @@
|
|
2
2
|
module GraphQL
|
3
3
|
class Schema
|
4
4
|
class IntrospectionSystem
|
5
|
-
attr_reader :
|
5
|
+
attr_reader :types, :possible_types
|
6
6
|
|
7
7
|
def initialize(schema)
|
8
8
|
@schema = schema
|
9
|
+
@class_based = !!@schema.is_a?(Class)
|
9
10
|
@built_in_namespace = GraphQL::Introspection
|
10
|
-
@custom_namespace =
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
11
|
+
@custom_namespace = if @class_based
|
12
|
+
schema.introspection || @built_in_namespace
|
13
|
+
else
|
14
|
+
schema.introspection_namespace || @built_in_namespace
|
15
|
+
end
|
16
|
+
|
17
|
+
type_defns = [
|
18
|
+
load_constant(:SchemaType),
|
19
|
+
load_constant(:TypeType),
|
20
|
+
load_constant(:FieldType),
|
21
|
+
load_constant(:DirectiveType),
|
22
|
+
load_constant(:EnumValueType),
|
23
|
+
load_constant(:InputValueType),
|
24
|
+
load_constant(:TypeKindEnum),
|
25
|
+
load_constant(:DirectiveLocationEnum)
|
26
|
+
]
|
27
|
+
@types = {}
|
28
|
+
@possible_types = {}
|
29
|
+
type_defns.each do |t|
|
30
|
+
@types[t.graphql_name] = t
|
31
|
+
@possible_types[t.graphql_name] = [t]
|
32
|
+
end
|
21
33
|
@entry_point_fields =
|
22
|
-
if schema.disable_introspection_entry_points
|
34
|
+
if schema.disable_introspection_entry_points?
|
23
35
|
{}
|
24
36
|
else
|
25
37
|
get_fields_from_class(class_sym: :EntryPoints)
|
@@ -27,19 +39,6 @@ module GraphQL
|
|
27
39
|
@dynamic_fields = get_fields_from_class(class_sym: :DynamicFields)
|
28
40
|
end
|
29
41
|
|
30
|
-
def object_types
|
31
|
-
[
|
32
|
-
@schema_type,
|
33
|
-
@type_type,
|
34
|
-
@field_type,
|
35
|
-
@directive_type,
|
36
|
-
@enum_value_type,
|
37
|
-
@input_value_type,
|
38
|
-
@type_kind_enum,
|
39
|
-
@directive_location_enum,
|
40
|
-
]
|
41
|
-
end
|
42
|
-
|
43
42
|
def entry_points
|
44
43
|
@entry_point_fields.values
|
45
44
|
end
|
@@ -56,25 +55,94 @@ module GraphQL
|
|
56
55
|
@dynamic_fields[name]
|
57
56
|
end
|
58
57
|
|
58
|
+
# The introspection system is prepared with a bunch of LateBoundTypes.
|
59
|
+
# Replace those with the objects that they refer to, since LateBoundTypes
|
60
|
+
# aren't handled at runtime.
|
61
|
+
#
|
62
|
+
# @api private
|
63
|
+
# @return void
|
64
|
+
def resolve_late_bindings
|
65
|
+
@types.each do |name, t|
|
66
|
+
if t.kind.fields?
|
67
|
+
t.fields.each do |_name, field_defn|
|
68
|
+
field_defn.type = resolve_late_binding(field_defn.type)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
@entry_point_fields.each do |name, f|
|
74
|
+
f.type = resolve_late_binding(f.type)
|
75
|
+
end
|
76
|
+
|
77
|
+
@dynamic_fields.each do |name, f|
|
78
|
+
f.type = resolve_late_binding(f.type)
|
79
|
+
end
|
80
|
+
nil
|
81
|
+
end
|
82
|
+
|
59
83
|
private
|
60
84
|
|
85
|
+
def resolve_late_binding(late_bound_type)
|
86
|
+
case late_bound_type
|
87
|
+
when GraphQL::Schema::LateBoundType
|
88
|
+
@schema.get_type(late_bound_type.name)
|
89
|
+
when GraphQL::Schema::List, GraphQL::ListType
|
90
|
+
resolve_late_binding(late_bound_type.of_type).to_list_type
|
91
|
+
when GraphQL::Schema::NonNull, GraphQL::NonNullType
|
92
|
+
resolve_late_binding(late_bound_type.of_type).to_non_null_type
|
93
|
+
when Module
|
94
|
+
# It's a normal type -- no change required
|
95
|
+
late_bound_type
|
96
|
+
else
|
97
|
+
raise "Invariant: unexpected type: #{late_bound_type} (#{late_bound_type.class})"
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
61
101
|
def load_constant(class_name)
|
62
|
-
@custom_namespace.const_get(class_name)
|
102
|
+
const = @custom_namespace.const_get(class_name)
|
103
|
+
if @class_based
|
104
|
+
dup_type_class(const)
|
105
|
+
else
|
106
|
+
# Use `.to_graphql` to get a freshly-made version, not shared between schemas
|
107
|
+
const.to_graphql
|
108
|
+
end
|
63
109
|
rescue NameError
|
64
110
|
# Dup the built-in so that the cached fields aren't shared
|
65
|
-
@built_in_namespace.const_get(class_name)
|
111
|
+
dup_type_class(@built_in_namespace.const_get(class_name))
|
66
112
|
end
|
67
113
|
|
68
114
|
def get_fields_from_class(class_sym:)
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
115
|
+
object_type_defn = load_constant(class_sym)
|
116
|
+
|
117
|
+
if object_type_defn.is_a?(Module)
|
118
|
+
object_type_defn.fields
|
119
|
+
else
|
120
|
+
extracted_field_defns = {}
|
121
|
+
object_class = object_type_defn.metadata[:type_class]
|
122
|
+
object_type_defn.all_fields.each do |field_defn|
|
123
|
+
inner_resolve = field_defn.resolve_proc
|
124
|
+
resolve_with_instantiate = PerFieldProxyResolve.new(object_class: object_class, inner_resolve: inner_resolve)
|
125
|
+
extracted_field_defns[field_defn.name] = field_defn.redefine(resolve: resolve_with_instantiate)
|
126
|
+
end
|
127
|
+
extracted_field_defns
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
# This is probably not 100% robust -- but it has to be good enough to avoid modifying the built-in introspection types
|
132
|
+
def dup_type_class(type_class)
|
133
|
+
type_name = type_class.graphql_name
|
134
|
+
Class.new(type_class) do
|
135
|
+
# This won't be inherited like other things will
|
136
|
+
graphql_name(type_name)
|
137
|
+
|
138
|
+
if type_class.kind.fields?
|
139
|
+
type_class.fields.each do |_name, field_defn|
|
140
|
+
dup_field = field_defn.dup
|
141
|
+
dup_field.owner = self
|
142
|
+
add_field(dup_field)
|
143
|
+
end
|
144
|
+
end
|
76
145
|
end
|
77
|
-
extracted_field_defns
|
78
146
|
end
|
79
147
|
|
80
148
|
class PerFieldProxyResolve
|