@@ -4,13 +4,20 @@ import {
4
4
getNamedType ,
5
5
GraphQLField ,
6
6
GraphQLInterfaceType ,
7
+ GraphQLNamedOutputType ,
8
+ GraphQLNamedType ,
7
9
GraphQLObjectType ,
8
10
GraphQLSchema ,
11
+ isInterfaceType ,
12
+ isLeafType ,
13
+ isObjectType ,
14
+ isUnionType ,
9
15
Kind ,
10
16
SelectionNode ,
17
+ SelectionSetNode ,
11
18
} from 'graphql' ;
12
19
import { StitchingInfo } from '@graphql-tools/delegate' ;
13
- import { collectSubFields } from '@graphql-tools/utils' ;
20
+ import { collectSubFields , Maybe } from '@graphql-tools/utils' ;
14
21
15
22
export function getFieldsNotInSubschema (
16
23
schema : GraphQLSchema ,
@@ -45,6 +52,7 @@ export function getFieldsNotInSubschema(
45
52
const field = fields [ fieldName ] ;
46
53
for ( const subFieldNode of subFieldNodes ) {
47
54
const unavailableFields = extractUnavailableFields (
55
+ schema ,
48
56
field ,
49
57
subFieldNode ,
50
58
( fieldType , selection ) => ! fieldNodesByField ?. [ fieldType . name ] ?. [ selection . name . value ] ,
@@ -77,51 +85,116 @@ export function getFieldsNotInSubschema(
77
85
return Array . from ( fieldsNotInSchema ) ;
78
86
}
79
87
80
- export function extractUnavailableFields (
81
- field : GraphQLField < any , any > ,
82
- fieldNode : FieldNode ,
88
+ export function extractUnavailableFieldsFromSelectionSet (
89
+ schema : GraphQLSchema ,
90
+ fieldType : GraphQLNamedOutputType ,
91
+ fieldSelectionSet : SelectionSetNode ,
83
92
shouldAdd : ( fieldType : GraphQLObjectType | GraphQLInterfaceType , selection : FieldNode ) => boolean ,
84
93
) {
85
- if ( fieldNode . selectionSet ) {
86
- const fieldType = getNamedType ( field . type ) ;
87
- // TODO: Only object types are supported
88
- if ( ! ( 'getFields' in fieldType ) ) {
89
- return [ ] ;
90
- }
91
- const subFields = fieldType . getFields ( ) ;
94
+ if ( isLeafType ( fieldType ) ) {
95
+ return [ ] ;
96
+ }
97
+ if ( isUnionType ( fieldType ) ) {
92
98
const unavailableSelections : SelectionNode [ ] = [ ] ;
93
- for ( const selection of fieldNode . selectionSet . selections ) {
94
- if ( selection . kind === Kind . FIELD ) {
95
- if ( selection . name . value === '__typename' ) {
96
- continue ;
99
+ for ( const type of fieldType . getTypes ( ) ) {
100
+ // Exclude other inline fragments
101
+ const fieldSelectionExcluded : SelectionSetNode = {
102
+ ...fieldSelectionSet ,
103
+ selections : fieldSelectionSet . selections . filter ( selection =>
104
+ selection . kind === Kind . INLINE_FRAGMENT
105
+ ? selection . typeCondition
106
+ ? selection . typeCondition . name . value === type . name
107
+ : false
108
+ : true ,
109
+ ) ,
110
+ } ;
111
+ unavailableSelections . push (
112
+ ...extractUnavailableFieldsFromSelectionSet (
113
+ schema ,
114
+ type ,
115
+ fieldSelectionExcluded ,
116
+ shouldAdd ,
117
+ ) ,
118
+ ) ;
119
+ }
120
+ return unavailableSelections ;
121
+ }
122
+ const subFields = fieldType . getFields ( ) ;
123
+ const unavailableSelections : SelectionNode [ ] = [ ] ;
124
+ for ( const selection of fieldSelectionSet . selections ) {
125
+ if ( selection . kind === Kind . FIELD ) {
126
+ if ( selection . name . value === '__typename' ) {
127
+ continue ;
128
+ }
129
+ const fieldName = selection . name . value ;
130
+ const selectionField = subFields [ fieldName ] ;
131
+ if ( ! selectionField ) {
132
+ if ( shouldAdd ( fieldType , selection ) ) {
133
+ unavailableSelections . push ( selection ) ;
97
134
}
98
- const fieldName = selection . name . value ;
99
- const selectionField = subFields [ fieldName ] ;
100
- if ( ! selectionField ) {
101
- if ( shouldAdd ( fieldType , selection ) ) {
102
- unavailableSelections . push ( selection ) ;
103
- }
104
- } else {
105
- const unavailableSubFields = extractUnavailableFields (
106
- selectionField ,
107
- selection ,
108
- shouldAdd ,
109
- ) ;
110
- if ( unavailableSubFields . length ) {
111
- unavailableSelections . push ( {
112
- ...selection ,
113
- selectionSet : {
114
- kind : Kind . SELECTION_SET ,
115
- selections : unavailableSubFields ,
116
- } ,
117
- } ) ;
118
- }
135
+ } else {
136
+ const unavailableSubFields = extractUnavailableFields (
137
+ schema ,
138
+ selectionField ,
139
+ selection ,
140
+ shouldAdd ,
141
+ ) ;
142
+ if ( unavailableSubFields . length ) {
143
+ unavailableSelections . push ( {
144
+ ...selection ,
145
+ selectionSet : {
146
+ kind : Kind . SELECTION_SET ,
147
+ selections : unavailableSubFields ,
148
+ } ,
149
+ } ) ;
150
+ }
151
+ }
152
+ } else if ( selection . kind === Kind . INLINE_FRAGMENT ) {
153
+ const subFieldType : Maybe < GraphQLNamedType > = selection . typeCondition
154
+ ? schema . getType ( selection . typeCondition . name . value )
155
+ : fieldType ;
156
+ if (
157
+ ! ( isInterfaceType ( subFieldType ) && isObjectType ( subFieldType ) ) ||
158
+ subFieldType === fieldType ||
159
+ ( isInterfaceType ( fieldType ) && schema . isSubType ( fieldType , subFieldType ) )
160
+ ) {
161
+ const unavailableFields = extractUnavailableFieldsFromSelectionSet (
162
+ schema ,
163
+ fieldType ,
164
+ selection . selectionSet ,
165
+ shouldAdd ,
166
+ ) ;
167
+ if ( unavailableFields . length ) {
168
+ unavailableSelections . push ( {
169
+ ...selection ,
170
+ selectionSet : {
171
+ kind : Kind . SELECTION_SET ,
172
+ selections : unavailableFields ,
173
+ } ,
174
+ } ) ;
119
175
}
120
- } else if ( selection . kind === Kind . INLINE_FRAGMENT ) {
121
- // TODO: Support for inline fragments
176
+ } else {
177
+ unavailableSelections . push ( selection ) ;
122
178
}
123
179
}
124
- return unavailableSelections ;
180
+ }
181
+ return unavailableSelections ;
182
+ }
183
+
184
+ export function extractUnavailableFields (
185
+ schema : GraphQLSchema ,
186
+ field : GraphQLField < any , any > ,
187
+ fieldNode : FieldNode ,
188
+ shouldAdd : ( fieldType : GraphQLObjectType | GraphQLInterfaceType , selection : FieldNode ) => boolean ,
189
+ ) {
190
+ if ( fieldNode . selectionSet ) {
191
+ const fieldType = getNamedType ( field . type ) ;
192
+ return extractUnavailableFieldsFromSelectionSet (
193
+ schema ,
194
+ fieldType ,
195
+ fieldNode . selectionSet ,
196
+ shouldAdd ,
197
+ ) ;
125
198
}
126
199
return [ ] ;
127
200
}
0 commit comments