graphql 2.3.5 → 2.3.11
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 +46 -0
- data/lib/graphql/analysis/analyzer.rb +89 -0
- data/lib/graphql/analysis/field_usage.rb +82 -0
- data/lib/graphql/analysis/max_query_complexity.rb +20 -0
- data/lib/graphql/analysis/max_query_depth.rb +20 -0
- data/lib/graphql/analysis/query_complexity.rb +183 -0
- data/lib/graphql/analysis/{ast/query_depth.rb → query_depth.rb} +23 -25
- data/lib/graphql/analysis/visitor.rb +283 -0
- data/lib/graphql/analysis.rb +92 -1
- data/lib/graphql/current.rb +52 -0
- data/lib/graphql/dataloader/async_dataloader.rb +2 -0
- data/lib/graphql/dataloader/source.rb +5 -2
- data/lib/graphql/dataloader.rb +4 -1
- data/lib/graphql/execution/interpreter/arguments_cache.rb +5 -10
- data/lib/graphql/execution/interpreter/runtime.rb +8 -14
- data/lib/graphql/execution/interpreter.rb +3 -1
- 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/language/document_from_schema_definition.rb +19 -26
- data/lib/graphql/language/lexer.rb +0 -3
- data/lib/graphql/language/nodes.rb +2 -2
- data/lib/graphql/language/parser.rb +9 -1
- data/lib/graphql/language/sanitized_printer.rb +1 -1
- data/lib/graphql/language.rb +0 -1
- data/lib/graphql/query/context.rb +7 -1
- data/lib/graphql/query/null_context.rb +2 -2
- data/lib/graphql/query/validation_pipeline.rb +2 -2
- data/lib/graphql/query.rb +26 -7
- data/lib/graphql/schema/always_visible.rb +1 -0
- data/lib/graphql/schema/argument.rb +19 -5
- data/lib/graphql/schema/build_from_definition.rb +8 -1
- data/lib/graphql/schema/directive/flagged.rb +1 -1
- data/lib/graphql/schema/directive.rb +2 -0
- data/lib/graphql/schema/enum.rb +9 -5
- data/lib/graphql/schema/field/connection_extension.rb +1 -1
- data/lib/graphql/schema/field.rb +13 -1
- data/lib/graphql/schema/has_single_input_argument.rb +2 -1
- data/lib/graphql/schema/input_object.rb +8 -7
- data/lib/graphql/schema/interface.rb +20 -4
- data/lib/graphql/schema/introspection_system.rb +5 -16
- data/lib/graphql/schema/member/has_arguments.rb +14 -9
- data/lib/graphql/schema/member/has_fields.rb +6 -4
- data/lib/graphql/schema/member/has_unresolved_type_error.rb +5 -1
- data/lib/graphql/schema/resolver.rb +5 -5
- data/lib/graphql/schema/subset.rb +510 -0
- data/lib/graphql/schema/type_expression.rb +2 -2
- data/lib/graphql/schema/types_migration.rb +185 -0
- data/lib/graphql/schema/validator/all_validator.rb +60 -0
- data/lib/graphql/schema/validator.rb +2 -0
- data/lib/graphql/schema/warden.rb +89 -5
- data/lib/graphql/schema.rb +74 -37
- 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 +1 -1
- data/lib/graphql/static_validation/rules/directives_are_defined.rb +1 -2
- data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +1 -1
- data/lib/graphql/static_validation/rules/fields_will_merge.rb +7 -7
- data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +3 -3
- data/lib/graphql/static_validation/rules/fragment_types_exist.rb +1 -1
- 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 +1 -1
- data/lib/graphql/static_validation/validation_context.rb +2 -2
- data/lib/graphql/subscriptions/broadcast_analyzer.rb +11 -5
- data/lib/graphql/subscriptions/event.rb +1 -1
- data/lib/graphql/subscriptions.rb +3 -3
- data/lib/graphql/testing/helpers.rb +8 -5
- 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/version.rb +1 -1
- data/lib/graphql.rb +1 -0
- metadata +14 -13
- data/lib/graphql/analysis/ast/analyzer.rb +0 -91
- data/lib/graphql/analysis/ast/field_usage.rb +0 -84
- data/lib/graphql/analysis/ast/max_query_complexity.rb +0 -22
- data/lib/graphql/analysis/ast/max_query_depth.rb +0 -22
- data/lib/graphql/analysis/ast/query_complexity.rb +0 -185
- data/lib/graphql/analysis/ast/visitor.rb +0 -284
- data/lib/graphql/analysis/ast.rb +0 -94
- data/lib/graphql/language/token.rb +0 -34
- data/lib/graphql/schema/invalid_type_error.rb +0 -7
@@ -0,0 +1,60 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module GraphQL
|
4
|
+
class Schema
|
5
|
+
class Validator
|
6
|
+
# Use this to validate each member of an array value.
|
7
|
+
#
|
8
|
+
# @example validate format of all strings in an array
|
9
|
+
#
|
10
|
+
# argument :handles, [String],
|
11
|
+
# validates: { all: { format: { with: /\A[a-z0-9_]+\Z/ } } }
|
12
|
+
#
|
13
|
+
# @example multiple validators can be combined
|
14
|
+
#
|
15
|
+
# argument :handles, [String],
|
16
|
+
# validates: { all: { format: { with: /\A[a-z0-9_]+\Z/ }, length: { maximum: 32 } } }
|
17
|
+
#
|
18
|
+
# @example any type can be used
|
19
|
+
#
|
20
|
+
# argument :choices, [Integer],
|
21
|
+
# validates: { all: { inclusion: { in: 1..12 } } }
|
22
|
+
#
|
23
|
+
class AllValidator < Validator
|
24
|
+
def initialize(validated:, allow_blank: false, allow_null: false, **validators)
|
25
|
+
super(validated: validated, allow_blank: allow_blank, allow_null: allow_null)
|
26
|
+
|
27
|
+
@validators = Validator.from_config(validated, validators)
|
28
|
+
end
|
29
|
+
|
30
|
+
def validate(object, context, value)
|
31
|
+
all_errors = EMPTY_ARRAY
|
32
|
+
|
33
|
+
value.each do |subvalue|
|
34
|
+
@validators.each do |validator|
|
35
|
+
errors = validator.validate(object, context, subvalue)
|
36
|
+
if errors &&
|
37
|
+
(errors.is_a?(Array) && errors != EMPTY_ARRAY) ||
|
38
|
+
(errors.is_a?(String))
|
39
|
+
if all_errors.frozen? # It's empty
|
40
|
+
all_errors = []
|
41
|
+
end
|
42
|
+
if errors.is_a?(String)
|
43
|
+
all_errors << errors
|
44
|
+
else
|
45
|
+
all_errors.concat(errors)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
unless all_errors.frozen?
|
52
|
+
all_errors.uniq!
|
53
|
+
end
|
54
|
+
|
55
|
+
all_errors
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -169,3 +169,5 @@ require "graphql/schema/validator/allow_null_validator"
|
|
169
169
|
GraphQL::Schema::Validator.install(:allow_null, GraphQL::Schema::Validator::AllowNullValidator)
|
170
170
|
require "graphql/schema/validator/allow_blank_validator"
|
171
171
|
GraphQL::Schema::Validator.install(:allow_blank, GraphQL::Schema::Validator::AllowBlankValidator)
|
172
|
+
require "graphql/schema/validator/all_validator"
|
173
|
+
GraphQL::Schema::Validator.install(:all, GraphQL::Schema::Validator::AllValidator)
|
@@ -61,14 +61,27 @@ module GraphQL
|
|
61
61
|
def interface_type_memberships(obj_t, ctx); obj_t.interface_type_memberships; end
|
62
62
|
def arguments(owner, ctx); owner.arguments(ctx); end
|
63
63
|
def loadable?(type, ctx); type.visible?(ctx); end
|
64
|
+
def schema_subset
|
65
|
+
@schema_subset ||= Warden::SchemaSubset.new(self)
|
66
|
+
end
|
64
67
|
end
|
65
68
|
end
|
66
69
|
|
67
70
|
class NullWarden
|
68
71
|
def initialize(_filter = nil, context:, schema:)
|
69
72
|
@schema = schema
|
73
|
+
@schema_subset = Warden::SchemaSubset.new(self)
|
74
|
+
end
|
75
|
+
|
76
|
+
# @api private
|
77
|
+
module NullSubset
|
78
|
+
def self.new(context:, schema:)
|
79
|
+
NullWarden.new(context: context, schema: schema).schema_subset
|
80
|
+
end
|
70
81
|
end
|
71
82
|
|
83
|
+
attr_reader :schema_subset
|
84
|
+
|
72
85
|
def visible_field?(field_defn, _ctx = nil, owner = nil); true; end
|
73
86
|
def visible_argument?(arg_defn, _ctx = nil); true; end
|
74
87
|
def visible_type?(type_defn, _ctx = nil); true; end
|
@@ -91,6 +104,80 @@ module GraphQL
|
|
91
104
|
def interfaces(obj_type); obj_type.interfaces; end
|
92
105
|
end
|
93
106
|
|
107
|
+
def schema_subset
|
108
|
+
@schema_subset ||= SchemaSubset.new(self)
|
109
|
+
end
|
110
|
+
|
111
|
+
class SchemaSubset
|
112
|
+
def initialize(warden)
|
113
|
+
@warden = warden
|
114
|
+
end
|
115
|
+
|
116
|
+
def directives
|
117
|
+
@warden.directives
|
118
|
+
end
|
119
|
+
|
120
|
+
def directive_exists?(dir_name)
|
121
|
+
@warden.directives.any? { |d| d.graphql_name == dir_name }
|
122
|
+
end
|
123
|
+
|
124
|
+
def type(name)
|
125
|
+
@warden.get_type(name)
|
126
|
+
end
|
127
|
+
|
128
|
+
def field(owner, field_name)
|
129
|
+
@warden.get_field(owner, field_name)
|
130
|
+
end
|
131
|
+
|
132
|
+
def argument(owner, arg_name)
|
133
|
+
@warden.get_argument(owner, arg_name)
|
134
|
+
end
|
135
|
+
|
136
|
+
def query_root
|
137
|
+
@warden.root_type_for_operation("query")
|
138
|
+
end
|
139
|
+
|
140
|
+
def mutation_root
|
141
|
+
@warden.root_type_for_operation("mutation")
|
142
|
+
end
|
143
|
+
|
144
|
+
def subscription_root
|
145
|
+
@warden.root_type_for_operation("subscription")
|
146
|
+
end
|
147
|
+
|
148
|
+
def arguments(owner)
|
149
|
+
@warden.arguments(owner)
|
150
|
+
end
|
151
|
+
|
152
|
+
def fields(owner)
|
153
|
+
@warden.fields(owner)
|
154
|
+
end
|
155
|
+
|
156
|
+
def possible_types(type)
|
157
|
+
@warden.possible_types(type)
|
158
|
+
end
|
159
|
+
|
160
|
+
def enum_values(enum_type)
|
161
|
+
@warden.enum_values(enum_type)
|
162
|
+
end
|
163
|
+
|
164
|
+
def all_types
|
165
|
+
@warden.reachable_types
|
166
|
+
end
|
167
|
+
|
168
|
+
def interfaces(obj_type)
|
169
|
+
@warden.interfaces(obj_type)
|
170
|
+
end
|
171
|
+
|
172
|
+
def loadable?(t, ctx) # TODO remove ctx here?
|
173
|
+
@warden.loadable?(t, ctx)
|
174
|
+
end
|
175
|
+
|
176
|
+
def reachable_type?(type_name)
|
177
|
+
!!@warden.reachable_type?(type_name)
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
94
181
|
# @param context [GraphQL::Query::Context]
|
95
182
|
# @param schema [GraphQL::Schema]
|
96
183
|
def initialize(context:, schema:)
|
@@ -101,13 +188,12 @@ module GraphQL
|
|
101
188
|
@subscription = @schema.subscription
|
102
189
|
@context = context
|
103
190
|
@visibility_cache = read_through { |m| schema.visible?(m, context) }
|
104
|
-
@visibility_cache.compare_by_identity
|
105
191
|
# Initialize all ivars to improve object shape consistency:
|
106
192
|
@types = @visible_types = @reachable_types = @visible_parent_fields =
|
107
193
|
@visible_possible_types = @visible_fields = @visible_arguments = @visible_enum_arrays =
|
108
194
|
@visible_enum_values = @visible_interfaces = @type_visibility = @type_memberships =
|
109
195
|
@visible_and_reachable_type = @unions = @unfiltered_interfaces =
|
110
|
-
@reachable_type_set =
|
196
|
+
@reachable_type_set = @schema_subset =
|
111
197
|
nil
|
112
198
|
end
|
113
199
|
|
@@ -376,9 +462,7 @@ module GraphQL
|
|
376
462
|
end
|
377
463
|
|
378
464
|
def read_through
|
379
|
-
|
380
|
-
h.compare_by_identity
|
381
|
-
h
|
465
|
+
Hash.new { |h, k| h[k] = yield(k) }.compare_by_identity
|
382
466
|
end
|
383
467
|
|
384
468
|
def reachable_type_set
|
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,8 @@ 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/subset"
|
49
|
+
require "graphql/schema/types_migration"
|
49
50
|
|
50
51
|
module GraphQL
|
51
52
|
# A GraphQL schema which may be queried with {GraphQL::Query}.
|
@@ -338,6 +339,9 @@ module GraphQL
|
|
338
339
|
# @return [Hash<String => Class>] A dictionary of type classes by their GraphQL name
|
339
340
|
# @see get_type Which is more efficient for finding _one type_ by name, because it doesn't merge hashes.
|
340
341
|
def types(context = GraphQL::Query::NullContext.instance)
|
342
|
+
if use_schema_subset?
|
343
|
+
return Subset.from_context(context, self).all_types_h
|
344
|
+
end
|
341
345
|
all_types = non_introspection_types.merge(introspection_system.types)
|
342
346
|
visible_types = {}
|
343
347
|
all_types.each do |k, v|
|
@@ -365,25 +369,32 @@ module GraphQL
|
|
365
369
|
# @param type_name [String]
|
366
370
|
# @return [Module, nil] A type, or nil if there's no type called `type_name`
|
367
371
|
def get_type(type_name, context = GraphQL::Query::NullContext.instance)
|
372
|
+
if use_schema_subset?
|
373
|
+
return Subset.from_context(context, self).type(type_name)
|
374
|
+
end
|
368
375
|
local_entry = own_types[type_name]
|
369
376
|
type_defn = case local_entry
|
370
377
|
when nil
|
371
378
|
nil
|
372
379
|
when Array
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
380
|
+
if context.respond_to?(:types) && context.types.is_a?(GraphQL::Schema::Subset)
|
381
|
+
local_entry
|
382
|
+
else
|
383
|
+
visible_t = nil
|
384
|
+
warden = Warden.from_context(context)
|
385
|
+
local_entry.each do |t|
|
386
|
+
if warden.visible_type?(t, context)
|
387
|
+
if visible_t.nil?
|
388
|
+
visible_t = t
|
389
|
+
else
|
390
|
+
raise DuplicateNamesError.new(
|
391
|
+
duplicated_name: type_name, duplicated_definition_1: visible_t.inspect, duplicated_definition_2: t.inspect
|
392
|
+
)
|
393
|
+
end
|
383
394
|
end
|
384
395
|
end
|
396
|
+
visible_t
|
385
397
|
end
|
386
|
-
visible_t
|
387
398
|
when Module
|
388
399
|
local_entry
|
389
400
|
else
|
@@ -419,17 +430,13 @@ module GraphQL
|
|
419
430
|
end
|
420
431
|
end
|
421
432
|
|
422
|
-
def new_connections?
|
423
|
-
!!connections
|
424
|
-
end
|
425
|
-
|
426
433
|
def query(new_query_object = nil)
|
427
434
|
if new_query_object
|
428
435
|
if @query_object
|
429
436
|
raise GraphQL::Error, "Second definition of `query(...)` (#{new_query_object.inspect}) is invalid, already configured with #{@query_object.inspect}"
|
430
437
|
else
|
431
438
|
@query_object = new_query_object
|
432
|
-
add_type_and_traverse(new_query_object, root: true)
|
439
|
+
add_type_and_traverse(new_query_object, root: true) unless use_schema_subset?
|
433
440
|
nil
|
434
441
|
end
|
435
442
|
else
|
@@ -443,7 +450,7 @@ module GraphQL
|
|
443
450
|
raise GraphQL::Error, "Second definition of `mutation(...)` (#{new_mutation_object.inspect}) is invalid, already configured with #{@mutation_object.inspect}"
|
444
451
|
else
|
445
452
|
@mutation_object = new_mutation_object
|
446
|
-
add_type_and_traverse(new_mutation_object, root: true)
|
453
|
+
add_type_and_traverse(new_mutation_object, root: true) unless use_schema_subset?
|
447
454
|
nil
|
448
455
|
end
|
449
456
|
else
|
@@ -458,7 +465,7 @@ module GraphQL
|
|
458
465
|
else
|
459
466
|
@subscription_object = new_subscription_object
|
460
467
|
add_subscription_extension_if_necessary
|
461
|
-
add_type_and_traverse(new_subscription_object, root: true)
|
468
|
+
add_type_and_traverse(new_subscription_object, root: true) unless use_schema_subset?
|
462
469
|
nil
|
463
470
|
end
|
464
471
|
else
|
@@ -482,7 +489,11 @@ module GraphQL
|
|
482
489
|
end
|
483
490
|
|
484
491
|
def root_types
|
485
|
-
|
492
|
+
if use_schema_subset?
|
493
|
+
[query, mutation, subscription].compact
|
494
|
+
else
|
495
|
+
@root_types
|
496
|
+
end
|
486
497
|
end
|
487
498
|
|
488
499
|
def warden_class
|
@@ -497,10 +508,39 @@ module GraphQL
|
|
497
508
|
|
498
509
|
attr_writer :warden_class
|
499
510
|
|
511
|
+
def subset_class
|
512
|
+
if defined?(@subset_class)
|
513
|
+
@subset_class
|
514
|
+
elsif superclass.respond_to?(:subset_class)
|
515
|
+
superclass.subset_class
|
516
|
+
else
|
517
|
+
GraphQL::Schema::Subset
|
518
|
+
end
|
519
|
+
end
|
520
|
+
|
521
|
+
attr_writer :subset_class, :use_schema_subset
|
522
|
+
|
523
|
+
def use_schema_subset?
|
524
|
+
if defined?(@use_schema_subset)
|
525
|
+
@use_schema_subset
|
526
|
+
elsif superclass.respond_to?(:use_schema_subset?)
|
527
|
+
superclass.use_schema_subset?
|
528
|
+
else
|
529
|
+
false
|
530
|
+
end
|
531
|
+
end
|
532
|
+
|
500
533
|
# @param type [Module] The type definition whose possible types you want to see
|
501
534
|
# @return [Hash<String, Module>] All possible types, if no `type` is given.
|
502
535
|
# @return [Array<Module>] Possible types for `type`, if it's given.
|
503
536
|
def possible_types(type = nil, context = GraphQL::Query::NullContext.instance)
|
537
|
+
if use_schema_subset?
|
538
|
+
if type
|
539
|
+
return Subset.from_context(context, self).possible_types(type)
|
540
|
+
else
|
541
|
+
raise "Schema.possible_types is not implemented for `use_schema_subset?`"
|
542
|
+
end
|
543
|
+
end
|
504
544
|
if type
|
505
545
|
# TODO duck-typing `.possible_types` would probably be nicer here
|
506
546
|
if type.kind.union?
|
@@ -573,9 +613,8 @@ module GraphQL
|
|
573
613
|
end
|
574
614
|
end
|
575
615
|
|
576
|
-
def type_from_ast(ast_node, context:
|
577
|
-
|
578
|
-
GraphQL::Schema::TypeExpression.build_type(type_owner, ast_node)
|
616
|
+
def type_from_ast(ast_node, context: self.query_class.new(self, "{ __typename }").context)
|
617
|
+
GraphQL::Schema::TypeExpression.build_type(context.query.types, ast_node)
|
579
618
|
end
|
580
619
|
|
581
620
|
def get_field(type_or_name, field_name, context = GraphQL::Query::NullContext.instance)
|
@@ -769,16 +808,6 @@ module GraphQL
|
|
769
808
|
@analysis_engine || find_inherited_value(:analysis_engine, self.default_analysis_engine)
|
770
809
|
end
|
771
810
|
|
772
|
-
def using_ast_analysis?
|
773
|
-
true
|
774
|
-
end
|
775
|
-
|
776
|
-
def interpreter?
|
777
|
-
true
|
778
|
-
end
|
779
|
-
|
780
|
-
attr_writer :interpreter
|
781
|
-
|
782
811
|
def error_bubbling(new_error_bubbling = nil)
|
783
812
|
if !new_error_bubbling.nil?
|
784
813
|
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 +916,7 @@ module GraphQL
|
|
887
916
|
To add other types to your schema, you might want `extra_types`: https://graphql-ruby.org/schema/definition.html#extra-types
|
888
917
|
ERR
|
889
918
|
end
|
890
|
-
add_type_and_traverse(new_orphan_types, root: false)
|
919
|
+
add_type_and_traverse(new_orphan_types, root: false) unless use_schema_subset?
|
891
920
|
own_orphan_types.concat(new_orphan_types.flatten)
|
892
921
|
end
|
893
922
|
|
@@ -1053,6 +1082,10 @@ module GraphQL
|
|
1053
1082
|
Member::HasDirectives.get_directives(self, @own_schema_directives, :schema_directives)
|
1054
1083
|
end
|
1055
1084
|
|
1085
|
+
# Called when a type is needed by name at runtime
|
1086
|
+
def load_type(type_name, ctx)
|
1087
|
+
get_type(type_name, ctx)
|
1088
|
+
end
|
1056
1089
|
# This hook is called when an object fails an `authorized?` check.
|
1057
1090
|
# You might report to your bug tracker here, so you can correct
|
1058
1091
|
# the field resolvers not to return unauthorized objects.
|
@@ -1142,7 +1175,11 @@ module GraphQL
|
|
1142
1175
|
# @param new_directive [Class]
|
1143
1176
|
# @return void
|
1144
1177
|
def directive(new_directive)
|
1145
|
-
|
1178
|
+
if use_schema_subset?
|
1179
|
+
own_directives[new_directive.graphql_name] = new_directive
|
1180
|
+
else
|
1181
|
+
add_type_and_traverse(new_directive, root: false)
|
1182
|
+
end
|
1146
1183
|
end
|
1147
1184
|
|
1148
1185
|
def default_directives
|
@@ -1485,7 +1522,7 @@ module GraphQL
|
|
1485
1522
|
end
|
1486
1523
|
|
1487
1524
|
def own_references_to
|
1488
|
-
@own_references_to ||= {}.
|
1525
|
+
@own_references_to ||= {}.compare_by_identity
|
1489
1526
|
end
|
1490
1527
|
|
1491
1528
|
def non_introspection_types
|
@@ -1501,7 +1538,7 @@ module GraphQL
|
|
1501
1538
|
end
|
1502
1539
|
|
1503
1540
|
def own_possible_types
|
1504
|
-
@own_possible_types ||= {}.
|
1541
|
+
@own_possible_types ||= {}.compare_by_identity
|
1505
1542
|
end
|
1506
1543
|
|
1507
1544
|
def own_union_memberships
|
@@ -10,6 +10,7 @@ module GraphQL
|
|
10
10
|
@argument_definitions = []
|
11
11
|
@directive_definitions = []
|
12
12
|
@context = context
|
13
|
+
@types = context.query.types
|
13
14
|
@schema = context.schema
|
14
15
|
super(document)
|
15
16
|
end
|
@@ -77,7 +78,7 @@ module GraphQL
|
|
77
78
|
|
78
79
|
def on_field(node, parent)
|
79
80
|
parent_type = @object_types.last
|
80
|
-
field_definition = @
|
81
|
+
field_definition = @types.field(parent_type, node.name)
|
81
82
|
@field_definitions.push(field_definition)
|
82
83
|
if !field_definition.nil?
|
83
84
|
next_object_type = field_definition.type.unwrap
|
@@ -103,14 +104,14 @@ module GraphQL
|
|
103
104
|
argument_defn = if (arg = @argument_definitions.last)
|
104
105
|
arg_type = arg.type.unwrap
|
105
106
|
if arg_type.kind.input_object?
|
106
|
-
@
|
107
|
+
@types.argument(arg_type, node.name)
|
107
108
|
else
|
108
109
|
nil
|
109
110
|
end
|
110
111
|
elsif (directive_defn = @directive_definitions.last)
|
111
|
-
@
|
112
|
+
@types.argument(directive_defn, node.name)
|
112
113
|
elsif (field_defn = @field_definitions.last)
|
113
|
-
@
|
114
|
+
@types.argument(field_defn, node.name)
|
114
115
|
else
|
115
116
|
nil
|
116
117
|
end
|
@@ -170,7 +171,7 @@ module GraphQL
|
|
170
171
|
|
171
172
|
def on_fragment_with_type(node)
|
172
173
|
object_type = if node.type
|
173
|
-
@
|
174
|
+
@types.type(node.type.name)
|
174
175
|
else
|
175
176
|
@object_types.last
|
176
177
|
end
|
@@ -5,7 +5,7 @@ module GraphQL
|
|
5
5
|
class LiteralValidator
|
6
6
|
def initialize(context:)
|
7
7
|
@context = context
|
8
|
-
@
|
8
|
+
@types = context.types
|
9
9
|
@invalid_response = GraphQL::Query::InputValidationResult.new(valid: false, problems: [])
|
10
10
|
@valid_response = GraphQL::Query::InputValidationResult.new(valid: true, problems: [])
|
11
11
|
end
|
@@ -109,7 +109,7 @@ module GraphQL
|
|
109
109
|
def required_input_fields_are_present(type, ast_node)
|
110
110
|
# TODO - would be nice to use these to create an error message so the caller knows
|
111
111
|
# that required fields are missing
|
112
|
-
required_field_names = @
|
112
|
+
required_field_names = @types.arguments(type)
|
113
113
|
.select { |argument| argument.type.kind.non_null? && !argument.default_value? }
|
114
114
|
.map!(&:name)
|
115
115
|
|
@@ -119,7 +119,7 @@ module GraphQL
|
|
119
119
|
missing_required_field_names.empty? ? @valid_response : @invalid_response
|
120
120
|
else
|
121
121
|
results = missing_required_field_names.map do |name|
|
122
|
-
arg_type = @
|
122
|
+
arg_type = @types.argument(type, name).type
|
123
123
|
recursively_validate(GraphQL::Language::Nodes::NullValue.new(name: name), arg_type)
|
124
124
|
end
|
125
125
|
if type.one_of? && ast_node.arguments.size != 1
|
@@ -131,7 +131,7 @@ module GraphQL
|
|
131
131
|
|
132
132
|
def present_input_field_values_are_valid(type, ast_node)
|
133
133
|
results = ast_node.arguments.map do |value|
|
134
|
-
field = @
|
134
|
+
field = @types.argument(type, value.name)
|
135
135
|
# we want to call validate on an argument even if it's an invalid one
|
136
136
|
# so that our raise exception is on it instead of the entire InputObject
|
137
137
|
field_type = field && field.type
|
@@ -15,7 +15,7 @@ module GraphQL
|
|
15
15
|
if @context.schema.error_bubbling || context.errors.none? { |err| err.path.take(@path.size) == @path }
|
16
16
|
parent_defn = parent_definition(parent)
|
17
17
|
|
18
|
-
if parent_defn && (arg_defn =
|
18
|
+
if parent_defn && (arg_defn = @types.argument(parent_defn, node.name))
|
19
19
|
validation_result = context.validate_literal(node.value, arg_defn.type)
|
20
20
|
if !validation_result.valid?
|
21
21
|
kind_of_node = node_type(parent)
|
@@ -5,7 +5,7 @@ module GraphQL
|
|
5
5
|
def on_argument(node, parent)
|
6
6
|
parent_defn = parent_definition(parent)
|
7
7
|
|
8
|
-
if parent_defn &&
|
8
|
+
if parent_defn && @types.argument(parent_defn, node.name)
|
9
9
|
super
|
10
10
|
elsif parent_defn
|
11
11
|
kind_of_node = node_type(parent)
|
@@ -4,11 +4,10 @@ module GraphQL
|
|
4
4
|
module DirectivesAreDefined
|
5
5
|
def initialize(*)
|
6
6
|
super
|
7
|
-
@directive_names = context.warden.directives.map(&:graphql_name)
|
8
7
|
end
|
9
8
|
|
10
9
|
def on_directive(node, parent)
|
11
|
-
if !@
|
10
|
+
if !@types.directive_exists?(node.name)
|
12
11
|
@directives_are_defined_errors_by_name ||= {}
|
13
12
|
error = @directives_are_defined_errors_by_name[node.name] ||= begin
|
14
13
|
err = GraphQL::StaticValidation::DirectivesAreDefinedError.new(
|
@@ -4,7 +4,7 @@ module GraphQL
|
|
4
4
|
module FieldsAreDefinedOnType
|
5
5
|
def on_field(node, parent)
|
6
6
|
parent_type = @object_types[-2]
|
7
|
-
field = context.
|
7
|
+
field = context.query.types.field(parent_type, node.name)
|
8
8
|
|
9
9
|
if field.nil?
|
10
10
|
if parent_type.kind.union?
|
@@ -117,8 +117,8 @@ module GraphQL
|
|
117
117
|
|
118
118
|
return if fragment1.nil? || fragment2.nil?
|
119
119
|
|
120
|
-
fragment_type1 = context.
|
121
|
-
fragment_type2 = context.
|
120
|
+
fragment_type1 = context.query.types.type(fragment1.type.name)
|
121
|
+
fragment_type2 = context.query.types.type(fragment2.type.name)
|
122
122
|
|
123
123
|
return if fragment_type1.nil? || fragment_type2.nil?
|
124
124
|
|
@@ -170,7 +170,7 @@ module GraphQL
|
|
170
170
|
fragment = context.fragments[fragment_name]
|
171
171
|
return if fragment.nil?
|
172
172
|
|
173
|
-
fragment_type =
|
173
|
+
fragment_type = @types.type(fragment.type.name)
|
174
174
|
return if fragment_type.nil?
|
175
175
|
|
176
176
|
fragment_fields, fragment_spreads = fields_and_fragments_from_selection(fragment, owner_type: fragment_type, parents: [*fragment_spread.parents, fragment_type])
|
@@ -340,10 +340,10 @@ module GraphQL
|
|
340
340
|
selections.each do |node|
|
341
341
|
case node
|
342
342
|
when GraphQL::Language::Nodes::Field
|
343
|
-
definition =
|
343
|
+
definition = @types.field(owner_type, node.name)
|
344
344
|
fields << Field.new(node, definition, owner_type, parents)
|
345
345
|
when GraphQL::Language::Nodes::InlineFragment
|
346
|
-
fragment_type = node.type ?
|
346
|
+
fragment_type = node.type ? @types.type(node.type.name) : owner_type
|
347
347
|
find_fields_and_fragments(node.selections, parents: [*parents, fragment_type], owner_type: owner_type, fields: fields, fragment_spreads: fragment_spreads) if fragment_type
|
348
348
|
when GraphQL::Language::Nodes::FragmentSpread
|
349
349
|
fragment_spreads << FragmentSpread.new(node.name, parents)
|
@@ -411,8 +411,8 @@ module GraphQL
|
|
411
411
|
false
|
412
412
|
else
|
413
413
|
# Check if these two scopes have _any_ types in common.
|
414
|
-
possible_right_types = context.
|
415
|
-
possible_left_types = context.
|
414
|
+
possible_right_types = context.types.possible_types(type1)
|
415
|
+
possible_left_types = context.types.possible_types(type2)
|
416
416
|
(possible_right_types & possible_left_types).empty?
|
417
417
|
end
|
418
418
|
end
|
@@ -28,7 +28,7 @@ module GraphQL
|
|
28
28
|
frag_node = context.fragments[frag_spread.node.name]
|
29
29
|
if frag_node
|
30
30
|
fragment_child_name = frag_node.type.name
|
31
|
-
fragment_child =
|
31
|
+
fragment_child = @types.type(fragment_child_name)
|
32
32
|
# Might be non-existent type name
|
33
33
|
if fragment_child
|
34
34
|
validate_fragment_in_scope(frag_spread.parent_type, fragment_child, frag_spread.node, context, frag_spread.path)
|
@@ -44,8 +44,8 @@ module GraphQL
|
|
44
44
|
# It's not a valid fragment type, this error was handled someplace else
|
45
45
|
return
|
46
46
|
end
|
47
|
-
parent_types =
|
48
|
-
child_types =
|
47
|
+
parent_types = @types.possible_types(parent_type.unwrap)
|
48
|
+
child_types = @types.possible_types(child_type.unwrap)
|
49
49
|
|
50
50
|
if child_types.none? { |c| parent_types.include?(c) }
|
51
51
|
name = node.respond_to?(:name) ? " #{node.name}" : ""
|
@@ -21,7 +21,7 @@ module GraphQL
|
|
21
21
|
true
|
22
22
|
else
|
23
23
|
type_name = fragment_node.type.name
|
24
|
-
type =
|
24
|
+
type = @types.type(type_name)
|
25
25
|
if type.nil?
|
26
26
|
add_error(GraphQL::StaticValidation::FragmentTypesExistError.new(
|
27
27
|
"No such type #{type_name}, so it can't be a fragment condition",
|
@@ -19,7 +19,7 @@ module GraphQL
|
|
19
19
|
true
|
20
20
|
else
|
21
21
|
type_name = node_type.to_query_string
|
22
|
-
type_def =
|
22
|
+
type_def = @types.type(type_name)
|
23
23
|
if type_def.nil? || !type_def.kind.composite?
|
24
24
|
add_error(GraphQL::StaticValidation::FragmentsAreOnCompositeTypesError.new(
|
25
25
|
"Invalid fragment on type #{type_name} (must be Union, Interface or Object)",
|
@@ -3,7 +3,7 @@ module GraphQL
|
|
3
3
|
module StaticValidation
|
4
4
|
module MutationRootExists
|
5
5
|
def on_operation_definition(node, _parent)
|
6
|
-
if node.operation_type == 'mutation' && context.
|
6
|
+
if node.operation_type == 'mutation' && context.query.types.mutation_root.nil?
|
7
7
|
add_error(GraphQL::StaticValidation::MutationRootExistsError.new(
|
8
8
|
'Schema is not configured for mutations',
|
9
9
|
nodes: node
|
@@ -3,7 +3,7 @@ module GraphQL
|
|
3
3
|
module StaticValidation
|
4
4
|
module QueryRootExists
|
5
5
|
def on_operation_definition(node, _parent)
|
6
|
-
if (node.operation_type == 'query' || node.operation_type.nil?) && context.
|
6
|
+
if (node.operation_type == 'query' || node.operation_type.nil?) && context.query.types.query_root.nil?
|
7
7
|
add_error(GraphQL::StaticValidation::QueryRootExistsError.new(
|
8
8
|
'Schema is not configured for queries',
|
9
9
|
nodes: node
|