1
- use crate :: graphql:: { EnumSource , __InputValue , __Type , ___Type } ;
1
+ use crate :: graphql:: * ;
2
2
use crate :: gson;
3
3
use graphql_parser:: query:: * ;
4
+ use graphql_parser:: Pos ;
4
5
use std:: collections:: HashMap ;
5
6
6
7
pub fn alias_or_name < ' a , T > ( query_field : & graphql_parser:: query:: Field < ' a , T > ) -> String
@@ -14,34 +15,221 @@ where
14
15
. unwrap_or_else ( || query_field. name . as_ref ( ) . to_string ( ) )
15
16
}
16
17
17
- pub fn normalize_selection_set < ' a , ' b , T > (
18
- selection_set : & ' b SelectionSet < ' a , T > ,
19
- fragment_definitions : & ' b Vec < FragmentDefinition < ' a , T > > ,
18
+ pub fn merge_fields < ' a , T , I > (
19
+ target_fields : & mut Vec < Field < ' a , T > > ,
20
+ next_fields : I ,
21
+ type_name : & str ,
22
+ field_map : & HashMap < String , __Field > ,
23
+ ) -> Result < ( ) , String >
24
+ where
25
+ T : Text < ' a > + Eq + AsRef < str > + std:: fmt:: Debug + Clone ,
26
+ I : IntoIterator < Item = Field < ' a , T > > ,
27
+ {
28
+ for field in next_fields {
29
+ merge_field ( target_fields, field, type_name, field_map) ?
30
+ }
31
+ Ok ( ( ) )
32
+ }
33
+
34
+ pub fn merge_field < ' a , T > (
35
+ target_fields : & mut Vec < Field < ' a , T > > ,
36
+ mut field : Field < ' a , T > ,
37
+ type_name : & str ,
38
+ field_map : & HashMap < String , __Field > ,
39
+ ) -> Result < ( ) , String >
40
+ where
41
+ T : Text < ' a > + Eq + AsRef < str > + std:: fmt:: Debug + Clone ,
42
+ {
43
+ let Some ( ( matching_idx, matching_field) ) = target_fields
44
+ . iter ( )
45
+ . enumerate ( )
46
+ . find ( |( _, target) | alias_or_name ( target) == alias_or_name ( & field) )
47
+ else {
48
+ target_fields. push ( field) ;
49
+ return Ok ( ( ) ) ;
50
+ } ;
51
+
52
+ can_fields_merge ( & matching_field, & field, type_name, field_map) ?;
53
+
54
+ field. position = field. position . min ( matching_field. position ) ;
55
+
56
+ field. selection_set . span =
57
+ min_encapsulating_span ( field. selection_set . span , matching_field. selection_set . span ) ;
58
+
59
+ // Subfields will be normalized and properly merged on a later pass.
60
+ field
61
+ . selection_set
62
+ . items
63
+ . extend ( matching_field. selection_set . items . clone ( ) ) ;
64
+
65
+ target_fields[ matching_idx] = field;
66
+
67
+ Ok ( ( ) )
68
+ }
69
+
70
+ pub fn can_fields_merge < ' a , T > (
71
+ field_a : & Field < ' a , T > ,
72
+ field_b : & Field < ' a , T > ,
73
+ type_name : & str ,
74
+ field_map : & HashMap < String , __Field > ,
75
+ ) -> Result < ( ) , String >
76
+ where
77
+ T : Text < ' a > + Eq + AsRef < str > + std:: fmt:: Debug + Clone ,
78
+ {
79
+ let Some ( _field_a) = field_map. get ( field_a. name . as_ref ( ) ) else {
80
+ return Err ( format ! (
81
+ "Unknown field '{}' on type '{}'" ,
82
+ field_a. name. as_ref( ) ,
83
+ type_name
84
+ ) ) ;
85
+ } ;
86
+ let Some ( _field_b) = field_map. get ( field_b. name . as_ref ( ) ) else {
87
+ return Err ( format ! (
88
+ "Unknown field '{}' on type '{}'" ,
89
+ field_b. name. as_ref( ) ,
90
+ type_name
91
+ ) ) ;
92
+ } ;
93
+
94
+ has_same_type_shape (
95
+ & alias_or_name ( field_a) ,
96
+ type_name,
97
+ & _field_a. type_ ,
98
+ & _field_b. type_ ,
99
+ ) ?;
100
+
101
+ if field_a. name != field_b. name {
102
+ return Err ( format ! (
103
+ "Fields '{}' on type '{}' conflict because '{}' and '{}' are different fields" ,
104
+ alias_or_name( field_a) ,
105
+ type_name,
106
+ field_a. name. as_ref( ) ,
107
+ field_b. name. as_ref( ) ,
108
+ ) ) ;
109
+ }
110
+
111
+ for ( arg_a_name, arg_a_value) in field_a. arguments . iter ( ) {
112
+ let arg_b_value = field_b. arguments . iter ( ) . find_map ( |( name, value) | {
113
+ if name == arg_a_name {
114
+ Some ( value)
115
+ } else {
116
+ None
117
+ }
118
+ } ) ;
119
+ let args_match = match arg_b_value {
120
+ None => false ,
121
+ Some ( arg_b_value) => arg_b_value == arg_a_value,
122
+ } ;
123
+ if !args_match {
124
+ return Err ( format ! (
125
+ "Fields '{}' on type '{}' conflict because they have differing arguments" ,
126
+ alias_or_name( field_a) ,
127
+ type_name,
128
+ ) ) ;
129
+ }
130
+ }
131
+
132
+ Ok ( ( ) )
133
+ }
134
+
135
+ pub fn has_same_type_shape (
136
+ field_name : & str ,
137
+ type_name : & str ,
138
+ type_a : & __Type ,
139
+ type_b : & __Type ,
140
+ ) -> Result < ( ) , String > {
141
+ let mut type_a = type_a;
142
+ let mut type_b = type_b;
143
+
144
+ if matches ! ( type_a, __Type:: NonNull ( _) ) || matches ! ( type_b, __Type:: NonNull ( _) ) {
145
+ if let ( __Type:: NonNull ( nullable_type_a) , __Type:: NonNull ( nullable_type_b) ) =
146
+ ( type_a, type_b)
147
+ {
148
+ type_a = nullable_type_a. type_ . as_ref ( ) ;
149
+ type_b = nullable_type_b. type_ . as_ref ( ) ;
150
+ } else {
151
+ return Err ( format ! (
152
+ "Fields '{}' on type '{}' conflict because only one is non nullable" ,
153
+ field_name, type_name,
154
+ ) ) ;
155
+ }
156
+ }
157
+
158
+ if matches ! ( type_a, __Type:: List ( _) ) || matches ! ( type_b, __Type:: List ( _) ) {
159
+ if let ( __Type:: List ( list_type_a) , __Type:: List ( list_type_b) ) = ( type_a, type_b) {
160
+ type_a = list_type_a. type_ . as_ref ( ) ;
161
+ type_b = list_type_b. type_ . as_ref ( ) ;
162
+ } else {
163
+ return Err ( format ! (
164
+ "Fields '{}' on type '{}' conflict because only one is a list type" ,
165
+ field_name, type_name,
166
+ ) ) ;
167
+ }
168
+
169
+ return has_same_type_shape ( field_name, type_name, type_a, type_b) ;
170
+ }
171
+
172
+ if matches ! ( type_a, __Type:: Enum ( _) )
173
+ || matches ! ( type_b, __Type:: Enum ( _) )
174
+ || matches ! ( type_a, __Type:: Scalar ( _) )
175
+ || matches ! ( type_b, __Type:: Scalar ( _) )
176
+ {
177
+ return if type_a == type_b {
178
+ Ok ( ( ) )
179
+ } else {
180
+ Err ( format ! (
181
+ "Fields '{}' on type '{}' conflict due to mismatched types" ,
182
+ field_name, type_name,
183
+ ) )
184
+ } ;
185
+ }
186
+
187
+ // TODO handle composite types?
188
+
189
+ // Subfield type shapes will be checked on a later pass.
190
+ Ok ( ( ) )
191
+ }
192
+
193
+ pub fn min_encapsulating_span ( a : ( Pos , Pos ) , b : ( Pos , Pos ) ) -> ( Pos , Pos ) {
194
+ ( a. 0 . min ( b. 0 ) , a. 1 . max ( b. 1 ) )
195
+ }
196
+
197
+ pub fn normalize_selection_set < ' a , T > (
198
+ selection_set : & SelectionSet < ' a , T > ,
199
+ fragment_definitions : & Vec < FragmentDefinition < ' a , T > > ,
20
200
type_name : & String , // for inline fragments
21
201
variables : & serde_json:: Value , // for directives
22
- ) -> Result < Vec < & ' b Field < ' a , T > > , String >
202
+ field_type : & __Type ,
203
+ ) -> Result < Vec < Field < ' a , T > > , String >
23
204
where
24
- T : Text < ' a > + Eq + AsRef < str > ,
205
+ T : Text < ' a > + Eq + AsRef < str > + std :: fmt :: Debug + Clone ,
25
206
{
26
- let mut selections: Vec < & ' b Field < ' a , T > > = vec ! [ ] ;
207
+ let mut normalized_fields: Vec < Field < ' a , T > > = vec ! [ ] ;
208
+
209
+ let field_map = field_map ( & field_type. unmodified_type ( ) ) ;
27
210
28
211
for selection in & selection_set. items {
29
- let sel = selection;
30
- match normalize_selection ( sel, fragment_definitions, type_name, variables) {
31
- Ok ( sels) => selections. extend ( sels) ,
212
+ match normalize_selection (
213
+ selection,
214
+ fragment_definitions,
215
+ type_name,
216
+ variables,
217
+ field_type,
218
+ ) {
219
+ Ok ( fields) => merge_fields ( & mut normalized_fields, fields, type_name, & field_map) ?,
32
220
Err ( err) => return Err ( err) ,
33
221
}
34
222
}
35
- Ok ( selections )
223
+ Ok ( normalized_fields )
36
224
}
37
225
38
226
/// Combines @skip and @include
39
- pub fn selection_is_skipped < ' a , ' b , T > (
40
- query_selection : & ' b Selection < ' a , T > ,
227
+ pub fn selection_is_skipped < ' a , T > (
228
+ query_selection : & Selection < ' a , T > ,
41
229
variables : & serde_json:: Value ,
42
230
) -> Result < bool , String >
43
231
where
44
- T : Text < ' a > + Eq + AsRef < str > ,
232
+ T : Text < ' a > + Eq + AsRef < str > + std :: fmt :: Debug ,
45
233
{
46
234
let directives = match query_selection {
47
235
Selection :: Field ( x) => & x. directives ,
@@ -130,24 +318,27 @@ where
130
318
}
131
319
132
320
/// Normalizes literal selections, fragment spreads, and inline fragments
133
- pub fn normalize_selection < ' a , ' b , T > (
134
- query_selection : & ' b Selection < ' a , T > ,
135
- fragment_definitions : & ' b Vec < FragmentDefinition < ' a , T > > ,
321
+ pub fn normalize_selection < ' a , T > (
322
+ query_selection : & Selection < ' a , T > ,
323
+ fragment_definitions : & Vec < FragmentDefinition < ' a , T > > ,
136
324
type_name : & String , // for inline fragments
137
325
variables : & serde_json:: Value , // for directives
138
- ) -> Result < Vec < & ' b Field < ' a , T > > , String >
326
+ field_type : & __Type , // for field merging shape check
327
+ ) -> Result < Vec < Field < ' a , T > > , String >
139
328
where
140
- T : Text < ' a > + Eq + AsRef < str > ,
329
+ T : Text < ' a > + Eq + AsRef < str > + std :: fmt :: Debug + Clone ,
141
330
{
142
- let mut selections : Vec < & Field < ' a , T > > = vec ! [ ] ;
331
+ let mut normalized_fields : Vec < Field < ' a , T > > = vec ! [ ] ;
143
332
144
333
if selection_is_skipped ( query_selection, variables) ? {
145
- return Ok ( selections ) ;
334
+ return Ok ( normalized_fields ) ;
146
335
}
147
336
337
+ let field_map = field_map ( & field_type. unmodified_type ( ) ) ;
338
+
148
339
match query_selection {
149
340
Selection :: Field ( field) => {
150
- selections . push ( field) ;
341
+ merge_field ( & mut normalized_fields , field. clone ( ) , type_name , & field_map ) ? ;
151
342
}
152
343
Selection :: FragmentSpread ( fragment_spread) => {
153
344
let frag_name = & fragment_spread. fragment_name ;
@@ -173,14 +364,15 @@ where
173
364
} ;
174
365
175
366
// TODO handle directives?
176
- let frag_selections = normalize_selection_set (
367
+ let frag_fields = normalize_selection_set (
177
368
& frag_def. selection_set ,
178
369
fragment_definitions,
179
370
type_name,
180
371
variables,
372
+ field_type,
181
373
) ;
182
- match frag_selections {
183
- Ok ( sels ) => selections . extend ( sels . iter ( ) ) ,
374
+ match frag_fields {
375
+ Ok ( fields ) => merge_fields ( & mut normalized_fields , fields , type_name , & field_map ) ? ,
184
376
Err ( err) => return Err ( err) ,
185
377
} ;
186
378
}
@@ -193,18 +385,19 @@ where
193
385
} ;
194
386
195
387
if inline_fragment_applies {
196
- let infrag_selections = normalize_selection_set (
388
+ let infrag_fields = normalize_selection_set (
197
389
& inline_fragment. selection_set ,
198
390
fragment_definitions,
199
391
type_name,
200
392
variables,
393
+ field_type,
201
394
) ?;
202
- selections . extend ( infrag_selections . iter ( ) ) ;
395
+ merge_fields ( & mut normalized_fields , infrag_fields , type_name , & field_map ) ? ;
203
396
}
204
397
}
205
398
}
206
399
207
- Ok ( selections )
400
+ Ok ( normalized_fields )
208
401
}
209
402
210
403
pub fn to_gson < ' a , T > (
@@ -213,7 +406,7 @@ pub fn to_gson<'a, T>(
213
406
variable_definitions : & Vec < VariableDefinition < ' a , T > > ,
214
407
) -> Result < gson:: Value , String >
215
408
where
216
- T : Text < ' a > + AsRef < str > ,
409
+ T : Text < ' a > + AsRef < str > + std :: fmt :: Debug ,
217
410
{
218
411
let result = match graphql_value {
219
412
Value :: Null => gson:: Value :: Null ,
@@ -273,7 +466,6 @@ where
273
466
}
274
467
275
468
pub fn validate_arg_from_type ( type_ : & __Type , value : & gson:: Value ) -> Result < gson:: Value , String > {
276
- use crate :: graphql:: Scalar ;
277
469
use crate :: gson:: Number as GsonNumber ;
278
470
use crate :: gson:: Value as GsonValue ;
279
471
@@ -482,7 +674,6 @@ pub fn validate_arg_from_input_object(
482
674
input_type : & __Type ,
483
675
value : & gson:: Value ,
484
676
) -> Result < gson:: Value , String > {
485
- use crate :: graphql:: __TypeKind;
486
677
use crate :: gson:: Value as GsonValue ;
487
678
488
679
let input_type_name = input_type. name ( ) . unwrap_or_default ( ) ;
0 commit comments