UNPKG

76.1 kBJavaScriptView Raw
1'use strict';
2
3Object.defineProperty(exports, '__esModule', { value: true });
4
5function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
6
7const utils = require('@graphql-tools/utils');
8const graphql = require('graphql');
9const AggregateError = _interopDefault(require('@ardatan/aggregate-error'));
10const isPromise = _interopDefault(require('is-promise'));
11const batchExecute = require('@graphql-tools/batch-execute');
12
13function applySchemaTransforms(originalWrappingSchema, subschemaConfig, transformedSchema) {
14 const schemaTransforms = subschemaConfig.transforms;
15 if (schemaTransforms == null) {
16 return originalWrappingSchema;
17 }
18 return schemaTransforms.reduce((schema, transform) => transform.transformSchema != null
19 ? transform.transformSchema(utils.cloneSchema(schema), subschemaConfig, transformedSchema)
20 : schema, originalWrappingSchema);
21}
22
23function isSubschema(value) {
24 return Boolean(value.transformedSchema);
25}
26class Subschema {
27 constructor(config) {
28 var _a;
29 this.schema = config.schema;
30 this.rootValue = config.rootValue;
31 this.executor = config.executor;
32 this.subscriber = config.subscriber;
33 this.batch = config.batch;
34 this.batchingOptions = config.batchingOptions;
35 this.createProxyingResolver = config.createProxyingResolver;
36 this.transforms = (_a = config.transforms) !== null && _a !== void 0 ? _a : [];
37 this.transformedSchema = applySchemaTransforms(this.schema, config);
38 this.merge = config.merge;
39 }
40}
41
42function getDelegatingOperation(parentType, schema) {
43 if (parentType === schema.getMutationType()) {
44 return 'mutation';
45 }
46 else if (parentType === schema.getSubscriptionType()) {
47 return 'subscription';
48 }
49 return 'query';
50}
51function createRequestFromInfo({ info, operationName, operation = getDelegatingOperation(info.parentType, info.schema), fieldName = info.fieldName, selectionSet, fieldNodes = info.fieldNodes, }) {
52 return createRequest({
53 sourceSchema: info.schema,
54 sourceParentType: info.parentType,
55 sourceFieldName: info.fieldName,
56 fragments: info.fragments,
57 variableDefinitions: info.operation.variableDefinitions,
58 variableValues: info.variableValues,
59 targetOperationName: operationName,
60 targetOperation: operation,
61 targetFieldName: fieldName,
62 selectionSet,
63 fieldNodes,
64 });
65}
66function createRequest({ sourceSchema, sourceParentType, sourceFieldName, fragments, variableDefinitions, variableValues, targetOperationName, targetOperation, targetFieldName, selectionSet, fieldNodes, }) {
67 var _a;
68 let newSelectionSet;
69 let argumentNodeMap;
70 if (selectionSet != null) {
71 newSelectionSet = selectionSet;
72 argumentNodeMap = Object.create(null);
73 }
74 else {
75 const selections = fieldNodes.reduce((acc, fieldNode) => (fieldNode.selectionSet != null ? acc.concat(fieldNode.selectionSet.selections) : acc), []);
76 newSelectionSet = selections.length
77 ? {
78 kind: graphql.Kind.SELECTION_SET,
79 selections,
80 }
81 : undefined;
82 argumentNodeMap = {};
83 const args = (_a = fieldNodes[0]) === null || _a === void 0 ? void 0 : _a.arguments;
84 if (args) {
85 argumentNodeMap = args.reduce((prev, curr) => ({
86 ...prev,
87 [curr.name.value]: curr,
88 }), argumentNodeMap);
89 }
90 }
91 const newVariables = Object.create(null);
92 const variableDefinitionMap = Object.create(null);
93 if (sourceSchema != null && variableDefinitions != null) {
94 variableDefinitions.forEach(def => {
95 const varName = def.variable.name.value;
96 variableDefinitionMap[varName] = def;
97 const varType = graphql.typeFromAST(sourceSchema, def.type);
98 const serializedValue = utils.serializeInputValue(varType, variableValues[varName]);
99 if (serializedValue !== undefined) {
100 newVariables[varName] = serializedValue;
101 }
102 });
103 }
104 if (sourceParentType != null) {
105 updateArgumentsWithDefaults(sourceParentType, sourceFieldName, argumentNodeMap, variableDefinitionMap, newVariables);
106 }
107 const rootfieldNode = {
108 kind: graphql.Kind.FIELD,
109 arguments: Object.keys(argumentNodeMap).map(argName => argumentNodeMap[argName]),
110 name: {
111 kind: graphql.Kind.NAME,
112 value: targetFieldName || fieldNodes[0].name.value,
113 },
114 selectionSet: newSelectionSet,
115 };
116 const operationName = targetOperationName
117 ? {
118 kind: graphql.Kind.NAME,
119 value: targetOperationName,
120 }
121 : undefined;
122 const operationDefinition = {
123 kind: graphql.Kind.OPERATION_DEFINITION,
124 name: operationName,
125 operation: targetOperation,
126 variableDefinitions: Object.keys(variableDefinitionMap).map(varName => variableDefinitionMap[varName]),
127 selectionSet: {
128 kind: graphql.Kind.SELECTION_SET,
129 selections: [rootfieldNode],
130 },
131 };
132 let definitions = [operationDefinition];
133 if (fragments != null) {
134 definitions = definitions.concat(Object.keys(fragments).map(fragmentName => fragments[fragmentName]));
135 }
136 const document = {
137 kind: graphql.Kind.DOCUMENT,
138 definitions,
139 };
140 return {
141 document,
142 variables: newVariables,
143 };
144}
145function updateArgumentsWithDefaults(sourceParentType, sourceFieldName, argumentNodeMap, variableDefinitionMap, variableValues) {
146 const sourceField = sourceParentType.getFields()[sourceFieldName];
147 sourceField.args.forEach((argument) => {
148 const argName = argument.name;
149 const sourceArgType = argument.type;
150 if (argumentNodeMap[argName] === undefined) {
151 const defaultValue = argument.defaultValue;
152 if (defaultValue !== undefined) {
153 utils.updateArgument(argName, sourceArgType, argumentNodeMap, variableDefinitionMap, variableValues, utils.serializeInputValue(sourceArgType, defaultValue));
154 }
155 }
156 });
157}
158
159const UNPATHED_ERRORS_SYMBOL = Symbol('subschemaErrors');
160const OBJECT_SUBSCHEMA_SYMBOL = Symbol('initialSubschema');
161const FIELD_SUBSCHEMA_MAP_SYMBOL = Symbol('subschemaMap');
162
163function isExternalObject(data) {
164 return data[UNPATHED_ERRORS_SYMBOL] !== undefined;
165}
166function annotateExternalObject(object, errors, subschema) {
167 Object.defineProperties(object, {
168 [OBJECT_SUBSCHEMA_SYMBOL]: { value: subschema },
169 [FIELD_SUBSCHEMA_MAP_SYMBOL]: { value: Object.create(null) },
170 [UNPATHED_ERRORS_SYMBOL]: { value: errors },
171 });
172 return object;
173}
174function getSubschema(object, responseKey) {
175 var _a;
176 return (_a = object[FIELD_SUBSCHEMA_MAP_SYMBOL][responseKey]) !== null && _a !== void 0 ? _a : object[OBJECT_SUBSCHEMA_SYMBOL];
177}
178function getUnpathedErrors(object) {
179 return object[UNPATHED_ERRORS_SYMBOL];
180}
181function mergeExternalObjects(schema, path, typeName, target, sources, selectionSets) {
182 var _a;
183 const results = [];
184 let errors = [];
185 sources.forEach((source, index) => {
186 if (source instanceof graphql.GraphQLError || source === null) {
187 const selectionSet = selectionSets[index];
188 const fieldNodes = utils.collectFields({
189 schema,
190 variableValues: {},
191 fragments: {},
192 }, schema.getType(typeName), selectionSet, Object.create(null), Object.create(null));
193 const nullResult = {};
194 Object.keys(fieldNodes).forEach(responseKey => {
195 nullResult[responseKey] =
196 source instanceof graphql.GraphQLError ? utils.relocatedError(source, path.concat([responseKey])) : null;
197 });
198 results.push(nullResult);
199 }
200 else {
201 errors = errors.concat(source[UNPATHED_ERRORS_SYMBOL]);
202 results.push(source);
203 }
204 });
205 const combinedResult = results.reduce(utils.mergeDeep, target);
206 const newFieldSubschemaMap = (_a = target[FIELD_SUBSCHEMA_MAP_SYMBOL]) !== null && _a !== void 0 ? _a : Object.create(null);
207 results.forEach((source) => {
208 const objectSubschema = source[OBJECT_SUBSCHEMA_SYMBOL];
209 const fieldSubschemaMap = source[FIELD_SUBSCHEMA_MAP_SYMBOL];
210 if (fieldSubschemaMap === undefined) {
211 Object.keys(source).forEach(responseKey => {
212 newFieldSubschemaMap[responseKey] = objectSubschema;
213 });
214 }
215 else {
216 Object.keys(source).forEach(responseKey => {
217 var _a;
218 newFieldSubschemaMap[responseKey] = (_a = fieldSubschemaMap[responseKey]) !== null && _a !== void 0 ? _a : objectSubschema;
219 });
220 }
221 });
222 combinedResult[FIELD_SUBSCHEMA_MAP_SYMBOL] = newFieldSubschemaMap;
223 combinedResult[OBJECT_SUBSCHEMA_SYMBOL] = target[OBJECT_SUBSCHEMA_SYMBOL];
224 combinedResult[UNPATHED_ERRORS_SYMBOL] = target[UNPATHED_ERRORS_SYMBOL].concat(errors);
225 return combinedResult;
226}
227
228function isSubschemaConfig(value) {
229 return Boolean(value === null || value === void 0 ? void 0 : value.schema);
230}
231function cloneSubschemaConfig(subschemaConfig) {
232 const newSubschemaConfig = {
233 ...subschemaConfig,
234 transforms: subschemaConfig.transforms != null ? [...subschemaConfig.transforms] : undefined,
235 };
236 if (newSubschemaConfig.merge != null) {
237 newSubschemaConfig.merge = { ...subschemaConfig.merge };
238 Object.keys(newSubschemaConfig.merge).forEach(typeName => {
239 newSubschemaConfig.merge[typeName] = { ...subschemaConfig.merge[typeName] };
240 const fields = newSubschemaConfig.merge[typeName].fields;
241 if (fields != null) {
242 Object.keys(fields).forEach(fieldName => {
243 fields[fieldName] = { ...fields[fieldName] };
244 });
245 }
246 const computedFields = newSubschemaConfig.merge[typeName].computedFields;
247 if (computedFields != null) {
248 Object.keys(computedFields).forEach(fieldName => {
249 computedFields[fieldName] = { ...computedFields[fieldName] };
250 });
251 }
252 });
253 }
254 return newSubschemaConfig;
255}
256
257function memoizeInfoAnd2Objects(fn) {
258 let cache1;
259 function memoized(a1, a2, a3) {
260 if (!cache1) {
261 cache1 = new WeakMap();
262 const cache2 = new WeakMap();
263 cache1.set(a1.fieldNodes, cache2);
264 const cache3 = new WeakMap();
265 cache2.set(a2, cache3);
266 const newValue = fn(a1, a2, a3);
267 cache3.set(a3, newValue);
268 return newValue;
269 }
270 let cache2 = cache1.get(a1.fieldNodes);
271 if (!cache2) {
272 cache2 = new WeakMap();
273 cache1.set(a1.fieldNodes, cache2);
274 const cache3 = new WeakMap();
275 cache2.set(a2, cache3);
276 const newValue = fn(a1, a2, a3);
277 cache3.set(a3, newValue);
278 return newValue;
279 }
280 let cache3 = cache2.get(a2);
281 if (!cache3) {
282 cache3 = new WeakMap();
283 cache2.set(a2, cache3);
284 const newValue = fn(a1, a2, a3);
285 cache3.set(a3, newValue);
286 return newValue;
287 }
288 const cachedValue = cache3.get(a3);
289 if (cachedValue === undefined) {
290 const newValue = fn(a1, a2, a3);
291 cache3.set(a3, newValue);
292 return newValue;
293 }
294 return cachedValue;
295 }
296 return memoized;
297}
298function memoize4(fn) {
299 let cache1;
300 function memoized(a1, a2, a3, a4) {
301 if (!cache1) {
302 cache1 = new WeakMap();
303 const cache2 = new WeakMap();
304 cache1.set(a1, cache2);
305 const cache3 = new WeakMap();
306 cache2.set(a2, cache3);
307 const cache4 = new WeakMap();
308 cache3.set(a3, cache4);
309 const newValue = fn(a1, a2, a3, a4);
310 cache4.set(a4, newValue);
311 return newValue;
312 }
313 let cache2 = cache1.get(a1);
314 if (!cache2) {
315 cache2 = new WeakMap();
316 cache1.set(a1, cache2);
317 const cache3 = new WeakMap();
318 cache2.set(a2, cache3);
319 const cache4 = new WeakMap();
320 cache3.set(a3, cache4);
321 const newValue = fn(a1, a2, a3, a4);
322 cache4.set(a4, newValue);
323 return newValue;
324 }
325 let cache3 = cache2.get(a2);
326 if (!cache3) {
327 cache3 = new WeakMap();
328 cache2.set(a2, cache3);
329 const cache4 = new WeakMap();
330 cache3.set(a3, cache4);
331 const newValue = fn(a1, a2, a3, a4);
332 cache4.set(a4, newValue);
333 return newValue;
334 }
335 const cache4 = cache3.get(a3);
336 if (!cache4) {
337 const cache4 = new WeakMap();
338 cache3.set(a3, cache4);
339 const newValue = fn(a1, a2, a3, a4);
340 cache4.set(a4, newValue);
341 return newValue;
342 }
343 const cachedValue = cache4.get(a4);
344 if (cachedValue === undefined) {
345 const newValue = fn(a1, a2, a3, a4);
346 cache4.set(a4, newValue);
347 return newValue;
348 }
349 return cachedValue;
350 }
351 return memoized;
352}
353function memoize3(fn) {
354 let cache1;
355 function memoized(a1, a2, a3) {
356 if (!cache1) {
357 cache1 = new WeakMap();
358 const cache2 = new WeakMap();
359 cache1.set(a1, cache2);
360 const cache3 = new WeakMap();
361 cache2.set(a2, cache3);
362 const newValue = fn(a1, a2, a3);
363 cache3.set(a3, newValue);
364 return newValue;
365 }
366 let cache2 = cache1.get(a1);
367 if (!cache2) {
368 cache2 = new WeakMap();
369 cache1.set(a1, cache2);
370 const cache3 = new WeakMap();
371 cache2.set(a2, cache3);
372 const newValue = fn(a1, a2, a3);
373 cache3.set(a3, newValue);
374 return newValue;
375 }
376 let cache3 = cache2.get(a2);
377 if (!cache3) {
378 cache3 = new WeakMap();
379 cache2.set(a2, cache3);
380 const newValue = fn(a1, a2, a3);
381 cache3.set(a3, newValue);
382 return newValue;
383 }
384 const cachedValue = cache3.get(a3);
385 if (cachedValue === undefined) {
386 const newValue = fn(a1, a2, a3);
387 cache3.set(a3, newValue);
388 return newValue;
389 }
390 return cachedValue;
391 }
392 return memoized;
393}
394function memoize2(fn) {
395 let cache1;
396 function memoized(a1, a2) {
397 if (!cache1) {
398 cache1 = new WeakMap();
399 const cache2 = new WeakMap();
400 cache1.set(a1, cache2);
401 const newValue = fn(a1, a2);
402 cache2.set(a2, newValue);
403 return newValue;
404 }
405 let cache2 = cache1.get(a1);
406 if (!cache2) {
407 cache2 = new WeakMap();
408 cache1.set(a1, cache2);
409 const newValue = fn(a1, a2);
410 cache2.set(a2, newValue);
411 return newValue;
412 }
413 const cachedValue = cache2.get(a2);
414 if (cachedValue === undefined) {
415 const newValue = fn(a1, a2);
416 cache2.set(a2, newValue);
417 return newValue;
418 }
419 return cachedValue;
420 }
421 return memoized;
422}
423
424function collectSubFields(info, typeName) {
425 let subFieldNodes = Object.create(null);
426 const visitedFragmentNames = Object.create(null);
427 const type = info.schema.getType(typeName);
428 const partialExecutionContext = {
429 schema: info.schema,
430 variableValues: info.variableValues,
431 fragments: info.fragments,
432 };
433 info.fieldNodes.forEach(fieldNode => {
434 subFieldNodes = utils.collectFields(partialExecutionContext, type, fieldNode.selectionSet, subFieldNodes, visitedFragmentNames);
435 });
436 const stitchingInfo = info.schema.extensions.stitchingInfo;
437 const selectionSetsByField = stitchingInfo.selectionSetsByField;
438 Object.keys(subFieldNodes).forEach(responseName => {
439 var _a;
440 const fieldName = subFieldNodes[responseName][0].name.value;
441 const fieldSelectionSet = (_a = selectionSetsByField === null || selectionSetsByField === void 0 ? void 0 : selectionSetsByField[typeName]) === null || _a === void 0 ? void 0 : _a[fieldName];
442 if (fieldSelectionSet != null) {
443 subFieldNodes = utils.collectFields(partialExecutionContext, type, fieldSelectionSet, subFieldNodes, visitedFragmentNames);
444 }
445 });
446 return subFieldNodes;
447}
448const getFieldsNotInSubschema = memoizeInfoAnd2Objects(function (info, subschema, mergedTypeInfo) {
449 const typeMap = isSubschemaConfig(subschema) ? mergedTypeInfo.typeMaps.get(subschema) : subschema.getTypeMap();
450 const typeName = mergedTypeInfo.typeName;
451 const fields = typeMap[typeName].getFields();
452 const subFieldNodes = collectSubFields(info, typeName);
453 let fieldsNotInSchema = [];
454 Object.keys(subFieldNodes).forEach(responseName => {
455 const fieldName = subFieldNodes[responseName][0].name.value;
456 if (!(fieldName in fields)) {
457 fieldsNotInSchema = fieldsNotInSchema.concat(subFieldNodes[responseName]);
458 }
459 });
460 return fieldsNotInSchema;
461});
462
463const sortSubschemasByProxiability = memoize4(function (mergedTypeInfo, sourceSubschemaOrSourceSubschemas, targetSubschemas, fieldNodes) {
464 // 1. calculate if possible to delegate to given subschema
465 const proxiableSubschemas = [];
466 const nonProxiableSubschemas = [];
467 targetSubschemas.forEach(t => {
468 const selectionSet = mergedTypeInfo.selectionSets.get(t);
469 const fieldSelectionSets = mergedTypeInfo.fieldSelectionSets.get(t);
470 if (selectionSet != null &&
471 !subschemaTypesContainSelectionSet(mergedTypeInfo, sourceSubschemaOrSourceSubschemas, selectionSet)) {
472 nonProxiableSubschemas.push(t);
473 }
474 else {
475 if (fieldSelectionSets == null ||
476 fieldNodes.every(fieldNode => {
477 const fieldName = fieldNode.name.value;
478 const fieldSelectionSet = fieldSelectionSets[fieldName];
479 return (fieldSelectionSet == null ||
480 subschemaTypesContainSelectionSet(mergedTypeInfo, sourceSubschemaOrSourceSubschemas, fieldSelectionSet));
481 })) {
482 proxiableSubschemas.push(t);
483 }
484 else {
485 nonProxiableSubschemas.push(t);
486 }
487 }
488 });
489 return {
490 proxiableSubschemas,
491 nonProxiableSubschemas,
492 };
493});
494const buildDelegationPlan = memoize3(function (mergedTypeInfo, fieldNodes, proxiableSubschemas) {
495 const { uniqueFields, nonUniqueFields } = mergedTypeInfo;
496 const unproxiableFieldNodes = [];
497 // 2. for each selection:
498 const delegationMap = new Map();
499 fieldNodes.forEach(fieldNode => {
500 if (fieldNode.name.value === '__typename') {
501 return;
502 }
503 // 2a. use uniqueFields map to assign fields to subschema if one of possible subschemas
504 const uniqueSubschema = uniqueFields[fieldNode.name.value];
505 if (uniqueSubschema != null) {
506 if (!proxiableSubschemas.includes(uniqueSubschema)) {
507 unproxiableFieldNodes.push(fieldNode);
508 return;
509 }
510 const existingSubschema = delegationMap.get(uniqueSubschema);
511 if (existingSubschema != null) {
512 existingSubschema.push(fieldNode);
513 }
514 else {
515 delegationMap.set(uniqueSubschema, [fieldNode]);
516 }
517 return;
518 }
519 // 2b. use nonUniqueFields to assign to a possible subschema,
520 // preferring one of the subschemas already targets of delegation
521 let nonUniqueSubschemas = nonUniqueFields[fieldNode.name.value];
522 if (nonUniqueSubschemas == null) {
523 unproxiableFieldNodes.push(fieldNode);
524 return;
525 }
526 nonUniqueSubschemas = nonUniqueSubschemas.filter(s => proxiableSubschemas.includes(s));
527 if (nonUniqueSubschemas == null) {
528 unproxiableFieldNodes.push(fieldNode);
529 return;
530 }
531 const subschemas = Array.from(delegationMap.keys());
532 const existingSubschema = nonUniqueSubschemas.find(s => subschemas.includes(s));
533 if (existingSubschema != null) {
534 delegationMap.get(existingSubschema).push(fieldNode);
535 }
536 else {
537 delegationMap.set(nonUniqueSubschemas[0], [fieldNode]);
538 }
539 });
540 const finalDelegationMap = new Map();
541 delegationMap.forEach((selections, subschema) => {
542 finalDelegationMap.set(subschema, {
543 kind: graphql.Kind.SELECTION_SET,
544 selections,
545 });
546 });
547 return {
548 delegationMap: finalDelegationMap,
549 unproxiableFieldNodes,
550 };
551});
552const combineSubschemas = memoize2(function (subschemaOrSubschemas, additionalSubschemas) {
553 return Array.isArray(subschemaOrSubschemas)
554 ? subschemaOrSubschemas.concat(additionalSubschemas)
555 : [subschemaOrSubschemas].concat(additionalSubschemas);
556});
557function mergeFields(mergedTypeInfo, typeName, object, fieldNodes, sourceSubschemaOrSourceSubschemas, targetSubschemas, context, info) {
558 if (!fieldNodes.length) {
559 return object;
560 }
561 const { proxiableSubschemas, nonProxiableSubschemas } = sortSubschemasByProxiability(mergedTypeInfo, sourceSubschemaOrSourceSubschemas, targetSubschemas, fieldNodes);
562 const { delegationMap, unproxiableFieldNodes } = buildDelegationPlan(mergedTypeInfo, fieldNodes, proxiableSubschemas);
563 if (!delegationMap.size) {
564 return object;
565 }
566 let containsPromises = false;
567 const resultMap = new Map();
568 delegationMap.forEach((selectionSet, s) => {
569 const resolver = mergedTypeInfo.resolvers.get(s);
570 let maybePromise = resolver(object, context, info, s, selectionSet);
571 if (isPromise(maybePromise)) {
572 containsPromises = true;
573 maybePromise = maybePromise.then(undefined, error => error);
574 }
575 resultMap.set(maybePromise, selectionSet);
576 });
577 return containsPromises
578 ? Promise.all(resultMap.keys()).then(results => mergeFields(mergedTypeInfo, typeName, mergeExternalObjects(info.schema, graphql.responsePathAsArray(info.path), object.__typename, object, results, Array.from(resultMap.values())), unproxiableFieldNodes, combineSubschemas(sourceSubschemaOrSourceSubschemas, proxiableSubschemas), nonProxiableSubschemas, context, info))
579 : mergeFields(mergedTypeInfo, typeName, mergeExternalObjects(info.schema, graphql.responsePathAsArray(info.path), object.__typename, object, Array.from(resultMap.keys()), Array.from(resultMap.values())), unproxiableFieldNodes, combineSubschemas(sourceSubschemaOrSourceSubschemas, proxiableSubschemas), nonProxiableSubschemas, context, info);
580}
581const subschemaTypesContainSelectionSet = memoize3(function (mergedTypeInfo, sourceSubschemaOrSourceSubschemas, selectionSet) {
582 if (Array.isArray(sourceSubschemaOrSourceSubschemas)) {
583 return typesContainSelectionSet(sourceSubschemaOrSourceSubschemas.map(sourceSubschema => sourceSubschema.transformedSchema.getType(mergedTypeInfo.typeName)), selectionSet);
584 }
585 return typesContainSelectionSet([sourceSubschemaOrSourceSubschemas.transformedSchema.getType(mergedTypeInfo.typeName)], selectionSet);
586});
587function typesContainSelectionSet(types, selectionSet) {
588 const fieldMaps = types.map(type => type.getFields());
589 for (const selection of selectionSet.selections) {
590 if (selection.kind === graphql.Kind.FIELD) {
591 const fields = fieldMaps.map(fieldMap => fieldMap[selection.name.value]).filter(field => field != null);
592 if (!fields.length) {
593 return false;
594 }
595 if (selection.selectionSet != null) {
596 return typesContainSelectionSet(fields.map(field => graphql.getNamedType(field.type)), selection.selectionSet);
597 }
598 }
599 else if (selection.kind === graphql.Kind.INLINE_FRAGMENT && selection.typeCondition.name.value === types[0].name) {
600 return typesContainSelectionSet(types, selection.selectionSet);
601 }
602 }
603 return true;
604}
605
606function resolveExternalValue(result, unpathedErrors, subschema, context, info, returnType = info.returnType, skipTypeMerging) {
607 const type = graphql.getNullableType(returnType);
608 if (result instanceof Error) {
609 return result;
610 }
611 if (result == null) {
612 return reportUnpathedErrorsViaNull(unpathedErrors);
613 }
614 if (graphql.isLeafType(type)) {
615 return type.parseValue(result);
616 }
617 else if (graphql.isCompositeType(type)) {
618 return resolveExternalObject(type, result, unpathedErrors, subschema, context, info, skipTypeMerging);
619 }
620 else if (graphql.isListType(type)) {
621 return resolveExternalList(type, result, unpathedErrors, subschema, context, info, skipTypeMerging);
622 }
623}
624function resolveExternalObject(type, object, unpathedErrors, subschema, context, info, skipTypeMerging) {
625 var _a;
626 const stitchingInfo = (_a = info === null || info === void 0 ? void 0 : info.schema.extensions) === null || _a === void 0 ? void 0 : _a.stitchingInfo;
627 annotateExternalObject(object, unpathedErrors, subschema);
628 if (skipTypeMerging || !stitchingInfo) {
629 return object;
630 }
631 let typeName;
632 if (graphql.isAbstractType(type)) {
633 const resolvedType = info.schema.getTypeMap()[object.__typename];
634 if (resolvedType == null) {
635 throw new Error(`Unable to resolve type '${object.__typename}'. Did you forget to include a transform that renames types? Did you delegate to the original subschema rather that the subschema config object containing the transform?`);
636 }
637 typeName = resolvedType.name;
638 }
639 else {
640 typeName = type.name;
641 }
642 const mergedTypeInfo = stitchingInfo.mergedTypes[typeName];
643 let targetSubschemas;
644 // Within the stitching context, delegation to a stitched GraphQLSchema or SubschemaConfig
645 // will be redirected to the appropriate Subschema object, from which merge targets can be queried.
646 if (mergedTypeInfo != null) {
647 targetSubschemas = mergedTypeInfo.targetSubschemas.get(subschema);
648 }
649 // If there are no merge targets from the subschema, return.
650 if (!targetSubschemas) {
651 return object;
652 }
653 const fieldNodes = getFieldsNotInSubschema(info, subschema, mergedTypeInfo);
654 return mergeFields(mergedTypeInfo, typeName, object, fieldNodes, subschema, targetSubschemas, context, info);
655}
656function resolveExternalList(type, list, unpathedErrors, subschema, context, info, skipTypeMerging) {
657 return list.map(listMember => resolveExternalListMember(graphql.getNullableType(type.ofType), listMember, unpathedErrors, subschema, context, info, skipTypeMerging));
658}
659function resolveExternalListMember(type, listMember, unpathedErrors, subschema, context, info, skipTypeMerging) {
660 if (listMember instanceof Error) {
661 return listMember;
662 }
663 if (listMember == null) {
664 return reportUnpathedErrorsViaNull(unpathedErrors);
665 }
666 if (graphql.isLeafType(type)) {
667 return type.parseValue(listMember);
668 }
669 else if (graphql.isCompositeType(type)) {
670 return resolveExternalObject(type, listMember, unpathedErrors, subschema, context, info, skipTypeMerging);
671 }
672 else if (graphql.isListType(type)) {
673 return resolveExternalList(type, listMember, unpathedErrors, subschema, context, info, skipTypeMerging);
674 }
675}
676const reportedErrors = new Map();
677function reportUnpathedErrorsViaNull(unpathedErrors) {
678 if (unpathedErrors.length) {
679 const unreportedErrors = [];
680 unpathedErrors.forEach(error => {
681 if (!reportedErrors.has(error)) {
682 unreportedErrors.push(error);
683 reportedErrors.set(error, true);
684 }
685 });
686 if (unreportedErrors.length) {
687 if (unreportedErrors.length === 1) {
688 return unreportedErrors[0];
689 }
690 const combinedError = new AggregateError(unreportedErrors);
691 return graphql.locatedError(combinedError, undefined, unreportedErrors[0].path);
692 }
693 }
694 return null;
695}
696
697/**
698 * Resolver that knows how to:
699 * a) handle aliases for proxied schemas
700 * b) handle errors from proxied schemas
701 * c) handle external to internal enum coversion
702 */
703function defaultMergedResolver(parent, args, context, info) {
704 if (!parent) {
705 return null;
706 }
707 const responseKey = utils.getResponseKeyFromInfo(info);
708 // check to see if parent is not a proxied result, i.e. if parent resolver was manually overwritten
709 // See https://github.com/apollographql/graphql-tools/issues/967
710 if (!isExternalObject(parent)) {
711 return graphql.defaultFieldResolver(parent, args, context, info);
712 }
713 const data = parent[responseKey];
714 const unpathedErrors = getUnpathedErrors(parent);
715 const subschema = getSubschema(parent, responseKey);
716 return resolveExternalValue(data, unpathedErrors, subschema, context, info);
717}
718
719class VisitSelectionSets {
720 constructor(visitor) {
721 this.visitor = visitor;
722 }
723 transformRequest(originalRequest, delegationContext, _transformationContext) {
724 const document = visitSelectionSets(originalRequest, delegationContext.info.schema, delegationContext.returnType, this.visitor);
725 return {
726 ...originalRequest,
727 document,
728 };
729 }
730}
731function visitSelectionSets(request, schema, initialType, visitor) {
732 const { document, variables } = request;
733 const operations = [];
734 const fragments = Object.create(null);
735 document.definitions.forEach(def => {
736 if (def.kind === graphql.Kind.OPERATION_DEFINITION) {
737 operations.push(def);
738 }
739 else if (def.kind === graphql.Kind.FRAGMENT_DEFINITION) {
740 fragments[def.name.value] = def;
741 }
742 });
743 const partialExecutionContext = {
744 schema,
745 variableValues: variables,
746 fragments,
747 };
748 const typeInfo = new graphql.TypeInfo(schema, undefined, initialType);
749 const newDefinitions = operations.map(operation => {
750 const type = operation.operation === 'query'
751 ? schema.getQueryType()
752 : operation.operation === 'mutation'
753 ? schema.getMutationType()
754 : schema.getSubscriptionType();
755 const fields = utils.collectFields(partialExecutionContext, type, operation.selectionSet, Object.create(null), Object.create(null));
756 const newSelections = [];
757 Object.keys(fields).forEach(responseKey => {
758 const fieldNodes = fields[responseKey];
759 fieldNodes.forEach(fieldNode => {
760 const selectionSet = fieldNode.selectionSet;
761 if (selectionSet == null) {
762 newSelections.push(fieldNode);
763 return;
764 }
765 const newSelectionSet = graphql.visit(selectionSet, graphql.visitWithTypeInfo(typeInfo, {
766 [graphql.Kind.SELECTION_SET]: node => visitor(node, typeInfo),
767 }));
768 if (newSelectionSet === selectionSet) {
769 newSelections.push(fieldNode);
770 return;
771 }
772 newSelections.push({
773 ...fieldNode,
774 selectionSet: newSelectionSet,
775 });
776 });
777 });
778 return {
779 ...operation,
780 selectionSet: {
781 kind: graphql.Kind.SELECTION_SET,
782 selections: newSelections,
783 },
784 };
785 });
786 Object.values(fragments).forEach(fragment => {
787 newDefinitions.push(graphql.visit(fragment, graphql.visitWithTypeInfo(typeInfo, {
788 [graphql.Kind.SELECTION_SET]: node => visitor(node, typeInfo),
789 })));
790 });
791 return {
792 ...document,
793 definitions: newDefinitions,
794 };
795}
796
797class AddSelectionSets {
798 constructor(selectionSetsByType, selectionSetsByField, dynamicSelectionSetsByField) {
799 this.transformer = new VisitSelectionSets((node, typeInfo) => visitSelectionSet(node, typeInfo, selectionSetsByType, selectionSetsByField, dynamicSelectionSetsByField));
800 }
801 transformRequest(originalRequest, delegationContext, transformationContext) {
802 return this.transformer.transformRequest(originalRequest, delegationContext, transformationContext);
803 }
804}
805function visitSelectionSet(node, typeInfo, selectionSetsByType, selectionSetsByField, dynamicSelectionSetsByField) {
806 const parentType = typeInfo.getParentType();
807 const newSelections = new Map();
808 if (parentType != null) {
809 const parentTypeName = parentType.name;
810 addSelectionsToMap(newSelections, node);
811 if (parentTypeName in selectionSetsByType) {
812 const selectionSet = selectionSetsByType[parentTypeName];
813 addSelectionsToMap(newSelections, selectionSet);
814 }
815 if (parentTypeName in selectionSetsByField) {
816 node.selections.forEach(selection => {
817 if (selection.kind === graphql.Kind.FIELD) {
818 const name = selection.name.value;
819 const selectionSet = selectionSetsByField[parentTypeName][name];
820 if (selectionSet != null) {
821 addSelectionsToMap(newSelections, selectionSet);
822 }
823 }
824 });
825 }
826 if (parentTypeName in dynamicSelectionSetsByField) {
827 node.selections.forEach(selection => {
828 if (selection.kind === graphql.Kind.FIELD) {
829 const name = selection.name.value;
830 const dynamicSelectionSets = dynamicSelectionSetsByField[parentTypeName][name];
831 if (dynamicSelectionSets != null) {
832 dynamicSelectionSets.forEach(selectionSetFn => {
833 const selectionSet = selectionSetFn(selection);
834 if (selectionSet != null) {
835 addSelectionsToMap(newSelections, selectionSet);
836 }
837 });
838 }
839 }
840 });
841 }
842 return {
843 ...node,
844 selections: Array.from(newSelections.values()),
845 };
846 }
847}
848const addSelectionsToMap = memoize2(function (map, selectionSet) {
849 selectionSet.selections.forEach(selection => {
850 map.set(graphql.print(selection), selection);
851 });
852});
853
854class ExpandAbstractTypes {
855 transformRequest(originalRequest, delegationContext, _transformationContext) {
856 const targetSchema = delegationContext.targetSchema;
857 const { possibleTypesMap, interfaceExtensionsMap } = extractPossibleTypes(delegationContext.info.schema, targetSchema);
858 const reversePossibleTypesMap = flipMapping(possibleTypesMap);
859 const document = expandAbstractTypes(targetSchema, possibleTypesMap, reversePossibleTypesMap, interfaceExtensionsMap, originalRequest.document);
860 return {
861 ...originalRequest,
862 document,
863 };
864 }
865}
866function extractPossibleTypes(sourceSchema, targetSchema) {
867 const typeMap = sourceSchema.getTypeMap();
868 const possibleTypesMap = Object.create(null);
869 const interfaceExtensionsMap = Object.create(null);
870 Object.keys(typeMap).forEach(typeName => {
871 const type = typeMap[typeName];
872 if (graphql.isAbstractType(type)) {
873 const targetType = targetSchema.getType(typeName);
874 if (graphql.isInterfaceType(type) && graphql.isInterfaceType(targetType)) {
875 const targetTypeFields = targetType.getFields();
876 const extensionFields = Object.create(null);
877 Object.keys(type.getFields()).forEach((fieldName) => {
878 if (!targetTypeFields[fieldName]) {
879 extensionFields[fieldName] = true;
880 }
881 });
882 if (Object.keys(extensionFields).length) {
883 interfaceExtensionsMap[typeName] = extensionFields;
884 }
885 }
886 if (!graphql.isAbstractType(targetType) || typeName in interfaceExtensionsMap) {
887 const implementations = sourceSchema.getPossibleTypes(type);
888 possibleTypesMap[typeName] = implementations
889 .filter(impl => targetSchema.getType(impl.name))
890 .map(impl => impl.name);
891 }
892 }
893 });
894 return { possibleTypesMap, interfaceExtensionsMap };
895}
896function flipMapping(mapping) {
897 const result = Object.create(null);
898 Object.keys(mapping).forEach(typeName => {
899 const toTypeNames = mapping[typeName];
900 toTypeNames.forEach(toTypeName => {
901 if (!(toTypeName in result)) {
902 result[toTypeName] = [];
903 }
904 result[toTypeName].push(typeName);
905 });
906 });
907 return result;
908}
909function expandAbstractTypes(targetSchema, possibleTypesMap, reversePossibleTypesMap, interfaceExtensionsMap, document) {
910 const operations = document.definitions.filter(def => def.kind === graphql.Kind.OPERATION_DEFINITION);
911 const fragments = document.definitions.filter(def => def.kind === graphql.Kind.FRAGMENT_DEFINITION);
912 const existingFragmentNames = fragments.map(fragment => fragment.name.value);
913 let fragmentCounter = 0;
914 const generateFragmentName = (typeName) => {
915 let fragmentName;
916 do {
917 fragmentName = `_${typeName}_Fragment${fragmentCounter.toString()}`;
918 fragmentCounter++;
919 } while (existingFragmentNames.indexOf(fragmentName) !== -1);
920 return fragmentName;
921 };
922 const generateInlineFragment = (typeName, selectionSet) => {
923 return {
924 kind: graphql.Kind.INLINE_FRAGMENT,
925 typeCondition: {
926 kind: graphql.Kind.NAMED_TYPE,
927 name: {
928 kind: graphql.Kind.NAME,
929 value: typeName,
930 },
931 },
932 selectionSet,
933 };
934 };
935 const newFragments = [];
936 const fragmentReplacements = Object.create(null);
937 fragments.forEach((fragment) => {
938 newFragments.push(fragment);
939 const possibleTypes = possibleTypesMap[fragment.typeCondition.name.value];
940 if (possibleTypes != null) {
941 fragmentReplacements[fragment.name.value] = [];
942 possibleTypes.forEach(possibleTypeName => {
943 const name = generateFragmentName(possibleTypeName);
944 existingFragmentNames.push(name);
945 const newFragment = {
946 kind: graphql.Kind.FRAGMENT_DEFINITION,
947 name: {
948 kind: graphql.Kind.NAME,
949 value: name,
950 },
951 typeCondition: {
952 kind: graphql.Kind.NAMED_TYPE,
953 name: {
954 kind: graphql.Kind.NAME,
955 value: possibleTypeName,
956 },
957 },
958 selectionSet: fragment.selectionSet,
959 };
960 newFragments.push(newFragment);
961 fragmentReplacements[fragment.name.value].push({
962 fragmentName: name,
963 typeName: possibleTypeName,
964 });
965 });
966 }
967 });
968 const newDocument = {
969 ...document,
970 definitions: [...operations, ...newFragments],
971 };
972 const typeInfo = new graphql.TypeInfo(targetSchema);
973 return graphql.visit(newDocument, graphql.visitWithTypeInfo(typeInfo, {
974 [graphql.Kind.SELECTION_SET](node) {
975 let newSelections = node.selections;
976 const addedSelections = [];
977 const maybeType = typeInfo.getParentType();
978 if (maybeType != null) {
979 const parentType = graphql.getNamedType(maybeType);
980 const interfaceExtension = interfaceExtensionsMap[parentType.name];
981 const interfaceExtensionFields = [];
982 node.selections.forEach((selection) => {
983 if (selection.kind === graphql.Kind.INLINE_FRAGMENT) {
984 if (selection.typeCondition != null) {
985 const possibleTypes = possibleTypesMap[selection.typeCondition.name.value];
986 if (possibleTypes != null) {
987 possibleTypes.forEach(possibleType => {
988 const maybePossibleType = targetSchema.getType(possibleType);
989 if (maybePossibleType != null &&
990 utils.implementsAbstractType(targetSchema, parentType, maybePossibleType)) {
991 addedSelections.push(generateInlineFragment(possibleType, selection.selectionSet));
992 }
993 });
994 }
995 }
996 }
997 else if (selection.kind === graphql.Kind.FRAGMENT_SPREAD) {
998 const fragmentName = selection.name.value;
999 if (fragmentName in fragmentReplacements) {
1000 fragmentReplacements[fragmentName].forEach(replacement => {
1001 const typeName = replacement.typeName;
1002 const maybeReplacementType = targetSchema.getType(typeName);
1003 if (maybeReplacementType != null && utils.implementsAbstractType(targetSchema, parentType, maybeType)) {
1004 addedSelections.push({
1005 kind: graphql.Kind.FRAGMENT_SPREAD,
1006 name: {
1007 kind: graphql.Kind.NAME,
1008 value: replacement.fragmentName,
1009 },
1010 });
1011 }
1012 });
1013 }
1014 }
1015 else if (interfaceExtension != null &&
1016 interfaceExtension[selection.name.value] &&
1017 selection.kind === graphql.Kind.FIELD) {
1018 interfaceExtensionFields.push(selection);
1019 }
1020 });
1021 if (parentType.name in reversePossibleTypesMap) {
1022 addedSelections.push({
1023 kind: graphql.Kind.FIELD,
1024 name: {
1025 kind: graphql.Kind.NAME,
1026 value: '__typename',
1027 },
1028 });
1029 }
1030 if (interfaceExtensionFields.length) {
1031 const possibleTypes = possibleTypesMap[parentType.name];
1032 if (possibleTypes != null) {
1033 possibleTypes.forEach(possibleType => {
1034 addedSelections.push(generateInlineFragment(possibleType, {
1035 kind: graphql.Kind.SELECTION_SET,
1036 selections: interfaceExtensionFields,
1037 }));
1038 });
1039 newSelections = newSelections.filter((selection) => !(selection.kind === graphql.Kind.FIELD && interfaceExtension[selection.name.value]));
1040 }
1041 }
1042 }
1043 if (addedSelections.length) {
1044 return {
1045 ...node,
1046 selections: newSelections.concat(addedSelections),
1047 };
1048 }
1049 },
1050 }));
1051}
1052
1053// For motivation, see https://github.com/ardatan/graphql-tools/issues/751
1054class WrapConcreteTypes {
1055 transformRequest(originalRequest, delegationContext, _transformationContext) {
1056 const document = wrapConcreteTypes(delegationContext.returnType, delegationContext.targetSchema, originalRequest.document);
1057 return {
1058 ...originalRequest,
1059 document,
1060 };
1061 }
1062}
1063function wrapConcreteTypes(returnType, targetSchema, document) {
1064 var _a, _b, _c;
1065 const namedType = graphql.getNamedType(returnType);
1066 if (!graphql.isObjectType(namedType)) {
1067 return document;
1068 }
1069 const queryTypeName = (_a = targetSchema.getQueryType()) === null || _a === void 0 ? void 0 : _a.name;
1070 const mutationTypeName = (_b = targetSchema.getMutationType()) === null || _b === void 0 ? void 0 : _b.name;
1071 const subscriptionTypeName = (_c = targetSchema.getSubscriptionType()) === null || _c === void 0 ? void 0 : _c.name;
1072 const typeInfo = new graphql.TypeInfo(targetSchema);
1073 const newDocument = graphql.visit(document, graphql.visitWithTypeInfo(typeInfo, {
1074 [graphql.Kind.FRAGMENT_DEFINITION]: (node) => {
1075 const typeName = node.typeCondition.name.value;
1076 if (typeName !== queryTypeName && typeName !== mutationTypeName && typeName !== subscriptionTypeName) {
1077 return false;
1078 }
1079 },
1080 [graphql.Kind.FIELD]: (node) => {
1081 if (graphql.isAbstractType(graphql.getNamedType(typeInfo.getType()))) {
1082 return {
1083 ...node,
1084 selectionSet: {
1085 kind: graphql.Kind.SELECTION_SET,
1086 selections: [
1087 {
1088 kind: graphql.Kind.INLINE_FRAGMENT,
1089 typeCondition: {
1090 kind: graphql.Kind.NAMED_TYPE,
1091 name: {
1092 kind: graphql.Kind.NAME,
1093 value: namedType.name,
1094 },
1095 },
1096 selectionSet: node.selectionSet,
1097 },
1098 ],
1099 },
1100 };
1101 }
1102 },
1103 }),
1104 // visitorKeys argument usage a la https://github.com/gatsbyjs/gatsby/blob/master/packages/gatsby-source-graphql/src/batching/merge-queries.js
1105 // empty keys cannot be removed only because of typescript errors
1106 // will hopefully be fixed in future version of graphql-js to be optional
1107 {
1108 Name: [],
1109 Document: ['definitions'],
1110 OperationDefinition: ['selectionSet'],
1111 VariableDefinition: [],
1112 Variable: [],
1113 SelectionSet: ['selections'],
1114 Field: [],
1115 Argument: [],
1116 FragmentSpread: [],
1117 InlineFragment: ['selectionSet'],
1118 FragmentDefinition: ['selectionSet'],
1119 IntValue: [],
1120 FloatValue: [],
1121 StringValue: [],
1122 BooleanValue: [],
1123 NullValue: [],
1124 EnumValue: [],
1125 ListValue: [],
1126 ObjectValue: [],
1127 ObjectField: [],
1128 Directive: [],
1129 NamedType: [],
1130 ListType: [],
1131 NonNullType: [],
1132 SchemaDefinition: [],
1133 OperationTypeDefinition: [],
1134 ScalarTypeDefinition: [],
1135 ObjectTypeDefinition: [],
1136 FieldDefinition: [],
1137 InputValueDefinition: [],
1138 InterfaceTypeDefinition: [],
1139 UnionTypeDefinition: [],
1140 EnumTypeDefinition: [],
1141 EnumValueDefinition: [],
1142 InputObjectTypeDefinition: [],
1143 DirectiveDefinition: [],
1144 SchemaExtension: [],
1145 ScalarTypeExtension: [],
1146 ObjectTypeExtension: [],
1147 InterfaceTypeExtension: [],
1148 UnionTypeExtension: [],
1149 EnumTypeExtension: [],
1150 InputObjectTypeExtension: [],
1151 });
1152 return newDocument;
1153}
1154
1155class FilterToSchema {
1156 transformRequest(originalRequest, delegationContext, _transformationContext) {
1157 return {
1158 ...originalRequest,
1159 ...filterToSchema(delegationContext.targetSchema, originalRequest.document, originalRequest.variables),
1160 };
1161 }
1162}
1163function filterToSchema(targetSchema, document, variables) {
1164 const operations = document.definitions.filter(def => def.kind === graphql.Kind.OPERATION_DEFINITION);
1165 const fragments = document.definitions.filter(def => def.kind === graphql.Kind.FRAGMENT_DEFINITION);
1166 let usedVariables = [];
1167 let usedFragments = [];
1168 const newOperations = [];
1169 let newFragments = [];
1170 const validFragments = fragments.filter((fragment) => {
1171 const typeName = fragment.typeCondition.name.value;
1172 return Boolean(targetSchema.getType(typeName));
1173 });
1174 const validFragmentsWithType = validFragments.reduce((prev, fragment) => ({
1175 ...prev,
1176 [fragment.name.value]: targetSchema.getType(fragment.typeCondition.name.value),
1177 }), {});
1178 let fragmentSet = Object.create(null);
1179 operations.forEach((operation) => {
1180 let type;
1181 if (operation.operation === 'subscription') {
1182 type = targetSchema.getSubscriptionType();
1183 }
1184 else if (operation.operation === 'mutation') {
1185 type = targetSchema.getMutationType();
1186 }
1187 else {
1188 type = targetSchema.getQueryType();
1189 }
1190 const { selectionSet, usedFragments: operationUsedFragments, usedVariables: operationUsedVariables, } = filterSelectionSet(targetSchema, type, validFragmentsWithType, operation.selectionSet);
1191 usedFragments = union(usedFragments, operationUsedFragments);
1192 const { usedVariables: collectedUsedVariables, newFragments: collectedNewFragments, fragmentSet: collectedFragmentSet, } = collectFragmentVariables(targetSchema, fragmentSet, validFragments, validFragmentsWithType, usedFragments);
1193 const operationOrFragmentVariables = union(operationUsedVariables, collectedUsedVariables);
1194 usedVariables = union(usedVariables, operationOrFragmentVariables);
1195 newFragments = collectedNewFragments;
1196 fragmentSet = collectedFragmentSet;
1197 const variableDefinitions = operation.variableDefinitions.filter((variable) => operationOrFragmentVariables.indexOf(variable.variable.name.value) !== -1);
1198 newOperations.push({
1199 kind: graphql.Kind.OPERATION_DEFINITION,
1200 operation: operation.operation,
1201 name: operation.name,
1202 directives: operation.directives,
1203 variableDefinitions,
1204 selectionSet,
1205 });
1206 });
1207 const newVariables = usedVariables.reduce((acc, variableName) => {
1208 const variableValue = variables[variableName];
1209 if (variableValue !== undefined) {
1210 acc[variableName] = variableValue;
1211 }
1212 return acc;
1213 }, {});
1214 return {
1215 document: {
1216 kind: graphql.Kind.DOCUMENT,
1217 definitions: [...newOperations, ...newFragments],
1218 },
1219 variables: newVariables,
1220 };
1221}
1222function collectFragmentVariables(targetSchema, fragmentSet, validFragments, validFragmentsWithType, usedFragments) {
1223 let remainingFragments = usedFragments.slice();
1224 let usedVariables = [];
1225 const newFragments = [];
1226 while (remainingFragments.length !== 0) {
1227 const nextFragmentName = remainingFragments.pop();
1228 const fragment = validFragments.find(fr => fr.name.value === nextFragmentName);
1229 if (fragment != null) {
1230 const name = nextFragmentName;
1231 const typeName = fragment.typeCondition.name.value;
1232 const type = targetSchema.getType(typeName);
1233 const { selectionSet, usedFragments: fragmentUsedFragments, usedVariables: fragmentUsedVariables, } = filterSelectionSet(targetSchema, type, validFragmentsWithType, fragment.selectionSet);
1234 remainingFragments = union(remainingFragments, fragmentUsedFragments);
1235 usedVariables = union(usedVariables, fragmentUsedVariables);
1236 if (!(name in fragmentSet)) {
1237 fragmentSet[name] = true;
1238 newFragments.push({
1239 kind: graphql.Kind.FRAGMENT_DEFINITION,
1240 name: {
1241 kind: graphql.Kind.NAME,
1242 value: name,
1243 },
1244 typeCondition: fragment.typeCondition,
1245 selectionSet,
1246 });
1247 }
1248 }
1249 }
1250 return {
1251 usedVariables,
1252 newFragments,
1253 fragmentSet,
1254 };
1255}
1256function filterSelectionSet(schema, type, validFragments, selectionSet) {
1257 const usedFragments = [];
1258 const usedVariables = [];
1259 const typeInfo = new graphql.TypeInfo(schema, undefined, type);
1260 const filteredSelectionSet = graphql.visit(selectionSet, graphql.visitWithTypeInfo(typeInfo, {
1261 [graphql.Kind.FIELD]: {
1262 enter(node) {
1263 const parentType = typeInfo.getParentType();
1264 if (graphql.isObjectType(parentType) || graphql.isInterfaceType(parentType)) {
1265 const fields = parentType.getFields();
1266 const field = node.name.value === '__typename' ? graphql.TypeNameMetaFieldDef : fields[node.name.value];
1267 if (!field) {
1268 return null;
1269 }
1270 const argNames = (field.args != null ? field.args : []).map(arg => arg.name);
1271 if (node.arguments != null) {
1272 const args = node.arguments.filter((arg) => argNames.indexOf(arg.name.value) !== -1);
1273 if (args.length !== node.arguments.length) {
1274 return {
1275 ...node,
1276 arguments: args,
1277 };
1278 }
1279 }
1280 }
1281 },
1282 leave(node) {
1283 const resolvedType = graphql.getNamedType(typeInfo.getType());
1284 if (graphql.isObjectType(resolvedType) || graphql.isInterfaceType(resolvedType)) {
1285 const selections = node.selectionSet != null ? node.selectionSet.selections : null;
1286 if (selections == null || selections.length === 0) {
1287 // need to remove any added variables. Is there a better way to do this?
1288 graphql.visit(node, {
1289 [graphql.Kind.VARIABLE](variableNode) {
1290 const index = usedVariables.indexOf(variableNode.name.value);
1291 if (index !== -1) {
1292 usedVariables.splice(index, 1);
1293 }
1294 },
1295 });
1296 return null;
1297 }
1298 }
1299 },
1300 },
1301 [graphql.Kind.FRAGMENT_SPREAD](node) {
1302 if (node.name.value in validFragments) {
1303 const parentType = typeInfo.getParentType();
1304 const innerType = validFragments[node.name.value];
1305 if (!utils.implementsAbstractType(schema, parentType, innerType)) {
1306 return null;
1307 }
1308 usedFragments.push(node.name.value);
1309 return;
1310 }
1311 return null;
1312 },
1313 [graphql.Kind.INLINE_FRAGMENT]: {
1314 enter(node) {
1315 if (node.typeCondition != null) {
1316 const parentType = typeInfo.getParentType();
1317 const innerType = schema.getType(node.typeCondition.name.value);
1318 if (!utils.implementsAbstractType(schema, parentType, innerType)) {
1319 return null;
1320 }
1321 }
1322 },
1323 },
1324 [graphql.Kind.VARIABLE](node) {
1325 usedVariables.push(node.name.value);
1326 },
1327 }));
1328 return {
1329 selectionSet: filteredSelectionSet,
1330 usedFragments,
1331 usedVariables,
1332 };
1333}
1334function union(...arrays) {
1335 const cache = Object.create(null);
1336 const result = [];
1337 arrays.forEach(array => {
1338 array.forEach(item => {
1339 if (!(item in cache)) {
1340 cache[item] = true;
1341 result.push(item);
1342 }
1343 });
1344 });
1345 return result;
1346}
1347
1348class AddTypenameToAbstract {
1349 transformRequest(originalRequest, delegationContext, _transformationContext) {
1350 const document = addTypenameToAbstract(delegationContext.targetSchema, originalRequest.document);
1351 return {
1352 ...originalRequest,
1353 document,
1354 };
1355 }
1356}
1357function addTypenameToAbstract(targetSchema, document) {
1358 const typeInfo = new graphql.TypeInfo(targetSchema);
1359 return graphql.visit(document, graphql.visitWithTypeInfo(typeInfo, {
1360 [graphql.Kind.SELECTION_SET](node) {
1361 const parentType = typeInfo.getParentType();
1362 let selections = node.selections;
1363 if (parentType != null && graphql.isAbstractType(parentType)) {
1364 selections = selections.concat({
1365 kind: graphql.Kind.FIELD,
1366 name: {
1367 kind: graphql.Kind.NAME,
1368 value: '__typename',
1369 },
1370 });
1371 }
1372 if (selections !== node.selections) {
1373 return {
1374 ...node,
1375 selections,
1376 };
1377 }
1378 },
1379 }));
1380}
1381
1382class CheckResultAndHandleErrors {
1383 transformResult(originalResult, delegationContext, _transformationContext) {
1384 return checkResultAndHandleErrors(originalResult, delegationContext.context != null ? delegationContext.context : {}, delegationContext.info, delegationContext.fieldName, delegationContext.subschema, delegationContext.returnType, delegationContext.skipTypeMerging, delegationContext.onLocatedError);
1385 }
1386}
1387function checkResultAndHandleErrors(result, context, info, responseKey = utils.getResponseKeyFromInfo(info), subschema, returnType = info.returnType, skipTypeMerging, onLocatedError) {
1388 const { data, unpathedErrors } = mergeDataAndErrors(result.data == null ? undefined : result.data[responseKey], result.errors == null ? [] : result.errors, info ? graphql.responsePathAsArray(info.path) : undefined, onLocatedError);
1389 return resolveExternalValue(data, unpathedErrors, subschema, context, info, returnType, skipTypeMerging);
1390}
1391function mergeDataAndErrors(data, errors, path, onLocatedError, index = 1) {
1392 if (data == null) {
1393 if (!errors.length) {
1394 return { data: null, unpathedErrors: [] };
1395 }
1396 if (errors.length === 1) {
1397 const error = onLocatedError ? onLocatedError(errors[0]) : errors[0];
1398 const newPath = path === undefined ? error.path : error.path === undefined ? path : path.concat(error.path.slice(1));
1399 return { data: utils.relocatedError(errors[0], newPath), unpathedErrors: [] };
1400 }
1401 const newError = graphql.locatedError(new AggregateError(errors), undefined, path);
1402 return { data: newError, unpathedErrors: [] };
1403 }
1404 if (!errors.length) {
1405 return { data, unpathedErrors: [] };
1406 }
1407 let unpathedErrors = [];
1408 const errorMap = Object.create(null);
1409 errors.forEach(error => {
1410 var _a;
1411 const pathSegment = (_a = error.path) === null || _a === void 0 ? void 0 : _a[index];
1412 if (pathSegment != null) {
1413 const pathSegmentErrors = errorMap[pathSegment];
1414 if (pathSegmentErrors === undefined) {
1415 errorMap[pathSegment] = [error];
1416 }
1417 else {
1418 pathSegmentErrors.push(error);
1419 }
1420 }
1421 else {
1422 unpathedErrors.push(error);
1423 }
1424 });
1425 Object.keys(errorMap).forEach(pathSegment => {
1426 if (data[pathSegment] !== undefined) {
1427 const { data: newData, unpathedErrors: newErrors } = mergeDataAndErrors(data[pathSegment], errorMap[pathSegment], path, onLocatedError, index + 1);
1428 data[pathSegment] = newData;
1429 unpathedErrors = unpathedErrors.concat(newErrors);
1430 }
1431 else {
1432 unpathedErrors = unpathedErrors.concat(errorMap[pathSegment]);
1433 }
1434 });
1435 return { data, unpathedErrors };
1436}
1437
1438class AddArgumentsAsVariables {
1439 constructor(args) {
1440 this.args = Object.entries(args).reduce((prev, [key, val]) => ({
1441 ...prev,
1442 [key]: val,
1443 }), {});
1444 }
1445 transformRequest(originalRequest, delegationContext, _transformationContext) {
1446 const { document, variables } = addVariablesToRootField(delegationContext.targetSchema, originalRequest, this.args);
1447 return {
1448 ...originalRequest,
1449 document,
1450 variables,
1451 };
1452 }
1453}
1454function addVariablesToRootField(targetSchema, originalRequest, args) {
1455 const document = originalRequest.document;
1456 const variableValues = originalRequest.variables;
1457 const operations = document.definitions.filter(def => def.kind === graphql.Kind.OPERATION_DEFINITION);
1458 const fragments = document.definitions.filter(def => def.kind === graphql.Kind.FRAGMENT_DEFINITION);
1459 const newOperations = operations.map((operation) => {
1460 const variableDefinitionMap = operation.variableDefinitions.reduce((prev, def) => ({
1461 ...prev,
1462 [def.variable.name.value]: def,
1463 }), {});
1464 let type;
1465 if (operation.operation === 'subscription') {
1466 type = targetSchema.getSubscriptionType();
1467 }
1468 else if (operation.operation === 'mutation') {
1469 type = targetSchema.getMutationType();
1470 }
1471 else {
1472 type = targetSchema.getQueryType();
1473 }
1474 const newSelectionSet = [];
1475 operation.selectionSet.selections.forEach((selection) => {
1476 var _a;
1477 if (selection.kind === graphql.Kind.FIELD) {
1478 const argumentNodes = (_a = selection.arguments) !== null && _a !== void 0 ? _a : [];
1479 const argumentNodeMap = argumentNodes.reduce((prev, argument) => ({
1480 ...prev,
1481 [argument.name.value]: argument,
1482 }), {});
1483 const targetField = type.getFields()[selection.name.value];
1484 // excludes __typename
1485 if (targetField != null) {
1486 updateArguments(targetField, argumentNodeMap, variableDefinitionMap, variableValues, args);
1487 }
1488 newSelectionSet.push({
1489 ...selection,
1490 arguments: Object.keys(argumentNodeMap).map(argName => argumentNodeMap[argName]),
1491 });
1492 }
1493 else {
1494 newSelectionSet.push(selection);
1495 }
1496 });
1497 return {
1498 ...operation,
1499 variableDefinitions: Object.keys(variableDefinitionMap).map(varName => variableDefinitionMap[varName]),
1500 selectionSet: {
1501 kind: graphql.Kind.SELECTION_SET,
1502 selections: newSelectionSet,
1503 },
1504 };
1505 });
1506 return {
1507 document: {
1508 ...document,
1509 definitions: [...newOperations, ...fragments],
1510 },
1511 variables: variableValues,
1512 };
1513}
1514function updateArguments(targetField, argumentNodeMap, variableDefinitionMap, variableValues, newArgs) {
1515 targetField.args.forEach((argument) => {
1516 const argName = argument.name;
1517 const argType = argument.type;
1518 if (argName in newArgs) {
1519 utils.updateArgument(argName, argType, argumentNodeMap, variableDefinitionMap, variableValues, utils.serializeInputValue(argType, newArgs[argName]));
1520 }
1521 });
1522}
1523
1524function defaultDelegationBinding(delegationContext) {
1525 var _a;
1526 let delegationTransforms = [new CheckResultAndHandleErrors()];
1527 const info = delegationContext.info;
1528 const stitchingInfo = (_a = info === null || info === void 0 ? void 0 : info.schema.extensions) === null || _a === void 0 ? void 0 : _a.stitchingInfo;
1529 if (stitchingInfo != null) {
1530 delegationTransforms = delegationTransforms.concat([
1531 new ExpandAbstractTypes(),
1532 new AddSelectionSets({}, stitchingInfo.selectionSetsByField, stitchingInfo.dynamicSelectionSetsByField),
1533 new WrapConcreteTypes(),
1534 ]);
1535 }
1536 else if (info != null) {
1537 delegationTransforms = delegationTransforms.concat([new WrapConcreteTypes(), new ExpandAbstractTypes()]);
1538 }
1539 else {
1540 delegationTransforms.push(new WrapConcreteTypes());
1541 }
1542 const transforms = delegationContext.transforms;
1543 if (transforms != null) {
1544 delegationTransforms = delegationTransforms.concat(transforms.slice().reverse());
1545 }
1546 const args = delegationContext.args;
1547 if (args != null) {
1548 delegationTransforms.push(new AddArgumentsAsVariables(args));
1549 }
1550 delegationTransforms = delegationTransforms.concat([new FilterToSchema(), new AddTypenameToAbstract()]);
1551 return delegationTransforms;
1552}
1553
1554class Transformer {
1555 constructor(context, binding = defaultDelegationBinding) {
1556 this.transformations = [];
1557 this.delegationContext = context;
1558 const delegationTransforms = binding(this.delegationContext);
1559 delegationTransforms.forEach(transform => this.addTransform(transform, {}));
1560 }
1561 addTransform(transform, context = {}) {
1562 this.transformations.push({ transform, context });
1563 }
1564 transformRequest(originalRequest) {
1565 return this.transformations.reduce((request, transformation) => transformation.transform.transformRequest != null
1566 ? transformation.transform.transformRequest(request, this.delegationContext, transformation.context)
1567 : request, originalRequest);
1568 }
1569 transformResult(originalResult) {
1570 return this.transformations.reduceRight((result, transformation) => transformation.transform.transformResult != null
1571 ? transformation.transform.transformResult(result, this.delegationContext, transformation.context)
1572 : result, originalResult);
1573 }
1574}
1575
1576function delegateToSchema(options) {
1577 const { info, operationName, operation = getDelegatingOperation(info.parentType, info.schema), fieldName = info.fieldName, returnType = info.returnType, selectionSet, fieldNodes, } = options;
1578 const request = createRequestFromInfo({
1579 info,
1580 operation,
1581 fieldName,
1582 selectionSet,
1583 fieldNodes,
1584 operationName,
1585 });
1586 return delegateRequest({
1587 ...options,
1588 request,
1589 operation,
1590 fieldName,
1591 returnType,
1592 });
1593}
1594function getDelegationReturnType(targetSchema, operation, fieldName) {
1595 let rootType;
1596 if (operation === 'query') {
1597 rootType = targetSchema.getQueryType();
1598 }
1599 else if (operation === 'mutation') {
1600 rootType = targetSchema.getMutationType();
1601 }
1602 else {
1603 rootType = targetSchema.getSubscriptionType();
1604 }
1605 return rootType.getFields()[fieldName].type;
1606}
1607function delegateRequest({ request, schema: subschemaOrSubschemaConfig, rootValue, info, operation, fieldName, args, returnType, onLocatedError, context, transforms = [], transformedSchema, skipValidation, skipTypeMerging, binding, }) {
1608 var _a, _b, _c;
1609 let operationDefinition;
1610 let targetOperation;
1611 let targetFieldName;
1612 if (operation == null) {
1613 operationDefinition = graphql.getOperationAST(request.document, undefined);
1614 targetOperation = operationDefinition.operation;
1615 }
1616 else {
1617 targetOperation = operation;
1618 }
1619 if (fieldName == null) {
1620 operationDefinition = operationDefinition !== null && operationDefinition !== void 0 ? operationDefinition : graphql.getOperationAST(request.document, undefined);
1621 targetFieldName = operationDefinition.selectionSet.selections[0].name.value;
1622 }
1623 else {
1624 targetFieldName = fieldName;
1625 }
1626 const { targetSchema, targetRootValue, subschemaConfig, allTransforms } = collectTargetParameters(subschemaOrSubschemaConfig, rootValue, info, transforms);
1627 const delegationContext = {
1628 subschema: subschemaOrSubschemaConfig,
1629 targetSchema,
1630 operation: targetOperation,
1631 fieldName: targetFieldName,
1632 args,
1633 context,
1634 info,
1635 returnType: (_a = returnType !== null && returnType !== void 0 ? returnType : info === null || info === void 0 ? void 0 : info.returnType) !== null && _a !== void 0 ? _a : getDelegationReturnType(targetSchema, targetOperation, targetFieldName),
1636 onLocatedError,
1637 transforms: allTransforms,
1638 transformedSchema: (_c = transformedSchema !== null && transformedSchema !== void 0 ? transformedSchema : (_b = subschemaConfig) === null || _b === void 0 ? void 0 : _b.transformedSchema) !== null && _c !== void 0 ? _c : targetSchema,
1639 skipTypeMerging,
1640 };
1641 const transformer = new Transformer(delegationContext, binding);
1642 const processedRequest = transformer.transformRequest(request);
1643 if (!skipValidation) {
1644 validateRequest(targetSchema, processedRequest.document);
1645 }
1646 if (targetOperation === 'query' || targetOperation === 'mutation') {
1647 let executor = (subschemaConfig === null || subschemaConfig === void 0 ? void 0 : subschemaConfig.executor) || createDefaultExecutor(targetSchema, (subschemaConfig === null || subschemaConfig === void 0 ? void 0 : subschemaConfig.rootValue) || targetRootValue);
1648 if (subschemaConfig === null || subschemaConfig === void 0 ? void 0 : subschemaConfig.batch) {
1649 const batchingOptions = subschemaConfig === null || subschemaConfig === void 0 ? void 0 : subschemaConfig.batchingOptions;
1650 executor = batchExecute.getBatchingExecutor(context, executor, batchingOptions === null || batchingOptions === void 0 ? void 0 : batchingOptions.dataLoaderOptions, batchingOptions === null || batchingOptions === void 0 ? void 0 : batchingOptions.extensionsReducer);
1651 }
1652 const executionResult = executor({
1653 ...processedRequest,
1654 context,
1655 info,
1656 });
1657 if (isPromise(executionResult)) {
1658 return executionResult.then(originalResult => {
1659 return transformer.transformResult(originalResult);
1660 });
1661 }
1662 return transformer.transformResult(executionResult);
1663 }
1664 const subscriber = (subschemaConfig === null || subschemaConfig === void 0 ? void 0 : subschemaConfig.subscriber) || createDefaultSubscriber(targetSchema, (subschemaConfig === null || subschemaConfig === void 0 ? void 0 : subschemaConfig.rootValue) || targetRootValue);
1665 return subscriber({
1666 ...processedRequest,
1667 context,
1668 info,
1669 }).then((subscriptionResult) => {
1670 if (Symbol.asyncIterator in subscriptionResult) {
1671 // "subscribe" to the subscription result and map the result through the transforms
1672 return utils.mapAsyncIterator(subscriptionResult, originalResult => ({
1673 [targetFieldName]: transformer.transformResult(originalResult),
1674 }));
1675 }
1676 return transformer.transformResult(subscriptionResult);
1677 });
1678}
1679const emptyObject = {};
1680function collectTargetParameters(subschema, rootValue, info, transforms = []) {
1681 var _a, _b, _c, _d, _e;
1682 const stitchingInfo = (_a = info === null || info === void 0 ? void 0 : info.schema.extensions) === null || _a === void 0 ? void 0 : _a.stitchingInfo;
1683 const subschemaOrSubschemaConfig = (_b = stitchingInfo === null || stitchingInfo === void 0 ? void 0 : stitchingInfo.subschemaMap.get(subschema)) !== null && _b !== void 0 ? _b : subschema;
1684 if (isSubschemaConfig(subschemaOrSubschemaConfig)) {
1685 return {
1686 targetSchema: subschemaOrSubschemaConfig.schema,
1687 targetRootValue: (_d = (_c = rootValue !== null && rootValue !== void 0 ? rootValue : subschemaOrSubschemaConfig === null || subschemaOrSubschemaConfig === void 0 ? void 0 : subschemaOrSubschemaConfig.rootValue) !== null && _c !== void 0 ? _c : info === null || info === void 0 ? void 0 : info.rootValue) !== null && _d !== void 0 ? _d : emptyObject,
1688 subschemaConfig: subschemaOrSubschemaConfig,
1689 allTransforms: subschemaOrSubschemaConfig.transforms != null
1690 ? subschemaOrSubschemaConfig.transforms.concat(transforms)
1691 : transforms,
1692 };
1693 }
1694 return {
1695 targetSchema: subschemaOrSubschemaConfig,
1696 targetRootValue: (_e = rootValue !== null && rootValue !== void 0 ? rootValue : info === null || info === void 0 ? void 0 : info.rootValue) !== null && _e !== void 0 ? _e : emptyObject,
1697 allTransforms: transforms,
1698 };
1699}
1700function validateRequest(targetSchema, document) {
1701 const errors = graphql.validate(targetSchema, document);
1702 if (errors.length > 0) {
1703 if (errors.length > 1) {
1704 const combinedError = new AggregateError(errors);
1705 throw combinedError;
1706 }
1707 const error = errors[0];
1708 throw error.originalError || error;
1709 }
1710}
1711const createDefaultExecutor = memoize2(function (schema, rootValue) {
1712 return (({ document, context, variables, info }) => graphql.execute({
1713 schema,
1714 document,
1715 contextValue: context,
1716 variableValues: variables,
1717 rootValue: rootValue !== null && rootValue !== void 0 ? rootValue : info === null || info === void 0 ? void 0 : info.rootValue,
1718 }));
1719});
1720function createDefaultSubscriber(schema, rootValue) {
1721 return ({ document, context, variables, info }) => graphql.subscribe({
1722 schema,
1723 document,
1724 contextValue: context,
1725 variableValues: variables,
1726 rootValue: rootValue !== null && rootValue !== void 0 ? rootValue : info === null || info === void 0 ? void 0 : info.rootValue,
1727 });
1728}
1729
1730exports.AddArgumentsAsVariables = AddArgumentsAsVariables;
1731exports.AddSelectionSets = AddSelectionSets;
1732exports.AddTypenameToAbstract = AddTypenameToAbstract;
1733exports.CheckResultAndHandleErrors = CheckResultAndHandleErrors;
1734exports.ExpandAbstractTypes = ExpandAbstractTypes;
1735exports.FilterToSchema = FilterToSchema;
1736exports.Subschema = Subschema;
1737exports.VisitSelectionSets = VisitSelectionSets;
1738exports.annotateExternalObject = annotateExternalObject;
1739exports.applySchemaTransforms = applySchemaTransforms;
1740exports.checkResultAndHandleErrors = checkResultAndHandleErrors;
1741exports.cloneSubschemaConfig = cloneSubschemaConfig;
1742exports.createRequest = createRequest;
1743exports.createRequestFromInfo = createRequestFromInfo;
1744exports.defaultDelegationBinding = defaultDelegationBinding;
1745exports.defaultMergedResolver = defaultMergedResolver;
1746exports.delegateRequest = delegateRequest;
1747exports.delegateToSchema = delegateToSchema;
1748exports.getDelegatingOperation = getDelegatingOperation;
1749exports.getSubschema = getSubschema;
1750exports.getUnpathedErrors = getUnpathedErrors;
1751exports.isExternalObject = isExternalObject;
1752exports.isSubschema = isSubschema;
1753exports.isSubschemaConfig = isSubschemaConfig;
1754exports.mergeExternalObjects = mergeExternalObjects;
1755exports.resolveExternalValue = resolveExternalValue;
1756//# sourceMappingURL=index.cjs.js.map