1- use crate :: graphql:: { EnumSource , __InputValue , __Type , ___Type } ;
1+ use crate :: graphql:: * ;
22use crate :: gson;
33use graphql_parser:: query:: * ;
4+ use graphql_parser:: Pos ;
45use std:: collections:: HashMap ;
56
67pub fn alias_or_name < ' a , T > ( query_field : & graphql_parser:: query:: Field < ' a , T > ) -> String
@@ -14,34 +15,221 @@ where
1415 . unwrap_or_else ( || query_field. name . as_ref ( ) . to_string ( ) )
1516}
1617
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 > > ,
20200 type_name : & String , // for inline fragments
21201 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 >
23204where
24- T : Text < ' a > + Eq + AsRef < str > ,
205+ T : Text < ' a > + Eq + AsRef < str > + std :: fmt :: Debug + Clone ,
25206{
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 ( ) ) ;
27210
28211 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) ?,
32220 Err ( err) => return Err ( err) ,
33221 }
34222 }
35- Ok ( selections )
223+ Ok ( normalized_fields )
36224}
37225
38226/// 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 > ,
41229 variables : & serde_json:: Value ,
42230) -> Result < bool , String >
43231where
44- T : Text < ' a > + Eq + AsRef < str > ,
232+ T : Text < ' a > + Eq + AsRef < str > + std :: fmt :: Debug ,
45233{
46234 let directives = match query_selection {
47235 Selection :: Field ( x) => & x. directives ,
@@ -130,24 +318,27 @@ where
130318}
131319
132320/// 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 > > ,
136324 type_name : & String , // for inline fragments
137325 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 >
139328where
140- T : Text < ' a > + Eq + AsRef < str > ,
329+ T : Text < ' a > + Eq + AsRef < str > + std :: fmt :: Debug + Clone ,
141330{
142- let mut selections : Vec < & Field < ' a , T > > = vec ! [ ] ;
331+ let mut normalized_fields : Vec < Field < ' a , T > > = vec ! [ ] ;
143332
144333 if selection_is_skipped ( query_selection, variables) ? {
145- return Ok ( selections ) ;
334+ return Ok ( normalized_fields ) ;
146335 }
147336
337+ let field_map = field_map ( & field_type. unmodified_type ( ) ) ;
338+
148339 match query_selection {
149340 Selection :: Field ( field) => {
150- selections . push ( field) ;
341+ merge_field ( & mut normalized_fields , field. clone ( ) , type_name , & field_map ) ? ;
151342 }
152343 Selection :: FragmentSpread ( fragment_spread) => {
153344 let frag_name = & fragment_spread. fragment_name ;
@@ -173,14 +364,15 @@ where
173364 } ;
174365
175366 // TODO handle directives?
176- let frag_selections = normalize_selection_set (
367+ let frag_fields = normalize_selection_set (
177368 & frag_def. selection_set ,
178369 fragment_definitions,
179370 type_name,
180371 variables,
372+ field_type,
181373 ) ;
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 ) ? ,
184376 Err ( err) => return Err ( err) ,
185377 } ;
186378 }
@@ -193,18 +385,19 @@ where
193385 } ;
194386
195387 if inline_fragment_applies {
196- let infrag_selections = normalize_selection_set (
388+ let infrag_fields = normalize_selection_set (
197389 & inline_fragment. selection_set ,
198390 fragment_definitions,
199391 type_name,
200392 variables,
393+ field_type,
201394 ) ?;
202- selections . extend ( infrag_selections . iter ( ) ) ;
395+ merge_fields ( & mut normalized_fields , infrag_fields , type_name , & field_map ) ? ;
203396 }
204397 }
205398 }
206399
207- Ok ( selections )
400+ Ok ( normalized_fields )
208401}
209402
210403pub fn to_gson < ' a , T > (
@@ -213,7 +406,7 @@ pub fn to_gson<'a, T>(
213406 variable_definitions : & Vec < VariableDefinition < ' a , T > > ,
214407) -> Result < gson:: Value , String >
215408where
216- T : Text < ' a > + AsRef < str > ,
409+ T : Text < ' a > + AsRef < str > + std :: fmt :: Debug ,
217410{
218411 let result = match graphql_value {
219412 Value :: Null => gson:: Value :: Null ,
@@ -273,7 +466,6 @@ where
273466}
274467
275468pub fn validate_arg_from_type ( type_ : & __Type , value : & gson:: Value ) -> Result < gson:: Value , String > {
276- use crate :: graphql:: Scalar ;
277469 use crate :: gson:: Number as GsonNumber ;
278470 use crate :: gson:: Value as GsonValue ;
279471
@@ -482,7 +674,6 @@ pub fn validate_arg_from_input_object(
482674 input_type : & __Type ,
483675 value : & gson:: Value ,
484676) -> Result < gson:: Value , String > {
485- use crate :: graphql:: __TypeKind;
486677 use crate :: gson:: Value as GsonValue ;
487678
488679 let input_type_name = input_type. name ( ) . unwrap_or_default ( ) ;
0 commit comments