@graphql-tools/delegate 8.2.2-alpha-5d885fa3.0 → 9.0.0-alpha-881b29e4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Subschema.d.ts +2 -6
- package/Transformer.d.ts +1 -1
- package/defaultMergedResolver.d.ts +3 -1
- package/delegateToSchema.d.ts +5 -2
- package/externalObjects.d.ts +11 -0
- package/externalValues.d.ts +4 -0
- package/getMergedParent.d.ts +9 -0
- package/index.d.ts +3 -2
- package/index.js +631 -305
- package/index.mjs +620 -306
- package/mergeDataAndErrors.d.ts +5 -0
- package/package.json +4 -4
- package/symbols.d.ts +5 -1
- package/types.d.ts +21 -13
- package/checkResultAndHandleErrors.d.ts +0 -8
- package/es5/README.md +0 -7
- package/es5/Subschema.d.ts +0 -19
- package/es5/Transformer.d.ts +0 -10
- package/es5/applySchemaTransforms.d.ts +0 -3
- package/es5/checkResultAndHandleErrors.d.ts +0 -8
- package/es5/createRequest.d.ts +0 -6
- package/es5/defaultMergedResolver.d.ts +0 -9
- package/es5/delegateToSchema.d.ts +0 -6
- package/es5/finalizeGatewayRequest.d.ts +0 -3
- package/es5/getDocumentMetadata.d.ts +0 -6
- package/es5/index.d.ts +0 -10
- package/es5/index.js +0 -1694
- package/es5/index.mjs +0 -1672
- package/es5/mergeFields.d.ts +0 -8
- package/es5/package.json +0 -39
- package/es5/prepareGatewayDocument.d.ts +0 -2
- package/es5/resolveExternalValue.d.ts +0 -3
- package/es5/subschemaConfig.d.ts +0 -3
- package/es5/symbols.d.ts +0 -3
- package/es5/types.d.ts +0 -149
- package/mergeFields.d.ts +0 -8
- package/resolveExternalValue.d.ts +0 -3
package/index.mjs
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { Kind, isAbstractType, isInterfaceType, TypeInfo, visit, visitWithTypeInfo, getNamedType, isObjectType, versionInfo, TypeNameMetaFieldDef,
|
|
2
|
-
import { memoize2, implementsAbstractType, getRootTypeNames, getDefinedRootType, createVariableNameGenerator, updateArgument, serializeInputValue, inspect,
|
|
1
|
+
import { Kind, isAbstractType, isInterfaceType, TypeInfo, visit, visitWithTypeInfo, getNamedType, isObjectType, versionInfo, TypeNameMetaFieldDef, typeFromAST, locatedError, responsePathAsArray, getNullableType, GraphQLError, isCompositeType, isListType, defaultFieldResolver, getOperationAST, GraphQLSchema, isSchema, validate, subscribe, execute } from 'graphql';
|
|
2
|
+
import { memoize2, implementsAbstractType, getRootTypeNames, getDefinedRootType, createVariableNameGenerator, updateArgument, serializeInputValue, inspect, relocatedError, AggregateError, memoize1, memoize4ofMany, collectFields, memoize3, getResponseKeyFromInfo, isAsyncIterable, mapAsyncIterator } from '@graphql-tools/utils';
|
|
3
|
+
import DataLoader from 'dataloader';
|
|
3
4
|
import { ValueOrPromise } from 'value-or-promise';
|
|
4
5
|
import { getBatchingExecutor } from '@graphql-tools/batch-execute';
|
|
5
6
|
|
|
@@ -665,262 +666,6 @@ function union(...arrays) {
|
|
|
665
666
|
return result;
|
|
666
667
|
}
|
|
667
668
|
|
|
668
|
-
const UNPATHED_ERRORS_SYMBOL = Symbol('subschemaErrors');
|
|
669
|
-
const OBJECT_SUBSCHEMA_SYMBOL = Symbol('initialSubschema');
|
|
670
|
-
const FIELD_SUBSCHEMA_MAP_SYMBOL = Symbol('subschemaMap');
|
|
671
|
-
|
|
672
|
-
function isExternalObject(data) {
|
|
673
|
-
return data[UNPATHED_ERRORS_SYMBOL] !== undefined;
|
|
674
|
-
}
|
|
675
|
-
function annotateExternalObject(object, errors, subschema, subschemaMap) {
|
|
676
|
-
Object.defineProperties(object, {
|
|
677
|
-
[OBJECT_SUBSCHEMA_SYMBOL]: { value: subschema },
|
|
678
|
-
[FIELD_SUBSCHEMA_MAP_SYMBOL]: { value: subschemaMap },
|
|
679
|
-
[UNPATHED_ERRORS_SYMBOL]: { value: errors },
|
|
680
|
-
});
|
|
681
|
-
return object;
|
|
682
|
-
}
|
|
683
|
-
function getSubschema(object, responseKey) {
|
|
684
|
-
var _a;
|
|
685
|
-
return (_a = object[FIELD_SUBSCHEMA_MAP_SYMBOL][responseKey]) !== null && _a !== void 0 ? _a : object[OBJECT_SUBSCHEMA_SYMBOL];
|
|
686
|
-
}
|
|
687
|
-
function getUnpathedErrors(object) {
|
|
688
|
-
return object[UNPATHED_ERRORS_SYMBOL];
|
|
689
|
-
}
|
|
690
|
-
const EMPTY_ARRAY = [];
|
|
691
|
-
const EMPTY_OBJECT = Object.create(null);
|
|
692
|
-
async function mergeFields(mergedTypeInfo, object, sourceSubschema, context, info) {
|
|
693
|
-
var _a;
|
|
694
|
-
const delegationMaps = mergedTypeInfo.delegationPlanBuilder(info.schema, sourceSubschema, info.variableValues != null && Object.keys(info.variableValues).length > 0 ? info.variableValues : EMPTY_OBJECT, info.fragments != null && Object.keys(info.fragments).length > 0 ? info.fragments : EMPTY_OBJECT, ((_a = info.fieldNodes) === null || _a === void 0 ? void 0 : _a.length) ? info.fieldNodes : EMPTY_ARRAY);
|
|
695
|
-
for (const delegationMap of delegationMaps) {
|
|
696
|
-
await executeDelegationStage(mergedTypeInfo, delegationMap, object, context, info);
|
|
697
|
-
}
|
|
698
|
-
return object;
|
|
699
|
-
}
|
|
700
|
-
async function executeDelegationStage(mergedTypeInfo, delegationMap, object, context, info) {
|
|
701
|
-
const combinedErrors = object[UNPATHED_ERRORS_SYMBOL];
|
|
702
|
-
const path = responsePathAsArray(info.path);
|
|
703
|
-
const combinedFieldSubschemaMap = object[FIELD_SUBSCHEMA_MAP_SYMBOL];
|
|
704
|
-
const type = info.schema.getType(object.__typename);
|
|
705
|
-
await Promise.all([...delegationMap.entries()].map(async ([s, selectionSet]) => {
|
|
706
|
-
var _a;
|
|
707
|
-
const resolver = mergedTypeInfo.resolvers.get(s);
|
|
708
|
-
if (resolver) {
|
|
709
|
-
let source;
|
|
710
|
-
try {
|
|
711
|
-
source = await resolver(object, context, info, s, selectionSet);
|
|
712
|
-
}
|
|
713
|
-
catch (error) {
|
|
714
|
-
source = error;
|
|
715
|
-
}
|
|
716
|
-
if (source instanceof Error || source == null) {
|
|
717
|
-
const fieldNodeResponseKeyMap = collectFields(info.schema, {}, {}, type, selectionSet, new Map(), new Set());
|
|
718
|
-
const nullResult = {};
|
|
719
|
-
for (const [responseKey, fieldNodes] of fieldNodeResponseKeyMap) {
|
|
720
|
-
const combinedPath = [...path, responseKey];
|
|
721
|
-
if (source instanceof GraphQLError) {
|
|
722
|
-
nullResult[responseKey] = relocatedError(source, combinedPath);
|
|
723
|
-
}
|
|
724
|
-
else if (source instanceof Error) {
|
|
725
|
-
nullResult[responseKey] = locatedError(source, fieldNodes, combinedPath);
|
|
726
|
-
}
|
|
727
|
-
else {
|
|
728
|
-
nullResult[responseKey] = null;
|
|
729
|
-
}
|
|
730
|
-
}
|
|
731
|
-
source = nullResult;
|
|
732
|
-
}
|
|
733
|
-
else {
|
|
734
|
-
if (source[UNPATHED_ERRORS_SYMBOL]) {
|
|
735
|
-
combinedErrors.push(...source[UNPATHED_ERRORS_SYMBOL]);
|
|
736
|
-
}
|
|
737
|
-
}
|
|
738
|
-
const objectSubschema = source[OBJECT_SUBSCHEMA_SYMBOL];
|
|
739
|
-
const fieldSubschemaMap = source[FIELD_SUBSCHEMA_MAP_SYMBOL];
|
|
740
|
-
for (const responseKey in source) {
|
|
741
|
-
object[responseKey] = source[responseKey];
|
|
742
|
-
combinedFieldSubschemaMap[responseKey] = (_a = fieldSubschemaMap === null || fieldSubschemaMap === void 0 ? void 0 : fieldSubschemaMap[responseKey]) !== null && _a !== void 0 ? _a : objectSubschema;
|
|
743
|
-
}
|
|
744
|
-
}
|
|
745
|
-
}));
|
|
746
|
-
}
|
|
747
|
-
|
|
748
|
-
function resolveExternalValue(result, unpathedErrors, subschema, context, info, returnType = getReturnType(info), skipTypeMerging) {
|
|
749
|
-
const type = getNullableType(returnType);
|
|
750
|
-
if (result instanceof Error) {
|
|
751
|
-
return result;
|
|
752
|
-
}
|
|
753
|
-
if (result == null) {
|
|
754
|
-
return reportUnpathedErrorsViaNull(unpathedErrors);
|
|
755
|
-
}
|
|
756
|
-
if ('parseValue' in type) {
|
|
757
|
-
return type.parseValue(result);
|
|
758
|
-
}
|
|
759
|
-
else if (isCompositeType(type)) {
|
|
760
|
-
return resolveExternalObject(type, result, unpathedErrors, subschema, context, info, skipTypeMerging);
|
|
761
|
-
}
|
|
762
|
-
else if (isListType(type)) {
|
|
763
|
-
return resolveExternalList(type, result, unpathedErrors, subschema, context, info, skipTypeMerging);
|
|
764
|
-
}
|
|
765
|
-
}
|
|
766
|
-
function resolveExternalObject(type, object, unpathedErrors, subschema, context, info, skipTypeMerging) {
|
|
767
|
-
var _a;
|
|
768
|
-
// if we have already resolved this object, for example, when the identical object appears twice
|
|
769
|
-
// in a list, see https://github.com/ardatan/graphql-tools/issues/2304
|
|
770
|
-
if (!isExternalObject(object)) {
|
|
771
|
-
annotateExternalObject(object, unpathedErrors, subschema, Object.create(null));
|
|
772
|
-
}
|
|
773
|
-
if (skipTypeMerging || info == null) {
|
|
774
|
-
return object;
|
|
775
|
-
}
|
|
776
|
-
const stitchingInfo = (_a = info.schema.extensions) === null || _a === void 0 ? void 0 : _a['stitchingInfo'];
|
|
777
|
-
if (stitchingInfo == null) {
|
|
778
|
-
return object;
|
|
779
|
-
}
|
|
780
|
-
let typeName;
|
|
781
|
-
if (isAbstractType(type)) {
|
|
782
|
-
const resolvedType = info.schema.getType(object.__typename);
|
|
783
|
-
if (resolvedType == null) {
|
|
784
|
-
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?`);
|
|
785
|
-
}
|
|
786
|
-
typeName = resolvedType.name;
|
|
787
|
-
}
|
|
788
|
-
else {
|
|
789
|
-
typeName = type.name;
|
|
790
|
-
}
|
|
791
|
-
const mergedTypeInfo = stitchingInfo.mergedTypes[typeName];
|
|
792
|
-
let targetSubschemas;
|
|
793
|
-
// Within the stitching context, delegation to a stitched GraphQLSchema or SubschemaConfig
|
|
794
|
-
// will be redirected to the appropriate Subschema object, from which merge targets can be queried.
|
|
795
|
-
if (mergedTypeInfo != null) {
|
|
796
|
-
targetSubschemas = mergedTypeInfo.targetSubschemas.get(subschema);
|
|
797
|
-
}
|
|
798
|
-
// If there are no merge targets from the subschema, return.
|
|
799
|
-
if (!targetSubschemas || !targetSubschemas.length) {
|
|
800
|
-
return object;
|
|
801
|
-
}
|
|
802
|
-
return mergeFields(mergedTypeInfo, object, subschema, context, info);
|
|
803
|
-
}
|
|
804
|
-
function resolveExternalList(type, list, unpathedErrors, subschema, context, info, skipTypeMerging) {
|
|
805
|
-
return list.map(listMember => resolveExternalListMember(getNullableType(type.ofType), listMember, unpathedErrors, subschema, context, info, skipTypeMerging));
|
|
806
|
-
}
|
|
807
|
-
function resolveExternalListMember(type, listMember, unpathedErrors, subschema, context, info, skipTypeMerging) {
|
|
808
|
-
if (listMember instanceof Error) {
|
|
809
|
-
return listMember;
|
|
810
|
-
}
|
|
811
|
-
if (listMember == null) {
|
|
812
|
-
return reportUnpathedErrorsViaNull(unpathedErrors);
|
|
813
|
-
}
|
|
814
|
-
if ('parseValue' in type) {
|
|
815
|
-
return type.parseValue(listMember);
|
|
816
|
-
}
|
|
817
|
-
else if (isCompositeType(type)) {
|
|
818
|
-
return resolveExternalObject(type, listMember, unpathedErrors, subschema, context, info, skipTypeMerging);
|
|
819
|
-
}
|
|
820
|
-
else if (isListType(type)) {
|
|
821
|
-
return resolveExternalList(type, listMember, unpathedErrors, subschema, context, info, skipTypeMerging);
|
|
822
|
-
}
|
|
823
|
-
}
|
|
824
|
-
const reportedErrors = new WeakMap();
|
|
825
|
-
function reportUnpathedErrorsViaNull(unpathedErrors) {
|
|
826
|
-
if (unpathedErrors.length) {
|
|
827
|
-
const unreportedErrors = [];
|
|
828
|
-
for (const error of unpathedErrors) {
|
|
829
|
-
if (!reportedErrors.has(error)) {
|
|
830
|
-
unreportedErrors.push(error);
|
|
831
|
-
reportedErrors.set(error, true);
|
|
832
|
-
}
|
|
833
|
-
}
|
|
834
|
-
if (unreportedErrors.length) {
|
|
835
|
-
if (unreportedErrors.length === 1) {
|
|
836
|
-
return unreportedErrors[0];
|
|
837
|
-
}
|
|
838
|
-
const combinedError = new AggregateError(unreportedErrors);
|
|
839
|
-
// We cast path as any for GraphQL.js 14 compat
|
|
840
|
-
// locatedError path argument must be defined, but it is just forwarded to a constructor that allows a undefined value
|
|
841
|
-
// https://github.com/graphql/graphql-js/blob/b4bff0ba9c15c9d7245dd68556e754c41f263289/src/error/locatedError.js#L25
|
|
842
|
-
// https://github.com/graphql/graphql-js/blob/b4bff0ba9c15c9d7245dd68556e754c41f263289/src/error/GraphQLError.js#L19
|
|
843
|
-
return locatedError(combinedError, undefined, unreportedErrors[0].path);
|
|
844
|
-
}
|
|
845
|
-
}
|
|
846
|
-
return null;
|
|
847
|
-
}
|
|
848
|
-
function getReturnType(info) {
|
|
849
|
-
if (info == null) {
|
|
850
|
-
throw new Error(`Return type cannot be inferred without a source schema.`);
|
|
851
|
-
}
|
|
852
|
-
return info.returnType;
|
|
853
|
-
}
|
|
854
|
-
|
|
855
|
-
function checkResultAndHandleErrors(result, delegationContext) {
|
|
856
|
-
const { context, info, fieldName: responseKey = getResponseKey(info), subschema, returnType = getReturnType$1(info), skipTypeMerging, onLocatedError, } = delegationContext;
|
|
857
|
-
const { data, unpathedErrors } = mergeDataAndErrors(result.data == null ? undefined : result.data[responseKey], result.errors == null ? [] : result.errors, info != null && info.path ? responsePathAsArray(info.path) : undefined, onLocatedError);
|
|
858
|
-
return resolveExternalValue(data, unpathedErrors, subschema, context, info, returnType, skipTypeMerging);
|
|
859
|
-
}
|
|
860
|
-
function mergeDataAndErrors(data, errors, path, onLocatedError, index = 1) {
|
|
861
|
-
var _a;
|
|
862
|
-
if (data == null) {
|
|
863
|
-
if (!errors.length) {
|
|
864
|
-
return { data: null, unpathedErrors: [] };
|
|
865
|
-
}
|
|
866
|
-
if (errors.length === 1) {
|
|
867
|
-
const error = onLocatedError ? onLocatedError(errors[0]) : errors[0];
|
|
868
|
-
const newPath = path === undefined ? error.path : error.path === undefined ? path : path.concat(error.path.slice(1));
|
|
869
|
-
return { data: relocatedError(errors[0], newPath), unpathedErrors: [] };
|
|
870
|
-
}
|
|
871
|
-
// We cast path as any for GraphQL.js 14 compat
|
|
872
|
-
// locatedError path argument must be defined, but it is just forwarded to a constructor that allows a undefined value
|
|
873
|
-
// https://github.com/graphql/graphql-js/blob/b4bff0ba9c15c9d7245dd68556e754c41f263289/src/error/locatedError.js#L25
|
|
874
|
-
// https://github.com/graphql/graphql-js/blob/b4bff0ba9c15c9d7245dd68556e754c41f263289/src/error/GraphQLError.js#L19
|
|
875
|
-
const newError = locatedError(new AggregateError(errors), undefined, path);
|
|
876
|
-
return { data: newError, unpathedErrors: [] };
|
|
877
|
-
}
|
|
878
|
-
if (!errors.length) {
|
|
879
|
-
return { data, unpathedErrors: [] };
|
|
880
|
-
}
|
|
881
|
-
const unpathedErrors = [];
|
|
882
|
-
const errorMap = new Map();
|
|
883
|
-
for (const error of errors) {
|
|
884
|
-
const pathSegment = (_a = error.path) === null || _a === void 0 ? void 0 : _a[index];
|
|
885
|
-
if (pathSegment != null) {
|
|
886
|
-
let pathSegmentErrors = errorMap.get(pathSegment);
|
|
887
|
-
if (pathSegmentErrors === undefined) {
|
|
888
|
-
pathSegmentErrors = [error];
|
|
889
|
-
errorMap.set(pathSegment, pathSegmentErrors);
|
|
890
|
-
}
|
|
891
|
-
else {
|
|
892
|
-
pathSegmentErrors.push(error);
|
|
893
|
-
}
|
|
894
|
-
}
|
|
895
|
-
else {
|
|
896
|
-
unpathedErrors.push(error);
|
|
897
|
-
}
|
|
898
|
-
}
|
|
899
|
-
for (const [pathSegment, pathSegmentErrors] of errorMap) {
|
|
900
|
-
if (data[pathSegment] !== undefined) {
|
|
901
|
-
const { data: newData, unpathedErrors: newErrors } = mergeDataAndErrors(data[pathSegment], pathSegmentErrors, path, onLocatedError, index + 1);
|
|
902
|
-
data[pathSegment] = newData;
|
|
903
|
-
unpathedErrors.push(...newErrors);
|
|
904
|
-
}
|
|
905
|
-
else {
|
|
906
|
-
unpathedErrors.push(...pathSegmentErrors);
|
|
907
|
-
}
|
|
908
|
-
}
|
|
909
|
-
return { data, unpathedErrors };
|
|
910
|
-
}
|
|
911
|
-
function getResponseKey(info) {
|
|
912
|
-
if (info == null) {
|
|
913
|
-
throw new Error(`Data cannot be extracted from result without an explicit key or source schema.`);
|
|
914
|
-
}
|
|
915
|
-
return getResponseKeyFromInfo(info);
|
|
916
|
-
}
|
|
917
|
-
function getReturnType$1(info) {
|
|
918
|
-
if (info == null) {
|
|
919
|
-
throw new Error(`Return type cannot be inferred without a source schema.`);
|
|
920
|
-
}
|
|
921
|
-
return info.returnType;
|
|
922
|
-
}
|
|
923
|
-
|
|
924
669
|
class Transformer {
|
|
925
670
|
constructor(context) {
|
|
926
671
|
this.transformations = [];
|
|
@@ -956,7 +701,7 @@ class Transformer {
|
|
|
956
701
|
result = transformation.transform.transformResult(result, this.delegationContext, transformation.context);
|
|
957
702
|
}
|
|
958
703
|
}
|
|
959
|
-
return
|
|
704
|
+
return result;
|
|
960
705
|
}
|
|
961
706
|
}
|
|
962
707
|
|
|
@@ -1097,70 +842,578 @@ function updateArgumentsWithDefaults(sourceParentType, sourceFieldName, argument
|
|
|
1097
842
|
}
|
|
1098
843
|
}
|
|
1099
844
|
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
return defaultFieldResolver(parent, args, context, info);
|
|
845
|
+
const INITIAL_PATH_SYMBOL = Symbol('initialPath');
|
|
846
|
+
const UNPATHED_ERRORS_SYMBOL = Symbol('unpathedErrors');
|
|
847
|
+
const OBJECT_SUBSCHEMA_SYMBOL = Symbol('initialSubschema');
|
|
848
|
+
const INITIAL_POSSIBLE_FIELDS = Symbol('initialPossibleFields');
|
|
849
|
+
const INFO_SYMBOL = Symbol('info');
|
|
850
|
+
const RESPONSE_KEY_SUBSCHEMA_MAP_SYMBOL = Symbol('subschemaMap');
|
|
851
|
+
|
|
852
|
+
function isExternalObject(data) {
|
|
853
|
+
return (data === null || data === void 0 ? void 0 : data[UNPATHED_ERRORS_SYMBOL]) !== undefined;
|
|
854
|
+
}
|
|
855
|
+
function annotateExternalObject(object, errors, initialPath, subschema, info) {
|
|
856
|
+
var _a, _b, _c;
|
|
857
|
+
if (isExternalObject(object)) {
|
|
858
|
+
return object;
|
|
1115
859
|
}
|
|
1116
|
-
const
|
|
1117
|
-
const
|
|
1118
|
-
|
|
1119
|
-
|
|
860
|
+
const schema = subschema instanceof Subschema ? subschema.transformedSchema : (_b = (_a = subschema) === null || _a === void 0 ? void 0 : _a.schema) !== null && _b !== void 0 ? _b : subschema;
|
|
861
|
+
const initialPossibleFields = (_c = schema.getType(object.__typename)) === null || _c === void 0 ? void 0 : _c.getFields();
|
|
862
|
+
Object.defineProperties(object, {
|
|
863
|
+
[INITIAL_PATH_SYMBOL]: { value: initialPath },
|
|
864
|
+
[OBJECT_SUBSCHEMA_SYMBOL]: { value: subschema },
|
|
865
|
+
[INITIAL_POSSIBLE_FIELDS]: { value: initialPossibleFields },
|
|
866
|
+
[INFO_SYMBOL]: { value: info },
|
|
867
|
+
[RESPONSE_KEY_SUBSCHEMA_MAP_SYMBOL]: { value: Object.create(null) },
|
|
868
|
+
[UNPATHED_ERRORS_SYMBOL]: { value: errors },
|
|
869
|
+
});
|
|
870
|
+
return object;
|
|
871
|
+
}
|
|
872
|
+
function getInitialPath(object) {
|
|
873
|
+
return object[INITIAL_PATH_SYMBOL];
|
|
874
|
+
}
|
|
875
|
+
function getInitialPossibleFields(object) {
|
|
876
|
+
return object[INITIAL_POSSIBLE_FIELDS];
|
|
877
|
+
}
|
|
878
|
+
function getInfo(object) {
|
|
879
|
+
return object[INFO_SYMBOL];
|
|
880
|
+
}
|
|
881
|
+
function getUnpathedErrors(object) {
|
|
882
|
+
return object[UNPATHED_ERRORS_SYMBOL];
|
|
883
|
+
}
|
|
884
|
+
function getObjectSubchema(object) {
|
|
885
|
+
return object[OBJECT_SUBSCHEMA_SYMBOL];
|
|
886
|
+
}
|
|
887
|
+
function getSubschemaMap(object) {
|
|
888
|
+
return object[RESPONSE_KEY_SUBSCHEMA_MAP_SYMBOL];
|
|
889
|
+
}
|
|
890
|
+
function getSubschema(object, responseKey) {
|
|
891
|
+
var _a;
|
|
892
|
+
return (_a = object[RESPONSE_KEY_SUBSCHEMA_MAP_SYMBOL][responseKey]) !== null && _a !== void 0 ? _a : object[OBJECT_SUBSCHEMA_SYMBOL];
|
|
1120
893
|
}
|
|
1121
894
|
|
|
1122
|
-
function
|
|
1123
|
-
|
|
895
|
+
function mergeDataAndErrors(data, errors = [], onLocatedError = (originalError) => originalError, index = 1) {
|
|
896
|
+
var _a;
|
|
897
|
+
if (data == null) {
|
|
898
|
+
if (!errors.length) {
|
|
899
|
+
return { data: null, unpathedErrors: [] };
|
|
900
|
+
}
|
|
901
|
+
if (errors.length === 1) {
|
|
902
|
+
const error = onLocatedError(errors[0]);
|
|
903
|
+
const newPath = error.path === undefined ? [] : error.path.slice(1);
|
|
904
|
+
const newError = relocatedError(error, newPath);
|
|
905
|
+
return { data: newError, unpathedErrors: [] };
|
|
906
|
+
}
|
|
907
|
+
const newErrors = errors.map(error => onLocatedError(error));
|
|
908
|
+
const firstError = newErrors[0];
|
|
909
|
+
const newPath = firstError.path === undefined ? [] : firstError.path.slice(1);
|
|
910
|
+
// We cast path as any for GraphQL.js 14 compat
|
|
911
|
+
// locatedError path argument must be defined, but it is just forwarded to a constructor that allows a undefined value
|
|
912
|
+
// https://github.com/graphql/graphql-js/blob/b4bff0ba9c15c9d7245dd68556e754c41f263289/src/error/locatedError.js#L25
|
|
913
|
+
// https://github.com/graphql/graphql-js/blob/b4bff0ba9c15c9d7245dd68556e754c41f263289/src/error/GraphQLError.js#L19
|
|
914
|
+
const newError = locatedError(new AggregateError(newErrors), undefined, newPath);
|
|
915
|
+
return { data: newError, unpathedErrors: [] };
|
|
916
|
+
}
|
|
917
|
+
if (!errors.length) {
|
|
918
|
+
return { data, unpathedErrors: [] };
|
|
919
|
+
}
|
|
920
|
+
const unpathedErrors = [];
|
|
921
|
+
const errorMap = new Map();
|
|
922
|
+
for (const error of errors) {
|
|
923
|
+
const pathSegment = (_a = error.path) === null || _a === void 0 ? void 0 : _a[index];
|
|
924
|
+
if (pathSegment != null) {
|
|
925
|
+
let pathSegmentErrors = errorMap.get(pathSegment);
|
|
926
|
+
if (pathSegmentErrors === undefined) {
|
|
927
|
+
pathSegmentErrors = [error];
|
|
928
|
+
errorMap.set(pathSegment, pathSegmentErrors);
|
|
929
|
+
}
|
|
930
|
+
else {
|
|
931
|
+
pathSegmentErrors.push(error);
|
|
932
|
+
}
|
|
933
|
+
}
|
|
934
|
+
else {
|
|
935
|
+
unpathedErrors.push(error);
|
|
936
|
+
}
|
|
937
|
+
}
|
|
938
|
+
for (const [pathSegment, pathSegmentErrors] of errorMap) {
|
|
939
|
+
if (data[pathSegment] !== undefined) {
|
|
940
|
+
const { data: newData, unpathedErrors: newErrors } = mergeDataAndErrors(data[pathSegment], pathSegmentErrors, onLocatedError, index + 1);
|
|
941
|
+
data[pathSegment] = newData;
|
|
942
|
+
unpathedErrors.push(...newErrors);
|
|
943
|
+
}
|
|
944
|
+
else {
|
|
945
|
+
unpathedErrors.push(...pathSegmentErrors);
|
|
946
|
+
}
|
|
947
|
+
}
|
|
948
|
+
return { data, unpathedErrors };
|
|
1124
949
|
}
|
|
1125
|
-
|
|
950
|
+
|
|
951
|
+
function externalValueFromResult({ result, schema, info, context, fieldName = getFieldName(info), returnType = getReturnType(info), onLocatedError = (error) => error, }) {
|
|
1126
952
|
var _a, _b;
|
|
1127
|
-
const
|
|
1128
|
-
|
|
1129
|
-
|
|
953
|
+
const data = (_a = result.data) === null || _a === void 0 ? void 0 : _a[fieldName];
|
|
954
|
+
const errors = (_b = result.errors) !== null && _b !== void 0 ? _b : [];
|
|
955
|
+
const initialPath = info ? responsePathAsArray(info.path) : [];
|
|
956
|
+
const { data: newData, unpathedErrors } = mergeDataAndErrors(data, errors, onLocatedError);
|
|
957
|
+
return createExternalValue(newData, unpathedErrors, initialPath, schema, context, info, returnType);
|
|
958
|
+
}
|
|
959
|
+
function createExternalValue(data, unpathedErrors, initialPath, subschema, context, info, returnType = getReturnType(info)) {
|
|
960
|
+
const type = getNullableType(returnType);
|
|
961
|
+
if (data instanceof GraphQLError) {
|
|
962
|
+
return relocatedError(data, data.path ? initialPath.concat(data.path) : initialPath);
|
|
963
|
+
}
|
|
964
|
+
if (data instanceof Error) {
|
|
965
|
+
return data;
|
|
966
|
+
}
|
|
967
|
+
if (data == null) {
|
|
968
|
+
return reportUnpathedErrorsViaNull(unpathedErrors);
|
|
969
|
+
}
|
|
970
|
+
if ('parseValue' in type) {
|
|
971
|
+
return type.parseValue(data);
|
|
972
|
+
}
|
|
973
|
+
else if (isCompositeType(type)) {
|
|
974
|
+
return annotateExternalObject(data, unpathedErrors, initialPath, subschema, info);
|
|
975
|
+
}
|
|
976
|
+
else if (isListType(type)) {
|
|
977
|
+
return createExternalList(type, data, unpathedErrors, initialPath, subschema, context, info);
|
|
978
|
+
}
|
|
979
|
+
}
|
|
980
|
+
function createExternalList(type, list, unpathedErrors, initialPath, subschema, context, info) {
|
|
981
|
+
return list.map(listMember => createExternalListMember(getNullableType(type.ofType), listMember, unpathedErrors, initialPath, subschema, context, info));
|
|
982
|
+
}
|
|
983
|
+
function createExternalListMember(type, listMember, unpathedErrors, initialPath, subschema, context, info) {
|
|
984
|
+
if (listMember instanceof GraphQLError) {
|
|
985
|
+
return relocatedError(listMember, listMember.path ? initialPath.concat(listMember.path) : initialPath);
|
|
986
|
+
}
|
|
987
|
+
if (listMember instanceof Error) {
|
|
988
|
+
return listMember;
|
|
989
|
+
}
|
|
990
|
+
if (listMember == null) {
|
|
991
|
+
return reportUnpathedErrorsViaNull(unpathedErrors);
|
|
992
|
+
}
|
|
993
|
+
if ('parseValue' in type) {
|
|
994
|
+
return type.parseValue(listMember);
|
|
995
|
+
}
|
|
996
|
+
else if (isCompositeType(type)) {
|
|
997
|
+
return annotateExternalObject(listMember, unpathedErrors, initialPath, subschema, info);
|
|
998
|
+
}
|
|
999
|
+
else if (isListType(type)) {
|
|
1000
|
+
return createExternalList(type, listMember, unpathedErrors, initialPath, subschema, context, info);
|
|
1001
|
+
}
|
|
1002
|
+
}
|
|
1003
|
+
const reportedErrors = new WeakMap();
|
|
1004
|
+
function reportUnpathedErrorsViaNull(unpathedErrors) {
|
|
1005
|
+
if (unpathedErrors.length) {
|
|
1006
|
+
const unreportedErrors = [];
|
|
1007
|
+
for (const error of unpathedErrors) {
|
|
1008
|
+
if (!reportedErrors.has(error)) {
|
|
1009
|
+
unreportedErrors.push(error);
|
|
1010
|
+
reportedErrors.set(error, true);
|
|
1011
|
+
}
|
|
1012
|
+
}
|
|
1013
|
+
if (unreportedErrors.length) {
|
|
1014
|
+
if (unreportedErrors.length === 1) {
|
|
1015
|
+
return unreportedErrors[0];
|
|
1016
|
+
}
|
|
1017
|
+
const combinedError = new AggregateError(unreportedErrors);
|
|
1018
|
+
// We cast path as any for GraphQL.js 14 compat
|
|
1019
|
+
// locatedError path argument must be defined, but it is just forwarded to a constructor that allows a undefined value
|
|
1020
|
+
// https://github.com/graphql/graphql-js/blob/b4bff0ba9c15c9d7245dd68556e754c41f263289/src/error/locatedError.js#L25
|
|
1021
|
+
// https://github.com/graphql/graphql-js/blob/b4bff0ba9c15c9d7245dd68556e754c41f263289/src/error/GraphQLError.js#L19
|
|
1022
|
+
return locatedError(combinedError, undefined, unreportedErrors[0].path);
|
|
1023
|
+
}
|
|
1024
|
+
}
|
|
1025
|
+
return null;
|
|
1026
|
+
}
|
|
1027
|
+
function getFieldName(info) {
|
|
1028
|
+
if (info == null) {
|
|
1029
|
+
throw new Error(`Data cannot be extracted from result without an explicit key or source schema.`);
|
|
1030
|
+
}
|
|
1031
|
+
return info.fieldName;
|
|
1032
|
+
}
|
|
1033
|
+
function getReturnType(info) {
|
|
1034
|
+
if (info == null) {
|
|
1035
|
+
throw new Error(`Return type cannot be inferred without a source schema.`);
|
|
1036
|
+
}
|
|
1037
|
+
return info.returnType;
|
|
1038
|
+
}
|
|
1039
|
+
|
|
1040
|
+
const getMergedTypeInfo = memoize1(function getMergedTypeInfo(info) {
|
|
1041
|
+
var _a;
|
|
1042
|
+
const schema = info.schema;
|
|
1043
|
+
const stitchingInfo = (_a = schema.extensions) === null || _a === void 0 ? void 0 : _a['stitchingInfo'];
|
|
1044
|
+
if (stitchingInfo == null) {
|
|
1045
|
+
return;
|
|
1046
|
+
}
|
|
1047
|
+
const parentTypeName = info.parentType.name;
|
|
1048
|
+
const mergedTypeInfo = stitchingInfo.mergedTypes[parentTypeName];
|
|
1049
|
+
if (mergedTypeInfo === undefined) {
|
|
1050
|
+
return;
|
|
1051
|
+
}
|
|
1052
|
+
return mergedTypeInfo;
|
|
1053
|
+
});
|
|
1054
|
+
const loaders = new WeakMap();
|
|
1055
|
+
async function getMergedParent(parent, context, info) {
|
|
1056
|
+
const mergedTypeInfo = getMergedTypeInfo(info);
|
|
1057
|
+
if (!mergedTypeInfo) {
|
|
1058
|
+
return parent;
|
|
1059
|
+
}
|
|
1060
|
+
// In the stitching context, all subschemas are compiled Subschema objects rather than SubschemaConfig objects
|
|
1061
|
+
const sourceSubschema = getObjectSubchema(parent);
|
|
1062
|
+
let loader = loaders.get(parent);
|
|
1063
|
+
if (loader === undefined) {
|
|
1064
|
+
loader = new DataLoader(fieldNodeArrays => getMergedParentsFromFieldNodes(parent, context, info.schema, fieldNodeArrays, mergedTypeInfo, sourceSubschema));
|
|
1065
|
+
loaders.set(parent, loader);
|
|
1066
|
+
}
|
|
1067
|
+
return loader.load(info.fieldNodes);
|
|
1068
|
+
}
|
|
1069
|
+
async function getMergedParentsFromFieldNodes(parent, context, gatewaySchema, fieldNodeArrays, mergedTypeInfo, sourceSubschema) {
|
|
1070
|
+
const { requiredKeys, delegationMaps, stageMap } = buildDelegationPlan(mergedTypeInfo, gatewaySchema, sourceSubschema, ...fieldNodeArrays);
|
|
1071
|
+
if (!delegationMaps.length) {
|
|
1072
|
+
return Array(fieldNodeArrays.length).fill(parent);
|
|
1073
|
+
}
|
|
1074
|
+
const promises = [];
|
|
1075
|
+
const parentInfo = getInfo(parent);
|
|
1076
|
+
const schema = parentInfo.schema;
|
|
1077
|
+
const type = schema.getType(parent.__typename);
|
|
1078
|
+
const parentPath = responsePathAsArray(parentInfo.path);
|
|
1079
|
+
let promise = executeDelegationStage(delegationMaps[0], schema, type, mergedTypeInfo, context, parent, parentInfo, parentPath);
|
|
1080
|
+
promises.push(promise);
|
|
1081
|
+
for (let i = 1, delegationStage = delegationMaps[i]; i < delegationMaps.length; i++) {
|
|
1082
|
+
promise = promise.then(parent => executeDelegationStage(delegationStage, schema, type, mergedTypeInfo, context, parent, parentInfo, parentPath));
|
|
1083
|
+
promises.push(promise);
|
|
1084
|
+
}
|
|
1085
|
+
return fieldNodeArrays.map(fieldNodeArray => {
|
|
1086
|
+
const fieldName = fieldNodeArray[0].name.value;
|
|
1087
|
+
const keys = requiredKeys[fieldName];
|
|
1088
|
+
if (keys === undefined) {
|
|
1089
|
+
const delegationStage = stageMap[fieldName];
|
|
1090
|
+
if (delegationStage !== undefined) {
|
|
1091
|
+
return promises[delegationStage];
|
|
1092
|
+
}
|
|
1093
|
+
return Promise.resolve(parent);
|
|
1094
|
+
}
|
|
1095
|
+
return Promise.all(Array.from(keys.values()).map(fieldName => {
|
|
1096
|
+
const delegationStage = stageMap[fieldName];
|
|
1097
|
+
if (delegationStage !== undefined) {
|
|
1098
|
+
return promises[delegationStage];
|
|
1099
|
+
}
|
|
1100
|
+
return Promise.resolve(parent);
|
|
1101
|
+
})).then(() => parent);
|
|
1102
|
+
});
|
|
1103
|
+
}
|
|
1104
|
+
function sortSubschemasByProxiability(mergedTypeInfo, sourceSubschemas, targetSubschemas, fieldNodes) {
|
|
1105
|
+
// 1. calculate if possible to delegate to given subschema
|
|
1106
|
+
const proxiableSubschemas = [];
|
|
1107
|
+
const nonProxiableSubschemas = [];
|
|
1108
|
+
for (const t of targetSubschemas) {
|
|
1109
|
+
const selectionSet = mergedTypeInfo.selectionSets.get(t);
|
|
1110
|
+
const fieldSelectionSets = mergedTypeInfo.fieldSelectionSets.get(t);
|
|
1111
|
+
if (selectionSet != null && !subschemaTypesContainSelectionSet(mergedTypeInfo, sourceSubschemas, selectionSet)) {
|
|
1112
|
+
nonProxiableSubschemas.push(t);
|
|
1113
|
+
}
|
|
1114
|
+
else {
|
|
1115
|
+
if (fieldSelectionSets == null ||
|
|
1116
|
+
fieldNodes.every(fieldNode => {
|
|
1117
|
+
const fieldName = fieldNode.name.value;
|
|
1118
|
+
const fieldSelectionSet = fieldSelectionSets[fieldName];
|
|
1119
|
+
return (fieldSelectionSet == null ||
|
|
1120
|
+
subschemaTypesContainSelectionSet(mergedTypeInfo, sourceSubschemas, fieldSelectionSet));
|
|
1121
|
+
})) {
|
|
1122
|
+
proxiableSubschemas.push(t);
|
|
1123
|
+
}
|
|
1124
|
+
else {
|
|
1125
|
+
nonProxiableSubschemas.push(t);
|
|
1126
|
+
}
|
|
1127
|
+
}
|
|
1128
|
+
}
|
|
1129
|
+
return {
|
|
1130
|
+
proxiableSubschemas,
|
|
1131
|
+
nonProxiableSubschemas,
|
|
1130
1132
|
};
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1133
|
+
}
|
|
1134
|
+
function calculateDelegationStage(mergedTypeInfo, sourceSubschemas, targetSubschemas, fieldNodes) {
|
|
1135
|
+
const { proxiableSubschemas, nonProxiableSubschemas } = sortSubschemasByProxiability(mergedTypeInfo, sourceSubschemas, targetSubschemas, fieldNodes);
|
|
1136
|
+
const { delegationMap, proxiableFieldNodes, unproxiableFieldNodes } = buildDelegationStage(mergedTypeInfo, fieldNodes, proxiableSubschemas);
|
|
1137
|
+
return {
|
|
1138
|
+
proxiableSubschemas,
|
|
1139
|
+
nonProxiableSubschemas,
|
|
1140
|
+
delegationMap,
|
|
1141
|
+
proxiableFieldNodes,
|
|
1142
|
+
unproxiableFieldNodes,
|
|
1143
|
+
};
|
|
1144
|
+
}
|
|
1145
|
+
const buildDelegationPlan = memoize4ofMany(function buildDelegationPlan(mergedTypeInfo, gatewaySchema, sourceSubschema, ...fieldNodeArrays) {
|
|
1146
|
+
var _a, _b, _c;
|
|
1147
|
+
const requiredKeys = Object.create(null);
|
|
1148
|
+
const delegationMaps = [];
|
|
1149
|
+
const stageMap = Object.create(null);
|
|
1150
|
+
const stitchingInfo = (_a = gatewaySchema.extensions) === null || _a === void 0 ? void 0 : _a['stitchingInfo'];
|
|
1151
|
+
if (stitchingInfo == null) {
|
|
1152
|
+
return { requiredKeys, delegationMaps, stageMap };
|
|
1153
|
+
}
|
|
1154
|
+
const targetSubschemas = mergedTypeInfo.targetSubschemas.get(sourceSubschema);
|
|
1155
|
+
if (targetSubschemas === undefined || targetSubschemas.length === 0) {
|
|
1156
|
+
return { requiredKeys, delegationMaps, stageMap };
|
|
1157
|
+
}
|
|
1158
|
+
const parentTypeName = mergedTypeInfo.typeName;
|
|
1159
|
+
const sourceSubschemaParentType = sourceSubschema.transformedSchema.getType(parentTypeName);
|
|
1160
|
+
const sourceSubschemaFields = sourceSubschemaParentType.getFields();
|
|
1161
|
+
const subschemaFields = mergedTypeInfo.subschemaFields;
|
|
1162
|
+
const typeFieldNodes = (_b = stitchingInfo.fieldNodesByField) === null || _b === void 0 ? void 0 : _b[parentTypeName];
|
|
1163
|
+
const fieldNodeSet = new Set();
|
|
1164
|
+
const fieldNodesByType = (_c = stitchingInfo.fieldNodesByType) === null || _c === void 0 ? void 0 : _c[parentTypeName];
|
|
1165
|
+
if (fieldNodesByType !== undefined) {
|
|
1166
|
+
for (const fieldNode of fieldNodesByType) {
|
|
1167
|
+
const fieldName = fieldNode.name.value;
|
|
1168
|
+
if (!sourceSubschemaFields[fieldName]) {
|
|
1169
|
+
const fieldName = fieldNode.name.value;
|
|
1170
|
+
if (!sourceSubschemaFields[fieldName]) {
|
|
1171
|
+
fieldNodeSet.add(fieldNode);
|
|
1172
|
+
}
|
|
1137
1173
|
}
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1174
|
+
}
|
|
1175
|
+
}
|
|
1176
|
+
for (const fieldNodeArray of fieldNodeArrays) {
|
|
1177
|
+
const fieldName = fieldNodeArray[0].name.value;
|
|
1178
|
+
if (subschemaFields[fieldName] !== undefined) {
|
|
1179
|
+
// merged subschema field
|
|
1180
|
+
for (const fieldNode of fieldNodeArray) {
|
|
1181
|
+
const fieldName = fieldNode.name.value;
|
|
1182
|
+
if (!sourceSubschemaFields[fieldName]) {
|
|
1183
|
+
fieldNodeSet.add(fieldNode);
|
|
1184
|
+
}
|
|
1185
|
+
}
|
|
1186
|
+
}
|
|
1187
|
+
else {
|
|
1188
|
+
// gateway field
|
|
1189
|
+
if (requiredKeys[fieldName] === undefined) {
|
|
1190
|
+
requiredKeys[fieldName] = new Set();
|
|
1191
|
+
}
|
|
1192
|
+
}
|
|
1193
|
+
const keyFieldNodes = new Set();
|
|
1194
|
+
const fieldNodesByField = typeFieldNodes === null || typeFieldNodes === void 0 ? void 0 : typeFieldNodes[fieldName];
|
|
1195
|
+
if (fieldNodesByField !== undefined) {
|
|
1196
|
+
for (const fieldNode of fieldNodesByField) {
|
|
1197
|
+
keyFieldNodes.add(fieldNode);
|
|
1198
|
+
}
|
|
1199
|
+
}
|
|
1200
|
+
if (requiredKeys[fieldName] !== undefined) {
|
|
1201
|
+
for (const fieldNode of keyFieldNodes.values()) {
|
|
1202
|
+
requiredKeys[fieldName].add(fieldNode.name.value);
|
|
1203
|
+
}
|
|
1204
|
+
}
|
|
1205
|
+
for (const fieldNode of keyFieldNodes) {
|
|
1206
|
+
fieldNodeSet.add(fieldNode);
|
|
1207
|
+
}
|
|
1208
|
+
}
|
|
1209
|
+
const fieldNodes = Array.from(fieldNodeSet);
|
|
1210
|
+
let sourceSubschemas = [sourceSubschema];
|
|
1211
|
+
let delegationStage = calculateDelegationStage(mergedTypeInfo, sourceSubschemas, targetSubschemas, fieldNodes);
|
|
1212
|
+
let stageIndex = 0;
|
|
1213
|
+
let delegationMap = delegationStage.delegationMap;
|
|
1214
|
+
while (delegationMap.size) {
|
|
1215
|
+
delegationMaps.push(delegationMap);
|
|
1216
|
+
const { proxiableSubschemas, nonProxiableSubschemas, proxiableFieldNodes, unproxiableFieldNodes } = delegationStage;
|
|
1217
|
+
sourceSubschemas = sourceSubschemas.concat(proxiableSubschemas);
|
|
1218
|
+
for (const fieldNode of proxiableFieldNodes) {
|
|
1219
|
+
stageMap[fieldNode.name.value] = stageIndex;
|
|
1220
|
+
}
|
|
1221
|
+
stageIndex++;
|
|
1222
|
+
delegationStage = calculateDelegationStage(mergedTypeInfo, sourceSubschemas, nonProxiableSubschemas, unproxiableFieldNodes);
|
|
1223
|
+
delegationMap = delegationStage.delegationMap;
|
|
1224
|
+
}
|
|
1225
|
+
return {
|
|
1226
|
+
requiredKeys,
|
|
1227
|
+
delegationMaps,
|
|
1228
|
+
stageMap,
|
|
1229
|
+
};
|
|
1230
|
+
});
|
|
1231
|
+
function buildDelegationStage(mergedTypeInfo, fieldNodes, proxiableSubschemas) {
|
|
1232
|
+
const { uniqueFields, nonUniqueFields } = mergedTypeInfo;
|
|
1233
|
+
const proxiableFieldNodes = [];
|
|
1234
|
+
const unproxiableFieldNodes = [];
|
|
1235
|
+
// 2. for each selection:
|
|
1236
|
+
const delegationMap = new Map();
|
|
1237
|
+
for (const fieldNode of fieldNodes) {
|
|
1238
|
+
if (fieldNode.name.value === '__typename') {
|
|
1239
|
+
continue;
|
|
1240
|
+
}
|
|
1241
|
+
// 2a. use uniqueFields map to assign fields to subschema if one of possible subschemas
|
|
1242
|
+
const uniqueSubschema = uniqueFields[fieldNode.name.value];
|
|
1243
|
+
if (uniqueSubschema != null) {
|
|
1244
|
+
if (!proxiableSubschemas.includes(uniqueSubschema)) {
|
|
1245
|
+
unproxiableFieldNodes.push(fieldNode);
|
|
1246
|
+
continue;
|
|
1247
|
+
}
|
|
1248
|
+
const existingSubschema = delegationMap.get(uniqueSubschema);
|
|
1249
|
+
if (existingSubschema != null) {
|
|
1250
|
+
existingSubschema.push(fieldNode);
|
|
1251
|
+
}
|
|
1252
|
+
else {
|
|
1253
|
+
delegationMap.set(uniqueSubschema, [fieldNode]);
|
|
1254
|
+
}
|
|
1255
|
+
proxiableFieldNodes.push(fieldNode);
|
|
1256
|
+
continue;
|
|
1257
|
+
}
|
|
1258
|
+
// 2b. use nonUniqueFields to assign to a possible subschema,
|
|
1259
|
+
// preferring one of the subschemas already targets of delegation
|
|
1260
|
+
let nonUniqueSubschemas = nonUniqueFields[fieldNode.name.value];
|
|
1261
|
+
if (nonUniqueSubschemas == null) {
|
|
1262
|
+
unproxiableFieldNodes.push(fieldNode);
|
|
1263
|
+
continue;
|
|
1264
|
+
}
|
|
1265
|
+
nonUniqueSubschemas = nonUniqueSubschemas.filter(s => proxiableSubschemas.includes(s));
|
|
1266
|
+
if (!nonUniqueSubschemas.length) {
|
|
1267
|
+
unproxiableFieldNodes.push(fieldNode);
|
|
1268
|
+
continue;
|
|
1269
|
+
}
|
|
1270
|
+
const existingSubschema = nonUniqueSubschemas.find(s => delegationMap.has(s));
|
|
1271
|
+
if (existingSubschema != null) {
|
|
1272
|
+
// It is okay we previously explicitly check whether the map has the element.
|
|
1273
|
+
delegationMap.get(existingSubschema).push(fieldNode);
|
|
1274
|
+
}
|
|
1275
|
+
else {
|
|
1276
|
+
delegationMap.set(nonUniqueSubschemas[0], [fieldNode]);
|
|
1277
|
+
}
|
|
1278
|
+
proxiableFieldNodes.push(fieldNode);
|
|
1279
|
+
}
|
|
1280
|
+
return {
|
|
1281
|
+
delegationMap,
|
|
1282
|
+
proxiableFieldNodes,
|
|
1283
|
+
unproxiableFieldNodes,
|
|
1284
|
+
};
|
|
1285
|
+
}
|
|
1286
|
+
async function executeDelegationStage(delegationMap, schema, type, mergedTypeInfo, context, object, parentInfo, parentPath) {
|
|
1287
|
+
const initialPath = getInitialPath(object);
|
|
1288
|
+
const newSubschemaMap = getSubschemaMap(object);
|
|
1289
|
+
const unpathedErrors = getUnpathedErrors(object);
|
|
1290
|
+
await Promise.all([...delegationMap.entries()].map(async ([s, fieldNodes]) => {
|
|
1291
|
+
var _a;
|
|
1292
|
+
const resolver = mergedTypeInfo.resolvers.get(s);
|
|
1293
|
+
if (resolver) {
|
|
1294
|
+
const selectionSet = { kind: Kind.SELECTION_SET, selections: fieldNodes };
|
|
1295
|
+
let source;
|
|
1296
|
+
try {
|
|
1297
|
+
source = await resolver(object, context, parentInfo, s, selectionSet);
|
|
1298
|
+
}
|
|
1299
|
+
catch (error) {
|
|
1300
|
+
source = error;
|
|
1301
|
+
}
|
|
1302
|
+
if (source instanceof Error || source === null) {
|
|
1303
|
+
const fieldNodes = collectFields(schema, {}, {}, type, selectionSet, new Map(), new Set());
|
|
1304
|
+
const nullResult = Object.create(null);
|
|
1305
|
+
if (source instanceof GraphQLError && source.path) {
|
|
1306
|
+
const basePath = parentPath.slice(initialPath.length);
|
|
1307
|
+
for (const [responseKey] of fieldNodes) {
|
|
1308
|
+
const tailPath = source.path.length === parentPath.length ? [responseKey] : source.path.slice(initialPath.length);
|
|
1309
|
+
const newPath = basePath.concat(tailPath);
|
|
1310
|
+
nullResult[responseKey] = relocatedError(source, newPath);
|
|
1311
|
+
}
|
|
1312
|
+
}
|
|
1313
|
+
else if (source instanceof Error) {
|
|
1314
|
+
const basePath = parentPath.slice(initialPath.length);
|
|
1315
|
+
for (const [responseKey] of fieldNodes) {
|
|
1316
|
+
const newPath = basePath.concat([responseKey]);
|
|
1317
|
+
nullResult[responseKey] = locatedError(source, fieldNodes[responseKey], newPath);
|
|
1318
|
+
}
|
|
1319
|
+
}
|
|
1320
|
+
else {
|
|
1321
|
+
for (const [responseKey] of fieldNodes) {
|
|
1322
|
+
nullResult[responseKey] = null;
|
|
1323
|
+
}
|
|
1142
1324
|
}
|
|
1325
|
+
source = nullResult;
|
|
1326
|
+
}
|
|
1327
|
+
// TODO: is this check necessary or just to make TS happy?
|
|
1328
|
+
if (!isExternalObject(source)) {
|
|
1329
|
+
Object.assign(object, source);
|
|
1330
|
+
return object;
|
|
1331
|
+
}
|
|
1332
|
+
const objectSubschema = getObjectSubchema(source);
|
|
1333
|
+
const subschemaMap = getSubschemaMap(source);
|
|
1334
|
+
for (const responseKey in source) {
|
|
1335
|
+
object[responseKey] = source[responseKey];
|
|
1336
|
+
newSubschemaMap[responseKey] = (_a = subschemaMap === null || subschemaMap === void 0 ? void 0 : subschemaMap[responseKey]) !== null && _a !== void 0 ? _a : objectSubschema;
|
|
1143
1337
|
}
|
|
1338
|
+
unpathedErrors.push(...getUnpathedErrors(source));
|
|
1339
|
+
}
|
|
1340
|
+
}));
|
|
1341
|
+
return object;
|
|
1342
|
+
}
|
|
1343
|
+
const subschemaTypesContainSelectionSet = memoize3(function subschemaTypesContainSelectionSet(mergedTypeInfo, sourceSubschemas, selectionSet) {
|
|
1344
|
+
return typesContainSelectionSet(sourceSubschemas.map(sourceSubschema => sourceSubschema.transformedSchema.getType(mergedTypeInfo.typeName)), selectionSet);
|
|
1345
|
+
});
|
|
1346
|
+
function typesContainSelectionSet(types, selectionSet) {
|
|
1347
|
+
var _a;
|
|
1348
|
+
const fieldMaps = types.map(type => type.getFields());
|
|
1349
|
+
for (const selection of selectionSet.selections) {
|
|
1350
|
+
if (selection.kind === Kind.FIELD) {
|
|
1351
|
+
const fields = fieldMaps.map(fieldMap => fieldMap[selection.name.value]).filter(field => field != null);
|
|
1352
|
+
if (!fields.length) {
|
|
1353
|
+
return false;
|
|
1354
|
+
}
|
|
1355
|
+
if (selection.selectionSet != null) {
|
|
1356
|
+
return typesContainSelectionSet(fields.map(field => getNamedType(field.type)), selection.selectionSet);
|
|
1357
|
+
}
|
|
1358
|
+
}
|
|
1359
|
+
else if (selection.kind === Kind.INLINE_FRAGMENT && ((_a = selection.typeCondition) === null || _a === void 0 ? void 0 : _a.name.value) === types[0].name) {
|
|
1360
|
+
return typesContainSelectionSet(types, selection.selectionSet);
|
|
1144
1361
|
}
|
|
1145
1362
|
}
|
|
1146
|
-
return
|
|
1363
|
+
return true;
|
|
1364
|
+
}
|
|
1365
|
+
|
|
1366
|
+
/**
|
|
1367
|
+
* Resolver that knows how to:
|
|
1368
|
+
* a) handle aliases for proxied schemas
|
|
1369
|
+
* b) handle errors from proxied schemas
|
|
1370
|
+
* c) handle external to internal enum/scalar conversion
|
|
1371
|
+
* d) handle type merging
|
|
1372
|
+
* e) handle deferred values
|
|
1373
|
+
*/
|
|
1374
|
+
function defaultMergedResolver(parent, args, context, info) {
|
|
1375
|
+
if (!isExternalObject(parent)) {
|
|
1376
|
+
return defaultFieldResolver(parent, args, context, info);
|
|
1377
|
+
}
|
|
1378
|
+
const responseKey = getResponseKeyFromInfo(info);
|
|
1379
|
+
const initialPossibleFields = getInitialPossibleFields(parent);
|
|
1380
|
+
if (initialPossibleFields === undefined) {
|
|
1381
|
+
// TODO: can this be removed in the next major release?
|
|
1382
|
+
// legacy use of delegation without setting transformedSchema
|
|
1383
|
+
const data = parent[responseKey];
|
|
1384
|
+
if (data !== undefined) {
|
|
1385
|
+
return resolveField(parent, responseKey, context, info);
|
|
1386
|
+
}
|
|
1387
|
+
}
|
|
1388
|
+
else if (info.fieldName in initialPossibleFields) {
|
|
1389
|
+
return resolveField(parent, responseKey, context, info);
|
|
1390
|
+
}
|
|
1391
|
+
return getMergedParent(parent, context, info).then(mergedParent => resolveField(mergedParent, responseKey, context, info));
|
|
1392
|
+
}
|
|
1393
|
+
function resolveField(parent, responseKey, context, info) {
|
|
1394
|
+
const initialPath = getInitialPath(parent);
|
|
1395
|
+
const subschema = getSubschema(parent, responseKey);
|
|
1396
|
+
const unpathedErrors = getUnpathedErrors(parent);
|
|
1397
|
+
return createExternalValue(parent[responseKey], unpathedErrors, initialPath, subschema, context, info);
|
|
1147
1398
|
}
|
|
1148
1399
|
|
|
1149
1400
|
function delegateToSchema(options) {
|
|
1150
|
-
const { info, schema, rootValue, operationName, operation = getDelegatingOperation(info.parentType, info.schema), fieldName = info.fieldName, selectionSet, fieldNodes, context, } = options;
|
|
1401
|
+
const { info, schema, rootValue = schema.rootValue, operationName, operation = getDelegatingOperation(info.parentType, info.schema), fieldName = info.fieldName, selectionSet, fieldNodes, context, } = options;
|
|
1151
1402
|
const request = createRequestFromInfo({
|
|
1152
1403
|
info,
|
|
1153
1404
|
operation,
|
|
1154
1405
|
fieldName,
|
|
1155
1406
|
selectionSet,
|
|
1156
1407
|
fieldNodes,
|
|
1157
|
-
rootValue
|
|
1408
|
+
rootValue,
|
|
1158
1409
|
operationName,
|
|
1159
1410
|
context,
|
|
1160
1411
|
});
|
|
1161
1412
|
return delegateRequest({
|
|
1162
1413
|
...options,
|
|
1163
1414
|
request,
|
|
1415
|
+
operation,
|
|
1416
|
+
fieldName,
|
|
1164
1417
|
});
|
|
1165
1418
|
}
|
|
1166
1419
|
function getDelegationReturnType(targetSchema, operation, fieldName) {
|
|
@@ -1168,10 +1421,30 @@ function getDelegationReturnType(targetSchema, operation, fieldName) {
|
|
|
1168
1421
|
return rootType.getFields()[fieldName].type;
|
|
1169
1422
|
}
|
|
1170
1423
|
function delegateRequest(options) {
|
|
1171
|
-
|
|
1424
|
+
var _a;
|
|
1425
|
+
let operationDefinition;
|
|
1426
|
+
let targetFieldName;
|
|
1427
|
+
const { document, operationName } = options.request;
|
|
1428
|
+
if (options.fieldName == null) {
|
|
1429
|
+
operationDefinition = getOperationAST(document, operationName);
|
|
1430
|
+
if (operationDefinition == null) {
|
|
1431
|
+
throw new Error('Cannot infer main operation from the provided document.');
|
|
1432
|
+
}
|
|
1433
|
+
targetFieldName = (operationDefinition === null || operationDefinition === void 0 ? void 0 : operationDefinition.selectionSet.selections[0]).name.value;
|
|
1434
|
+
}
|
|
1435
|
+
else {
|
|
1436
|
+
targetFieldName = options.fieldName;
|
|
1437
|
+
}
|
|
1438
|
+
const { schema, info, operation = getDelegatingOperation(info.parentType, info.schema), returnType = (_a = info === null || info === void 0 ? void 0 : info.returnType) !== null && _a !== void 0 ? _a : getDelegationReturnType(schema instanceof GraphQLSchema ? schema : schema.schema, operation, targetFieldName), context, onLocatedError = (error) => error, validateRequest: shouldValidateRequest, } = options;
|
|
1439
|
+
const delegationContext = getDelegationContext({
|
|
1440
|
+
...options,
|
|
1441
|
+
operation,
|
|
1442
|
+
fieldName: targetFieldName,
|
|
1443
|
+
returnType,
|
|
1444
|
+
});
|
|
1172
1445
|
const transformer = new Transformer(delegationContext);
|
|
1173
1446
|
const processedRequest = transformer.transformRequest(options.request);
|
|
1174
|
-
if (
|
|
1447
|
+
if (shouldValidateRequest) {
|
|
1175
1448
|
validateRequest(delegationContext, processedRequest.document);
|
|
1176
1449
|
}
|
|
1177
1450
|
const executor = getExecutor(delegationContext);
|
|
@@ -1179,13 +1452,29 @@ function delegateRequest(options) {
|
|
|
1179
1452
|
.then(originalResult => {
|
|
1180
1453
|
if (isAsyncIterable(originalResult)) {
|
|
1181
1454
|
// "subscribe" to the subscription result and map the result through the transforms
|
|
1182
|
-
return mapAsyncIterator(originalResult, result =>
|
|
1455
|
+
return mapAsyncIterator(originalResult, result => externalValueFromResult({
|
|
1456
|
+
result: transformer.transformResult(result),
|
|
1457
|
+
schema,
|
|
1458
|
+
info,
|
|
1459
|
+
context,
|
|
1460
|
+
fieldName: targetFieldName,
|
|
1461
|
+
returnType,
|
|
1462
|
+
onLocatedError,
|
|
1463
|
+
}));
|
|
1183
1464
|
}
|
|
1184
|
-
return
|
|
1465
|
+
return externalValueFromResult({
|
|
1466
|
+
result: transformer.transformResult(originalResult),
|
|
1467
|
+
schema,
|
|
1468
|
+
info,
|
|
1469
|
+
context,
|
|
1470
|
+
fieldName: targetFieldName,
|
|
1471
|
+
returnType,
|
|
1472
|
+
onLocatedError,
|
|
1473
|
+
});
|
|
1185
1474
|
})
|
|
1186
1475
|
.resolve();
|
|
1187
1476
|
}
|
|
1188
|
-
function getDelegationContext({ request, schema, fieldName, returnType, args, info, transforms = [], transformedSchema,
|
|
1477
|
+
function getDelegationContext({ request, schema, fieldName, returnType, args, info, transforms = [], transformedSchema, }) {
|
|
1189
1478
|
var _a, _b, _c, _d;
|
|
1190
1479
|
const { operationType: operation, context, operationName, document } = request;
|
|
1191
1480
|
let operationDefinition;
|
|
@@ -1202,7 +1491,7 @@ function getDelegationContext({ request, schema, fieldName, returnType, args, in
|
|
|
1202
1491
|
}
|
|
1203
1492
|
const stitchingInfo = (_a = info === null || info === void 0 ? void 0 : info.schema.extensions) === null || _a === void 0 ? void 0 : _a['stitchingInfo'];
|
|
1204
1493
|
const subschemaOrSubschemaConfig = (_b = stitchingInfo === null || stitchingInfo === void 0 ? void 0 : stitchingInfo.subschemaMap.get(schema)) !== null && _b !== void 0 ? _b : schema;
|
|
1205
|
-
if (
|
|
1494
|
+
if (!isSchema(subschemaOrSubschemaConfig)) {
|
|
1206
1495
|
const targetSchema = subschemaOrSubschemaConfig.schema;
|
|
1207
1496
|
return {
|
|
1208
1497
|
subschema: schema,
|
|
@@ -1218,7 +1507,6 @@ function getDelegationContext({ request, schema, fieldName, returnType, args, in
|
|
|
1218
1507
|
? subschemaOrSubschemaConfig.transforms.concat(transforms)
|
|
1219
1508
|
: transforms,
|
|
1220
1509
|
transformedSchema: transformedSchema !== null && transformedSchema !== void 0 ? transformedSchema : (subschemaOrSubschemaConfig instanceof Subschema ? subschemaOrSubschemaConfig.transformedSchema : targetSchema),
|
|
1221
|
-
skipTypeMerging,
|
|
1222
1510
|
};
|
|
1223
1511
|
}
|
|
1224
1512
|
return {
|
|
@@ -1233,7 +1521,6 @@ function getDelegationContext({ request, schema, fieldName, returnType, args, in
|
|
|
1233
1521
|
returnType: (_d = returnType !== null && returnType !== void 0 ? returnType : info === null || info === void 0 ? void 0 : info.returnType) !== null && _d !== void 0 ? _d : getDelegationReturnType(subschemaOrSubschemaConfig, operation, targetFieldName),
|
|
1234
1522
|
transforms,
|
|
1235
1523
|
transformedSchema: transformedSchema !== null && transformedSchema !== void 0 ? transformedSchema : subschemaOrSubschemaConfig,
|
|
1236
|
-
skipTypeMerging,
|
|
1237
1524
|
};
|
|
1238
1525
|
}
|
|
1239
1526
|
function validateRequest(delegationContext, document) {
|
|
@@ -1274,4 +1561,31 @@ const createDefaultExecutor = memoize1(function createDefaultExecutor(schema) {
|
|
|
1274
1561
|
};
|
|
1275
1562
|
});
|
|
1276
1563
|
|
|
1277
|
-
|
|
1564
|
+
function isSubschemaConfig(value) {
|
|
1565
|
+
return Boolean(value === null || value === void 0 ? void 0 : value.schema);
|
|
1566
|
+
}
|
|
1567
|
+
function cloneSubschemaConfig(subschemaConfig) {
|
|
1568
|
+
var _a, _b;
|
|
1569
|
+
const newSubschemaConfig = {
|
|
1570
|
+
...subschemaConfig,
|
|
1571
|
+
transforms: subschemaConfig.transforms != null ? [...subschemaConfig.transforms] : undefined,
|
|
1572
|
+
};
|
|
1573
|
+
if (newSubschemaConfig.merge != null) {
|
|
1574
|
+
newSubschemaConfig.merge = { ...subschemaConfig.merge };
|
|
1575
|
+
for (const typeName in newSubschemaConfig.merge) {
|
|
1576
|
+
const mergedTypeConfig = (newSubschemaConfig.merge[typeName] = { ...((_b = (_a = subschemaConfig.merge) === null || _a === void 0 ? void 0 : _a[typeName]) !== null && _b !== void 0 ? _b : {}) });
|
|
1577
|
+
if (mergedTypeConfig.entryPoints != null) {
|
|
1578
|
+
mergedTypeConfig.entryPoints = mergedTypeConfig.entryPoints.map(entryPoint => ({ ...entryPoint }));
|
|
1579
|
+
}
|
|
1580
|
+
if (mergedTypeConfig.fields != null) {
|
|
1581
|
+
const fields = (mergedTypeConfig.fields = { ...mergedTypeConfig.fields });
|
|
1582
|
+
for (const fieldName in fields) {
|
|
1583
|
+
fields[fieldName] = { ...fields[fieldName] };
|
|
1584
|
+
}
|
|
1585
|
+
}
|
|
1586
|
+
}
|
|
1587
|
+
}
|
|
1588
|
+
return newSubschemaConfig;
|
|
1589
|
+
}
|
|
1590
|
+
|
|
1591
|
+
export { Subschema, Transformer, annotateExternalObject, applySchemaTransforms, buildDelegationPlan, cloneSubschemaConfig, createDefaultExecutor, createExternalValue, createRequest, createRequestFromInfo, defaultMergedResolver, delegateRequest, delegateToSchema, externalValueFromResult, getDelegatingOperation, getDelegationContext, getExecutor, getInfo, getInitialPath, getInitialPossibleFields, getMergedParent, getObjectSubchema, getSubschema, getSubschemaMap, getUnpathedErrors, isExternalObject, isSubschema, isSubschemaConfig, validateRequest };
|