/
handleObject.ts
128 lines (107 loc) · 3.62 KB
/
handleObject.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
import {
GraphQLCompositeType,
GraphQLError,
GraphQLSchema,
isAbstractType,
FieldNode,
GraphQLObjectType,
GraphQLResolveInfo,
} from 'graphql';
import { collectFields, GraphQLExecutionContext, setErrors, slicedError } from '@graphql-tools/utils';
import { setObjectSubschema, isSubschemaConfig } from '../Subschema';
import { mergeFields } from '../mergeFields';
import { MergedTypeInfo, SubschemaConfig, StitchingInfo } from '../types';
export function handleObject(
type: GraphQLCompositeType,
object: any,
errors: ReadonlyArray<GraphQLError>,
subschema: GraphQLSchema | SubschemaConfig,
context: Record<string, any>,
info: GraphQLResolveInfo,
skipTypeMerging?: boolean
) {
const stitchingInfo = info?.schema.extensions?.stitchingInfo;
setErrors(
object,
errors.map(error => slicedError(error))
);
setObjectSubschema(object, subschema);
if (skipTypeMerging || !stitchingInfo) {
return object;
}
const typeName = isAbstractType(type) ? info.schema.getTypeMap()[object.__typename].name : type.name;
const mergedTypeInfo = stitchingInfo.mergedTypes[typeName];
let targetSubschemas: Array<SubschemaConfig>;
if (mergedTypeInfo != null) {
targetSubschemas = mergedTypeInfo.subschemas;
}
if (!targetSubschemas) {
return object;
}
targetSubschemas = targetSubschemas.filter(s => s !== subschema);
if (!targetSubschemas.length) {
return object;
}
const fieldNodes = getFieldsNotInSubschema(info, subschema, mergedTypeInfo, object.__typename);
return mergeFields(
mergedTypeInfo,
typeName,
object,
fieldNodes,
[subschema as SubschemaConfig],
targetSubschemas,
context,
info
);
}
function collectSubFields(info: GraphQLResolveInfo, typeName: string): Record<string, Array<FieldNode>> {
let subFieldNodes: Record<string, Array<FieldNode>> = Object.create(null);
const visitedFragmentNames = Object.create(null);
const type = info.schema.getType(typeName) as GraphQLObjectType;
const partialExecutionContext = ({
schema: info.schema,
variableValues: info.variableValues,
fragments: info.fragments,
} as unknown) as GraphQLExecutionContext;
info.fieldNodes.forEach(fieldNode => {
subFieldNodes = collectFields(
partialExecutionContext,
type,
fieldNode.selectionSet,
subFieldNodes,
visitedFragmentNames
);
});
const selectionSetsByField = (info.schema.extensions.stitchingInfo as StitchingInfo).selectionSetsByField;
Object.keys(subFieldNodes).forEach(responseName => {
const fieldName = subFieldNodes[responseName][0].name.value;
if (selectionSetsByField[typeName] && selectionSetsByField[typeName][fieldName]) {
subFieldNodes = collectFields(
partialExecutionContext,
type,
selectionSetsByField[typeName][fieldName],
subFieldNodes,
visitedFragmentNames
);
}
});
return subFieldNodes;
}
function getFieldsNotInSubschema(
info: GraphQLResolveInfo,
subschema: GraphQLSchema | SubschemaConfig,
mergedTypeInfo: MergedTypeInfo,
typeName: string
): Array<FieldNode> {
const typeMap = isSubschemaConfig(subschema) ? mergedTypeInfo.typeMaps.get(subschema) : subschema.getTypeMap();
const fields = (typeMap[typeName] as GraphQLObjectType).getFields();
const subFieldNodes = collectSubFields(info, typeName);
let fieldsNotInSchema: Array<FieldNode> = [];
Object.keys(subFieldNodes).forEach(responseName => {
const fieldName = subFieldNodes[responseName][0].name.value;
if (!(fieldName in fields)) {
fieldsNotInSchema = fieldsNotInSchema.concat(subFieldNodes[responseName]);
}
});
return fieldsNotInSchema;
}