graphql 2.3.14 → 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/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.rb +1 -1
- data/lib/graphql/dataloader/async_dataloader.rb +3 -2
- data/lib/graphql/dataloader/source.rb +1 -1
- data/lib/graphql/dataloader.rb +31 -10
- data/lib/graphql/execution/interpreter/resolve.rb +10 -6
- 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 +38 -4
- data/lib/graphql/language/lexer.rb +15 -12
- data/lib/graphql/language/nodes.rb +22 -14
- data/lib/graphql/language/parser.rb +5 -0
- data/lib/graphql/language/printer.rb +23 -7
- data/lib/graphql/language.rb +6 -5
- data/lib/graphql/query/null_context.rb +1 -1
- data/lib/graphql/query.rb +49 -16
- data/lib/graphql/rubocop/graphql/field_type_in_block.rb +23 -8
- data/lib/graphql/schema/always_visible.rb +6 -3
- data/lib/graphql/schema/argument.rb +14 -1
- data/lib/graphql/schema/build_from_definition.rb +1 -0
- data/lib/graphql/schema/enum.rb +3 -0
- data/lib/graphql/schema/enum_value.rb +9 -1
- data/lib/graphql/schema/field.rb +35 -14
- data/lib/graphql/schema/input_object.rb +20 -7
- data/lib/graphql/schema/interface.rb +1 -0
- data/lib/graphql/schema/member/base_dsl_methods.rb +15 -0
- data/lib/graphql/schema/member/has_arguments.rb +2 -2
- data/lib/graphql/schema/member/has_fields.rb +2 -2
- data/lib/graphql/schema/printer.rb +1 -0
- data/lib/graphql/schema/resolver.rb +3 -4
- data/lib/graphql/schema/validator/required_validator.rb +28 -4
- 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 +77 -15
- data/lib/graphql/schema.rb +203 -61
- data/lib/graphql/static_validation/rules/arguments_are_defined.rb +2 -1
- data/lib/graphql/static_validation/rules/directives_are_defined.rb +2 -1
- 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 +2 -1
- data/lib/graphql/static_validation/rules/fields_will_merge.rb +1 -0
- data/lib/graphql/static_validation/rules/fragment_types_exist.rb +11 -1
- data/lib/graphql/static_validation/rules/variables_are_input_types.rb +10 -1
- data/lib/graphql/static_validation/validation_context.rb +15 -0
- data/lib/graphql/subscriptions/action_cable_subscriptions.rb +2 -1
- data/lib/graphql/subscriptions.rb +3 -1
- data/lib/graphql/testing/helpers.rb +2 -1
- data/lib/graphql/tracing/notifications_trace.rb +2 -2
- data/lib/graphql/version.rb +1 -1
- metadata +11 -9
- data/lib/graphql/schema/subset.rb +0 -509
- data/lib/graphql/schema/types_migration.rb +0 -187
@@ -250,6 +250,8 @@ module GraphQL
|
|
250
250
|
def normalize_arguments(event_name, arg_owner, args, context)
|
251
251
|
case arg_owner
|
252
252
|
when GraphQL::Schema::Field, Class
|
253
|
+
return args if args.nil?
|
254
|
+
|
253
255
|
if arg_owner.is_a?(Class) && !arg_owner.kind.input_object?
|
254
256
|
# it's a type, but not an input object
|
255
257
|
return args
|
@@ -302,7 +304,7 @@ module GraphQL
|
|
302
304
|
|
303
305
|
normalized_args
|
304
306
|
when GraphQL::Schema::List
|
305
|
-
args
|
307
|
+
args&.map { |a| normalize_arguments(event_name, arg_owner.of_type, a, context) }
|
306
308
|
when GraphQL::Schema::NonNull
|
307
309
|
normalize_arguments(event_name, arg_owner.of_type, args, context)
|
308
310
|
else
|
@@ -55,6 +55,7 @@ module GraphQL
|
|
55
55
|
visible_field = dummy_query.types.field(object_type, field_name) # rubocop:disable Development/ContextIsPassedCop
|
56
56
|
if visible_field
|
57
57
|
dummy_query.context.dataloader.run_isolated {
|
58
|
+
query_context[:current_field] = visible_field
|
58
59
|
field_args = visible_field.coerce_arguments(graphql_result, arguments, query_context)
|
59
60
|
field_args = schema.sync_lazy(field_args)
|
60
61
|
if visible_field.extras.any?
|
@@ -91,7 +92,7 @@ module GraphQL
|
|
91
92
|
end
|
92
93
|
graphql_result
|
93
94
|
else
|
94
|
-
unfiltered_type = Schema::
|
95
|
+
unfiltered_type = Schema::Visibility::Profile.pass_thru(schema: schema, context: context).type(type_name)
|
95
96
|
if unfiltered_type
|
96
97
|
raise TypeNotVisibleError.new(type_name: type_name)
|
97
98
|
else
|
@@ -33,8 +33,8 @@ module GraphQL
|
|
33
33
|
"resolve_type_lazy" => "resolve_type.graphql",
|
34
34
|
}.each do |trace_method, platform_key|
|
35
35
|
module_eval <<-RUBY, __FILE__, __LINE__
|
36
|
-
def #{trace_method}(**metadata, &
|
37
|
-
@notifications_engine.instrument("#{platform_key}", metadata, &
|
36
|
+
def #{trace_method}(**metadata, &block)
|
37
|
+
@notifications_engine.instrument("#{platform_key}", metadata) { super(**metadata, &block) }
|
38
38
|
end
|
39
39
|
RUBY
|
40
40
|
end
|
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
|
+
version: 2.4.0
|
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-10-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: base64
|
@@ -168,16 +168,16 @@ dependencies:
|
|
168
168
|
name: rubocop
|
169
169
|
requirement: !ruby/object:Gem::Requirement
|
170
170
|
requirements:
|
171
|
-
- -
|
171
|
+
- - ">="
|
172
172
|
- !ruby/object:Gem::Version
|
173
|
-
version: '
|
173
|
+
version: '0'
|
174
174
|
type: :development
|
175
175
|
prerelease: false
|
176
176
|
version_requirements: !ruby/object:Gem::Requirement
|
177
177
|
requirements:
|
178
|
-
- -
|
178
|
+
- - ">="
|
179
179
|
- !ruby/object:Gem::Version
|
180
|
-
version: '
|
180
|
+
version: '0'
|
181
181
|
- !ruby/object:Gem::Dependency
|
182
182
|
name: jekyll
|
183
183
|
requirement: !ruby/object:Gem::Requirement
|
@@ -382,6 +382,7 @@ files:
|
|
382
382
|
- lib/graphql/language.rb
|
383
383
|
- lib/graphql/language/block_string.rb
|
384
384
|
- lib/graphql/language/cache.rb
|
385
|
+
- lib/graphql/language/comment.rb
|
385
386
|
- lib/graphql/language/definition_slice.rb
|
386
387
|
- lib/graphql/language/document_from_schema_definition.rb
|
387
388
|
- lib/graphql/language/generation.rb
|
@@ -485,11 +486,9 @@ files:
|
|
485
486
|
- lib/graphql/schema/resolver/has_payload_type.rb
|
486
487
|
- lib/graphql/schema/scalar.rb
|
487
488
|
- lib/graphql/schema/subscription.rb
|
488
|
-
- lib/graphql/schema/subset.rb
|
489
489
|
- lib/graphql/schema/timeout.rb
|
490
490
|
- lib/graphql/schema/type_expression.rb
|
491
491
|
- lib/graphql/schema/type_membership.rb
|
492
|
-
- lib/graphql/schema/types_migration.rb
|
493
492
|
- lib/graphql/schema/union.rb
|
494
493
|
- lib/graphql/schema/unique_within_type.rb
|
495
494
|
- lib/graphql/schema/validator.rb
|
@@ -502,6 +501,9 @@ files:
|
|
502
501
|
- lib/graphql/schema/validator/length_validator.rb
|
503
502
|
- lib/graphql/schema/validator/numericality_validator.rb
|
504
503
|
- lib/graphql/schema/validator/required_validator.rb
|
504
|
+
- lib/graphql/schema/visibility.rb
|
505
|
+
- lib/graphql/schema/visibility/migration.rb
|
506
|
+
- lib/graphql/schema/visibility/profile.rb
|
505
507
|
- lib/graphql/schema/warden.rb
|
506
508
|
- lib/graphql/schema/wrapper.rb
|
507
509
|
- lib/graphql/static_validation.rb
|
@@ -663,7 +665,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
663
665
|
- !ruby/object:Gem::Version
|
664
666
|
version: '0'
|
665
667
|
requirements: []
|
666
|
-
rubygems_version: 3.
|
668
|
+
rubygems_version: 3.5.12
|
667
669
|
signing_key:
|
668
670
|
specification_version: 4
|
669
671
|
summary: A GraphQL language and runtime for Ruby
|
@@ -1,509 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module GraphQL
|
4
|
-
class Schema
|
5
|
-
# This class filters the types, fields, arguments, enum values, and directives in a schema
|
6
|
-
# based on the given `context`.
|
7
|
-
#
|
8
|
-
# It's like {Warden}, but has some differences:
|
9
|
-
#
|
10
|
-
# - It doesn't use {Schema}'s top-level caches (eg {Schema.references_to}, {Schema.possible_types}, {Schema.types})
|
11
|
-
# - It doesn't hide Interface or Union types when all their possible types are hidden. (Instead, those types should implement `.visible?` to hide in that case.)
|
12
|
-
# - It checks `.visible?` on root introspection types
|
13
|
-
#
|
14
|
-
# In the future, {Subset} will support lazy-loading types as needed during execution and multi-request caching of subsets.
|
15
|
-
#
|
16
|
-
# @see Schema::TypesMigration for a helper class in adopting this filter
|
17
|
-
class Subset
|
18
|
-
# @return [Schema::Subset]
|
19
|
-
def self.from_context(ctx, schema)
|
20
|
-
if ctx.respond_to?(:types) && (types = ctx.types).is_a?(self)
|
21
|
-
types
|
22
|
-
else
|
23
|
-
# TODO use a cached instance from the schema
|
24
|
-
self.new(context: ctx, schema: schema)
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
def self.pass_thru(context:, schema:)
|
29
|
-
subset = self.new(context: context, schema: schema)
|
30
|
-
subset.instance_variable_set(:@cached_visible, Hash.new { |h,k| h[k] = true })
|
31
|
-
subset
|
32
|
-
end
|
33
|
-
|
34
|
-
def initialize(context:, schema:)
|
35
|
-
@context = context
|
36
|
-
@schema = schema
|
37
|
-
@all_types = {}
|
38
|
-
@all_types_loaded = false
|
39
|
-
@unvisited_types = []
|
40
|
-
@referenced_types = Hash.new { |h, type_defn| h[type_defn] = [] }.compare_by_identity
|
41
|
-
@cached_directives = {}
|
42
|
-
@all_directives = nil
|
43
|
-
@cached_visible = Hash.new { |h, member|
|
44
|
-
h[member] = @schema.visible?(member, @context)
|
45
|
-
}.compare_by_identity
|
46
|
-
|
47
|
-
@cached_visible_fields = Hash.new { |h, owner|
|
48
|
-
h[owner] = Hash.new do |h2, field|
|
49
|
-
h2[field] = if @cached_visible[field] &&
|
50
|
-
(ret_type = field.type.unwrap) &&
|
51
|
-
@cached_visible[ret_type] &&
|
52
|
-
(owner == field.owner || (!owner.kind.object?) || field_on_visible_interface?(field, owner))
|
53
|
-
|
54
|
-
if !field.introspection?
|
55
|
-
# The problem is that some introspection fields may have references
|
56
|
-
# to non-custom introspection types.
|
57
|
-
# If those were added here, they'd cause a DuplicateNamesError.
|
58
|
-
# This is basically a bug -- those fields _should_ reference the custom types.
|
59
|
-
add_type(ret_type, field)
|
60
|
-
end
|
61
|
-
true
|
62
|
-
else
|
63
|
-
false
|
64
|
-
end
|
65
|
-
end.compare_by_identity
|
66
|
-
}.compare_by_identity
|
67
|
-
|
68
|
-
@cached_visible_arguments = Hash.new do |h, arg|
|
69
|
-
h[arg] = if @cached_visible[arg] && (arg_type = arg.type.unwrap) && @cached_visible[arg_type]
|
70
|
-
add_type(arg_type, arg)
|
71
|
-
true
|
72
|
-
else
|
73
|
-
false
|
74
|
-
end
|
75
|
-
end.compare_by_identity
|
76
|
-
|
77
|
-
@cached_parent_fields = Hash.new do |h, type|
|
78
|
-
h[type] = Hash.new do |h2, field_name|
|
79
|
-
h2[field_name] = type.get_field(field_name, @context)
|
80
|
-
end
|
81
|
-
end.compare_by_identity
|
82
|
-
|
83
|
-
@cached_parent_arguments = Hash.new do |h, arg_owner|
|
84
|
-
h[arg_owner] = Hash.new do |h2, arg_name|
|
85
|
-
h2[arg_name] = arg_owner.get_argument(arg_name, @context)
|
86
|
-
end
|
87
|
-
end.compare_by_identity
|
88
|
-
|
89
|
-
@cached_possible_types = Hash.new do |h, type|
|
90
|
-
h[type] = case type.kind.name
|
91
|
-
when "INTERFACE"
|
92
|
-
load_all_types
|
93
|
-
pts = []
|
94
|
-
@unfiltered_interface_type_memberships[type].each { |itm|
|
95
|
-
if @cached_visible[itm] && (ot = itm.object_type) && @cached_visible[ot] && referenced?(ot)
|
96
|
-
pts << ot
|
97
|
-
end
|
98
|
-
}
|
99
|
-
pts
|
100
|
-
when "UNION"
|
101
|
-
pts = []
|
102
|
-
type.type_memberships.each { |tm|
|
103
|
-
if @cached_visible[tm] &&
|
104
|
-
(ot = tm.object_type) &&
|
105
|
-
@cached_visible[ot] &&
|
106
|
-
referenced?(ot)
|
107
|
-
pts << ot
|
108
|
-
end
|
109
|
-
}
|
110
|
-
pts
|
111
|
-
when "OBJECT"
|
112
|
-
load_all_types
|
113
|
-
if @all_types[type.graphql_name] == type
|
114
|
-
[type]
|
115
|
-
else
|
116
|
-
EmptyObjects::EMPTY_ARRAY
|
117
|
-
end
|
118
|
-
else
|
119
|
-
GraphQL::EmptyObjects::EMPTY_ARRAY
|
120
|
-
end
|
121
|
-
end.compare_by_identity
|
122
|
-
|
123
|
-
@cached_enum_values = Hash.new do |h, enum_t|
|
124
|
-
values = non_duplicate_items(enum_t.all_enum_value_definitions, @cached_visible)
|
125
|
-
if values.size == 0
|
126
|
-
raise GraphQL::Schema::Enum::MissingValuesError.new(enum_t)
|
127
|
-
end
|
128
|
-
h[enum_t] = values
|
129
|
-
end.compare_by_identity
|
130
|
-
|
131
|
-
@cached_fields = Hash.new do |h, owner|
|
132
|
-
h[owner] = non_duplicate_items(owner.all_field_definitions.each(&:ensure_loaded), @cached_visible_fields[owner])
|
133
|
-
end.compare_by_identity
|
134
|
-
|
135
|
-
@cached_arguments = Hash.new do |h, owner|
|
136
|
-
h[owner] = non_duplicate_items(owner.all_argument_definitions, @cached_visible_arguments)
|
137
|
-
end.compare_by_identity
|
138
|
-
end
|
139
|
-
|
140
|
-
def field_on_visible_interface?(field, owner)
|
141
|
-
ints = owner.interface_type_memberships.map(&:abstract_type)
|
142
|
-
field_name = field.graphql_name
|
143
|
-
filtered_ints = interfaces(owner)
|
144
|
-
any_interface_has_field = false
|
145
|
-
any_interface_has_visible_field = false
|
146
|
-
ints.each do |int_t|
|
147
|
-
if (_int_f_defn = @cached_parent_fields[int_t][field_name])
|
148
|
-
any_interface_has_field = true
|
149
|
-
|
150
|
-
if filtered_ints.include?(int_t) # TODO cycles, or maybe not necessary since previously checked? && @cached_visible_fields[owner][field]
|
151
|
-
any_interface_has_visible_field = true
|
152
|
-
break
|
153
|
-
end
|
154
|
-
end
|
155
|
-
end
|
156
|
-
|
157
|
-
if any_interface_has_field
|
158
|
-
any_interface_has_visible_field
|
159
|
-
else
|
160
|
-
true
|
161
|
-
end
|
162
|
-
end
|
163
|
-
|
164
|
-
def type(type_name)
|
165
|
-
t = if (loaded_t = @all_types[type_name])
|
166
|
-
loaded_t
|
167
|
-
elsif !@all_types_loaded
|
168
|
-
load_all_types
|
169
|
-
@all_types[type_name]
|
170
|
-
end
|
171
|
-
if t
|
172
|
-
if t.is_a?(Array)
|
173
|
-
vis_t = nil
|
174
|
-
t.each do |t_defn|
|
175
|
-
if @cached_visible[t_defn]
|
176
|
-
if vis_t.nil?
|
177
|
-
vis_t = t_defn
|
178
|
-
else
|
179
|
-
raise_duplicate_definition(vis_t, t_defn)
|
180
|
-
end
|
181
|
-
end
|
182
|
-
end
|
183
|
-
vis_t
|
184
|
-
else
|
185
|
-
if t && @cached_visible[t]
|
186
|
-
t
|
187
|
-
else
|
188
|
-
nil
|
189
|
-
end
|
190
|
-
end
|
191
|
-
end
|
192
|
-
end
|
193
|
-
|
194
|
-
def field(owner, field_name)
|
195
|
-
f = if owner.kind.fields? && (field = @cached_parent_fields[owner][field_name])
|
196
|
-
field
|
197
|
-
elsif owner == query_root && (entry_point_field = @schema.introspection_system.entry_point(name: field_name))
|
198
|
-
entry_point_field
|
199
|
-
elsif (dynamic_field = @schema.introspection_system.dynamic_field(name: field_name))
|
200
|
-
dynamic_field
|
201
|
-
else
|
202
|
-
nil
|
203
|
-
end
|
204
|
-
if f.is_a?(Array)
|
205
|
-
visible_f = nil
|
206
|
-
f.each do |f_defn|
|
207
|
-
if @cached_visible_fields[owner][f_defn]
|
208
|
-
|
209
|
-
if visible_f.nil?
|
210
|
-
visible_f = f_defn
|
211
|
-
else
|
212
|
-
raise_duplicate_definition(visible_f, f_defn)
|
213
|
-
end
|
214
|
-
end
|
215
|
-
end
|
216
|
-
visible_f.ensure_loaded
|
217
|
-
elsif f && @cached_visible_fields[owner][f.ensure_loaded]
|
218
|
-
f
|
219
|
-
else
|
220
|
-
nil
|
221
|
-
end
|
222
|
-
end
|
223
|
-
|
224
|
-
def fields(owner)
|
225
|
-
@cached_fields[owner]
|
226
|
-
end
|
227
|
-
|
228
|
-
def arguments(owner)
|
229
|
-
@cached_arguments[owner]
|
230
|
-
end
|
231
|
-
|
232
|
-
def argument(owner, arg_name)
|
233
|
-
arg = @cached_parent_arguments[owner][arg_name]
|
234
|
-
if arg.is_a?(Array)
|
235
|
-
visible_arg = nil
|
236
|
-
arg.each do |arg_defn|
|
237
|
-
if @cached_visible_arguments[arg_defn]
|
238
|
-
if visible_arg.nil?
|
239
|
-
visible_arg = arg_defn
|
240
|
-
else
|
241
|
-
raise_duplicate_definition(visible_arg, arg_defn)
|
242
|
-
end
|
243
|
-
end
|
244
|
-
end
|
245
|
-
visible_arg
|
246
|
-
else
|
247
|
-
if arg && @cached_visible_arguments[arg]
|
248
|
-
arg
|
249
|
-
else
|
250
|
-
nil
|
251
|
-
end
|
252
|
-
end
|
253
|
-
end
|
254
|
-
|
255
|
-
def possible_types(type)
|
256
|
-
@cached_possible_types[type]
|
257
|
-
end
|
258
|
-
|
259
|
-
def interfaces(obj_or_int_type)
|
260
|
-
ints = obj_or_int_type.interface_type_memberships
|
261
|
-
.select { |itm| @cached_visible[itm] && @cached_visible[itm.abstract_type] }
|
262
|
-
.map!(&:abstract_type)
|
263
|
-
ints.uniq! # Remove any duplicate interfaces implemented via other interfaces
|
264
|
-
ints
|
265
|
-
end
|
266
|
-
|
267
|
-
def query_root
|
268
|
-
add_if_visible(@schema.query)
|
269
|
-
end
|
270
|
-
|
271
|
-
def mutation_root
|
272
|
-
add_if_visible(@schema.mutation)
|
273
|
-
end
|
274
|
-
|
275
|
-
def subscription_root
|
276
|
-
add_if_visible(@schema.subscription)
|
277
|
-
end
|
278
|
-
|
279
|
-
def all_types
|
280
|
-
load_all_types
|
281
|
-
@all_types.values
|
282
|
-
end
|
283
|
-
|
284
|
-
def all_types_h
|
285
|
-
load_all_types
|
286
|
-
@all_types
|
287
|
-
end
|
288
|
-
|
289
|
-
def enum_values(owner)
|
290
|
-
@cached_enum_values[owner]
|
291
|
-
end
|
292
|
-
|
293
|
-
def directive_exists?(dir_name)
|
294
|
-
if (dir = @schema.directives[dir_name]) && @cached_visible[dir]
|
295
|
-
!!dir
|
296
|
-
else
|
297
|
-
load_all_types
|
298
|
-
!!@cached_directives[dir_name]
|
299
|
-
end
|
300
|
-
end
|
301
|
-
|
302
|
-
def directives
|
303
|
-
@all_directives ||= begin
|
304
|
-
load_all_types
|
305
|
-
dirs = []
|
306
|
-
@schema.directives.each do |name, dir_defn|
|
307
|
-
if !@cached_directives[name] && @cached_visible[dir_defn]
|
308
|
-
dirs << dir_defn
|
309
|
-
end
|
310
|
-
end
|
311
|
-
dirs.concat(@cached_directives.values)
|
312
|
-
end
|
313
|
-
end
|
314
|
-
|
315
|
-
def loadable?(t, _ctx)
|
316
|
-
!@all_types[t.graphql_name] && @cached_visible[t]
|
317
|
-
end
|
318
|
-
|
319
|
-
def loaded_types
|
320
|
-
@all_types.values
|
321
|
-
end
|
322
|
-
|
323
|
-
def reachable_type?(name)
|
324
|
-
load_all_types
|
325
|
-
!!@all_types[name]
|
326
|
-
end
|
327
|
-
|
328
|
-
private
|
329
|
-
|
330
|
-
def add_if_visible(t)
|
331
|
-
(t && @cached_visible[t]) ? (add_type(t, true); t) : nil
|
332
|
-
end
|
333
|
-
|
334
|
-
def add_type(t, by_member)
|
335
|
-
if t && @cached_visible[t]
|
336
|
-
n = t.graphql_name
|
337
|
-
if (prev_t = @all_types[n])
|
338
|
-
if !prev_t.equal?(t)
|
339
|
-
raise_duplicate_definition(prev_t, t)
|
340
|
-
end
|
341
|
-
false
|
342
|
-
else
|
343
|
-
@referenced_types[t] << by_member
|
344
|
-
@all_types[n] = t
|
345
|
-
@unvisited_types << t
|
346
|
-
true
|
347
|
-
end
|
348
|
-
else
|
349
|
-
false
|
350
|
-
end
|
351
|
-
end
|
352
|
-
|
353
|
-
def non_duplicate_items(definitions, visibility_cache)
|
354
|
-
non_dups = []
|
355
|
-
definitions.each do |defn|
|
356
|
-
if visibility_cache[defn]
|
357
|
-
if (dup_defn = non_dups.find { |d| d.graphql_name == defn.graphql_name })
|
358
|
-
raise_duplicate_definition(dup_defn, defn)
|
359
|
-
end
|
360
|
-
non_dups << defn
|
361
|
-
end
|
362
|
-
end
|
363
|
-
non_dups
|
364
|
-
end
|
365
|
-
|
366
|
-
def raise_duplicate_definition(first_defn, second_defn)
|
367
|
-
raise DuplicateNamesError.new(duplicated_name: first_defn.path, duplicated_definition_1: first_defn.inspect, duplicated_definition_2: second_defn.inspect)
|
368
|
-
end
|
369
|
-
|
370
|
-
def referenced?(t)
|
371
|
-
load_all_types
|
372
|
-
@referenced_types[t].any? { |reference| (reference == true) || @cached_visible[reference] }
|
373
|
-
end
|
374
|
-
|
375
|
-
def load_all_types
|
376
|
-
return if @all_types_loaded
|
377
|
-
@all_types_loaded = true
|
378
|
-
entry_point_types = [
|
379
|
-
query_root,
|
380
|
-
mutation_root,
|
381
|
-
subscription_root,
|
382
|
-
*@schema.introspection_system.types.values,
|
383
|
-
]
|
384
|
-
|
385
|
-
# Don't include any orphan_types whose interfaces aren't visible.
|
386
|
-
@schema.orphan_types.each do |orphan_type|
|
387
|
-
if @cached_visible[orphan_type] &&
|
388
|
-
orphan_type.interface_type_memberships.any? { |tm| @cached_visible[tm] && @cached_visible[tm.abstract_type] }
|
389
|
-
entry_point_types << orphan_type
|
390
|
-
end
|
391
|
-
end
|
392
|
-
|
393
|
-
@schema.directives.each do |_dir_name, dir_class|
|
394
|
-
if @cached_visible[dir_class]
|
395
|
-
arguments(dir_class).each do |arg|
|
396
|
-
entry_point_types << arg.type.unwrap
|
397
|
-
end
|
398
|
-
end
|
399
|
-
end
|
400
|
-
|
401
|
-
entry_point_types.compact! # TODO why is this necessary?!
|
402
|
-
entry_point_types.flatten! # handle multiple defns
|
403
|
-
entry_point_types.each { |t| add_type(t, true) }
|
404
|
-
|
405
|
-
@unfiltered_interface_type_memberships = Hash.new { |h, k| h[k] = [] }.compare_by_identity
|
406
|
-
@add_possible_types = Set.new
|
407
|
-
|
408
|
-
while @unvisited_types.any?
|
409
|
-
while t = @unvisited_types.pop
|
410
|
-
# These have already been checked for `.visible?`
|
411
|
-
visit_type(t)
|
412
|
-
end
|
413
|
-
@add_possible_types.each do |int_t|
|
414
|
-
itms = @unfiltered_interface_type_memberships[int_t]
|
415
|
-
itms.each do |itm|
|
416
|
-
if @cached_visible[itm] && (obj_type = itm.object_type) && @cached_visible[obj_type]
|
417
|
-
add_type(obj_type, itm)
|
418
|
-
end
|
419
|
-
end
|
420
|
-
end
|
421
|
-
@add_possible_types.clear
|
422
|
-
end
|
423
|
-
|
424
|
-
@all_types.delete_if { |type_name, type_defn| !referenced?(type_defn) }
|
425
|
-
nil
|
426
|
-
end
|
427
|
-
|
428
|
-
def visit_type(type)
|
429
|
-
visit_directives(type)
|
430
|
-
case type.kind.name
|
431
|
-
when "OBJECT", "INTERFACE"
|
432
|
-
if type.kind.object?
|
433
|
-
type.interface_type_memberships.each do |itm|
|
434
|
-
@unfiltered_interface_type_memberships[itm.abstract_type] << itm
|
435
|
-
end
|
436
|
-
# recurse into visible implemented interfaces
|
437
|
-
interfaces(type).each do |interface|
|
438
|
-
add_type(interface, type)
|
439
|
-
end
|
440
|
-
else
|
441
|
-
type.orphan_types.each { |t| add_type(t, type)}
|
442
|
-
end
|
443
|
-
|
444
|
-
# recurse into visible fields
|
445
|
-
t_f = type.all_field_definitions
|
446
|
-
t_f.each do |field|
|
447
|
-
field.ensure_loaded
|
448
|
-
if @cached_visible[field]
|
449
|
-
visit_directives(field)
|
450
|
-
field_type = field.type.unwrap
|
451
|
-
if field_type.kind.interface?
|
452
|
-
@add_possible_types.add(field_type)
|
453
|
-
end
|
454
|
-
add_type(field_type, field)
|
455
|
-
|
456
|
-
# recurse into visible arguments
|
457
|
-
arguments(field).each do |argument|
|
458
|
-
visit_directives(argument)
|
459
|
-
add_type(argument.type.unwrap, argument)
|
460
|
-
end
|
461
|
-
end
|
462
|
-
end
|
463
|
-
when "INPUT_OBJECT"
|
464
|
-
# recurse into visible arguments
|
465
|
-
arguments(type).each do |argument|
|
466
|
-
visit_directives(argument)
|
467
|
-
add_type(argument.type.unwrap, argument)
|
468
|
-
end
|
469
|
-
when "UNION"
|
470
|
-
# recurse into visible possible types
|
471
|
-
type.type_memberships.each do |tm|
|
472
|
-
if @cached_visible[tm]
|
473
|
-
obj_t = tm.object_type
|
474
|
-
if obj_t.is_a?(String)
|
475
|
-
obj_t = Member::BuildType.constantize(obj_t)
|
476
|
-
tm.object_type = obj_t
|
477
|
-
end
|
478
|
-
if @cached_visible[obj_t]
|
479
|
-
add_type(obj_t, tm)
|
480
|
-
end
|
481
|
-
end
|
482
|
-
end
|
483
|
-
when "ENUM"
|
484
|
-
enum_values(type).each do |val|
|
485
|
-
visit_directives(val)
|
486
|
-
end
|
487
|
-
when "SCALAR"
|
488
|
-
# pass
|
489
|
-
end
|
490
|
-
end
|
491
|
-
|
492
|
-
def visit_directives(member)
|
493
|
-
member.directives.each { |dir|
|
494
|
-
dir_class = dir.class
|
495
|
-
if @cached_visible[dir_class]
|
496
|
-
dir_name = dir_class.graphql_name
|
497
|
-
if (existing_dir = @cached_directives[dir_name])
|
498
|
-
if existing_dir != dir_class
|
499
|
-
raise ArgumentError, "Two directives for `@#{dir_name}`: #{existing_dir}, #{dir.class}"
|
500
|
-
end
|
501
|
-
else
|
502
|
-
@cached_directives[dir.graphql_name] = dir_class
|
503
|
-
end
|
504
|
-
end
|
505
|
-
}
|
506
|
-
end
|
507
|
-
end
|
508
|
-
end
|
509
|
-
end
|