graphql 1.11.12 → 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/install_generator.rb +5 -5
- data/lib/generators/graphql/relay_generator.rb +63 -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/node_type.erb +9 -0
- data/lib/generators/graphql/templates/object.erb +1 -1
- data/lib/generators/graphql/templates/query_type.erb +1 -3
- data/lib/generators/graphql/templates/schema.erb +8 -35
- data/lib/graphql/analysis/analyze_query.rb +7 -0
- data/lib/graphql/analysis/ast/visitor.rb +9 -1
- data/lib/graphql/analysis/ast.rb +11 -2
- data/lib/graphql/backtrace/legacy_tracer.rb +56 -0
- data/lib/graphql/backtrace/table.rb +22 -2
- data/lib/graphql/backtrace/tracer.rb +40 -9
- data/lib/graphql/backtrace.rb +28 -19
- 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/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/dataloader.rb +197 -0
- data/lib/graphql/define/assign_global_id_field.rb +1 -1
- 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/arguments.rb +51 -14
- data/lib/graphql/execution/interpreter/handles_raw_value.rb +0 -7
- data/lib/graphql/execution/interpreter/runtime.rb +210 -124
- data/lib/graphql/execution/interpreter.rb +10 -6
- 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/interface_type.rb +3 -1
- data/lib/graphql/language/document_from_schema_definition.rb +50 -23
- data/lib/graphql/language/nodes.rb +0 -5
- data/lib/graphql/language/visitor.rb +0 -1
- data/lib/graphql/object_type.rb +2 -0
- data/lib/graphql/pagination/connection.rb +5 -1
- data/lib/graphql/pagination/connections.rb +6 -16
- data/lib/graphql/query/context.rb +4 -0
- data/lib/graphql/query/serial_execution.rb +1 -0
- data/lib/graphql/query/validation_pipeline.rb +1 -1
- data/lib/graphql/query.rb +2 -0
- 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/type_extensions.rb +2 -0
- data/lib/graphql/scalar_type.rb +2 -0
- data/lib/graphql/schema/argument.rb +30 -10
- data/lib/graphql/schema/build_from_definition.rb +145 -58
- data/lib/graphql/schema/directive/flagged.rb +57 -0
- data/lib/graphql/schema/directive.rb +76 -0
- data/lib/graphql/schema/enum.rb +3 -0
- data/lib/graphql/schema/enum_value.rb +13 -7
- data/lib/graphql/schema/field/connection_extension.rb +3 -2
- data/lib/graphql/schema/field.rb +28 -10
- data/lib/graphql/schema/input_object.rb +36 -28
- data/lib/graphql/schema/interface.rb +1 -0
- data/lib/graphql/schema/member/base_dsl_methods.rb +1 -0
- data/lib/graphql/schema/member/build_type.rb +3 -3
- data/lib/graphql/schema/member/has_arguments.rb +24 -6
- 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_validators.rb +31 -0
- data/lib/graphql/schema/member/type_system_helpers.rb +1 -1
- data/lib/graphql/schema/member.rb +4 -0
- data/lib/graphql/schema/object.rb +11 -0
- data/lib/graphql/schema/printer.rb +5 -4
- data/lib/graphql/schema/resolver/has_payload_type.rb +2 -0
- data/lib/graphql/schema/resolver.rb +7 -0
- data/lib/graphql/schema/subscription.rb +19 -1
- data/lib/graphql/schema/timeout_middleware.rb +2 -0
- data/lib/graphql/schema/validation.rb +2 -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/validator.rb +163 -0
- data/lib/graphql/schema.rb +72 -49
- data/lib/graphql/static_validation/base_visitor.rb +0 -3
- data/lib/graphql/static_validation/rules/fields_will_merge.rb +4 -4
- data/lib/graphql/static_validation/rules/fragments_are_finite.rb +2 -2
- data/lib/graphql/static_validation/validation_context.rb +1 -6
- data/lib/graphql/static_validation/validator.rb +12 -14
- data/lib/graphql/subscriptions.rb +17 -20
- data/lib/graphql/tracing/appoptics_tracing.rb +3 -1
- data/lib/graphql/tracing/platform_tracing.rb +3 -1
- data/lib/graphql/tracing/skylight_tracing.rb +1 -1
- data/lib/graphql/tracing.rb +2 -2
- data/lib/graphql/types/relay/base_connection.rb +2 -92
- data/lib/graphql/types/relay/base_edge.rb +2 -35
- 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/relay.rb +11 -3
- 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/lib/graphql.rb +38 -4
- metadata +34 -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
@@ -3,6 +3,7 @@ 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
|
7
8
|
if !String.method_defined?(:-@)
|
8
9
|
using GraphQL::StringDedupBackport
|
@@ -18,8 +19,8 @@ module GraphQL
|
|
18
19
|
from_document(parser.parse_file(definition_path), **kwargs)
|
19
20
|
end
|
20
21
|
|
21
|
-
def from_document(document, default_resolve:, using: {}, relay: false
|
22
|
-
Builder.build(document, default_resolve: default_resolve || {}, relay: relay, using: using
|
22
|
+
def from_document(document, default_resolve:, using: {}, relay: false)
|
23
|
+
Builder.build(document, default_resolve: default_resolve || {}, relay: relay, using: using)
|
23
24
|
end
|
24
25
|
end
|
25
26
|
|
@@ -27,7 +28,7 @@ module GraphQL
|
|
27
28
|
module Builder
|
28
29
|
extend self
|
29
30
|
|
30
|
-
def build(document, default_resolve:, using: {},
|
31
|
+
def build(document, default_resolve:, using: {}, relay:)
|
31
32
|
raise InvalidDocumentError.new('Must provide a document ast.') if !document || !document.is_a?(GraphQL::Language::Nodes::Document)
|
32
33
|
|
33
34
|
if default_resolve.is_a?(Hash)
|
@@ -41,45 +42,43 @@ module GraphQL
|
|
41
42
|
schema_definition = schema_defns.first
|
42
43
|
types = {}
|
43
44
|
directives = {}
|
44
|
-
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
|
+
})
|
45
56
|
|
46
57
|
document.definitions.each do |definition|
|
47
|
-
|
48
|
-
|
49
|
-
nil # already handled
|
50
|
-
when GraphQL::Language::Nodes::EnumTypeDefinition
|
51
|
-
types[definition.name] = build_enum_type(definition, type_resolver)
|
52
|
-
when GraphQL::Language::Nodes::ObjectTypeDefinition
|
53
|
-
types[definition.name] = build_object_type(definition, type_resolver)
|
54
|
-
when GraphQL::Language::Nodes::InterfaceTypeDefinition
|
55
|
-
types[definition.name] = build_interface_type(definition, type_resolver)
|
56
|
-
when GraphQL::Language::Nodes::UnionTypeDefinition
|
57
|
-
types[definition.name] = build_union_type(definition, type_resolver)
|
58
|
-
when GraphQL::Language::Nodes::ScalarTypeDefinition
|
59
|
-
types[definition.name] = build_scalar_type(definition, type_resolver, default_resolve: default_resolve)
|
60
|
-
when GraphQL::Language::Nodes::InputObjectTypeDefinition
|
61
|
-
types[definition.name] = build_input_object_type(definition, type_resolver)
|
62
|
-
when GraphQL::Language::Nodes::DirectiveDefinition
|
63
|
-
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)
|
64
60
|
end
|
65
61
|
end
|
66
62
|
|
67
|
-
|
68
|
-
|
69
|
-
#
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
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
|
79
78
|
end
|
80
79
|
end
|
81
80
|
|
82
|
-
|
81
|
+
replace_late_bound_types_with_built_in(types)
|
83
82
|
|
84
83
|
if schema_definition
|
85
84
|
if schema_definition.query
|
@@ -133,11 +132,6 @@ module GraphQL
|
|
133
132
|
ast_node(schema_definition)
|
134
133
|
end
|
135
134
|
|
136
|
-
if interpreter
|
137
|
-
use GraphQL::Execution::Interpreter
|
138
|
-
use GraphQL::Analysis::AST
|
139
|
-
end
|
140
|
-
|
141
135
|
using.each do |plugin, options|
|
142
136
|
if options
|
143
137
|
use(plugin, **options)
|
@@ -169,10 +163,85 @@ module GraphQL
|
|
169
163
|
raise(GraphQL::RequiredImplementationMissingError, "Generated Schema cannot use Interface or Union types for execution. Implement resolve_type on your resolver.")
|
170
164
|
}
|
171
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
|
+
|
172
240
|
def build_enum_type(enum_type_definition, type_resolver)
|
173
241
|
builder = self
|
174
242
|
Class.new(GraphQL::Schema::Enum) do
|
175
243
|
graphql_name(enum_type_definition.name)
|
244
|
+
builder.build_directives(self, enum_type_definition, type_resolver)
|
176
245
|
description(enum_type_definition.description)
|
177
246
|
ast_node(enum_type_definition)
|
178
247
|
enum_type_definition.values.each do |enum_value_definition|
|
@@ -180,6 +249,7 @@ module GraphQL
|
|
180
249
|
value: enum_value_definition.name,
|
181
250
|
deprecation_reason: builder.build_deprecation_reason(enum_value_definition.directives),
|
182
251
|
description: enum_value_definition.description,
|
252
|
+
directives: builder.prepare_directives(enum_value_definition, type_resolver),
|
183
253
|
ast_node: enum_value_definition,
|
184
254
|
)
|
185
255
|
end
|
@@ -202,6 +272,7 @@ module GraphQL
|
|
202
272
|
graphql_name(scalar_type_definition.name)
|
203
273
|
description(scalar_type_definition.description)
|
204
274
|
ast_node(scalar_type_definition)
|
275
|
+
builder.build_directives(self, scalar_type_definition, type_resolver)
|
205
276
|
|
206
277
|
if default_resolve.respond_to?(:coerce_input)
|
207
278
|
# Put these method definitions in another method to avoid retaining `type_resolve`
|
@@ -219,11 +290,13 @@ module GraphQL
|
|
219
290
|
end
|
220
291
|
|
221
292
|
def build_union_type(union_type_definition, type_resolver)
|
293
|
+
builder = self
|
222
294
|
Class.new(GraphQL::Schema::Union) do
|
223
295
|
graphql_name(union_type_definition.name)
|
224
296
|
description(union_type_definition.description)
|
225
297
|
possible_types(*union_type_definition.types.map { |type_name| type_resolver.call(type_name) })
|
226
298
|
ast_node(union_type_definition)
|
299
|
+
builder.build_directives(self, union_type_definition, type_resolver)
|
227
300
|
end
|
228
301
|
end
|
229
302
|
|
@@ -234,6 +307,7 @@ module GraphQL
|
|
234
307
|
graphql_name(object_type_definition.name)
|
235
308
|
description(object_type_definition.description)
|
236
309
|
ast_node(object_type_definition)
|
310
|
+
builder.build_directives(self, object_type_definition, type_resolver)
|
237
311
|
|
238
312
|
object_type_definition.interfaces.each do |interface_name|
|
239
313
|
interface_defn = type_resolver.call(interface_name)
|
@@ -250,6 +324,7 @@ module GraphQL
|
|
250
324
|
graphql_name(input_object_type_definition.name)
|
251
325
|
description(input_object_type_definition.description)
|
252
326
|
ast_node(input_object_type_definition)
|
327
|
+
builder.build_directives(self, input_object_type_definition, type_resolver)
|
253
328
|
builder.build_arguments(self, input_object_type_definition.fields, type_resolver)
|
254
329
|
end
|
255
330
|
end
|
@@ -290,6 +365,7 @@ module GraphQL
|
|
290
365
|
ast_node: argument_defn,
|
291
366
|
camelize: false,
|
292
367
|
method_access: false,
|
368
|
+
directives: prepare_directives(argument_defn, type_resolver),
|
293
369
|
**default_value_kwargs
|
294
370
|
)
|
295
371
|
end
|
@@ -313,6 +389,7 @@ module GraphQL
|
|
313
389
|
graphql_name(interface_type_definition.name)
|
314
390
|
description(interface_type_definition.description)
|
315
391
|
ast_node(interface_type_definition)
|
392
|
+
builder.build_directives(self, interface_type_definition, type_resolver)
|
316
393
|
|
317
394
|
builder.build_fields(self, interface_type_definition.fields, type_resolver, default_resolve: nil)
|
318
395
|
end
|
@@ -335,6 +412,7 @@ module GraphQL
|
|
335
412
|
ast_node: field_definition,
|
336
413
|
method_conflict_warning: false,
|
337
414
|
camelize: false,
|
415
|
+
directives: prepare_directives(field_definition, type_resolver),
|
338
416
|
resolver_method: resolve_method_name,
|
339
417
|
)
|
340
418
|
|
@@ -342,30 +420,39 @@ module GraphQL
|
|
342
420
|
|
343
421
|
# Don't do this for interfaces
|
344
422
|
if default_resolve
|
345
|
-
|
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)
|
428
|
+
end
|
429
|
+
RUBY
|
346
430
|
end
|
347
431
|
end
|
348
432
|
end
|
349
433
|
|
350
|
-
def
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
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
|
368
454
|
}
|
455
|
+
resolve_type_proc
|
369
456
|
end
|
370
457
|
|
371
458
|
def resolve_type_name(type)
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module GraphQL
|
3
|
+
class Schema
|
4
|
+
class Directive < GraphQL::Schema::Member
|
5
|
+
# This is _similar_ to {Directive::Feature}, except it's prescribed by the server, not the client.
|
6
|
+
#
|
7
|
+
# In this case, the server hides types and fields _entirely_, unless the current context has certain `:flags` present.
|
8
|
+
class Flagged < GraphQL::Schema::Directive
|
9
|
+
def initialize(target, **options)
|
10
|
+
if target.is_a?(Module) && !target.ancestors.include?(VisibleByFlag)
|
11
|
+
# This is type class of some kind, `include` will put this module
|
12
|
+
# in between the type class itself and its super class, so `super` will work fine
|
13
|
+
target.include(VisibleByFlag)
|
14
|
+
elsif !target.is_a?(VisibleByFlag)
|
15
|
+
# This is an instance of a base class. `include` won't put this in front of the
|
16
|
+
# base class implementation, so we need to `.prepend`.
|
17
|
+
# `#visible?` could probably be moved to a module and then this could use `include` instead.
|
18
|
+
target.class.prepend(VisibleByFlag)
|
19
|
+
end
|
20
|
+
super
|
21
|
+
end
|
22
|
+
|
23
|
+
description "Hides this part of the schema unless the named flag is present in context[:flags]"
|
24
|
+
|
25
|
+
locations(
|
26
|
+
GraphQL::Schema::Directive::FIELD_DEFINITION,
|
27
|
+
GraphQL::Schema::Directive::OBJECT,
|
28
|
+
GraphQL::Schema::Directive::SCALAR,
|
29
|
+
GraphQL::Schema::Directive::ENUM,
|
30
|
+
GraphQL::Schema::Directive::UNION,
|
31
|
+
GraphQL::Schema::Directive::INTERFACE,
|
32
|
+
GraphQL::Schema::Directive::INPUT_OBJECT,
|
33
|
+
GraphQL::Schema::Directive::ENUM_VALUE,
|
34
|
+
GraphQL::Schema::Directive::ARGUMENT_DEFINITION,
|
35
|
+
GraphQL::Schema::Directive::INPUT_FIELD_DEFINITION,
|
36
|
+
)
|
37
|
+
|
38
|
+
argument :by, [String], "Flags to check for this schema member", required: true
|
39
|
+
|
40
|
+
module VisibleByFlag
|
41
|
+
def self.included(schema_class)
|
42
|
+
schema_class.extend(self)
|
43
|
+
end
|
44
|
+
|
45
|
+
def visible?(context)
|
46
|
+
if dir = self.directives.find { |d| d.is_a?(Flagged) }
|
47
|
+
relevant_flags = (f = context[:flags]) && dir.arguments[:by] & f
|
48
|
+
relevant_flags && relevant_flags.any? && super
|
49
|
+
else
|
50
|
+
super
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -9,6 +9,13 @@ module GraphQL
|
|
9
9
|
class Directive < GraphQL::Schema::Member
|
10
10
|
extend GraphQL::Schema::Member::HasArguments
|
11
11
|
class << self
|
12
|
+
# Directives aren't types, they don't have kinds.
|
13
|
+
undef_method :kind
|
14
|
+
|
15
|
+
def path
|
16
|
+
"@#{super}"
|
17
|
+
end
|
18
|
+
|
12
19
|
# Return a name based on the class name,
|
13
20
|
# but downcase the first letter.
|
14
21
|
def default_graphql_name
|
@@ -21,6 +28,11 @@ module GraphQL
|
|
21
28
|
|
22
29
|
def locations(*new_locations)
|
23
30
|
if new_locations.any?
|
31
|
+
new_locations.each do |new_loc|
|
32
|
+
if !LOCATIONS.include?(new_loc.to_sym)
|
33
|
+
raise ArgumentError, "#{self} (#{self.graphql_name}) has an invalid directive location: `locations #{new_loc}` "
|
34
|
+
end
|
35
|
+
end
|
24
36
|
@locations = new_locations
|
25
37
|
else
|
26
38
|
@locations ||= (superclass.respond_to?(:locations) ? superclass.locations : [])
|
@@ -87,6 +99,23 @@ module GraphQL
|
|
87
99
|
end
|
88
100
|
end
|
89
101
|
|
102
|
+
# @return [GraphQL::Schema::Field, GraphQL::Schema::Argument, Class, Module]
|
103
|
+
attr_reader :owner
|
104
|
+
|
105
|
+
# @return [GraphQL::Interpreter::Arguments]
|
106
|
+
attr_reader :arguments
|
107
|
+
|
108
|
+
def initialize(owner, **arguments)
|
109
|
+
@owner = owner
|
110
|
+
assert_valid_owner
|
111
|
+
# It's be nice if we had the real context here, but we don't. What we _would_ get is:
|
112
|
+
# - error handling
|
113
|
+
# - lazy resolution
|
114
|
+
# Probably, those won't be needed here, since these are configuration arguments,
|
115
|
+
# not runtime arguments.
|
116
|
+
@arguments = self.class.coerce_arguments(nil, arguments, Query::NullContext)
|
117
|
+
end
|
118
|
+
|
90
119
|
LOCATIONS = [
|
91
120
|
QUERY = :QUERY,
|
92
121
|
MUTATION = :MUTATION,
|
@@ -129,6 +158,53 @@ module GraphQL
|
|
129
158
|
INPUT_OBJECT: 'Location adjacent to an input object type definition.',
|
130
159
|
INPUT_FIELD_DEFINITION: 'Location adjacent to an input object field definition.',
|
131
160
|
}
|
161
|
+
|
162
|
+
private
|
163
|
+
|
164
|
+
def assert_valid_owner
|
165
|
+
case @owner
|
166
|
+
when Class
|
167
|
+
if @owner < GraphQL::Schema::Object
|
168
|
+
assert_has_location(OBJECT)
|
169
|
+
elsif @owner < GraphQL::Schema::Union
|
170
|
+
assert_has_location(UNION)
|
171
|
+
elsif @owner < GraphQL::Schema::Enum
|
172
|
+
assert_has_location(ENUM)
|
173
|
+
elsif @owner < GraphQL::Schema::InputObject
|
174
|
+
assert_has_location(INPUT_OBJECT)
|
175
|
+
elsif @owner < GraphQL::Schema::Scalar
|
176
|
+
assert_has_location(SCALAR)
|
177
|
+
elsif @owner < GraphQL::Schema
|
178
|
+
assert_has_location(SCHEMA)
|
179
|
+
else
|
180
|
+
raise "Unexpected directive owner class: #{@owner}"
|
181
|
+
end
|
182
|
+
when Module
|
183
|
+
assert_has_location(INTERFACE)
|
184
|
+
when GraphQL::Schema::Argument
|
185
|
+
if @owner.owner.is_a?(GraphQL::Schema::Field)
|
186
|
+
assert_has_location(ARGUMENT_DEFINITION)
|
187
|
+
else
|
188
|
+
assert_has_location(INPUT_FIELD_DEFINITION)
|
189
|
+
end
|
190
|
+
when GraphQL::Schema::Field
|
191
|
+
assert_has_location(FIELD_DEFINITION)
|
192
|
+
when GraphQL::Schema::EnumValue
|
193
|
+
assert_has_location(ENUM_VALUE)
|
194
|
+
else
|
195
|
+
raise "Unexpected directive owner: #{@owner.inspect}"
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
def assert_has_location(location)
|
200
|
+
if !self.class.locations.include?(location)
|
201
|
+
raise ArgumentError, <<-MD
|
202
|
+
Directive `@#{self.class.graphql_name}` can't be attached to #{@owner.graphql_name} because #{location} isn't included in its locations (#{self.class.locations.join(", ")}).
|
203
|
+
|
204
|
+
Use `locations(#{location})` to update this directive's definition, or remove it from #{@owner.graphql_name}.
|
205
|
+
MD
|
206
|
+
end
|
207
|
+
end
|
132
208
|
end
|
133
209
|
end
|
134
210
|
end
|
data/lib/graphql/schema/enum.rb
CHANGED
@@ -37,6 +37,9 @@ module GraphQL
|
|
37
37
|
def value(*args, **kwargs, &block)
|
38
38
|
kwargs[:owner] = self
|
39
39
|
value = enum_value_class.new(*args, **kwargs, &block)
|
40
|
+
if own_values.key?(value.graphql_name)
|
41
|
+
raise ArgumentError, "#{value.graphql_name} is already defined for #{self.graphql_name}, please remove one of the definitions."
|
42
|
+
end
|
40
43
|
own_values[value.graphql_name] = value
|
41
44
|
nil
|
42
45
|
end
|
@@ -30,26 +30,32 @@ module GraphQL
|
|
30
30
|
include GraphQL::Schema::Member::AcceptsDefinition
|
31
31
|
include GraphQL::Schema::Member::HasPath
|
32
32
|
include GraphQL::Schema::Member::HasAstNode
|
33
|
+
include GraphQL::Schema::Member::HasDirectives
|
34
|
+
include GraphQL::Schema::Member::HasDeprecationReason
|
33
35
|
|
34
36
|
attr_reader :graphql_name
|
35
37
|
|
36
38
|
# @return [Class] The enum type that owns this value
|
37
39
|
attr_reader :owner
|
38
40
|
|
39
|
-
|
40
|
-
attr_accessor :deprecation_reason
|
41
|
-
|
42
|
-
def initialize(graphql_name, desc = nil, owner:, ast_node: nil, description: nil, value: nil, deprecation_reason: nil, &block)
|
41
|
+
def initialize(graphql_name, desc = nil, owner:, ast_node: nil, directives: nil, description: nil, value: nil, deprecation_reason: nil, &block)
|
43
42
|
@graphql_name = graphql_name.to_s
|
44
43
|
GraphQL::NameValidator.validate!(@graphql_name)
|
45
44
|
@description = desc || description
|
46
45
|
@value = value.nil? ? @graphql_name : value
|
47
|
-
|
46
|
+
if deprecation_reason
|
47
|
+
self.deprecation_reason = deprecation_reason
|
48
|
+
end
|
48
49
|
@owner = owner
|
49
50
|
@ast_node = ast_node
|
51
|
+
if directives
|
52
|
+
directives.each do |dir_class, dir_options|
|
53
|
+
directive(dir_class, **dir_options)
|
54
|
+
end
|
55
|
+
end
|
50
56
|
|
51
57
|
if block_given?
|
52
|
-
|
58
|
+
instance_eval(&block)
|
53
59
|
end
|
54
60
|
end
|
55
61
|
|
@@ -73,7 +79,7 @@ module GraphQL
|
|
73
79
|
enum_value.name = @graphql_name
|
74
80
|
enum_value.description = @description
|
75
81
|
enum_value.value = @value
|
76
|
-
enum_value.deprecation_reason =
|
82
|
+
enum_value.deprecation_reason = self.deprecation_reason
|
77
83
|
enum_value.metadata[:type_class] = self
|
78
84
|
enum_value.ast_node = ast_node
|
79
85
|
enum_value
|
@@ -42,6 +42,7 @@ module GraphQL
|
|
42
42
|
value.after_value ||= original_arguments[:after]
|
43
43
|
value.last_value ||= original_arguments[:last]
|
44
44
|
value.before_value ||= original_arguments[:before]
|
45
|
+
value.field ||= field
|
45
46
|
if field.has_max_page_size? && !value.has_max_page_size_override?
|
46
47
|
value.max_page_size = field.max_page_size
|
47
48
|
end
|
@@ -50,8 +51,8 @@ module GraphQL
|
|
50
51
|
end
|
51
52
|
value
|
52
53
|
elsif context.schema.new_connections?
|
53
|
-
|
54
|
-
context.schema.connections.wrap(field, object.object, value, original_arguments, context
|
54
|
+
context.namespace(:connections)[:all_wrappers] ||= context.schema.connections.all_wrappers
|
55
|
+
context.schema.connections.wrap(field, object.object, value, original_arguments, context)
|
55
56
|
else
|
56
57
|
if object.is_a?(GraphQL::Schema::Object)
|
57
58
|
object = object.object
|