graphql 1.11.3 → 1.12.0
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.
Potentially problematic release.
This version of graphql might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/lib/generators/graphql/core.rb +8 -0
- data/lib/generators/graphql/install_generator.rb +5 -5
- data/lib/generators/graphql/object_generator.rb +2 -0
- data/lib/generators/graphql/relay_generator.rb +63 -0
- data/lib/generators/graphql/templates/base_argument.erb +2 -0
- data/lib/generators/graphql/templates/base_connection.erb +8 -0
- data/lib/generators/graphql/templates/base_edge.erb +8 -0
- data/lib/generators/graphql/templates/base_enum.erb +2 -0
- data/lib/generators/graphql/templates/base_field.erb +2 -0
- data/lib/generators/graphql/templates/base_input_object.erb +2 -0
- data/lib/generators/graphql/templates/base_interface.erb +2 -0
- data/lib/generators/graphql/templates/base_mutation.erb +2 -0
- data/lib/generators/graphql/templates/base_object.erb +2 -0
- data/lib/generators/graphql/templates/base_scalar.erb +2 -0
- data/lib/generators/graphql/templates/base_union.erb +2 -0
- data/lib/generators/graphql/templates/enum.erb +2 -0
- data/lib/generators/graphql/templates/graphql_controller.erb +2 -0
- data/lib/generators/graphql/templates/interface.erb +2 -0
- data/lib/generators/graphql/templates/loader.erb +2 -0
- data/lib/generators/graphql/templates/mutation.erb +2 -0
- data/lib/generators/graphql/templates/mutation_type.erb +2 -0
- data/lib/generators/graphql/templates/node_type.erb +9 -0
- data/lib/generators/graphql/templates/object.erb +3 -1
- data/lib/generators/graphql/templates/query_type.erb +3 -3
- data/lib/generators/graphql/templates/scalar.erb +2 -0
- data/lib/generators/graphql/templates/schema.erb +10 -35
- data/lib/generators/graphql/templates/union.erb +3 -1
- data/lib/graphql.rb +55 -4
- data/lib/graphql/analysis/analyze_query.rb +7 -0
- data/lib/graphql/analysis/ast.rb +11 -2
- data/lib/graphql/analysis/ast/visitor.rb +9 -1
- data/lib/graphql/argument.rb +3 -3
- data/lib/graphql/backtrace.rb +28 -19
- data/lib/graphql/backtrace/legacy_tracer.rb +56 -0
- data/lib/graphql/backtrace/table.rb +22 -2
- data/lib/graphql/backtrace/tracer.rb +40 -8
- data/lib/graphql/backwards_compatibility.rb +1 -0
- data/lib/graphql/compatibility/execution_specification.rb +1 -0
- data/lib/graphql/compatibility/lazy_execution_specification.rb +2 -0
- data/lib/graphql/compatibility/query_parser_specification.rb +2 -0
- data/lib/graphql/compatibility/schema_parser_specification.rb +2 -0
- data/lib/graphql/dataloader.rb +197 -0
- data/lib/graphql/dataloader/null_dataloader.rb +21 -0
- data/lib/graphql/dataloader/request.rb +24 -0
- data/lib/graphql/dataloader/request_all.rb +22 -0
- data/lib/graphql/dataloader/source.rb +93 -0
- data/lib/graphql/define/assign_global_id_field.rb +2 -2
- data/lib/graphql/define/instance_definable.rb +32 -2
- data/lib/graphql/define/type_definer.rb +5 -5
- data/lib/graphql/deprecated_dsl.rb +5 -0
- data/lib/graphql/enum_type.rb +2 -0
- data/lib/graphql/execution/errors.rb +4 -0
- data/lib/graphql/execution/execute.rb +7 -0
- data/lib/graphql/execution/interpreter.rb +20 -6
- data/lib/graphql/execution/interpreter/arguments.rb +57 -5
- data/lib/graphql/execution/interpreter/arguments_cache.rb +8 -0
- data/lib/graphql/execution/interpreter/handles_raw_value.rb +0 -7
- data/lib/graphql/execution/interpreter/runtime.rb +251 -138
- data/lib/graphql/execution/multiplex.rb +20 -6
- data/lib/graphql/function.rb +4 -0
- data/lib/graphql/input_object_type.rb +2 -0
- data/lib/graphql/integer_decoding_error.rb +17 -0
- data/lib/graphql/interface_type.rb +3 -1
- 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/invalid_null_error.rb +1 -1
- data/lib/graphql/language/block_string.rb +24 -5
- data/lib/graphql/language/document_from_schema_definition.rb +50 -23
- 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/object_type.rb +2 -0
- data/lib/graphql/pagination/connection.rb +5 -1
- data/lib/graphql/pagination/connections.rb +15 -17
- data/lib/graphql/query.rb +8 -3
- data/lib/graphql/query/context.rb +38 -4
- data/lib/graphql/query/fingerprint.rb +2 -0
- data/lib/graphql/query/serial_execution.rb +1 -0
- data/lib/graphql/query/validation_pipeline.rb +4 -1
- data/lib/graphql/relay/array_connection.rb +2 -2
- data/lib/graphql/relay/base_connection.rb +7 -0
- data/lib/graphql/relay/connection_instrumentation.rb +4 -4
- data/lib/graphql/relay/connection_type.rb +1 -1
- data/lib/graphql/relay/mutation.rb +1 -0
- data/lib/graphql/relay/node.rb +3 -0
- data/lib/graphql/relay/range_add.rb +14 -5
- data/lib/graphql/relay/type_extensions.rb +2 -0
- data/lib/graphql/scalar_type.rb +2 -0
- data/lib/graphql/schema.rb +107 -38
- data/lib/graphql/schema/argument.rb +74 -5
- data/lib/graphql/schema/build_from_definition.rb +203 -86
- data/lib/graphql/schema/default_type_error.rb +2 -0
- data/lib/graphql/schema/directive.rb +76 -0
- data/lib/graphql/schema/directive/deprecated.rb +1 -1
- data/lib/graphql/schema/directive/flagged.rb +57 -0
- data/lib/graphql/schema/enum.rb +3 -0
- data/lib/graphql/schema/enum_value.rb +12 -6
- data/lib/graphql/schema/field.rb +59 -24
- data/lib/graphql/schema/field/connection_extension.rb +11 -9
- data/lib/graphql/schema/field/scope_extension.rb +1 -1
- data/lib/graphql/schema/input_object.rb +38 -25
- data/lib/graphql/schema/interface.rb +2 -1
- data/lib/graphql/schema/late_bound_type.rb +2 -2
- data/lib/graphql/schema/loader.rb +1 -0
- data/lib/graphql/schema/member.rb +4 -0
- data/lib/graphql/schema/member/base_dsl_methods.rb +1 -0
- data/lib/graphql/schema/member/build_type.rb +17 -7
- data/lib/graphql/schema/member/has_arguments.rb +70 -51
- data/lib/graphql/schema/member/has_deprecation_reason.rb +25 -0
- data/lib/graphql/schema/member/has_directives.rb +98 -0
- data/lib/graphql/schema/member/has_fields.rb +2 -2
- data/lib/graphql/schema/member/has_validators.rb +31 -0
- data/lib/graphql/schema/member/type_system_helpers.rb +3 -3
- data/lib/graphql/schema/object.rb +11 -0
- data/lib/graphql/schema/printer.rb +5 -4
- data/lib/graphql/schema/relay_classic_mutation.rb +4 -2
- data/lib/graphql/schema/resolver.rb +7 -0
- data/lib/graphql/schema/resolver/has_payload_type.rb +2 -0
- data/lib/graphql/schema/subscription.rb +20 -12
- data/lib/graphql/schema/timeout.rb +29 -15
- data/lib/graphql/schema/timeout_middleware.rb +2 -0
- data/lib/graphql/schema/unique_within_type.rb +1 -2
- data/lib/graphql/schema/validation.rb +10 -0
- data/lib/graphql/schema/validator.rb +163 -0
- data/lib/graphql/schema/validator/exclusion_validator.rb +31 -0
- data/lib/graphql/schema/validator/format_validator.rb +49 -0
- data/lib/graphql/schema/validator/inclusion_validator.rb +33 -0
- data/lib/graphql/schema/validator/length_validator.rb +57 -0
- data/lib/graphql/schema/validator/numericality_validator.rb +71 -0
- data/lib/graphql/schema/validator/required_validator.rb +68 -0
- data/lib/graphql/schema/warden.rb +2 -3
- data/lib/graphql/static_validation.rb +1 -0
- data/lib/graphql/static_validation/all_rules.rb +1 -0
- data/lib/graphql/static_validation/rules/fields_will_merge.rb +25 -17
- data/lib/graphql/static_validation/rules/input_object_names_are_unique.rb +30 -0
- data/lib/graphql/static_validation/rules/input_object_names_are_unique_error.rb +30 -0
- data/lib/graphql/static_validation/validation_timeout_error.rb +25 -0
- data/lib/graphql/static_validation/validator.rb +31 -7
- data/lib/graphql/subscriptions.rb +23 -16
- data/lib/graphql/subscriptions/action_cable_subscriptions.rb +21 -7
- data/lib/graphql/tracing.rb +2 -2
- data/lib/graphql/tracing/appoptics_tracing.rb +12 -2
- data/lib/graphql/tracing/platform_tracing.rb +4 -2
- data/lib/graphql/tracing/prometheus_tracing/graphql_collector.rb +4 -1
- data/lib/graphql/tracing/skylight_tracing.rb +1 -1
- data/lib/graphql/types/int.rb +9 -2
- data/lib/graphql/types/iso_8601_date_time.rb +2 -1
- data/lib/graphql/types/relay.rb +11 -3
- data/lib/graphql/types/relay/base_connection.rb +2 -90
- data/lib/graphql/types/relay/base_edge.rb +2 -34
- data/lib/graphql/types/relay/connection_behaviors.rb +123 -0
- data/lib/graphql/types/relay/default_relay.rb +27 -0
- data/lib/graphql/types/relay/edge_behaviors.rb +42 -0
- data/lib/graphql/types/relay/has_node_field.rb +41 -0
- data/lib/graphql/types/relay/has_nodes_field.rb +41 -0
- data/lib/graphql/types/relay/node.rb +2 -4
- data/lib/graphql/types/relay/node_behaviors.rb +15 -0
- data/lib/graphql/types/relay/node_field.rb +1 -19
- data/lib/graphql/types/relay/nodes_field.rb +1 -19
- data/lib/graphql/types/relay/page_info.rb +2 -14
- data/lib/graphql/types/relay/page_info_behaviors.rb +25 -0
- data/lib/graphql/types/string.rb +7 -1
- data/lib/graphql/unauthorized_error.rb +1 -1
- data/lib/graphql/union_type.rb +2 -0
- data/lib/graphql/upgrader/member.rb +1 -0
- data/lib/graphql/upgrader/schema.rb +1 -0
- data/lib/graphql/version.rb +1 -1
- data/readme.md +1 -1
- metadata +38 -9
- data/lib/graphql/types/relay/base_field.rb +0 -22
- data/lib/graphql/types/relay/base_interface.rb +0 -29
- data/lib/graphql/types/relay/base_object.rb +0 -26
@@ -10,6 +10,10 @@ module GraphQL
|
|
10
10
|
include GraphQL::Schema::Member::AcceptsDefinition
|
11
11
|
include GraphQL::Schema::Member::HasPath
|
12
12
|
include GraphQL::Schema::Member::HasAstNode
|
13
|
+
include GraphQL::Schema::Member::HasDirectives
|
14
|
+
include GraphQL::Schema::Member::HasDeprecationReason
|
15
|
+
include GraphQL::Schema::Member::HasValidators
|
16
|
+
include GraphQL::Schema::FindInheritedValue::EmptyObjects
|
13
17
|
|
14
18
|
NO_DEFAULT = :__no_default__
|
15
19
|
|
@@ -45,7 +49,10 @@ module GraphQL
|
|
45
49
|
# @param camelize [Boolean] if true, the name will be camelized when building the schema
|
46
50
|
# @param from_resolver [Boolean] if true, a Resolver class defined this argument
|
47
51
|
# @param method_access [Boolean] If false, don't build method access on legacy {Query::Arguments} instances.
|
48
|
-
|
52
|
+
# @param directives [Hash{Class => Hash}]
|
53
|
+
# @param deprecation_reason [String]
|
54
|
+
# @param validates [Hash, nil] Options for building validators, if any should be applied
|
55
|
+
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:, validates: nil, directives: nil, deprecation_reason: nil, &definition_block)
|
49
56
|
arg_name ||= name
|
50
57
|
@name = -(camelize ? Member::BuildType.camelize(arg_name.to_s) : arg_name.to_s)
|
51
58
|
@type_expr = type_expr || type
|
@@ -60,6 +67,15 @@ module GraphQL
|
|
60
67
|
@ast_node = ast_node
|
61
68
|
@from_resolver = from_resolver
|
62
69
|
@method_access = method_access
|
70
|
+
self.deprecation_reason = deprecation_reason
|
71
|
+
|
72
|
+
if directives
|
73
|
+
directives.each do |dir_class, dir_options|
|
74
|
+
directive(dir_class, **dir_options)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
self.validates(validates)
|
63
79
|
|
64
80
|
if definition_block
|
65
81
|
if definition_block.arity == 1
|
@@ -89,6 +105,20 @@ module GraphQL
|
|
89
105
|
end
|
90
106
|
end
|
91
107
|
|
108
|
+
# @return [String] Deprecation reason for this argument
|
109
|
+
def deprecation_reason(text = nil)
|
110
|
+
if text
|
111
|
+
self.deprecation_reason = text
|
112
|
+
else
|
113
|
+
super()
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
def deprecation_reason=(new_reason)
|
118
|
+
validate_deprecated_or_optional(null: @null, deprecation_reason: new_reason)
|
119
|
+
super
|
120
|
+
end
|
121
|
+
|
92
122
|
def visible?(context)
|
93
123
|
true
|
94
124
|
end
|
@@ -143,15 +173,32 @@ module GraphQL
|
|
143
173
|
if NO_DEFAULT != @default_value
|
144
174
|
argument.default_value = @default_value
|
145
175
|
end
|
176
|
+
if self.deprecation_reason
|
177
|
+
argument.deprecation_reason = self.deprecation_reason
|
178
|
+
end
|
146
179
|
argument
|
147
180
|
end
|
148
181
|
|
149
|
-
|
182
|
+
def type=(new_type)
|
183
|
+
validate_input_type(new_type)
|
184
|
+
# This isn't true for LateBoundTypes, but we can assume those will
|
185
|
+
# be updated via this codepath later in schema setup.
|
186
|
+
if new_type.respond_to?(:non_null?)
|
187
|
+
validate_deprecated_or_optional(null: !new_type.non_null?, deprecation_reason: deprecation_reason)
|
188
|
+
end
|
189
|
+
@type = new_type
|
190
|
+
end
|
150
191
|
|
151
192
|
def type
|
152
|
-
@type ||=
|
153
|
-
|
154
|
-
|
193
|
+
@type ||= begin
|
194
|
+
parsed_type = begin
|
195
|
+
Member::BuildType.parse_type(@type_expr, null: @null)
|
196
|
+
rescue StandardError => err
|
197
|
+
raise ArgumentError, "Couldn't build type for Argument #{@owner.name}.#{name}: #{err.class.name}: #{err.message}", err.backtrace
|
198
|
+
end
|
199
|
+
# Use the setter method to get validations
|
200
|
+
self.type = parsed_type
|
201
|
+
end
|
155
202
|
end
|
156
203
|
|
157
204
|
def statically_coercible?
|
@@ -168,6 +215,8 @@ module GraphQL
|
|
168
215
|
value = value.prepare
|
169
216
|
end
|
170
217
|
|
218
|
+
Schema::Validator.validate!(validators, obj, context, value)
|
219
|
+
|
171
220
|
if @prepare.nil?
|
172
221
|
value
|
173
222
|
elsif @prepare.is_a?(String) || @prepare.is_a?(Symbol)
|
@@ -186,6 +235,26 @@ module GraphQL
|
|
186
235
|
raise "Invalid prepare for #{@owner.name}.name: #{@prepare.inspect}"
|
187
236
|
end
|
188
237
|
end
|
238
|
+
|
239
|
+
private
|
240
|
+
|
241
|
+
def validate_input_type(input_type)
|
242
|
+
if input_type.is_a?(String) || input_type.is_a?(GraphQL::Schema::LateBoundType)
|
243
|
+
# Do nothing; assume this will be validated later
|
244
|
+
elsif input_type.kind.non_null? || input_type.kind.list?
|
245
|
+
validate_input_type(input_type.unwrap)
|
246
|
+
elsif !input_type.kind.input?
|
247
|
+
raise ArgumentError, "Invalid input type for #{path}: #{input_type.graphql_name}. Must be scalar, enum, or input object, not #{input_type.kind.name}."
|
248
|
+
else
|
249
|
+
# It's an input type, we're OK
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
def validate_deprecated_or_optional(null:, deprecation_reason:)
|
254
|
+
if deprecation_reason && !null
|
255
|
+
raise ArgumentError, "Required arguments cannot be deprecated: #{path}."
|
256
|
+
end
|
257
|
+
end
|
189
258
|
end
|
190
259
|
end
|
191
260
|
end
|
@@ -3,24 +3,32 @@ require "graphql/schema/build_from_definition/resolve_map"
|
|
3
3
|
|
4
4
|
module GraphQL
|
5
5
|
class Schema
|
6
|
+
# TODO Populate `.directive(...)` from here
|
6
7
|
module BuildFromDefinition
|
8
|
+
if !String.method_defined?(:-@)
|
9
|
+
using GraphQL::StringDedupBackport
|
10
|
+
end
|
11
|
+
|
7
12
|
class << self
|
8
13
|
# @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)
|
14
|
+
def from_definition(definition_string, parser: GraphQL.default_parser, **kwargs)
|
15
|
+
from_document(parser.parse(definition_string), **kwargs)
|
13
16
|
end
|
14
|
-
end
|
15
17
|
|
16
|
-
|
17
|
-
|
18
|
+
def from_definition_path(definition_path, parser: GraphQL.default_parser, **kwargs)
|
19
|
+
from_document(parser.parse_file(definition_path), **kwargs)
|
20
|
+
end
|
21
|
+
|
22
|
+
def from_document(document, default_resolve:, using: {}, relay: false)
|
23
|
+
Builder.build(document, default_resolve: default_resolve || {}, relay: relay, using: using)
|
24
|
+
end
|
25
|
+
end
|
18
26
|
|
19
27
|
# @api private
|
20
28
|
module Builder
|
21
29
|
extend self
|
22
30
|
|
23
|
-
def build(document, default_resolve:, using: {},
|
31
|
+
def build(document, default_resolve:, using: {}, relay:)
|
24
32
|
raise InvalidDocumentError.new('Must provide a document ast.') if !document || !document.is_a?(GraphQL::Language::Nodes::Document)
|
25
33
|
|
26
34
|
if default_resolve.is_a?(Hash)
|
@@ -34,45 +42,43 @@ module GraphQL
|
|
34
42
|
schema_definition = schema_defns.first
|
35
43
|
types = {}
|
36
44
|
directives = {}
|
37
|
-
type_resolver = ->(
|
45
|
+
type_resolver = build_resolve_type(types, directives, ->(type_name) { types[type_name] ||= Schema::LateBoundType.new(type_name)})
|
46
|
+
# Make a different type resolver because we need to coerce directive arguments
|
47
|
+
# _while_ building the schema.
|
48
|
+
# It will dig for a type if it encounters a custom type. This could be a problem if there are cycles.
|
49
|
+
directive_type_resolver = nil
|
50
|
+
directive_type_resolver = build_resolve_type(GraphQL::Schema::BUILT_IN_TYPES, directives, ->(type_name) {
|
51
|
+
types[type_name] ||= begin
|
52
|
+
defn = document.definitions.find { |d| d.respond_to?(:name) && d.name == type_name }
|
53
|
+
build_definition_from_node(defn, directive_type_resolver, default_resolve)
|
54
|
+
end
|
55
|
+
})
|
38
56
|
|
39
57
|
document.definitions.each do |definition|
|
40
|
-
|
41
|
-
|
42
|
-
nil # already handled
|
43
|
-
when GraphQL::Language::Nodes::EnumTypeDefinition
|
44
|
-
types[definition.name] = build_enum_type(definition, type_resolver)
|
45
|
-
when GraphQL::Language::Nodes::ObjectTypeDefinition
|
46
|
-
types[definition.name] = build_object_type(definition, type_resolver, default_resolve: default_resolve)
|
47
|
-
when GraphQL::Language::Nodes::InterfaceTypeDefinition
|
48
|
-
types[definition.name] = build_interface_type(definition, type_resolver)
|
49
|
-
when GraphQL::Language::Nodes::UnionTypeDefinition
|
50
|
-
types[definition.name] = build_union_type(definition, type_resolver)
|
51
|
-
when GraphQL::Language::Nodes::ScalarTypeDefinition
|
52
|
-
types[definition.name] = build_scalar_type(definition, type_resolver, default_resolve: default_resolve)
|
53
|
-
when GraphQL::Language::Nodes::InputObjectTypeDefinition
|
54
|
-
types[definition.name] = build_input_object_type(definition, type_resolver)
|
55
|
-
when GraphQL::Language::Nodes::DirectiveDefinition
|
56
|
-
directives[definition.name] = build_directive(definition, type_resolver)
|
58
|
+
if definition.is_a?(GraphQL::Language::Nodes::DirectiveDefinition)
|
59
|
+
directives[definition.name] = build_directive(definition, directive_type_resolver)
|
57
60
|
end
|
58
61
|
end
|
59
62
|
|
60
|
-
|
61
|
-
|
62
|
-
#
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
types[
|
63
|
+
directives = GraphQL::Schema.default_directives.merge(directives)
|
64
|
+
|
65
|
+
# In case any directives referenced built-in types for their arguments:
|
66
|
+
replace_late_bound_types_with_built_in(types)
|
67
|
+
|
68
|
+
document.definitions.each do |definition|
|
69
|
+
case definition
|
70
|
+
when GraphQL::Language::Nodes::SchemaDefinition, GraphQL::Language::Nodes::DirectiveDefinition
|
71
|
+
nil # already handled
|
72
|
+
else
|
73
|
+
# It's possible that this was already loaded by the directives
|
74
|
+
prev_type = types[definition.name]
|
75
|
+
if prev_type.nil? || prev_type.is_a?(Schema::LateBoundType)
|
76
|
+
types[definition.name] = build_definition_from_node(definition, type_resolver, default_resolve)
|
77
|
+
end
|
72
78
|
end
|
73
79
|
end
|
74
80
|
|
75
|
-
|
81
|
+
replace_late_bound_types_with_built_in(types)
|
76
82
|
|
77
83
|
if schema_definition
|
78
84
|
if schema_definition.query
|
@@ -111,11 +117,11 @@ module GraphQL
|
|
111
117
|
end
|
112
118
|
|
113
119
|
if default_resolve.respond_to?(:resolve_type)
|
114
|
-
|
115
|
-
|
120
|
+
def self.resolve_type(*args)
|
121
|
+
self.definition_default_resolve.resolve_type(*args)
|
116
122
|
end
|
117
123
|
else
|
118
|
-
|
124
|
+
def self.resolve_type(*args)
|
119
125
|
NullResolveType.call(*args)
|
120
126
|
end
|
121
127
|
end
|
@@ -126,11 +132,6 @@ module GraphQL
|
|
126
132
|
ast_node(schema_definition)
|
127
133
|
end
|
128
134
|
|
129
|
-
if interpreter
|
130
|
-
use GraphQL::Execution::Interpreter
|
131
|
-
use GraphQL::Analysis::AST
|
132
|
-
end
|
133
|
-
|
134
135
|
using.each do |plugin, options|
|
135
136
|
if options
|
136
137
|
use(plugin, **options)
|
@@ -141,6 +142,20 @@ module GraphQL
|
|
141
142
|
|
142
143
|
# Empty `orphan_types` -- this will make unreachable types ... unreachable.
|
143
144
|
own_orphan_types.clear
|
145
|
+
|
146
|
+
class << self
|
147
|
+
attr_accessor :definition_default_resolve
|
148
|
+
end
|
149
|
+
|
150
|
+
self.definition_default_resolve = default_resolve
|
151
|
+
|
152
|
+
def definition_default_resolve
|
153
|
+
self.class.definition_default_resolve
|
154
|
+
end
|
155
|
+
|
156
|
+
def self.inherited(child_class)
|
157
|
+
child_class.definition_default_resolve = self.definition_default_resolve
|
158
|
+
end
|
144
159
|
end
|
145
160
|
end
|
146
161
|
|
@@ -148,10 +163,85 @@ module GraphQL
|
|
148
163
|
raise(GraphQL::RequiredImplementationMissingError, "Generated Schema cannot use Interface or Union types for execution. Implement resolve_type on your resolver.")
|
149
164
|
}
|
150
165
|
|
166
|
+
def build_definition_from_node(definition, type_resolver, default_resolve)
|
167
|
+
case definition
|
168
|
+
when GraphQL::Language::Nodes::EnumTypeDefinition
|
169
|
+
build_enum_type(definition, type_resolver)
|
170
|
+
when GraphQL::Language::Nodes::ObjectTypeDefinition
|
171
|
+
build_object_type(definition, type_resolver)
|
172
|
+
when GraphQL::Language::Nodes::InterfaceTypeDefinition
|
173
|
+
build_interface_type(definition, type_resolver)
|
174
|
+
when GraphQL::Language::Nodes::UnionTypeDefinition
|
175
|
+
build_union_type(definition, type_resolver)
|
176
|
+
when GraphQL::Language::Nodes::ScalarTypeDefinition
|
177
|
+
build_scalar_type(definition, type_resolver, default_resolve: default_resolve)
|
178
|
+
when GraphQL::Language::Nodes::InputObjectTypeDefinition
|
179
|
+
build_input_object_type(definition, type_resolver)
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
# Modify `types`, replacing any late-bound references to built-in types
|
184
|
+
# with their actual definitions.
|
185
|
+
#
|
186
|
+
# (Schema definitions are allowed to reference those built-ins without redefining them.)
|
187
|
+
# @return void
|
188
|
+
def replace_late_bound_types_with_built_in(types)
|
189
|
+
GraphQL::Schema::BUILT_IN_TYPES.each do |scalar_name, built_in_scalar|
|
190
|
+
existing_type = types[scalar_name]
|
191
|
+
if existing_type.is_a?(GraphQL::Schema::LateBoundType)
|
192
|
+
types[scalar_name] = built_in_scalar
|
193
|
+
end
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
def build_directives(definition, ast_node, type_resolver)
|
198
|
+
dirs = prepare_directives(ast_node, type_resolver)
|
199
|
+
dirs.each do |dir_class, options|
|
200
|
+
definition.directive(dir_class, **options)
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
def prepare_directives(ast_node, type_resolver)
|
205
|
+
dirs = {}
|
206
|
+
ast_node.directives.each do |dir_node|
|
207
|
+
if dir_node.name == "deprecated"
|
208
|
+
# This is handled using `deprecation_reason`
|
209
|
+
next
|
210
|
+
else
|
211
|
+
dir_class = type_resolver.call(dir_node.name)
|
212
|
+
if dir_class.nil?
|
213
|
+
raise ArgumentError, "No definition for @#{dir_node.name} on #{ast_node.name} at #{ast_node.line}:#{ast_node.col}"
|
214
|
+
end
|
215
|
+
options = args_to_kwargs(dir_class, dir_node)
|
216
|
+
dirs[dir_class] = options
|
217
|
+
end
|
218
|
+
end
|
219
|
+
dirs
|
220
|
+
end
|
221
|
+
|
222
|
+
def args_to_kwargs(arg_owner, node)
|
223
|
+
if node.respond_to?(:arguments)
|
224
|
+
kwargs = {}
|
225
|
+
node.arguments.each do |arg_node|
|
226
|
+
arg_defn = arg_owner.get_argument(arg_node.name)
|
227
|
+
kwargs[arg_defn.keyword] = args_to_kwargs(arg_defn.type.unwrap, arg_node.value)
|
228
|
+
end
|
229
|
+
kwargs
|
230
|
+
elsif node.is_a?(Array)
|
231
|
+
node.map { |n| args_to_kwargs(arg_owner, n) }
|
232
|
+
elsif node.is_a?(Language::Nodes::Enum)
|
233
|
+
node.name
|
234
|
+
else
|
235
|
+
# scalar
|
236
|
+
node
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
151
240
|
def build_enum_type(enum_type_definition, type_resolver)
|
152
241
|
builder = self
|
153
242
|
Class.new(GraphQL::Schema::Enum) do
|
154
243
|
graphql_name(enum_type_definition.name)
|
244
|
+
builder.build_directives(self, enum_type_definition, type_resolver)
|
155
245
|
description(enum_type_definition.description)
|
156
246
|
ast_node(enum_type_definition)
|
157
247
|
enum_type_definition.values.each do |enum_value_definition|
|
@@ -159,6 +249,7 @@ module GraphQL
|
|
159
249
|
value: enum_value_definition.name,
|
160
250
|
deprecation_reason: builder.build_deprecation_reason(enum_value_definition.directives),
|
161
251
|
description: enum_value_definition.description,
|
252
|
+
directives: builder.prepare_directives(enum_value_definition, type_resolver),
|
162
253
|
ast_node: enum_value_definition,
|
163
254
|
)
|
164
255
|
end
|
@@ -176,49 +267,54 @@ module GraphQL
|
|
176
267
|
end
|
177
268
|
|
178
269
|
def build_scalar_type(scalar_type_definition, type_resolver, default_resolve:)
|
270
|
+
builder = self
|
179
271
|
Class.new(GraphQL::Schema::Scalar) do
|
180
272
|
graphql_name(scalar_type_definition.name)
|
181
273
|
description(scalar_type_definition.description)
|
182
274
|
ast_node(scalar_type_definition)
|
275
|
+
builder.build_directives(self, scalar_type_definition, type_resolver)
|
183
276
|
|
184
277
|
if default_resolve.respond_to?(:coerce_input)
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
define_singleton_method(:coerce_result) do |val, ctx|
|
190
|
-
default_resolve.coerce_result(self, val, ctx)
|
191
|
-
end
|
278
|
+
# Put these method definitions in another method to avoid retaining `type_resolve`
|
279
|
+
# from this method's bindiing
|
280
|
+
builder.build_scalar_type_coerce_method(self, :coerce_input, default_resolve)
|
281
|
+
builder.build_scalar_type_coerce_method(self, :coerce_result, default_resolve)
|
192
282
|
end
|
193
283
|
end
|
194
284
|
end
|
195
285
|
|
286
|
+
def build_scalar_type_coerce_method(scalar_class, method_name, default_definition_resolve)
|
287
|
+
scalar_class.define_singleton_method(method_name) do |val, ctx|
|
288
|
+
default_definition_resolve.public_send(method_name, self, val, ctx)
|
289
|
+
end
|
290
|
+
end
|
291
|
+
|
196
292
|
def build_union_type(union_type_definition, type_resolver)
|
293
|
+
builder = self
|
197
294
|
Class.new(GraphQL::Schema::Union) do
|
198
295
|
graphql_name(union_type_definition.name)
|
199
296
|
description(union_type_definition.description)
|
200
297
|
possible_types(*union_type_definition.types.map { |type_name| type_resolver.call(type_name) })
|
201
298
|
ast_node(union_type_definition)
|
299
|
+
builder.build_directives(self, union_type_definition, type_resolver)
|
202
300
|
end
|
203
301
|
end
|
204
302
|
|
205
|
-
def build_object_type(object_type_definition, type_resolver
|
303
|
+
def build_object_type(object_type_definition, type_resolver)
|
206
304
|
builder = self
|
207
|
-
type_def = nil
|
208
|
-
typed_resolve_fn = ->(field, obj, args, ctx) { default_resolve.call(type_def, field, obj, args, ctx) }
|
209
305
|
|
210
306
|
Class.new(GraphQL::Schema::Object) do
|
211
|
-
type_def = self
|
212
307
|
graphql_name(object_type_definition.name)
|
213
308
|
description(object_type_definition.description)
|
214
309
|
ast_node(object_type_definition)
|
310
|
+
builder.build_directives(self, object_type_definition, type_resolver)
|
215
311
|
|
216
312
|
object_type_definition.interfaces.each do |interface_name|
|
217
313
|
interface_defn = type_resolver.call(interface_name)
|
218
314
|
implements(interface_defn)
|
219
315
|
end
|
220
316
|
|
221
|
-
builder.build_fields(self, object_type_definition.fields, type_resolver, default_resolve:
|
317
|
+
builder.build_fields(self, object_type_definition.fields, type_resolver, default_resolve: true)
|
222
318
|
end
|
223
319
|
end
|
224
320
|
|
@@ -228,6 +324,7 @@ module GraphQL
|
|
228
324
|
graphql_name(input_object_type_definition.name)
|
229
325
|
description(input_object_type_definition.description)
|
230
326
|
ast_node(input_object_type_definition)
|
327
|
+
builder.build_directives(self, input_object_type_definition, type_resolver)
|
231
328
|
builder.build_arguments(self, input_object_type_definition.fields, type_resolver)
|
232
329
|
end
|
233
330
|
end
|
@@ -247,13 +344,16 @@ module GraphQL
|
|
247
344
|
end
|
248
345
|
end
|
249
346
|
|
347
|
+
NO_DEFAULT_VALUE = {}.freeze
|
348
|
+
|
250
349
|
def build_arguments(type_class, arguments, type_resolver)
|
251
350
|
builder = self
|
252
351
|
|
253
352
|
arguments.each do |argument_defn|
|
254
|
-
default_value_kwargs =
|
255
|
-
|
256
|
-
|
353
|
+
default_value_kwargs = if !argument_defn.default_value.nil?
|
354
|
+
{ default_value: builder.build_default_value(argument_defn.default_value) }
|
355
|
+
else
|
356
|
+
NO_DEFAULT_VALUE
|
257
357
|
end
|
258
358
|
|
259
359
|
type_class.argument(
|
@@ -261,9 +361,11 @@ module GraphQL
|
|
261
361
|
type: type_resolver.call(argument_defn.type),
|
262
362
|
required: false,
|
263
363
|
description: argument_defn.description,
|
364
|
+
deprecation_reason: builder.build_deprecation_reason(argument_defn.directives),
|
264
365
|
ast_node: argument_defn,
|
265
366
|
camelize: false,
|
266
367
|
method_access: false,
|
368
|
+
directives: prepare_directives(argument_defn, type_resolver),
|
267
369
|
**default_value_kwargs
|
268
370
|
)
|
269
371
|
end
|
@@ -287,6 +389,7 @@ module GraphQL
|
|
287
389
|
graphql_name(interface_type_definition.name)
|
288
390
|
description(interface_type_definition.description)
|
289
391
|
ast_node(interface_type_definition)
|
392
|
+
builder.build_directives(self, interface_type_definition, type_resolver)
|
290
393
|
|
291
394
|
builder.build_fields(self, interface_type_definition.fields, type_resolver, default_resolve: nil)
|
292
395
|
end
|
@@ -295,10 +398,10 @@ module GraphQL
|
|
295
398
|
def build_fields(owner, field_definitions, type_resolver, default_resolve:)
|
296
399
|
builder = self
|
297
400
|
|
298
|
-
field_definitions.
|
401
|
+
field_definitions.each do |field_definition|
|
299
402
|
type_name = resolve_type_name(field_definition.type)
|
300
|
-
resolve_method_name = "resolve_field_#{field_definition.name}"
|
301
|
-
owner.field(
|
403
|
+
resolve_method_name = -"resolve_field_#{field_definition.name}"
|
404
|
+
schema_field_defn = owner.field(
|
302
405
|
field_definition.name,
|
303
406
|
description: field_definition.description,
|
304
407
|
type: type_resolver.call(field_definition.type),
|
@@ -309,33 +412,47 @@ module GraphQL
|
|
309
412
|
ast_node: field_definition,
|
310
413
|
method_conflict_warning: false,
|
311
414
|
camelize: false,
|
415
|
+
directives: prepare_directives(field_definition, type_resolver),
|
312
416
|
resolver_method: resolve_method_name,
|
313
|
-
)
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
417
|
+
)
|
418
|
+
|
419
|
+
builder.build_arguments(schema_field_defn, field_definition.arguments, type_resolver)
|
420
|
+
|
421
|
+
# Don't do this for interfaces
|
422
|
+
if default_resolve
|
423
|
+
owner.class_eval <<-RUBY, __FILE__, __LINE__
|
424
|
+
# frozen_string_literal: true
|
425
|
+
def #{resolve_method_name}(**args)
|
426
|
+
field_instance = self.class.get_field("#{field_definition.name}")
|
427
|
+
context.schema.definition_default_resolve.call(self.class, field_instance, object, args, context)
|
321
428
|
end
|
322
|
-
|
429
|
+
RUBY
|
323
430
|
end
|
324
431
|
end
|
325
432
|
end
|
326
433
|
|
327
|
-
def
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
434
|
+
def build_resolve_type(lookup_hash, directives, missing_type_handler)
|
435
|
+
resolve_type_proc = nil
|
436
|
+
resolve_type_proc = ->(ast_node) {
|
437
|
+
case ast_node
|
438
|
+
when GraphQL::Language::Nodes::TypeName
|
439
|
+
type_name = ast_node.name
|
440
|
+
if lookup_hash.key?(type_name)
|
441
|
+
lookup_hash[type_name]
|
442
|
+
else
|
443
|
+
missing_type_handler.call(type_name)
|
444
|
+
end
|
445
|
+
when GraphQL::Language::Nodes::NonNullType
|
446
|
+
resolve_type_proc.call(ast_node.of_type).to_non_null_type
|
447
|
+
when GraphQL::Language::Nodes::ListType
|
448
|
+
resolve_type_proc.call(ast_node.of_type).to_list_type
|
449
|
+
when String
|
450
|
+
directives[ast_node]
|
451
|
+
else
|
452
|
+
raise "Unexpected ast_node: #{ast_node.inspect}"
|
453
|
+
end
|
454
|
+
}
|
455
|
+
resolve_type_proc
|
339
456
|
end
|
340
457
|
|
341
458
|
def resolve_type_name(type)
|