1
1
import {
2
2
defaultFieldResolver ,
3
+ FieldNode ,
3
4
GraphQLResolveInfo ,
4
5
Kind ,
5
6
responsePathAsArray ,
@@ -15,7 +16,11 @@ import {
15
16
} from './mergeFields.js' ;
16
17
import { resolveExternalValue } from './resolveExternalValue.js' ;
17
18
import { Subschema } from './Subschema.js' ;
18
- import { FIELD_SUBSCHEMA_MAP_SYMBOL , UNPATHED_ERRORS_SYMBOL } from './symbols.js' ;
19
+ import {
20
+ FIELD_SUBSCHEMA_MAP_SYMBOL ,
21
+ OBJECT_SUBSCHEMA_SYMBOL ,
22
+ UNPATHED_ERRORS_SYMBOL ,
23
+ } from './symbols.js' ;
19
24
import { ExternalObject , MergedTypeResolver , StitchingInfo } from './types.js' ;
20
25
21
26
/**
@@ -66,6 +71,7 @@ export function defaultMergedResolver(
66
71
}
67
72
const deferred = createDeferred ( ) ;
68
73
missingDeferredFields . set ( responseKey , deferred ) ;
74
+ handleResult ( parent , responseKey , context , info ) ;
69
75
return deferred . promise ;
70
76
}
71
77
return undefined ;
@@ -110,16 +116,35 @@ function handleLeftOver<TContext extends Record<string, any>>(
110
116
if ( stitchingInfo ) {
111
117
for ( const possibleSubschema of leftOver . nonProxiableSubschemas ) {
112
118
const parentTypeName = info . parentType . name ;
113
- const selectionSet =
119
+ const selectionSets = new Set < SelectionSetNode > ( ) ;
120
+ const mainSelectionSet =
114
121
stitchingInfo . mergedTypes [ parentTypeName ] . selectionSets . get ( possibleSubschema ) ;
122
+ if ( mainSelectionSet ) {
123
+ selectionSets . add ( mainSelectionSet ) ;
124
+ }
125
+ for ( const fieldNode of leftOver . unproxiableFieldNodes ) {
126
+ const fieldName = fieldNode . name . value ;
127
+ const fieldSelectionSet =
128
+ stitchingInfo . mergedTypes [ parentTypeName ] . fieldSelectionSets . get ( possibleSubschema ) ?. [
129
+ fieldName
130
+ ] ;
131
+ if ( fieldSelectionSet ) {
132
+ selectionSets . add ( fieldSelectionSet ) ;
133
+ }
134
+ }
115
135
// Wait until the parent is flattened, then check if non proxiable subschemas are satisfied now,
116
136
// then the deferred fields can be resolved
117
- if ( selectionSet ) {
137
+ if ( selectionSets . size ) {
138
+ const selectionSet : SelectionSetNode = {
139
+ kind : Kind . SELECTION_SET ,
140
+ selections : Array . from ( selectionSets ) . flatMap ( selectionSet => selectionSet . selections ) ,
141
+ } ;
118
142
const flattenedParent$ = flattenPromise ( parent ) ;
119
143
if ( isPromise ( flattenedParent$ ) ) {
120
144
flattenedParent$ . then ( flattenedParent => {
121
145
handleFlattenedParent (
122
146
flattenedParent ,
147
+ parent ,
123
148
possibleSubschema ,
124
149
selectionSet ,
125
150
leftOver ,
@@ -132,6 +157,7 @@ function handleLeftOver<TContext extends Record<string, any>>(
132
157
} else {
133
158
handleFlattenedParent (
134
159
flattenedParent$ ,
160
+ parent ,
135
161
possibleSubschema ,
136
162
selectionSet ,
137
163
leftOver ,
@@ -148,6 +174,7 @@ function handleLeftOver<TContext extends Record<string, any>>(
148
174
149
175
function handleFlattenedParent < TContext extends Record < string , any > > (
150
176
flattenedParent : ExternalObject ,
177
+ leftOverParent : ExternalObject ,
151
178
possibleSubschema : Subschema ,
152
179
selectionSet : SelectionSetNode ,
153
180
leftOver : DelegationPlanLeftOver ,
@@ -158,7 +185,8 @@ function handleFlattenedParent<TContext extends Record<string, any>>(
158
185
) {
159
186
// If this subschema is satisfied now, try to resolve the deferred fields
160
187
if ( parentSatisfiedSelectionSet ( flattenedParent , selectionSet ) ) {
161
- for ( const [ leftOverParent , missingFieldNodes ] of leftOver . missingFieldsParentMap ) {
188
+ const missingFieldNodes = leftOver . missingFieldsParentMap . get ( leftOverParent ) ;
189
+ if ( missingFieldNodes ) {
162
190
const resolver = stitchingInfo . mergedTypes [ parentTypeName ] . resolvers . get ( possibleSubschema ) ;
163
191
if ( resolver ) {
164
192
try {
@@ -208,6 +236,84 @@ function handleFlattenedParent<TContext extends Record<string, any>>(
208
236
}
209
237
}
210
238
}
239
+ } else {
240
+ // try to resolve the missing fields
241
+ for ( const selectionNode of selectionSet . selections ) {
242
+ if ( selectionNode . kind === Kind . FIELD && selectionNode . selectionSet ?. selections ?. length ) {
243
+ const responseKey = selectionNode . alias ?. value ?? selectionNode . name . value ;
244
+ const nestedParent = flattenedParent [ responseKey ] ;
245
+ const nestedSelectionSet = selectionNode . selectionSet ;
246
+ if ( nestedParent != null ) {
247
+ if ( ! parentSatisfiedSelectionSet ( nestedParent , nestedSelectionSet ) ) {
248
+ async function handleNestedParentItem ( nestedParentItem : any , fieldNode : FieldNode ) {
249
+ const nestedTypeName = nestedParentItem [ '__typename' ] ;
250
+ const sourceSubschema = getSubschema ( flattenedParent , responseKey ) as Subschema ;
251
+ if ( sourceSubschema && nestedTypeName ) {
252
+ const delegationPlan = stitchingInfo . mergedTypes [
253
+ nestedTypeName
254
+ ] . delegationPlanBuilder (
255
+ info . schema ,
256
+ sourceSubschema ,
257
+ info . variableValues ,
258
+ info . fragments ,
259
+ [ fieldNode ] ,
260
+ ) ;
261
+ // Later optimize
262
+ for ( const delegationMap of delegationPlan ) {
263
+ for ( const [ subschema , selectionSet ] of delegationMap ) {
264
+ const resolver =
265
+ stitchingInfo . mergedTypes [ nestedTypeName ] . resolvers . get ( subschema ) ;
266
+ if ( resolver ) {
267
+ const res = await resolver (
268
+ nestedParentItem ,
269
+ context ,
270
+ info ,
271
+ subschema ,
272
+ selectionSet ,
273
+ info . parentType ,
274
+ info . parentType ,
275
+ ) ;
276
+ if ( res ) {
277
+ handleResolverResult (
278
+ res ,
279
+ subschema ,
280
+ selectionSet ,
281
+ nestedParentItem ,
282
+ ( nestedParentItem [ FIELD_SUBSCHEMA_MAP_SYMBOL ] ||= new Map ( ) ) ,
283
+ info ,
284
+ responsePathAsArray ( info . path ) ,
285
+ ( nestedParentItem [ UNPATHED_ERRORS_SYMBOL ] ||= [ ] ) ,
286
+ ) ;
287
+ }
288
+ }
289
+ }
290
+ }
291
+ if ( parentSatisfiedSelectionSet ( nestedParent , nestedSelectionSet ) ) {
292
+ handleFlattenedParent (
293
+ flattenedParent ,
294
+ leftOverParent ,
295
+ possibleSubschema ,
296
+ selectionSet ,
297
+ leftOver ,
298
+ stitchingInfo ,
299
+ parentTypeName ,
300
+ context ,
301
+ info ,
302
+ ) ;
303
+ }
304
+ }
305
+ }
306
+ if ( Array . isArray ( nestedParent ) ) {
307
+ nestedParent . forEach ( nestedParentItem =>
308
+ handleNestedParentItem ( nestedParentItem , selectionNode ) ,
309
+ ) ;
310
+ } else {
311
+ handleNestedParentItem ( nestedParent , selectionNode ) ;
312
+ }
313
+ }
314
+ }
315
+ }
316
+ }
211
317
}
212
318
}
213
319
@@ -339,6 +445,15 @@ function flattenPromise<T>(data: T): Promise<T> | T {
339
445
newData [ key ] = keyResult ;
340
446
}
341
447
}
448
+ if ( data [ OBJECT_SUBSCHEMA_SYMBOL ] ) {
449
+ newData [ OBJECT_SUBSCHEMA_SYMBOL ] = data [ OBJECT_SUBSCHEMA_SYMBOL ] ;
450
+ }
451
+ if ( data [ FIELD_SUBSCHEMA_MAP_SYMBOL ] ) {
452
+ newData [ FIELD_SUBSCHEMA_MAP_SYMBOL ] = data [ FIELD_SUBSCHEMA_MAP_SYMBOL ] ;
453
+ }
454
+ if ( data [ UNPATHED_ERRORS_SYMBOL ] ) {
455
+ newData [ UNPATHED_ERRORS_SYMBOL ] = data [ UNPATHED_ERRORS_SYMBOL ] ;
456
+ }
342
457
if ( jobs . length ) {
343
458
return Promise . all ( jobs ) . then ( ( ) => newData ) as Promise < T > ;
344
459
}
0 commit comments