1
- # frozen_string_literal: true
1
+ # frozen_string_literal: true
2
2
module GraphQL
3
3
module StaticValidation
4
4
module FieldsWillMerge
@@ -8,8 +8,8 @@ module FieldsWillMerge
8
8
#
9
9
# Original Algorithm: https://github.com/graphql/graphql-js/blob/master/src/validation/rules/OverlappingFieldsCanBeMerged.js
10
10
NO_ARGS = { } . freeze
11
- Field = Struct . new ( :node , :definition , :parent_type )
12
- FragmentSpread = Struct . new ( :name , :parent_type )
11
+ Field = Struct . new ( :node , :definition , :parents )
12
+ FragmentSpread = Struct . new ( :name , :parents )
13
13
14
14
def initialize ( *)
15
15
super
@@ -33,14 +33,14 @@ def on_field(node, _parent)
33
33
def conflicts_within_selection_set ( node , parent_type )
34
34
return if parent_type . nil?
35
35
36
- fields , fragment_spreads = fields_and_fragments_from_selection ( node , parent_type : parent_type )
36
+ fields , fragment_spreads = fields_and_fragments_from_selection ( node , parents : [ parent_type ] )
37
37
38
38
# (A) Find find all conflicts "within" the fields of this selection set.
39
39
find_conflicts_within ( fields )
40
40
41
41
fragment_spreads . each_with_index do |fragment_spread , i |
42
42
are_mutually_exclusive = mutually_exclusive? (
43
- fragment_spread . parent_type ,
43
+ fragment_spread . parents . last ,
44
44
parent_type
45
45
)
46
46
@@ -58,8 +58,8 @@ def conflicts_within_selection_set(node, parent_type)
58
58
# item in that same list (except for itself).
59
59
fragment_spreads [ i + 1 ..-1 ] . each do |fragment_spread2 |
60
60
are_mutually_exclusive = mutually_exclusive? (
61
- fragment_spread . parent_type ,
62
- fragment_spread2 . parent_type
61
+ fragment_spread . parents . last ,
62
+ fragment_spread2 . parents . last
63
63
)
64
64
65
65
find_conflicts_between_fragments (
@@ -97,8 +97,14 @@ def find_conflicts_between_fragments(fragment_spread1, fragment_spread2, mutuall
97
97
98
98
return if fragment_type1 . nil? || fragment_type2 . nil?
99
99
100
- fragment_fields1 , fragment_spreads1 = fields_and_fragments_from_selection ( fragment1 , parent_type : fragment_type1 )
101
- fragment_fields2 , fragment_spreads2 = fields_and_fragments_from_selection ( fragment2 , parent_type : fragment_type2 )
100
+ fragment_fields1 , fragment_spreads1 = fields_and_fragments_from_selection (
101
+ fragment1 ,
102
+ parents : [ *fragment_spread1 . parents , fragment_type1 ]
103
+ )
104
+ fragment_fields2 , fragment_spreads2 = fields_and_fragments_from_selection (
105
+ fragment2 ,
106
+ parents : [ *fragment_spread2 , fragment_type2 ]
107
+ )
102
108
103
109
# (F) First, find all conflicts between these two collections of fields
104
110
# (not including any nested fragments).
@@ -140,7 +146,7 @@ def find_conflicts_between_fields_and_fragment(fragment_spread, fields, mutually
140
146
fragment_type = context . schema . types [ fragment . type . name ]
141
147
return if fragment_type . nil?
142
148
143
- fragment_fields , fragment_spreads = fields_and_fragments_from_selection ( fragment , parent_type : fragment_type )
149
+ fragment_fields , fragment_spreads = fields_and_fragments_from_selection ( fragment , parents : [ * fragment_spread . parents , fragment_type ] )
144
150
145
151
# (D) First find any conflicts between the provided collection of fields
146
152
# and the collection of fields represented by the given fragment.
@@ -174,8 +180,8 @@ def find_conflicts_within(response_keys)
174
180
end
175
181
176
182
def find_conflict ( response_key , field1 , field2 , mutually_exclusive : false )
177
- parent_type1 = field1 . parent_type
178
- parent_type2 = field2 . parent_type
183
+ parent_type1 = field1 . parents . last
184
+ parent_type2 = field2 . parents . last
179
185
180
186
node1 = field1 . node
181
187
node2 = field2 . node
@@ -207,11 +213,17 @@ def find_conflict(response_key, field1, field2, mutually_exclusive: false)
207
213
def find_conflicts_between_sub_selection_sets ( field1 , field2 , mutually_exclusive :)
208
214
return if field1 . definition . nil? || field2 . definition . nil?
209
215
210
- parent_type1 = field1 . definition . type . unwrap
211
- parent_type2 = field2 . definition . type . unwrap
216
+ return_type1 = field1 . definition . type . unwrap
217
+ return_type2 = field2 . definition . type . unwrap
212
218
213
- fields , fragment_spreads = fields_and_fragments_from_selection ( field1 . node , parent_type : parent_type1 )
214
- fields2 , fragment_spreads2 = fields_and_fragments_from_selection ( field2 . node , parent_type : parent_type2 )
219
+ fields , fragment_spreads = fields_and_fragments_from_selection (
220
+ field1 . node ,
221
+ parents : [ *field1 . parents , return_type1 ] )
222
+
223
+ fields2 , fragment_spreads2 = fields_and_fragments_from_selection (
224
+ field2 . node ,
225
+ parents : [ *field2 . parents , return_type2 ]
226
+ )
215
227
216
228
# (H) First, collect all conflicts between these two collections of field.
217
229
find_conflicts_between ( fields , fields2 , mutually_exclusive : mutually_exclusive )
@@ -220,8 +232,8 @@ def find_conflicts_between_sub_selection_sets(field1, field2, mutually_exclusive
220
232
# those referenced by each fragment name associated with the second.
221
233
fragment_spreads2 . each do |fragment_spread |
222
234
fragment_is_mutually_exclusive = mutually_exclusive? (
223
- parent_type1 ,
224
- fragment_spread . parent_type
235
+ return_type1 ,
236
+ fragment_spread . parents . last
225
237
)
226
238
227
239
find_conflicts_between_fields_and_fragment (
@@ -235,8 +247,8 @@ def find_conflicts_between_sub_selection_sets(field1, field2, mutually_exclusive
235
247
# those referenced by each fragment name associated with the first.
236
248
fragment_spreads . each do |fragment_spread |
237
249
fragment_is_mutually_exclusive = mutually_exclusive? (
238
- parent_type2 ,
239
- fragment_spread . parent_type
250
+ return_type2 ,
251
+ fragment_spread . parents . last
240
252
)
241
253
242
254
find_conflicts_between_fields_and_fragment (
@@ -252,8 +264,8 @@ def find_conflicts_between_sub_selection_sets(field1, field2, mutually_exclusive
252
264
fragment_spreads . each do |frag1 |
253
265
fragment_spreads2 . each do |frag2 |
254
266
fragments_are_mutually_exclusive = mutually_exclusive? (
255
- frag1 . parent_type ,
256
- frag2 . parent_type
267
+ frag1 . parents . last ,
268
+ frag2 . parents . last
257
269
)
258
270
259
271
find_conflicts_between_fragments (
@@ -283,25 +295,25 @@ def find_conflicts_between(response_keys, response_keys2, mutually_exclusive:)
283
295
end
284
296
end
285
297
286
- def fields_and_fragments_from_selection ( node , parent_type :)
298
+ def fields_and_fragments_from_selection ( node , parents :)
287
299
@fields_and_fragments_from_node [ node ] ||= begin
288
- fields , fragment_spreads = find_fields_and_fragments ( node . selections , parent_type : parent_type )
300
+ fields , fragment_spreads = find_fields_and_fragments ( node . selections , parents : parents )
289
301
response_keys = fields . group_by { |f | f . node . alias || f . node . name }
290
302
[ response_keys , fragment_spreads ]
291
303
end
292
304
end
293
305
294
- def find_fields_and_fragments ( selections , parent_type :, fields : [ ] , fragment_spreads : [ ] )
306
+ def find_fields_and_fragments ( selections , parents :, fields : [ ] , fragment_spreads : [ ] )
295
307
selections . each do |node |
296
308
case node
297
309
when GraphQL ::Language ::Nodes ::Field
298
- definition = context . schema . get_field ( parent_type , node . name )
299
- fields << Field . new ( node , definition , parent_type )
310
+ definition = context . schema . get_field ( parents . last , node . name )
311
+ fields << Field . new ( node , definition , parents )
300
312
when GraphQL ::Language ::Nodes ::InlineFragment
301
- fragment_type = node . type ? context . schema . types [ node . type . name ] : parent_type
302
- find_fields_and_fragments ( node . selections , parent_type : fragment_type , fields : fields , fragment_spreads : fragment_spreads ) if fragment_type
313
+ fragment_type = node . type ? context . schema . types [ node . type . name ] : parents . last
314
+ find_fields_and_fragments ( node . selections , parents : [ * parents , fragment_type ] , fields : fields , fragment_spreads : fragment_spreads ) if fragment_type
303
315
when GraphQL ::Language ::Nodes ::FragmentSpread
304
- fragment_spreads << FragmentSpread . new ( node . name , parent_type )
316
+ fragment_spreads << FragmentSpread . new ( node . name , parents )
305
317
end
306
318
end
307
319
0 commit comments