graphql 2.3.7 → 2.4.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.
- checksums.yaml +4 -4
- data/lib/generators/graphql/install_generator.rb +46 -0
- data/lib/generators/graphql/orm_mutations_base.rb +1 -1
- data/lib/generators/graphql/templates/base_resolver.erb +2 -0
- data/lib/generators/graphql/type_generator.rb +1 -1
- data/lib/graphql/analysis/field_usage.rb +1 -1
- data/lib/graphql/analysis/query_complexity.rb +3 -3
- data/lib/graphql/analysis/visitor.rb +7 -6
- data/lib/graphql/analysis.rb +1 -1
- data/lib/graphql/current.rb +52 -0
- data/lib/graphql/dataloader/async_dataloader.rb +3 -2
- data/lib/graphql/dataloader/source.rb +6 -3
- data/lib/graphql/dataloader.rb +35 -11
- data/lib/graphql/execution/interpreter/arguments_cache.rb +5 -10
- data/lib/graphql/execution/interpreter/resolve.rb +10 -6
- data/lib/graphql/execution/interpreter/runtime.rb +29 -25
- data/lib/graphql/execution/interpreter.rb +2 -0
- data/lib/graphql/execution/lookahead.rb +10 -10
- data/lib/graphql/introspection/directive_type.rb +1 -1
- data/lib/graphql/introspection/entry_points.rb +2 -2
- data/lib/graphql/introspection/field_type.rb +1 -1
- data/lib/graphql/introspection/schema_type.rb +6 -11
- data/lib/graphql/introspection/type_type.rb +5 -5
- data/lib/graphql/invalid_null_error.rb +1 -1
- data/lib/graphql/language/comment.rb +18 -0
- data/lib/graphql/language/document_from_schema_definition.rb +55 -28
- data/lib/graphql/language/lexer.rb +15 -15
- data/lib/graphql/language/nodes.rb +24 -16
- data/lib/graphql/language/parser.rb +14 -1
- data/lib/graphql/language/printer.rb +23 -7
- data/lib/graphql/language/sanitized_printer.rb +1 -1
- data/lib/graphql/language.rb +6 -6
- data/lib/graphql/query/context.rb +7 -1
- data/lib/graphql/query/null_context.rb +2 -2
- data/lib/graphql/query.rb +60 -8
- data/lib/graphql/rubocop/graphql/field_type_in_block.rb +144 -0
- data/lib/graphql/rubocop/graphql/root_types_in_block.rb +38 -0
- data/lib/graphql/rubocop.rb +2 -0
- data/lib/graphql/schema/addition.rb +1 -0
- data/lib/graphql/schema/always_visible.rb +6 -2
- data/lib/graphql/schema/argument.rb +14 -1
- data/lib/graphql/schema/build_from_definition.rb +9 -1
- data/lib/graphql/schema/directive/flagged.rb +1 -1
- data/lib/graphql/schema/enum.rb +54 -20
- data/lib/graphql/schema/enum_value.rb +9 -1
- data/lib/graphql/schema/field/connection_extension.rb +1 -1
- data/lib/graphql/schema/field.rb +92 -37
- data/lib/graphql/schema/has_single_input_argument.rb +2 -1
- data/lib/graphql/schema/input_object.rb +27 -13
- data/lib/graphql/schema/interface.rb +21 -4
- data/lib/graphql/schema/introspection_system.rb +5 -16
- data/lib/graphql/schema/member/base_dsl_methods.rb +15 -0
- data/lib/graphql/schema/member/has_arguments.rb +14 -9
- data/lib/graphql/schema/member/has_fields.rb +8 -6
- data/lib/graphql/schema/member/has_unresolved_type_error.rb +5 -1
- data/lib/graphql/schema/printer.rb +1 -0
- data/lib/graphql/schema/resolver.rb +7 -9
- data/lib/graphql/schema/type_expression.rb +2 -2
- data/lib/graphql/schema/validator/all_validator.rb +62 -0
- data/lib/graphql/schema/validator/required_validator.rb +28 -4
- data/lib/graphql/schema/validator.rb +2 -0
- data/lib/graphql/schema/visibility/migration.rb +186 -0
- data/lib/graphql/schema/visibility/profile.rb +523 -0
- data/lib/graphql/schema/visibility.rb +75 -0
- data/lib/graphql/schema/warden.rb +156 -10
- data/lib/graphql/schema.rb +283 -85
- data/lib/graphql/static_validation/base_visitor.rb +6 -5
- data/lib/graphql/static_validation/literal_validator.rb +4 -4
- data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +1 -1
- data/lib/graphql/static_validation/rules/arguments_are_defined.rb +3 -2
- data/lib/graphql/static_validation/rules/directives_are_defined.rb +3 -3
- data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +2 -0
- data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +3 -2
- data/lib/graphql/static_validation/rules/fields_will_merge.rb +8 -7
- data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +3 -3
- data/lib/graphql/static_validation/rules/fragment_types_exist.rb +12 -2
- data/lib/graphql/static_validation/rules/fragments_are_on_composite_types.rb +1 -1
- data/lib/graphql/static_validation/rules/mutation_root_exists.rb +1 -1
- data/lib/graphql/static_validation/rules/query_root_exists.rb +1 -1
- data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +3 -3
- data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +3 -3
- data/lib/graphql/static_validation/rules/subscription_root_exists.rb +1 -1
- data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +18 -27
- data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +1 -1
- data/lib/graphql/static_validation/rules/variables_are_input_types.rb +11 -2
- data/lib/graphql/static_validation/validation_context.rb +17 -2
- data/lib/graphql/subscriptions/action_cable_subscriptions.rb +2 -1
- data/lib/graphql/subscriptions/broadcast_analyzer.rb +10 -4
- data/lib/graphql/subscriptions/event.rb +1 -1
- data/lib/graphql/subscriptions.rb +5 -3
- data/lib/graphql/testing/helpers.rb +9 -5
- data/lib/graphql/tracing/notifications_trace.rb +2 -2
- data/lib/graphql/types/relay/connection_behaviors.rb +10 -0
- data/lib/graphql/types/relay/edge_behaviors.rb +10 -0
- data/lib/graphql/types/relay/page_info_behaviors.rb +4 -0
- data/lib/graphql/unauthorized_enum_value_error.rb +13 -0
- data/lib/graphql/version.rb +1 -1
- data/lib/graphql.rb +3 -0
- metadata +29 -8
- data/lib/graphql/language/token.rb +0 -34
- data/lib/graphql/schema/invalid_type_error.rb +0 -7
data/lib/graphql/schema.rb
CHANGED
|
@@ -5,7 +5,6 @@ require "graphql/schema/always_visible"
|
|
|
5
5
|
require "graphql/schema/base_64_encoder"
|
|
6
6
|
require "graphql/schema/find_inherited_value"
|
|
7
7
|
require "graphql/schema/finder"
|
|
8
|
-
require "graphql/schema/invalid_type_error"
|
|
9
8
|
require "graphql/schema/introspection_system"
|
|
10
9
|
require "graphql/schema/late_bound_type"
|
|
11
10
|
require "graphql/schema/null_mask"
|
|
@@ -46,6 +45,7 @@ require "graphql/schema/mutation"
|
|
|
46
45
|
require "graphql/schema/has_single_input_argument"
|
|
47
46
|
require "graphql/schema/relay_classic_mutation"
|
|
48
47
|
require "graphql/schema/subscription"
|
|
48
|
+
require "graphql/schema/visibility"
|
|
49
49
|
|
|
50
50
|
module GraphQL
|
|
51
51
|
# A GraphQL schema which may be queried with {GraphQL::Query}.
|
|
@@ -162,6 +162,7 @@ module GraphQL
|
|
|
162
162
|
# re-apply them here
|
|
163
163
|
mods = trace_modules_for(:default)
|
|
164
164
|
mods.each { |mod| new_class.include(mod) }
|
|
165
|
+
new_class.include(DefaultTraceClass)
|
|
165
166
|
trace_mode(:default, new_class)
|
|
166
167
|
backtrace_class = Class.new(new_class)
|
|
167
168
|
backtrace_class.include(GraphQL::Backtrace::Trace)
|
|
@@ -204,24 +205,19 @@ module GraphQL
|
|
|
204
205
|
@own_trace_modes ||= {}
|
|
205
206
|
end
|
|
206
207
|
|
|
207
|
-
module DefaultTraceClass
|
|
208
|
-
end
|
|
209
|
-
|
|
210
|
-
private_constant :DefaultTraceClass
|
|
211
|
-
|
|
212
208
|
def build_trace_mode(mode)
|
|
213
209
|
case mode
|
|
214
210
|
when :default
|
|
215
211
|
# Use the superclass's default mode if it has one, or else start an inheritance chain at the built-in base class.
|
|
216
|
-
base_class = (superclass.respond_to?(:trace_class_for) && superclass.trace_class_for(mode)) || GraphQL::Tracing::Trace
|
|
217
|
-
Class.new(base_class) do
|
|
212
|
+
base_class = (superclass.respond_to?(:trace_class_for) && superclass.trace_class_for(mode, build: true)) || GraphQL::Tracing::Trace
|
|
213
|
+
const_set(:DefaultTrace, Class.new(base_class) do
|
|
218
214
|
include DefaultTraceClass
|
|
219
|
-
end
|
|
215
|
+
end)
|
|
220
216
|
when :default_backtrace
|
|
221
217
|
schema_base_class = trace_class_for(:default, build: true)
|
|
222
|
-
Class.new(schema_base_class) do
|
|
218
|
+
const_set(:DefaultTraceBacktrace, Class.new(schema_base_class) do
|
|
223
219
|
include(GraphQL::Backtrace::Trace)
|
|
224
|
-
end
|
|
220
|
+
end)
|
|
225
221
|
else
|
|
226
222
|
# First, see if the superclass has a custom-defined class for this.
|
|
227
223
|
# Then, if it doesn't, use this class's default trace
|
|
@@ -321,6 +317,9 @@ module GraphQL
|
|
|
321
317
|
GraphQL::StaticValidation::Validator.new(schema: self)
|
|
322
318
|
end
|
|
323
319
|
|
|
320
|
+
# Add `plugin` to this schema
|
|
321
|
+
# @param plugin [#use] A Schema plugin
|
|
322
|
+
# @return void
|
|
324
323
|
def use(plugin, **kwargs)
|
|
325
324
|
if kwargs.any?
|
|
326
325
|
plugin.use(self, **kwargs)
|
|
@@ -338,6 +337,10 @@ module GraphQL
|
|
|
338
337
|
# @return [Hash<String => Class>] A dictionary of type classes by their GraphQL name
|
|
339
338
|
# @see get_type Which is more efficient for finding _one type_ by name, because it doesn't merge hashes.
|
|
340
339
|
def types(context = GraphQL::Query::NullContext.instance)
|
|
340
|
+
if use_visibility_profile?
|
|
341
|
+
types = Visibility::Profile.from_context(context, self)
|
|
342
|
+
return types.all_types_h
|
|
343
|
+
end
|
|
341
344
|
all_types = non_introspection_types.merge(introspection_system.types)
|
|
342
345
|
visible_types = {}
|
|
343
346
|
all_types.each do |k, v|
|
|
@@ -363,27 +366,36 @@ module GraphQL
|
|
|
363
366
|
end
|
|
364
367
|
|
|
365
368
|
# @param type_name [String]
|
|
369
|
+
# @param context [GraphQL::Query::Context] Used for filtering definitions at query-time
|
|
370
|
+
# @param use_visibility_profile Private, for migration to {Schema::Visibility}
|
|
366
371
|
# @return [Module, nil] A type, or nil if there's no type called `type_name`
|
|
367
|
-
def get_type(type_name, context = GraphQL::Query::NullContext.instance)
|
|
372
|
+
def get_type(type_name, context = GraphQL::Query::NullContext.instance, use_visibility_profile = use_visibility_profile?)
|
|
373
|
+
if use_visibility_profile
|
|
374
|
+
return Visibility::Profile.from_context(context, self).type(type_name)
|
|
375
|
+
end
|
|
368
376
|
local_entry = own_types[type_name]
|
|
369
377
|
type_defn = case local_entry
|
|
370
378
|
when nil
|
|
371
379
|
nil
|
|
372
380
|
when Array
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
381
|
+
if context.respond_to?(:types) && context.types.is_a?(GraphQL::Schema::Visibility::Profile)
|
|
382
|
+
local_entry
|
|
383
|
+
else
|
|
384
|
+
visible_t = nil
|
|
385
|
+
warden = Warden.from_context(context)
|
|
386
|
+
local_entry.each do |t|
|
|
387
|
+
if warden.visible_type?(t, context)
|
|
388
|
+
if visible_t.nil?
|
|
389
|
+
visible_t = t
|
|
390
|
+
else
|
|
391
|
+
raise DuplicateNamesError.new(
|
|
392
|
+
duplicated_name: type_name, duplicated_definition_1: visible_t.inspect, duplicated_definition_2: t.inspect
|
|
393
|
+
)
|
|
394
|
+
end
|
|
383
395
|
end
|
|
384
396
|
end
|
|
397
|
+
visible_t
|
|
385
398
|
end
|
|
386
|
-
visible_t
|
|
387
399
|
when Module
|
|
388
400
|
local_entry
|
|
389
401
|
else
|
|
@@ -392,7 +404,7 @@ module GraphQL
|
|
|
392
404
|
|
|
393
405
|
type_defn ||
|
|
394
406
|
introspection_system.types[type_name] || # todo context-specific introspection?
|
|
395
|
-
(superclass.respond_to?(:get_type) ? superclass.get_type(type_name, context) : nil)
|
|
407
|
+
(superclass.respond_to?(:get_type) ? superclass.get_type(type_name, context, use_visibility_profile) : nil)
|
|
396
408
|
end
|
|
397
409
|
|
|
398
410
|
# @return [Boolean] Does this schema have _any_ definition for a type named `type_name`, regardless of visibility?
|
|
@@ -419,55 +431,92 @@ module GraphQL
|
|
|
419
431
|
end
|
|
420
432
|
end
|
|
421
433
|
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
434
|
+
# Get or set the root `query { ... }` object for this schema.
|
|
435
|
+
#
|
|
436
|
+
# @example Using `Types::Query` as the entry-point
|
|
437
|
+
# query { Types::Query }
|
|
438
|
+
#
|
|
439
|
+
# @param new_query_object [Class<GraphQL::Schema::Object>] The root type to use for queries
|
|
440
|
+
# @param lazy_load_block If a block is given, then it will be called when GraphQL-Ruby needs the root query type.
|
|
441
|
+
# @return [Class<GraphQL::Schema::Object>, nil] The configured query root type, if there is one.
|
|
442
|
+
def query(new_query_object = nil, &lazy_load_block)
|
|
443
|
+
if new_query_object || block_given?
|
|
428
444
|
if @query_object
|
|
429
|
-
|
|
445
|
+
dup_defn = new_query_object || yield
|
|
446
|
+
raise GraphQL::Error, "Second definition of `query(...)` (#{dup_defn.inspect}) is invalid, already configured with #{@query_object.inspect}"
|
|
447
|
+
elsif use_visibility_profile?
|
|
448
|
+
@query_object = block_given? ? lazy_load_block : new_query_object
|
|
430
449
|
else
|
|
431
|
-
@query_object = new_query_object
|
|
432
|
-
add_type_and_traverse(
|
|
433
|
-
nil
|
|
450
|
+
@query_object = new_query_object || lazy_load_block.call
|
|
451
|
+
add_type_and_traverse(@query_object, root: true)
|
|
434
452
|
end
|
|
453
|
+
nil
|
|
454
|
+
elsif @query_object.is_a?(Proc)
|
|
455
|
+
@query_object = @query_object.call
|
|
435
456
|
else
|
|
436
457
|
@query_object || find_inherited_value(:query)
|
|
437
458
|
end
|
|
438
459
|
end
|
|
439
460
|
|
|
440
|
-
|
|
441
|
-
|
|
461
|
+
# Get or set the root `mutation { ... }` object for this schema.
|
|
462
|
+
#
|
|
463
|
+
# @example Using `Types::Mutation` as the entry-point
|
|
464
|
+
# mutation { Types::Mutation }
|
|
465
|
+
#
|
|
466
|
+
# @param new_mutation_object [Class<GraphQL::Schema::Object>] The root type to use for mutations
|
|
467
|
+
# @param lazy_load_block If a block is given, then it will be called when GraphQL-Ruby needs the root mutation type.
|
|
468
|
+
# @return [Class<GraphQL::Schema::Object>, nil] The configured mutation root type, if there is one.
|
|
469
|
+
def mutation(new_mutation_object = nil, &lazy_load_block)
|
|
470
|
+
if new_mutation_object || block_given?
|
|
442
471
|
if @mutation_object
|
|
443
|
-
|
|
472
|
+
dup_defn = new_mutation_object || yield
|
|
473
|
+
raise GraphQL::Error, "Second definition of `mutation(...)` (#{dup_defn.inspect}) is invalid, already configured with #{@mutation_object.inspect}"
|
|
474
|
+
elsif use_visibility_profile?
|
|
475
|
+
@mutation_object = block_given? ? lazy_load_block : new_mutation_object
|
|
444
476
|
else
|
|
445
|
-
@mutation_object = new_mutation_object
|
|
446
|
-
add_type_and_traverse(
|
|
447
|
-
nil
|
|
477
|
+
@mutation_object = new_mutation_object || lazy_load_block.call
|
|
478
|
+
add_type_and_traverse(@mutation_object, root: true)
|
|
448
479
|
end
|
|
480
|
+
nil
|
|
481
|
+
elsif @mutation_object.is_a?(Proc)
|
|
482
|
+
@mutation_object = @mutation_object.call
|
|
449
483
|
else
|
|
450
484
|
@mutation_object || find_inherited_value(:mutation)
|
|
451
485
|
end
|
|
452
486
|
end
|
|
453
487
|
|
|
454
|
-
|
|
455
|
-
|
|
488
|
+
# Get or set the root `subscription { ... }` object for this schema.
|
|
489
|
+
#
|
|
490
|
+
# @example Using `Types::Subscription` as the entry-point
|
|
491
|
+
# subscription { Types::Subscription }
|
|
492
|
+
#
|
|
493
|
+
# @param new_subscription_object [Class<GraphQL::Schema::Object>] The root type to use for subscriptions
|
|
494
|
+
# @param lazy_load_block If a block is given, then it will be called when GraphQL-Ruby needs the root subscription type.
|
|
495
|
+
# @return [Class<GraphQL::Schema::Object>, nil] The configured subscription root type, if there is one.
|
|
496
|
+
def subscription(new_subscription_object = nil, &lazy_load_block)
|
|
497
|
+
if new_subscription_object || block_given?
|
|
456
498
|
if @subscription_object
|
|
457
|
-
|
|
499
|
+
dup_defn = new_subscription_object || yield
|
|
500
|
+
raise GraphQL::Error, "Second definition of `subscription(...)` (#{dup_defn.inspect}) is invalid, already configured with #{@subscription_object.inspect}"
|
|
501
|
+
elsif use_visibility_profile?
|
|
502
|
+
@subscription_object = block_given? ? lazy_load_block : new_subscription_object
|
|
503
|
+
add_subscription_extension_if_necessary
|
|
458
504
|
else
|
|
459
|
-
@subscription_object = new_subscription_object
|
|
505
|
+
@subscription_object = new_subscription_object || lazy_load_block.call
|
|
460
506
|
add_subscription_extension_if_necessary
|
|
461
|
-
add_type_and_traverse(
|
|
462
|
-
nil
|
|
507
|
+
add_type_and_traverse(@subscription_object, root: true)
|
|
463
508
|
end
|
|
509
|
+
nil
|
|
510
|
+
elsif @subscription_object.is_a?(Proc)
|
|
511
|
+
@subscription_object = @subscription_object.call
|
|
512
|
+
add_subscription_extension_if_necessary
|
|
513
|
+
@subscription_object
|
|
464
514
|
else
|
|
465
515
|
@subscription_object || find_inherited_value(:subscription)
|
|
466
516
|
end
|
|
467
517
|
end
|
|
468
518
|
|
|
469
|
-
# @
|
|
470
|
-
# @return [GraphQL::ObjectType, nil]
|
|
519
|
+
# @api private
|
|
471
520
|
def root_type_for_operation(operation)
|
|
472
521
|
case operation
|
|
473
522
|
when "query"
|
|
@@ -481,10 +530,16 @@ module GraphQL
|
|
|
481
530
|
end
|
|
482
531
|
end
|
|
483
532
|
|
|
533
|
+
# @return [Array<Class>] The root types (query, mutation, subscription) defined for this schema
|
|
484
534
|
def root_types
|
|
485
|
-
|
|
535
|
+
if use_visibility_profile?
|
|
536
|
+
[query, mutation, subscription].compact
|
|
537
|
+
else
|
|
538
|
+
@root_types
|
|
539
|
+
end
|
|
486
540
|
end
|
|
487
541
|
|
|
542
|
+
# @api private
|
|
488
543
|
def warden_class
|
|
489
544
|
if defined?(@warden_class)
|
|
490
545
|
@warden_class
|
|
@@ -495,12 +550,48 @@ module GraphQL
|
|
|
495
550
|
end
|
|
496
551
|
end
|
|
497
552
|
|
|
553
|
+
# @api private
|
|
498
554
|
attr_writer :warden_class
|
|
499
555
|
|
|
556
|
+
# @api private
|
|
557
|
+
def visibility_profile_class
|
|
558
|
+
if defined?(@visibility_profile_class)
|
|
559
|
+
@visibility_profile_class
|
|
560
|
+
elsif superclass.respond_to?(:visibility_profile_class)
|
|
561
|
+
superclass.visibility_profile_class
|
|
562
|
+
else
|
|
563
|
+
GraphQL::Schema::Visibility::Profile
|
|
564
|
+
end
|
|
565
|
+
end
|
|
566
|
+
|
|
567
|
+
# @api private
|
|
568
|
+
attr_writer :visibility_profile_class, :use_visibility_profile
|
|
569
|
+
# @api private
|
|
570
|
+
attr_accessor :visibility
|
|
571
|
+
# @api private
|
|
572
|
+
def use_visibility_profile?
|
|
573
|
+
if defined?(@use_visibility_profile)
|
|
574
|
+
@use_visibility_profile
|
|
575
|
+
elsif superclass.respond_to?(:use_visibility_profile?)
|
|
576
|
+
superclass.use_visibility_profile?
|
|
577
|
+
else
|
|
578
|
+
false
|
|
579
|
+
end
|
|
580
|
+
end
|
|
581
|
+
|
|
500
582
|
# @param type [Module] The type definition whose possible types you want to see
|
|
583
|
+
# @param context [GraphQL::Query::Context] used for filtering visible possible types at runtime
|
|
584
|
+
# @param use_visibility_profile Private, for migration to {Schema::Visibility}
|
|
501
585
|
# @return [Hash<String, Module>] All possible types, if no `type` is given.
|
|
502
586
|
# @return [Array<Module>] Possible types for `type`, if it's given.
|
|
503
|
-
def possible_types(type = nil, context = GraphQL::Query::NullContext.instance)
|
|
587
|
+
def possible_types(type = nil, context = GraphQL::Query::NullContext.instance, use_visibility_profile = use_visibility_profile?)
|
|
588
|
+
if use_visibility_profile
|
|
589
|
+
if type
|
|
590
|
+
return Visibility::Profile.from_context(context, self).possible_types(type)
|
|
591
|
+
else
|
|
592
|
+
raise "Schema.possible_types is not implemented for `use_visibility_profile?`"
|
|
593
|
+
end
|
|
594
|
+
end
|
|
504
595
|
if type
|
|
505
596
|
# TODO duck-typing `.possible_types` would probably be nicer here
|
|
506
597
|
if type.kind.union?
|
|
@@ -518,7 +609,7 @@ module GraphQL
|
|
|
518
609
|
introspection_system.possible_types[type] ||
|
|
519
610
|
(
|
|
520
611
|
superclass.respond_to?(:possible_types) ?
|
|
521
|
-
superclass.possible_types(type, context) :
|
|
612
|
+
superclass.possible_types(type, context, use_visibility_profile) :
|
|
522
613
|
EMPTY_ARRAY
|
|
523
614
|
)
|
|
524
615
|
end
|
|
@@ -573,9 +664,8 @@ module GraphQL
|
|
|
573
664
|
end
|
|
574
665
|
end
|
|
575
666
|
|
|
576
|
-
def type_from_ast(ast_node, context:
|
|
577
|
-
|
|
578
|
-
GraphQL::Schema::TypeExpression.build_type(type_owner, ast_node)
|
|
667
|
+
def type_from_ast(ast_node, context: self.query_class.new(self, "{ __typename }").context)
|
|
668
|
+
GraphQL::Schema::TypeExpression.build_type(context.query.types, ast_node)
|
|
579
669
|
end
|
|
580
670
|
|
|
581
671
|
def get_field(type_or_name, field_name, context = GraphQL::Query::NullContext.instance)
|
|
@@ -722,6 +812,7 @@ module GraphQL
|
|
|
722
812
|
res[:errors]
|
|
723
813
|
end
|
|
724
814
|
|
|
815
|
+
# @param new_query_class [Class<GraphQL::Query>] A subclass to use when executing queries
|
|
725
816
|
def query_class(new_query_class = NOT_CONFIGURED)
|
|
726
817
|
if NOT_CONFIGURED.equal?(new_query_class)
|
|
727
818
|
@query_class || (superclass.respond_to?(:query_class) ? superclass.query_class : GraphQL::Query)
|
|
@@ -732,13 +823,11 @@ module GraphQL
|
|
|
732
823
|
|
|
733
824
|
attr_writer :validate_max_errors
|
|
734
825
|
|
|
735
|
-
def validate_max_errors(new_validate_max_errors =
|
|
736
|
-
if new_validate_max_errors
|
|
737
|
-
@validate_max_errors
|
|
738
|
-
elsif defined?(@validate_max_errors)
|
|
739
|
-
@validate_max_errors
|
|
826
|
+
def validate_max_errors(new_validate_max_errors = NOT_CONFIGURED)
|
|
827
|
+
if NOT_CONFIGURED.equal?(new_validate_max_errors)
|
|
828
|
+
defined?(@validate_max_errors) ? @validate_max_errors : find_inherited_value(:validate_max_errors)
|
|
740
829
|
else
|
|
741
|
-
|
|
830
|
+
@validate_max_errors = new_validate_max_errors
|
|
742
831
|
end
|
|
743
832
|
end
|
|
744
833
|
|
|
@@ -769,16 +858,6 @@ module GraphQL
|
|
|
769
858
|
@analysis_engine || find_inherited_value(:analysis_engine, self.default_analysis_engine)
|
|
770
859
|
end
|
|
771
860
|
|
|
772
|
-
def using_ast_analysis?
|
|
773
|
-
true
|
|
774
|
-
end
|
|
775
|
-
|
|
776
|
-
def interpreter?
|
|
777
|
-
true
|
|
778
|
-
end
|
|
779
|
-
|
|
780
|
-
attr_writer :interpreter
|
|
781
|
-
|
|
782
861
|
def error_bubbling(new_error_bubbling = nil)
|
|
783
862
|
if !new_error_bubbling.nil?
|
|
784
863
|
warn("error_bubbling(#{new_error_bubbling.inspect}) is deprecated; the default value of `false` will be the only option in GraphQL-Ruby 3.0")
|
|
@@ -887,7 +966,7 @@ module GraphQL
|
|
|
887
966
|
To add other types to your schema, you might want `extra_types`: https://graphql-ruby.org/schema/definition.html#extra-types
|
|
888
967
|
ERR
|
|
889
968
|
end
|
|
890
|
-
add_type_and_traverse(new_orphan_types, root: false)
|
|
969
|
+
add_type_and_traverse(new_orphan_types, root: false) unless use_visibility_profile?
|
|
891
970
|
own_orphan_types.concat(new_orphan_types.flatten)
|
|
892
971
|
end
|
|
893
972
|
|
|
@@ -919,6 +998,8 @@ module GraphQL
|
|
|
919
998
|
end
|
|
920
999
|
end
|
|
921
1000
|
|
|
1001
|
+
|
|
1002
|
+
# @param new_default_logger [#log] Something to use for logging messages
|
|
922
1003
|
def default_logger(new_default_logger = NOT_CONFIGURED)
|
|
923
1004
|
if NOT_CONFIGURED.equal?(new_default_logger)
|
|
924
1005
|
if defined?(@default_logger)
|
|
@@ -939,6 +1020,7 @@ module GraphQL
|
|
|
939
1020
|
end
|
|
940
1021
|
end
|
|
941
1022
|
|
|
1023
|
+
# @param new_context_class [Class<GraphQL::Query::Context>] A subclass to use when executing queries
|
|
942
1024
|
def context_class(new_context_class = nil)
|
|
943
1025
|
if new_context_class
|
|
944
1026
|
@context_class = new_context_class
|
|
@@ -947,6 +1029,20 @@ module GraphQL
|
|
|
947
1029
|
end
|
|
948
1030
|
end
|
|
949
1031
|
|
|
1032
|
+
# Register a handler for errors raised during execution. The handlers can return a new value or raise a new error.
|
|
1033
|
+
#
|
|
1034
|
+
# @example Handling "not found" with a client-facing error
|
|
1035
|
+
# rescue_from(ActiveRecord::NotFound) { raise GraphQL::ExecutionError, "An object could not be found" }
|
|
1036
|
+
#
|
|
1037
|
+
# @param err_classes [Array<StandardError>] Classes which should be rescued by `handler_block`
|
|
1038
|
+
# @param handler_block The code to run when one of those errors is raised during execution
|
|
1039
|
+
# @yieldparam error [StandardError] An instance of one of the configured `err_classes`
|
|
1040
|
+
# @yieldparam object [Object] The current application object in the query when the error was raised
|
|
1041
|
+
# @yieldparam arguments [GraphQL::Query::Arguments] The current field arguments when the error was raised
|
|
1042
|
+
# @yieldparam context [GraphQL::Query::Context] The context for the currently-running operation
|
|
1043
|
+
# @yieldreturn [Object] Some object to use in the place where this error was raised
|
|
1044
|
+
# @raise [GraphQL::ExecutionError] In the handler, raise to add a client-facing error to the response
|
|
1045
|
+
# @raise [StandardError] In the handler, raise to crash the query with a developer-facing error
|
|
950
1046
|
def rescue_from(*err_classes, &handler_block)
|
|
951
1047
|
err_classes.each do |err_class|
|
|
952
1048
|
Execution::Errors.register_rescue_from(err_class, error_handlers[:subclass_handlers], handler_block)
|
|
@@ -1013,8 +1109,24 @@ module GraphQL
|
|
|
1013
1109
|
end
|
|
1014
1110
|
end
|
|
1015
1111
|
|
|
1016
|
-
|
|
1017
|
-
|
|
1112
|
+
# GraphQL-Ruby calls this method during execution when it needs the application to determine the type to use for an object.
|
|
1113
|
+
#
|
|
1114
|
+
# Usually, this object was returned from a field whose return type is an {GraphQL::Schema::Interface} or a {GraphQL::Schema::Union}.
|
|
1115
|
+
# But this method is called in other cases, too -- for example, when {GraphQL::Schema::Argument.loads} cases an object to be directly loaded from the database.
|
|
1116
|
+
#
|
|
1117
|
+
# @example Returning a GraphQL type based on the object's class name
|
|
1118
|
+
# class MySchema < GraphQL::Schema
|
|
1119
|
+
# def resolve_type(_abs_type, object, _context)
|
|
1120
|
+
# graphql_type_name = "Types::#{object.class.name}Type"
|
|
1121
|
+
# graphql_type_name.constantize # If this raises a NameError, then come implement special cases in this method
|
|
1122
|
+
# end
|
|
1123
|
+
# end
|
|
1124
|
+
# @param abstract_type [Class, Module, nil] The Interface or Union type which is being resolved, if there is one
|
|
1125
|
+
# @param application_object [Object] The object returned from a field whose type must be determined
|
|
1126
|
+
# @param context [GraphQL::Query::Context] The query context for the currently-executing query
|
|
1127
|
+
# @return [Class<GraphQL::Schema::Object] The Object type definition to use for `obj`
|
|
1128
|
+
def resolve_type(abstract_type, application_object, context)
|
|
1129
|
+
raise GraphQL::RequiredImplementationMissingError, "#{self.name}.resolve_type(abstract_type, application_object, context) must be implemented to use Union types, Interface types, or `loads:` (tried to resolve: #{abstract_type.name})"
|
|
1018
1130
|
end
|
|
1019
1131
|
# rubocop:enable Lint/DuplicateMethods
|
|
1020
1132
|
|
|
@@ -1029,15 +1141,45 @@ module GraphQL
|
|
|
1029
1141
|
child_class.own_trace_modes[name] = child_class.build_trace_mode(name)
|
|
1030
1142
|
end
|
|
1031
1143
|
child_class.singleton_class.prepend(ResolveTypeWithType)
|
|
1032
|
-
super
|
|
1033
|
-
end
|
|
1034
1144
|
|
|
1035
|
-
|
|
1036
|
-
|
|
1145
|
+
if use_visibility_profile?
|
|
1146
|
+
vis = self.visibility
|
|
1147
|
+
child_class.visibility = vis.dup_for(child_class)
|
|
1148
|
+
end
|
|
1149
|
+
super
|
|
1037
1150
|
end
|
|
1038
1151
|
|
|
1039
|
-
|
|
1040
|
-
|
|
1152
|
+
# Fetch an object based on an incoming ID and the current context. This method should return an object
|
|
1153
|
+
# from your application, or return `nil` if there is no object or the object shouldn't be available to this operation.
|
|
1154
|
+
#
|
|
1155
|
+
# @example Fetching an object with Rails's GlobalID
|
|
1156
|
+
# def self.object_from_id(object_id, _context)
|
|
1157
|
+
# GlobalID.find(global_id)
|
|
1158
|
+
# # TODO: use `context[:current_user]` to determine if this object is authorized.
|
|
1159
|
+
# end
|
|
1160
|
+
# @param object_id [String] The ID to fetch an object for. This may be client-provided (as in `node(id: ...)` or `loads:`) or previously stored by the schema (eg, by the `ObjectCache`)
|
|
1161
|
+
# @param context [GraphQL::Query::Context] The context for the currently-executing operation
|
|
1162
|
+
# @return [Object, nil] The application which `object_id` references, or `nil` if there is no object or the current operation shouldn't have access to the object
|
|
1163
|
+
# @see id_from_object which produces these IDs
|
|
1164
|
+
def object_from_id(object_id, context)
|
|
1165
|
+
raise GraphQL::RequiredImplementationMissingError, "#{self.name}.object_from_id(object_id, context) must be implemented to load by ID (tried to load from id `#{object_id}`)"
|
|
1166
|
+
end
|
|
1167
|
+
|
|
1168
|
+
# Return a stable ID string for `object` so that it can be refetched later, using {.object_from_id}.
|
|
1169
|
+
#
|
|
1170
|
+
# {GlobalID}(https://github.com/rails/globalid) and {SQIDs}(https://sqids.org/ruby) can both be used to create IDs.
|
|
1171
|
+
#
|
|
1172
|
+
# @example Using Rails's GlobalID to generate IDs
|
|
1173
|
+
# def self.id_from_object(application_object, graphql_type, context)
|
|
1174
|
+
# application_object.to_gid_param
|
|
1175
|
+
# end
|
|
1176
|
+
#
|
|
1177
|
+
# @param application_object [Object] Some object encountered by GraphQL-Ruby while running a query
|
|
1178
|
+
# @param graphql_type [Class, Module] The type that GraphQL-Ruby is using for `application_object` during this query
|
|
1179
|
+
# @param context [GraphQL::Query::Context] The context for the operation that is currently running
|
|
1180
|
+
# @return [String] A stable identifier which can be passed to {.object_from_id} later to re-fetch `application_object`
|
|
1181
|
+
def id_from_object(application_object, graphql_type, context)
|
|
1182
|
+
raise GraphQL::RequiredImplementationMissingError, "#{self.name}.id_from_object(application_object, graphql_type, context) must be implemented to create global ids (tried to create an id for `#{application_object.inspect}`)"
|
|
1041
1183
|
end
|
|
1042
1184
|
|
|
1043
1185
|
def visible?(member, ctx)
|
|
@@ -1053,6 +1195,10 @@ module GraphQL
|
|
|
1053
1195
|
Member::HasDirectives.get_directives(self, @own_schema_directives, :schema_directives)
|
|
1054
1196
|
end
|
|
1055
1197
|
|
|
1198
|
+
# Called when a type is needed by name at runtime
|
|
1199
|
+
def load_type(type_name, ctx)
|
|
1200
|
+
get_type(type_name, ctx)
|
|
1201
|
+
end
|
|
1056
1202
|
# This hook is called when an object fails an `authorized?` check.
|
|
1057
1203
|
# You might report to your bug tracker here, so you can correct
|
|
1058
1204
|
# the field resolvers not to return unauthorized objects.
|
|
@@ -1088,6 +1234,16 @@ module GraphQL
|
|
|
1088
1234
|
unauthorized_object(unauthorized_error)
|
|
1089
1235
|
end
|
|
1090
1236
|
|
|
1237
|
+
# Called at runtime when GraphQL-Ruby encounters a mismatch between the application behavior
|
|
1238
|
+
# and the GraphQL type system.
|
|
1239
|
+
#
|
|
1240
|
+
# The default implementation of this method is to follow the GraphQL specification,
|
|
1241
|
+
# but you can override this to report errors to your bug tracker or customize error handling.
|
|
1242
|
+
# @param type_error [GraphQL::Error] several specific error classes are passed here, see the default implementation for details
|
|
1243
|
+
# @param context [GraphQL::Query::Context] the context for the currently-running operation
|
|
1244
|
+
# @return [void]
|
|
1245
|
+
# @raise [GraphQL::ExecutionError] to return this error to the client
|
|
1246
|
+
# @raise [GraphQL::Error] to crash the query and raise a developer-facing error
|
|
1091
1247
|
def type_error(type_error, ctx)
|
|
1092
1248
|
case type_error
|
|
1093
1249
|
when GraphQL::InvalidNullError
|
|
@@ -1142,7 +1298,11 @@ module GraphQL
|
|
|
1142
1298
|
# @param new_directive [Class]
|
|
1143
1299
|
# @return void
|
|
1144
1300
|
def directive(new_directive)
|
|
1145
|
-
|
|
1301
|
+
if use_visibility_profile?
|
|
1302
|
+
own_directives[new_directive.graphql_name] = new_directive
|
|
1303
|
+
else
|
|
1304
|
+
add_type_and_traverse(new_directive, root: false)
|
|
1305
|
+
end
|
|
1146
1306
|
end
|
|
1147
1307
|
|
|
1148
1308
|
def default_directives
|
|
@@ -1179,6 +1339,7 @@ module GraphQL
|
|
|
1179
1339
|
# @param mode [Symbol] Trace module will only be used for this trade mode
|
|
1180
1340
|
# @param options [Hash] Keywords that will be passed to the tracing class during `#initialize`
|
|
1181
1341
|
# @return [void]
|
|
1342
|
+
# @see GraphQL::Tracing::Trace for available tracing methods
|
|
1182
1343
|
def trace_with(trace_mod, mode: :default, **options)
|
|
1183
1344
|
if mode.is_a?(Array)
|
|
1184
1345
|
mode.each { |m| trace_with(trace_mod, mode: m, **options) }
|
|
@@ -1256,6 +1417,8 @@ module GraphQL
|
|
|
1256
1417
|
trace_class_for_mode.new(**trace_options)
|
|
1257
1418
|
end
|
|
1258
1419
|
|
|
1420
|
+
# @param new_analyzer [Class<GraphQL::Analysis::Analyzer>] An analyzer to run on queries to this schema
|
|
1421
|
+
# @see GraphQL::Analysis the analysis system
|
|
1259
1422
|
def query_analyzer(new_analyzer)
|
|
1260
1423
|
own_query_analyzers << new_analyzer
|
|
1261
1424
|
end
|
|
@@ -1264,6 +1427,8 @@ module GraphQL
|
|
|
1264
1427
|
find_inherited_value(:query_analyzers, EMPTY_ARRAY) + own_query_analyzers
|
|
1265
1428
|
end
|
|
1266
1429
|
|
|
1430
|
+
# @param new_analyzer [Class<GraphQL::Analysis::Analyzer>] An analyzer to run on multiplexes to this schema
|
|
1431
|
+
# @see GraphQL::Analysis the analysis system
|
|
1267
1432
|
def multiplex_analyzer(new_analyzer)
|
|
1268
1433
|
own_multiplex_analyzers << new_analyzer
|
|
1269
1434
|
end
|
|
@@ -1336,7 +1501,8 @@ module GraphQL
|
|
|
1336
1501
|
|
|
1337
1502
|
# @api private
|
|
1338
1503
|
def add_subscription_extension_if_necessary
|
|
1339
|
-
|
|
1504
|
+
# TODO: when there's a proper API for extending root types, migrat this to use it.
|
|
1505
|
+
if !defined?(@subscription_extension_added) && @subscription_object.is_a?(Class) && self.subscriptions
|
|
1340
1506
|
@subscription_extension_added = true
|
|
1341
1507
|
subscription.all_field_definitions.each do |field|
|
|
1342
1508
|
if !field.extensions.any? { |ext| ext.is_a?(Subscriptions::DefaultSubscriptionResolveExtension) }
|
|
@@ -1346,6 +1512,11 @@ module GraphQL
|
|
|
1346
1512
|
end
|
|
1347
1513
|
end
|
|
1348
1514
|
|
|
1515
|
+
# Called when execution encounters a `SystemStackError`. By default, it adds a client-facing error to the response.
|
|
1516
|
+
# You could modify this method to report this error to your bug tracker.
|
|
1517
|
+
# @param query [GraphQL::Query]
|
|
1518
|
+
# @param err [SystemStackError]
|
|
1519
|
+
# @return [void]
|
|
1349
1520
|
def query_stack_error(query, err)
|
|
1350
1521
|
query.context.errors.push(GraphQL::ExecutionError.new("This query is too large to execute."))
|
|
1351
1522
|
end
|
|
@@ -1404,11 +1575,34 @@ module GraphQL
|
|
|
1404
1575
|
end
|
|
1405
1576
|
end
|
|
1406
1577
|
|
|
1578
|
+
# Returns `DidYouMean` if it's defined.
|
|
1579
|
+
# Override this to return `nil` if you don't want to use `DidYouMean`
|
|
1580
|
+
def did_you_mean(new_dym = NOT_CONFIGURED)
|
|
1581
|
+
if NOT_CONFIGURED.equal?(new_dym)
|
|
1582
|
+
if defined?(@did_you_mean)
|
|
1583
|
+
@did_you_mean
|
|
1584
|
+
else
|
|
1585
|
+
find_inherited_value(:did_you_mean, defined?(DidYouMean) ? DidYouMean : nil)
|
|
1586
|
+
end
|
|
1587
|
+
else
|
|
1588
|
+
@did_you_mean = new_dym
|
|
1589
|
+
end
|
|
1590
|
+
end
|
|
1591
|
+
|
|
1407
1592
|
private
|
|
1408
1593
|
|
|
1409
1594
|
def add_trace_options_for(mode, new_options)
|
|
1410
|
-
|
|
1411
|
-
|
|
1595
|
+
if mode == :default
|
|
1596
|
+
own_trace_modes.each do |mode_name, t_class|
|
|
1597
|
+
if t_class <= DefaultTraceClass
|
|
1598
|
+
t_opts = trace_options_for(mode_name)
|
|
1599
|
+
t_opts.merge!(new_options)
|
|
1600
|
+
end
|
|
1601
|
+
end
|
|
1602
|
+
else
|
|
1603
|
+
t_opts = trace_options_for(mode)
|
|
1604
|
+
t_opts.merge!(new_options)
|
|
1605
|
+
end
|
|
1412
1606
|
nil
|
|
1413
1607
|
end
|
|
1414
1608
|
|
|
@@ -1485,7 +1679,7 @@ module GraphQL
|
|
|
1485
1679
|
end
|
|
1486
1680
|
|
|
1487
1681
|
def own_references_to
|
|
1488
|
-
@own_references_to ||= {}.
|
|
1682
|
+
@own_references_to ||= {}.compare_by_identity
|
|
1489
1683
|
end
|
|
1490
1684
|
|
|
1491
1685
|
def non_introspection_types
|
|
@@ -1501,7 +1695,7 @@ module GraphQL
|
|
|
1501
1695
|
end
|
|
1502
1696
|
|
|
1503
1697
|
def own_possible_types
|
|
1504
|
-
@own_possible_types ||= {}.
|
|
1698
|
+
@own_possible_types ||= {}.compare_by_identity
|
|
1505
1699
|
end
|
|
1506
1700
|
|
|
1507
1701
|
def own_union_memberships
|
|
@@ -1552,5 +1746,9 @@ module GraphQL
|
|
|
1552
1746
|
|
|
1553
1747
|
# Install these here so that subclasses will also install it.
|
|
1554
1748
|
self.connections = GraphQL::Pagination::Connections.new(schema: self)
|
|
1749
|
+
|
|
1750
|
+
# @api private
|
|
1751
|
+
module DefaultTraceClass
|
|
1752
|
+
end
|
|
1555
1753
|
end
|
|
1556
1754
|
end
|