graphql 1.10.0.pre1 → 1.10.0.pre2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/generators/graphql/core.rb +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
|