graphql 2.4.0 → 2.4.2
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/graphql/query/null_context.rb +3 -5
- data/lib/graphql/schema/enum.rb +17 -3
- data/lib/graphql/schema/enum_value.rb +1 -1
- data/lib/graphql/schema/visibility/migration.rb +2 -1
- data/lib/graphql/schema/visibility/profile.rb +9 -5
- data/lib/graphql/schema/visibility.rb +68 -0
- data/lib/graphql/schema/warden.rb +13 -9
- data/lib/graphql/schema.rb +38 -3
- data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +10 -1
- data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +2 -2
- data/lib/graphql/testing/helpers.rb +1 -1
- data/lib/graphql/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bbf9779d0fbc1da481a481d987489b980818c5ea6afb352f4e65f0654ea14163
|
4
|
+
data.tar.gz: 91528aabb657b8602c7f3143b6a9dc3a770a336f6a31af0f89fce1c27e5e00a0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c73cedf9cd1fc6ab4d91f026dfe627cb1490d5888d1252f591b944359e1f537a479c5d7f7ceed691ddd79883ae1ba027dfb952e969d14617e6a19becee792aa6
|
7
|
+
data.tar.gz: 4d429bb74350c9fbbaa0e33498ccb193acfa6691f62342b38923965e69bc23bb377e6ade8a56b8f5d5c785ea24a2f6e04a47a8384000a45140d320e7461c6832
|
@@ -18,17 +18,15 @@ module GraphQL
|
|
18
18
|
extend Forwardable
|
19
19
|
|
20
20
|
attr_reader :schema, :query, :warden, :dataloader
|
21
|
-
def_delegators GraphQL::EmptyObjects::EMPTY_HASH, :[], :fetch, :dig, :key
|
21
|
+
def_delegators GraphQL::EmptyObjects::EMPTY_HASH, :[], :fetch, :dig, :key?, :to_h
|
22
22
|
|
23
23
|
def initialize
|
24
24
|
@query = NullQuery.new
|
25
25
|
@dataloader = GraphQL::Dataloader::NullDataloader.new
|
26
26
|
@schema = NullSchema
|
27
27
|
@warden = Schema::Warden::NullWarden.new(context: self, schema: @schema)
|
28
|
-
|
29
|
-
|
30
|
-
def types
|
31
|
-
@types ||= Schema::Warden::VisibilityProfile.new(@warden)
|
28
|
+
@types = @warden.visibility_profile
|
29
|
+
freeze
|
32
30
|
end
|
33
31
|
end
|
34
32
|
end
|
data/lib/graphql/schema/enum.rb
CHANGED
@@ -86,10 +86,24 @@ module GraphQL
|
|
86
86
|
def enum_values(context = GraphQL::Query::NullContext.instance)
|
87
87
|
inherited_values = superclass.respond_to?(:enum_values) ? superclass.enum_values(context) : nil
|
88
88
|
visible_values = []
|
89
|
-
|
89
|
+
types = Warden.types_from_context(context)
|
90
90
|
own_values.each do |key, values_entry|
|
91
|
-
|
92
|
-
|
91
|
+
visible_value = nil
|
92
|
+
if values_entry.is_a?(Array)
|
93
|
+
values_entry.each do |v|
|
94
|
+
if types.visible_enum_value?(v, context)
|
95
|
+
if visible_value.nil?
|
96
|
+
visible_value = v
|
97
|
+
visible_values << v
|
98
|
+
else
|
99
|
+
raise DuplicateNamesError.new(
|
100
|
+
duplicated_name: v.path, duplicated_definition_1: visible_value.inspect, duplicated_definition_2: v.inspect
|
101
|
+
)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
elsif types.visible_enum_value?(values_entry, context)
|
106
|
+
visible_values << values_entry
|
93
107
|
end
|
94
108
|
end
|
95
109
|
|
@@ -74,7 +74,7 @@ module GraphQL
|
|
74
74
|
end
|
75
75
|
|
76
76
|
def inspect
|
77
|
-
"#<#{self.class} #{path} @value=#{@value.inspect}#{description ? " @description=#{description.inspect}" : ""}>"
|
77
|
+
"#<#{self.class} #{path} @value=#{@value.inspect}#{description ? " @description=#{description.inspect}" : ""}#{deprecation_reason ? " @deprecation_reason=#{deprecation_reason.inspect}" : ""}>"
|
78
78
|
end
|
79
79
|
|
80
80
|
def visible?(_ctx); true; end
|
@@ -22,9 +22,9 @@ module GraphQL
|
|
22
22
|
end
|
23
23
|
end
|
24
24
|
|
25
|
-
def self.
|
26
|
-
profile = self.new(context: context, schema: schema)
|
27
|
-
profile.instance_variable_set(:@cached_visible, Hash.new { |
|
25
|
+
def self.null_profile(context:, schema:)
|
26
|
+
profile = self.new(name: "NullProfile", context: context, schema: schema)
|
27
|
+
profile.instance_variable_set(:@cached_visible, Hash.new { |k, v| k[v] = true }.compare_by_identity)
|
28
28
|
profile
|
29
29
|
end
|
30
30
|
|
@@ -123,7 +123,7 @@ module GraphQL
|
|
123
123
|
end.compare_by_identity
|
124
124
|
|
125
125
|
@cached_enum_values = Hash.new do |h, enum_t|
|
126
|
-
values = non_duplicate_items(enum_t.
|
126
|
+
values = non_duplicate_items(enum_t.enum_values(@context), @cached_visible)
|
127
127
|
if values.size == 0
|
128
128
|
raise GraphQL::Schema::Enum::MissingValuesError.new(enum_t)
|
129
129
|
end
|
@@ -327,6 +327,10 @@ module GraphQL
|
|
327
327
|
!!@all_types[name]
|
328
328
|
end
|
329
329
|
|
330
|
+
def visible_enum_value?(enum_value, _ctx = nil)
|
331
|
+
@cached_visible[enum_value]
|
332
|
+
end
|
333
|
+
|
330
334
|
private
|
331
335
|
|
332
336
|
def add_if_visible(t)
|
@@ -400,7 +404,7 @@ module GraphQL
|
|
400
404
|
end
|
401
405
|
end
|
402
406
|
|
403
|
-
entry_point_types.compact! #
|
407
|
+
entry_point_types.compact! # Root types might be nil
|
404
408
|
entry_point_types.flatten! # handle multiple defns
|
405
409
|
entry_point_types.each { |t| add_type(t, true) }
|
406
410
|
|
@@ -21,11 +21,27 @@ module GraphQL
|
|
21
21
|
if migration_errors
|
22
22
|
schema.visibility_profile_class = Migration
|
23
23
|
end
|
24
|
+
@preload = preload
|
24
25
|
@profiles = profiles
|
25
26
|
@cached_profiles = {}
|
26
27
|
@dynamic = dynamic
|
27
28
|
@migration_errors = migration_errors
|
28
29
|
if preload
|
30
|
+
# Traverse the schema now (and in the *_configured hooks below)
|
31
|
+
# To make sure things are loaded during boot
|
32
|
+
@preloaded_types = Set.new
|
33
|
+
types_to_visit = [
|
34
|
+
@schema.query,
|
35
|
+
@schema.mutation,
|
36
|
+
@schema.subscription,
|
37
|
+
*@schema.introspection_system.types.values,
|
38
|
+
*@schema.introspection_system.entry_points.map { |ep| ep.type.unwrap },
|
39
|
+
*@schema.orphan_types,
|
40
|
+
]
|
41
|
+
# Root types may have been nil:
|
42
|
+
types_to_visit.compact!
|
43
|
+
ensure_all_loaded(types_to_visit)
|
44
|
+
|
29
45
|
profiles.each do |profile_name, example_ctx|
|
30
46
|
example_ctx[:visibility_profile] = profile_name
|
31
47
|
prof = profile_for(example_ctx, profile_name)
|
@@ -34,6 +50,45 @@ module GraphQL
|
|
34
50
|
end
|
35
51
|
end
|
36
52
|
|
53
|
+
# @api private
|
54
|
+
def query_configured(query_type)
|
55
|
+
if @preload
|
56
|
+
ensure_all_loaded([query_type])
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# @api private
|
61
|
+
def mutation_configured(mutation_type)
|
62
|
+
if @preload
|
63
|
+
ensure_all_loaded([mutation_type])
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
# @api private
|
68
|
+
def subscription_configured(subscription_type)
|
69
|
+
if @preload
|
70
|
+
ensure_all_loaded([subscription_type])
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
# @api private
|
75
|
+
def orphan_types_configured(orphan_types)
|
76
|
+
if @preload
|
77
|
+
ensure_all_loaded(orphan_types)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
# @api private
|
82
|
+
def introspection_system_configured(introspection_system)
|
83
|
+
if @preload
|
84
|
+
introspection_types = [
|
85
|
+
*@schema.introspection_system.types.values,
|
86
|
+
*@schema.introspection_system.entry_points.map { |ep| ep.type.unwrap },
|
87
|
+
]
|
88
|
+
ensure_all_loaded(introspection_types)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
37
92
|
# Make another Visibility for `schema` based on this one
|
38
93
|
# @return [Visibility]
|
39
94
|
# @api private
|
@@ -70,6 +125,19 @@ module GraphQL
|
|
70
125
|
@schema.visibility_profile_class.new(context: context, schema: @schema)
|
71
126
|
end
|
72
127
|
end
|
128
|
+
|
129
|
+
private
|
130
|
+
|
131
|
+
def ensure_all_loaded(types_to_visit)
|
132
|
+
while (type = types_to_visit.shift)
|
133
|
+
if type.kind.fields? && @preloaded_types.add?(type)
|
134
|
+
type.all_field_definitions.each do |field_defn|
|
135
|
+
field_defn.ensure_loaded
|
136
|
+
types_to_visit << field_defn.type.unwrap
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
73
141
|
end
|
74
142
|
end
|
75
143
|
end
|
@@ -19,6 +19,13 @@ module GraphQL
|
|
19
19
|
PassThruWarden
|
20
20
|
end
|
21
21
|
|
22
|
+
def self.types_from_context(context)
|
23
|
+
context.types || PassThruWarden
|
24
|
+
rescue NoMethodError
|
25
|
+
# this might be a hash which won't respond to #warden
|
26
|
+
PassThruWarden
|
27
|
+
end
|
28
|
+
|
22
29
|
def self.use(schema)
|
23
30
|
# no-op
|
24
31
|
end
|
@@ -80,24 +87,17 @@ module GraphQL
|
|
80
87
|
# No-op, but for compatibility:
|
81
88
|
attr_writer :skip_warning
|
82
89
|
|
83
|
-
# @api private
|
84
|
-
module NullVisibilityProfile
|
85
|
-
def self.new(context:, schema:)
|
86
|
-
NullWarden.new(context: context, schema: schema).visibility_profile
|
87
|
-
end
|
88
|
-
end
|
89
|
-
|
90
90
|
attr_reader :visibility_profile
|
91
91
|
|
92
92
|
def visible_field?(field_defn, _ctx = nil, owner = nil); true; end
|
93
93
|
def visible_argument?(arg_defn, _ctx = nil); true; end
|
94
94
|
def visible_type?(type_defn, _ctx = nil); true; end
|
95
|
-
def visible_enum_value?(enum_value, _ctx = nil);
|
95
|
+
def visible_enum_value?(enum_value, _ctx = nil); enum_value.visible?(Query::NullContext.instance); end
|
96
96
|
def visible_type_membership?(type_membership, _ctx = nil); true; end
|
97
97
|
def interface_type_memberships(obj_type, _ctx = nil); obj_type.interface_type_memberships; end
|
98
98
|
def get_type(type_name); @schema.get_type(type_name, Query::NullContext.instance, false); end # rubocop:disable Development/ContextIsPassedCop
|
99
99
|
def arguments(argument_owner, ctx = nil); argument_owner.all_argument_definitions; end
|
100
|
-
def enum_values(enum_defn); enum_defn.enum_values; end # rubocop:disable Development/ContextIsPassedCop
|
100
|
+
def enum_values(enum_defn); enum_defn.enum_values(Query::NullContext.instance); end # rubocop:disable Development/ContextIsPassedCop
|
101
101
|
def get_argument(parent_type, argument_name); parent_type.get_argument(argument_name); end # rubocop:disable Development/ContextIsPassedCop
|
102
102
|
def types; @schema.types; end # rubocop:disable Development/ContextIsPassedCop
|
103
103
|
def root_type_for_operation(op_name); @schema.root_type_for_operation(op_name); end
|
@@ -183,6 +183,10 @@ module GraphQL
|
|
183
183
|
def reachable_type?(type_name)
|
184
184
|
!!@warden.reachable_type?(type_name)
|
185
185
|
end
|
186
|
+
|
187
|
+
def visible_enum_value?(enum_value, ctx = nil)
|
188
|
+
@warden.visible_enum_value?(enum_value, ctx)
|
189
|
+
end
|
186
190
|
end
|
187
191
|
|
188
192
|
# @param context [GraphQL::Query::Context]
|
data/lib/graphql/schema.rb
CHANGED
@@ -445,7 +445,12 @@ module GraphQL
|
|
445
445
|
dup_defn = new_query_object || yield
|
446
446
|
raise GraphQL::Error, "Second definition of `query(...)` (#{dup_defn.inspect}) is invalid, already configured with #{@query_object.inspect}"
|
447
447
|
elsif use_visibility_profile?
|
448
|
-
|
448
|
+
if block_given?
|
449
|
+
@query_object = lazy_load_block
|
450
|
+
else
|
451
|
+
@query_object = new_query_object
|
452
|
+
self.visibility.query_configured(@query_object)
|
453
|
+
end
|
449
454
|
else
|
450
455
|
@query_object = new_query_object || lazy_load_block.call
|
451
456
|
add_type_and_traverse(@query_object, root: true)
|
@@ -453,6 +458,8 @@ module GraphQL
|
|
453
458
|
nil
|
454
459
|
elsif @query_object.is_a?(Proc)
|
455
460
|
@query_object = @query_object.call
|
461
|
+
self.visibility&.query_configured(@query_object)
|
462
|
+
@query_object
|
456
463
|
else
|
457
464
|
@query_object || find_inherited_value(:query)
|
458
465
|
end
|
@@ -472,7 +479,12 @@ module GraphQL
|
|
472
479
|
dup_defn = new_mutation_object || yield
|
473
480
|
raise GraphQL::Error, "Second definition of `mutation(...)` (#{dup_defn.inspect}) is invalid, already configured with #{@mutation_object.inspect}"
|
474
481
|
elsif use_visibility_profile?
|
475
|
-
|
482
|
+
if block_given?
|
483
|
+
@mutation_object = lazy_load_block
|
484
|
+
else
|
485
|
+
@mutation_object = new_mutation_object
|
486
|
+
self.visibility.mutation_configured(@mutation_object)
|
487
|
+
end
|
476
488
|
else
|
477
489
|
@mutation_object = new_mutation_object || lazy_load_block.call
|
478
490
|
add_type_and_traverse(@mutation_object, root: true)
|
@@ -480,6 +492,8 @@ module GraphQL
|
|
480
492
|
nil
|
481
493
|
elsif @mutation_object.is_a?(Proc)
|
482
494
|
@mutation_object = @mutation_object.call
|
495
|
+
self.visibility&.mutation_configured(@query_object)
|
496
|
+
@mutation_object
|
483
497
|
else
|
484
498
|
@mutation_object || find_inherited_value(:mutation)
|
485
499
|
end
|
@@ -499,7 +513,12 @@ module GraphQL
|
|
499
513
|
dup_defn = new_subscription_object || yield
|
500
514
|
raise GraphQL::Error, "Second definition of `subscription(...)` (#{dup_defn.inspect}) is invalid, already configured with #{@subscription_object.inspect}"
|
501
515
|
elsif use_visibility_profile?
|
502
|
-
|
516
|
+
if block_given?
|
517
|
+
@subscription_object = lazy_load_block
|
518
|
+
else
|
519
|
+
@subscription_object = new_subscription_object
|
520
|
+
self.visibility.subscription_configured(@subscription_object)
|
521
|
+
end
|
503
522
|
add_subscription_extension_if_necessary
|
504
523
|
else
|
505
524
|
@subscription_object = new_subscription_object || lazy_load_block.call
|
@@ -510,6 +529,7 @@ module GraphQL
|
|
510
529
|
elsif @subscription_object.is_a?(Proc)
|
511
530
|
@subscription_object = @subscription_object.call
|
512
531
|
add_subscription_extension_if_necessary
|
532
|
+
self.visibility.subscription_configured(@subscription_object)
|
513
533
|
@subscription_object
|
514
534
|
else
|
515
535
|
@subscription_object || find_inherited_value(:subscription)
|
@@ -695,20 +715,27 @@ module GraphQL
|
|
695
715
|
type.fields(context)
|
696
716
|
end
|
697
717
|
|
718
|
+
# Pass a custom introspection module here to use it for this schema.
|
719
|
+
# @param new_introspection_namespace [Module] If given, use this module for custom introspection on the schema
|
720
|
+
# @return [Module, nil] The configured namespace, if there is one
|
698
721
|
def introspection(new_introspection_namespace = nil)
|
699
722
|
if new_introspection_namespace
|
700
723
|
@introspection = new_introspection_namespace
|
701
724
|
# reset this cached value:
|
702
725
|
@introspection_system = nil
|
726
|
+
introspection_system
|
727
|
+
@introspection
|
703
728
|
else
|
704
729
|
@introspection || find_inherited_value(:introspection)
|
705
730
|
end
|
706
731
|
end
|
707
732
|
|
733
|
+
# @return [Schema::IntrospectionSystem] Based on {introspection}
|
708
734
|
def introspection_system
|
709
735
|
if !@introspection_system
|
710
736
|
@introspection_system = Schema::IntrospectionSystem.new(self)
|
711
737
|
@introspection_system.resolve_late_bindings
|
738
|
+
self.visibility&.introspection_system_configured(@introspection_system)
|
712
739
|
end
|
713
740
|
@introspection_system
|
714
741
|
end
|
@@ -952,6 +979,13 @@ module GraphQL
|
|
952
979
|
end
|
953
980
|
end
|
954
981
|
|
982
|
+
# Tell the schema about these types so that they can be registered as implementations of interfaces in the schema.
|
983
|
+
#
|
984
|
+
# This method must be used when an object type is connected to the schema as an interface implementor but
|
985
|
+
# not as a return type of a field. In that case, if the object type isn't registered here, GraphQL-Ruby won't be able to find it.
|
986
|
+
#
|
987
|
+
# @param new_orphan_types [Array<Class<GraphQL::Schema::Object>>] Object types to register as implementations of interfaces in the schema.
|
988
|
+
# @return [Array<Class<GraphQL::Schema::Object>>] All previously-registered orphan types for this schema
|
955
989
|
def orphan_types(*new_orphan_types)
|
956
990
|
if new_orphan_types.any?
|
957
991
|
new_orphan_types = new_orphan_types.flatten
|
@@ -968,6 +1002,7 @@ module GraphQL
|
|
968
1002
|
end
|
969
1003
|
add_type_and_traverse(new_orphan_types, root: false) unless use_visibility_profile?
|
970
1004
|
own_orphan_types.concat(new_orphan_types.flatten)
|
1005
|
+
self.visibility&.orphan_types_configured(new_orphan_types)
|
971
1006
|
end
|
972
1007
|
|
973
1008
|
inherited_ot = find_inherited_value(:orphan_types, nil)
|
@@ -14,7 +14,9 @@ module GraphQL
|
|
14
14
|
node_name: parent_type.graphql_name
|
15
15
|
))
|
16
16
|
else
|
17
|
-
|
17
|
+
possible_fields = possible_fields(context, parent_type)
|
18
|
+
suggestion = context.did_you_mean_suggestion(node.name, possible_fields)
|
19
|
+
message = "Field '#{node.name}' doesn't exist on type '#{parent_type.graphql_name}'#{suggestion}"
|
18
20
|
add_error(GraphQL::StaticValidation::FieldsAreDefinedOnTypeError.new(
|
19
21
|
message,
|
20
22
|
nodes: node,
|
@@ -26,6 +28,13 @@ module GraphQL
|
|
26
28
|
super
|
27
29
|
end
|
28
30
|
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def possible_fields(context, parent_type)
|
35
|
+
return EmptyObjects::EMPTY_ARRAY if parent_type.kind.leaf?
|
36
|
+
context.types.fields(parent_type).map(&:graphql_name)
|
37
|
+
end
|
29
38
|
end
|
30
39
|
end
|
31
40
|
end
|
@@ -25,7 +25,7 @@ module GraphQL
|
|
25
25
|
def validate_field_selections(ast_node, resolved_type)
|
26
26
|
msg = if resolved_type.nil?
|
27
27
|
nil
|
28
|
-
elsif
|
28
|
+
elsif ast_node.selections.any? && resolved_type.kind.leaf?
|
29
29
|
selection_strs = ast_node.selections.map do |n|
|
30
30
|
case n
|
31
31
|
when GraphQL::Language::Nodes::InlineFragment
|
@@ -38,7 +38,7 @@ module GraphQL
|
|
38
38
|
raise "Invariant: unexpected selection node: #{n}"
|
39
39
|
end
|
40
40
|
end
|
41
|
-
"Selections can't be made on
|
41
|
+
"Selections can't be made on #{resolved_type.kind.name.sub("_", " ").downcase}s (%{node_name} returns #{resolved_type.graphql_name} but has selections [#{selection_strs.join(", ")}])"
|
42
42
|
elsif resolved_type.kind.fields? && ast_node.selections.empty?
|
43
43
|
"Field must have selections (%{node_name} returns #{resolved_type.graphql_name} but has no selections. Did you mean '#{ast_node.name} { ... }'?)"
|
44
44
|
else
|
@@ -92,7 +92,7 @@ module GraphQL
|
|
92
92
|
end
|
93
93
|
graphql_result
|
94
94
|
else
|
95
|
-
unfiltered_type = Schema::Visibility::Profile.
|
95
|
+
unfiltered_type = Schema::Visibility::Profile.null_profile(schema: schema, context: context).type(type_name)
|
96
96
|
if unfiltered_type
|
97
97
|
raise TypeNotVisibleError.new(type_name: type_name)
|
98
98
|
else
|
data/lib/graphql/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: graphql
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.4.
|
4
|
+
version: 2.4.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Robert Mosolgo
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-11-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: base64
|